125 lines
6.0 KiB
Markdown
125 lines
6.0 KiB
Markdown
# Effective initial-risk floor A/B - frozen specification
|
|
|
|
Date frozen: 2026-08-05
|
|
Branch: research/portfolio-capacity-rebalancing
|
|
Runner: scripts/run_portfolio_construction_matrix.py
|
|
Study ID: risk-floor-ab
|
|
|
|
## Question
|
|
|
|
Does rejecting an otherwise qualified cap-10 entry when its actual initial
|
|
stop-risk after cash and notional sizing is below 0.5% of marked equity improve
|
|
trade selection?
|
|
|
|
The completed capacity bracket cannot answer this. Its cash_unbounded arm
|
|
removed the count cap and applied the 0.5% floor simultaneously. In the 70 paths
|
|
where the control cap never bound, that arm still raised mean EV from 0.328 to
|
|
0.399 R and profit factor from 1.60 to 1.75 while trades fell about 8% and
|
|
exposure stayed nearly flat. Capacity was a no-op in those paths, so the floor
|
|
is the plausible cause, but the prior arm remains confounded.
|
|
|
|
This A/B changes only the floor. It has no formal promotion gate and does not
|
|
automatically change production.
|
|
|
|
## Frozen arms
|
|
|
|
1. cap10_incumbent: current production-style cap-10 control, with no minimum
|
|
effective-risk floor.
|
|
2. cap10_min_risk_005: the same cap-10 strategy, rejecting an entry only when
|
|
actual initial stop-risk after cash/notional sizing is below 0.5% of marked
|
|
equity.
|
|
|
|
Both arms have max_positions=10, weekly replacement disabled, 1% target risk
|
|
per trade, and identical admission ordering. The only differing simulator
|
|
argument is min_initial_risk_fraction: None versus 0.005.
|
|
|
|
All other settings remain the frozen daily Phase A control: current production
|
|
construction universe, full-universe residual-momentum/low-volatility 80/20
|
|
rank, threshold 80, normal gate-reset re-entry, close fills, 3x ATR trail,
|
|
30-session maximum hold, 20% per-position notional ceiling, no leverage, and
|
|
costs of 0.10% and 0.20% per fill.
|
|
|
|
Every priced symbol contributes to the daily cross-sectional rank. Rank-only
|
|
symbols cannot submit trades. Validation retains the 450-600-symbol production
|
|
construction guardrail and the legacy-snapshot column-scoped loader.
|
|
|
|
## Frozen cohorts
|
|
|
|
Reuse the completed bracket's point-in-time daily candidate/rank cache and
|
|
cohort manifest:
|
|
|
|
- Empty book: first eligible session of each month in 2019-2025, with 504 prior
|
|
scoring sessions and 252 measurement sessions. This is the primary start-date
|
|
evidence.
|
|
- Warm book: weekly seeds 63-126 sessions before each 2019-2025 annual anchor,
|
|
with state carried into the same 252-session measurement window. This is a
|
|
state-carrying replication, not independent evidence.
|
|
|
|
The expected realization is 78 empty-book paths, 97 warm paths, seven annual
|
|
clusters in each protocol, two costs, two arms, and 700 cells.
|
|
|
|
Do not use warm-seed IQR as evidence. Six of seven completed-bracket anchors
|
|
were structurally degenerate because fractional sizing is scale invariant and
|
|
the 30-session maximum hold washed out books before anchors. The 2023 exception
|
|
shows that state carrying itself works.
|
|
|
|
## Reporting and interpretation
|
|
|
|
For every protocol and cost, pair identical paths. Report:
|
|
|
|
- mean, median, P25, and P75 paired net-EV changes in R;
|
|
- positive-path and bit-identical-path fractions;
|
|
- the median paired delta within each year and the median across seven years;
|
|
- simple 90% cluster-bootstrap context for EV and Calmar, with no CI gate;
|
|
- mean paired PF, Gain-to-Pain, Sortino, Calmar/MAR, CAGR, maximum drawdown,
|
|
total return, and Sharpe changes;
|
|
- trades, floor rejections, holding time, cash, gross exposure, average/peak
|
|
positions, turnover, and costs.
|
|
|
|
Means and identical-path fractions must appear beside medians so inert cohorts
|
|
cannot turn a left- or right-skewed treatment into a misleading zero headline.
|
|
For these 252-session windows, the implementation's full-window Calmar is CAGR
|
|
divided by maximum drawdown, the same numeric definition commonly called MAR;
|
|
do not present the duplicate label as a second independent metric.
|
|
|
|
Today's production membership is projected backward. Use paired differences
|
|
for the treatment conclusion; absolute profitability remains descriptive and
|
|
survivorship-biased. Empty and warm protocols cover the same seven market years
|
|
and must not be interpreted as independent replications.
|
|
|
|
Interpretation is deliberately simple:
|
|
|
|
- a positive result means the isolated floor improves the paired EV
|
|
distribution without an economically important loss of total-return or
|
|
drawdown quality;
|
|
- a negative result closes the floor;
|
|
- mixed EV/portfolio-quality results are reported as a trade-off, not forced
|
|
through a composite score.
|
|
|
|
## Reproducibility and macOS execution
|
|
|
|
The authoritative run refuses a dirty worktree. Its fingerprint includes the
|
|
implementation commit, this specification hash, snapshot hash, candidate-cache
|
|
key, construction view, cohort manifest, arm definitions, costs, and study
|
|
version. Cells checkpoint atomically and --resume verifies the fingerprint.
|
|
|
|
From the repository root on macOS:
|
|
|
|
python3 -m venv .venv
|
|
./.venv/bin/python -m pip install -e '.[dev]'
|
|
|
|
Preflight, reusing the completed bracket's candidate/rank cache:
|
|
|
|
./.venv/bin/python scripts/run_portfolio_construction_matrix.py + backtest_snapshots/research.sqlite + --study risk-floor-ab + --run-id prod505-effective-risk-floor-ab-daily-v1 + --candidate-cache reports/.cache/prod505-capacity-bracket-daily-v1-candidates.pkl + --workers 8 + --resume + --validate-only
|
|
|
|
Authoritative run:
|
|
|
|
./.venv/bin/python scripts/run_portfolio_construction_matrix.py + backtest_snapshots/research.sqlite + --study risk-floor-ab + --run-id prod505-effective-risk-floor-ab-daily-v1 + --candidate-cache reports/.cache/prod505-capacity-bracket-daily-v1-candidates.pkl + --workers 8 + --resume
|
|
|
|
On an M2 Pro, eight workers is the explicit high-utilization setting. Use six
|
|
instead on a memory-constrained machine; auto intentionally caps itself at six.
|
|
Changing worker count does not change the fingerprint or results.
|
|
|
|
Commit only the compact final JSON and Markdown reports. Candidate caches,
|
|
checkpoints, raw curves, and trade ledgers remain ignored.
|