← Voltar aos artigos
July 16, 2026
5 min read

Simulação de fills: a escada da fantasia do preço de fechamento à realidade ciente da fila

Simulação de fills: a escada da fantasia do preço de fechamento à realidade ciente da fila
#simulação de fills
#backtest
#ordens limitadas
#posição na fila
#fills parciais
#market making
#execução
#microestrutura de mercado

Seu backtest contém dois modelos: um modelo do seu alpha e um modelo dos seus fills. A maioria das pessoas gasta 95% do esforço no primeiro e herda o segundo do framework que estiver usando. Isso está invertido. Um sinal medíocre com um modelo de fill honesto produz uma estimativa de PnL medíocre, mas real. Um ótimo sinal com fill_price = candle.close produz um número que não é a estimativa de nada — é o resultado de uma premissa que você nunca examinou.

Para estratégias taker em instrumentos líquidos, o modelo de fill é um termo de correção. Para tudo que envolve ordens limitadas passivas — market making, entradas passivas, captura de rebate post-only — o modelo de fill é a estratégia. Se você é preenchido, quando, em que quantidade, e condicional a qual movimento de preço subsequente determina o sinal do PnL, não apenas sua magnitude.

Em Backtest-live parity mapeamos a taxonomia completa das divergências backtest-live e classificamos a divergência de execução com severidade 5/5 — a pior classe. Aquele artigo deu à simulação de fills três níveis grosseiros de precisão e seguiu em frente. Este é o complemento em profundidade: a escada completa, degrau por degrau, com o ciclo de vida da ordem como máquina de estados, limites de probabilidade de fill que você realmente pode calcular, e um experimento medido mostrando exatamente em qual degrau da escada uma estratégia maker "lucrativa" morre.

A escada

Escada de cinco degraus de fidelidade na simulação de fills

Cada degrau exige mais dados e mais código, e cada degrau remove um viés sistemático específico. Os degraus são ordenados pelo que fazem de errado, não apenas pelo custo.

Degrau 0: fill a preço de fechamento

fill_price = bar.close

A ordem é preenchida instantaneamente, integralmente, no fechamento da barra que gerou o sinal. O sinal foi calculado a partir desse mesmo fechamento, então você está operando com dados que não existiam quando o preço foi impresso: look-ahead bias vestido de fantasia de execução. Qualquer estratégia com giro parece boa aqui.

Degrau 1: abertura da próxima barra

fill_price = next_bar.open

O modelo mínimo honesto para lógica taker em barras. O sinal é calculado na barra tt, o fill acontece no primeiro preço observável da barra t+1t+1. Isso elimina o look-ahead, mas ainda assume spread zero, impacto zero, liquidez infinita no preço de abertura e 100% de certeza de fill. Para ordens limitadas, isso degenera em lógica de touch-fill (mais adiante sobre por que isso é veneno).

Degrau 2: spread + slippage fixo

half_spread = mid * spread_bps / 2e4
slip        = mid * slippage_bps / 1e4
fill_price  = mid + side * (half_spread + slip)   # side: +1 buy, -1 sell

Agora todo trade taker paga metade do spread mais uma constante calibrada. Este é o primeiro degrau em que uma estratégia de alto giro pode morrer no backtest — e esse é o ponto. O erro residual: o slippage não é constante. Ele escala com o tamanho da ordem em relação à profundidade exibida e explode exatamente quando sua estratégia mais quer operar. Um valor fixo de 5 bps é uma média sobre regimes; sua estratégia não opera no regime médio.

Degrau 3: depth-walk em L2 para ordens a mercado

Com snapshots do order book você para de adivinhar o slippage e passa a calculá-lo. Uma compra a mercado de tamanho QQ percorre o lado ask nível por nível; o preço de fill é a média ponderada por volume entre os níveis consumidos:

Pfill(Q)=1Qipimin ⁣(qi,  Qj<iqj)P_{\text{fill}}(Q) = \frac{1}{Q}\sum_{i} p_i \cdot \min\!\left(q_i,\; Q - \textstyle\sum_{j<i} q_j\right)

