Help with Exchange Rate Data Feed
-
Hi, I am trying to build a simple backtest for a moving crossover strategy on some historical FX trading data. Currently, the account currency is in pounds (as would be in reality). I want to trade EUR/USD, for example. I input the first data feed as the traded pair EUR/USD, and then the exchange rate GBP/USD for the second.
class SmaCross(bt.Strategy): params = ( ('pfast', 50), ('pslow', 200), ('stake', 1000), # units of the base currency (base/quote) => 1000 = 1000EUR in EUR/USD trading ('exectype', bt.Order.Market), ) def log(self, txt, dt=None, time=None): """ Logging function for this strategy""" dt = dt or self.data0.datetime.date(0) time = time or self.data0.datetime.time(0) print('%s %s, %s' % (dt.isoformat(), time.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close sma1 = bt.indicators.SMA(self.data, period=self.p.pfast) sma2 = bt.indicators.SMA(self.data, period=self.p.pslow) self.crossover = bt.ind.CrossOver(sma1, sma2, plot=False) # Crossover signal # To keep track of pending orders self.order = None def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enough cash if order.status in [order.Completed]: if order.isbuy(): self.log("BUY EXECUTED, %f" % order.executed.price) elif order.issell(): self.log("SELL EXECUTED, %f. BALANCE: %f. MARGIN REMAINING: %f." % (order.executed.price, cerebro.broker.getvalue(), cerebro.broker.get_cash() )) cerebro.signals = [] elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if trade.justopened: print('----TRADE OPENED----') print('Size: %f' % trade.size) elif trade.isclosed: print('----TRADE CLOSED----') print('Profit, Gross {}, Net {}'.format( trade.pnl, trade.pnlcomm)) else: return def next(self): # self.log((self.broker.getvalue(), self.broker.get_cash(), self.dataclose[0])) # current price of the position if self.order: return if not self.position: if self.crossover > 0: self.order = self.buy(size=self.p.stake, exectype=self.p.exectype, price=self.data.close[0]) # enter long cerebro.broker.get_value() self.log('BUYING AT %f. BALANCE: %f. MARGIN REMAINING: %f.' % (self.data.close[0], cerebro.broker.getvalue(),cerebro.broker.get_cash())) elif self.crossover < 0: self.order = self.close(exectype=self.p.exectype, price=self.data.close[0]) # close long position self.log('CLOSING AT %f' % self.data.close[0]) cerebro.signals.append('CLOSING')
In my custom commission scheme, I have changed the profitandloss calculations, along with the cash adjustment so that the floating balance of the account represents the profits and losses in real time in the account currency (pounds).
def profitandloss(self, size, price, newprice): backtrader_prof = size * (newprice - price) * self.p.mult if backtrader_prof == 0: return backtrader_prof else: pips = (newprice - price) * 10000 if acc_currency == 'Base': pip_value = (size / price) * self.p.multiplier elif acc_currency == "Quote": pip_value = (size * self.p.multiplier) else: if self.p.exchange_format == "XXX/GBP": pip_value = size * self.p.multiplier pip_value = pip_value * self.p.exchange_rate # pip value in pounds elif self.p.exchange_format == "GBP/XXX": pip_value = size * self.p.multiplier if "CLOSING" in cerebro.signals: pip_value = pip_value * (1 / cerebro.datas[1].open), # pip value in pounds else: pip_value = pip_value * (1 / cerebro.datas[1]) pnl = pips * pip_value return pnl def cashadjust(self, size, price, newprice): """Calculates cash adjustment for a given price difference""" return self.profitandloss(size, price, newprice)
The problem, is that the profit and loss is calculated correctly for the trade below
£4.34
, but the balance in the account after this one trade is incorrect at£2003.98
.Starting Portfolio Value: £2000.000000 2016-03-16 21:00:00, BUYING AT 1.121060. BALANCE: 2000.000000. MARGIN REMAINING: 2000.000000. 2016-03-17 01:00:00, BUY EXECUTED, 1.121100 ----TRADE OPENED---- Size: 1000.000000 2016-05-18 09:00:00, CLOSING AT 1.127440 2016-05-18 13:00:00, SELL EXECUTED, 1.127410. BALANCE: 2003.984311. MARGIN REMAINING: 2003.984311. ----TRADE CLOSED---- Profit, Gross 4.335577848014318, Net 4.335577848014318 Final Portfolio Value: £2003.984311
I do not understand how the cash adjustment can be incorrect if it uses the same code to provide the profit and loss, which is correct?
Any help would be greatly provided. Maybe it's something wrong with the inputting of a second data feed. I don't enumerate through them in the strategy as I just want to carry out the strategy on the first dataset, and then use the second as an exchange rate for my commission scheme.
Many thanks!
-
OK: thought this through and it appears the discrepancy comes from calculating the floating balance at each bar and converting it into pounds using different exchange rates for every bar. The final profit and loss is just calculated using the difference between entry and exit price and the exchange rate at the point of exit - so there’s the discrepancy.
Any ideas on how to correctly calculate the floating balance in pounds or to make the account value and PnL match up after a trade would be much appreciated.