BackTrader, algorithm, buy if price decreasing
-
In result, didn't print self.dataclose[-2], can not identify it
if self.datastatus and len(self.orderid) < 1: print('0 STEPPP') if self.dataclose[0] < self.dataclose[-1]: print("1 Step", self.dataclose[0], self.dataclose[-1]) if self.dataclose[-1] < self.dataclose[-2]: print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES") # 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: print("NOOO")
-
What is your question? There isn't a print statement for dataclose[-2].
-
if self.dataclose[-1] < self.dataclose[-2]:
self.dataclose[-2] can not identify it -
I'd suggest to show all your code. If the example is long, try to eliminate parts that are not required to repro the error. Also, include the exact error message.
-
from future import (absolute_import, division, print_function,
unicode_literals)import datetime # For datetime objects
import os.path # To manage paths
import sys # To find out the script name (in argv[0])import argparse
import datetime
import backtrader as btfrom backtrader.utils import flushfile
Create a Stratey
class TestStrategy(bt.Strategy): params = dict( # smaperiod=5, trade=False, stake=10, exectype=bt.Order.Market, stopafter=0, valid=None, upper=2.1, cancel=0, donotsell=False, ) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.orderid = list() self.order = None self.dataclose = self.datas[0].close self.upper_limit = self.p.upper # self.counttostop = 0 self.datastatus = 0 self.bar_executed = 0 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 notify_data(self, data, status, *args, **kwargs): print('*' * 5, 'DATA NOTIF:', data._getstatusname(status), *args) if status == data.LIVE: # self.counttostop = self.p.stopafter self.datastatus = 1 def notify_store(self, msg, *args, **kwargs): print('*' * 5, 'STORE NOTIF:', msg) def notify_order(self, order): if order.status in [order.Completed, order.Cancelled, order.Rejected]: self.order = None # 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) print('-' * 50, 'ORDER BEGIN', datetime.datetime.now()) print(order) print('-' * 50, 'ORDER END') # 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): print('-' * 50, 'TRADE BEGIN', datetime.datetime.now()) print(trade) print('-' * 50, 'TRADE END') def prenext(self): self.next(frompre=True) def next(self, frompre=False): # Simply log the closing price of the series from the reference txt = list() txt.append('%04d' % len(self)) dtfmt = '%Y-%m-%dT%H:%M:%S.%f' txt.append('%s' % self.data.datetime.datetime(0).strftime(dtfmt)) txt.append('{}'.format(self.data.close[0])) txt.append('{}'.format(self.data.close[-1])) print(', '.join(txt)) # if len(self.datas) > 1: # txt = list() # txt.append('%04d' % len(self)) # dtfmt = '%Y-%m-%dT%H:%M:%S.%f' # txt.append('%s' % self.data1.datetime.datetime(0).strftime(dtfmt)) # txt.append('{}'.format(self.data1.close[0])) # # txt.append('{}'.format(self.data.close[-1])) # # txt.append('{}'.format(self.data.close[-2])) # txt.append('{}'.format(float('NaN'))) # print(', '.join(txt)) # if self.counttostop: # stop after x live lines # self.counttostop -= 1 # if not self.counttostop: # self.env.runstop() # return if not self.p.trade: return if self.datastatus and len(self.orderid) < 1: print('0 STEPPP') if self.dataclose[0] < self.dataclose[-1]: print("1 Step", self.dataclose[0], self.dataclose[-1]) if self.dataclose[-1] < self.upper_limit: print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES") # 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: print("NOOO") # elif self.position.size > 0 and not self.p.donotsell: # if self.order is None: # self.order = self.sell(size=self.p.stake // 2, # exectype=bt.Order.Market, # price=self.data0.close[0]) # self.cancel(self.order) # elif self.order is not None and self.p.cancel: # if self.datastatus > self.p.cancel: # self.cancel(self.order) if self.datastatus: self.datastatus += 1 def start(self): if self.data0.contractdetails is not None: print('Timezone from ContractDetails: {}'.format( self.data0.contractdetails.m_timeZoneId)) # # header = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume', # 'OpenInterest'] header = ['Datetime', 'Close'] print(', '.join(header)) self.done = False
def runstrategy():
args = parse_args()# Create a cerebro cerebro = bt.Cerebro() storekwargs = dict( host=args.host, port=args.port, clientId=args.clientId, timeoffset=not args.no_timeoffset, reconnect=args.reconnect, timeout=args.timeout, notifyall=args.notifyall, _debug=args.debug ) if args.usestore: ibstore = bt.stores.IBStore(**storekwargs) if args.broker: if args.usestore: broker = ibstore.getbroker() else: broker = bt.brokers.IBBroker(**storekwargs) cerebro.setbroker(broker) timeframe = bt.TimeFrame.TFrame(args.timeframe) if args.resample or args.replay: datatf = bt.TimeFrame.Ticks datacomp = 1 else: datatf = timeframe datacomp = args.compression fromdate = None if args.fromdate: dtformat = '%Y-%m-%d' + ('T%H:%M:%S' * ('T' in args.fromdate)) fromdate = datetime.datetime.strptime(args.fromdate, dtformat) IBDataFactory = ibstore.getdata if args.usestore else bt.feeds.IBData datakwargs = dict( timeframe=datatf, compression=datacomp, historical=args.historical, fromdate=fromdate, rtbar=args.rtbar, qcheck=args.qcheck, what=args.what, backfill_start=not args.no_backfill_start, backfill=not args.no_backfill, latethrough=args.latethrough, tz=args.timezone ) if not args.usestore and not args.broker: # neither store nor broker datakwargs.update(storekwargs) # pass the store args over the data data0 = IBDataFactory(dataname=args.data0, **datakwargs) data1 = None if args.data1 is not None: data1 = IBDataFactory(dataname=args.data1, **datakwargs) rekwargs = dict( timeframe=timeframe, compression=args.compression, bar2edge=not args.no_bar2edge, adjbartime=not args.no_adjbartime, rightedge=not args.no_rightedge, takelate=not args.no_takelate, ) if args.replay: cerebro.replaydata(dataname=data0, **rekwargs) if data1 is not None: cerebro.replaydata(dataname=data1, **rekwargs) elif args.resample: cerebro.resampledata(dataname=data0, **rekwargs) if data1 is not None: cerebro.resampledata(dataname=data1, **rekwargs) else: cerebro.adddata(data0) if data1 is not None: cerebro.adddata(data1) if args.valid is None: valid = None else: datetime.timedelta(seconds=args.valid) # Add the strategy cerebro.addstrategy(TestStrategy, # smaperiod=args.smaperiod, trade=args.trade, exectype=bt.Order.ExecType(args.exectype), stake=args.stake, stopafter=args.stopafter, valid=valid, cancel=args.cancel, donotsell=args.donotsell) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Live data ... avoid long data accumulation by switching to "exactbars" cerebro.run(exactbars=args.exactbars) # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) if args.plot and args.exactbars < 1: # plot if possible cerebro.plot()
def parse_args():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='Test Interactive Brokers integration')parser.add_argument('--exactbars', default=1, type=int, required=False, action='store', help='exactbars level, use 0/-1/-2 to enable plotting') parser.add_argument('--plot', required=False, action='store_true', help='Plot if possible') parser.add_argument('--stopafter', default=0, type=int, required=False, action='store', help='Stop after x lines of LIVE data') parser.add_argument('--usestore', required=False, action='store_true', help='Use the store pattern') parser.add_argument('--notifyall', required=False, action='store_true', help='Notify all messages to strategy as store notifs') parser.add_argument('--debug', required=False, action='store_true', help='Display all info received form IB') parser.add_argument('--host', default='127.0.0.1', required=False, action='store', help='Host for the Interactive Brokers TWS Connection') parser.add_argument('--qcheck', default=0.5, type=float, required=False, action='store', help=('Timeout for periodic ' 'notification/resampling/replaying check')) parser.add_argument('--port', default=7496, type=int, required=False, action='store', help='Port for the Interactive Brokers TWS Connection') parser.add_argument('--clientId', default=None, type=int, required=False, action='store', help='Client Id to connect to TWS (default: random)') parser.add_argument('--no-timeoffset', required=False, action='store_true', help=('Do not Use TWS/System time offset for non ' 'timestamped prices and to align resampling')) parser.add_argument('--reconnect', default=3, type=int, required=False, action='store', help='Number of recconnection attempts to TWS') parser.add_argument('--timeout', default=3.0, type=float, required=False, action='store', help='Timeout between reconnection attempts to TWS') parser.add_argument('--data0', default=None, required=True, action='store', help='data 0 into the system') parser.add_argument('--data1', default=None, required=False, action='store', help='data 1 into the system') parser.add_argument('--timezone', default=None, required=False, action='store', help='timezone to get time output into (pytz names)') parser.add_argument('--what', default=None, required=False, action='store', help='specific price type for historical requests') parser.add_argument('--no-backfill_start', required=False, action='store_true', help='Disable backfilling at the start') parser.add_argument('--latethrough', required=False, action='store_true', help=('if resampling replaying, adjusting time ' 'and disabling time offset, let late samples ' 'through')) parser.add_argument('--no-backfill', required=False, action='store_true', help='Disable backfilling after a disconnection') parser.add_argument('--rtbar', default=False, required=False, action='store_true', help='Use 5 seconds real time bar updates if possible') parser.add_argument('--historical', required=False, action='store_true', help='do only historical download') parser.add_argument('--fromdate', required=False, action='store', help=('Starting date for historical download ' 'with format: YYYY-MM-DD[THH:MM:SS]')) # parser.add_argument('--smaperiod', default=5, type=int, # required=False, action='store', # help='Period to apply to the Simple Moving Average') pgroup = parser.add_mutually_exclusive_group(required=False) pgroup.add_argument('--replay', required=False, action='store_true', help='replay to chosen timeframe') pgroup.add_argument('--resample', required=False, action='store_true', help='resample to chosen timeframe') parser.add_argument('--timeframe', default=bt.TimeFrame.Names[0], choices=bt.TimeFrame.Names, required=False, action='store', help='TimeFrame for Resample/Replay') parser.add_argument('--compression', default=1, type=int, required=False, action='store', help='Compression for Resample/Replay') parser.add_argument('--no-takelate', required=False, action='store_true', help=('resample/replay, do not accept late samples ' 'in new bar if the data source let them through ' '(latethrough)')) parser.add_argument('--no-bar2edge', required=False, action='store_true', help='no bar2edge for resample/replay') parser.add_argument('--no-adjbartime', required=False, action='store_true', help='no adjbartime for resample/replay') parser.add_argument('--no-rightedge', required=False, action='store_true', help='no rightedge for resample/replay') parser.add_argument('--broker', required=False, action='store_true', help='Use IB as broker') parser.add_argument('--trade', required=False, action='store_true', help='Do Sample Buy/Sell operations') parser.add_argument('--donotsell', required=False, action='store_true', help='Do not sell after a buy') parser.add_argument('--exectype', default=bt.Order.ExecTypes[0], choices=bt.Order.ExecTypes, required=False, action='store', help='Execution to Use when opening position') parser.add_argument('--stake', default=10, type=int, required=False, action='store', help='Stake to use in buy operations') parser.add_argument('--valid', default=None, type=int, required=False, action='store', help='Seconds to keep the order alive (0 means DAY)') parser.add_argument('--cancel', default=0, type=int, required=False, action='store', help=('Cancel a buy order after n bars in operation,' ' to be combined with orders like Limit')) return parser.parse_args()
if name == 'main':
runstrategy() -
In the script you shown
self.dataclose[-2]
is not called. Also please use ``` to block the code, will be easier to review. Would be nice to see short version which generates the problem as @scottz1 proposed. -
To check these statements, I tried to use like print("0 STEPPP"), and in result, it printed only
0 and 1 Step, but 2 step it is correct and does not printed ("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES").
I checked when I wrote print(self.dataclose[-2]) it is printed today's valueif self.datastatus and len(self.orderid) < 1: print('0 STEPPP') if self.dataclose[0] < self.dataclose[-1]: print("1 Step", self.dataclose[0], self.dataclose[-1]) if self.dataclose[-1] < self.dataclose[-2]: print("YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES") # 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: print("NOOO")
-
@YELNAr you use two different scripts in this post. One of them uses
dataclose[-2]
and one don't. Would you be so kind and post the script which causes the problem. But removed from that script all un-necessary parts. -
@YELNAr said in BackTrader, algorithm, buy if price decreasing:
def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.orderid = list() self.order = None self.dataclose = self.datas[0].close self.upper_limit = self.p.upper # self.counttostop = 0 self.datastatus = 0 self.bar_executed = 0
Your
__init__
statement contain no indicators and no constraints to ensure buffers are filled with a minimum. This means that when you enternext
the first time anything which uses[-1]
and[-2]
is actually broken, because the minimum period is1
, which means the code goes directly intonext
as soon as data is available.My recommendation: learn backtesting loading data from a file and not playing with InteractiveBrokers.
In the meanwhile read this about the minimum period: https://www.backtrader.com/docu/operating/