Many buy orders are cancelled in the backtests and I cannot find why. Looking at the Writefile log it seems the buy orders are created at the next day's close. In most cases the buy price is in the day's range but still not executed.
I have tried on different assets, different sizes of the data feed, different strategies, with the same result.
Running on Jupyter notebook. I include the code and the log.
Finally I changed the default parameter ('100') in AllInSizerInt() below 100 and it worked. I do not really understand why, I thought the sizer would get the cash position from the broker and adjust the order.
Here is the fix:
''''
python
#Add the sizer. We plan to go 'all in' every time
cerebro.addsizer(bt.sizers.AllInSizerInt, percents = 95)
''''
And here is the original code:
''''
python
#### Import databases
from datetime import datetime
import backtrader as bt
import backtrader.indicators as btind
abspath = '/mypath/'
logfile = 'abs_momentum.csv'
# Create a Strategy
class Abs_momentum(bt.Strategy):
alias = ('Abs_momentum',)
params = (
# period for momentum calculation
('lookback', 252),
('range', 100))
def __init__(self):
# keep track of close price in the series
self.data_close = self.datas[0].close
# keep track of pending orders/buy price/buy commission
self.order = None
self.price = None
self.comm = None
# add a momentum indicator
self.mom = btind.MomentumOsc(self.data_close, \
period = self.p.lookback, \
band = self.p.range)
self.buysig = self.mom
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_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, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
#self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
if not trade.isclosed:
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# do nothing if an order is pending
if self.order:
return
# check if there is already a position
if not self.position:
# buy condition
if self.buysig > 100:
self.log(f'BUY CREATED --- Price: {self.data_close[0]:.2f}')
self.order = self.buy(size = None)
else:
# sell condition
if self.buysig < 100:
self.log(f'SELL CREATED --- Price: {self.data_close[0]:.2f}')
self.order = self.sell(Size = None)
###
#### Download data from Yahoo Finance
data = bt.feeds.YahooFinanceData(dataname= 'SPY', \
fromdate=datetime(2018, 6, 15),\
todate=datetime(2021, 3, 17),\
reverse = False)
####
# create a Cerebro entity
cerebro = bt.Cerebro(stdstats = False)
### Set up the backtest
# Add the Data Feed to Cerebro
cerebro.adddata(data)
# Set our desired cash start
cerebro.broker.setcash(100000.0)
# Set the commission - 0.1% ... divide by 100 to remove the %
cerebro.broker.setcommission(commission=0.001)
#Add the sizer. We plan to go 'all in' every time
cerebro.addsizer(bt.sizers.AllInSizerInt)
#Add the strategy
cerebro.addstrategy(Abs_momentum)
#Add the observers to the plot
cerebro.addobserver(bt.observers.BuySell)
cerebro.addobserver(bt.observers.Value)
#Write to a csv file
cerebro.addwriter(bt.WriterFile, out = (abspath + logfile), csv=True,\ data(csv) = False)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
###
### Plot the results
cerebro.plot(iplot=True, volume=False)
###
''''
Here is the log:
>Starting Portfolio Value: 100000.00
>2019-06-18, BUY CREATED --- Price: 282.95
>2019-06-19, Order Canceled/Margin/Rejected
>2019-06-19, BUY CREATED --- Price: 283.58
>2019-06-20, Order Canceled/Margin/Rejected
>2019-06-20, BUY CREATED --- Price: 286.29
>2019-06-21, Order Canceled/Margin/Rejected
>2019-06-21, BUY CREATED --- Price: 285.88
>2019-06-24, BUY EXECUTED, Price: 286.10, Cost: 99848.90, Comm 99.85
>2020-03-12, SELL CREATED --- Price: 243.56
>2020-03-13, SELL EXECUTED, Price: 258.27, Cost: 99848.90, Comm 90.14
>2020-03-13, OPERATION PROFIT, GROSS -9712.67, NET -9902.66
>2020-04-17, BUY CREATED --- Price: 283.04
>2020-04-20, BUY EXECUTED, Price: 279.06, Cost: 88741.08, Comm 88.74
>2020-04-20, SELL CREATED --- Price: 278.05
>2020-04-21, SELL EXECUTED, Price: 273.25, Cost: 88741.08, Comm 86.89
>2020-04-21, OPERATION PROFIT, GROSS -1847.58, NET -2023.21
>2020-04-29, BUY CREATED --- Price: 289.53
>2020-04-30, Order Canceled/Margin/Rejected
>2020-04-30, BUY CREATED --- Price: 286.83
>2020-05-01, Order Canceled/Margin/Rejected
>2020-05-06, BUY CREATED --- Price: 280.68
>2020-05-07, Order Canceled/Margin/Rejected
>2020-05-07, BUY CREATED --- Price: 284.07
>2020-05-08, Order Canceled/Margin/Rejected
>2020-05-08, BUY CREATED --- Price: 288.77
>2020-05-11, BUY EXECUTED, Price: 286.69, Cost: 87153.76, Comm 87.15
>Final Portfolio Value: 121189.86