diff --git a/crates/ml-alpha/cuda/rl_reward_scale_controller.cu b/crates/ml-alpha/cuda/rl_reward_scale_controller.cu index fcb98773f..58e586e56 100644 --- a/crates/ml-alpha/cuda/rl_reward_scale_controller.cu +++ b/crates/ml-alpha/cuda/rl_reward_scale_controller.cu @@ -130,6 +130,15 @@ extern "C" __global__ void rl_reward_scale_controller( const float a = fmaxf(alpha_step, WIENER_ALPHA_FLOOR); float out = (1.0f - a) * prev + a * target; + // Per-step movement clamp: scale moves at most ±2% from previous. + // Damps the 10,000× oscillation from sparse trade PnL spikes to + // a smooth ramp. At 2%/step, doubling takes ~35 steps, halving + // takes ~35 steps — fast enough to track regime changes, slow + // enough to give Q stable targets across the replay window. + const float max_move = prev * 1.02f; + const float min_move = prev * 0.98f; + out = fmaxf(min_move, fminf(out, max_move)); + out = fmaxf(scale_min, fminf(out, REWARD_SCALE_MAX)); isv[RL_REWARD_SCALE_INDEX] = out; }