σμ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 6 · Backtesting e custos de trading›Tópico 6.4·~45 minAvançado

Custos de transação

Posição no roteiroMódulo 6 de 11 · Tópico 4 de 6
6.4 Custos de transação
—Nota do lab— / 100XP total—Sequência—

Negociar não é de graça

Um backtest que negocia de graça superestima toda estratégia, e quanto mais negocia, mais mente. Os custos reais são a corretagem, taxas de bolsa e regulatórias e, acima de tudo, o spread entre compra e venda cruzado a cada vez. Costumam ser cotados em pontos-base do valor negociado: 1 pb é 0,01%. Uma ida e volta a 5 pb por lado custa 10 pb, o que uma estratégia que ganha 3 pb por dia não aguenta se trocar de lado todo dia.

def trade_cost(notional, bps):
    return abs(notional) * bps / 10000

print(trade_cost(25000, 5))         # 12.5   buying 25,000 at 5 bps
print(trade_cost(-25000, 5))        # 12.5   selling costs the same
print(trade_cost(1_000_000, 1))     # 100.0  one basis point on a million

Giro: quanto você negocia

O custo depende de quanto a posição muda, não do seu tamanho. Com a posição como fração da conta, o giro de um dia é a mudança absoluta em relação à posição anterior: abs(position[t] - position[t - 1]), partindo de zero no dia 0. Continuar comprado não custa nada após a primeira compra; passar de comprado a vendido negocia a conta duas vezes. Somado em um ano, o giro é o primeiro número a olhar em qualquer estratégia.

import numpy as np

positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0])        # long, long, flip to short, short, flat
turnover = np.abs(np.diff(positions, prepend=0.0))       # day 0 starts from a flat position
print(turnover)                                          # [1. 0. 2. 0. 1.]
print(turnover.sum())                                    # 4.0  accounts traded over the five days

Retornos líquidos e custo de equilíbrio

O custo do dia, como fração da conta, é turnover * bps / 10000, e o retorno líquido é o bruto menos isso. Um número útil é o custo de equilíbrio: o custo por unidade negociada em que o lucro total é exatamente zero, sum(gross) / sum(turnover) * 10000. Compare-o com o que você paga de verdade. Uma estratégia com equilíbrio de 2 pb está morta na prática; uma de 40 pb tem folga.

# Gross and net returns of a rule that flips often, at 5 bps per unit traded
import numpy as np

rng = np.random.default_rng(11)
positions = np.where(rng.random(250) > 0.5, 1.0, -1.0)      # a coin-flip position, flipping often
gross = rng.normal(0.0015, 0.005, size=250)                   # a strategy with a real daily edge before costs

turnover = np.abs(np.diff(positions, prepend=0.0))
net = gross - turnover * 5 / 10000
print(round(float(gross.sum()), 4), round(float(net.sum()), 4))
print(round(float(turnover.sum()), 1), "accounts traded;", round(float(gross.sum() / turnover.sum() * 10000), 2), "bps break-even")
# The break-even cost of a small example
import numpy as np

gross = np.array([0.004, 0.002, 0.003, 0.001, 0.002])
positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0])
turnover = np.abs(np.diff(positions, prepend=0.0))
breakeven = gross.sum() / turnover.sum() * 10000
print(round(float(breakeven), 2))                                           # 30.0 bps per unit traded
print(abs(round(float((gross - turnover * breakeven / 10000).sum()), 10)))       # 0.0: the whole profit is gone
Custos não são só a corretagemUma taxa fixa em pb é o modelo mais simples. Os custos reais dependem também do instrumento, da hora do dia e do tamanho da ordem: o spread é maior em small caps e na abertura, e ordens grandes movem o preço contra você, assunto dos próximos tópicos. Seja qual for o modelo, um backtest que ignora custos é otimista, e um que os cobra baixo demais é perigoso.
  • Os custos são cotados em pontos-base do valor negociado: abs(notional) * bps / 10000, igual para compra e venda.
  • O giro é abs(mudança de posição) (uma virada negocia 2); retorno líquido = bruto - giro * pb / 10000.
  • O custo de equilíbrio sum(gross) / sum(turnover) * 10000 diz quanto custo uma estratégia aguenta; compare com o real.

A seguir: o deslizamento, a diferença entre o preço esperado e o preço obtido.

Lab: o que é avaliado

  • Precificar uma negociação com trade_cost25 pts
  • Contar o que é negociado com turnover25 pts
  • Descontar a conta com net_returns25 pts
  • Achar o custo que a mata com breakeven_bps25 pts
Explorador · lab-90-1
▾ lab-90-1
…
bash · no navegador
learner@quantcraft:~/lab-90-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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