Skip to content

Commit

Permalink
annual turnover metric
Browse files Browse the repository at this point in the history
  • Loading branch information
richklee committed Feb 20, 2024
1 parent 79b6461 commit d0e2da6
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 20 deletions.
25 changes: 21 additions & 4 deletions alphavec/backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ def backtest(
port_rets = strat_rets.sum(axis=1)
port_cum = strat_cum.sum(axis=1)

port_ann_turnover = 1
# Aproximate the portfolio turnover as the weighted average sum of the asset-wise turnover
port_ann_turnover = (strat_ann_turnover * weights.mean().abs()).sum()

port_perf = pd.DataFrame(
{
Expand Down Expand Up @@ -319,9 +320,25 @@ def _turnover(
weights: pd.DataFrame | pd.Series,
rets: pd.DataFrame | pd.Series,
) -> pd.Series | float:
diff = weights.fillna(0).diff().abs()
port = (1 + rets).cumprod() - 1
turnover = diff.sum() / ((1 + port.iloc[-1]) / 2)
"""Calculate the turnover for each position in the strategy."""
# Assume capital of 1000
capital = 1000
# Calculate the delta of the weight between each interval
# Buy will be +ve, sell will be -ve
diff = weights.fillna(0).diff()
# Capital is fixed (uncompounded) for each interval so we can calculate the trade volume
# Sum the volume of the buy and sell trades
buy_volume = (diff.where(diff > 0, 0).abs() * capital).sum()
sell_volume = (diff.where(diff < 0, 0).abs() * capital).sum()
# Trade volume is the minimum of the buy and sell volumes
# Wrap in Series in case of scalar volume sum (when weights is a Series)
trade_volume = pd.concat(
[pd.Series(buy_volume), pd.Series(sell_volume)], axis=1
).min(axis=1)
# Calculate the uncompounded returns to get the average of the portfolio
# Finally take the ratio of trading volume to mean portfolio value
equity = capital + (capital * rets.cumsum())
turnover = trade_volume / equity.mean()
return turnover


Expand Down
30 changes: 15 additions & 15 deletions example.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -709,7 +709,7 @@
" <td>0.512587</td>\n",
" <td>1.616165</td>\n",
" <td>0.632456</td>\n",
" <td>0.644781</td>\n",
" <td>2.944701</td>\n",
" <td>1.000637</td>\n",
" </tr>\n",
" <tr>\n",
Expand All @@ -722,7 +722,7 @@
" <td>1.058797</td>\n",
" <td>0.699507</td>\n",
" <td>0.659074</td>\n",
" <td>4.950039</td>\n",
" <td>2.331747</td>\n",
" <td>1.000745</td>\n",
" </tr>\n",
" <tr>\n",
Expand All @@ -735,7 +735,7 @@
" <td>0.385551</td>\n",
" <td>0.233350</td>\n",
" <td>0.497637</td>\n",
" <td>15.555918</td>\n",
" <td>4.970033</td>\n",
" <td>1.000637</td>\n",
" </tr>\n",
" <tr>\n",
Expand All @@ -748,7 +748,7 @@
" <td>0.615083</td>\n",
" <td>0.081175</td>\n",
" <td>0.585446</td>\n",
" <td>27.251474</td>\n",
" <td>5.556876</td>\n",
" <td>1.000708</td>\n",
" </tr>\n",
" <tr>\n",
Expand All @@ -761,7 +761,7 @@
" <td>0.477024</td>\n",
" <td>0.174253</td>\n",
" <td>0.459495</td>\n",
" <td>21.644242</td>\n",
" <td>5.605835</td>\n",
" <td>1.001065</td>\n",
" </tr>\n",
" <tr>\n",
Expand All @@ -774,7 +774,7 @@
" <td>0.408337</td>\n",
" <td>-0.086424</td>\n",
" <td>0.659143</td>\n",
" <td>59.531211</td>\n",
" <td>8.762681</td>\n",
" <td>1.000637</td>\n",
" </tr>\n",
" </tbody>\n",
Expand Down Expand Up @@ -805,12 +805,12 @@
" \n",
" annual_turnover trades_per_day \n",
"symbol \n",
"BTCUSDT 0.644781 1.000637 \n",
"DOGEUSDT 4.950039 1.000745 \n",
"ETHUSDT 15.555918 1.000637 \n",
"MATICUSDT 27.251474 1.000708 \n",
"SOLUSDT 21.644242 1.001065 \n",
"XRPUSDT 59.531211 1.000637 "
"BTCUSDT 2.944701 1.000637 \n",
"DOGEUSDT 2.331747 1.000745 \n",
"ETHUSDT 4.970033 1.000637 \n",
"MATICUSDT 5.556876 1.000708 \n",
"SOLUSDT 5.605835 1.001065 \n",
"XRPUSDT 8.762681 1.000637 "
]
},
"metadata": {},
Expand Down Expand Up @@ -893,7 +893,7 @@
" <td>1.582458</td>\n",
" <td>2.094833</td>\n",
" <td>0.954154</td>\n",
" <td>1</td>\n",
" <td>1.287296</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
Expand All @@ -904,7 +904,7 @@
"portfolio 1.425487 1.582458 2.094833 0.954154 \n",
"\n",
" annual_turnover \n",
"portfolio 1 "
"portfolio 1.287296 "
]
},
"metadata": {},
Expand Down
3 changes: 2 additions & 1 deletion tests/test_backtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ def test_turnover():
prices = pd.Series([10, 20, 40, 80, 40])
returns = weights * prices.pct_change()

act = bt._ann_turnover(returns, weights)
act = bt._turnover(weights, returns).squeeze()
assert act == 0.48
logging.info(act)


Expand Down

0 comments on commit d0e2da6

Please sign in to comment.