Source code for quant_risk.statistics.financial_ratios

"Put all financial ratios here, no need for class I think"

from quant_risk.statistics.annualize import annualised_returns, annualised_volatility
import empyrical
import pandas as pd
from typing import Union
from quant_risk.statistics.stats import maximum_drawdown

__all__ = [
    'sharpe_ratio',
    'calmar_ratio',
    'omega_ratio',
    'sortino_ratio',
    'tail_ratio'
]


[docs]def sharpe_ratio(price: Union[pd.DataFrame, pd.Series], riskFreeRate: float = 0.0, periodsPerYear: Union[float, int] = 252)-> float: """ Calculates annualised sharpe ratio for given set of prices and risk free rate Parameters ---------- price : Union[pd.DataFrame, pd.Series] historical prices of a given security riskFreeRate : float given constant risk free rate throughout the period periodsPerYear : Union[float, int] periodicity of the returns data for purposes of annualising Returns ------- float annualised sharpe ratio """ returns = price.pct_change().dropna() rfPerPeriod = (1 + riskFreeRate) ** (1 / periodsPerYear) - 1 excessReturn = returns - rfPerPeriod annualiseExcessReturn = annualised_returns(excessReturn, periodsPerYear) annualiseVol = annualised_volatility(returns, periodsPerYear) return annualiseExcessReturn / annualiseVol
[docs]def calmar_ratio(price: Union[pd.DataFrame, pd.Series], periodsPerYear: Union[float, int] = 252, riskFreeRate: float = 0.0)-> float: """Calculates annualised calmar ratio for given set of prices and risk free rate Parameters ---------- price : Union[pd.DataFrame, pd.Series] historical prices of a given security periodsPerYear : Union[float, int] periodicity of the returns data for purposes of annualising Returns ------- float annualised calmar ratio """ returns = price.pct_change().dropna() rfPerPeriod = (1 + riskFreeRate) ** (1 / periodsPerYear) - 1 excessReturn = returns - rfPerPeriod annualiseExcessReturn = annualised_returns(excessReturn, periodsPerYear) calmar = annualiseExcessReturn / abs(maximum_drawdown(price)) return calmar
[docs]def omega_ratio(price: Union[pd.DataFrame, pd.Series], riskFreeRate: float = 0.0, periodsPerYear: Union[float, int] = 252)-> float: """Calculates annualised omega ratio for given set of prices and risk free rate Parameters ---------- price : Union[pd.DataFrame, pd.Series] historical prices of a given security riskFreeRate : float given constant risk free rate throughout the period periodsPerYear : Union[float, int] periodicity of the returns data for purposes of annualising Returns ------- float annualised omega ratio """ if isinstance(price, pd.DataFrame): return price.apply(omega_ratio, axis=0) returns = price.pct_change().dropna() omega = empyrical.stats.omega_ratio(returns, risk_free = riskFreeRate, annualization = periodsPerYear) return omega
[docs]def sortino_ratio(price: Union[pd.DataFrame, pd.Series], periodsPerYear: Union[float, int] = 252, reqReturn: float = 0) -> float: """Calculates annualised sortino ratio for given set of prices and risk free rate Parameters ---------- price : Union[pd.DataFrame, pd.Series] historical prices of a given security periodsPerYear : Union[float, int] periodicity of the returns data for purposes of annualising reqReturn : float, optional the minimum acceptable return by investors, by default 0 Returns ------- float annualised sortino ratio """ if isinstance(price, pd.DataFrame): return price.apply(sortino_ratio, axis=0) returns = price.pct_change().dropna() sortino = empyrical.stats.sortino_ratio(returns, annualization = periodsPerYear, required_return = reqReturn) return sortino
[docs]def tail_ratio(price: Union[pd.DataFrame, pd.Series]) -> float: """Calculates annualised tail ratio for given set of prices and risk free rate Parameters ---------- price : Union[pd.DataFrame, pd.Series] historical prices of a given security Returns ------- float annualised tail ratio """ if isinstance(price, pd.DataFrame): return price.apply(tail_ratio, axis=0) returns = price.pct_change().dropna() tail = empyrical.stats.tail_ratio(returns) return tail