σμ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 11 · Sistemas de produção e modelos de ponta›Tópico 11.6·~1 h 30 minEspecialista

Market making

Posição no roteiroMódulo 11 de 11 · Tópico 6 de 13
11.6 Market making
—Nota do lab— / 100XP total—Sequência—

Ganhar o spread, carregar o risco

Um market maker publica uma compra e uma venda e espera. Quando um vendedor atinge a compra e um comprador pega a venda, o maker compra barato, vende caro e fica com o spread. Essa é a receita. O custo é o risco de estoque: entre os dois negócios o maker mantém uma posição cujo valor se move com o preço, e é executado com mais frequência por quem sabe mais (seleção adversa) do que por quem não sabe. Fazer mercado bem é equilibrar cotações apertadas o bastante para serem acionadas com frequência e largas o bastante para pagar pelo risco, mantendo o estoque perto de zero.

# The income: buy at the bid, sell at the ask, keep the spread
bid, ask, size = 99.95, 100.05, 100
cash = -bid * size + ask * size
print(round(cash, 2))                                # 10.0    a round trip of 100 shares earned the 0.10 spread

# The risk: between the two trades the price moves against the inventory
inventory, mid_after = 100, 99.80
print(round(inventory * (mid_after - bid), 2))       # -15.0   the position lost more than the spread would have earned

Avellaneda-Stoikov: onde cotar

O modelo de Avellaneda-Stoikov dá uma resposta em forma fechada. Primeiro, o preço de reserva r = mid - q * gamma * sigma^2 * tau é onde o maker ficaria contente em negociar dado o estoque q: um maker comprado (q > 0) deve valorizar o ativo abaixo do mid e cotar mais baixo para atrair compradores, um vendido deve cotar mais alto. A aversão ao risco gamma, a volatilidade sigma e o tempo restante tau definem o quanto se inclinar. Segundo, o spread ótimo gamma * sigma^2 * tau + (2 / gamma) * ln(1 + gamma / k) tem duas partes: uma cobrança pelo risco de manter a posição até o horizonte e um termo do fluxo de ordens, em que k diz quão rápido as execuções secam ao cotar mais longe do mid. As cotações são r - spread/2 e r + spread/2.

# The reservation price leans against inventory: long -> quote lower, short -> quote higher
def reservation_price(mid, inventory, gamma, sigma, tau):
    return mid - inventory * gamma * sigma ** 2 * tau

for inventory in (-50, 0, 50):
    print(inventory, round(reservation_price(100.0, inventory, 0.1, 0.2, 1.0), 4))
# -50 100.2   short: quote higher to buy back
#   0 100.0   flat: centred on the mid
#  50  99.8   long: quote lower to sell
# The optimal spread and the two quotes around the reservation price
import math

def optimal_spread(gamma, sigma, tau, k):
    return gamma * sigma ** 2 * tau + (2 / gamma) * math.log(1 + gamma / k)

def make_quotes(mid, inventory, gamma, sigma, tau, k):
    centre = mid - inventory * gamma * sigma ** 2 * tau
    half = optimal_spread(gamma, sigma, tau, k) / 2
    return centre - half, centre + half

print(round(optimal_spread(0.1, 0.2, 1.0, 1.5), 4))                       # 1.2948
bid, ask = make_quotes(100.0, 0, 0.1, 0.2, 1.0, 1.5)
print(round(bid, 4), round(ask, 4))                  # 99.3526 100.6474   symmetric around the mid when flat
bid, ask = make_quotes(100.0, 50, 0.1, 0.2, 1.0, 1.5)
print(round(bid, 4), round(ask, 4))                  # 99.1526 100.4474   long 50: both quotes move down by 0.2

Estoque, execuções e P&L

Acompanhe o estado com dois números, o estoque e o caixa. Quando a compra é atingida, você comprou: o estoque sobe e o caixa cai price * quantity; quando a venda é atingida, você vendeu: o inverso. Sua riqueza em qualquer momento é o caixa mais o estoque marcado ao mid, cash + inventory * mid, e a variação dela é seu P&L. Esse P&L vem do spread capturado e dos movimentos de preço enquanto se mantém estoque; cotar em torno do preço de reserva puxa o estoque de volta a zero porque o lado que o reduz fica mais atraente. Limites importam na prática: um teto rígido de estoque, uma pausa em mercados rápidos e a checagem em toda cotação de que a compra esteja abaixo da venda.

# Booking fills and marking the book to market
def apply_fill(state, side, price, quantity):
    inventory, cash = state
    if side == "bid":
        return inventory + quantity, cash - price * quantity
    return inventory - quantity, cash + price * quantity

state = (0, 0.0)
state = apply_fill(state, "bid", 99.95, 100)         # our bid is hit: we buy 100
print(state)                                         # (100, -9995.0)
state = apply_fill(state, "ask", 100.05, 100)        # our ask is hit: we sell 100
print(state)                                         # (0, 10.0)   flat again, and the spread is the profit
inventory, cash = apply_fill(state, "bid", 99.9, 50)
print(round(cash + inventory * 99.9, 2))             # 10.0   marked at the price we just paid, the equity is unchanged
Um modelo é um ponto de partidaO modelo supõe um preço mid em passeio aleatório, volatilidade constante e uma curva exponencial suave de chegada de ordens. Mercados reais têm filas, tamanhos de tick, taxas e rebates, saltos e traders informados que pegam cotações velhas. Trate as fórmulas como um jeito de raciocinar sobre a direção de cada efeito (estoque comprado: cotar mais baixo; mais volatilidade: mais largo), depois calibre e teste em dados gravados num simulador antes de arriscar dinheiro, com limites rígidos que nenhum modelo possa passar por cima.
  • Um market maker ganha o spread mas carrega risco de estoque e seleção adversa; o objetivo: apertado o bastante para negociar, largo o bastante para ser pago e estoque perto de zero.
  • O preço de reserva mid - q * gamma * sigma^2 * tau se inclina contra o estoque; o spread gamma * sigma^2 * tau + (2/gamma) ln(1 + gamma/k) cresce com a volatilidade ponderada pela aversão ao risco e o tempo.
  • Acompanhe estoque e caixa, marque ao mid, imponha limites rígidos de estoque e teste a estratégia num simulador com dados gravados antes de usá-la ao vivo.

A seguir: o modelo de Heston, uma volatilidade que é ela mesma aleatória.

Lab: o que é avaliado

  • Inclinar-se contra o estoque com reservation_price25 pts
  • Definir a largura com optimal_spread25 pts
  • Cotar os dois lados com make_quotes25 pts
  • Registrar uma execução com apply_fill25 pts
Explorador · lab-135-1
▾ lab-135-1
…
bash · no navegador
learner@quantcraft:~/lab-135-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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