def depth_walk(levels: list[tuple[float, float]], qty: float) -> tuple[float, float]:
    """levels: [(price, size), ...] sorted best-first. Returns (vwap, filled_qty)."""
    remaining, cost = qty, 0.0
    for price, size in levels:
        take = min(size, remaining)
        cost += take * price
        remaining -= take
        if remaining <= 0:
            break
    filled = qty - remaining
    return (cost / filled if filled > 0 else float("nan"), filled)

Duas correções tornam isso substancialmente mais honesto. Primeiro, latência: percorra o book como ele estava Δt\Delta t depois do timestamp da sua decisão, onde Δt\Delta t é sua latência medida de sinal até a exchange — o book que você viu não é o book que você atingiu. Segundo, fills parciais de ordens a mercado: se a profundidade exibida dentro do seu preço-limite for menor que QQ, o modelo precisa retornar um fill parcial e deixar um remanescente passivo, o que passa o problema para a máquina de estados abaixo.

O erro residual no degrau 3 é impacto e reposição: você consome o book como um objeto estático, mas books reais se repõem parcialmente (e contrapartes reais reagem). Para clips abaixo de alguns por cento da profundidade no topo do book esse erro é pequeno; para clips maiores você precisa de um modelo de impacto (Almgren-Chriss 2001) sobreposto.

Degrau 4: fills probabilísticos por posição na fila para ordens limitadas

Os degraus 0-3 respondem "a que preço minha ordem agressiva é preenchida". O degrau 4 responde à pergunta mais difícil: minha ordem passiva é preenchida de fato — e é o único degrau capaz de precificar uma estratégia maker. Uma ordem limitada passiva no preço pp é preenchida quando o volume negociado acumulado em pp excede o volume da fila que estava à sua frente. Isso exige rastrear sua posição em uma fila FIFO que você não consegue observar diretamente.

O maquinário de estimativa de posição na fila — posição inicial, regras de atualização em trades vs. cancelamentos, a família de probabilidade f(x)f(x) para alocar cancelamentos não observados — é o primitivo que construímos em Queue inside the wall. Não vou rederivá-lo aqui; o simulador o consome. O que o degrau 4 acrescenta é a regra de decisão de fill sobre a estimativa, coberta na seção de probabilidade de fill abaixo.

Por que este degrau importa é quantificado na literatura: Moallemi e Yuan (2016), "A Model for Queue Position Valuation in a Limit Order Book", mostram que, para instrumentos de tick grande, o valor econômico de uma posição na frente da fila versus no fundo da fila é comparável ao meio-spread — a mesma ordem de grandeza de toda a vantagem teórica de uma estratégia de market making. Um modelo de fill que ignora a posição na fila não subestima ou superestima o PnL de um maker; ele estima o PnL de uma estratégia diferente.

Existe um degrau 5 — simulação completa baseada em agentes, em que o mercado reage às suas ordens (modelos queue-reactive no sentido de Huang, Lehalle e Rosenbaum 2015; frameworks multiagente como o ABIDES, Byrd et al. 2020). O replay histórico, mesmo ciente da fila, assume que sua ordem não muda nada no comportamento de todos os demais. Essa premissa é razoável em tamanho de varejo e cada vez mais errada à medida que suas cotações se tornam uma fração visível do nível. O degrau 5 está fora do escopo aqui; saiba que a escada não termina no 4.

Fills parciais como máquina de estados

Os degraus 0-2 podem fingir que uma ordem é uma chamada de função: envia, recebe o preço, pronto. A partir do degrau 3, uma ordem é um processo com um ciclo de vida, e o simulador precisa modelá-la como uma máquina de estados ou vai lidar mal, silenciosamente, com os casos que mais importam.

Máquina de estados do ciclo de vida da ordem com anotações de posição na fila

