2 de setembro de 2026 · microestrutura

A sua ordem limitada não foi executada: uma carta sobre posição na fila, backtests maker e o Sharpe que inventou

A sua ordem limitada não foi executada: uma carta sobre posição na fila, backtests maker e o Sharpe que inventou

Enviou-me o notebook na semana passada: o mesmo sinal, o mesmo universo, os mesmos 14 meses de dados do perp BTCUSDT. A única mudança foi a execução. Deixou de atravessar o spread e começou a deixar ofertas de compra um tick abaixo, e o Sharpe passou de 0.42 para 2.14. Perguntou-me se era real ou se tinha estragado alguma coisa.

Estragou alguma coisa. Quero mostrar-lhe exatamente onde, porque o bug está numa linha e a lição por trás dela é muito maior.

Eis a sua regra de execução, copiada do motor:

if bar.low <= limit_price: fill(limit_price)

Isto diz: se o mercado registou uma transação ao meu preço ou abaixo dele durante este minuto, a minha ordem foi executada ao meu preço. Na realidade, o que codifica é que o preço tocou no seu nível. Tocar não é executar. Entre as duas coisas há uma fila, que no seu modelo está vazia.

O que está à sua frente

Quando coloca uma oferta de compra a 84,120.0 no perp BTCUSDT, vai para o fim de tudo o que já está à espera nesse nível. No melhor nível do livro desse contrato, costuma haver entre 4 e 30 BTC, dependendo da hora do dia; a mediana na janela da sua amostra ronda os 12 BTC. A sua ordem é de 0.4 BTC. Para negociar, os vendedores têm de agredir esse nível com volume agregado suficiente para ultrapassar todos os que chegaram antes de si, e têm de o fazer antes de o nível ser cancelado debaixo de si ou de o mercado subir.

Por isso, a pergunta que o seu backtest devia fazer não é «o preço chegou a 84,120.0?», mas «foram executados pelo menos 12.4 BTC em vendas a mercado a 84,120.0 enquanto a minha ordem esteve lá?». São eventos muito diferentes. Nos seus dados, diferem por um fator de cerca de 3.

12.4 BTCvolume mediano à sua frente quando o preço toca no nível
100%taxa de execução assumida pelo seu backtest
31%dos toques que esvaziaram a fila à sua frente
4,180transações que passaram a ser cerca de 1,300

3 regras de execução, 3 estratégias diferentes

Voltei a correr o seu sinal com as mesmas entradas e 3 modelos de execução. O mesmo alpha, as mesmas comissões, o mesmo funding. Só mudou a lógica de execução.

Regra de execuçãoExecuçõesVantagem média aos 60 s após execuçãoSharpe
Toque: low <= limit4,180+2.6 bp2.14
Penetração estrita: low < limit - 1 tick1,712+0.4 bp0.61
Simulação de fila por volume no nível1,306+0.9 bp0.77

A linha do meio é a correção rudimentar a que toda a gente recorre primeiro: só contar uma execução se o mercado negociou estritamente para lá do seu preço, partindo do princípio de que, se o preço o ultrapassou, teve necessariamente de consumir a sua ordem. A ideia está certa e elimina a maior parte da fantasia. Mas também introduz um enviesamento desagradável, a que já chegarei.

A linha de baixo é a que deve implementar. Não precisa de feed L3 nem de reconstruir as ordens uma a uma. Já tem quase tudo o que precisa.

Uma simulação de fila que pode criar com aggTrades

Obtenha o fluxo de transações agregadas em vez das klines. Cada transação inclui preço, quantidade, data e hora e a indicação do lado maker, que lhe diz se o agressor estava a comprar ou a vender. É suficiente para uma simulação funcional da sua própria ordem passiva:

  1. Quando a sua ordem é colocada, registe o volume em espera no seu preço. Se só tiver um feed do livro de ordens a cada 100 ms, use a última captura; o erro é pequeno comparado com o que está a corrigir.
  2. Defina queue_ahead = resting_size. Seja pessimista e assuma que está no fim da fila. Está, a menos que seja quem cria o nível.
  3. Percorra o fluxo de transações. Cada venda iniciada por um agressor, ao seu preço ou abaixo, reduz queue_ahead pela respetiva quantidade. Quando o valor ficar negativo, a sua ordem é executada ao seu preço, nessa data e hora.
  4. Se o preço se afastar 1 tick, não reponha a fila a 0. Reduza-a gradualmente. Algumas das ordens à sua frente são canceladas quando o nível deixa de estar no melhor preço; outras não. Uma redução de 30-40% por cada segundo completo fora do melhor preço ajustou-se melhor às minhas reconstruções do que qualquer um dos extremos.
  5. Se a sua estratégia cancelar e voltar a colocar a ordem, modele-a como uma ordem nova no fim da nova fila. É este passo que as pessoas ignoram, e é aí que se esconde o resto da fantasia.

É no passo 2 que vai querer discutir comigo. Sim, às vezes está perto do início da fila porque colocou a ordem no momento em que o nível se formou. Muito bem: meça isso, não o presuma. Registe o volume em espera quando coloca a ordem e deixe os dados dizerem que fração das suas ordens chega mesmo cedo. Na sua estratégia, eram 11%, porque o sinal dispara depois de um movimento. Ou seja, o nível a que se junta já existe e já tem gente à espera.

