Files
foxhunt/docs/plans/2026-05-12-sp22-wr-plateau-investigation.md
jgrusewski f50a974fb6 docs(sp22): H1 falsified + H6 aux→policy state bridge design
H1 result (commit 9adbca826, smoke train-5zmkr, reverted at e8814079d):
  aux_dir_acc HD[2] = 78% with H=200 — aux head LEARNS direction at
  longer horizon. But policy WR stayed pinned at 50.1-50.2% — the
  learned aux signal does NOT propagate to policy (per
  pearl_separate_aux_trunk_when_shared_starves: aux on separate
  trunk with stop-grad to policy).

H6 design (synthesized from all v5-v11 + H1 evidence):

  Wire the aux head's directional probability into the policy STATE
  as an input feature.
    - Policy gradient flows THROUGH the feature (uses it)
    - Stop-grad blocks gradient BACK (aux trunk unaffected, pearl
      preserved)
    - Uses existing padding slot [121..128) in STATE_DIM=128 (no
      layout growth)

  Why this is the structural fix:
    - Aux PROVED directional signal is in the features (78% at H=200)
    - Policy PROVED it can't extract direction (WR=50% across all
      v5-v11 conditions)
    - Bridge connects the two without violating trunk separation
    - Information-theoretic: gives policy a feature it provably
      can't compute itself

  Test outcome interpretation:
    WR > 50.5%  → Mechanism 1 was binding (trunk separation gap)
    WR pinned   → Mechanism 2 (reward density) or Mechanism 3 (V/A
                  unidentifiability) dominates → H3 or V/A fix next

Files changed:
  - docs/plans/2026-05-12-sp22-wr-plateau-investigation.md:
      H6 added as new primary hypothesis after H1; experiment order
      revised
  - docs/dqn-wire-up-audit.md: H6 design entry with three-mechanism
      synthesis

Implementation scope (separate commit):
  1. State layout: claim slot in padding [121..128) for aux_dir_prob
  2. Aux trunk export: pull "up" probability per bar from aux forward
  3. Experience collection: write aux_dir_prob into per-bar state
  4. Stop-grad verification: confirm policy gradient blocked
  5. Trade-open persistence: latch aux_dir_prob for trade duration

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 20:58:13 +02:00

8.7 KiB
Raw Blame History

SP22 — WR Plateau Investigation

Author: jgrusewski + assistant pair Date: 2026-05-12 Branch: TBD (off sp20-aux-h-fixed after merge) Predecessor: SP21 T2.2 (cascade wiring; closed docs/dqn-wire-up-audit.md 2026-05-12) Goal: Move WR from the current ~50.1% plateau toward project_goal_wr_55_pf_2's WR≥55% / PF≥2.0.

State at session start

SP21 T2.2 cascade is feature-complete:

d482efc41  fix(sp21): T2.2 Phase 8.4-fix — winner_conc z-score separation
9f2d0fffb  fix(sp21): T2.2 Phase 8.7 — default ISV buffer
518670198+ ... Phase 8.x stack ...
2937da889  fix(sp21): Return v3 (later v3.1)

All E1-E8 enrichment producers wired to consumers. Local compute-sanitizer clean on eval-baseline closure path. v9 cycle 1 confirms cascade live: win_conc=1.72, curric_conc=0.31, hindsight_mag=1.47e-5.

Binding constraint (v10 hypothesis test, 8 epochs, fold 0):

  • val_Sharpe peaks at E3 (174), monotonically degrades to E8 (66, -62%)
  • WR pinned at 50.1-50.2% across ALL 8 epochs
  • PF pinned at 1.00-1.01
  • Trade volume contracts as policy degrades (492K → 402K)
  • Cascade controllers stable but cannot move the policy off the plateau

Hypotheses

Each hypothesis gets its own atomic experiment. Compare against the v9 baseline (3-epoch, full cascade, fold 0 peak val=174, WR=50.1%).

H1: Label horizon mismatch (project_label_horizon_is_bottleneck)

Theory: The model predicts next-bar return but the actual directional signal lives at a different time scale (e.g., 5-bar, 30-bar lookback in volume bars ≈ 4-25 seconds). With volume bars firing every ~0.78s at 34_496 bars/day, single-bar prediction is dominated by micro-noise.

Test: Modify the training reward (and aux-head label if applicable) to use N-bar forward return for N ∈ {5, 20, 60} bars. Compare WR/PF peak across the three settings.

Predicted outcome if H1 is true: WR jumps above 50.5% at N=20 or N=60.

Predicted outcome if H1 is false: WR stays at 50.1-50.2% across all N.

Cost: 3 smokes × ~30 min each on L40S = 90 min wall-clock.

H2: Action-space pathology (project_hold_hides_directional_signal_hypothesis)

Theory: The 4-direction action space (Short/Hold/Long/Flat) collapses directional signal. Hold (keep position) and Flat (close position) both register as "no-op" in metrics but differ structurally — the model may be learning to predict Hold/Flat as a coward strategy that breaks even without committing direction.

Test: Run with Hold action disabled (force the model to choose between Short, Long, Flat each bar). If WR ≥ 50.1% with no Hold, directional learning is structurally suppressed by Hold. If WR drops significantly below 50% without Hold, Hold is the right thing and the plateau is elsewhere.

Cost: One smoke + one comparison run. ~60 min.

Caveat: requires action-space change in training config + state-layout fields. Larger code change than H1.

H3: Reward shape doesn't produce directional gradient