enum OrderState {
    PendingNew,                                  // sent, not yet acked (latency window)
    Resting     { remaining: f64, q_ahead: f64 }, // in book, queue position estimated
    PartialFill { remaining: f64, q_ahead: f64 }, // some qty done, rest still queued
    PendingAmend,                                 // amend in flight
    PendingCancel,                                // cancel in flight
    Filled,
    Canceled    { filled_qty: f64 },              // may be partially filled at cancel time
    Rejected,
}

As transições carregam a economia:

  • PendingNewResting: a ordem entra na fila atrás de tudo que já existia no momento do ack, não no momento da decisão. Sua posição na fila é semeada com o volume do nível no instante t+Δtackt + \Delta t_{\text{ack}}. Simuladores que semeiam no momento da decisão superestimam sistematicamente a prioridade na fila — exatamente pelo volume que chegou durante sua janela de latência, que é a maior parte do volume durante rajadas.
  • RestingPartialFill: um trade no seu nível maior que a fila à sua frente te preenche parcialmente. O remanescente mantém sua posição (agora na frente da fila). Fills parciais não são ruído — são informação: ser preenchido em 0,3 de 1,0 e ver o preço saltar para longe é um evento de PnL diferente de um fill total, e o processo de inventário de um maker é construído a partir desses fragmentos.
  • RestingPendingAmendResting: a armadilha. Praticamente em toda exchange cripto, um amend é um cancel/replace — o cancelReplace da Binance é atômico contra dupla execução, mas retorna um novo order ID no fundo da fila. Mesmo exchanges com semântica nativa de modificação (CME Globex) preservam a prioridade temporal apenas para uma redução de quantidade; uma mudança de preço ou aumento de quantidade a perde. Logo, no simulador: qualquer amend de preço reseta q_ahead para o volume total atual do nível. Um motor de cotação que se reposiciona a cada 500ms não está "mantendo uma cotação" — está reentrando perpetuamente no fundo da fila, e seu perfil realista de fill é quase puramente seleção adversa. Combinado com o resultado de Moallemi-Yuan: recotar tem um preço, e o preço é a sua posição na fila.
  • PendingCancelPartialFillCanceled: cancelamentos também têm latência. Na janela entre decidir puxar uma cotação e o cancelamento chegar ao matching engine, você ainda pode ser preenchido — e esses são os piores fills que você vai receber, porque o motivo pelo qual você estava puxando a cotação é que o mercado estava prestes a te atropelar. Um simulador sem latência de cancelamento apaga exatamente os fills mais tóxicos do seu histórico.

A máquina de estados também é o que torna a contabilidade do simulador honesta: taxas incidem por evento de fill, o inventário é atualizado por evento de fill, e as estatísticas de tempo-em-estado (quanto tempo as ordens ficam passivas até serem preenchidas versus canceladas) tornam-se diretamente comparáveis com logs ao vivo — o que alimenta o loop de calibração no final.

Probabilidade de fill de ordem limitada: três modelos e uma faixa

Dada uma ordem passiva no preço pp (digamos, um bid), quando o simulador declara um fill? Três regras de decisão, em ordem crescente de honestidade:

1. Touch-fill (ingênua). Preenche se o preço tocar seu nível: lowtp\text{low}_t \le p. Esta é uma regra de first-passage-time, e sua falha foi medida há um quarto de século: Lo, MacKinlay e Zhang (2002), "Econometric Models of Limit-Order Executions" (Journal of Financial Economics 65), ajustaram modelos de sobrevivência a dados reais de ordens limitadas e concluem que execuções hipotéticas construídas a partir de first-passage times "são proxies muito pobres das execuções reais de ordens limitadas". O modo de falha é estrutural: quando o preço toca seu nível e recua, o toque consumiu a frente da fila — os traders que cotaram antes de você. O touch-fill concede a você os fills deles. Pior, concede exatamente os bons fills (touch-and-bounce é o cenário lucrativo para um maker), enquanto seu conjunto real de fills é enviesado para touch-and-run-through — os adversamente selecionados.

