O risco em um só número
A volatilidade é o desvio padrão dos retornos, expresso por ano para comparar ativos: cerca de 15 a 20% para um índice de ações, 30 a 60% para uma ação individual, perto de 0 para caixa. Ela dimensiona posições, precifica opções e define limites de risco. A estimativa mais simples é a volatilidade realizada numa janela: o desvio padrão amostral dos retornos vezes sqrt(períodos por ano). Trata todos os dias da janela igualmente, o que é ao mesmo tempo sua força (estável) e sua fraqueza (lenta).
import math
import numpy as np
# Eight quiet days, one -3% shock, three more days
returns = np.array([0.004, -0.002, 0.001, 0.003, -0.004, 0.002, 0.006, -0.001, -0.030, 0.004, 0.002, -0.003])
print(round(returns[:8].std(ddof=1) * math.sqrt(252), 4)) # 0.0526 before the shock: 5.3% a year
print(round(returns.std(ddof=1) * math.sqrt(252), 4)) # 0.1505 with the shock: 15.1% a yearReagir mais rápido: EWMA
A volatilidade se agrupa: períodos calmos e períodos agitados duram um tempo, então o choque de ontem diz mais sobre amanhã do que um dia tranquilo de um mês atrás. A média móvel exponencial (EWMA, popularizada pelo RiskMetrics) atualiza a variância a cada dia: variância_t = lam * variância_(t-1) + (1 - lam) * retorno_t². Com lam = 0,94 o retorno mais recente pesa 6% e os antigos se apagam geometricamente. A estimativa salta no choque e decai aos poucos, em vez de ficar alta até o choque sair da janela e cair de uma vez.
lam = 0.94
variance = np.empty(len(returns))
variance[0] = returns[0] ** 2
for t in range(1, len(returns)):
variance[t] = lam * variance[t - 1] + (1 - lam) * returns[t] ** 2 # the recursion needs the previous value
ewma = np.sqrt(variance)
print(ewma.round(5).tolist())
# [0.004, 0.00391, 0.0038, 0.00375, 0.00377, 0.00369, 0.00387, 0.00376, 0.0082, 0.00801, 0.00778, 0.00758]
# ^ the shock doubles the estimate, then it fades
print(round(ewma[-1] * math.sqrt(252), 4)) # 0.1204 today's annualised estimateUsar a amplitude e mirar uma volatilidade
Os preços de fechamento ignoram o que aconteceu durante o dia. A máxima e a mínima do dia carregam mais informação: o estimador de Parkinson sqrt(mean(ln(high/low)²) / (4 ln 2)) é várias vezes mais eficiente que a estimativa de fechamento a fechamento, ou seja, alcança a mesma precisão com muito menos dias (supõe que não há grandes saltos entre os dias). Um uso prático de qualquer estimativa de volatilidade é a meta de volatilidade: se você quer 10% de risco e a volatilidade realizada é 15%, mantenha 10 / 15 = 0,67 da posição. A alavancagem encolhe na tempestade e cresce na calma.
high = np.array([101.5, 102.0, 103.2, 102.8, 104.0])
low = np.array([99.8, 100.9, 101.7, 101.1, 102.4])
parkinson = math.sqrt(np.mean(np.log(high / low) ** 2) / (4 * math.log(2)))
print(round(parkinson, 5)) # 0.00905 per-day volatility from the daily ranges
target = 0.10
realized = returns.std(ddof=1) * math.sqrt(252)
print(round(target / realized, 3)) # 0.664 hold two thirds of the position to run at 10% risk# Close-to-close versus range: the same five days
close = np.array([100.0, 101.2, 102.5, 101.9, 103.4])
print(round(float(np.diff(np.log(close)).std(ddof=1)), 5)) # 0.00955 from the closes only
print(round(parkinson, 5)) # 0.00905 from the high-low ranges of the same days- Volatilidade realizada: desvio padrão amostral vezes
sqrt(períodos por ano); estável, mas lenta para reagir. - EWMA:
variância_t = lam * variância_(t-1) + (1 - lam) * retorno_t²; choques recentes pesam mais e se apagam geometricamente. - Parkinson usa a amplitude máxima/mínima diária; a meta de volatilidade escala a posição por
meta / realizada.
A seguir: o índice de Sharpe, a recompensa por unidade de risco, e até onde confiar nele.
Lab: o que é avaliado
- Medir a volatilidade anual com
realized_volatility25 pts - Dar mais peso aos choques recentes com
ewma_volatility25 pts - Usar a amplitude diária com
parkinson_volatility25 pts - Dimensionar uma posição a um orçamento de risco com
volatility_target_leverage25 pts