Skip to content

feat(phase8): Session 3 — centrality penalty overlay + N=140 factor backtest#6

Merged
shiviancodes merged 1 commit into
mainfrom
feature/phase8-session3
May 17, 2026
Merged

feat(phase8): Session 3 — centrality penalty overlay + N=140 factor backtest#6
shiviancodes merged 1 commit into
mainfrom
feature/phase8-session3

Conversation

@shiviancodes

Copy link
Copy Markdown
Owner

Summary

  • Centrality penalty overlay in build_portfolio(): positions are
    scaled by (1 − 0.30 × centrality_percentile_i), using
    graph_delta_eigenvector z-score rank as the fragility signal.
    Min multiplier 0.70 — no ticker zeroed. Fully backward-compatible.
  • paper_trader.py: graph_gnn_embedding_drift removed from
    _factor_panel dispatch (stale N=30 embeddings distort 110 new tickers);
    _centrality_penalty_df() helper wired into rebalance loop.
  • rolling_registry rebuilt on N=140: 406 rows (58 × 7 factors).
    graph_delta_eigenvector gated out as alpha (negative rolling mean_ic);
    correct — it is a risk overlay, not a return predictor.
  • signal_registry updated for graph_delta_eigenvector:
    t_stat=−3.194 (63d, N=140), status=monitoring, regime_profile records
    fragility-indicator role and sign-flip vs Phase 5.
  • graph_customer_momentum closed permanently: null at all horizons
    (21d t=−1.419, 63d=+0.280, 126d=−0.519, N=1,465 in-universe edges).
  • Phase 8 paper trader: CAGR +5.97%, Sharpe 0.374, Max DD −36.68%
    vs Phase 7A baseline +10.94% / 0.521 / −32.81%. Degradation reflects
    N=140 factor gates correctly classifying more signals as null — extended
    cash periods are the honest consequence, not a regression.

… session 3 research results (127/128 tests passing)

Portfolio construction:
- build_portfolio() gains centrality_penalty + lambda_centrality=0.30 params
  weight_i *= (1 - 0.30 * centrality_percentile_i) before renormalisation
  missing tickers default to percentile=0.5; no ticker zeroed (min mult 0.70)
- 3 new tests; 17/17 pass in test_portfolio.py

Paper trader:
- _centrality_penalty_df() helper: cross-sectional percentile rank of
  graph_delta_eigenvector z-score at each rebalance date
- graph_gnn_embedding_drift popped from _factor_panel dispatch — stale
  N=30 embeddings distort z-scores for 110 new tickers at N=140
- Rebalance loop wired to pass centrality_penalty into build_portfolio

Registry / rolling:
- scripts/update_registry_phase8.py: idempotent UPDATE for
  graph_delta_eigenvector (t_stat=-3.194, status=monitoring,
  regime_profile records fragility-indicator role and N=140 findings)
- rolling_registry rebuilt: 406 rows (58 dates x 7 factors, N=140)

Research:
- research/phase8_backtest.py: multi-horizon IC backtest (21d/63d/126d)
  on 140-ticker universe; excludes gnn_embedding_drift; includes
  graph_customer_momentum; regime splits for |t|>1.5
- Key findings: Phase 5 t-stats were N=30 artifacts (momentum_12_1
  126d: 4.149->1.506); graph_delta_eigenvector sign-flipped to t=-3.194
  at 63d; graph_customer_momentum definitively null at all horizons

Phase 8 paper trader: CAGR +5.97%, Sharpe 0.374, Max DD -36.68%
vs Phase 7A baseline CAGR +10.94%, Sharpe 0.521, Max DD -32.81%.
Degradation driven by N=140 factor gates correctly classifying more
signals as null, producing extended cash periods (100% cash Sep-Dec 2025).
@shiviancodes shiviancodes merged commit 00c1e12 into main May 17, 2026
1 check passed
@shiviancodes shiviancodes deleted the feature/phase8-session3 branch May 17, 2026 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant