def _get_sharpe_ratio(price_series: NDFrame, rf_series: Series, scale_to_annualise: bool): """" Returns the Sharpe ratio based on a series of asset prices and risk-free asset prices. The calculation is based on the arithmetic mean of actual returns, as appears to be standard :param price_series - a pandas series or data frame of prices :param rf_series - a pandas series representing the total return/price series of the risk free rate :param scale_to_annualise - bool governing whether or not a scaling factor is applied to annualise the statistic Notes ------- https://en.wikipedia.org/wiki/Sharpe_ratio """ # excess_return = get_annualised_excess_return(price_series, rf_series) # vol = get_annual_vol(price_series) # sharpe_ratio = excess_return/vol returns = (price_series / price_series.shift(1)).dropna() returns_rf = (rf_series / rf_series.shift(1)).dropna() rel_returns = returns.subtract(returns_rf, axis=0) avg_excess = rel_returns.mean() vol = rel_returns.std() annualising_scaling = TSeriesHelper._get_annualisation_factor(price_series.index) if scale_to_annualise else 1 sharpe_ratio = avg_excess * annualising_scaling / vol return sharpe_ratio
def get_annualised_vol(price_series: NDFrame): """" Returns the annualised volatility of returns based on a stream of asset prices. The function derives the time period of the price data uses this to calculate a suitable factor to annualise the data with. Note that the function calculates the standard deviation of the NATURAL LOG of the returns, as is conventional. :param price_series - a pandas series or dataframe of prices Notes -------- https://en.wikipedia.org/wiki/Volatility_(finance) """ log_returns = np.log(price_series / price_series.shift(1)) annualising_scaling = TSeriesHelper._get_annualisation_factor(price_series.index) return np.std(log_returns) * annualising_scaling
def price_to_return(price_series: NDFrame): """ convert a series of asset prices to a series or returns :param price_series: pandas price series or dataframe of price series :return: """ if (price_series == 0).any(axis=None).any(): raise ValueError("Cannot convert price series with zeroes to a return") price_series = price_series / price_series.shift(1) price_series.dropna(inplace=True) price_series = price_series - 1 return price_series
def _get_sortino_ratio(price_series: NDFrame, benchmark_series: Series, scale_to_annualise: bool): """" Returns the Sortino ratio :param price_series - a pandas series or data frame of prices :param benchmark_series - a pandas series representing the total return/price series of the chosen benchmark Notes ------ https://en.wikipedia.org/wiki/Sortino_ratio """ returns = (price_series / price_series.shift(1)).dropna() returns_rf = (benchmark_series / benchmark_series.shift(1)).dropna() avg_excess = (returns.subtract(returns_rf, axis=0)).mean() vol = TSeriesHelper._get_downside_deviation(returns, returns_rf) annualising_scaling = TSeriesHelper._get_annualisation_factor(price_series.index) if scale_to_annualise else 1 sortino_ratio = avg_excess * annualising_scaling / vol return sortino_ratio