Skip to main content
Um spread de 5% que dura 3 segundos não serve para quem precisa de 20 minutos para transferir na rede. A análise histórica responde duas perguntas por rota (par + exchange de compra + exchange de venda):
  • Quanto tempo as oportunidades duram? Número de janelas acima do threshold, duração média, mediana (p50), p90 e máxima, distribuição de duração e horário do dia em que as janelas começam.
  • Teria dado para operar? Um backtest simples com capital, tempo de transferência e custos líquidos, que separa as operações completadas das que expiraram antes de a transferência chegar.
No aplicativo a tela fica em /analise-historica (plano premium) e pode ser aberta pelo botão “Ver análise histórica e backtest” no detalhe de uma operação.

Fonte dos dados

Os cálculos usam a coleção MongoDB operations_audit, gravada pelo processamento REST a cada ~19 segundos. Ela tem limitações que valem para todos os números:

Como uma janela é detectada

As amostras da rota são lidas em ordem cronológica. Uma janela começa na primeira amostra com spread ≥ threshold e termina quando:
  • uma amostra fica abaixo do threshold; ou
  • a próxima amostra chega mais de 60 s depois da anterior (cerca de três ciclos perdidos, o que indica que o spread saiu da faixa gravada).
A duração é fim − início. Com basis=net o valor comparado é o netSpread gravado na linha (notional de referência de US$ 1.000). Em linhas antigas, sem o modelo de custo, o líquido é estimado com as mesmas taxas padrão do cálculo de spread líquido (NET_SPREAD_DEFAULT_TAKER_RATE, NET_SPREAD_DEFAULT_WITHDRAWAL_USD). A incidência por hora é contada pelo início de cada janela, em UTC, e a tela converte para o fuso do navegador.

Sugestão de tempo de transferência

A resposta traz suggestedTransfer, calculado assim: a rede mais usada nas janelas × a mediana de confirmações gravada em fees.network.confirmations × um tempo de bloco aproximado por rede, mais 5 minutos de processamento da exchange. Redes sem tempo de bloco conhecido não recebem sugestão. É só um valor inicial: o usuário pode alterar o campo.

Hipóteses do backtest

  • Capital único e uma operação por janela. Entra assim que o spread atinge o threshold e o capital está livre. Janelas que começam e terminam com o capital em trânsito contam como skippedBusy. O rebalanceamento de volta para a exchange de compra não é modelado.
  • Rota inviável. Amostras com executable=false (sem rede comum ou com saque/depósito suspenso) não abrem operação. Uma janela só com amostras assim conta como skippedInfeasible.
  • Completada. A janela continua aberta quando a transferência chega (entrada + transferMinutes). O resultado usa o spread bruto da primeira amostra a partir da chegada, e não o da entrada. É a hipótese conservadora.
  • Expirada. A janela fechou antes da chegada. Como não existe dado abaixo de 4%, a hipótese é spread 0 com pagamento dos custos.
  • Custos. líquido% = bruto − (takerCompra + takerVenda) × 100 − saqueUSD / capital × 100, com as taxas da amostra de entrada. O custo de saque é fixo em USD, por isso pesa menos com capital maior. Operações cuja amostra não tinha custos completos são marcadas com costsEstimated e contadas em estimatedCosts.
  • Em andamento. Uma operação aberta cuja janela ainda não fechou no fim do histórico entra em unresolved e não soma no resultado.

Endpoints

Os dois estão no limitador de arbitragem (30 req/min por IP), têm timeout de 10 s e cache de 30 minutos por combinação de parâmetros. Na inicialização o backend cria em operations_audit o índice {ticker, best_buy_exchange_name, best_sell_exchange_name, timestamp} usado por essas consultas.

Código

  • crypto-core/internal/application/opportunity/: detecção das janelas, estatísticas, backtest e sugestão de transferência
  • crypto-core/internal/infra/db/opportunity_history.go: leitura em streaming com projeção e o índice
  • crypto-core/internal/api/opportunity-history-api.go: handlers HTTP
  • front-argitragem/src/pages/opportunity-history/: a tela