fix(adaptive-strategy): replace fake Kelly return history with error + fallback
get_historical_returns was returning a hardcoded 20-value vector of fake returns for ALL symbols, causing Kelly criterion to compute position sizes based on fabricated data. Now returns an error explaining that no market data feed is connected. calculate_position_size catches the Kelly/PPO sizing errors and falls back to standard fixed-fraction sizing with a warning log, instead of propagating the error to callers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ use anyhow::Result;
|
||||
use num_traits::ToPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
// Add missing core types
|
||||
use super::config::{PositionSizingMethod, RiskConfig};
|
||||
@@ -382,26 +382,50 @@ impl RiskManager {
|
||||
symbol, expected_return
|
||||
);
|
||||
|
||||
// Use enhanced Kelly sizer if available and method is Kelly
|
||||
// Use enhanced Kelly sizer if available and method is Kelly.
|
||||
// Falls back to standard sizing if historical data is unavailable.
|
||||
if let PositionSizingMethod::Kelly = &self.config.position_sizing_method {
|
||||
if self.kelly_sizer.is_some() {
|
||||
return self
|
||||
match self
|
||||
.calculate_kelly_position_size(
|
||||
symbol,
|
||||
expected_return,
|
||||
confidence,
|
||||
current_price,
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
Ok(recommendation) => return Ok(recommendation),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
symbol = %symbol,
|
||||
error = %e,
|
||||
"Kelly sizing failed (no historical data?), falling back to fixed-fraction sizing"
|
||||
);
|
||||
// Fall through to standard sizing below
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use PPO sizer if available and method is PPO
|
||||
// Use PPO sizer if available and method is PPO.
|
||||
// Falls back to standard sizing if historical data is unavailable.
|
||||
if let PositionSizingMethod::PPO = &self.config.position_sizing_method {
|
||||
if self.ppo_sizer.is_some() {
|
||||
return self
|
||||
match self
|
||||
.calculate_ppo_position_size(symbol, expected_return, confidence, current_price)
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
Ok(recommendation) => return Ok(recommendation),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
symbol = %symbol,
|
||||
error = %e,
|
||||
"PPO sizing failed (no historical data?), falling back to fixed-fraction sizing"
|
||||
);
|
||||
// Fall through to standard sizing below
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,15 +579,17 @@ impl RiskManager {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get historical returns for a symbol (production implementation)
|
||||
async fn get_historical_returns(&self, _symbol: &str) -> Result<Vec<f64>> {
|
||||
// In production, this would fetch from market data service
|
||||
// For now, return sample data
|
||||
Ok(vec![
|
||||
0.05_f64, -0.02_f64, 0.08_f64, -0.03_f64, 0.06_f64, -0.01_f64, 0.04_f64, -0.02_f64,
|
||||
0.07_f64, -0.01_f64, 0.03_f64, -0.04_f64, 0.09_f64, -0.02_f64, 0.05_f64, -0.03_f64,
|
||||
0.06_f64, -0.01_f64, 0.08_f64, -0.02_f64,
|
||||
])
|
||||
/// Get historical returns for a symbol.
|
||||
///
|
||||
/// Returns an error because no market data feed is connected yet.
|
||||
/// Callers should fall back to fixed-fraction position sizing when this fails.
|
||||
async fn get_historical_returns(&self, symbol: &str) -> Result<Vec<f64>> {
|
||||
anyhow::bail!(
|
||||
"No historical return data available for '{}'. \
|
||||
A market data service must be integrated to provide real return history. \
|
||||
Falling back to fixed-fraction sizing is recommended.",
|
||||
symbol
|
||||
)
|
||||
}
|
||||
|
||||
/// Build market data for Kelly calculation
|
||||
|
||||
Reference in New Issue
Block a user