As execuções que consegue são as que preferia não ter tido

Agora vem a parte que realmente interessa e a razão pela qual a regra de penetração estrita é enviesada.

Pense em quando a sua oferta de compra é totalmente consumida. Isso acontece quando a pressão vendedora é suficiente para absorver todo o volume do nível. Ou seja, por definição, é o momento em que o mercado desce através do seu preço. As execuções de que tem mais certeza são precisamente aquelas em que fica imediatamente numa posição desfavorável.

Separe as suas execuções pelo modo como ocorreram e meça o mark-out aos 60 segundos:

Tipo de execuçãoPercentagem das execuçõesMark-out aos 60 s
O nível foi negociado, o preço recuperou38%+3.1 bp
O nível foi negociado, o preço ficou estável21%+0.2 bp
O preço passou 2+ ticks abaixo41%−2.4 bp

O seu backtest ingénuo deu-lhe as 3 categorias e tratou-as a todas como gratuitas. A regra de penetração estrita dá-lhe quase exclusivamente a terceira categoria, e é por isso que a vantagem caiu ainda mais do que na simulação de fila. Nenhuma das duas está certa. A simulação de fila dá-lhe uma combinação realista, e a combinação é o que conta: a execução passiva rende-lhe o spread e cobra-lhe em seleção adversa; a relação entre os dois é a sua estratégia real.

A velha perspetiva da mesa de ações continua válida: uma ordem maker é uma opção gratuita que vendeu ao mercado. Alguém a exerce quando lhe convém. O seu backtest recebia o prémio e esquecia-se de que a opção também podia dar prejuízo.

As transações que não conseguiu executar mudam a estratégia, não apenas o custo

É nisto que mais quero que pense. Quando modela mal a execução taker, obtém as transações certas ao preço errado, e corrigir as comissões resolve a maior parte do problema. Quando modela mal a execução maker, obtém um conjunto de transações completamente diferente. Cerca de 2,900 das suas 4,180 entradas nunca aconteceram. Algumas eram dos seus melhores sinais, em velas que dispararam e inverteram, exatamente o tipo de movimento em que o mercado se afastou sem si.

Por isso, a ramificação para ordens não executadas precisa de lógica real. O que faz a estratégia quando a ordem de entrada não é executada antes de o sinal perder validade? Vai atrás com uma ordem taker e paga o spread mais o impacto? Volta a colocar a ordem mais abaixo e aceita uma base de entrada diferente? Ignora a transação e fica sem posição? Cada opção produz uma curva de capital substancialmente diferente, e nenhuma equivale a «assuma que a ordem foi executada». Nas nossas simulações, acrescentar uma regra honesta para ir atrás do preço (atravessar o spread após 20 segundos sem execução, com slippage limitado a 3 bp) recuperou cerca de um terço das transações em falta e aproximadamente metade da diferença entre o Sharpe ingénuo e o da simulação de fila. É um resultado realmente interessante, que só aparece quando o modelo de execução é suficientemente realista para a pergunta fazer sentido.

Verificação rápida, em 10 minutos: pegue no seu registo de paper trading em tempo real e no backtest, usando a mesma janela temporal. Compare a taxa de execução, não o PnL. Se o backtest executa 100% das ordens em espera e o paper trading executa 34%, não está a comparar estratégias: tem um bug no modelo de execução. Corrija-o antes de olhar para um único número de retorno.

Mais 2 coisas enquanto o tenho aqui

Rejeições post-only. Se usa post-only para garantir a categoria de comissões maker e o livro muda entre a sua decisão e a confirmação da exchange, a ordem é rejeitada em vez de ficar em espera. Nos nossos registos de paper trading, isso acontece em 3-6% das tentativas com BTCUSDT em horas normais e em mais de 15% no minuto após a divulgação do CPI dos EUA. Uma ordem rejeitada não é uma ordem executada nem uma ordem em espera por executar: é uma transação que nunca existiu. Se o seu backtest não contemplar esse estado, a contagem de transações fica inflacionada precisamente nos regimes que mais lhe interessam.

Prevenção de self-trade e a sua própria presença no mercado. Com 0.4 BTC, não está a mexer no preço de BTCUSDT, por isso ignore este ponto. Mas disse que queria aplicar isto a um perp de uma altcoin de capitalização média, onde o valor nominal no melhor nível do livro fica muitas vezes abaixo de $15k. Aí, a sua ordem representa uma parte significativa da fila, e o valor que regista para o volume à sua frente já inclui o efeito da presença da sua última ordem. Quando o seu tamanho ultrapassa cerca de 10% do volume em espera no nível, a simulação tem de ter em conta que os outros participantes reagem à sua presença. E, francamente, nessa altura confiaria mais no paper trading do que em qualquer simulação que você ou eu consigamos escrever.

Volte a correr a simulação de fila e envie-me a tabela de mark-out dividida por tipo de execução. Se a categoria de recuperação ainda concentrar a maior parte da vantagem e a categoria de penetração não a eliminar toda, talvez tenha algo que valha a pena testar em paper trading. Se tudo dependia das 2,900 execuções que nunca teria conseguido, é melhor descobrir agora do que após 4 semanas a ver uma conta de paper trading não fazer o que o notebook prometeu.

ordens limitadasposição na filaseleção adversabacktestingfuturos de cripto
← Todos os artigos