A further update. I've simplified it further. the order is now being cancelled as it should. The execution is also fine bar one last problem. If the bar where the trade gets entered also hits the target, it doesn't execute the buy and sell on the same bar. I don't see how this can be achieved.
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)
# cerebro.adddata(data)
# Add a FixedSize sizer according to the stake
cerebro.addsizer(bt.sizers.PercentSizer, percents=5000)
#Add Analyzer
cerebro.addanalyzer(bt.analyzers.PyFolio)
cerebro.broker.setcommission(commission=0.0,leverage=500)
# Set our desired cash start
cerebro.broker.setcash(1000000.0)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
HG = cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
below is a copy of the log again. It should sell 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: 49324578, Comm 0.00
2020-08-12 06:30, SELL EXECUTED, Price: 1.17203, Cost: 49324578, Comm 0.00
2020-08-12 06:30, Order Canceled/Margin/Rejected
2020-08-12 06:30, OPERATION PROFIT, GROSS 7576.41679, NET 7576.41679