Metrics#

Portfolio and asset performance/risk metric functions: return compounding and annualization, higher-moment statistics, risk-adjusted performance (Sharpe ratio), drawdown analysis, and Value-at-Risk / Conditional Value-at-Risk estimation.

Portfolio and asset performance/risk metric functions.

This module provides a collection of statistical and financial functions for analyzing return series, including higher-moment statistics (skewness, kurtosis), return compounding and annualization, risk-adjusted performance (Sharpe ratio), drawdown analysis, and Value-at-Risk / Conditional Value-at-Risk estimation (historic and Gaussian/Cornish-Fisher).

All functions that accept a returns argument r are designed to work transparently with either a pandas.Series (a single return series) or a pandas.DataFrame (multiple return series, one per column), returning a scalar or a pandas.Series of per-column results accordingly.

annualize_rets(r: Series | DataFrame, periods_per_year: int) → float | Series[source]#

Annualize a set of returns.

Notes

We should infer the periods per year, but that is currently left as an exercise to the reader :-)

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of periodic returns.

  • periods_per_year (int) – Number of periods per year (e.g. 252 for daily returns, 12 for monthly returns).

Returns:

The annualized return. Returns a float if r is a Series, or a Series of per-column annualized returns if r is a DataFrame.

Return type:

float or pandas.Series

annualize_vol(r: Series | DataFrame, periods_per_year: int) → float | Series[source]#

Annualize the volatility of a set of returns.

Notes

We should infer the periods per year, but that is currently left as an exercise to the reader :-)

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of periodic returns.

  • periods_per_year (int) – Number of periods per year (e.g. 252 for daily returns, 12 for monthly returns).

Returns:

The annualized volatility. Returns a float if r is a Series, or a Series of per-column annualized volatilities if r is a DataFrame.

Return type:

float or pandas.Series

compound(r: Series | DataFrame) → float | Series[source]#

Compound the set of returns in r.

Parameters:

r (pandas.Series or pandas.DataFrame) – Series or DataFrame of periodic returns.

Returns:

The compounded (total) return over the whole period. Returns a float if r is a Series, or a Series of per-column compounded returns if r is a DataFrame.

Return type:

float or pandas.Series

cvar_historic(r: Series | DataFrame, level: float = 5) → float | Series[source]#

Compute the historic Conditional Value at Risk (CVaR) of r.

The CVaR (also known as expected shortfall) is the average of the returns that fall beyond the historic VaR threshold.

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

  • level (float, default 5) – The percentile level, in percent, used to compute the underlying VaR threshold (see var_historic()).

Returns:

The historic CVaR, expressed as a positive number. Returns a float if r is a Series, or a Series of per-column CVaR values if r is a DataFrame.

Return type:

float or pandas.Series

Raises:

TypeError – If r is neither a pandas.Series nor a pandas.DataFrame.

drawdown(return_series: Series) → DataFrame[source]#

Compute the wealth index, running maximum, and drawdown of a return series.

Parameters:

return_series (pandas.Series) – Time series of asset returns.

Returns:

DataFrame indexed like return_series, with columns:

  • Wealth: the cumulative wealth index, starting at 1000.

  • Previous Peak: the running maximum of the wealth index.

  • Drawdown: the percentage drawdown from the previous peak.

Return type:

pandas.DataFrame

kurtosis(r: Series | DataFrame) → float | Series[source]#

Compute the kurtosis of the supplied returns.

Alternative to scipy.stats.kurtosis() that uses the population standard deviation (ddof=0).

Parameters:

r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

Returns:

The kurtosis of r. Returns a float if r is a Series, or a Series of per-column kurtosis values if r is a DataFrame.

Return type:

float or pandas.Series

portfolio_return_daily_ts(portfolio_weights: DataFrame, asset_returns: DataFrame) → Series[source]#

Calculate daily portfolio returns from weights and asset returns.

The two DataFrames are aligned on their common dates (index) and common assets (columns) before computing the weighted sum of returns.

