# Learned position-conditioned exit/hold experiment — 2026-09-21

## Recommendation

**Stop optimizing this four-bar continuation-value head. Do not promote it or port it to TradingView.** Both the regularized linear model and a small nonlinear tree failed to produce consistent improvements. Keep the experimental harness and results.

The next experiment I would prioritize is a **bounded, volatility-scaled trailing-stop study on BTC 4H**, preceded by refreshed chart/trade exports and a reserved forward evaluation period. In this experiment's seven paired windows, 35 of 46 baseline 4H exits (76%) were trailing-stop exits. An exit head that is required to honor those stops cannot improve those decisions. This is a reason to investigate that mechanism, not evidence that wider or volatility-scaled stops will improve returns. Legacy strategyMain code already includes ATR stops; repository search found no comparable completed study for the current MLP strategy, so this is new to this MLP experiment series, not new to the repository as a whole.

A follow-up should compare the existing fixed percentage stop against a small predeclared set of causal ATR/price-normalized stops, preserving a maximum loss bound and preventing the stop from loosening after entry. Start with an event study of stop-outs versus subsequent recovery/continued decline; do not jump straight to a broad threshold sweep. Measure risk and avoided losses as well as missed recovery. Require sufficient untouched trades before a Pine port.

## What was built and run

The first-stage protocol was recorded in `docs/mlp_learned_exit_protocol_2026_09_21.md` before fitting candidate models. A subsequent nonlinear-capacity check was recorded after viewing the linear results; it is exploratory, not independent confirmation.

- Five BTC timeframes: 4H, 6H, 8H, 12H, 1D.
- Six configured historical evaluation windows plus the available period beginning 2026-03-01.
- Frozen promoted entry models, thresholds and trailing-stop percentages.
- Expanding exit-head fits; all target endpoints must be strictly before the evaluation start.
- Trade-weighted training: every originating trade has equal total weight despite differing durations.
- At least 20 originating training trades to fit; otherwise the policy abstains to the baseline.
- Market-only, position-only and combined input ablations, plus a constant-delay control.
- Two model families: ridge with penalty 1.0; depth-2 regression tree with at most four leaves and at least 10% of training weight per leaf. No hyperparameter search.
- 315 final metric rows, 175 model/cutoff audit records, and 15,817 saved predictions independently reconstructed from model artifacts and candidate state.

The market inputs are the MLP score, two-bar score change, four-bar return, 20-bar volatility, MVRV regime, relative volume and Fed liquidity sign. Position inputs are trade age, unrealized return, drawdown from the trade high, extension age, and a few fixed interactions. Combined models also receive score × return and regime × drawdown interactions.

The head estimates incremental after-fee wealth from holding four more bars versus exiting now. The continuation ends early if the existing stop fires or the extension budget expires. This uses a realizable fixed horizon, not the best future price. Entry cost is already sunk; exit fees follow the canonical 0.5% convention. Training labels contain explicit endpoint timestamps so overlapping future labels can be purged.

Training states include baseline positions and hypothetical continuations after score exits, limited to 12 bars and stopped by the existing trailing rule. During evaluation, the model uses **its own candidate position state**, including its own entry bar and price; it never reads exported TradingView position or holding-age columns.

The veto variants decide only when a score exit occurs or is pending. A positive forecast holds; a nonpositive forecast exits. The manage variants can also exit earlier on ordinary holding bars. Score exits remain pending and are reconsidered each bar; extension is capped at 12 bars. Trailing stops and trading-window restrictions always take precedence. Every evaluation starts flat, including the paired baseline, with market indicators warmed on prior data. Thus results are separate window experiments, not one continuous stitched equity curve.

## Historical results

P&L comparison against the paired baseline across 30 historical timeframe/window pairs:

| Policy | Better | Worse | Tied | Calmar improved |
|---|---:|---:|---:|---:|
| Constant 12-bar score-exit delay | 5 | 25 | 0 | 6 |
| Linear market-only veto | 3 | 10 | 17 | 3 |
| Linear position-only veto | 2 | 23 | 5 | 3 |
| Linear combined veto | 1 | 15 | 14 | 1 |
| Linear combined early-exit management | 7 | 21 | 2 | 3 |
| Tree market-only veto | 3 | 16 | 11 | 5 |
| Tree combined veto | 5 | 14 | 11 | 5 |
| Tree combined early-exit management | 7 | 21 | 2 | 2 |

Two of the 30 historical windows have fewer than 20 training trades and learned variants abstain. Ties also arise when the fitted policy makes the same decisions as the baseline; a fitted model is not proof of incremental value.

The linear combined veto improved P&L over the linear market-only veto in only 4 historical pairs, worsened 12 and tied 14. Its median P&L change versus baseline was -0.17 percentage points. The early-exit models were much more disruptive: median P&L changes were -34.92 points for linear and -20.61 points for the tree. Lower drawdown alone does not justify abandoning profitable holding periods.

The opportunity diagnostic is also unfavorable to a general delay policy. Among score exits with a complete four-bar label in these evaluation windows, average incremental holding advantage was negative on every timeframe. Only about 18% of 4H events and 40–47% elsewhere benefited from the short extension. These labels are diagnostics, not evidence of a profitable perfect-foresight trading policy; event effects cannot be added as if later entries were unaffected.

## Later-period results: intriguing but insufficient

The period after 2026-03-01 is later than the recorded upstream training cutoff, but it was already inspected in earlier experiments. It is not a pristine holdout. Available exports end in August for 4H/6H/8H and June for 12H/1D.

