cheat-on-close not working?
-
Hi all. I am fairly new to Backtrader and I am trying to modify the quickstart tutorial to make cheat-on-close work. I have already set cerebro.broker.set_coc(True), but when the strategy runs, the BUY/SELL orders are still executed on the next day, not the current day close. What did I do wrong?
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 the backtrader platform import backtrader as bt # Create a Stratey class TestStrategy(bt.Strategy): params = ( ('maperiod', 15), ) def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Add a MovingAverageSimple indicator self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.maperiod) # Add a RSI2 indicator self.rsi2 = bt.indicators.RelativeStrengthIndex( self.datas[0], period=2 ) # Add a RSI4 indicator self.rsi4 = bt.indicators.RelativeStrengthIndex( self.datas[0], period=4 ) 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): # Simply log the closing price of the series from the reference self.log('Close, %.2f, RSI2, %.2f' % (self.dataclose[0], self.rsi2[0])) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... # if self.dataclose[0] > self.sma[0]: if self.rsi2 < 10: # BUY, BUY, BUY!!! (with all possible 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(exectype=bt.Order.Close) else: # if self.dataclose[0] < self.sma[0]: if self.rsi2 > 90: # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.sell(bt.Order.Close) if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(TestStrategy) # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere modpath = os.path.dirname(os.path.abspath(sys.argv[0])) datapath = os.path.join(modpath, 'datas\\MSFT.csv') # Create a Data Feed data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2020, 1, 1), # Do not pass values before this date todate=datetime.datetime(2020, 12, 31), # Do not pass values after this date reverse=False) # 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) # Set cheat-on-close cerebro.broker.set_coc(True) # 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 result cerebro.plot()
2020-09-08, BUY CREATE, 202.66 2020-09-09, BUY EXECUTED, Price: 211.29, Cost: 211.29, Comm 0.21
-
In case of
cheat-on-close
the order notification comes on the next bar, but the execution price should be the theclose
of the bar when the order was issued. -
@ab_trader In my case, cheat-on-close is set to True, but the order.executed.price still is the next bar open price, rather than curr bar close price.
-
@ab_trader Hi, I'm working with coc, and read this thread. Is it not possible to have the order notification with cheat on close to allign with the order executation date?