Stats


stats.py

A module for statistical functions.

compile_numba_functions(size: int = 10) -> dict

Compile the numba functions

compute_average_drawdown(returns: np.ndarray) -> float

Compute the Average Drawdown

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

Returns:
  • float

    the average drawdown value

Examples:

>>> compute_average_drawdown(np.array([0.0, -0.1, 0.2, -0.1, 0.3]))
0.1

>>> compute_average_drawdown(np.array([0.1, 0.2, 0.3]))
0.0

References:

Chekhlov, Alexei, Stanislav Uryasev, and Michael Zabarankin.
"Drawdown measure in portfolio optimization."
International Journal of Theoretical and Applied Finance 8.01 (2005): 13-58.

Geboers, Hans, Benoît Depaire, and Jan Annaert.
"A review on drawdown risk measures and their implications for risk management."
Journal of Economic Surveys 37.3 (2023): 865-889.

compute_calmar_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the Calmar ratio: annualized return divided by the maximum drawdown.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the Calmar-ratio value

Examples:

>>> compute_calmar_ratio(np.array([0.01, 0.02, 0.03]))
5.7735

>>> compute_calmar_ratio(np.array([-0.1, 0.05, 0.05]))
nan

References:

Magdon-Ismail, Malik, and Amir F. Atiya.
"Maximum drawdown."
Risk Magazine 17.10 (2004): 99-102.

Petroni, Filippo, and Giulia Rotundo.
"Effectiveness of measures of performance during speculative bubbles."
Physica A: Statistical Mechanics and its
Applications 387.15 (2008): 3942-3948.

compute_cvar(returns: np.ndarray, alpha: float = 0.05, n_step: int = 100, low_alpha: float = 0.001) -> float

Compute Conditional Value-at-Risk (CVaR) by numerical approximation.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • alpha (float, default: 0.05 ) –

    quantile level

  • n_step (int, default: 100 ) –

    number of step in the numerical approximation

  • low_alpha (float, default: 0.001 ) –

    low level of alpha used in integration

Returns:
  • float

    conditional value-at-risk

Examples:

>>> compute_cvar(np.array([0.01, -0.02, 0.03]))
0.019970000000000004

>>> compute_cvar(np.array([-0.1, -0.05, 0.0]), alpha=0.1)
0.0499

References:

Artzner, Philippe, et al.
"Coherent measures of risk."
Mathematical finance 9.3 (1999): 203-228.

Rockafellar, R. Tyrrell, and Stanislav Uryasev.
"Optimization of conditional value-at-risk."
Journal of risk 2 (2000): 21-42.

Norton, Matthew, Valentyn Khokhlov, and Stan Uryasev.
"Calculating CVaR and bPOE for common probability
distributions with application to portfolio optimization
and density estimation."
Annals of Operations Research 299.1 (2021): 1281-1315.

compute_cvar_sharpe_ratio(returns: np.ndarray, r: float = 0.0, alpha: float | np.ndarray = 0.05) -> float

Compute Risk-Adjusted Return on Capital (RAROC), defined as the ratio of the expected return over the CVaR

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

  • alpha (float | ndarray, default: 0.05 ) –

    quantile level

Returns:
  • float

    the CVaR Sharpe Ratio value

Examples:

>>> compute_cvar_sharpe_ratio(np.array([0.01, 0.02, -0.01]), alpha=0.05)
0.668

>>> compute_cvar_sharpe_ratio(np.array([-0.1, -0.05, 0.0]), alpha=0.1)
0.0

References:

Dowd, Kevin.
"A value risk approach to risk-return analysis."
Journal of Portfolio Management 25.4 (1999): 60.

Esfahanipour, Akbar, and Somayeh Mousavi.
"A genetic programming model to generate risk-adjusted technical
trading rules in stock markets."
Expert Systems with Applications 38.7 (2011): 8438-8445.

compute_downside_risk(returns: np.ndarray, r: float = 0.0) -> float

Compute the annualized Downside Risk measure

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the semideviance value

Examples:

>>> compute_downside_risk(np.array([0.01, -0.02, 0.03]), r=0.0)
2.82842712474619

>>> compute_downside_risk(np.array([0.1, 0.2, 0.3]), r=0.0)
0.0

References:

Nawrocki, David N.
"A brief history of downside risk measures."
The Journal of Investing 8.3 (1999): 9-25

compute_evar(returns: np.ndarray, alpha: float = 0.5) -> float

Compute Entropic Value at Risk (EVaR)

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • alpha (float, default: 0.5 ) –

    quantile level