2. Trade-through (limite conservador). Preenche apenas se o preço negociar estritamente através do seu nível: lowt<pϵ\text{low}_t < p - \epsilon, ou, em dados de tick, se o volume negociado acumulado em pp exceder o nível inteiro. Se o preço atravessou, toda a fila em pp foi consumida, então você foi preenchido independentemente da posição. Isso nunca concede um fill que você não teria recebido. Seu viés é a imagem espelhada do touch-fill: nega todo fill em que a fila se esgotou até sua posição sem penetração total, e os fills que concede são desproporcionalmente os de run-through (adversamente selecionados). Um backtest de maker sob trade-through é um teste de estresse, não uma estimativa.

3. Estimativa de esgotamento de fila. Rastreie o volume negociado acumulado MtM_t no seu preço a partir do trade tape e o volume cancelado CtC_t inferido a partir de deltas de L2. Sua fila estimada à frente:

Q^ahead(t)=max ⁣(Q0MtϕCt,  0)\hat{Q}_{\text{ahead}}(t) = \max\!\Big(Q_0 - M_t - \phi \cdot C_t,\; 0\Big)

onde Q0Q_0 é o volume do nível na entrada da ordem (momento do ack) e ϕ[0,1]\phi \in [0,1] é a fração de cancelamentos assumida como vinda de posições à sua frente — o parâmetro cuja forma principiada (a família f(x)f(x)) é derivada no artigo de posição na fila. O fill começa quando Q^ahead=0\hat{Q}_{\text{ahead}} = 0; sua quantidade preenchida é o volume negociado em excesso a isso, o que gera fills parciais naturalmente:

filled(t)=min ⁣(S,  max(MtQ0+ϕCt,0))\text{filled}(t) = \min\!\Big(S,\; \max(M_t - Q_0 + \phi\, C_t,\, 0)\Big)

Definir ϕ=1\phi = 1 (todos os cancelamentos à sua frente) dá o extremo otimista deste modelo; ϕ=0\phi = 0, o extremo pessimista. Quando você tem apenas snapshots esparsos de L2 e nenhum trade tape no nível — comum em feeds cripto com throttle de 100ms — você pode recorrer a um prior baseado em modelo: Cont, Stoikov e Talreja (2010), "A Stochastic Model for Order Book Dynamics" (Operations Research 58), modelam cada nível de preço como uma fila de nascimento-morte e calculam, via transformadas de Laplace, a probabilidade de uma ordem no bid ser executada antes que o mid se mova, condicional aos tamanhos atuais da fila. É um oráculo analítico de probabilidade de fill: cru em relação ao replay do tape, muito melhor que o touch-fill, e barato o suficiente para avaliar dentro de um loop de backtest quente.

A disciplina da faixa

As três regras não são concorrentes — são uma ordenação:

fillstrade-through    fillsqueue    fillstouch\text{fills}_{\text{trade-through}} \;\subseteq\; \text{fills}_{\text{queue}} \;\subseteq\; \text{fills}_{\text{touch}}

o que induz uma faixa de PnL. Rode todo backtest de maker três vezes e reporte o intervalo:

PnLtrade-through    PnLlivePnLtouch\text{PnL}_{\text{trade-through}} \;\le\; \text{PnL}_{\text{live}} \lesssim \text{PnL}_{\text{touch}}

(a desigualdade superior é aproximada — o touch-fill pode reclassificar estratégias, não apenas inflá-las, porque concede fills contrafactuais bons). A regra de decisão que se segue: uma estratégia maker só é implantável se sobreviver no extremo conservador da faixa, e a faixa precisa ser estreita o suficiente para que a estimativa pontual signifique algo. Uma estratégia mostrando +9ktouch/9k touch / -3k trade-through tem uma faixa de 12kdelargura;voce^na~osabenada,excetoqueapremissadoseusimuladordominaseualpha.Umaestrateˊgiamostrando+12k de largura; você não sabe nada, exceto que a premissa do seu simulador domina seu alpha. Uma estratégia mostrando +2,1k / +$0,4k está te dizendo algo real.

