Skip to content

docs(experiments): three rules, 24 assets, zero free parameters — the viable intersection is empty - #252

Merged
eaitbrahim merged 1 commit into
mainfrom
docs/intersection-test
Aug 12, 2026
Merged

docs(experiments): three rules, 24 assets, zero free parameters — the viable intersection is empty#252
eaitbrahim merged 1 commit into
mainfrom
docs/intersection-test

Conversation

@eaitbrahim

Copy link
Copy Markdown
Contributor

Closes #251.

Measures every signal rule the codebase ships at its shipped constructor defaults, across the
whole 24-asset hourly corpus, at three fee levels. 270 backtests, 0 errors. Documentation only
— no code, no config, no rule status, no version bump.

Verdict

There is no asset-rule combination that clears the promotion trade floor with an edge surviving
even the cheapest fee we can reach — and the three rules fail for three unrelated reasons.

rule n≥100 ∧ gross>1 ∧ net@0.6%>1 ∧ net@1.2%>1 the lever
turtle_breakout 21/24 7 1 (ZEC) 0 cost
pullback_continuation 4/24 1 0 0 signal
rsi_meanrev 0/24 0 sample size
total 25/72 8 1 0

The single survivor, ZEC-turtle, is then eliminated by a temporal decomposition: three
consecutive losing years (2022–24) with 92.7% of lifetime PnL compressed into 2025–26.

Two earlier conclusions this supersedes

1. rsi_meanrev does not lack gross edge. #248 recorded that it "has no gross edge at all" on
the strength of BTC at 0.775. Across all 24 assets it has the best gross distribution of the
three rules — median gross PF 1.1631, against turtle's 0.9892 and pullback's 0.9292 over
the same universe. BTC sits near the bottom of its distribution. The rule does not lose; it is
not observable — 0 of 24 assets reach n≥100, median n=38. #248's figures came from widened
parameters (oversold 25–35), not defaults, so both documents are right about what they measured;
the error was generalising from one asset.

2. The 864-trial sweep winner is not overfit. #248 framed it as selection. Arm B evaluates that
config on the 18 assets it was never scored on: in-sample mean net PF 0.6335 → out-of-sample
0.6346, gross 1.5317. A clean three-decimal replication across disjoint assets. That is a
harder result than overfitting — overfitting has a methodology fix; a stable measurement of 0.63
does not.

pullback_continuation, measured for the first time

In RULE_REGISTRY since it was written, never backtested. Median gross 0.929, and a fee
collapse qualitatively unlike turtle's — PAXG-USDT 1.097 → 0.001 at maker. The cause is in
the win rates: 52–75% wins at PF≈1.0 is measured_1to1 taking small wins against small losses, so
a 1.2% round trip does not reduce the edge, it erases it. High win rate is the symptom of maximal
fee fragility here, not a strength.

Why the temporal probe is reported and never gated

Three reasons in §6, the third decisive: ZEC under pullback_continuation is the only
combination in the study with no losing complete year
(1.06/1.17/1.16/1.13) — at gross PF
0.875. Perfectly stationary at losing slightly, reliably. A stationarity gate would wave it
through while rejecting ZEC-turtle, which at least made money gross. The probe is also
underpowered (passes zero-edge strategies ~50% of the time at four buckets) and fragile to bucket
boundaries (excluding partial 2021/2026 flips the verdict for 4 of 21 assets, including FET).

The principled instrument already exists and is now live: #247 wired g4_pbo_gate into
can_promote, where pbo=None blocks. It is deployed and nothing feeds it. Building a weaker
annual-bucket heuristic beside an unfed rigorous one is the wrong order of work.

Honesty notes recorded in the document rather than omitted

  • The pre-registration lived in the dispatch brief, not the script docstring — weaker than
    every other harness here. The script now says so at the top instead of presenting the
    reconstruction as though it had always been there.
  • The tail and regime probes were written after seeing Arm A. Post-hoc by construction, which
    is exactly why they are diagnostics.
  • Four failed runs preceded the successful one, caused by piping into tail (buffers until EOF,
    then dies with the shell) and by pkill -f not reaping multiprocessing children. Both produced
    confident status reports that were false. §7.
  • 27 combinations ran on 0.6.1 and the rest on 0.7.0 after fix(strategy): price fills at the taker rate, and wire the dormant PBO gate into promotion #247 deployed mid-run. Version
    independence was checked, not assumed: BTC-USD reproduces to six decimal places across the
    boundary.

What this leaves open

One lead, and it is cheap: does rsi_meanrev's gross edge survive being made to fire more
often?
#248's 108-cell diagnostic widened the thresholds and found no net-viable cell, but never
asked whether widening preserved the gross edge or simply bought trades by accepting worse
setups. Different findings, different consequences, and the data separating them was never
computed.

A limit-order queue simulator has no target: its measured prize was one asset with ~8bp of headroom
below maker, and §6 removes that asset.

Ledger

Two rows — Arm A (a_priori) and Arm B (fitted, since the params were selected even though this
evaluation selects nothing further). Both diagnostic_only, both series_missing: true so the
CSCV matrix refuses them. verify_chain clean at 82 rows.

🤖 Generated with Claude Code

… viable intersection is empty

Measures every signal rule the codebase ships at its shipped constructor defaults, across the
whole 24-asset hourly corpus, at three fee levels. 270 backtests, 0 errors.

No combination clears the trade floor with an edge surviving even the maker rate, and the three
rules fail for three unrelated reasons — cost, signal, and sample size — which pooling destroys.

Supersedes two earlier conclusions:
- #248 recorded rsi_meanrev as having "no gross edge at all" from BTC alone. Across 24 assets it
  has the BEST gross distribution of the three (median 1.1631 vs turtle 0.9892, pullback 0.9292);
  BTC is near the bottom of it. Its failure is sample size — 0 of 24 reach n>=100.
- #248 framed the sweep winner as a selection artifact. Arm B refutes it: 0.6335 in-sample
  reproduces as 0.6346 on 18 disjoint assets. Not overfit — stably unprofitable, which is worse.

pullback_continuation is measured here for the first time since it was written.

Two ledger rows (Arm A a_priori, Arm B fitted), both diagnostic_only, chain verifies clean at 82.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@eaitbrahim
eaitbrahim merged commit 08be8b6 into main Aug 12, 2026
1 check passed
@eaitbrahim
eaitbrahim deleted the docs/intersection-test branch August 12, 2026 13:59
eaitbrahim added a commit that referenced this pull request Aug 12, 2026
… last live lead closes (#255)

#252 left one open question: does rsi_meanrev's gross edge survive being made to fire more often?
It does not. The rule reaches the promotion floor trivially — 21 of 24 assets at oversold=40 — and
has no edge when it gets there.

    gross PF at oversold=20 (median n=38) : median 1.1631   gross>1 14/24
    gross PF at every cell with n>=100    : median 0.8938   gross>1 11/76
    net > 1.0 at n>=100, at ANY fee       : 0 of 76, including maker

The edge evaporates exactly when the rule becomes measurable. The 1.1631 that made this look like
the best of the three rules IS what n=38 looks like.

Pre-registration lives in the script docstring this time, which is the correction to the defect
#252 recorded against itself. The declared statistic — a linear slope — is reported as declared
(-0.0386/100 trades, 15/24 negative) AND flagged as underpowered: the phenomenon is a threshold
effect at the floor, and two barely-trading assets supply most of its variance.

Investigating a 34x non-monotonic trade count on UNI-USD found a simulator defect: backtest()
never expires a pending setup, so a strategy whose entry is never revisited freezes silently for
the rest of the series. Filed as #254, deliberately not fixed here. #252's headline results were
checked against it and are clean.

Closes #253.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
eaitbrahim added a commit that referenced this pull request Aug 13, 2026
…ine, and record why the defects were invisible (#261)

Both experiments re-run under #256 (pending setups no longer freeze the detector) and #258
(entries fill at the next bar's open, as production's market orders do). Same designs, same
combinations, same fee grid and slippage pin -- only the engine differs.

EVERY CONCLUSION SURVIVES EXCEPT ONE. ZEC-turtle no longer clears the maker line (1.034 -> 0.968),
so #252 section 6's three-probe narrative describes a survivor the faithful engine never produces.
The replacement is simpler and worse for the library: the viable quadrant is empty at every
reachable fee -- 0 of 90 in #252, 0 of 82 in #255 -- with nothing needing three gates to die.

#255 strengthens: the level shift across the trade floor widens from 1.1631 -> 0.8938 to
1.1251 -> 0.8396, gross-positive cells at the floor nearly halve (11/76 -> 6/82), and the 34x
UNI-USD monotonicity anomaly that exposed both defects is structurally gone (3 assets -> 0).

The two defects pushed in OPPOSITE directions -- #256 suppressed opportunity, #258 flattered
execution -- so correcting both moved everything one way rather than adding noise: trade counts
rose in 87 of 90, gross profit factors fell in 69 of 90.

Arm B's transfer is restated on a single engine: 0.5770 in-sample vs 0.5427 out-of-sample, a gap
of 0.034. #252's 0.6335 vs 0.6346 compared figures from one engine and was partly luck. The
conclusion is unchanged -- the sweep winner is not overfit, it is stably unprofitable.

Records the operational takeaway as section 5: NEITHER DEFECT WAS FOUND BY LOOKING FOR DEFECTS,
and neither was findable by the means we had. 2,712 tests passed throughout. A frozen backtest and
a highly selective strategy produce identical-looking output, so no summary ledger distinguishes
them. The fix is invariants the engine reports about itself -- a dead-tail warning, intent-vs-fill
divergence logging (#260), and cost anchored to output (#247, shipped, and the model for the rest)
-- not more unit tests, which only assert behaviour someone already imagined.

Annotates rather than rewrites, per the convention #247 set: the original numbers were real
outputs of the code as it stood. Both documents keep their figures and carry a banner pointing
here.

Two ledger rows; chain verifies clean at 85.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

All three signal rules measured at shipped defaults: the viable intersection is empty, and rsi_meanrev's failure is not the one #248 recorded

1 participant