| TF | Baseline P&L | Linear combined veto | Tree combined veto | Constant delay | Baseline entries |
|---|---:|---:|---:|---:|---:|
| 4H | 9.24% | 9.24% | 12.46% | 12.46% | 6 |
| 6H | 0.00% | 0.00% | 0.00% | 0.00% | 0 |
| 8H | -5.42% | 24.59% | 22.76% | 22.76% | 3 |
| 12H | -12.19% | -12.19% | -12.19% | -5.76% | 3 |
| 1D | -10.51% | -10.51% | -10.51% | 0.34% | 4 |

The 8H learned candidates take only two entries. The simple delay control captures most or all of their apparent improvement. The tree manage policy also looks good on later 4H (18.68% versus 9.24%), but has only eight entries and loses to the baseline in 21 of 30 historical pairs. No later-period policy/timeframe combination reaches the repository's 10-entry coverage floor. These observations do not establish a repeatable edge or justify selecting a model after seeing the period.

The 1D baseline differs from the prior fixed-policy report because these evaluation windows start flat rather than carry in the preceding trade. Both candidates and controls use that same reset.

## What we learned and what remains untested

Position awareness is feasible and inexpensive: a small numeric head or four-leaf tree can be evaluated alongside the existing score without adding external data requests. But adding trade age and unrealized return did not reliably improve decisions in this experiment.

This conclusion is scoped to the target and models tested. Four-bar continuation is myopic relative to some of the baseline's long winning trades. It does not explicitly price the opportunity to exit and later re-enter, and training includes ordinary in-position bars as well as exit-decision states. The candidate rollout evaluates the resulting entry displacement, but the supervised label does not optimize that full objective. Training only on exit-decision states, longer/multiple horizons, a small MLP, or fitted-Q optimal stopping remain untested. I would not pursue those next on the same repeatedly inspected sample: they add search freedom while the present evidence is weak and independent trade counts are small.

Historical exit-head cutoffs are clean, but **the complete pipeline is not historical out-of-fold**: the upstream promoted MLPs and thresholds were selected using that broader history. The 30 pairs are also correlated BTC observations, not 30 independent trials. These are conditional component screens. Any future promising result needs nested upstream/exit-model training or a genuinely untouched forward sample before claims of generalization.

Other limitations: TradingView exports may contain revised macro data; this experiment cannot certify point-in-time feature vintages. Return/stop simulation preserves the repository's close-price approximation and fee timing, not exact broker fills. Existing data warnings include gaps, shortened warmup and stale exports. The incomplete final row is excluded, as in the prior experiment; leading relative-volume warmup rows are also removed, entirely before SCORE_START. No score history is discarded.

## Code, artifacts and reproduction

New implementation:

- `strategies/mlp_learned_exit.py`: causal inputs, trade-weighted head fitting, purged targets and sequential policy replay.
- `tools/run_mlp_learned_exit_experiment.py`: enforced prerequisites, paired controls, folds, models, decision traces and manifests.
- `tests/test_mlp_learned_exit.py`: state, target, model and temporal-isolation tests.

`_score_to_signals(..., return_opportunities=True)` exposes the canonical pre-execution opportunities for this runner. The default strategy path is unchanged. No Pine code, winner artifact, model weights, parameter file or production default was modified by this experiment.

Final canonical artifacts are in `results/mlp_experiments/learned_exit_nonlinear/`:

- `metrics.csv`: 315 paired evaluation rows.
- `models.json`: model parameters, training sample/trade counts, maximum label timestamp, cutoff and abstention status.
- `decisions.csv`: prediction/exit traces with actual candidate entry and position context.
- `exit_opportunities.csv`: baseline score-exit continuation diagnostics.
- `manifest.json`: exact inputs, policies, constants and source/input/output SHA-256 hashes.
- `audit.json`: completed independent artifact/prediction reconstruction checks.

The initial ridge-only screen remains in `results/mlp_experiments/learned_exit/`; the final directory reruns all linear controls alongside the nonlinear variants on the final source version.

```bash
.venv/bin/python tools/validate_chart_data.py
.venv/bin/python tools/run_mlp_learned_exit_experiment.py \
  --output results/mlp_experiments/learned_exit_nonlinear
.venv/bin/python -m pytest tests/ -q
```

`--tfs 6H` runs a smaller reproducibility check. Output directories are explicit and there is no promotion path.

## Prerequisites and verification

Before fitting, `sync_params.py` passes for all 20 parameter files and `check_pine.py` exits 0. The checker previously rejected counts exactly equal to its hard limits. Boundary regression tests demonstrated that defect; it now rejects only over-limit estimates and warns at capacity. TradingView permits a maximum of 64 plot counts; individual function calls can consume multiple counts, so this remains a static estimate rather than proof of compilation. See [TradingView's limits documentation](https://www.tradingview.com/pine-script-docs/writing/limitations/). The project's conservative 40-request ceiling remains in place. Pine and the validation sentinel were not changed.

Final fast suite: **171 passed, 2 slow tests skipped**, with three existing warnings. `git diff --check` passes. Tests cover the unchanged default replay across smoothing/stop combinations, mandatory stop priority, extension caps, future-label purge, training-only scalers, trade weighting, candidate-owned state, prefix causality, fee-aware labels, missing/nonfinite input rejection, nonlinear prediction behavior and hard-limit boundaries.

A separate audit verified all source/input/output hashes, 175 strict label cutoffs, all 315 unique metric rows, and reconstructed all 15,817 recorded learned predictions from the saved model parameters and candidate state. Every prediction matched, including tree inference precision. Canonical baseline equivalence is asserted for every timeframe/window during each run.

Local review checked target/inference consistency, model training boundaries, default-path isolation, actual position state, stop/cap precedence, data exclusions and report arithmetic. It caught and addressed numerical reduction warnings and matched exported tree inference to sklearn's float32 branch behavior. No independent peer review or TradingView execution was performed. Changes remain local and uncommitted alongside the pre-existing work.
