Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 26 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

![Python 3.11+](https://img.shields.io/badge/Python-3.11%2B-2563eb)
![Research status](https://img.shields.io/badge/status-paper--live_research-d97706)
![Tests](https://img.shields.io/badge/tests-218_passing-0f766e)
![Tests](https://img.shields.io/badge/tests-221_passing-0f766e)
![License](https://img.shields.io/badge/license-MIT-64748b)

The project asks a narrow investment question:
Expand Down Expand Up @@ -227,7 +227,14 @@ visible from the shared decision-close baseline. It reports net return,
SPY-relative return, replacement-only turnover, and rebalance counts under
identical execution assumptions.

[Open the deployed live-forward dashboard →](https://hansun103.github.io/AI-Driven-Portfolio-Optimization-Backtesting-System/)
The deployed monitor now has two linked pages with one shared visual shell:

- [Live Forward Monitor — default view →](https://hansun103.github.io/AI-Driven-Portfolio-Optimization-Backtesting-System/)
- [Horizon Comparison — 5/10/20-session research →](https://hansun103.github.io/AI-Driven-Portfolio-Optimization-Backtesting-System/horizons.html)

The original Stock-level view remains canonical rather than being duplicated
on the horizon page. The two-page contract and evidence boundaries are recorded
in the [dashboard merge design](docs/design/DASHBOARD_TWO_PAGE_MERGE.md).

This monitoring track does not replace the primary horizon-matched 5/10/20
experiment described above. The former one-session fitting workflow remains
Expand Down Expand Up @@ -378,20 +385,29 @@ because they weaken the preferred narrative.
## Known limitations

1. No redesigned 20-session paper-live forecast has matured yet.
2. The strongest portfolio results remain development evidence, not a genuine
2. The strongest repaired historical test covers roughly 2018–2023, not a
full decade. It therefore spans too few independent market regimes for a
durable claim. Extending point-in-time testing toward at least ten years is
a research target, not a guarantee of adequacy: long-window backtests still
require regime analysis, untouched confirmation, and correction for the
number of strategies tried. See
[CFA Institute’s backtesting guidance](https://www.cfainstitute.org/insights/professional-learning/refresher-readings/2026/backtesting-and-simulation)
and the
[deflated-Sharpe discussion of sample length and multiple testing](https://academic.oup.com/jrssig/article/18/6/22/7038278).
3. The strongest portfolio results remain development evidence, not a genuine
untouched confirmation.
3. Public data does not fully solve delisted-security coverage or historical
4. Public data does not fully solve delisted-security coverage or historical
sector classification.
4. The average ranking edge is small and varies materially by year and regime.
5. Sentiment is promising, but coverage, timestamp quality, and causal
5. The average ranking edge is small and varies materially by year and regime.
6. Sentiment is promising, but coverage, timestamp quality, and causal
attribution remain incomplete.
6. The high-recall survival model has not passed its activation gates and
7. The high-recall survival model has not passed its activation gates and
remains a shadow watchlist.
7. Same-close tactical execution is unvalidated without intraday quotes and
8. Same-close tactical execution is unvalidated without intraday quotes and
actual paper or broker fills.
8. Scheduled full top-40 replacement remains under audit; the six-session
9. Scheduled full top-40 replacement remains under audit; the six-session
ablation is too short to activate a freeze or buffer.
9. Static cost assumptions do not establish capacity, taxes, borrow
10. Static cost assumptions do not establish capacity, taxes, borrow
availability, market impact, or partial-fill behavior.

## Research disclaimer
Expand Down
88 changes: 88 additions & 0 deletions docs/design/DASHBOARD_TWO_PAGE_MERGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Two-page dashboard merge design

Status: local proposal awaiting approval. Do not merge or deploy yet.

## Decision

Publish one dashboard product with two real static pages:

| Page | Proposed URL | Responsibility |
| --- | --- | --- |
| Live Forward Monitor | `dashboard.html` | Daily operational evidence, benchmark comparison, stability, the canonical stock-level view, and experiment history |
| Horizon Comparison | `horizons.html` | Horizon-matched 5/10/20-session progress, validation context, model specifications, SHAP explanations, and pipeline health |

Both headers use the same two-option page switcher. The selected page is visually
active. Ordinary links are preferable to a hidden single-page application because
browser back/forward works, each page can fail independently, and GitHub Pages can
serve the files without a runtime.

## Shared stock-level view

The Horizon Comparison page does not implement another portfolio table.

The existing Stock-level view remains the canonical component. Its model selector
will be extended to understand both:

- legacy daily live-forward snapshots; and
- v2 Ridge/XGBoost arms for the 5-, 10-, and 20-session horizons.

An `Inspect stocks` action on a horizon model will link to a URL such as:

```text
dashboard.html?decision=2026-07-29&family=xgb_ranker&horizon=20#stock-level
```

The original page reads those parameters, selects the requested frozen portfolio,
and scrolls to the shared Stock-level view. This avoids divergent filtering,
sorting, return formatting, and holding-level evaluation logic.

## Partial and mature evidence

The horizon page reports three different evidence states without mixing them:

1. **Awaiting entry** — the portfolio is frozen but its next-open entry has not
occurred.
2. **Interim mark** — one or more open-to-open observations exist. The page shows
session progress and the compounded partial return immediately.
3. **Matured label** — the complete 5-, 10-, or 20-session evaluation is available
and may enter the formal prospective comparison.

The page never displays validation return as live return. A zero-session portfolio
is shown as `0 / horizon` and `Awaiting entry`, not as a zero realized return.

## Explainability

Every newly frozen v2 forecast writes `shap_summary.csv`.

- Ridge uses linear SHAP contributions around the current eligible cohort as the
background.
- XGBoost uses exact TreeSHAP contributions from the fitted booster.
- The dashboard publishes mean absolute SHAP, signed mean SHAP, positive
contribution share, method, and explanation-row count.

Each model card contains a collapsed `Show SHAP feature importance` control.
Opening it displays a horizontal importance chart. Old immutable forecasts that
predate this artifact state that SHAP was not captured; coefficients or XGBoost
gain are not relabelled as SHAP.

## Daily refresh contract

The daily pipeline should:

1. refresh data and generate the current snapshots;
2. evaluate all available interim open-to-open observations;
3. evaluate newly matured forecasts;
4. generate SHAP summaries for new horizon snapshots;
5. rebuild `dashboard.html` and `horizons.html`;
6. run public-payload and browser smoke checks; and
7. publish both pages together through the existing GitHub Pages action.

Publishing must be atomic: a cycle should never expose one page with a newer data
contract than the other.

## Approval boundary

The current local Horizon Comparison preview demonstrates the second page. After
approval, the merge work will add the page switcher and v2 arm support to the
original dashboard, generate the final `horizons.html`, update the refresh and
deployment workflows, and then request approval before pushing.
13 changes: 7 additions & 6 deletions site/assets/dashboard.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions site/data/manifest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
{
"schema_version": 2,
"generated_at_utc": "2026-07-29T16:55:17.967215+00:00",
"schema_version": 3,
"generated_at_utc": "2026-07-29T22:29:54.012984+00:00",
"latest_decision_date": "2026-07-28",
"snapshot_count": 17,
"evaluation_count": 14,
"dashboard_sha256": "9d15420d6e5370038763505be97432e381f7a0932cc1aeac953399c030b2185c",
"dashboard_bytes": 546502,
"horizon_dashboard_sha256": "20d6bdaa4d619ecca77441801a4f2e63b93c665822979b278cb490999bd4695a",
"horizon_dashboard_bytes": 66861,
"horizon_forecast_arms": 6,
"source_policy": "sanitized_live_forward_outputs_only"
}
Loading