augment_rolling_risk_metrics

augment_rolling_risk_metrics(
    data,
    date_column,
    close_column,
    window=252,
    risk_free_rate=0.0,
    benchmark_column=None,
    annualization_factor=252,
    metrics=None,
    reduce_memory=False,
    engine='auto',
)

The augment_rolling_risk_metrics function calculates rolling risk-adjusted performance metrics for a financial time series using either pandas or polars engine, and returns the augmented DataFrame with columns for Sharpe Ratio, Sortino Ratio, and other metrics.

Parameters

Name Type Description Default
data Union[pd.DataFrame, pd.core.groupby.generic.DataFrameGroupBy] The input data can be a pandas DataFrame or a pandas DataFrameGroupBy object containing the time series data for risk metric calculations. required
date_column str or ColumnSelector The name or selector of the column containing dates or timestamps. required
close_column str, ColumnSelector, or list The column(s) containing closing prices to calculate returns and risk metrics from. Must resolve to exactly one column. required
window int The rolling window size for calculations (e.g., 252 for annual). Default is 252. 252
risk_free_rate float The assumed risk-free rate (e.g., 0.0 for 0%). Default is 0.0. 0.0
benchmark_column str, ColumnSelector, or None Column containing benchmark returns (e.g., market index) for Treynor and Information Ratios. If provided it must resolve to one column. Default is None. None
annualization_factor int The factor to annualize returns and volatility (e.g., 252 for daily data). Default is 252. 252
metrics List[str] or None The list of risk metrics to calculate. Choose from: ‘sharpe_ratio’, ‘sortino_ratio’, ‘treynor_ratio’, ‘information_ratio’, ‘omega_ratio’, ‘volatility_annualized’, ‘skewness’, ‘kurtosis’. Default is None (all metrics). None
reduce_memory bool If True, reduces memory usage of the DataFrame before calculation. Default is False. False
engine str The computation engine to use: ‘pandas’ or ‘polars’. Default is ‘pandas’. 'auto'

Returns

Name Type Description
pd.DataFrame A pandas DataFrame augmented with columns: - {close_column}sharpe_ratio{window}: Rolling Sharpe Ratio - {close_column}sortino_ratio{window}: Rolling Sortino Ratio - {close_column}treynor_ratio{window}: Rolling Treynor Ratio (if benchmark provided) - {close_column}information_ratio{window}: Rolling Information Ratio (if benchmark provided) - {close_column}omega_ratio{window}: Rolling Omega Ratio - {close_column}volatility_annualized{window}: Rolling annualized volatility - {close_column}skewness{window}: Rolling skewness of returns - {close_column}kurtosis{window}: Rolling kurtosis of returns

Notes

This function computes returns from closing prices and calculates rolling risk metrics:

  • Sharpe Ratio: Excess return over risk-free rate divided by volatility
  • Sortino Ratio: Excess return over risk-free rate divided by downside deviation
  • Treynor Ratio: Excess return over risk-free rate divided by beta (requires benchmark)
  • Information Ratio: Excess return over benchmark divided by tracking error (requires benchmark)
  • Omega Ratio: Ratio of gains to losses above/below a threshold
  • Volatility: Annualized standard deviation of returns
  • Skewness: Asymmetry of return distribution
  • Kurtosis: Fat-tailedness of return distribution

Examples

import pandas as pd
import polars as pl
import pytimetk as tk

df = tk.load_dataset("stocks_daily", parse_dates=["date"])

df
symbol date open high low close volume adjusted
0 META 2013-01-02 27.440001 28.180000 27.420000 28.000000 69846400 28.000000
1 META 2013-01-03 27.879999 28.469999 27.590000 27.770000 63140600 27.770000
2 META 2013-01-04 28.010000 28.930000 27.830000 28.760000 72715400 28.760000
3 META 2013-01-07 28.690001 29.790001 28.650000 29.420000 83781800 29.420000
4 META 2013-01-08 29.510000 29.600000 28.860001 29.059999 45871300 29.059999
... ... ... ... ... ... ... ... ...
16189 GOOG 2023-09-15 138.800003 139.360001 137.179993 138.300003 48947600 138.300003
16190 GOOG 2023-09-18 137.630005 139.929993 137.630005 138.960007 16233600 138.960007
16191 GOOG 2023-09-19 138.250000 139.175003 137.500000 138.830002 15479100 138.830002
16192 GOOG 2023-09-20 138.830002 138.839996 134.520004 134.589996 21473500 134.589996
16193 GOOG 2023-09-21 132.389999 133.190002 131.089996 131.360001 22042700 131.360001

16194 rows × 8 columns

# Rolling risk metrics - single stock (pandas)
risk_single = (
    df
    .query("symbol == 'AAPL'")
    .augment_rolling_risk_metrics(
        date_column="date",
        close_column="adjusted",
        window=252,
    )
)