O experimento: descendo uma estratégia maker pela escada

Colapso do PnL de estratégia maker degrau a degrau na escada do modelo de fill

Tome um maker deliberadamente simples — cotações simétricas no melhor bid/ask, clips fixos de 0,05 BTC, inventário limitado a ±0,5 BTC com flattening taker no limite. Um mês de dados perpétuos de BTCUSDT: barras de 1m para os degraus baixos, diffs de L2 a 100ms mais o trade tape para os degraus altos; taxa maker de 1,0 bps, taker de 4,0 bps. Mesmo código de sinal em cada degrau (núcleo compartilhado, de modo que a única variável seja o modelo de fill). Os números abaixo são de uma rodada representativa nossa — suas magnitudes vão variar por exchange, mês e tamanho; a forma, não:

Degrau Modelo de fill Taxa de fill das cotações Fills PnL do mês Veredito
0 close-fill 98% 41.200 +$14.800 fantasia
1 next-bar-open / touch em barras de 1m 89% 37.400 +$9.600 fantasia com latência
2 touch + spread e slippage fixo nos flattens taker 89% 37.400 +$7.100 custos modelados, fills ainda fictícios
3 + depth-walk em L2 nos flattens taker 89% 37.400 +$6.400 saídas honestas, entradas ainda fictícias
4a trade-through (conservador) 21% 8.900 -$3.900 limite de estresse
4b esgotamento de fila, ϕ\phi calibrado 37% 15.600 -$700 melhor estimativa
4c esgotamento de fila, ϕ=1\phi = 1 (otimista) 44% 18.700 +$1.900 extremo superior
shadow run ao vivo, mesmo mês 35% 14.100 -$1.150 realidade

Leia a tabela de cima para baixo e observe onde a estratégia morre. Não é no degrau 2 — taxas e slippage tiram 26%, e a estratégia ainda parece robustamente lucrativa. Ela morre entre o degrau 3 e o degrau 4, e morre por um motivo que nenhum modelo de custo consegue capturar: seleção de fills. O touch-fill concedeu 37.400 fills, dos quais a maioria era touch-and-bounce — captura pura de spread. O modelo ciente da fila eliminou 58% desses fills, e os fills eliminados eram desproporcionalmente os lucrativos: quando o nível é atingido levemente, a fila à frente de um maker que recota com latência de varejo absorve tudo. Os fills que sobrevivem até o degrau 4 são enviesados para varreduras que limpam o nível — os fills em que o preço já está atravessando você. A taxa de fill caiu 2,4x; o PnL trocou de sinal. Essa assimetria — perder os bons fills, manter os ruins — é a seleção adversa tornada mecanicamente explícita, e é invisível em todo degrau abaixo do 4.

Note também o que a faixa fez: [-3.900,+3.900, +1.900] engloba o zero, com a estimativa calibrada em -700eoaovivoem700 e o ao vivo em -1.150. O simulador não acertou o PnL ao vivo com precisão de centavos — mas acertou o sinal, a magnitude, e a taxa de fill dentro de 2 pontos percentuais. É para isso que serve um modelo de fill. O backtest do degrau 1 errou o PnL ao vivo por $10.750 numa estratégia cuja vantagem bruta mensal total era de poucos milhares de dólares: o erro do modelo de fill foi cerca de 3x o tamanho do alpha. Daí a tese: seu modelo de fill é uma premissa maior que seu alpha.

Uma ressalva para os degraus baixos: se você precisa viver com dados de barra (degraus 0-2), no mínimo resolva a ambiguidade intrabar com drill-down adaptativo — descendo de 1m para 1s/100ms/trades onde SL, TP ou níveis de cotação caem dentro do range da barra. O drill-down corrige erros de sequenciamento (qual nível foi atingido primeiro), mas não corrige erros de fila; é o complemento de resolução de dados deste artigo, não um substituto do degrau 4.

