Skip to content

Commit d47185f

Browse files
authored
Remove flooring on ratios & add Kelly Criterion (#640)
* Remove flooring on ratios and adding Kelly Criterion * fix build
1 parent 109c352 commit d47185f

File tree

4 files changed

+8
-3
lines changed

4 files changed

+8
-3
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Avg. Trade Duration 32 days 00:00:00
7979
Profit Factor 2.13
8080
Expectancy [%] 6.91
8181
SQN 1.78
82+
Kelly Criterion 0.6134
8283
_strategy SmaCross(n1=10, n2=20)
8384
_equity_curve Equ...
8485
_trades Size EntryB...

backtesting/_stats.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ def _round_timedelta(value, _period=_data_period(index)):
117117

118118
# Our Sharpe mismatches `empyrical.sharpe_ratio()` because they use arithmetic mean return
119119
# and simple standard deviation
120-
s.loc['Sharpe Ratio'] = np.clip((s.loc['Return (Ann.) [%]'] - risk_free_rate) / (s.loc['Volatility (Ann.) [%]'] or np.nan), 0, np.inf) # noqa: E501
120+
s.loc['Sharpe Ratio'] = (s.loc['Return (Ann.) [%]'] - risk_free_rate) / (s.loc['Volatility (Ann.) [%]'] or np.nan) # noqa: E501
121121
# Our Sortino mismatches `empyrical.sortino_ratio()` because they use arithmetic mean return
122-
s.loc['Sortino Ratio'] = np.clip((annualized_return - risk_free_rate) / (np.sqrt(np.mean(day_returns.clip(-np.inf, 0)**2)) * np.sqrt(annual_trading_days)), 0, np.inf) # noqa: E501
122+
s.loc['Sortino Ratio'] = (annualized_return - risk_free_rate) / (np.sqrt(np.mean(day_returns.clip(-np.inf, 0)**2)) * np.sqrt(annual_trading_days)) # noqa: E501
123123
max_dd = -np.nan_to_num(dd.max())
124-
s.loc['Calmar Ratio'] = np.clip(annualized_return / (-max_dd or np.nan), 0, np.inf)
124+
s.loc['Calmar Ratio'] = annualized_return / (-max_dd or np.nan)
125125
s.loc['Max. Drawdown [%]'] = max_dd * 100
126126
s.loc['Avg. Drawdown [%]'] = -dd_peaks.mean() * 100
127127
s.loc['Max. Drawdown Duration'] = _round_timedelta(dd_dur.max())
@@ -137,6 +137,8 @@ def _round_timedelta(value, _period=_data_period(index)):
137137
s.loc['Profit Factor'] = returns[returns > 0].sum() / (abs(returns[returns < 0].sum()) or np.nan) # noqa: E501
138138
s.loc['Expectancy [%]'] = returns.mean() * 100
139139
s.loc['SQN'] = np.sqrt(n_trades) * pl.mean() / (pl.std() or np.nan)
140+
win_prob = (pl > 0).sum() / n_trades
141+
s.loc['Kelly Criterion'] = win_prob - (1 - win_prob) / (pl[pl > 0].mean() / pl[pl < 0].mean()) # noqa: E501
140142

141143
s.loc['_strategy'] = strategy_instance
142144
s.loc['_equity_curve'] = equity_df

backtesting/backtesting.py

+1
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,7 @@ def run(self, **kwargs) -> pd.Series:
11341134
Profit Factor 2.08802
11351135
Expectancy [%] 8.79171
11361136
SQN 0.916893
1137+
Kelly Criterion 0.6134
11371138
_strategy SmaCross
11381139
_equity_curve Eq...
11391140
_trades Size EntryB...

backtesting/test/_test.py

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ def test_compute_stats(self):
276276
'Return [%]': 414.2298999999996,
277277
'Volatility (Ann.) [%]': 36.49390889140787,
278278
'SQN': 1.0766187356697705,
279+
'Kelly Criterion': 0.7875234266909678,
279280
'Sharpe Ratio': 0.5803778344714113,
280281
'Sortino Ratio': 1.0847880675854096,
281282
'Start': pd.Timestamp('2004-08-19 00:00:00'),

0 commit comments

Comments
 (0)