σμ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 9 · Dados de mercado e microestrutura›Tópico 9.1·~1 hAvançado

O livro de ordens limitadas

Posição no roteiroMódulo 9 de 11 · Tópico 1 de 5
9.1 O livro de ordens limitadas
—Nota do lab— / 100XP total—Sequência—

Onde os preços se formam

Um preço na tela é o resultado de uma fila. Numa bolsa, compradores e vendedores colocam ordens limitadas: «comprar 300 a 99,50», «vender 200 a 100,00». As que não são executadas ficam no livro de ordens: as ofertas de compra (bids), a melhor no preço mais alto, e as de venda (asks), a melhor no preço mais baixo. Um negócio ocorre quando uma ordem que chega encontra uma em espera. Tudo o que os tópicos anteriores chamam de preço, spread, deslizamento e impacto vem dessa estrutura.

# A side of the book as a dict {price: total size}
bids = {99.5: 300, 99.4: 500, 99.0: 1200}
asks = {100.0: 200, 100.1: 400, 100.5: 800}

best_bid, best_ask = max(bids), min(asks)
print(best_bid, best_ask)                                 # 99.5 100.0
print(round(best_ask - best_bid, 2), (best_bid + best_ask) / 2)   # the spread 0.5 and the mid 99.75

Spread, preço médio e profundidade

O melhor bid e o melhor ask são o topo do livro. Sua diferença é o spread, o preço de negociar na hora: um comprador que toma o ask e revende ao bid perde o spread. A meio caminho está o preço médio, a referência usual de um preço justo. A profundidade é o tamanho em espera em cada nível e além, e diz quanto pode ser negociado antes de o preço se mover. Um lado vazio significa que não há preço nesse lado, então spread e médio ficam indefinidos: None, não zero.

def best_bid_ask(bids, asks):
    return (max(bids) if bids else None, min(asks) if asks else None)

def spread_and_mid(bids, asks):
    bid, ask = best_bid_ask(bids, asks)
    if bid is None or ask is None:
        return None, None
    return ask - bid, (bid + ask) / 2

print(spread_and_mid({99.5: 300, 99.4: 500}, {100.0: 200, 100.1: 400}))      # (0.5, 99.75)
print(spread_and_mid({}, {100.0: 200}))                                       # (None, None): one side is empty

Adicionar ordens sem mudar o passado

Uma nova ordem limitada se junta a um nível de preço existente, somando ao seu tamanho total, ou abre um nível novo. Escrever isso como uma função que devolve um dict novo em vez de alterar o antigo tem uma vantagem prática: guarda-se um instantâneo do livro antes da ordem, útil para testar e reproduzir. Copie com dict(side), altere a cópia, devolva-a. Uma função que altera em silêncio seu argumento é fonte clássica de bugs quando o mesmo livro é usado em dois lugares.

def add_limit_order(side, price, size):
    new = dict(side)                                   # a copy: the original book is not touched
    new[price] = new.get(price, 0) + size
    return new

bids = {99.5: 300, 99.4: 500}
after = add_limit_order(bids, 99.5, 100)               # joins the existing level
after = add_limit_order(after, 99.3, 50)               # opens a new level
print(after)                                           # {99.5: 400, 99.4: 500, 99.3: 50}
print(bids)                                            # {99.5: 300, 99.4: 500}  unchanged

Casar uma ordem a mercado

Uma compra a mercado leva os asks do preço mais baixo para cima: todo o primeiro nível, depois o segundo, até a ordem ser preenchida ou o livro esvaziar. Percorra os preços ordenados, leve min(left, size_at_price) em cada um, registre a execução e apague o nível (levado inteiro) ou reduza-o (levado em parte). A lista de execuções dá o preço médio visto no tópico de execuções, e o livro restante é o mercado após sua negociação: mais fino no topo, com um melhor ask pior.

def match_market_buy(asks, size):
    remaining = dict(asks)
    fills = []
    left = size
    for price in sorted(asks):                          # cheapest first
        if left <= 0:
            break
        take = min(left, asks[price])
        fills.append((price, take))
        left -= take
        if take == asks[price]:
            del remaining[price]                        # the level is used up
        else:
            remaining[price] = asks[price] - take
    return fills, remaining

asks = {100.0: 200, 100.1: 400, 100.5: 800}
fills, remaining = match_market_buy(asks, 500)
print(fills)                                            # [(100.0, 200), (100.1, 300)]
print(remaining)                                        # {100.1: 100, 100.5: 800}
Livros reais são filasUm dict de tamanho total por preço esconde a fila: em cada nível as ordens são preenchidas na ordem de chegada (prioridade preço-tempo), e o lugar da sua ordem nessa fila decide se ela é preenchida. Os feeds reais também cancelam e modificam ordens, o que domina o tráfego de mensagens. O livro agregado aqui é o modelo certo para entender profundidade, spread e impacto, e o ponto de partida do desequilíbrio do fluxo de ordens do próximo tópico.
  • Cada lado é um dict {price: size}: o melhor bid é max(bids), o melhor ask min(asks); o spread é ask - bid, o médio sua média, e ambos são None se um lado estiver vazio.
  • Adicione uma ordem copiando o dict, somando no preço e devolvendo a cópia; o livro recebido fica inalterado.
  • Uma compra a mercado percorre os asks ordenados, levando min(left, size) por nível, apagando os esgotados e reduzindo os levados em parte; livros reais também têm uma fila em cada nível.

A seguir: o desequilíbrio do fluxo de ordens, ler a pressão no livro para antecipar o próximo movimento do preço.

Lab: o que é avaliado

  • Achar o topo do livro com best_bid_ask25 pts
  • Medir a diferença com spread_and_mid25 pts
  • Colocar uma ordem no livro com add_limit_order25 pts
  • Consumir as ofertas de venda com match_market_buy25 pts
Explorador · lab-112-1
▾ lab-112-1
…
bash · no navegador
learner@quantcraft:~/lab-112-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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