σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademyRoteiros
Ctrl K
AO
+1,2 mil alunos
EntrarParticipar ↗
Roteiros
AO
+1,2 mil alunos
Entrar
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Roteiro de Python›Módulo 7 · Pesquisa de alfa e risco›Tópico 7.2·~1 hAvançado

Modelos multifatoriais: Fama-French

Posição no roteiroMódulo 7 de 11 · Tópico 2 de 9
7.2 Modelos multifatoriais: Fama-French
—Nota do lab— / 100XP total—Sequência—

Mais de um motivo para se mover

O CAPM tem um fator, o mercado. Em 1992, Fama e French mostraram que outros dois explicam grande parte das diferenças de retorno entre ações: o tamanho (empresas pequenas renderam mais que grandes, fator SMB, small minus big) e o valor (ações baratas pela relação valor contábil/mercado renderam mais que as caras, fator HML, high minus low). Modelos posteriores acrescentaram momentum, rentabilidade e investimento. Cada fator é uma série de retornos, e a exposição de um ativo a ela diz o quanto ele se move com essa série.

import numpy as np

rng = np.random.default_rng(1)
n = 250
market = rng.normal(0.0004, 0.010, size=n)               # excess returns of three factors
smb = rng.normal(0.0001, 0.005, size=n)
hml = rng.normal(0.0001, 0.005, size=n)
factors = np.column_stack([market, smb, hml])             # shape (n, k) = (250, 3)

asset = 0.0002 + factors @ np.array([1.1, 0.5, -0.3]) + rng.normal(0, 0.004, size=n)
X = np.column_stack([np.ones(n), factors])                # design matrix: a column of ones for alpha
print(X.shape)                                            # (250, 4)
# The design matrix of three days and two factors
import numpy as np

factors = np.array([[0.010, -0.002], [-0.004, 0.001], [0.006, 0.003]])
X = np.column_stack([np.ones(len(factors)), factors])
print(X)                                           # a column of ones, then market and SMB

Mínimos quadrados em forma matricial

Com vários fatores a regressão é asset = alpha + b1 * f1 + ... + bk * fk + erro. Empilham-se os fatores ao lado de uma coluna de uns numa matriz X, e os coeficientes de mínimos quadrados resolvem as equações normais (X'X) c = X'y. Em NumPy: np.linalg.solve(X.T @ X, X.T @ y). É a mesma mecânica da regressão de um fator, agora com k + 1 incógnitas. O primeiro coeficiente é o alfa, os demais são as exposições.

import numpy as np

rng = np.random.default_rng(1)
n = 250
factors = np.column_stack([rng.normal(0.0004, 0.010, size=n), rng.normal(0.0001, 0.005, size=n), rng.normal(0.0001, 0.005, size=n)])
asset = 0.0002 + factors @ np.array([1.1, 0.5, -0.3]) + rng.normal(0, 0.004, size=n)

X = np.column_stack([np.ones(n), factors])
coef = np.linalg.solve(X.T @ X, X.T @ asset)
print(np.round(coef, 4))                                   # [alpha, market, SMB, HML]: the loadings come out near [1.1, 0.5, -0.3]

residual = asset - X @ coef
r2 = 1 - np.sum(residual ** 2) / np.sum((asset - asset.mean()) ** 2)
print(round(float(r2), 4))

Quanto os fatores explicam?

O R quadrado responde: a parcela da variação do ativo que os fatores explicam, 1 - SSres / SStot, entre 0 (nada) e 1 (tudo). Uma carteira de ações diversificada costuma ter R quadrado acima de 0,9 nos fatores de Fama–French: seu risco é quase todo risco fatorial. Uma ação isolada tem menos, e o resto, a variação residual, é específico da empresa. Acrescentar um fator nunca reduz o R quadrado na amostra, então um número maior sozinho não prova que um fator importa.

# What the model implies: the expected return from the loadings and the factor premia
import numpy as np

betas = np.array([1.1, 0.5, -0.3])             # market, SMB, HML loadings
premia = np.array([0.0006, 0.0002, 0.0002])    # expected daily factor returns
rf = 0.0001

expected = rf + np.sum(betas * premia)
print(round(float(expected), 6))               # 0.0008 per day, about 20% a year on 250 days
Fatores são apostas, não almoços grátisUm prêmio de fator é a recompensa por um risco que dói nos momentos ruins, e pode sumir ou se inverter por anos. As exposições estimadas numa amostra curta são ruidosas, e com fatores correlacionados os coeficientes individuais podem ser instáveis mesmo com bom ajuste. O uso de um modelo fatorial é principalmente decompor risco e desempenho: quanto veio do mercado, tamanho, valor, e quanto, o alfa, sobra.
  • Um modelo fatorial regride os retornos excedentes sobre vários fatores: X = [uns | fatores], coeficientes [alpha, beta_1..beta_k].
  • Resolva as equações normais np.linalg.solve(X.T @ X, X.T @ y); o R quadrado é 1 - SSres / SStot e nunca cai ao acrescentar um fator.
  • O modelo implica rf + sum(betas * premia); exposições e prêmios são estimativas, e um prêmio de fator pode desaparecer.

A seguir: o coeficiente de informação, medir se um sinal prevê os retornos.

Lab: o que é avaliado

  • Montar a regressão com design_matrix25 pts
  • Estimar as exposições com fit_factor_model25 pts
  • Pontuar o ajuste com r_squared25 pts
  • Precificar as exposições com factor_expected_return25 pts
Explorador · lab-94-1
▾ lab-94-1
…
bash · no navegador
learner@quantcraft:~/lab-94-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-94-1 volta aos arquivos iniciais e o terminal é limpo. Sua solução atual será perdida — isso não pode ser desfeito.

Será redefinido
  • main.py → código inicial
  • Histórico do terminal e saída dos testes
  • Alterações não enviadas
Será mantido
  • Melhor nota do lab
  • Seu XP e sua sequência
  • Progresso da aula e anotações

Entre para executar o seu código.

Todas as aulas são gratuitas para ler. Crie uma conta ou entre para executar código, rodar os testes e enviar este lab.

  • IDE no navegador com terminal bash — nada para instalar
  • Correção instantânea, XP e o seu lugar no roteiro
Criar uma contaEntrar
OU
Continuar com o GitHub