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

Need Help on Backtesting with Oanda Data



  • I need help on few problems I had while using Oanda data.

    Before anything, I tried oandatest.py and it worked fine.

    python oandatest.py --token XXXX --account 0000 --data0 EUR_USD --timeframe Minutes --historical
    

    gave me

    --------------------------------------------------
    Strategy Created
    --------------------------------------------------
    -- Contract Details:
    {'instrument': 'EUR_USD', 'displayName': 'EUR/USD', 'pip': '0.0001', 'maxTradeUnits': 10000000}
    Datetime, Open, High, Low, Close, Volume, OpenInterest, SMA
    ***** DATA NOTIF: DELAYED
    Data0, 0001, 736732.538194, 2018-02-07T12:55:00.000000, 1.234450, 1.234540, 1.234320, 1.234320,     46, 0, nan
    .
    .
    .
    Data0, 0500, 736633.366667, 2017-10-31T08:48:00.000000, 1.164445, 1.164460, 1.164300, 1.164325,     18, 0, 1.164377
    ***** DATA NOTIF: DISCONNECTED
    

    Then I tried to test the strategy from "Quickstart"

    import backtrader as bt
    from datetime import datetime  # For datetime objects
    
    #Oanda Account Info
    api_key = "XXXX"
    account_number = "0000"
    
    # Create a Stratey
    class TestStrategy(bt.Strategy):
    
        def log(self, txt, dt=None):
            ''' Logging function for this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
    
        def next(self):
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
    if __name__ == '__main__':
    
        cerebro = bt.Cerebro()
    
        cerebro.addstrategy(TestStrategy)
    
        oandastore = bt.stores.OandaStore(token=api_key, account=account_number, practice=True)
    
        cerebro.broker = oandastore.getbroker()
    
        data = oandastore.getdata(
            dataname = "USD_JPY",
            timeframe = bt.TimeFrame.Minutes,
            compression = 30,
            fromdate = datetime(2017,11,1),
            todate=datetime(2017,11,30)
            )
    
        # Add data
        cerebro.adddata(data)
    
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
        cerebro.run()
    
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
        # Finally plot the end results
        cerebro.plot(style="candle")
    

    It worked but with two problems:
    One problem is compression of 30 and below shows no log.

    Starting Portfolio Value: 0.00
    position for instrument: USD_JPY
    Final Portfolio Value: 96053.55
    

    But compression of 60 and above does show logs.

    Starting Portfolio Value: 0.00
    position for instrument: USD_JPY
    2017-11-01, Close, 113.88
    2017-11-01, Close, 113.90
    .
    .
    .
    2017-11-29, Close, 112.00
    2017-11-30, Close, 111.98
    Final Portfolio Value: 96053.55
    

    Is there a problem with my coding or is it the practice server thing?

    Second problem is that, as you can see from above logs, "Starting Portfolio Value:" is 0 and "Final Portfolio Value:" shows the amount of USD I have on Oanda account. Aren't those two supposed to be same?

    Lastly, when I change the strategy to the next one (compression=60 and keeping everything else same),

    class TestStrategy(bt.Strategy):
    
        def log(self, txt, dt=None):
            ''' Logging function fot this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
    
            # 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, %.2f' % order.executed.price)
                elif order.issell():
                    self.log('SELL EXECUTED, %.2f' % order.executed.price)
    
                self.bar_executed = len(self)
    
            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 next(self):
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
            # Check if an order is pending ... if yes, we cannot send a 2nd one
            if self.order:
                return
    
            # Check if we are in the market
            if not self.position:
    
                # Not yet ... we MIGHT BUY if ...
                if self.dataclose[0] < self.dataclose[-1]:
                        # current close less than previous close
    
                        if self.dataclose[-1] < self.dataclose[-2]:
                            # previous close less than the previous close
    
                            # BUY, BUY, BUY!!! (with default parameters)
                            self.log('BUY CREATE, %.2f' % self.dataclose[0])
    
                            # Keep track of the created order to avoid a 2nd order
                            self.order = self.buy()
    
            else:
    
                # Already in the market ... we might sell
                if len(self) >= (self.bar_executed + 5):
                    # SELL, SELL, SELL!!! (with all possible default parameters)
                    self.log('SELL CREATE, %.2f' % self.dataclose[0])
    
                    # Keep track of the created order to avoid a 2nd order
                    self.order = self.sell()
    

    I get an error of AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'bar_executed' What do I need to do?


  • administrators

    @vensaiten said in Need Help on Backtesting with Oanda Data:

    One problem is compression of 30 and below shows no log.

    This may be due to a bug in the OandaData feed, which was using the same code to retrieve 5 minutes bars as to retrieve 10, 15 and 30 minutes bars. Recalling things, the codes were copied verbatim from Oanda's reference documentation, but they are different today. Regardless of the source it has been pushed.

    @vensaiten said in Need Help on Backtesting with Oanda Data:

    I get an error of AttributeError: 'Lines_LineSeries_LineIterator_DataAccessor_Strateg' object has no attribute 'bar_executed' What do I need to do?

    Initialize self.bar_executed somewhere in your code.


Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.