O loop de calibração: fechando contra fills ao vivo

Um simulador de degrau 4 tem parâmetros livres — ϕ\phi, latência Δt\Delta t, latência de cancelamento, a premissa de reposição de nível. Sem calibração, é apenas um palpite com formato diferente. O loop que o transforma em instrumento:

1. Registre tudo ao vivo. Cada evento de ordem com timestamps da exchange: envio, ack, cada fill parcial, acks de amend, acks de cancelamento. Mais o estado do L2 no momento do envio. Esta é a mesma disciplina de log que backtest-live parity exige para seu DivergenceMonitor — a calibração do modelo de fill é a camada mais profunda desse monitor.

2. Reproduza as mesmas ordens pelo simulador. Alimente os dados de mercado registrados e as instruções de ordem registradas (não os fills) no simulador. Agora você tem resultados pareados: para cada ordem ao vivo, um destino simulado.

3. Compare distribuições, não médias, em buckets. Uma única taxa de fill global pode esconder erros que se compensam (otimista demais em regimes calmos, pessimista demais em rajadas — anulando-se em uma média "calibrada"). Agrupe por drivers:

import numpy as np
from scipy.stats import ks_2samp

def calibration_report(pairs, bucket_key):
    """pairs: [{'bucket':…, 'live_filled':bool, 'sim_filled':bool,
                'live_ttf':float|None, 'sim_ttf':float|None}, …]"""
    out = {}
    for b in sorted({p['bucket'] for p in pairs}):
        grp = [p for p in pairs if p['bucket'] == b]
        live_fr = np.mean([p['live_filled'] for p in grp])
        sim_fr  = np.mean([p['sim_filled']  for p in grp])
        live_ttf = [p['live_ttf'] for p in grp if p['live_ttf'] is not None]
        sim_ttf  = [p['sim_ttf']  for p in grp if p['sim_ttf']  is not None]
        ks = ks_2samp(live_ttf, sim_ttf) if len(live_ttf) > 20 and len(sim_ttf) > 20 else None
        out[b] = {
            'n': len(grp),
            'fill_rate_live': live_fr,
            'fill_rate_sim':  sim_fr,
            'fill_rate_gap':  sim_fr - live_fr,      # signed: + means sim optimistic
            'ttf_ks_pvalue':  ks.pvalue if ks else None,
        }
    return out

Duas estatísticas por bucket: o gap de taxa de fill com sinal (simulador menos ao vivo) e um teste KS nas distribuições de tempo-até-fill entre as ordens preenchidas. A comparação de tempo-até-fill é a mais afiada — um simulador pode acertar as taxas de fill enquanto preenche em momentos sistematicamente errados, o que corrompe toda estatística downstream de inventário e seleção adversa. Esta é precisamente a lição do enquadramento de análise de sobrevivência de Lo-MacKinlay-Zhang: execução é um problema de tempo-até-evento, então valide-a como tal.

4. Ajuste os parâmetros, em ordem de identificabilidade. Latência primeiro (medida diretamente a partir dos timestamps de ack — não ajustada). Depois ϕ\phi, minimizando o gap de taxa de fill entre os buckets de profundidade de fila. Depois verifique os buckets de regime de volatilidade: um gap otimista persistente concentrado nos buckets de rajada geralmente significa que seu simulador subestima fills tóxicos por latência de cancelamento ou reposição de nível, não ϕ\phi.

5. Rode a faixa novamente. Após a calibração, a estimativa de esgotamento de fila deve cair dentro da faixa, perto do ao vivo, e — o verdadeiro teste de aceitação — a classificação das variantes de estratégia sob o simulador deve corresponder à classificação delas em modo shadow. Então congele os parâmetros e recalibre em um cronograma; a dinâmica de fill deriva com as faixas de taxa da exchange, mudanças de tick size e a população de HFT, e um ϕ\phi calibrado em março é uma hipótese em julho.

