# Endpoint signal light backtest

Start with [ARTICLE.md](ARTICLE.md), the [matrix](results/matrix.csv), or [ranked primary profiles](results/ranking.csv).

This is an actual historical quote experiment: 30 frozen endpoint-derived gates applied to six option structures on SPY, QQQ and IWM, 2020-2025. Signals select dates; they do not alter the baseline contracts or manufacture a return for an endpoint. It is not an exact production-score replay.

Revision 2 (`endpoint-light-backtest-v2`, 17 September 2026): OI-based features now read the expiry carrying the most lagged open interest within 30-60 days of the signal (the monthly) instead of the trade's own nearest-35-day expiry, which was usually a weekly with a median 2.3% of in-range OI and zero archived OI in 46 of 133 windows. Rules, thresholds, trades and bootstrap policy are unchanged; see `revision_history` in `protocol.json`.

## Reproduce offline

Python 3.13, standard library only. Unzip into any directory, then run:

```text
python -B reproduce.py check
python -B reproduce.py run
```

`check` verifies every sealed input and output hash. `run` rebuilds features, 180 matrix cells, 30 profiles, controls, slices, coverage and independent verification in two temporary directories under different Python hash seeds. Calculation subprocesses have sockets and child-process creation blocked. All output hashes must match. No credentials, database connection, dependency installation or application build is needed.

Maintenance only: `collect.py` makes bounded SELECT queries through the existing authorized SSH host alias, caches the exact SQL and records extraction times. It does not deploy, backfill or write to the archive. Existing caches must have identical SQL. `reproduce.py seal` updates the frozen release after intentional changes; it is not part of reproduction.

## Inputs and lineage

