for simple MA crossover strategy, when an order is created, if the next bar triggers the entry but simultaneously hits the target, it will only execute the entry and then exit the bar after that on the open. I can't figure it out. I've been trying different order types but I haven't been able to change the behavior. I've experimented with cheat on open but that didn't get me anywhere
class Order_testing(bt.Strategy):
params = dict(
pfast=10, # period for the fast moving average
pslow=30 # period for the slow moving average
)
def log(self, txt, dt=None):
''' Logging function for this strategy'''
dt = dt or self.datas[0].datetime.datetime(0)
print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))
def __init__(self):
sma1 = bt.ind.SMA(period=self.p.pfast) # fast moving average
sma2 = bt.ind.SMA(period=self.p.pslow) # slow moving average
self.crossover = bt.ind.CrossOver(sma1, sma2) # crossover signal
# To keep track of pending orders and buy price/commission
self.order = None
self.buyprice = None
self.buycomm = None
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: %.5f, Cost: %.f, 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: %.5f, Cost: %.f, 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 %.5f, NET %.5f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# Check if an order is pending ... if yes, we cannot send a 2nd one
if self.order:
if self.order.status == 2 and len(self) == self.bar_order_submitted + 1:
self.broker.cancel(self.order)
self.log("order was cancelled")
# Check if we are in the market
if not self.position:
# Not yet ... we MIGHT BUY if ...
if self.crossover > 0: # if fast crosses slow to the upside
self.order = self.buy(exectype=bt.Order.StopLimit, price=self.data.high[0], transmit=False)
self.StopLoss = self.sell(price=self.data.low[0],exectype=bt.Order.Stop,
transmit=False, size=self.order.size,parent=self.order)
self.target = self.sell(price=(self.data.high[0]-self.data.low[0])*1.1+self.data.high[0], exectype=bt.Order.Limit,
transmit=True, size=self.order.size, parent=self.order)
self.bar_order_submitted = len(self)
self.log('BUY CREATE, %.5f' % self.order.price)
self.log('SL: %.5f, T: %.5f' %(self.StopLoss.price,self.target.price))
if __name__ == '__main__':
cerebro = bt.Cerebro()
# Add a strategy
cerebro.addstrategy(Order_testing)
# Create a Data Feed
data = bt.feeds.PandasData(dataname=df2020)
one_minute = cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=1)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
log for reference. it should both execute the buy and sell order at 06:29
2020-08-12 06:28, BUY CREATE, 1.17185
2020-08-12 06:28, SL: 1.17171, T: 1.17200
2020-08-12 06:29, BUY EXECUTED, Price: 1.17185, Cost: 1, Comm 0.00
2020-08-12 06:30, SELL EXECUTED, Price: 1.17203, Cost: 1, Comm 0.00
2020-08-12 06:30, Order Canceled/Margin/Rejected
2020-08-12 06:30, OPERATION PROFIT, GROSS 0.00018, NET 0.00018