feat: stop the position count cap from binding (10 -> 15)
The capacity bracket study (reports/portfolio-construction-prod505-capacity- bracket-daily-v1) showed a book whose count cap never binds earns +1.1pp CAGR over the old 10 -- 51 of 175 paired cohorts better, 2 worse -- at unchanged drawdown (+0.007pp) and better Calmar in 51 of the 52 cohorts that moved. The headline EV-per-trade delta is ~0 (+0.001), which is the trap: capacity does not change trade quality, it changes trade COUNT. Flat EV/trade means the blocked entries were just as good as the taken ones, so refusing them cost their whole contribution to return. Judge capacity on CAGR, never on EV per trade. 15 is headroom, not a target. cap15 peaked at 12 positions with zero full-book skips, so cash plus SIM_NOTIONAL_CAP is the real ceiling and 15/20/None are the same experiment. SIM_MAX_POSITIONS and the shadow book's DEFAULT_CAPACITY move together to keep backtest and production in parity. Historical research arms pass max_positions explicitly, so their labels and past results are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1701,7 +1701,14 @@ def _gate_ablation(candidates: list[dict], activation: dict, threshold: float) -
|
||||
# the QUALIFIED setups at their detection close, best momentum first while
|
||||
# slots and cash allow.
|
||||
SIM_STARTING_CAPITAL = 10_000.0
|
||||
SIM_MAX_POSITIONS = 10
|
||||
# Headroom, not a target: the count cap should never bind. The capacity study
|
||||
# (reports/portfolio-construction-prod505-capacity-bracket-daily-v1) showed a book
|
||||
# that never hits the count cap earns +1.1pp CAGR over the old 10 (51 cohorts of 175
|
||||
# better, 2 worse) at unchanged drawdown, because the blocked entries were as good as
|
||||
# the taken ones — capacity costs trade COUNT, not trade quality. The real ceiling is
|
||||
# cash plus SIM_NOTIONAL_CAP, which saturates the book near 12 positions, so 15/20/None
|
||||
# are the same experiment. Judge any future change here on CAGR, never on EV per trade.
|
||||
SIM_MAX_POSITIONS = 15
|
||||
SIM_RISK_PER_TRADE = 0.01 # fraction of equity risked per position (entry→stop)
|
||||
SIM_NOTIONAL_CAP = 0.20 # max fraction of equity per position (no margin)
|
||||
_EULER_MASCHERONI = 0.5772156649015329
|
||||
|
||||
@@ -40,10 +40,12 @@ KEY_CAPACITY = "shadow_book_capacity"
|
||||
KEY_RISK_PCT = "shadow_book_risk_pct"
|
||||
KEY_START_EQUITY = "shadow_book_start_equity"
|
||||
|
||||
# Matches the validated configuration: 10-position book, 1% fixed-fractional
|
||||
# risk. Start equity is only a sizing base — comparisons are drawn in percent
|
||||
# and R-multiples, never in raw currency.
|
||||
DEFAULT_CAPACITY = 10
|
||||
# Matches the validated configuration: 1% fixed-fractional risk, and a count cap
|
||||
# set as headroom rather than a target — see backtest_service.SIM_MAX_POSITIONS,
|
||||
# which this must track. NOTIONAL_CAP below saturates the book near 12 positions,
|
||||
# so the count cap should simply never bind. Start equity is only a sizing base —
|
||||
# comparisons are drawn in percent and R-multiples, never in raw currency.
|
||||
DEFAULT_CAPACITY = 15
|
||||
DEFAULT_RISK_PCT = 1.0
|
||||
DEFAULT_START_EQUITY = 100_000.0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user