fix(ml): eliminate hold reward bias — remove /1000 penalty divisor

Hold penalty was divided by 1000 (producing ~0.00001), negligible vs
transaction costs (0.05-0.15%). Now uses hold_penalty_weight directly
from hyperopt (0.01-2.0 range).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-03-04 21:02:32 +01:00
parent 0acb89b638
commit 92e47f5efc

View File

@@ -926,13 +926,9 @@ impl RewardFunction {
// |ln(P_{t+1} / P_t)| measures the magnitude of the price change (velocity)
let volatility = next_log_return.abs();
// BUG FIX: Scale hold_penalty_weight to percentage units
// Config value: 0.5-2.0 (raw scalar from hyperopt)
// Scaled value: 0.0005-0.002 (50-200 basis points = 0.05-0.2%)
// This makes hold penalty comparable to transaction costs (0.05-0.15%), not 30x weaker
let hold_penalty_scale = Decimal::try_from(1000.0)
.unwrap_or(Decimal::ONE);
let hold_penalty_pct = self.config.hold_penalty_weight / hold_penalty_scale;
// Hold penalty weight used directly (0.01-2.0 range from hyperopt).
// Previously divided by 1000, making it 0.00001 — negligible vs tx costs (0.05-0.15%).
let hold_penalty_pct = self.config.hold_penalty_weight;
// Compare volatility to movement threshold
let hold_reward = if volatility < self.config.movement_threshold {