feat(plan): track intra_trade_max_pnl in ps[21] for hindsight labels (N18)

Max unrealized P&L tracked each bar during trade. Enables hindsight
plan learning: compare plan's profit_target vs actual max P&L.
The plan head learns optimal targets from what was achievable.
Reset on trade entry, reversal, and episode hard/soft reset.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-17 09:35:08 +02:00
parent 614d4dbf84
commit d144171b92

View File

@@ -34,7 +34,7 @@
* [10] hold_time — consecutive steps with position (total, not just losing)
* [11] realized_pnl — cumulative realized PnL
* [20] intra_trade_max_dd — worst unrealized drawdown during current trade (v8)
* [21] (reserved) — was last_trade_t (clustering stats, slot retained)
* [21] intra_trade_max_pnl — best unrealized P&L during current trade (hindsight)
* [22] (reserved) — was interval_sum (clustering stats, slot retained)
* [23] plan_target_bars — 0=no plan, >0=active plan max hold bars
* [24] plan_profit_target — raw profit threshold %
@@ -1499,6 +1499,7 @@ extern "C" __global__ void experience_env_step(
ps[28] = pp[5]; /* asymmetry */
/* Store entry regime_stability for drift detection (P12). */
ps[29] = (isv_signals_ptr != NULL) ? isv_signals_ptr[11] : 1.0f;
ps[21] = 0.0f; /* reset max P&L for new trade */
/* Apply conviction to position size — scale by readiness for smooth ramp */
position *= fmaxf(ps[27] * readiness, 0.1f);
}
@@ -1618,9 +1619,11 @@ extern "C" __global__ void experience_env_step(
float intra_trade_max_dd = (ps[20]);
if (entering_trade) {
intra_trade_max_dd = 0.0f;
ps[21] = 0.0f; /* reset max P&L for new trade */
}
if (reversing_trade) {
intra_trade_max_dd = 0.0f;
ps[21] = 0.0f; /* reset max P&L for reversed trade */
}
if (fabsf(position) > 0.001f && entry_price > 0.0f) {
float unrealized = (position > 0.0f)
@@ -1628,6 +1631,11 @@ extern "C" __global__ void experience_env_step(
: (entry_price - raw_close) / entry_price;
float current_dd = fminf(unrealized, 0.0f);
intra_trade_max_dd = fminf(intra_trade_max_dd, current_dd);
/* Track best unrealized P&L during trade (for hindsight plan labels) */
float pnl_pct = (raw_close - entry_price) / fmaxf(fabsf(entry_price), 1.0f)
* ((position > 0.0f) ? 1.0f : -1.0f);
ps[21] = fmaxf(ps[21], pnl_pct); /* max P&L during trade */
}
/* Idle counter (flat bars) — used for state features, no penalty */
@@ -1956,7 +1964,7 @@ extern "C" __global__ void experience_env_step(
ps[18] = (sum_returns); /* Kelly continuous: sum returns */
ps[19] = (sum_sq_returns); /* Kelly continuous: sum returns^2 */
ps[20] = (intra_trade_max_dd); /* v7: intra-trade max drawdown */
/* ps[21], ps[22]: reserved (formerly clustering stats, retained for slot stability) */
/* ps[22]: reserved (formerly clustering stats, retained for slot stability) */
/* ---- NO global reward clamp ---- */
/* Reward v7: sparse trade-completion with asymmetric soft-clamp.
@@ -2148,6 +2156,7 @@ extern "C" __global__ void experience_env_step(
ps[18] = 0.0f;
ps[19] = 0.0f;
ps[20] = 0.0f; /* intra_trade_max_dd */
ps[21] = 0.0f; /* intra_trade_max_pnl */
ps[23] = 0.0f; ps[24] = 0.0f; ps[25] = 0.0f;
ps[26] = 0.0f; ps[27] = 0.0f; ps[28] = 0.0f;
ps[29] = 0.0f; /* plan slots zeroed */
@@ -2161,6 +2170,7 @@ extern "C" __global__ void experience_env_step(
ps[12] = 0.0f; /* entry_price — no active trade */
ps[13] = (ps[11]); /* trade_start_pnl = current realized_pnl */
ps[20] = 0.0f; /* intra_trade_max_dd — reset for next trade */
ps[21] = 0.0f; /* intra_trade_max_pnl — reset for next trade */
ps[23] = 0.0f; ps[24] = 0.0f; ps[25] = 0.0f;
ps[26] = 0.0f; ps[27] = 0.0f; ps[28] = 0.0f;
ps[29] = 0.0f; /* plan slots zeroed on trade complete */