For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

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.


Log in to reply
 

});