fix(backtest): settle delisted US holdings (engine v3), PIT membership before 2011, registry causality test

- execution/trader: a held US stock with no print for 5 sessions that has left
  the index is sold at its last print (execution.SETTLE_AFTER_SESSIONS), in both
  the batch replay and the live session ledger. Acquired names used to stay at
  their last mark forever: lowrisk_top20 ended 2017-12..2026-10 with 11 of 26
  dead positions, and CAGR rises 1.7-5.5pp once they settle. ENGINE_VERSION
  cash-ledger-pit-v3; the API cache key follows.
- universe_history: current members whose pre-2011 addition the Wikipedia change
  log missed now start at the list page's "Date added" (80 of 94 current members
  added 2001-2010 were open-start, e.g. ISRG, MA, BKNG). Membership from 2016 on
  is unchanged; the research panel cache now keys on the membership intervals.
- research/lab/registered: pure-ETF strategies replay on the ETF panel (they ran
  as all-cash books or crashed); prepare_strategy refuses an ETF strategy that
  lacks its ETF universe.
- research/lab/factors: trend_hzz uses a month's regression betas only from the
  session its forward returns end (short months read 1-2 sessions ahead).
- tests: every registered strategy (US and CN) is truncation-invariant on the
  production signal path; batch and live ledgers settle a delisting identically.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 00:21:49 -07:00
parent a9683b6d1f
commit cd0721eada
12 changed files with 279 additions and 41 deletions

View File

@@ -265,6 +265,7 @@ def main() -> None:
run = simulate_book(targets.loc[days], strat_data.loc[days], initial_capital,
previous_prices=strat_data.ffill().shift(1).loc[days],
volume=panels["volume"].reindex(index=days, columns=strat_data.columns),
member=member.reindex(index=days, columns=strat_data.columns, fill_value=True),
market=args.market, integer_shares=True,
lot_size=100 if args.market == "cn" else 1,
fixed_fee=args.fixed_fee, min_trade_value=50, resize_band=.10)