1+ """
2+ The Sharpe Ratio is a widely used risk-adjusted performance metric. It
3+ measures the excess return per unit of risk (volatility), where risk is
4+ represented by the standard deviation of returns.
5+
6+ | Sharpe Ratio | Interpretation |
7+ | -------------- | ------------------------------------------- |
8+ | **< 0** | Bad: Underperforms risk-free asset |
9+ | **0.0 – 1.0** | Suboptimal: Returns do not justify risk |
10+ | **1.0 – 1.99** | Acceptable: Reasonable risk-adjusted return |
11+ | **2.0 – 2.99** | Good: Strong risk-adjusted performance |
12+ | **3.0+** | Excellent: Exceptional risk-adjusted return |
13+
14+ Sharpe Ratio is highly sensitive to the volatility estimate: Inconsistent sampling frequency, short backtests, or low trade frequency can distort it.
15+
16+ Different strategies have different risk profiles:
17+
18+ High-frequency strategies may have high Sharpe Ratios (>3).
19+
20+ Trend-following strategies might have lower Sharpe (1–2) but strong CAGR and Calmar.
21+
22+ Use risk-free rate (~4–5% annual currently) if your backtest spans long periods.
23+
24+ ### 📌 Practical Notes about the implementation:
25+
26+ - Use **daily returns** for consistent Sharpe Ratio calculation and **annualize** the result using this formula:
27+
28+
29+ Sharpe Ratio Formula:
30+ Sharpe Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
31+ (Standard Deviation of Daily Returns × sqrt(Periods Per Year))
32+
33+ - You can also calculate a **rolling Sharpe Ratio** (e.g., over a 90-day window) to detect changes in performance stability over time.
34+
35+ Mean daily return is either based on the real returns from the backtest or the CAGR, depending on the data duration.
36+
37+ When do we use actual returns vs CAGR?
38+
39+ | Data Duration | Use This Approach | Reason |
40+ | ------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- |
41+ | **< 1 year** | Use **CAGR** directly and avoid Sharpe Ratio | Not enough data to estimate volatility robustly |
42+ | **1–2 years** | Use **CAGR + conservative vol estimate** OR Sharpe with caution | Sharpe may be unstable, consider adding error bars or disclaimers |
43+ | **> 2 years** | Use **Sharpe Ratio** based on periodic returns | Adequate data to reliably estimate risk-adjusted return |
44+
45+ """
46+
147from typing import Optional
248
49+ import math
50+
351from investing_algorithm_framework .domain .models import BacktestReport
4- from .cagr import get_cagr
52+ from .mean_daily_return import get_mean_daily_return
553from .risk_free_rate import get_risk_free_rate_us
6- from .standard_deviation import get_standard_deviation_returns
54+ from .standard_deviation import get_daily_returns_std
755
856
957def get_sharpe_ratio (
@@ -25,14 +73,15 @@ def get_sharpe_ratio(
2573 Returns:
2674 float: The Sharpe Ratio.
2775 """
28- annualized_return = get_cagr (backtest_report )
29- # Convert annualized return to decimal
30- annualized_return = annualized_return / 100.0
31- standard_deviation_downside = \
32- get_standard_deviation_returns (backtest_report )
76+ snapshots = backtest_report .get_snapshots ()
77+ snapshots = sorted (snapshots , key = lambda s : s .created_at )
78+ mean_daily_return = get_mean_daily_return (backtest_report )
79+ std_daily_return = get_daily_returns_std (snapshots )
3380
3481 if risk_free_rate is None :
3582 risk_free_rate = get_risk_free_rate_us ()
3683
37- # Calculate sharp ratio
38- return (annualized_return - risk_free_rate ) / standard_deviation_downside
84+ # Formula: Sharpe Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
85+ # (Standard Deviation of Daily Returns × sqrt(Periods Per Year))
86+ return (mean_daily_return * 365 - risk_free_rate ) / \
87+ (std_daily_return * math .sqrt (365 ))
0 commit comments