Theory: Current reward is some combination of per-bar return, trade-cost penalty, hold-time bonus etc. (per pearl_reward_shape_drives_quality_over_quantity). With WR=50% and PF=1.0, the reward gradient may be too noisy to teach direction — model finds break-even policies more easily than directional ones.

Test: Two variants:

  1. Pure directional reward: reward = sign(next_return) * |action_dir| (binary correct/incorrect signal, no magnitude).
  2. Asymmetric loss-aversion (per pearl_audit_unboundedness_for_implicit_asymmetry): amplify losing trades 1.5× to penalize indecisive HOLD-as-default.

Predicted outcome if H3 is true: variant 1 either rises (model learns direction without magnitude confounders) or collapses (magnitude noise was actually helping); variant 2 forces model out of indecision.

Cost: 2 smokes × 30 min each = 60 min.

H4: Feature representation gap

Theory: At 34_496 bars/day on volume bars, the feature set (42-dim market features from extract_ml_features) may not capture multi-bar context needed for directional prediction. MTF features exist in state layout (16 dims at indices 90-106) but eval-baseline feeds zeros for these.

Test: Train with real MTF features computed (not zero-padded). If WR rises ≥ 0.5%, MTF carries the directional signal. If not, MTF is also noise at this resolution.

Cost: Feature pipeline change + one smoke. Higher engineering cost than H1-H3.

H5 (longshot): Bar-resolution itself is too noisy

Theory: 34_496 bars/day = 0.78s/bar is below the timescale where directional signal exists in ES.FUT order flow. Per project_bar_resolution_is_actual_architecture, the "hybrid tick→bar" architecture is aspirational not built. Maybe the model needs longer bars to find signal.

Test: Switch to time bars (e.g., 1-min or 5-min) and re-train. Compare WR/PF against volume-bar baseline.

Cost: Significant — different data ingestion path, retrain from scratch, may need hyperparam re-tuning. Longest experiment.

H6 (added 2026-05-12 after H1 falsification): Aux→Policy state bridge

Theory (synthesized from H1 result + memory pearls): The aux head proved it can extract directional signal at H=200 (78% accuracy within-fold), but pearl_separate_aux_trunk_when_shared_starves walls off the aux trunk from the policy trunk via stop-grad. The proven directional capability sits idle while the policy can't extract direction on its own (WR=50.1% across all conditions).

The bridge: Wire the aux head's directional probability into the policy's STATE as an input feature. Policy gradient flows THROUGH the feature (uses it) but NOT BACK (stop-grad → aux trunk unaffected). Uses one of the existing padding slots [121..128) in STATE_DIM=128.

Test: Add aux probability state slot → run smoke → watch WR. If WR breaks past 50.5%, mechanism 1 (trunk separation gap) was the binding constraint. If WR stays pinned, the bottleneck is downstream of policy state input (Mechanism 2 reward density or Mechanism 3 V/A unidentifiability).

Caveats (must be scoped into implementation):

  1. Aux drops 78%→49% across fold boundaries (within-fold overfit at aux level). May need cross-fold stabilization or feed calibrated probability not argmax.
  2. Aux predicts per-bar; trades hold ~1.7 bars. Aux output at trade-open should persist for trade duration to avoid flicker.
  3. Reward density (Mechanism 2) might still kill the gradient even with direction info in state — follow-up scope.

Cost: ~1 day engineering (state layout, experience collection wireup, aux probability extraction) + 1 smoke ~30min.

Experiment order (revised 2026-05-12)

Run in this priority order, killing early on each as soon as the hypothesis is conclusively resolved:

  1. H1 (label horizon) — FALSIFIED 2026-05-12. Aux learns at H=200 (78% acc) but doesn't propagate to policy (trunk separation).
  2. H6 (aux→policy state bridge) — PRIMARY now. Bridges proven aux capability into policy.
  3. H3 (reward shape) — if H6 falsified, address per-step cost dominance (pearl_event_driven_reward_density_alignment).
  4. H2 (Hold disable) — if H3 inconclusive.
  5. H4 (MTF features) — higher engineering cost.
  6. H5 (bar resolution) — last resort.

Stop after the first hypothesis that produces WR ≥ 51% as a clear signal.

Success criteria

Phase 1 milestone: WR ≥ 51% on val window for ≥ 1 fold (any hypothesis). Phase 2 milestone: WR ≥ 53% sustained across 3 folds. Phase 3 milestone: WR ≥ 55% AND PF ≥ 2.0 (the SP20+ goal).

Each milestone gates the next phase. Phase 1's hypothesis becomes the core architectural change going into Phase 2.

Non-goals (out of scope for SP22)

  • Cascade controller tuning (SP21 T2.2 is closed)
  • Eval pipeline architecture (Phase 8.3-8.7 wraps it; OFI/TLOB/MTF fidelity is a separate deferred concern from SP21)
  • Hyperopt — premature until the WR plateau is broken
  • Multi-symbol generalization — single-symbol (ES.FUT) until plateau resolves

Risk: confounded signal from multiple changes

The cascade is active — its controllers will react to whatever training-side change we make. If WR jumps, distinguishing "cascade amplification of new signal" from "the new signal alone" requires the cascade-off comparison.

Mitigation: For any hypothesis that produces WR ≥ 51%, immediately run a comparison smoke with cascade disabled (set all enrichment producers to constant defaults). If WR holds → signal is real. If WR drops back to 50% → cascade was amplifying the signal (expected and desirable, but flag for the writeup).

Audit pointer

Findings + commit log: docs/dqn-wire-up-audit.md (continue appending under ## 2026-05-12 — SP22 ... headers).