risk_single.glimpse()
<class 'pandas.core.frame.DataFrame'>: 2699 rows of 14 columns
symbol:                              object            ['AAPL', 'AAPL',  ...
date:                                datetime64[ns]    [Timestamp('2013- ...
open:                                float64           [19.7792854309082 ...
high:                                float64           [19.8214282989501 ...
low:                                 float64           [19.3439292907714 ...
close:                               float64           [19.6082134246826 ...
volume:                              int64             [560518000, 35296 ...
adjusted:                            float64           [16.7911796569824 ...
adjusted_sharpe_ratio_252:           float64           [nan, nan, nan, n ...
adjusted_sortino_ratio_252:          float64           [nan, nan, nan, n ...
adjusted_volatility_annualized_252:  float64           [nan, nan, nan, n ...
adjusted_omega_ratio_252:            float64           [nan, nan, nan, n ...
adjusted_skewness_252:               float64           [nan, nan, nan, n ...
adjusted_kurtosis_252:               float64           [nan, nan, nan, n ...
# Rolling risk metrics - polars grouped
pl_df = pl.from_pandas(df)
risk_polars = (
    pl_df
    .group_by("symbol")
    .tk.augment_rolling_risk_metrics(
        date_column="date",
        close_column="adjusted",
        window=60,
    )
)

risk_polars.glimpse()
Rows: 16194
Columns: 14
$ symbol                                     <str> 'META', 'META', 'META', 'META', 'META', 'META', 'META', 'META', 'META', 'META'
$ date                              <datetime[ns]> 2013-01-02 00:00:00, 2013-01-03 00:00:00, 2013-01-04 00:00:00, 2013-01-07 00:00:00, 2013-01-08 00:00:00, 2013-01-09 00:00:00, 2013-01-10 00:00:00, 2013-01-11 00:00:00, 2013-01-14 00:00:00, 2013-01-15 00:00:00
$ open                                       <f64> 27.440000534057617, 27.8799991607666, 28.010000228881836, 28.690000534057617, 29.510000228881836, 29.670000076293945, 30.600000381469727, 31.280000686645508, 32.08000183105469, 30.63999938964844
$ high                                       <f64> 28.18000030517578, 28.469999313354492, 28.93000030517578, 29.790000915527344, 29.600000381469727, 30.600000381469727, 31.450000762939453, 31.959999084472656, 32.209999084472656, 31.709999084472656
$ low                                        <f64> 27.420000076293945, 27.59000015258789, 27.829999923706055, 28.649999618530273, 28.86000061035156, 29.489999771118164, 30.280000686645508, 31.100000381469727, 30.6200008392334, 29.8799991607666
$ close                                      <f64> 28.0, 27.770000457763672, 28.760000228881836, 29.420000076293945, 29.059999465942383, 30.59000015258789, 31.299999237060547, 31.719999313354492, 30.950000762939453, 30.100000381469727
$ volume                                     <i64> 69846400, 63140600, 72715400, 83781800, 45871300, 104787700, 95316400, 89598000, 98892800, 173242600
$ adjusted                                   <f64> 28.0, 27.770000457763672, 28.760000228881836, 29.420000076293945, 29.059999465942383, 30.59000015258789, 31.299999237060547, 31.719999313354492, 30.950000762939453, 30.100000381469727
$ adjusted_sharpe_ratio_60                   <f64> None, None, None, None, None, None, None, None, None, None
$ adjusted_volatility_annualized_60          <f64> None, None, None, None, None, None, None, None, None, None
$ adjusted_sortino_ratio_60                  <f64> None, None, None, None, None, None, None, None, None, None
$ adjusted_omega_ratio_60                    <f64> None, None, None, None, None, None, None, None, None, None
$ adjusted_skewness_60                       <f64> None, None, None, None, None, None, None, None, None, None
$ adjusted_kurtosis_60                       <f64> None, None, None, None, None, None, None, None, None, None
# Rolling risk metrics - selective pandas metrics
risk_selected = (
    df
    .groupby("symbol")
    .augment_rolling_risk_metrics(
        date_column="date",
        close_column="adjusted",
        window=252,
        metrics=["sharpe_ratio", "sortino_ratio", "volatility_annualized"],
    )
)

risk_selected.glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 11 columns
symbol:                              object            ['META', 'META',  ...
date:                                datetime64[ns]    [Timestamp('2013- ...
open:                                float64           [27.4400005340576 ...
high:                                float64           [28.1800003051757 ...
low:                                 float64           [27.4200000762939 ...
close:                               float64           [28.0, 27.7700004 ...
volume:                              int64             [69846400, 631406 ...
adjusted:                            float64           [28.0, 27.7700004 ...
adjusted_sharpe_ratio_252:           float64           [nan, nan, nan, n ...
adjusted_sortino_ratio_252:          float64           [nan, nan, nan, n ...
adjusted_volatility_annualized_252:  float64           [nan, nan, nan, n ...
from pytimetk.utils.selection import contains

selector_df = (
    df
    .groupby("symbol")
    .augment_rolling_risk_metrics(
        date_column=contains("dat"),
        close_column=contains("adj"),
        benchmark_column=contains("clos"),
        window=63,
        metrics=["sharpe_ratio"],
    )
)

selector_df.glimpse()
<class 'pandas.core.frame.DataFrame'>: 16194 rows of 9 columns
symbol:                    object            ['META', 'META', 'META', 'M ...
date:                      datetime64[ns]    [Timestamp('2013-01-02 00:0 ...
open:                      float64           [27.440000534057617, 27.879 ...
high:                      float64           [28.18000030517578, 28.4699 ...
low:                       float64           [27.420000076293945, 27.590 ...
close:                     float64           [28.0, 27.770000457763672,  ...
volume:                    int64             [69846400, 63140600, 727154 ...
adjusted:                  float64           [28.0, 27.770000457763672,  ...
adjusted_sharpe_ratio_63:  float64           [nan, nan, nan, nan, nan, n ...