σμ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 8 · Modelos estocásticos e aprendizado de máquina›Tópico 8.8·~1 hAvançado

Pipelines do scikit-learn para retornos

Posição no roteiroMódulo 8 de 11 · Tópico 8 de 10
8.8 Pipelines do scikit-learn para retornos
—Nota do lab— / 100XP total—Sequência—

Aprendizado de máquina sobre retornos

O aprendizado supervisionado ajusta uma função das variáveis X ao alvo y. Em finanças o alvo costuma ser um retorno futuro e as variáveis são coisas conhecidas de antemão: retornos passados, volatilidade, volume. O scikit-learn oferece uma interface uniforme: todo modelo tem fit(X, y) e predict(X). Uma diferença-chave dos problemas de livro-texto é a relação sinal/ruído: retornos são quase puro ruído, então mesmo um bom modelo explica uma fração mínima, e uma configuração descuidada encontra padrões que não existem.

import numpy as np

returns = np.array([0.01, -0.02, 0.015, 0.005, -0.01, 0.02])
n_lags = 2

# Row i holds the two returns before the target; y[i] is the return that follows them
windows = np.lib.stride_tricks.sliding_window_view(returns, n_lags)
X, y = windows[:-1], returns[n_lags:]
print(X)
print(y)                                             # the targets are one step ahead of the features

Variáveis a partir de defasagens

As variáveis mais simples de um retorno são os retornos anteriores. Construa uma matriz de defasagens: a linha i contém returns[i : i + n_lags], e o alvo é returns[i + n_lags], o valor seguinte. Uma visão de janela deslizante a dá sem laço. Tudo numa linha deve ser conhecido no momento de prever, a regra de antecipação aplicada a um modelo: uma variável deslocada uma posição no sentido errado deixaria o modelo ver a resposta.

import numpy as np
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

# Pipeline: scale each feature, then a ridge regression (a linear model with a penalty on large coefficients)
pipe = Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=10.0))])
print([name for name, _ in pipe.steps])

rng = np.random.default_rng(1)
returns = np.zeros(400)
noise = rng.normal(0, 0.01, size=400)
for t in range(1, 400):
    returns[t] = 0.3 * returns[t - 1] + noise[t]                    # a series with a little memory

windows = np.lib.stride_tricks.sliding_window_view(returns, 3)
X, y = windows[:-1], returns[3:]
pipe.fit(X[:300], y[:300])                                          # fit on the first 300 rows
print(np.round(pipe.named_steps["model"].coef_, 4))                 # the last lag weighs most

Pipelines e vazamento

Um Pipeline reúne o escalonador e o modelo de modo que fit aprende as estatísticas de escala (média e desvio de cada variável) só com as linhas de treino e predict as aplica sem alteração a linhas novas. Escalar o conjunto inteiro antes de dividir vazaria a média e a dispersão do período de teste para o treino: o mesmo viés de antecipação, num lugar novo. Numa série temporal a divisão também é cronológica: treinar nas linhas iniciais, testar nas posteriores, nunca um embaralhamento aleatório.

import numpy as np
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

def build_pipeline(alpha):
    return Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=alpha))])

rng = np.random.default_rng(1)
returns = np.zeros(600)
noise = rng.normal(0, 0.01, size=600)
for t in range(1, 600):
    returns[t] = 0.3 * returns[t - 1] + noise[t]

windows = np.lib.stride_tricks.sliding_window_view(returns, 3)
X, y = windows[:-1], returns[3:]
model = build_pipeline(10.0).fit(X[:400], y[:400])                  # chronological split: early rows to train
pred = model.predict(X[400:])                                       # later rows to test
print(round(float(np.mean(np.sign(y[400:]) == np.sign(pred))), 3))  # direction accuracy on unseen data

Julgar o resultado com honestidade

Para um sinal de trading, a direção costuma ser o que importa, então uma pontuação simples é a acurácia direcional: a fração de dias em que o retorno previsto e o real têm o mesmo sinal. 50% é cara ou coroa. Preditores reais de retornos chegam a 51 a 53%, e 60% em dados de teste é mais provavelmente um vazamento que uma descoberta. Compare com as referências triviais (prever sempre alta, prever zero) antes de acreditar em qualquer coisa.

import numpy as np

y_true = np.array([0.01, -0.02, 0.015, -0.005, 0.02, -0.01])
y_pred = np.array([0.004, 0.001, 0.002, -0.001, 0.003, 0.002])        # the model is right on 4 of 6 signs

accuracy = float(np.mean(np.sign(y_true) == np.sign(y_pred)))
always_up = float(np.mean(np.sign(y_true) == 1))                      # the trivial baseline: always predict a rise
print(round(accuracy, 3), round(always_up, 3))                        # compare the model with the baseline
Modelos simples, validação honestaCom tanto ruído, modelos lineares regularizados (ridge, lasso) costumam vencer os flexíveis como árvores profundas ou redes neurais, que memorizam o período de treino. A penalidade alpha é um botão a ajustar, mas num período de validação, nunca no de teste. Os próximos tópicos constroem as variáveis e a validação walk-forward que tornam isso honesto.
  • Uma matriz de defasagens (sliding_window_view) dá variáveis a partir dos retornos antes de cada alvo; tudo numa linha deve ser conhecido no momento da previsão.
  • Um Pipeline([("scale", StandardScaler()), ("model", Ridge(alpha=alpha))]) aprende a escala só nas linhas de treino; divida cronologicamente, nunca ao acaso.
  • Pontue a direção (fração de sinais iguais) contra referências triviais; 51 a 53% é realista, 60% sugere vazamento; modelos lineares regularizados servem a dados ruidosos.

A seguir: a engenharia de variáveis para dados financeiros, construir entradas melhores que retornos defasados brutos.

Lab: o que é avaliado

  • Transformar uma série em variáveis com lag_matrix25 pts
  • Encadear as etapas com build_pipeline25 pts
  • Treinar no passado e prever o resto com fit_predict25 pts
  • Pontuar as direções com direction_accuracy25 pts
Explorador · lab-109-1
▾ lab-109-1
…
bash · no navegador
learner@quantcraft:~/lab-109-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

Tudo em lab-109-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