For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/
Incorrect datetime execution or time zone handlind
-
I noticed that accepted orders and executed orders differ in time for more than 6 hours.
Could you please tell me what can be wrong with my example?
Backtrader version is the latest, installed yesterday.
Datasample is 2006-min-005.txt downloaded from herefrom __future__ import (absolute_import, division, print_function, ) # unicode_literals) import argparse import datetime import backtrader as bt import backtrader.feeds as btfeeds import pytz mytimezone = pytz.timezone('US/Eastern') mytimezone2 = pytz.timezone('Europe/Kiev') class St(bt.Strategy): def __init__(self): self.curdate = datetime.date.min self.last_order_status_name = 'None' self.last_position_size = 0 self.elapsed = 0 self.order = None def notify_order(self, order): curdtstr = self.data.datetime.datetime().strftime('%a %Y-%m-%d %H:%M:%S') if order.status in [order.Completed] or True: if order.isbuy(): if order.executed.dt is not None: dtstr = bt.num2date(order.executed.dt).strftime('%a %Y-%m-%d %H:%M:%S') print('{}: BUY EXECUTED, on: {}, dt {}'.format(curdtstr, dtstr, order.executed.dt)) self.order = None else: dtstr = bt.num2date(order.created.dt).strftime('%a %Y-%m-%d %H:%M:%S') print('{}: BUY {}, on: {}, dt {}'.format(curdtstr, order.getstatusname(), dtstr, order.created.dt)) else: if order.executed.dt is not None: # Sell dtstr = bt.num2date(order.executed.dt).strftime('%a %Y-%m-%d %H:%M:%S') print('{}: SELL EXECUTED, on: {}, dt {}'.format(curdtstr, dtstr, order.executed.dt)) def next(self): curdate = self.data.datetime.datetime() if self.curdate == datetime.date.min: self.curdate = curdate return if curdate.weekday() != 0: self.elapsed = 0 return is_order_or_position_changed = self.last_position_size != self.position.size if not is_order_or_position_changed and self.order: is_order_or_position_changed = self.order.getstatusname() != self.last_order_status_name dtstr = self.data.datetime.datetime().strftime('%a %Y-%m-%d %H:%M:%S') difference: datetime = curdate - self.curdate seconds = difference.total_seconds() hours = seconds // 3600 minutes = (seconds % 3600) // 60 seconds = seconds % 60 # if curdate > self.curdate: # self.elapsed += 1 # self.curdate = curdate if minutes: self.elapsed += minutes order_status = 'None' if self.order: order_status = self.order.getstatusname() if is_order_or_position_changed: print('{}: elapsedh: {:.2f}, current hour: {}, self.order.status {}, position {}'.format(dtstr, self.elapsed / 60, curdate.hour, order_status, self.position.size)) dtstr = self.data.datetime.datetime().strftime('%a %Y-%m-%d %H:%M:%S') if self.position.size > 0 and self.order is None and int(self.elapsed / 60) > 6: print('%s: SELL CREATED' % dtstr) self.close(exectype=bt.Order.Close) self.elapsed = 0 elif self.order is None and curdate.hour < 12 and self.position.size == 0: # no pending order print('%s: BUY CREATED' % dtstr) self.order = self.buy(exectype=bt.Order.Close) self.elapsed = 0 self.curdate = curdate self.last_position_size = self.position.size if self.order: self.last_order_status_name = self.order.getstatusname() else: self.last_order_status_name = 'None' def runstrat(): args = parse_args() cerebro = bt.Cerebro() data = getdata(args) cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=30) cerebro.addstrategy(St) if args.eosbar: cerebro.broker.seteosbar(True) cerebro.run() cerebro.plot(style='candlestick', volume=False) def getdata(args): dataformat = dict( bt=btfeeds.BacktraderCSVData, visualchart=btfeeds.VChartCSVData, sierrachart=btfeeds.SierraChartCSVData, yahoo=btfeeds.YahooFinanceCSVData, yahoo_unreversed=btfeeds.YahooFinanceCSVData, tz=mytimezone ) dfkwargs = dict() if args.csvformat == 'yahoo_unreversed': dfkwargs['reverse'] = True if args.fromdate: fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d') dfkwargs['fromdate'] = fromdate if args.todate: todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d') dfkwargs['todate'] = todate if args.tend is not None: # internally only the "time" part is used dfkwargs['sessionend'] = datetime.datetime.strptime(args.tend, '%H:%M') dfkwargs['dataname'] = args.infile dfcls = dataformat[args.csvformat] data = dfcls(**dfkwargs) return data def parse_args(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='Sample for Close Orders with daily data') parser.add_argument('--infile', '-i', required=False, default='2006-min-005.txt', help='File to be read in') parser.add_argument('--csvformat', '-c', required=False, default='bt', choices=['bt', 'visualchart', 'sierrachart', 'yahoo', 'yahoo_unreversed'], help='CSV Format') parser.add_argument('--fromdate', '-f', required=False, default=None, help='Starting date in YYYY-MM-DD format') parser.add_argument('--todate', '-t', required=False, default=None, help='Ending date in YYYY-MM-DD format') parser.add_argument('--eosbar', required=False, action='store_true', help=('Consider a bar with the end of session time to' 'be the end of the session')) parser.add_argument('--tend', '-te', default=None, required=False, help='End time for the Session Filter (HH:MM)') return parser.parse_args() if __name__ == '__main__': runstrat()
App output:
Mon 2006-01-02 10:00:00: BUY CREATED Mon 2006-01-02 10:30:00: BUY Submitted, on: Mon 2006-01-02 10:00:00, dt 732313.4166666666 Mon 2006-01-02 10:30:00: BUY Accepted, on: Mon 2006-01-02 10:00:00, dt 732313.4166666666 Mon 2006-01-02 10:30:00: elapsedh: 0.50, current hour: 10, self.order.status Accepted, position 0 Tue 2006-01-03 09:30:00: BUY EXECUTED, on: Mon 2006-01-02 17:30:00, dt 732313.7291666666 Mon 2006-01-09 09:30:00: elapsedh: 0.00, current hour: 9, self.order.status None, position 1 Mon 2006-01-09 16:30:00: SELL CREATED Tue 2006-01-10 09:30:00: SELL EXECUTED, on: Mon 2006-01-09 17:30:00, dt 732320.7291666666 Mon 2006-01-16 09:30:00: elapsedh: 0.00, current hour: 9, self.order.status None, position 0 Mon 2006-01-16 09:30:00: BUY CREATED Mon 2006-01-16 10:00:00: BUY Submitted, on: Mon 2006-01-16 09:30:00, dt 732327.3958333334 Mon 2006-01-16 10:00:00: BUY Accepted, on: Mon 2006-01-16 09:30:00, dt 732327.3958333334 Mon 2006-01-16 10:00:00: elapsedh: 0.50, current hour: 10, self.order.status Accepted, position 0 Tue 2006-01-17 09:30:00: BUY EXECUTED, on: Mon 2006-01-16 17:30:00, dt 732327.7291666666 Mon 2006-01-23 09:30:00: elapsedh: 0.00, current hour: 9, self.order.status None, position 1 Mon 2006-01-23 16:30:00: SELL CREATED Tue 2006-01-24 09:30:00: SELL EXECUTED, on: Mon 2006-01-23 17:30:00, dt 732334.7291666666 Mon 2006-01-30 09:30:00: elapsedh: 0.00, current hour: 9, self.order.status None, position 0 Mon 2006-01-30 09:30:00: BUY CREATED Mon 2006-01-30 10:00:00: BUY Submitted, on: Mon 2006-01-30 09:30:00, dt 732341.3958333334 Mon 2006-01-30 10:00:00: BUY Accepted, on: Mon 2006-01-30 09:30:00, dt 732341.3958333334 Mon 2006-01-30 10:00:00: elapsedh: 0.50, current hour: 10, self.order.status Accepted, position 0
-
May be unrelated, but I don't see where you specify the timeframe and compression of the original CSV data (no resampled) in
getdata()
. The CSV seems to have a 5 min bars and if timeframe and compression are not set, the default is assumed, which is daily bars AFAIK.