Problem with bt.sizers.FixedSize, when stake is an integar larger than 3
-
When I try the order-history.py in the samples distributed with the source code, a problem occurs.
The code is as follows:
import backtrader as bt ORDER_HISTORY = ( ('2005-02-01', 1, 2984.63), ('2005-03-04', -1, 3079.93), ('2005-03-08', 1, 3113.82), ('2005-03-22', -1, 3040.55), ) class St(bt.Strategy): params = dict( ) def notify_order(self, order): if not order.alive(): print(','.join(str(x) for x in (self.data.num2date(order.executed.dt).date(), order.executed.size * 1 if order.isbuy() else -1, order.executed.price))) def notify_trade(self, trade): if trade.isclosed: print('profit {}'.format(trade.pnlcomm)) def __init__(self): print('Creating Empty Strategy') pass def next(self): pass def runstrat(): cerebro = bt.Cerebro() data0 = bt.feeds.BacktraderCSVData(dataname='../../datas/2005-2006-day-001.txt') cerebro.adddata(data0) cerebro.broker.setcash(5000000000.0) # Broker cerebro.broker = bt.brokers.BackBroker() # Sizer cerebro.addsizer(bt.sizers.FixedSize) # Strategy cerebro.addstrategy(St) cerebro.add_order_history(ORDER_HISTORY, notify=True) cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Months) cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years) cerebro.addanalyzer(bt.analyzers.TradeAnalyzer) # Execute cerebro.run() # cerebro.plot() if __name__ == '__main__': runstrat()
the corresponding outputs:
Creating Empty Strategy 2005-02-01,1,2984.63 2005-03-04,-1,3079.93 profit 95.29999999999973 2005-03-08,1,3113.82 2005-03-22,-1,3040.55 profit -73.26999999999998
Everything are OK now. But when I change the ORDER_HISTORY, problems occurs:
ORDER_HISTORY = ( ('2005-02-01', 2, 2984.63), ('2005-03-04', -2, 3079.93), ('2005-03-08', 1, 3113.82), ('2005-03-22', -1, 3040.55), ) 'The profit of each trade is right, but the size of the close(sell) order is WRONG!' 'The output:' Creating Empty Strategy 2005-02-01,2,2984.63 2005-03-04,-1,3079.93 profit 190.59999999999945 2005-03-08,1,3113.82 2005-03-22,-1,3040.55 profit -73.26999999999998
When stake is larger than 3, things will be even worse:
ORDER_HISTORY = ( ('2005-02-01', 4, 2984.63), ('2005-03-04', -4, 3079.93), ('2005-03-08', 1, 3113.82), ('2005-03-22', -1, 3040.55), ) 'The size of the buy will always be 0, and that of the close(sell) orders will always be -1!' 'Profit of each trade is missing!' 'The output:' Creating Empty Strategy 2005-02-01,0,0.0 2005-03-04,-1,3079.93 2005-03-08,1,3113.82 2005-03-22,-1,3040.55
What's the Problem?
Additionally, to check if the problem relates to the cerebro.add_order_history(ORDER_HISTORY, notify=True) function, the samples with a normal SmaCross strategy is also tested. The results show that, when using the function cerebro.addsizer(bt.sizers.FixedSize, stake=3), when stake is an integar larger than 3, similar problem also occurs.
The code:
import backtrader as bt class SmaCross(bt.SignalStrategy): params = dict(sma1=10, sma2=20) def notify_order(self, order): if not order.alive(): print(','.join(str(x) for x in (self.data.num2date(order.executed.dt).date(), order.executed.size * 1 if order.isbuy() else -1, order.executed.price))) def notify_trade(self, trade): if trade.isclosed: print('profit {}'.format(trade.pnlcomm)) def __init__(self): print('Creating Signal Strategy') sma1 = bt.ind.SMA(period=self.params.sma1) sma2 = bt.ind.SMA(period=self.params.sma2) crossover = bt.ind.CrossOver(sma1, sma2) self.signal_add(bt.SIGNAL_LONG, crossover) def runstrat(): cerebro = bt.Cerebro() data0 = bt.feeds.BacktraderCSVData(dataname='../../datas/2005-2006-day-001.txt') cerebro.adddata(data0) cerebro.broker.setcash(5000000000.0) # Broker cerebro.broker = bt.brokers.BackBroker() # Sizer cerebro.addsizer(bt.sizers.FixedSize, stake=3) # Strategy cerebro.addstrategy(SmaCross) cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Months) cerebro.addanalyzer(bt.analyzers.TimeReturn, timeframe=bt.TimeFrame.Years) cerebro.addanalyzer(bt.analyzers.TradeAnalyzer) # Execute cerebro.run() # cerebro.plot() if __name__ == '__main__': runstrat()
The output:
Creating Signal Strategy 2005-02-01,3,2984.6299999999997 2005-03-04,-1,3079.93 profit 285.90000000000055 2005-03-08,3,3113.82 2005-03-22,-1,3040.5500000000006 profit -219.80999999999995 ...
The profit of each trade is right, but the size of the close(sell) order is WRONG!
when stake=4, the output:
Creating Signal Strategy 2005-02-01,0,0.0 2005-03-08,0,0.0 2005-04-08,0,0.0 2005-05-13,0,0.0
Since using bt.SIGNAL_LONG, the size of the buy will always be 0, no close(sell) orders
when using the bt.SIGNAL_LONGSHORT signal, similar results occurs as the order_historyCreating Signal Strategy 2005-02-01,0,0.0 2005-03-04,-1,3079.93 2005-03-08,0,0.0 2005-03-08,4,3113.82 profit -135.5600000000013 2005-03-22,-1,3040.55 2005-04-08,0,0.0 2005-04-08,4,3092.07
The strange thing occurs, no trade is closed, but the profit reports!
-
Problem has been solved!
in the above code, the cash in the broker has been set before the broker has been declared. So, in the newly defined broker, the cash is limited. When stake is large, the order will be rejected due to not enougth cash.
cerebro.broker = bt.brokers.BackBroker() cerebro.broker.setcash(50000000.0)