Expectativas de convergência de nossas rodadas: um simulador de degrau 4 sem calibração tipicamente cai dentro de ±10-15 pontos da taxa de fill ao vivo; após uma rodada de calibração, ±3-5 pontos, com p-values do teste KS de tempo-até-fill deixando de rejeitar uniformemente. Você não vai fazer melhor que isso com replay histórico — o resíduo é a reação do mercado a você, o que é problema do degrau 5.

O que levar

  1. Nomeie seu degrau. Todo backtest está nesta escada, quer você tenha escolhido o degrau, quer seu framework tenha escolhido por você. Se você não consegue nomear o degrau do seu modelo de fill e seus vieses conhecidos, seu número de PnL tem margens de erro que você não viu.
  2. Takers podem parar no degrau 3. Depth-walk mais latência medida precifica execução agressiva honestamente em tamanho de varejo. Gaste o esforço economizado em qualidade de dados.
  3. Makers começam no degrau 4. Abaixo dele, a lógica de fill de ordem limitada não é aproximada — ela seleciona um conjunto contrafactual de fills com viés de seleção adversa oposto. Backtests de touch-fill de estratégias maker são o gerador mais confiável de estratégias que morrem ao contato com produção.
  4. Modele o ciclo de vida, não o fill. Fills parciais, reset de fila por amend, latência de cancelamento — a máquina de estados é onde vivem os fills tóxicos, e os fills tóxicos são onde o PnL do maker vai morrer.
  5. Reporte a faixa. Limites conservador e otimista custam duas rodadas extras de backtest e convertem "meu backtest diz +7k"em"arealidadeestaˊemalgumlugarde[7k" em "a realidade está em algum lugar de [-3,9k, +$1,9k]" — o que é uma decisão diferente, e melhor.
  6. Calibre contra fills ao vivo em buckets. Um modelo de fill validado apenas em agregado é um modelo de fill com erros compensatórios ocultos. Gaps de taxa de fill em buckets mais testes KS de tempo-até-fill, recalibrados trimestralmente.

Os degraus da escada não são gradações acadêmicas — cada um é uma mentira específica que seu backtest para de contar. Suba até que as mentiras sejam menores que sua vantagem.

Links úteis

  1. Moallemi, C., Yuan, K. — A Model for Queue Position Valuation in a Limit Order Book (2016)
  2. Cont, R., Stoikov, S., Talreja, R. — A Stochastic Model for Order Book Dynamics, Operations Research 58(3), 549-563 (2010)
  3. Lo, A., MacKinlay, C., Zhang, J. — Econometric Models of Limit-Order Executions, Journal of Financial Economics 65(1), 31-71 (2002)
  4. Huang, W., Lehalle, C.-A., Rosenbaum, M. — Simulating and Analyzing Order Book Data: The Queue-Reactive Model, JASA 110(509), 107-122 (2015)
  5. Almgren, R., Chriss, N. — Optimal Execution of Portfolio Transactions (2001)
  6. Byrd, D., Hybinette, M., Balch, T. — ABIDES: Towards High-Fidelity Multi-Agent Market Simulation (2020)
  7. Binance API — Cancel-Replace order semantics
  8. CME Globex — Order modification and time priority rules

Citação

@article{soloviov2026fillsimulation,
  author = {Soloviov, Eugen},
  title = {Fill simulation: the ladder from close-price fantasy to queue-aware reality},
  year = {2026},
  url = {https://marketmaker.cc/blog/fill-simulation-partial-fills-backtest},
  description = {Five rungs of fill simulation fidelity — from close-price fills to probabilistic queue-position models. Partial fills as a state machine, limit-fill probability bounds as a PnL bracket, and a calibration loop against live fills.}
}
blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Fique à frente do mercado

Assine nossa newsletter para insights exclusivos sobre trading com IA, análises de mercado e atualizações da plataforma.

Respeitamos sua privacidade. Cancele a inscrição a qualquer momento.