fix(dqn): normalize VaR/CVaR to percentage returns using initial capital
pnl_history stores raw dollar rewards but VaR calculation treated them as percentage returns, producing nonsensical -500% VaR values. Now divides by initial_capital before calculating percentiles. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3931,8 +3931,14 @@ impl DQNTrainer {
|
||||
|
||||
// WAVE 3.11: Calculate and log VaR/CVaR from PnL history
|
||||
if self.pnl_history.len() > 20 {
|
||||
let returns: Vec<f64> = self.pnl_history.iter().copied().collect();
|
||||
|
||||
// Normalize raw dollar PnL to percentage returns relative to initial capital
|
||||
let capital = self.hyperparams.initial_capital as f64;
|
||||
let returns: Vec<f64> = if capital > 0.0 {
|
||||
self.pnl_history.iter().map(|&pnl| pnl / capital).collect()
|
||||
} else {
|
||||
self.pnl_history.iter().copied().collect()
|
||||
};
|
||||
|
||||
// Calculate VaR/CVaR at 95% and 99% confidence levels
|
||||
// confidence_level=0.05 means we're looking at the worst 5% of returns (95% VaR)
|
||||
let (var_95, cvar_95) = calculate_var_cvar(&returns, 0.05);
|
||||
@@ -3942,10 +3948,10 @@ impl DQNTrainer {
|
||||
"Epoch {}/{}: Risk Metrics - VaR(95%)={:.4}%, CVaR(95%)={:.4}%, VaR(99%)={:.4}%, CVaR(99%)={:.4}% (from {} PnL samples)",
|
||||
epoch + 1,
|
||||
self.hyperparams.epochs,
|
||||
var_95 * 100.0, // Convert to percentage
|
||||
cvar_95 * 100.0, // Convert to percentage
|
||||
var_99 * 100.0, // Convert to percentage
|
||||
cvar_99 * 100.0, // Convert to percentage
|
||||
var_95 * 100.0,
|
||||
cvar_95 * 100.0,
|
||||
var_99 * 100.0,
|
||||
cvar_99 * 100.0,
|
||||
returns.len()
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user