Backtesting: How to use today's closing prices to act at tomorrow's market open? #4559
|
I have a look-ahead bias problem while backtesting and I am unsure how to solve it. Strategy
Backtesting
|
Replies: 1 comment
|
With only external daily bars, there is no native “submit after bar N closes, fill at bar N+1 open” mode. The important detail is the backtest event order:
This is why the market order fills at today's close. Adding a small Although A robust approach is to separate signal time from execution time: class MyStrategy(Strategy):
def __init__(self, config):
super().__init__(config)
self.enter_at_next_open = False
self.sma = SimpleMovingAverage(100)
def on_bar(self, bar: Bar):
# This daily bar is complete here; the registered SMA is already updated.
self.enter_at_next_open = bar.close > self.sma.value
def on_trade_tick(self, tick: TradeTick):
if not self.enter_at_next_open:
return
if not self.is_first_regular_session_tick(tick):
return
self.enter_at_next_open = False
order = self.order_factory.market(
instrument_id=tick.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.config.trade_size),
)
self.submit_order(order)Feed a trade/quote tick at the regular-session open (or sufficiently granular intraday data) in addition to the completed daily bars, and replace If your source timestamps daily bars at the session open, also shift If the data set truly contains only one completed OHLC record per day, exact next-open execution cannot be modeled causally by the daily |
With only external daily bars, there is no native “submit after bar N closes, fill at bar N+1 open” mode.
The important detail is the backtest event order:
on_bar(N),This is why the market order fills at today's close. Adding a small
LatencyModeldoes not turn it into a next-open order either: with bar-only data, the next bar's OHLC sweep occurs before the delayed command is drained, so it will generally see the next bar's close. The current bar-execution documentation describes both behaviors and explicitly notes …