- `protocol.json`: 30 rules, thresholds, primary payoffs, costs, lags, expiry windows (`front_expiry` for quote-derived features, `oi_expiry` for OI-based features), risk-metric definitions, sample and bootstrap policy, plus the revision history. Rules were frozen before the first run; the `oi_expiry` rule was revised after it. Earlier backtest results were already known, so this is not preregistered out-of-sample evidence.
- `raw/features_*.json`: signal-day quotes and Greeks, all strikes with 30-80 days to expiry. Quote-derived features select the expiry nearest 35 days (the trade's expiry); the term feature adds the expiry nearest 65 days; OI-based features select the highest-OI expiry within 30-60 days.
- `raw/oi_*.json`: OI and unsigned volume two and three observed sessions before the signal. Duplicate rows with identical fields are collapsed. Conflicting duplicates abort. The raw files remain unchanged.
- `raw/svi.json`, `raw/macro.json`: saved SVI parameters and macro closes. SVI publication vintages remain unverified. Macro observations precede the signal date.
- `raw/stock_closes_*.json`: archived underlying quotes also used by the original strategy study; bid/ask midpoints drive the return features.
- `raw/outcome_chains_*.json`: original archived option quotes underlying the reused trade ledgers. These are separate from the new feature extracts.
- `inputs/trades.csv`, `legs.csv`, `attempts.csv`: original 50-strategy research outputs. The new runner uses only the six declared monthly ETF structures; no earnings or wheel returns enter the new rankings.
- `inputs/windows.csv`: 216 scheduled ETF-month windows.
- `inputs/catalogue.json`: the prior source-audited endpoint catalogue, pinned to API commit `8d9ede9c9d4a1e7f5596ebb5bcdc860061189519`.
- `raw_manifest.json`: raw-byte fingerprints. Raw responses retain source SQL, column metadata and extraction times where available; hashes establish identity, not correctness of original market data.

## Results and denominators

- `features.csv`: one row per scheduled window. Empty means unavailable, never zero. Records signal/entry/exit dates, lagged OI dates, macro date, expiry choices (`front_expiry`, `back_expiry`, `oi_expiry`, `oi_expiry_dte`), `lagged_total_oi` on the OI expiry, `front_expiry_lagged_oi` on the trade expiry (how thin it was), features and matched Greek/OI coverage.
- `feature_lineage.csv`: selected option roles with exact raw file and zero-based row number. Exposure and surface features use all eligible contracts in the disclosed expiry/strike range; their complete inputs remain in the raw extracts.
- `decisions.csv`: all 6,480 signal/window decisions, including rejected dates and missing signals.
- `matrix.csv`: 180 signal/structure summaries on the original common cohort. All six cells in a signal row share exactly the same selected dates. Different signal rows can have different feature availability.
- `ranking.csv`: primary payoffs fixed in the protocol, ranked by selected mean after costs, only when at least 30 trades exist. This cutoff does not make the rows statistically reliable. `ranking_sharpe.csv` orders the same rows by annualized monthly Sharpe and carries `rank_by_mean`.
- Risk metric columns on every summary row: `sharpe`, `profit_factor`, `max_drawdown`, `avg_win`, `avg_loss`, `best`, `total` for the selected trades and `control_sharpe`, `control_max_drawdown`, `control_profit_factor`, `control_win_rate` for every feature-valid window. Definitions match the options-strategies article: equal-weight monthly series across the ETFs traded that month; Sharpe = mean / stdev x sqrt(12), no risk-free rate; max drawdown on the running total of that series, not compounded; profit factor = gross gains / gross losses (empty when no losing trade).
- `series.json`: per primary profile, the running total per eligible month for the selected trades (skipped months add zero) and for the unconditional control, plus `baseline:<structure>` on the 133 shared windows. Used for the article's charts.
- `small_samples.csv`: the nine primary profiles below that display cutoff, including a zero-trade rule.
- `trades.csv`: selected AND rejected outcomes; `active=True` identifies the selected trades. Do not average the full file as if every row were selected. The same baseline trade can occur in many signals.
- `<signal>.csv`: one primary-payoff ledger per rule, including rejected-date controls.
- `baseline.csv`: all six unconditional outcomes on the 133 shared windows.
- `slices.csv`: primary-payoff results by ETF, year, and 2020-2023 / 2024-2025. The chronological split is descriptive, not an untouched holdout.
- `full_cohort_sensitivity.csv`: each payoff on its own larger valid quote sample; do not merge its rows with the main common-cohort matrix.
- `endpoint_coverage.csv`: every one of the 93 documented routes, associated tests, classification and reason. Sharing a formula does not establish full endpoint coverage. Intraday/event/basket endpoints are not counted as tested merely because they embed a shared formula.
- `formulas.csv`: exact experimental formulas, primary payoffs and related routes.
- `verification.json`: independent raw-quote cashflow, chronology, gate, cohort and control checks.
- `input_quality.json`: exact duplicate rows collapsed and the no-conflicting-duplicates policy.

All P&L numbers in the CSVs use basis points of the value of 100 ETF shares at entry. One basis point is 0.01% of that reference value; the article shows the same figures as percentages. It is not premium return, margin return or a compounded account return.

`mean_net` is the average selected trade. `control_mean` uses every feature-valid eligible window. `rejected_mean` uses only dates rejected by the gate. `per_eligible_mean` includes zero P&L on skipped dates; `per_eligible_lift` subtracts the unconditional control on that same denominator. No idle cash interest is paid. Missing features are excluded from BOTH gate and control, not counted as skipped zero-P&L dates.

Bootstrap intervals resample calendar months, keeping ETFs together. A one-trade interval cannot express missing tail risk and must not be treated as meaningful confidence. None of the intervals correct for trying 30 gates and six correlated payoffs, serial dependence, universe selection or unknown data vintages.

## What was verified and what was not

Independent Decimal accounting checks trace the 798 distinct baseline option trades and their 1,729 legs to exact signal, entry and exit quotes. The rules precede entry, option exits precede expiry, gates and summary denominators are recomputed, the OI expiry is re-derived from the raw OI extracts for every window, and the six strategies share dates within each matrix row.

The experiment does not certify original quote synchronization, original historical endpoint responses, SVI fit publication times or OI publication vintages. Two-session OI lags are a conservative research choice, not proof of point-in-time correctness. The common cohort excludes trades with missing future quotes, which can bias results. Raw price returns are not dividend adjusted. Early assignment, margin, funding, collateral yield, taxes, impact and account drawdowns are not modeled.

The article is exploratory research, not a deployment or live trading program.