Parameters:
  • portfolio_weights (pandas.DataFrame) – DataFrame with dates as index and assets as columns, containing the portfolio weight of each asset on each date.

  • asset_returns (pandas.DataFrame) – DataFrame with dates as index and assets as columns, containing the periodic return of each asset on each date.

Returns:

Series of daily portfolio returns, indexed by the dates common to both portfolio_weights and asset_returns.

Return type:

pandas.Series

semideviation(r: Series | DataFrame) → float | Series[source]#

Compute the semideviation (negative semideviation) of r.

Parameters:

r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

Returns:

The semideviation, computed as the population standard deviation (ddof=0) of the negative values in r. Returns a float if r is a Series, or a Series of per-column semideviations if r is a DataFrame.

Return type:

float or pandas.Series

Raises:

TypeError – If r is neither a pandas.Series nor a pandas.DataFrame.

sharpe_ratio(r: Series | DataFrame, riskfree_rate: float, periods_per_year: int) → float | Series[source]#

Compute the annualized Sharpe ratio of a set of returns.

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of periodic returns.

  • riskfree_rate (float) – Annual risk-free rate, expressed as a decimal (e.g. 0.03 for 3%). It’s converted internally to a per-period rate using periods_per_year.

  • periods_per_year (int) – Number of periods per year (e.g. 252 for daily returns, 12 for monthly returns).

Returns:

The annualized Sharpe ratio. Returns a float if r is a Series, or a Series of per-column Sharpe ratios if r is a DataFrame.

Return type:

float or pandas.Series

skewness(r: Series | DataFrame) → float | Series[source]#

Compute the skewness of the supplied returns.

Alternative to scipy.stats.skew() that uses the population standard deviation (ddof=0).

Parameters:

r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

Returns:

The skewness of r. Returns a float if r is a Series, or a Series of per-column skewness values if r is a DataFrame.

Return type:

float or pandas.Series

summary_stats(r: DataFrame, riskfree_rate: float = 0.0, periods_per_year: int = 252) → DataFrame[source]#

Compute aggregated summary statistics for the returns in r.

Parameters:
  • r (pandas.DataFrame) – DataFrame of periodic returns, one column per asset/strategy.

  • riskfree_rate (float, default 0.0) – Annual risk-free rate, expressed as a decimal, used to compute the Sharpe ratio (see sharpe_ratio()).

  • periods_per_year (int, default 252) – Number of periods per year used for annualizing returns, volatility, and the Sharpe ratio.

Returns:

A single-row DataFrame (indexed by 'Strategy') with one column per summary statistic: Annualized Return, Annualized Vol, Sharpe Ratio, Max Drawdown, Skewness, Kurtosis, Cornish-Fisher VaR (5%), and Historic CVaR (5%).

Return type:

pandas.DataFrame

var_gaussian(r: Series | DataFrame, level: float = 5, *, modified: bool = False) → float | Series[source]#

Compute the parametric Gaussian VaR of r.

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

  • level (float, default 5) – The percentile level, in percent (e.g. 5 for the 5th percentile / 95% VaR).

  • modified (bool, default False) – If True, apply the Cornish-Fisher modification to the Z-score using the observed skewness and kurtosis of r, returning the modified VaR instead of the plain Gaussian VaR.

Returns:

The parametric (optionally Cornish-Fisher modified) Gaussian VaR, expressed as a positive number. Returns a float if r is a Series, or a Series of per-column VaR values if r is a DataFrame.

Return type:

float or pandas.Series

var_historic(r: Series | DataFrame, level: float = 5) → float | Series[source]#

Compute the historic Value at Risk (VaR) at a specified level.

Returns the number such that level percent of the returns fall below that number (as a positive loss figure), and 100 - level percent are above it.

Parameters:
  • r (pandas.Series or pandas.DataFrame) – Series or DataFrame of returns.

  • level (float, default 5) – The percentile level, in percent (e.g. 5 for the 5th percentile / 95% VaR).

Returns:

The historic VaR, expressed as a positive number. Returns a float if r is a Series, or a Series of per-column VaR values if r is a DataFrame.

Return type:

float or pandas.Series

Raises:

TypeError – If r is neither a pandas.Series nor a pandas.DataFrame.