133 lines
6.5 KiB
Markdown
133 lines
6.5 KiB
Markdown
# Portfolio-capacity bracket — frozen specification
|
||
|
||
Date frozen: 2026-08-05
|
||
Branch: research/portfolio-capacity-rebalancing
|
||
Runner: scripts/run_portfolio_construction_matrix.py
|
||
|
||
## Question and motivation
|
||
|
||
The daily Phase A production control (a0_control: close fill, 30-session
|
||
maximum hold, 1% fixed-fractional risk, no correlation or volatility overlay)
|
||
recorded 472 trades and 519 otherwise qualified entries rejected because the
|
||
ten-position book was full. The blocked share is 519 / (519 + 472) = 52.4%.
|
||
The book is therefore materially arrival-order constrained.
|
||
|
||
This supersedes the older statement that the ten-slot cap never bound. That
|
||
statement came from a shorter, weekly, pre-gate-reset replay and is not evidence
|
||
about the current daily strategy.
|
||
|
||
The study brackets the value of capacity before tuning replacement details. It
|
||
does not contain a formal promotion rule or automatically change production.
|
||
Because the current ~505-name production membership is projected backward,
|
||
paired arm-versus-control differences are the primary evidence. Absolute
|
||
profitability is descriptive and survivorship-biased.
|
||
|
||
## Frozen arms
|
||
|
||
1. **cap10_incumbent:** exact production-style cap-10 control, no displacement.
|
||
2. **cash_unbounded:** no position-count cap; cash/no leverage and the existing
|
||
20% per-position notional ceiling remain. Reject an entry if actual initial
|
||
stop-risk after cash/notional sizing is below 0.5% of marked equity.
|
||
3. **cap10_weekly_top10:** on the final trading session of each ISO week, rank
|
||
holdings plus fresh same-day qualified entrants and retain the top ten.
|
||
4. **cap15_incumbent:** cap 15, no displacement.
|
||
|
||
All arms use the frozen Phase A control configuration: daily candidate replay,
|
||
live-like full-universe residual-momentum/low-volatility 80/20 rank, activation
|
||
threshold 80, normal gate-reset re-entry, close fill, 3×ATR trail, 30-session
|
||
maximum hold, 1% risk, and costs of 0.10% and 0.20% per fill.
|
||
|
||
The daily replay uses zero outcome horizon: setup and rank observations continue
|
||
through the snapshot's last session because portfolio simulation, unlike outcome
|
||
grading, does not require 30 future bars.
|
||
|
||
Control-parity note: a direct main-versus-branch comparison found identical
|
||
total return, CAGR, maximum drawdown, and Sharpe. The branch intentionally
|
||
changes only the first calendar year's `yearly_returns` convention: it starts
|
||
from initial capital rather than equity after the first session, so day-one
|
||
entry costs are now charged to year one. Older reports can therefore show a
|
||
different first-year contextual return without a strategy-performance
|
||
regression. New trade-detail and measurement-start fields are additive.
|
||
|
||
### Weekly-selection mechanics
|
||
|
||
- Ordinary exits run before entries/rebalancing.
|
||
- Open slots may still fill from daily qualified entries during the week.
|
||
- On the final ISO-week session, current holdings and that day's fresh qualified
|
||
entrants use the full-universe strategy_rank for that same date.
|
||
- Stored entry-day rank is never used.
|
||
- Holdings with missing current rank/data are protected and consume a slot;
|
||
entrants missing rank are ineligible.
|
||
- Incumbents win exact rank ties; symbol is the deterministic final tie-breaker.
|
||
- Rebalance exits pay costs and bypass cooldown/post-stop state.
|
||
- Report entrant-pool sizes, replacements, turnover, and same-symbol re-entry
|
||
within 5/10/20 sessions.
|
||
|
||
## Frozen cohorts
|
||
|
||
research.sqlite is expected to cover 2016-01-04 through 2026-07-17. Residual
|
||
momentum requires 252 benchmark sessions. Empty-book starts additionally require
|
||
504 prior scoring sessions and 252 forward measurement sessions.
|
||
|
||
- **Empty book:** first eligible session of each month, approximately January
|
||
2019 through July 2025; start with no positions and measure 252 sessions.
|
||
- **Warm book:** first session of each year 2019–2025 is the measurement anchor.
|
||
Seed the portfolio on the first session of every ISO week falling 63–126
|
||
trading sessions before the anchor, carry all positions and gate-reset state
|
||
forward, and measure the same 252-session anchor window.
|
||
|
||
Warm portfolio returns reset to marked equity immediately before the anchor
|
||
session. P&L after the anchor from carried positions belongs to portfolio
|
||
returns, while trade EV includes only entries on or after the anchor. Remaining
|
||
positions liquidate at the last measurement close with costs.
|
||
|
||
The validate-only mode must print realized cohort counts and fail unless both
|
||
protocols contain the seven annual clusters 2019–2025 and every warm anchor has
|
||
at least 12 seeds.
|
||
|
||
## Reporting
|
||
|
||
Primary reported measures:
|
||
|
||
- net EV per trade in R, with costs and actual initial stop-risk dollars;
|
||
- Calmar (CAGR / max drawdown);
|
||
- profit factor on net trade R;
|
||
- Gain-to-Pain (sum of all monthly returns / absolute sum of negative months);
|
||
- Sortino using daily returns and zero target.
|
||
|
||
Also report total return/CAGR, maximum drawdown, Sharpe, win rate, time
|
||
underwater, exposure, cash, average/peak positions, sessions at capacity,
|
||
turnover, costs, qualified/admitted/blocked opportunities, and minimum-risk
|
||
rejections.
|
||
|
||
For each arm/protocol/cost/metric, pair identical paths with cap10_incumbent,
|
||
take the median paired delta within each start year or annual anchor, show all
|
||
seven cluster values, and headline their median.
|
||
|
||
Initialization dispersion is reported separately for EV and Calmar: calculate
|
||
the seed-path IQR within each warm anchor, divide by the paired control IQR, show
|
||
all seven ratios, and headline their median. Do not combine them into a composite.
|
||
|
||
For context only, run a deterministic 10,000-replicate cluster bootstrap over
|
||
the seven paired annual summaries and report the central 90% percentile interval
|
||
for median EV and Calmar deltas and warm IQR ratios. These intervals are not
|
||
promotion gates, independent-population confidence claims, or formal inference.
|
||
|
||
## Reproducibility and execution
|
||
|
||
Candidate replay/ranks cache under reports/.cache; each matrix cell checkpoints
|
||
atomically and resume verifies a fingerprint over the implementation commit,
|
||
this specification hash, snapshot SHA-256, cache key, arm definitions, costs,
|
||
and cohort manifest. An authoritative run refuses a dirty worktree.
|
||
|
||
Preflight:
|
||
|
||
python scripts/run_portfolio_construction_matrix.py backtest_snapshots/research.sqlite --run-id prod505-capacity-bracket-daily-v1 --validate-only
|
||
|
||
Authoritative run:
|
||
|
||
python scripts/run_portfolio_construction_matrix.py backtest_snapshots/research.sqlite --run-id prod505-capacity-bracket-daily-v1 --workers auto --resume
|
||
|
||
Commit only the compact final JSON and Markdown reports. Raw curves, trades,
|
||
candidate caches, and checkpoints remain ignored.
|