chore: backtest engine fee model, metrics, and strategy fixes

- main.py: add IBKR-style tiered fee schedule (fee_base + fee_per_share),
  PIT universe support, and open-to-close execution improvements
- metrics.py: add raw_summary helper for JSON-safe metric export
- Misc strategy fixes: deprecation warnings, NaN handling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 20:57:56 +08:00
parent 1f50253d13
commit 149a00c458
7 changed files with 154 additions and 74 deletions

View File

@@ -89,11 +89,13 @@ class TrendRiderV6(TrendRiderV5):
def _resolve_universe(self, prices: pd.DataFrame) -> list[str]:
if self.stock_universe is not None:
return [s for s in self.stock_universe if s in prices.columns]
# Heuristic: stocks are columns NOT in our known ETF/leveraged set
non_stock = (set(self.core_equity)
| set(self.leveraged_equity)
# Heuristic: stocks are columns NOT in our known ETF/leveraged set.
# We inherit V3's risk_on (e.g. TQQQ/UPRO) and risk_off (GLD/DBC),
# plus V6's risk_off_basket + moderate_anchor + signal + overlay sym.
non_stock = (set(self.risk_on)
| set(self.risk_off)
| {self.signal, *self.risk_off_basket, self.moderate_anchor})
| {self.signal, self.moderate_anchor,
self.leverage_overlay_symbol, *self.risk_off_basket})
return [c for c in prices.columns if c not in non_stock]
def _stock_top_n_weights(self, prices: pd.DataFrame, universe: list[str]) -> pd.DataFrame: