diff --git a/blueprints/always-long.json b/blueprints/always-long.json new file mode 100644 index 0000000..5ad3ec5 --- /dev/null +++ b/blueprints/always-long.json @@ -0,0 +1 @@ +{"format_version":1,"blueprint":{"name":"always_long","nodes":[{"primitive":{"type":"Const","name":"always_long","bound":[{"pos":0,"name":"value","kind":"F64","value":{"F64":1.0}}]}}],"input_roles":[{"name":"close","targets":[{"node":0,"slot":0}],"source":"F64"}],"output":[{"node":0,"field":0,"name":"bias"}]}} diff --git a/docs/arc-2-costs-and-stops.md b/docs/arc-2-costs-and-stops.md new file mode 100644 index 0000000..8eee7c2 --- /dev/null +++ b/docs/arc-2-costs-and-stops.md @@ -0,0 +1,168 @@ +# Arc 2 — do Arc 1's findings survive costs, and what does the stop regime do to them? + +**Date:** 2026-07-13 +**Engine:** aura @ `84e1075` (release build) +**Campaigns:** `research/campaign-arc2-net-*.json`, `research/campaign-arc2b-stopgeom-*.json`, +`research/campaign-arc2c-kladder-*.json` + +## Hypothesis + +Arc 1 closed with "all of it is gross of costs" as its biggest open flank. Arc 2 +charges the exact Arc 1 matrix (both variants, same axes {24,48,96}², same seed, +same window 2018-01-01..2026-06-30) with a cost model (#234) and asks three +questions in sequence: + +1. **arc2-net** — does anything survive realistic retail costs at Arc 1's stop + regime (vol{3, k2})? +2. **arc2b-stopgeom** — is cost fragility a stop-geometry artifact? (regimes + vol{60, k2}, vol{240, k3}) +3. **arc2c-kladder** — the corrected geometry lever: k ∈ {6, 12} on the smoothed + EMA-60 estimator. + +## Cost model (labelled stress parameters, not claims) + +`ConstantCost.cost_per_trade` is in **price units**, charged in R as +`cost / |entry − stop|` — it does not transfer across instruments, so constant +costs run in four per-instrument campaigns (process = the Arc 1 pipeline minus +generalize, `research/process-screen-nogen.json`), while the cross-instrument +generalize leg carries vol-proportional slippage only (the one scale-free factor): + +| instrument | constant round-trip (price units) | rationale | +|---|---|---| +| GER40 | 1.5 | index CFD spread ~1–2 pts | +| US500 | 0.5 | ~0.4–0.6 pts | +| EURUSD | 0.00012 | ~1.2 pips incl. commission | +| XAUUSD | 0.25 | ~0.2–0.3 $ | + +plus `vol_slippage { slip_vol_mult: 0.1 }` everywhere. + +## Findings + +### 1. At Arc 1's stop regime, nothing survives net (arc2-net) + +Constant + slippage costs consume **0.35–0.67 R per trade** (GER40 0.35, US500 +0.40–0.44, XAUUSD 0.44–0.50, EURUSD 0.61–0.67) against full-window gross +expectancies of at most +0.44. Across all 72 members (2 variants × 9 cells × 4 +instruments), exactly **one** is net-positive full-window: XAUUSD `bo_h1` +hi=96/lo=96 at **+0.0038** — zero for practical purposes. The root cause is +churn: the vol{3, k2} stop is a *minute*-scale stop under an *hourly* signal, so +members trade 2 600–5 900 times in 8.5 y and pay the spread against a tiny +R-denominator. + +Slippage alone (the generalize leg) costs a uniform ~0.17 R/trade — by +construction, since both the stop and the slippage scale with local vol — and +leaves a few full-window net positives (XAUUSD +0.27, GER40 +0.08, US500 up to ++0.21), but the walk-forward OOS picture stays the Arc 1 picture and the +cross-instrument floors stay deeply negative (worst-case −0.19…−0.75, sign +agreement 0/4). + +### 2. The screen is cost-blind + +Selection stays on gross `sqn_normalized` (Arc 1 methodology, kept for +comparability), and the sweep winner is often not the best net member (US500: +winner hi=48/lo=96 net −0.19 vs best-net hi=96/lo=96 at −0.05) — the gross +screen systematically prefers churny configurations that costs then punish +hardest. With full-window net>0 members this rare (1/72), a net-aware selection +metric cannot rescue this signal family, but the observation stands as +methodology: a costed campaign should be able to *select* on net. See the +engine-gap notes below. + +### 3. Stop geometry: `length` smooths, `k` scales (arc2b) + +The stop rule is `k · Sqrt(EMA(Δ², length))` over **engine cycles (m1)** — so +vol{60} / vol{240} do *not* produce hourly/4-hourly stops, they produce +*smoother minute-vol* stops of the same magnitude. arc2b therefore measured the +estimator-smoothing and k=2→3 effects, not timescale-matched stops (that is +arc2c's k-ladder). Drag falls ∝ 1/k as expected (EURUSD 0.66 → 0.48 R/trade at +k=3); net stays negative everywhere (0/9 members net>0 per cell) except XAUUSD +at vol{240, k3} with 1/9 at +0.027. + +Analytically, both gross E[R] and cost drag scale as 1/stop, so **the sign of +net expectancy is k-invariant unless the trade population itself changes** +(fewer noise stop-outs, longer holds). The k-ladder tests exactly that +population effect. + +### 4. One cell survives deflation, gross: XAUUSD breakout (arc2b) + +XAUUSD `bo_h1` at vol{60, k2}, hi=24/lo=96 is the only cell in the whole +project so far with a **positive deflated score** (+0.009, overfit probability +0.044) and a near-significant pooled WF-OOS bootstrap (**gross** mean +0.254, +P(E[R]≤0) = 0.052, n=5228). At stress costs it nets to −0.0006 — the signal is +real-ish and the costs eat precisely all of it at this stop scale. The trend +gate *hurts* XAUUSD under every regime tested (replicating Arc 1's +instrument-dependence finding). + +### 5. The k-ladder (arc2c) + +The k-ladder confirms drag ∝ 1/k (XAUUSD: 0.52 R/trade at k2 → 0.18 at k6 → +0.09 at k12) and shrinks the trade population as intended (XAUUSD `bo_h1` +4 173 → 1 763 → 1 027 trades). The population effect is real but +instrument-selective: + +- **GER40, EURUSD:** null at every k. Gross shrinks in lockstep with drag; + net stays negative (0/9 members net>0 in every cell). +- **US500:** thin full-window net positives appear (best +0.045 at k12, 1/9 + members) but the WF-OOS bootstrap stays noise (P(≤0) 0.3–0.4). +- **XAUUSD `bo_h1`:** the arc2b thread strengthens monotonically with k. + At vol{60, k6}: deflated +0.019 (overfit-p 0.040), full-window net **+0.26** + (3/9 members net>0), WF-OOS gross +0.141 (P(≤0) 0.089). At vol{60, k12}: + deflated **+0.074** (overfit-p **0.026**), full-window net **+0.29** (5/9 + net>0, n=1027), WF-OOS gross +0.118 (P(≤0) 0.081). The winning cell is + hi=24/lo=96 under *every* regime tested (k2, k3, k6, k12) — fast long + entries, slow short entries — and the trend gate hurts it everywhere. + +## Verdict + +As a cross-instrument, deployable proposition the Arc 1 breakout is an +**honest null, now net-of-costs and stop-geometry-robust**: generalize floors +stay deeply negative with 0–1/4 sign agreement under every regime and cost +treatment, and three of four instruments never produce a net-positive member. + +One thread survives every within-arc filter: **XAUUSD `bo_h1` at wide stops** +— positive deflated score (up to +0.074, overfit-p 0.026), net-positive +full-window at stress costs (+0.29 R/trade), borderline WF-OOS gross bootstrap +(P(≤0) ≈ 0.08), and parameter-stable (hi=24/lo=96) across four stop regimes. +The thread died at the beta control +(`research/campaign-control-always-long.json`, arc 4): an always-long bias +on XAUUSD under the same regimes and costs produces WF-OOS gross means of ++0.78 to +1.45 R/trade with P(E[R]≤0) = 0.002–0.003 — several times the +breakout's +0.12–0.25 at P ≈ 0.08. The channel logic *dilutes* long-gold +beta rather than adding to it. Verdict: the XAUUSD cell was beta in a +secular bull market, surfaced by a pipeline that (correctly) has no +benchmark-relative stage to catch it — see the engine-gap list. What +survives Arc 2 is methodology, not signal: the cost/stop mechanics above and +the always-long control as a mandatory rung for every future candidate. + +## Engine friction / gaps (filed in the aura tracker) + +Filed 2026-07-13 as Brummel/Aura#259 (net-R bootstrap), #260 (per-instrument +cost factors), #261 (Session node reachability), #262 (timescale-matched stop +regime), #263 (reference strategy), #264 (archive inventory verb), #265 +(cost/risk knob units), #266 (engine commit in --version), #267 (agent +bootstrap card). + +1. **`std::monte_carlo` bootstraps gross R only.** With a cost model attached, + the pooled-OOS bootstrap numbers are bit-identical to the uncosted Arc 1 run + — there is no net-R path through the walk-forward/MC evidence chain, so a + costed campaign's headline (net WF-OOS distribution) cannot be produced by + the process pipeline. Net evidence exists only as full-window family + metrics (`net_expectancy_r`). +2. **The campaign `cost` list cannot vary per instrument.** `ConstantCost` is + price-unit-scaled, so any multi-instrument campaign with a constant cost is + unit-inconsistent; this forces per-instrument campaign splits and makes + "generalize under constant costs" inexpressible. +3. **No session/time-of-day node is rostered** (`session.rs` exists in + aura-std but is not in the vocabulary), so Arc 1's proposed time-of-day + conditioner is not constructible data-only. +4. **The risk-regime vocabulary has one variant** (minute-Δ vol EMA); a + timescale-matched stop (vol over resampled bars, ATR-style range) is not + expressible, and the `length`-smooths / `k`-scales semantics deserve a + doc note near the `risk` section. +5. **No benchmark-relative evaluation.** The pipeline measures a candidate + against zero, not against a baseline strategy on the same matrix; a + secular-trend instrument lets pure beta sail through every stage with + spectacular scores (the always-long control's overfit-p is 0.001 — the + deflation guards against *selection* luck, not *confound* luck). A + campaign-level notion of "reference strategy" whose per-cell stats are + reported beside (or subtracted from) every candidate's would make the + beta control structural instead of a hand-authored convention. diff --git a/research/campaign-arc2-net-eurusd.json b/research/campaign-arc2-net-eurusd.json new file mode 100644 index 0000000..af1afe4 --- /dev/null +++ b/research/campaign-arc2-net-eurusd.json @@ -0,0 +1,34 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2-net-eurusd", + "description": "Arc 2 gross-to-net stress: the Arc 1 matrix on EURUSD alone, charged with a constant round-trip cost (0.00012 price units, a labelled stress parameter approximating typical retail spread+commission) plus vol-proportional slippage (slip_vol_mult 0.1). Single instrument, so the process drops the generalize stage.", + "seed": 0, + "data": { + "instruments": ["EURUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ { "vol": { "length": 3, "k": 2.0 } } ], + "cost": [ + { "constant": { "cost_per_trade": 0.00012 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2-net-generalize.json b/research/campaign-arc2-net-generalize.json new file mode 100644 index 0000000..da106d1 --- /dev/null +++ b/research/campaign-arc2-net-generalize.json @@ -0,0 +1,33 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2-net-generalize", + "description": "Arc 2 cross-instrument leg: the exact Arc 1 matrix (both variants, 4 instruments) charged with vol-proportional slippage only (slip_vol_mult 0.1) — the one cost factor that scales per instrument, so a shared cost model stays unit-consistent. Constant spread costs live in the per-instrument arc2-net-* campaigns.", + "seed": 0, + "data": { + "instruments": ["GER40", "US500", "EURUSD", "XAUUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ { "vol": { "length": 3, "k": 2.0 } } ], + "cost": [ + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "41863fcae9300b334056c6f2a899e8c2672ecb29387d294e9a6e58f159ef51b4" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2-net-ger40.json b/research/campaign-arc2-net-ger40.json new file mode 100644 index 0000000..d937275 --- /dev/null +++ b/research/campaign-arc2-net-ger40.json @@ -0,0 +1,34 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2-net-ger40", + "description": "Arc 2 gross-to-net stress: the Arc 1 matrix on GER40 alone, charged with a constant round-trip cost (1.5 price units, a labelled stress parameter approximating typical retail spread+commission) plus vol-proportional slippage (slip_vol_mult 0.1). Single instrument, so the process drops the generalize stage.", + "seed": 0, + "data": { + "instruments": ["GER40"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ { "vol": { "length": 3, "k": 2.0 } } ], + "cost": [ + { "constant": { "cost_per_trade": 1.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2-net-us500.json b/research/campaign-arc2-net-us500.json new file mode 100644 index 0000000..509395f --- /dev/null +++ b/research/campaign-arc2-net-us500.json @@ -0,0 +1,34 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2-net-us500", + "description": "Arc 2 gross-to-net stress: the Arc 1 matrix on US500 alone, charged with a constant round-trip cost (0.5 price units, a labelled stress parameter approximating typical retail spread+commission) plus vol-proportional slippage (slip_vol_mult 0.1). Single instrument, so the process drops the generalize stage.", + "seed": 0, + "data": { + "instruments": ["US500"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ { "vol": { "length": 3, "k": 2.0 } } ], + "cost": [ + { "constant": { "cost_per_trade": 0.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2-net-xauusd.json b/research/campaign-arc2-net-xauusd.json new file mode 100644 index 0000000..56afa91 --- /dev/null +++ b/research/campaign-arc2-net-xauusd.json @@ -0,0 +1,34 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2-net-xauusd", + "description": "Arc 2 gross-to-net stress: the Arc 1 matrix on XAUUSD alone, charged with a constant round-trip cost (0.25 price units, a labelled stress parameter approximating typical retail spread+commission) plus vol-proportional slippage (slip_vol_mult 0.1). Single instrument, so the process drops the generalize stage.", + "seed": 0, + "data": { + "instruments": ["XAUUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ { "vol": { "length": 3, "k": 2.0 } } ], + "cost": [ + { "constant": { "cost_per_trade": 0.25 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2b-stopgeom-eurusd.json b/research/campaign-arc2b-stopgeom-eurusd.json new file mode 100644 index 0000000..a0bf890 --- /dev/null +++ b/research/campaign-arc2b-stopgeom-eurusd.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2b-stopgeom-eurusd", + "description": "Arc 2b stop-geometry test on EURUSD: the Arc 1 matrix under two wider vol-stop regimes (EMA-60 k=2 hourly-scale, EMA-240 k=3 multi-hour-scale) instead of Arc 1 minute-scale vol{3,k2}. Same constant round-trip cost (0.00012 price units, stress parameter) + vol slippage. Question: does the cost drag collapse and leave a net-positive signal once the stop matches the H1 signal timescale?", + "seed": 0, + "data": { + "instruments": ["EURUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 2.0 } }, + { "vol": { "length": 240, "k": 3.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.00012 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2b-stopgeom-generalize.json b/research/campaign-arc2b-stopgeom-generalize.json new file mode 100644 index 0000000..2b5a173 --- /dev/null +++ b/research/campaign-arc2b-stopgeom-generalize.json @@ -0,0 +1,101 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2b-stopgeom-generalize", + "description": "Arc 2b cross-instrument leg: the Arc 1 matrix under the two wider vol-stop regimes (EMA-60 k=2, EMA-240 k=3), vol slippage only, with the generalize floor.", + "seed": 0, + "data": { + "instruments": [ + "GER40", + "US500", + "EURUSD", + "XAUUSD" + ], + "windows": [ + { + "from_ms": 1514764800000, + "to_ms": 1782863999999 + } + ] + }, + "risk": [ + { + "vol": { + "length": 60, + "k": 2.0 + } + }, + { + "vol": { + "length": 240, + "k": 3.0 + } + } + ], + "cost": [ + { + "vol_slippage": { + "slip_vol_mult": 0.1 + } + } + ], + "strategies": [ + { + "ref": { + "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" + }, + "axes": { + "channel_hi.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + }, + "channel_lo.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + } + } + }, + { + "ref": { + "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" + }, + "axes": { + "channel_hi.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + }, + "channel_lo.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + } + } + } + ], + "process": { + "ref": { + "content_id": "41863fcae9300b334056c6f2a899e8c2672ecb29387d294e9a6e58f159ef51b4" + } + }, + "presentation": { + "persist_taps": [], + "emit": [ + "selection_report" + ] + } +} \ No newline at end of file diff --git a/research/campaign-arc2b-stopgeom-ger40.json b/research/campaign-arc2b-stopgeom-ger40.json new file mode 100644 index 0000000..f28482e --- /dev/null +++ b/research/campaign-arc2b-stopgeom-ger40.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2b-stopgeom-ger40", + "description": "Arc 2b stop-geometry test on GER40: the Arc 1 matrix under two wider vol-stop regimes (EMA-60 k=2 hourly-scale, EMA-240 k=3 multi-hour-scale) instead of Arc 1 minute-scale vol{3,k2}. Same constant round-trip cost (1.5 price units, stress parameter) + vol slippage. Question: does the cost drag collapse and leave a net-positive signal once the stop matches the H1 signal timescale?", + "seed": 0, + "data": { + "instruments": ["GER40"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 2.0 } }, + { "vol": { "length": 240, "k": 3.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 1.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2b-stopgeom-us500.json b/research/campaign-arc2b-stopgeom-us500.json new file mode 100644 index 0000000..7a20f74 --- /dev/null +++ b/research/campaign-arc2b-stopgeom-us500.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2b-stopgeom-us500", + "description": "Arc 2b stop-geometry test on US500: the Arc 1 matrix under two wider vol-stop regimes (EMA-60 k=2 hourly-scale, EMA-240 k=3 multi-hour-scale) instead of Arc 1 minute-scale vol{3,k2}. Same constant round-trip cost (0.5 price units, stress parameter) + vol slippage. Question: does the cost drag collapse and leave a net-positive signal once the stop matches the H1 signal timescale?", + "seed": 0, + "data": { + "instruments": ["US500"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 2.0 } }, + { "vol": { "length": 240, "k": 3.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2b-stopgeom-xauusd.json b/research/campaign-arc2b-stopgeom-xauusd.json new file mode 100644 index 0000000..e85c144 --- /dev/null +++ b/research/campaign-arc2b-stopgeom-xauusd.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2b-stopgeom-xauusd", + "description": "Arc 2b stop-geometry test on XAUUSD: the Arc 1 matrix under two wider vol-stop regimes (EMA-60 k=2 hourly-scale, EMA-240 k=3 multi-hour-scale) instead of Arc 1 minute-scale vol{3,k2}. Same constant round-trip cost (0.25 price units, stress parameter) + vol slippage. Question: does the cost drag collapse and leave a net-positive signal once the stop matches the H1 signal timescale?", + "seed": 0, + "data": { + "instruments": ["XAUUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 2.0 } }, + { "vol": { "length": 240, "k": 3.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.25 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2c-kladder-eurusd.json b/research/campaign-arc2c-kladder-eurusd.json new file mode 100644 index 0000000..59f65cc --- /dev/null +++ b/research/campaign-arc2c-kladder-eurusd.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2c-kladder-eurusd", + "description": "Arc 2c stop-scale ladder on EURUSD: the vol{length} knob only smooths the minute-vol estimator (stop = k*Sqrt(EMA(dP^2,length)) over m1 cycles), so timescale-matched stops require k. Ladder k in {6, 12} on the smoothed EMA-60 estimator (random-walk scaling: 1h-vol ~ 7.7x m1-vol), same constant round-trip cost (0.00012 price units, stress parameter) + vol slippage as arc2-net. Question: does drag ~ 1/k shrink faster than gross per-trade expectancy (in growing R units), leaving a net-positive region?", + "seed": 0, + "data": { + "instruments": ["EURUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 6.0 } }, + { "vol": { "length": 60, "k": 12.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.00012 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2c-kladder-generalize.json b/research/campaign-arc2c-kladder-generalize.json new file mode 100644 index 0000000..c356baa --- /dev/null +++ b/research/campaign-arc2c-kladder-generalize.json @@ -0,0 +1,101 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2c-kladder-generalize", + "description": "Arc 2c cross-instrument leg: both variants under the k-ladder regimes (vol{60,k6}, vol{60,k12}), vol slippage only, generalize floor.", + "seed": 0, + "data": { + "instruments": [ + "GER40", + "US500", + "EURUSD", + "XAUUSD" + ], + "windows": [ + { + "from_ms": 1514764800000, + "to_ms": 1782863999999 + } + ] + }, + "risk": [ + { + "vol": { + "length": 60, + "k": 6.0 + } + }, + { + "vol": { + "length": 60, + "k": 12.0 + } + } + ], + "cost": [ + { + "vol_slippage": { + "slip_vol_mult": 0.1 + } + } + ], + "strategies": [ + { + "ref": { + "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" + }, + "axes": { + "channel_hi.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + }, + "channel_lo.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + } + } + }, + { + "ref": { + "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" + }, + "axes": { + "channel_hi.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + }, + "channel_lo.length": { + "kind": "I64", + "values": [ + 24, + 48, + 96 + ] + } + } + } + ], + "process": { + "ref": { + "content_id": "41863fcae9300b334056c6f2a899e8c2672ecb29387d294e9a6e58f159ef51b4" + } + }, + "presentation": { + "persist_taps": [], + "emit": [ + "selection_report" + ] + } +} \ No newline at end of file diff --git a/research/campaign-arc2c-kladder-ger40.json b/research/campaign-arc2c-kladder-ger40.json new file mode 100644 index 0000000..ad4b4f6 --- /dev/null +++ b/research/campaign-arc2c-kladder-ger40.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2c-kladder-ger40", + "description": "Arc 2c stop-scale ladder on GER40: the vol{length} knob only smooths the minute-vol estimator (stop = k*Sqrt(EMA(dP^2,length)) over m1 cycles), so timescale-matched stops require k. Ladder k in {6, 12} on the smoothed EMA-60 estimator (random-walk scaling: 1h-vol ~ 7.7x m1-vol), same constant round-trip cost (1.5 price units, stress parameter) + vol slippage as arc2-net. Question: does drag ~ 1/k shrink faster than gross per-trade expectancy (in growing R units), leaving a net-positive region?", + "seed": 0, + "data": { + "instruments": ["GER40"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 6.0 } }, + { "vol": { "length": 60, "k": 12.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 1.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2c-kladder-us500.json b/research/campaign-arc2c-kladder-us500.json new file mode 100644 index 0000000..33ae6e2 --- /dev/null +++ b/research/campaign-arc2c-kladder-us500.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2c-kladder-us500", + "description": "Arc 2c stop-scale ladder on US500: the vol{length} knob only smooths the minute-vol estimator (stop = k*Sqrt(EMA(dP^2,length)) over m1 cycles), so timescale-matched stops require k. Ladder k in {6, 12} on the smoothed EMA-60 estimator (random-walk scaling: 1h-vol ~ 7.7x m1-vol), same constant round-trip cost (0.5 price units, stress parameter) + vol slippage as arc2-net. Question: does drag ~ 1/k shrink faster than gross per-trade expectancy (in growing R units), leaving a net-positive region?", + "seed": 0, + "data": { + "instruments": ["US500"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 6.0 } }, + { "vol": { "length": 60, "k": 12.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.5 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-arc2c-kladder-xauusd.json b/research/campaign-arc2c-kladder-xauusd.json new file mode 100644 index 0000000..234cd7c --- /dev/null +++ b/research/campaign-arc2c-kladder-xauusd.json @@ -0,0 +1,37 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "arc2c-kladder-xauusd", + "description": "Arc 2c stop-scale ladder on XAUUSD: the vol{length} knob only smooths the minute-vol estimator (stop = k*Sqrt(EMA(dP^2,length)) over m1 cycles), so timescale-matched stops require k. Ladder k in {6, 12} on the smoothed EMA-60 estimator (random-walk scaling: 1h-vol ~ 7.7x m1-vol), same constant round-trip cost (0.25 price units, stress parameter) + vol slippage as arc2-net. Question: does drag ~ 1/k shrink faster than gross per-trade expectancy (in growing R units), leaving a net-positive region?", + "seed": 0, + "data": { + "instruments": ["XAUUSD"], + "windows": [ { "from_ms": 1514764800000, "to_ms": 1782863999999 } ] + }, + "risk": [ + { "vol": { "length": 60, "k": 6.0 } }, + { "vol": { "length": 60, "k": 12.0 } } + ], + "cost": [ + { "constant": { "cost_per_trade": 0.25 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], + "strategies": [ + { + "ref": { "content_id": "82515a31bfe58ae087b4bd09eb4adb032cc2cabddd71a2761c543066bd237d3d" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + }, + { + "ref": { "content_id": "82d61d13bf21984068d6fd3ae9de9766fe99edb5163ea50ffb3485bfae9f56bc" }, + "axes": { + "channel_hi.length": { "kind": "I64", "values": [24, 48, 96] }, + "channel_lo.length": { "kind": "I64", "values": [24, 48, 96] } + } + } + ], + "process": { "ref": { "content_id": "d568fe9b8a82b7f1862816680de2498b6e045deb47f9941ca991a62baa4c8fe3" } }, + "presentation": { "persist_taps": [], "emit": ["selection_report"] } +} diff --git a/research/campaign-control-always-long.json b/research/campaign-control-always-long.json new file mode 100644 index 0000000..df02fb1 --- /dev/null +++ b/research/campaign-control-always-long.json @@ -0,0 +1,74 @@ +{ + "format_version": 1, + "kind": "campaign", + "name": "control-always-long", + "description": "Beta control: a constant bias=+1 strategy (no signal at all) under the same regimes, window, and slippage cost as the arc2c/arc3 candidates. Any candidate whose R-statistics do not clearly beat this baseline on its instrument is long-beta in a secular bull market, not signal. The bound value param is re-opened as a single-point axis (empty axes are refused); the sweep degenerates to one member.", + "seed": 0, + "data": { + "instruments": [ + "GER40", + "US500", + "EURUSD", + "XAUUSD" + ], + "windows": [ + { + "from_ms": 1514764800000, + "to_ms": 1782863999999 + } + ] + }, + "risk": [ + { + "vol": { + "length": 3, + "k": 2.0 + } + }, + { + "vol": { + "length": 60, + "k": 6.0 + } + }, + { + "vol": { + "length": 60, + "k": 12.0 + } + } + ], + "cost": [ + { + "vol_slippage": { + "slip_vol_mult": 0.1 + } + } + ], + "strategies": [ + { + "ref": { + "content_id": "198ca420039925af330f120376836d9c49a167b26e81324cb4857f5c20f81a44" + }, + "axes": { + "always_long.value": { + "kind": "F64", + "values": [ + 1.0 + ] + } + } + } + ], + "process": { + "ref": { + "content_id": "41863fcae9300b334056c6f2a899e8c2672ecb29387d294e9a6e58f159ef51b4" + } + }, + "presentation": { + "persist_taps": [], + "emit": [ + "selection_report" + ] + } +} \ No newline at end of file diff --git a/research/process-screen-nogen.json b/research/process-screen-nogen.json new file mode 100644 index 0000000..d724da0 --- /dev/null +++ b/research/process-screen-nogen.json @@ -0,0 +1,11 @@ +{ + "format_version": 1, + "kind": "process", + "name": "screen-wf-mc", + "description": "Arc 2 per-instrument methodology: identical to Arc 1's screen-wf-mc-generalize (deflated argmax on sqn_normalized, 90/30-day rolling walk-forward refit, pooled-OOS R-bootstrap) minus the generalize stage, for single-instrument campaigns.", + "pipeline": [ + { "block": "std::sweep", "metric": "sqn_normalized", "select": "argmax", "deflate": true }, + { "block": "std::walk_forward", "in_sample_ms": 7776000000, "out_of_sample_ms": 2592000000, "step_ms": 2592000000, "mode": "rolling", "metric": "sqn_normalized", "select": "argmax" }, + { "block": "std::monte_carlo", "resamples": 1000, "block_len": 5 } + ] +}