fix(rl): trail distance units mismatch — was 400× too small

trail_distance was computed from mean_abs_pnl (scaled reward space)
but compared against mid-entry (price space). At reward_scale=0.0024,
the trail was 0.002 price units = effectively zero, causing immediate
trail-stop on every trade regardless of min_hold.

Fix: divide by reward_scale to recover price-space magnitude:
  trail = k_init × (mean_abs_pnl / reward_scale)

This gives trail ≈ 0.8 ticks at k_init=2.0 — reasonable for ES.
avg_hold should now respect min_hold (100 steps) since trail stops
won't fire on the first tick.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-05-26 00:24:48 +02:00
parent e30f9721e9
commit 787418e779
2 changed files with 13 additions and 4 deletions

View File

@@ -31,6 +31,7 @@
// ISV slot indices (must match crates/ml-alpha/src/rl/isv_slots.rs)
#define RL_TRAIL_K_INIT_INDEX 496
#define RL_MEAN_ABS_PNL_EMA_INDEX 423
#define RL_REWARD_SCALE_INDEX 406
#define RL_PYRAMID_ADD_COUNT_INDEX 507
#define RL_STEP_COUNTER_ISV_INDEX 548
#define RL_ENTRY_COST_INDEX 532
@@ -104,9 +105,11 @@ extern "C" __global__ void rl_fused_reward_pipeline(
const int current_step = (int)isv[RL_STEP_COUNTER_ISV_INDEX];
const int unit_prev = unit_prev_pos_lots[b];
const float k_init = isv[RL_TRAIL_K_INIT_INDEX];
const float mean_abs_pnl = isv[RL_MEAN_ABS_PNL_EMA_INDEX];
const float bootstrap_d = k_init * (mean_abs_pnl + 1e-8f);
const float k_init = isv[RL_TRAIL_K_INIT_INDEX];
const float mean_abs_pnl = isv[RL_MEAN_ABS_PNL_EMA_INDEX];
const float reward_scale = isv[RL_REWARD_SCALE_INDEX];
const float raw_magnitude = mean_abs_pnl / fmaxf(reward_scale, 1e-9f);
const float bootstrap_d = k_init * (raw_magnitude + 1e-8f);
const int base = b * MAX_UNITS;

View File

@@ -26,6 +26,7 @@
#define MAX_UNITS 4
#define RL_TRAIL_K_INIT_INDEX 496
#define RL_MEAN_ABS_PNL_EMA_INDEX 423
#define RL_REWARD_SCALE_INDEX 406
#define RL_PYRAMID_ADD_COUNT_INDEX 507
#define RL_STEP_COUNTER_ISV_INDEX 548
@@ -60,7 +61,12 @@ extern "C" __global__ void rl_unit_state_update(
const float k_init = isv[RL_TRAIL_K_INIT_INDEX];
const float mean_abs_pnl = isv[RL_MEAN_ABS_PNL_EMA_INDEX];
const float bootstrap_d = k_init * (mean_abs_pnl + 1e-8f);
const float reward_scale = isv[RL_REWARD_SCALE_INDEX];
// mean_abs_pnl is in SCALED reward space. Convert to price space
// by dividing out the reward_scale: raw_magnitude ≈ scaled / scale.
// Trail distance must be in price units (compared against mid-entry).
const float raw_magnitude = mean_abs_pnl / fmaxf(reward_scale, 1e-9f);
const float bootstrap_d = k_init * (raw_magnitude + 1e-8f);
const int base = b * MAX_UNITS;