Skip to content

Kelly criterion sizing silently returns 0 when no historical performance data is available #17

@bradsmithmba

Description

@bradsmithmba

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:

  1. 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
  2. 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."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions