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

Order executed price mismatch!



  • When I try the sample multidata-strategy.py from the source distribution of backtrader under the samples/multidata-strategy directory, an Order executed price mismatching phenomenon happens.

    As such:
    on 2003-02-11:
    BUY CREATE , 9.14 => yahoo close 9.145000 --- OK
    on 2003-02-12:
    BUY COMPLETE, 10.51 => orcl no data match ?
    2003-02-12,11.820000,11.950000,11.490000,11.500000,10.229136,39650300
    2003-02-12T23:59:59.999989, BUY COMPLETE, 9.10 => yahoo open 9.100000 ---OK

    It seems that, when it goes for Data0-orcl, the Order executed price matching will always go wrong!

    Some details:

    (backtrader37) D:\Python\BackTrader\Test>python ./multidata-strategy.py --plot
    ...
    Self  len: 28
    Data0 len: 28
    Data1 len: 28
    Data0 len == Data1 len: True
    Data0 dt: 2003-02-11 23:59:59.999989
    Data1 dt: 2003-02-11 23:59:59.999989
    2003-02-11T23:59:59.999989, BUY CREATE , 9.14
    2003-02-12T23:59:59.999989, BUY COMPLETE, 10.51
    2003-02-12T23:59:59.999989, BUY COMPLETE, 9.10
    Self  len: 29
    Data0 len: 29
    Data1 len: 29
    Data0 len == Data1 len: True
    Data0 dt: 2003-02-12 23:59:59.999989
    Data1 dt: 2003-02-12 23:59:59.999989
    2003-02-12T23:59:59.999989, SELL CREATE , 9.09
    2003-02-13T23:59:59.999989, SELL COMPLETE, 10.28
    2003-02-13T23:59:59.999989, SELL COMPLETE, 9.35
    ...
    

    And the corresponding data feeds:
    Data0 - orcl-1995-2014.txt,

    Date,Open,High,Low,Close,Adj Close,Volume
    ...
    2003-02-10,11.410000,11.800000,11.380000,11.750000,10.451510,33763500
    2003-02-11,11.840000,12.140000,11.720000,11.910000,10.593827,46126300
    2003-02-12,11.820000,11.950000,11.490000,11.500000,10.229136,39650300
    2003-02-13,11.560000,11.690000,11.350000,11.540000,10.264715,34557500
    2003-02-14,11.560000,11.920000,11.350000,11.700000,10.407034,41473100
    ...
    

    Data1 - yhoo-1996-2014.txt,

    Date,Open,High,Low,Close,Adj Close,Volume
    ...
    2003-02-10,8.785000,8.985000,8.730000,8.960000,8.960000,10486400
    2003-02-11,9.000000,9.245000,8.990000,9.145000,9.145000,14895800
    2003-02-12,9.100000,9.300000,9.000000,9.085000,9.085000,12368000
    2003-02-13,9.345000,9.365000,8.780000,9.025000,9.025000,26697800
    2003-02-14,9.155000,9.455000,9.045000,9.450000,9.450000,15901600
    ...
    

    Appendix:
    multidata-strategy.py

    #!/usr/bin/env python
    # -*- coding: utf-8; py-indent-offset:4 -*-
    ###############################################################################
    #
    # Copyright (C) 2015, 2016 Daniel Rodriguez
    #
    # This program is free software: you can redistribute it and/or modify
    # it under the terms of the GNU General Public License as published by
    # the Free Software Foundation, either version 3 of the License, or
    # (at your option) any later version.
    #
    # This program is distributed in the hope that it will be useful,
    # but WITHOUT ANY WARRANTY; without even the implied warranty of
    # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    # GNU General Public License for more details.
    #
    # You should have received a copy of the GNU General Public License
    # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    #
    ###############################################################################
    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import argparse
    import datetime
    
    # The above could be sent to an independent module
    import backtrader as bt
    import backtrader.feeds as btfeeds
    import backtrader.indicators as btind
    
    
    class MultiDataStrategy(bt.Strategy):
        '''
        This strategy operates on 2 datas. The expectation is that the 2 datas are
        correlated and the 2nd data is used to generate signals on the 1st
    
          - Buy/Sell Operationss will be executed on the 1st data
          - The signals are generated using a Simple Moving Average on the 2nd data
            when the close price crosses upwwards/downwards
    
        The strategy is a long-only strategy
        '''
        params = dict(
            period=15,
            stake=10,
            printout=True,
        )
    
        def log(self, txt, dt=None):
            if self.p.printout:
                dt = dt or self.data.datetime[0]
                dt = bt.num2date(dt)
                print('%s, %s' % (dt.isoformat(), txt))
    
        def notify_order(self, order):
            if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
                return  # Await further notifications
    
            if order.status == order.Completed:
                if order.isbuy():
                    buytxt = 'BUY COMPLETE, %.2f' % order.executed.price
                    self.log(buytxt, order.executed.dt)
                else:
                    selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                    self.log(selltxt, order.executed.dt)
    
            elif order.status in [order.Expired, order.Canceled, order.Margin]:
                self.log('%s ,' % order.Status[order.status])
                pass  # Simply log
    
            # Allow new orders
            self.orderid = None
    
        def __init__(self):
            # To control operation entries
            self.orderid = None
    
            # Create SMA on 2nd data
            sma = btind.MovAv.SMA(self.data1, period=self.p.period)
            # Create a CrossOver Signal from close an moving average
            self.signal = btind.CrossOver(self.data1.close, sma)
    
        def next(self):
            if self.orderid:
                return  # if an order is active, no new orders are allowed
    
            if self.p.printout:
                print('Self  len:', len(self))
                print('Data0 len:', len(self.data0))
                print('Data1 len:', len(self.data1))
                print('Data0 len == Data1 len:',
                      len(self.data0) == len(self.data1))
    
                print('Data0 dt:', self.data0.datetime.datetime())
                print('Data1 dt:', self.data1.datetime.datetime())
    
            if not self.position:  # not yet in market
                if self.signal > 0.0:  # cross upwards
                    self.log('BUY CREATE , %.2f' % self.data1.close[0])
                    self.buy(size=self.p.stake)
                    self.buy(data=self.data1, size=self.p.stake)
    
            else:  # in the market
                if self.signal < 0.0:  # crosss downwards
                    self.log('SELL CREATE , %.2f' % self.data1.close[0])
                    self.sell(size=self.p.stake)
                    self.sell(data=self.data1, size=self.p.stake)
    
        def stop(self):
            print('==================================================')
            print('Starting Value - %.2f' % self.broker.startingcash)
            print('Ending   Value - %.2f' % self.broker.getvalue())
            print('==================================================')
    
    
    def runstrategy():
        args = parse_args()
    
        # Create a cerebro
        cerebro = bt.Cerebro()
    
        # Get the dates from the args
        fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
        todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
    
        # Create the 1st data
        data0 = btfeeds.YahooFinanceCSVData(
            dataname=args.data0,
            fromdate=fromdate,
            todate=todate)
    
        # Add the 1st data to cerebro
        cerebro.adddata(data0)
    
        # Create the 2nd data
        data1 = btfeeds.YahooFinanceCSVData(
            dataname=args.data1,
            fromdate=fromdate,
            todate=todate)
    
        # Add the 2nd data to cerebro
        cerebro.adddata(data1)
    
        # Add the strategy
        cerebro.addstrategy(MultiDataStrategy,
                            period=args.period,
                            stake=args.stake)
    
        # Add the commission - only stocks like a for each operation
        cerebro.broker.setcash(args.cash)
    
        # Add the commission - only stocks like a for each operation
        cerebro.broker.setcommission(commission=args.commperc)
    
        # And run it
        cerebro.run(runonce=not args.runnext,
                    preload=not args.nopreload,
                    oldsync=args.oldsync)
    
        # Plot if requested
        if args.plot:
            cerebro.plot(numfigs=args.numfigs, volume=False, zdown=False)
    
    
    def parse_args():
        parser = argparse.ArgumentParser(description='MultiData Strategy')
    
        parser.add_argument('--data0', '-d0',
                            default='../../datas/orcl-1995-2014.txt',
                            help='1st data into the system')
    
        parser.add_argument('--data1', '-d1',
                            default='../../datas/yhoo-1996-2014.txt',
                            help='2nd data into the system')
    
        parser.add_argument('--fromdate', '-f',
                            default='2003-01-01',
                            help='Starting date in YYYY-MM-DD format')
    
        parser.add_argument('--todate', '-t',
                            default='2005-12-31',
                            help='Starting date in YYYY-MM-DD format')
    
        parser.add_argument('--period', default=15, type=int,
                            help='Period to apply to the Simple Moving Average')
    
        parser.add_argument('--cash', default=100000, type=int,
                            help='Starting Cash')
    
        parser.add_argument('--runnext', action='store_true',
                            help='Use next by next instead of runonce')
    
        parser.add_argument('--nopreload', action='store_true',
                            help='Do not preload the data')
    
        parser.add_argument('--oldsync', action='store_true',
                            help='Use old data synchronization method')
    
        parser.add_argument('--commperc', default=0.005, type=float,
                            help='Percentage commission (0.005 is 0.5%%')
    
        parser.add_argument('--stake', default=10, type=int,
                            help='Stake to apply in each operation')
    
        parser.add_argument('--plot', '-p', action='store_true',
                            help='Plot the read data')
    
        parser.add_argument('--numfigs', '-n', default=1,
                            help='Plot using numfigs figures')
    
        return parser.parse_args()
    
    
    if __name__ == '__main__':
        runstrategy()
    
    


  • Check the next bar prices, they will match.
    For example you place order on 1st, you see price "x", however, the order will execute on the next daily bar with its prices.



  • There are two data feeds, ocrl and yhoo, the 1st day orders are created on both datas, when the 2nd day, the orders are completed. However, the executed price for yhoo, is right, exactly the open price of the next daily bar, but the executed price for ocrl, I can not find out where does it come from... CAN NOT MATCH PRICES FROM ANY DAY!!!



  • YahooFinanceCSVData data feed provides adjusted prices to bt with the default settings. For ORCL on 2/12/2003 it will be the following price:

    10.229 / 11.5 * 11.82 = 10.514
    

    which is what bt logged.



  • Yes, that's right now~


Log in to reply
 

});