Returns:
  • float

    the Entropic Value at Risk value

Examples:

>>> compute_evar(np.array([0.01, -0.02, 0.03]))
0.013531...

>>> compute_evar(np.array([-0.1, -0.05, 0.0]), alpha=0.1)
0.067...

References:

Ahmadi-Javid, Amir.
"Entropic value-at-risk: A new coherent risk measure."
Journal of Optimization Theory and Applications 155.3 (2012): 1105-1123.

compute_final_pnl(returns: np.ndarray) -> float

Compute the final PnL value

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

Returns:
  • float

    final PnL (last cumulative sum value)

Examples:

>>> compute_final_pnl(np.array([0.01, 0.02, -0.01]))
0.02

>>> compute_final_pnl(np.array([-0.1, 0.05, 0.05]))
0.0

compute_final_pnl_percentage(returns: np.ndarray, baseline: float = 1) -> float

Compute final PnL as percentage (multiplied by 100).

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • baseline (float, default: 1 ) –

    default value for portfolio

Returns:
  • float

    final PnL percentage

Examples:

>>> compute_final_pnl_percentage(np.array([0.01, 0.02, -0.01]))
2.0

>>> compute_final_pnl_percentage(np.array([-0.1, 0.05, 0.05]))
0.0

compute_max_drawdown(returns: np.ndarray) -> float

Compute the Maximum Drawdown https://stackoverflow.com/questions/22607324

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

Returns:
  • float

    the max-drawdown value

Examples:

>>> compute_max_drawdown(np.array([0.0, -0.1, 0.2, -0.1, 0.3]))
0.30000000000000004

>>> compute_max_drawdown(np.array([0.1, 0.2, 0.3]))
0.0

References:

Chekhlov, Alexei, Stanislav Uryasev, and Michael Zabarankin.
"Drawdown measure in portfolio optimization."
International Journal of Theoretical and Applied Finance 8.01 (2005): 13-58.

Geboers, Hans, Benoît Depaire, and Jan Annaert.
"A review on drawdown risk measures and their implications for risk management."
Journal of Economic Surveys 37.3 (2023): 865-889.

compute_omega_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the annualized Omega ratio, which is the ratio of gains over losses relative to a threshold r.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the Omega-ratio value

Examples:

>>> compute_omega_ratio(np.array([0.01, 0.02, -0.01]), r=0.0)
2.0

>>> compute_omega_ratio(np.array([-0.01, -0.02, -0.03]), r=0.0)
0.0

References:

Kapsos, M., Zymler, S., Christofides, N., & Rustem, B
"Optimizing the Omega ratio using linear programming."
Journal of Computational Finance 17.4 (2014): 49-57.

compute_probabilistic_sharpe_ratio(returns: np.ndarray, r: float = 0.0, sr: float = 0.0) -> float

Compute the Probabilistic Sharpe Ratio (PSR), which is the probability that the Sharpe ratio of a given set of returns is greater than a benchmark Sharpe ratio (sr).

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

  • sr (float, default: 0.0 ) –

    benchmark Sharpe ratio

Returns:
  • float

    the Probabilistic Sharpe Ratio value

Examples:

>>> compute_probabilistic_sharpe_ratio(np.array([0.01, 0.02, 0.03]), r=0.0, sr=1.0)
0.9986501019683699
>>> compute_probabilistic_sharpe_ratio(np.array([-0.01, -0.02, -0.03]), r=0.0, sr=1.0)
0.0013498980316301035

References:

Bailey, David H., and Marcos López de Prado.
"The probabilistic Sharpe ratio."
Journal of Portfolio Management 40.5 (2014): 39-49.

compute_risk_of_ruin_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the Risk of Ruin ratio, which is the probability of losing all capital.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the Risk of Ruin ratio value

Examples:

>>> compute_risk_of_ruin_ratio(np.array([0.01, -0.02, 0.03]), r=0.0)
0.3333333333333333

>>> compute_risk_of_ruin_ratio(np.array([-0.1, -0.05, 0.05]), r=0.0)
1.0
References

Taranto, Aldo, and Shahjahan Khan. "Gambler’s ruin problem and bi-directional grid constrained trading and investment strategies." Investment Management and Financial Innovations 17.3 (2020): 54-66.

compute_sharpe_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the annualized Sharpe ratio of the returns.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    annualized Sharpe-ratio value

Examples:

