@ -261,6 +261,7 @@ class BacktestRunner:
self . _pending_open_exits : dict [ dt . date , list [ dict [ str , Any ] ] ] = defaultdict ( list )
self . _pending_open_exits : dict [ dt . date , list [ dict [ str , Any ] ] ] = defaultdict ( list )
self . _parent_add_on_counts : dict [ str , int ] = defaultdict ( int )
self . _parent_add_on_counts : dict [ str , int ] = defaultdict ( int )
self . _simulation_dates : list [ dt . date ] = [ ]
self . _simulation_dates : list [ dt . date ] = [ ]
self . _last_simulation_date : dt . date | None = None
self . _simulation_date_index : dict [ dt . date , int ] = { }
self . _simulation_date_index : dict [ dt . date , int ] = { }
self . _next_trading_day : dict [ dt . date , dt . date ] = { }
self . _next_trading_day : dict [ dt . date , dt . date ] = { }
self . _dividend_capture_trade_counter : int = 0
self . _dividend_capture_trade_counter : int = 0
@ -562,6 +563,7 @@ class BacktestRunner:
# exits are checked every day, not just on days with new candidates.
# exits are checked every day, not just on days with new candidates.
all_dates = self . _get_simulation_dates ( )
all_dates = self . _get_simulation_dates ( )
self . _simulation_dates = list ( all_dates )
self . _simulation_dates = list ( all_dates )
self . _last_simulation_date = all_dates [ - 1 ] if all_dates else None
self . _simulation_date_index = {
self . _simulation_date_index = {
sim_date : idx for idx , sim_date in enumerate ( self . _simulation_dates )
sim_date : idx for idx , sim_date in enumerate ( self . _simulation_dates )
}
}
@ -1396,7 +1398,11 @@ class BacktestRunner:
risk_amount = investable * invested_fraction
risk_amount = investable * invested_fraction
sgov_amount = investable - risk_amount
sgov_amount = investable - risk_amount
if target_sym != " sgov " :
if target_sym != " sgov " :
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
if park_close and park_close > 0 and risk_amount > = park_close :
if park_close and park_close > 0 and risk_amount > = park_close :
shares = int ( risk_amount / park_close )
shares = int ( risk_amount / park_close )
@ -1440,7 +1446,11 @@ class BacktestRunner:
if self . _fixed_capital_sizing :
if self . _fixed_capital_sizing :
investable = min ( investable , max ( 0.0 , equity_est - reserve ) )
investable = min ( investable , max ( 0.0 , equity_est - reserve ) )
if target_sym == " sgov " :
if target_sym == " sgov " :
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
park_close = macro_data_eod . get ( f " sgov_ { _px_key } " ) or macro_data_eod . get ( " sgov_close " )
park_close = macro_data_eod . get ( f " sgov_ { _px_key } " ) or macro_data_eod . get ( " sgov_close " )
if park_close and park_close > 0 and investable > = park_close :
if park_close and park_close > 0 and investable > = park_close :
new_shares = int ( investable / park_close )
new_shares = int ( investable / park_close )
@ -1459,7 +1469,11 @@ class BacktestRunner:
self . _commit_parking_target ( " sgov " )
self . _commit_parking_target ( " sgov " )
self . _cash - = new_shares * park_close
self . _cash - = new_shares * park_close
else :
else :
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
if park_close and park_close > 0 and investable > = park_close :
if park_close and park_close > 0 and investable > = park_close :
new_shares = int ( investable / park_close )
new_shares = int ( investable / park_close )
@ -1532,7 +1546,11 @@ class BacktestRunner:
)
)
self . _cash - = defensive_amount
self . _cash - = defensive_amount
elif target_sym == " sgov " :
elif target_sym == " sgov " :
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
park_close = macro_data_eod . get ( f " sgov_ { _px_key } " ) or macro_data_eod . get ( " sgov_close " )
park_close = macro_data_eod . get ( f " sgov_ { _px_key } " ) or macro_data_eod . get ( " sgov_close " )
if park_close and park_close > 0 and investable > = park_close :
if park_close and park_close > 0 and investable > = park_close :
new_shares = int ( investable / park_close )
new_shares = int ( investable / park_close )
@ -1561,7 +1579,11 @@ class BacktestRunner:
and self . _parking_current_symbol != " tqqq_blend "
and self . _parking_current_symbol != " tqqq_blend "
) :
) :
w_qqqm , w_tqqq = self . _compute_overlay_blend_weights ( macro_data_eod )
w_qqqm , w_tqqq = self . _compute_overlay_blend_weights ( macro_data_eod )
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
tqqq_close = macro_data_eod . get ( f " tqqq_ { _px_key } " ) or macro_data_eod . get ( " tqqq_close " )
tqqq_close = macro_data_eod . get ( f " tqqq_ { _px_key } " ) or macro_data_eod . get ( " tqqq_close " )
qqqm_close = macro_data_eod . get ( f " qqqm_ { _px_key } " ) or macro_data_eod . get ( " qqqm_close " )
qqqm_close = macro_data_eod . get ( f " qqqm_ { _px_key } " ) or macro_data_eod . get ( " qqqm_close " )
if tqqq_close and tqqq_close > 0 and qqqm_close and qqqm_close > 0 :
if tqqq_close and tqqq_close > 0 and qqqm_close and qqqm_close > 0 :
@ -1608,7 +1630,11 @@ class BacktestRunner:
) :
) :
symbol_investable = investable * bearish_alloc_pct
symbol_investable = investable * bearish_alloc_pct
sgov_amount = investable - symbol_investable
sgov_amount = investable - symbol_investable
_px_key = " close " if self . _had_event_activity_today else " open "
_px_key = (
" open "
if ( self . _last_simulation_date is not None and date == self . _last_simulation_date )
else ( " close " if self . _had_event_activity_today else " open " )
)
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
park_close = macro_data_eod . get ( f " { target_sym } _ { _px_key } " ) or macro_data_eod . get ( f " { target_sym } _close " )
if park_close and park_close > 0 and symbol_investable > = park_close :
if park_close and park_close > 0 and symbol_investable > = park_close :
new_shares = int ( symbol_investable / park_close )
new_shares = int ( symbol_investable / park_close )
@ -8301,6 +8327,21 @@ def _extend_store_to_requested_window(
error = str ( exc ) ,
error = str ( exc ) ,
)
)
# Cap _requested_end_date at the last day where parking symbols actually have
# close-price data. SPY/QQQ are fetched as core and settle before QQQM/TQQQ/SGOV,
# which are fetched as extras and can lag Oracle by minutes after market close.
_parking_close_keys = ( " qqqm_close " , " tqqq_close " , " sgov_close " )
_parking_last_dates : list [ dt . date ] = [ ]
for _k in _parking_close_keys :
_sym_dates = [ d for d in store . _macro if store . _macro [ d ] . get ( _k ) ]
if _sym_dates :
_parking_last_dates . append ( max ( _sym_dates ) )
if _parking_last_dates :
_parking_cap = min ( _parking_last_dates )
current_end = getattr ( store , " _requested_end_date " , end_date )
if _parking_cap < current_end :
setattr ( store , " _requested_end_date " , _parking_cap )
# Extend individual stock bars only forward. Needed so open positions and
# Extend individual stock bars only forward. Needed so open positions and
# event entries can still be valued when end_date exceeds snapshot coverage.
# event entries can still be valued when end_date exceeds snapshot coverage.
if store . _bars :
if store . _bars :