Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 70a2c33

Browse filesBrowse files
authored
ENH: Add Alpha & Beta stats (#1221)
* added beta & alpha / resolved merge conflict * simplified beta calculation * remove DS_store * move beta & alpha / use log return * Update backtesting/_stats.py * Update backtesting/_stats.py * alpha & beta test * #noqa: E501 * add space * update docs * Revert unrelated change * Add comment
1 parent 5e68bba commit 70a2c33
Copy full SHA for 70a2c33

File tree

Expand file treeCollapse file tree

4 files changed

+13
-0
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+13
-0
lines changed

‎README.md

Copy file name to clipboardExpand all lines: README.md
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ CAGR [%] 16.80
6868
Sharpe Ratio 0.66
6969
Sortino Ratio 1.30
7070
Calmar Ratio 0.77
71+
Alpha [%] 450.62
72+
Beta 0.02
7173
Max. Drawdown [%] -33.08
7274
Avg. Drawdown [%] -5.58
7375
Max. Drawdown Duration 688 days 00:00:00

‎backtesting/_stats.py

Copy file name to clipboardExpand all lines: backtesting/_stats.py
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ def _round_timedelta(value, _period=_data_period(index)):
152152
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
153153
max_dd = -np.nan_to_num(dd.max())
154154
s.loc['Calmar Ratio'] = annualized_return / (-max_dd or np.nan)
155+
equity_log_returns = np.log(equity[1:] / equity[:-1])
156+
market_log_returns = np.log(c[1:] / c[:-1])
157+
cov_matrix = np.cov(equity_log_returns, market_log_returns)
158+
beta = cov_matrix[0, 1] / cov_matrix[1, 1]
159+
# Jensen CAPM Alpha: can be strongly positive when beta is negative and B&H Return is large
160+
s.loc['Alpha [%]'] = s.loc['Return [%]'] - risk_free_rate * 100 - beta * (s.loc['Buy & Hold Return [%]'] - risk_free_rate * 100) # noqa: E501
161+
s.loc['Beta'] = beta
155162
s.loc['Max. Drawdown [%]'] = max_dd * 100
156163
s.loc['Avg. Drawdown [%]'] = -dd_peaks.mean() * 100
157164
s.loc['Max. Drawdown Duration'] = _round_timedelta(dd_dur.max())

‎backtesting/backtesting.py

Copy file name to clipboardExpand all lines: backtesting/backtesting.py
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,8 @@ def run(self, **kwargs) -> pd.Series:
12621262
Sharpe Ratio 0.58038
12631263
Sortino Ratio 1.08479
12641264
Calmar Ratio 0.44144
1265+
Alpha [%] 394.37391
1266+
Beta 0.03803
12651267
Max. Drawdown [%] -47.98013
12661268
Avg. Drawdown [%] -5.92585
12671269
Max. Drawdown Duration 584 days 00:00:00

‎backtesting/test/_test.py

Copy file name to clipboardExpand all lines: backtesting/test/_test.py
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ def test_compute_stats(self):
317317
'Start': pd.Timestamp('2004-08-19 00:00:00'),
318318
'Win Rate [%]': 46.96969696969697,
319319
'Worst Trade [%]': -18.39887353835481,
320+
'Alpha [%]': 394.37391142027462,
321+
'Beta': 0.03803390709192,
320322
})
321323

322324
def almost_equal(a, b):

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.