>>> compute_sharpe_ratio(np.array([0.01, 0.02, 0.03]), r=0.0)
12.598349018279691
>>> compute_sharpe_ratio(np.array([0.0, 0.0, 0.0]), r=0.0)
nan

References:

Sharpe, William F.
"The sharpe ratio."
Journal of portfolio management 21.1 (1994): 49-58.

compute_sortino_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the annualized Sortino-ratio, penalizing downside volatility only

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the Sortino-ratio value

Examples:

>>> compute_sortino_ratio(np.array([0.01, 0.02, -0.01]), r=0.0)
12.598349018279691

>>> compute_sortino_ratio(np.array([-0.01, -0.02, -0.03]), r=0.0)
nan

References:

Sortino, Frank A., and Lee N. Price.
"Performance measurement in a downside risk framework."
The Journal of Investing 3.3 (1994): 59-64.

compute_stability_of_timeseries(returns: np.ndarray) -> float

Compute the stability of a time series by regressing cumulative returns against time.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

Returns:
  • float

    stability coefficient (R-squared of regression)

Examples:

>>> compute_stability_of_timeseries(np.array([0.01, 0.02, 0.03]))
1.0

>>> compute_stability_of_timeseries(np.array([0.0, 0.0, 0.0]))
0.0

compute_sterling_ratio(returns: np.ndarray, r: float = 0.0) -> float

Compute the Sterling ratio: annualized return divided by the average drawdown.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

Returns:
  • float

    the Sterling-ratio value

Examples:

>>> compute_sterling_ratio(np.array([0.01, 0.02, -0.03]))
0.0

>>> compute_sterling_ratio(np.array([0.01, 0.02, -0.03]))
nan

References:

Bacon, Carl R.
Practical portfolio performance measurement and attribution.
John Wiley & Sons, 2023.

van Heerden, Chris.
"Establishing the risk denominator in a Sharpe ratio framework
for share selection from a momentum investment strategy approach."
South African Journal of Economic and Management Sciences 23.1 (2020): 1-19.

compute_tail_ratio(returns: np.ndarray) -> float

Compute the Tail Ratio: ratio of the absolute value of the 95th percentile gains to the absolute value of the 5th percentile losses.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

Returns:
  • float

    the tail-ratio value

Examples:

>>> compute_tail_ratio(np.array([0.01, -0.02, 0.03]))
1.5

>>> compute_tail_ratio(np.array([0.1, -0.05, 0.05]))
2.0

References:

Konno, Hiroshi, Katsuhiro Tanaka, and Rei Yamamoto.
"Construction of a portfolio with shorter downside tail
and longer upside tail."
Computational Optimization and Applications 48.2 (2011): 199-212.

compute_var(returns: np.ndarray, alpha: float | np.ndarray = 0.05) -> float

Compute Value-at-Risk (VaR) using the quantile method

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • alpha (float | ndarray, default: 0.05 ) –

    quantile level

Returns:
  • float

    value-at-risk at quantile alpha

Examples:

>>> compute_var(np.array([0.01, -0.02, 0.03]))
0.02

>>> compute_var(np.array([-0.1, -0.05, 0.0]), alpha=0.1)
0.05

References:

Artzner, Philippe, et al.
"Coherent measures of risk."
Mathematical finance 9.3 (1999): 203-228.

compute_var_sharpe_ratio(returns: np.ndarray, r: float = 0.0, alpha: float | np.ndarray = 0.05) -> float

Compute Risk-Adjusted Return on Capital (RAROC), defined as the ratio of the expected return over the CVaR

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level

  • alpha (float | ndarray, default: 0.05 ) –

    quantile level

Returns:
  • float

    the VaR Sharpe Ratio value

Examples:

>>> compute_var_sharpe_ratio(np.array([0.01, 0.02, -0.01]), alpha=0.05)
0.668

>>> compute_var_sharpe_ratio(np.array([-0.1, -0.05, 0.0]), alpha=0.1)
0.0

References:

Stoughton, Neal M., and Josef Zechner.
"Optimal capital allocation using RAROC and EVA."
Journal of Financial Intermediation 16.3 (2007): 312-342.

Prokopczuk, Marcel, et al.
"Quantifying risk in the electricity business: A RAROC-based approach."
Energy Economics 29.5 (2007): 1033-1049.

compute_win_rate(returns: np.ndarray, r: float = 0.0) -> float

Compute the win rate of returns.

Parameters:
  • returns (ndarray) –

    a vector-like object of returns

  • r (float, default: 0.0 ) –

    risk-free level (default is 0)

Returns:
  • float

    win rate (percentage of positive returns)