Summary
ScoringEngine._calculate_kelly_sizing() in src/models/scoring_engine.py defaults to avg_win=1.0 and avg_loss=1.0 (1:1 win/loss ratio) and win_rate=0.5 when no historical data is provided. With these values, Kelly = (0.5 * 1 - 0.5) / 1 = 0. Position sizing is silently disabled for every strategy that has no backtest data, which is the common case since _performance_cache starts empty on every run.
Location
src/models/scoring_engine.py, score_strategies() call site (~line 108):
kelly_size = self._calculate_kelly_sizing(
metrics.get('win_rate', 0.5), # default 0.5
metrics.get('avg_win', 1.0), # default 1.0
metrics.get('avg_loss', 1.0) # default 1.0
)
With those defaults: b = 1.0/1.0 = 1, kelly_full = (0.5*1 - 0.5)/1 = 0. After fractional Kelly: still 0.
Impact
ScoredStrategy.kelly_size is 0 for all strategies unless the caller explicitly provides avg_win/avg_loss in the risk_metrics dict
RecommendationEngine uses kelly_size directly for position sizing recommendations
- The user is told "recommended position size: 0%" — which looks like no position should be taken, not like a missing data condition
- There is no warning, no fallback size, no indicator that the 0 is a data artifact
Recommended fix
Two options:
-
Return a conservative default (e.g., max_position_size * 0.5) when historical data is absent, with a flag in ScoredStrategy indicating it is a default:
if not metrics.get('avg_win') or not metrics.get('avg_loss'):
return self.max_position_size * 0.5 # conservative default, no historical data
-
Return None and have RecommendationEngine handle the missing-data case explicitly, surfacing it to the user rather than silently outputting 0.
Option 2 is cleaner: make missing data visible rather than masking it with a zero that reads as "don't trade."
Summary
ScoringEngine._calculate_kelly_sizing()insrc/models/scoring_engine.pydefaults toavg_win=1.0andavg_loss=1.0(1:1 win/loss ratio) andwin_rate=0.5when no historical data is provided. With these values, Kelly =(0.5 * 1 - 0.5) / 1 = 0. Position sizing is silently disabled for every strategy that has no backtest data, which is the common case since_performance_cachestarts empty on every run.Location
src/models/scoring_engine.py,score_strategies()call site (~line 108):With those defaults:
b = 1.0/1.0 = 1,kelly_full = (0.5*1 - 0.5)/1 = 0. After fractional Kelly: still 0.Impact
ScoredStrategy.kelly_sizeis 0 for all strategies unless the caller explicitly providesavg_win/avg_lossin therisk_metricsdictRecommendationEngineuseskelly_sizedirectly for position sizing recommendationsRecommended fix
Two options:
Return a conservative default (e.g.,
max_position_size * 0.5) when historical data is absent, with a flag inScoredStrategyindicating it is a default:Return
Noneand haveRecommendationEnginehandle the missing-data case explicitly, surfacing it to the user rather than silently outputting 0.Option 2 is cleaner: make missing data visible rather than masking it with a zero that reads as "don't trade."