fix(D7/N7): zero out_q_gaps during contrarian mode — prevents full-conviction sizing on argmin trades

Addresses reviewer's IMPORTANT flag: the conviction Q-gap was not sign-flipped when
contrarian_active, so downstream env_step would size contrarian (argmin) positions
with maximum conviction, amplifying losses. During contrarian override, set
out_q_gaps=0 so those trades size minimally — the override is deliberate and
temporary; we don't want to compound it with aggressive position sizing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-04-20 20:59:23 +02:00
parent f0d01478ec
commit 8be3d05ab7

View File

@@ -1010,13 +1010,22 @@ extern "C" __global__ void experience_action_select(
/* Output Q-gap for conviction-based position sizing.
* Q-gap = Q(best_direction) - Q(Flat). Higher = more conviction.
* Used by env_step to scale target_position. */
* Used by env_step to scale target_position.
*
* D7/N7: During contrarian override, the action selected is argmin rather
* than argmax. The raw Q(best) - Q(Flat) gap would mislead the position
* sizer into full conviction for what's actually the "deliberately wrong"
* action. Zero out the gap so contrarian trades size minimal. */
if (out_q_gaps != NULL) {
int flat_idx = 3; /* Flat = index 3 for direction(4): Short(0)/Hold(1)/Long(2)/Flat(3) */
float q_best = q_b0[argmax_n(q_b0, b0_size)];
float q_flat = q_b0[flat_idx];
float gap = q_best - q_flat;
out_q_gaps[i] = (gap > 0.0f) ? gap : 0.0f;
if (contrarian_active != 0) {
out_q_gaps[i] = 0.0f;
} else {
int flat_idx = 3; /* Flat = index 3 for direction(4): Short(0)/Hold(1)/Long(2)/Flat(3) */
float q_best = q_b0[argmax_n(q_b0, b0_size)];
float q_flat = q_b0[flat_idx];
float gap = q_best - q_flat;
out_q_gaps[i] = (gap > 0.0f) ? gap : 0.0f;
}
}
}