Skip to content

annualized_return ignores trading_days constructor parameter, hardcodes 365.25 #12

@bradsmithmba

Description

@bradsmithmba

Summary

src/backtesting/performance/metrics.py accepts a trading_days parameter in its constructor but never uses it. annualized_return is hardcoded to divide by 365.25 regardless of what was configured. The parameter is dead code and the metric is silently wrong for anyone who set trading_days=252 (the standard for equity markets).

Location

src/backtesting/performance/metrics.py:

# Constructor accepts trading_days
def __init__(self, ..., trading_days: int = 252):
    self.trading_days = trading_days  # stored but never read

# annualized_return uses hardcoded 365.25
annualized_return = (1 + total_return) ** (365.25 / trading_days_held) - 1
#                                           ^^^^^^ should be self.trading_days

Impact

  • Annualized return is always calculated on a calendar-day basis, not a trading-day basis
  • For a 252 trading-day year, calendar days inflate annualized returns by a factor of ~1.45x vs trading-day convention
  • The trading_days=252 constructor argument a user passes does nothing, so callers think they have control they don't
  • Related: test_sharpe_ratio_calculation asserts annualized_return > 10 (interpreted as >1000%), which passes only because this inflation produces nonsense numbers that satisfy the assertion by accident

Correct fix

annualized_return = (1 + total_return) ** (self.trading_days / trading_days_held) - 1

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