La recompensa por unidad de riesgo
Una estrategia que gana un 12 % con un 20 % de volatilidad no es mejor que una que gana un 6 % con un 5 %. El ratio de Sharpe las pone en una misma escala: el rendimiento medio por encima de la tasa libre de riesgo dividido por la volatilidad, (mean - rf) / std, anualizado con sqrt(periodos). Viste la fórmula en el tema de media y varianza. Este tema trata de su uso: cómo leer un ratio de Sharpe, mejorarlo y, sobre todo, cuánto fiarse de él. Un Sharpe de 0,5 es mediocre, 1 es bueno, 2 es excelente y sospechoso.
La volatilidad cuenta igual la subida y la bajada, pero nadie se queja de una ganancia sorpresa. El ratio de Sortino conserva solo el lado malo: sustituye la desviación típica por la desviación a la baja, sqrt(mean(min(r - mar, 0)²)), donde mar es el rendimiento mínimo aceptable. Los días por encima de mar aportan cero pero siguen contando en la media. Una estrategia con grandes saltos positivos y pequeñas pérdidas puntúa mucho mejor en Sortino que en Sharpe.
import math
import numpy as np
import pandas as pd
returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, -0.010, 0.004, 0.002, -0.003])
sharpe = returns.mean() / returns.std(ddof=1) * math.sqrt(252)
print(round(sharpe, 3)) # 0.598
mar = 0.0 # a day below zero is a bad day
downside = math.sqrt(np.mean(np.minimum(returns - mar, 0) ** 2))
sortino = (returns.mean() - mar) / downside * math.sqrt(252)
print(round(downside, 5), round(sortino, 3)) # 0.00329 0.804 the up days no longer count as riskVerlo moverse
Un solo ratio de Sharpe para todo el historial oculta la historia. Un ratio de Sharpe móvil lo recalcula con los últimos window rendimientos, de modo que se ven los buenos y malos regímenes de la estrategia. Con pandas es la media móvil dividida por la desviación típica móvil, anualizada. Fíjate en cuánto saltan las ventanas cortas: un mes de datos no basta ni de lejos para clasificar estrategias.
series = pd.Series(returns)
rolling = series.rolling(5)
rolling_sharpe = rolling.mean() / rolling.std() * math.sqrt(252)
print(rolling_sharpe.round(2).tolist())
# [nan, nan, nan, nan, 1.89, 0.0, 6.96, 4.97, -3.66, 0.51, 0.51, -4.69] a 5-day Sharpe ratio is mostly noise¿Cuánto es suerte?
Un ratio de Sharpe es una estimación, y las estimaciones tienen error. Para un Sharpe por periodo sr medido con n rendimientos, el error estándar es aproximadamente sqrt((1 + 0,5 * sr²) / n). Con nuestros 12 días es 0,29 diario frente a un Sharpe de 0,04: el error es siete veces la estimación. Anualizados, esos mismos 12 días dan 0,6 ± 4,6. Para un Sharpe anual S observado durante years años, el estadístico t es S * sqrt(years), así que hacen falta (1,96 / S)² años para estar seguro al 95 % de que no es cero: 15 años para un Sharpe de 0,5, 4 años para un Sharpe de 1. Los backtests cortos de estrategias modestas no prueban nada.
per_period = returns.mean() / returns.std(ddof=1) # the per-day Sharpe ratio
std_error = math.sqrt((1 + 0.5 * per_period ** 2) / len(returns))
print(round(per_period, 4), round(std_error, 4)) # 0.0376 0.2888 the error is 7 times the estimate
print(round(std_error * math.sqrt(252), 3)) # 4.584 annualised: 0.6 +/- 4.6
# Years needed for an annual Sharpe ratio to reach t = 1.96
for annual in (0.5, 1.0, 2.0):
print(annual, round((1.96 / annual) ** 2, 1))
# 0.5 15.4
# 1.0 3.8
# 2.0 1.0# A yearly Sharpe of 1.0 observed over 4 years (1,008 days): how precise is it?
per_day = 1.0 / math.sqrt(252)
error_per_day = math.sqrt((1 + 0.5 * per_day ** 2) / 1008)
print(round(per_day, 4), round(error_per_day, 4), round(error_per_day * math.sqrt(252), 3)) # 0.063 0.0315 0.5 so 1.0 +/- 0.5- Sharpe =
(mean - rf) / std * sqrt(periodos); Sortino sustituye la desviación por la desviación a la bajasqrt(mean(min(r - mar, 0)²)). - Un Sharpe móvil (
rolling.mean() / rolling.std()) muestra cómo cambia el ratio; las ventanas cortas son sobre todo ruido. - Su error estándar es
sqrt((1 + 0,5 * sr²) / n)por periodo; el estadístico t de un Sharpe anual esS * sqrt(years): un Sharpe de 1 necesita unos 4 años.
A continuación: los drawdowns, las pérdidas desde un máximo que los inversores realmente sienten.
Lab: qué se califica
- Penalizar solo los días malos con
sortino_ratio25 pts - Ver cómo cambia el ratio en el tiempo con
rolling_sharpe25 pts - Medir la suerte de un ratio de Sharpe con
sharpe_standard_error25 pts - Preguntarse si es real con
sharpe_t_stat25 pts