σμ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.3·~1 hAvançado

Código assíncrono com asyncio

Posição no roteiroMódulo 9 de 11 · Tópico 3 de 5
9.3 Código assíncrono com asyncio
—Nota do lab— / 100XP total—Sequência—

Esperar sem ficar parado

Na maior parte do tempo um programa de dados não calcula, espera: o servidor de preços responder, uma ordem ser confirmada, um download terminar. Se pede dez preços um a um, espera dez vezes seguidas. O código assíncrono permite que um programa inicie um pedido, o deixe de lado enquanto espera e siga com outro, tudo numa única thread. A ferramenta do Python para isso é o asyncio, construído com duas palavras-chave, async def e await.

# A coroutine: calling it does nothing until it is awaited
import asyncio

async def get_price(symbol):
    await asyncio.sleep(0.01)                  # stands in for waiting on a network answer
    return {"AAPL": 184.25, "MSFT": 410.5}[symbol]

coro = get_price("AAPL")
print(type(coro).__name__)                     # coroutine  nothing has run yet
print(asyncio.run(coro))                       # 184.25     the event loop runs it

async def, await e o laço de eventos

Uma função definida com async def é uma função corrotina: chamá-la devolve um objeto corrotina e não executa nada do corpo. Dentro, await algo pausa a corrotina até algo estar pronto e devolve o controle ao laço de eventos, que pode executar outras corrotinas nesse meio-tempo. asyncio.run(coro) inicia um laço e executa uma corrotina até o fim. await só vale dentro de uma async def; esquecê-lo é o erro clássico, pois a chamada devolve uma corrotina em vez da resposta.

# Awaiting ten prices one after another waits ten times; gather overlaps the waits
import asyncio
import time

async def get_price(symbol):
    await asyncio.sleep(0.05)
    return len(symbol) * 10.0

async def one_by_one(symbols):
    return [await get_price(s) for s in symbols]

async def together(symbols):
    return await asyncio.gather(*(get_price(s) for s in symbols))

symbols = ["AAPL", "MSFT", "NVDA", "TSLA", "AMZN", "META", "GOOG", "NFLX", "ORCL", "INTC"]
t0 = time.perf_counter()
asyncio.run(one_by_one(symbols))
slow = time.perf_counter() - t0
t0 = time.perf_counter()
asyncio.run(together(symbols))
fast = time.perf_counter() - t0
print(f"one by one: {slow:.2f} s, gathered: {fast:.2f} s")      # about 0.50 s against 0.05 s
print(slow > 4 * fast)                                           # True

Erros, timeouts e fazer à mão

A espera pode falhar. Um pedido que nunca responde deve ser cortado com asyncio.wait_for(coro, timeout), que levanta TimeoutError; um await dentro de try / except trata erros exatamente como código comum, então uma nova tentativa é um laço em volta de uma chamada aguardada. Por baixo, uma corrotina é algo que se pode avançar passo a passo: coro.send(None) a executa até a próxima pausa e, ao terminar, levanta StopIteration com o resultado. Um laço de eventos é o código que faz isso sem parar com muitas corrotinas ao mesmo tempo, e é assim também que os testes deste laboratório executam as suas.

# Stepping a coroutine by hand: this is what an event loop does for many of them
class Pause:
    def __await__(self):
        yield

async def job():
    await Pause()
    await Pause()
    return 184.25

coro = job()
steps = 0
while True:
    try:
        coro.send(None)
    except StopIteration as stop:
        print("finished with", stop.value)                  # finished with 184.25
        break
    steps += 1
print("paused", steps, "times")                              # paused 2 times
# A timeout turns a slow answer into an error you can handle, then retry
import asyncio

async def slow_feed():
    await asyncio.sleep(1.0)
    return 184.25

async def main():
    for attempt in range(1, 4):
        try:
            return await asyncio.wait_for(slow_feed(), timeout=0.01)
        except TimeoutError:
            print(f"attempt {attempt} timed out")
    return None

print(asyncio.run(main()))                                   # three timeouts, then None
Concorrência não é paralelismoO asyncio executa uma corrotina por vez e só troca em um await. Acelera a espera da rede, não a aritmética pesada: um cálculo longo dentro de uma corrotina bloqueia o laço e todas as outras com ele. Faça a matemática em funções comuns e deixe as corrotinas para a espera.
  • async def define uma função corrotina; chamá-la só cria uma corrotina, nada executa ainda.
  • await pausa até o resultado estar pronto e deixa o laço de eventos executar outras; só funciona dentro de async def.
  • asyncio.run inicia o laço, gather sobrepõe as esperas, wait_for adiciona um tempo limite; erros se tratam com try / except comum.

A seguir: dados em streaming com websockets, receber um fluxo de ticks ao vivo conforme acontecem.

Lab: o que é avaliado

  • Esperar uma cotação com get_price25 pts
  • Buscar uma lista de acompanhamento com get_prices25 pts
  • Sobreviver a um timeout com retry_price25 pts
  • Ser o laço de eventos com drive25 pts
Explorador · lab-114-1
▾ lab-114-1
…
bash · no navegador
learner@quantcraft:~/lab-114-1$
Python ainda não carregadoPythonLn 1, Col 1Spaces: 4UTF-8

Redefinir este tópico?

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