Documentation

Live Execution API

Inscreva uma estratégia num ativo e timeframe ao vivo — receba um sinal no momento em que sua condition de entrada ou saída dispara num candle real e fechado.

#Visão geral

Live Execution está em beta. A API é estável e disponível em todo plano, incluindo o Free — espere que o ferramental ao redor (dashboards, webhooks) continue crescendo a partir daqui.

Uma subscription ao vivo observa um par de ativo num timeframe. Toda vez que um candle fecha pra esse par, sua estratégia é avaliada contra ele — a mesma Strategy DSL e o mesmo engine de avaliação que a Backtesting API usa, só que rodando continuamente em vez de sobre um intervalo histórico.

URL base: https://live.emidlabs.com/api/public/v1/live

Toda requisição exige o header x-api-key com uma API key válida escopada pro serviço live. Keys são geradas no Console — o toggle de Live Execution aparece lá, ao lado de Backtesting.

#Providers e ativos suportados

Escuta diretamente naCoinbaseBinance

Uma subscription ao vivo se conecta direto no próprio feed de dados de mercado da corretora escolhida — não há lista fixa de ativos pra consultar antes. Qualquer par que o provider realmente liste pode ser inscrito, no formato de assetPair próprio daquele provider (veja provider abaixo). Isso é mais amplo, de propósito, do que o que Backtesting suporta.

Live vs. Backtesting não é o mesmo universo de ativos. Backtesting só cobre ativos que a EmidLabs já extraiu e armazenou candles históricos — uma lista fixa e curada (veja a página Referência de Dados). Live Execution não tem essa lista: ele se inscreve direto no feed ao vivo da Coinbase ou da Binance, então cobre tudo que qualquer uma das duas corretoras lista, não só o que já foi backtestado antes. O trade-off é que a validação acontece de forma diferente — veja os campos assetPair/provider abaixo pro que acontece quando um par acaba não existindo.

#Como funciona

Não há loop de polling pra construir. Inscreva uma vez; um sinal só existe porque uma condition real de entrada ou saída ficou true num candle real e fechado:

EtapaO que acontece
1. InscreverFaça POST com uma estratégia + assetPair. O timeframe vem do próprio configuration.timeframe da estratégia.
2. Candle fechaTodo candle fechado pra esse ativo+timeframe avalia sua estratégia — o mesmo StrategyRunner que a Backtesting API usa.
3. Sinal disparaSe entry ou exit avalia true, é registrado imediatamente — faça polling em GET .../signals ou confira o dashboard do Console.
4. Pare a qualquer momentoFaça DELETE na subscription — nenhuma avaliação a mais acontece pra ela, sem cobrança de período parcial.

#Signal Model: Stateless vs Stateful

Todo fechamento de candle reavalia decision.entry/decision.exit do zero — não há memória embutida de se o último candle já disparou o mesmo sinal. Se uma condition não é edge-triggered (uma comparação simples como rsi14 > 55 em vez de crossUp(...)/crossDown(...)), ela permanece true por vários candles consecutivos, e o comportamento padrão redispara esse mesmo sinal em cada um deles.

modelComportamento
"stateless" (padrão)Toda subscription começa aqui. Um sinal é registrado/entregue exatamente quando decision.entry/decision.exit avalia true — toda vez, mesmo repetidamente pra uma condition que fica true por vários candles.
"stateful"A subscription rastreia sua própria posição de Entry/Exit internamente (isPositioned) — nunca consultada da sua corretora — e só registra/entrega um sinal numa transição de verdade: Entry enquanto não posicionado, ou Exit enquanto posicionado. O resto é suprimido silenciosamente, nenhum sinal registrado, nenhum webhook enviado.
isPositioned nunca é inferido de um saldo ou posição real da corretora — essa API não tem integração própria com corretora nenhuma. Se desviar da realidade (um trade feito manualmente fora desse sistema), corrija você mesmo via PATCH /subscriptions/{id}. Você pode definir model diretamente em POST /subscriptions/POST /subscriptions/batch pra criar uma subscription já "stateful" numa única chamada, ou mudar uma existente a qualquer momento do mesmo jeito.

#POST /subscriptions — Criar

POST/subscriptions

Inscreve uma estratégia pra avaliação ao vivo num par de ativo.

Mesmo formato de strategySnapshotJson da Backtesting API — veja Strategy System pra referência completa da DSL. configuration.timeframe dentro dele é o que determina o limite de candle em que sua estratégia avalia (5M, 15M, 1H, etc.) — não há um campo de timeframe separado na própria subscription.

Corpo da requisição

CampoTipoObrigatórioDescrição
strategySnapshotJsonobjectSimObjeto de estratégia — configuration, inputs, conditions, score, decision, riskManagement. configuration.timeframe determina a frequência de avaliação.
assetPairstringSimPar de negociação, no formato exato que o provider escolhido usa — veja provider abaixo. Nenhuma tradução acontece em lugar nenhum: um ativo que não existe sob essa string exata nesse provider é aceito aqui e falha assincronamente, não é rejeitado na criação.
providerstringNãoQual provedor de dados de mercado escutar: "coinbase" ou "binance". Usa "coinbase" por padrão quando omitido.
webhookUrlstringNãoURL https:// absoluta. Quando definida, todo sinal emitido também é enviado via POST pra ela — veja Webhooks abaixo.
modelstringNão"stateless" (padrão quando omitido) ou "stateful" — veja Signal Model acima.
isPositionedbooleanNãoSó tem significado quando model é "stateful". Usa false (ainda não posicionado) por padrão quando omitido.
O formato de assetPair depende inteiramente de provider — eles não são intercambiáveis. Coinbase usa hífen ("BTC-USDC"); Binance não usa ("BTCUSDC"). Não há checagem de existência contra nenhuma das duas corretoras no momento da criação: um par inválido, ou o par certo no formato errado de provider, retorna 201 imediatamente e depois o status da subscription muda pra "Errored" em cerca de um minuto — confira depois de criar, ou fique de olho na falha via o log de webhook/sinal ficando vazio por mais tempo que o esperado.

Resposta

CampoTipoDescrição
idstring (UUID)Identificador único da subscription.
statusstring"Active" imediatamente após a criação.
modelstring"Stateless" a menos que model tenha sido definido como "stateful" na requisição.
isPositionedbooleanReflete o isPositioned da requisição quando model é "Stateful"; false caso contrário.
webhookSecretstring | nullSó presente quando webhookUrl foi definida. Retornado uma vez, só aqui — nenhum endpoint o repete depois.

#POST /subscriptions/batch — Criar em Batch

POST/subscriptions/batch

Inscreve a MESMA estratégia pra avaliação ao vivo em vários pares de ativo de uma vez.

Uma subscription por entrada em assetPairs, todas compartilhando o mesmo strategySnapshotJson/provider/webhookUrl. Best-effort por item — um par de ativo ruim (desconhecido, formato errado de provider, limite de subscription concorrente atingido) nunca falha o resto do batch.

Corpo da requisição

CampoTipoObrigatórioDescrição
strategySnapshotJsonobjectSimCompartilhado por toda subscription criada nessa chamada.
assetPairsstring[]SimUma entrada por subscription a criar, cada uma no próprio formato do provider escolhido. Máximo de 50 por chamada.
providerstringNãoCompartilhado por toda subscription desse batch. Usa "coinbase" por padrão quando omitido.
webhookUrlstringNãoCompartilhado por toda subscription desse batch — cada uma ainda ganha suas próprias entregas assinadas e seu próprio webhookSecret.
modelstringNãoCompartilhado por toda subscription desse batch. "stateless" (padrão quando omitido) ou "stateful" — veja Signal Model acima.
isPositionedbooleanNãoCompartilhado por toda subscription desse batch, só tem significado quando model é "stateful". Usa false por padrão quando omitido.

Resposta

CampoTipoDescrição
itemsarrayUma entrada por par de ativo requisitado, na ordem submetida.
items[].assetPairstringEcoa o par de ativo requisitado.
items[].idstring | nullDefinido em caso de sucesso.
items[].statusstring | nullDefinido em caso de sucesso — "Active".
items[].webhookSecretstring | nullDefinido em caso de sucesso, só quando webhookUrl foi fornecida. Retornado uma vez, só aqui.
items[].errorstring | nullDefinido em vez de id/status/webhookSecret quando esse item específico falhou.

#Webhooks

Passe webhookUrl na criação e todo sinal que essa subscription emitir também é enviado via POST pra lá como JSON, no mesmo formato do objeto de sinal abaixo, assinado via um header X-Emidlabs-Signature t={timestamp unix},v1={HMAC-SHA256 hex} de `${timestamp}.${rawBody}` usando webhookSecret como chave. Entrega tenta de novo até 3 vezes em erros de rede, timeouts, 429s, e respostas 5xx do seu endpoint — um webhook lento ou inacessível nunca bloqueia a avaliação de sinal em si.

#DELETE /subscriptions/{id} — Parar

DELETE/subscriptions/{id}

Para uma subscription. Nenhum candle a mais é avaliado pra ela.

Retorna 404 se a subscription não existe ou não pertence à sua conta.

#POST /subscriptions/stop-all — Parar Todas

POST/subscriptions/stop-all

Para toda subscription atualmente ativa na sua conta, numa chamada.

Sem corpo de requisição. Idempotente — subscriptions já paradas são simplesmente ignoradas, não é erro.

Resposta

CampoTipoDescrição
itemsarrayUma entrada por subscription que estava ativa quando essa chamada começou.
items[].idstringUUID da subscription.
items[].statusstring | nullDefinido em caso de sucesso — "Stopped".
items[].errorstring | nullDefinido em vez de status quando esse item específico falhou.
Não há como restringir isso a um subconjunto das suas subscriptions — age na conta inteira. Use POST /subscriptions/stop com uma lista explícita de ids se você só quer parar algumas.

#POST /subscriptions/stop — Parar Por Ids

POST/subscriptions/stop

Para uma lista específica de subscriptions, numa chamada.

Corpo da requisição

CampoTipoObrigatórioDescrição
idsstring[]SimIds de subscription a parar. Máximo de 200 por chamada.

Resposta

CampoTipoDescrição
itemsarrayUma entrada por id requisitado, na ordem submetida.
items[].idstringEcoa o id requisitado.
items[].statusstring | nullDefinido em caso de sucesso — "Stopped". Idempotente, igual ao stop único.
items[].errorstring | nullDefinido em vez de status quando esse id específico falhou (ex: não encontrado).

#PATCH /subscriptions/{id} — Atualizar

PATCH/subscriptions/{id}

Atualiza o signal model, estado de posição, ou webhook de uma subscription.

assetPair, timeframe, provider, e a estratégia em si nunca podem ser mudados depois da criação — pare a subscription e crie uma nova pra isso. Todo campo abaixo é opcional; omita um campo pra deixá-lo inalterado.

Corpo da requisição

CampoTipoDescrição
modelstring"stateless" ou "stateful" — veja Signal Model abaixo.
isPositionedbooleanSó tem significado quando model é (ou está sendo definido pra) "stateful". Uma correção manual, nunca inferida automaticamente — veja Signal Model abaixo.
webhookUrlstringUma nova URL https:// absoluta, ou uma string vazia pra remover o webhook existente. Qualquer mudança não-vazia gera um webhookSecret novo.

Resposta

CampoTipoDescrição
idstringUUID da subscription.
modelstringO model da subscription depois dessa atualização.
isPositionedbooleanA flag de posição da subscription depois dessa atualização.
webhookSecretstring | nullSó presente quando webhookUrl acabou de ser mudada pra um valor não-vazio nessa chamada. Retornado uma vez, só aqui.

Retorna 404 se a subscription não existe ou não pertence à sua conta.

#GET /subscriptions/{id} — Status

GET/subscriptions/{id}

Busca o status atual de uma única subscription.

Campos da resposta

CampoTipoDescrição
idstringUUID da subscription.
assetPairstringPar de ativo sendo observado, exatamente como submetido.
providerstringProvedor de dados de mercado que essa subscription escuta — "coinbase" ou "binance".
timeframestringResolvido a partir do próprio configuration da estratégia no momento da criação.
statusstring"Active", "Stopped", ou "Errored" (o provider nunca conseguiu produzir dados pra esse assetPair — veja o Callout do request de criação acima).
lastEvaluatedCandleOpenTimenumber | nullSegundos unix — OpenTime do candle mais recente que essa subscription avaliou. null se nenhum ainda.
modelstring"Stateless" ou "Stateful" — veja Signal Model abaixo.
isPositionedbooleanSó tem significado quando model é "Stateful" — veja Signal Model abaixo.
createdAtUtcstringTimestamp de criação (UTC).
stoppedAtUtcstring | nullQuando a subscription foi parada, se foi.

#GET /subscriptions — Listar

GET/subscriptions

Lista subscriptions da sua conta, paginado.

Parâmetros de query

ParâmetroTipoPadrãoDescrição
pageinteger1Número da página, começando em 1.
pageSizeinteger20Resultados por página. Deve estar entre 1 e 100.
statusstring(nenhum)Filtro opcional de correspondência exata: "Active", "Stopped", ou "Errored". Omita pra retornar todos os status.

Resposta

Mesmos campos por item da resposta de subscription única acima, sob items, mais metadados de paginação:

CampoTipoDescrição
itemsarraySubscriptions dessa página — mesmo formato de GET /subscriptions/{id}.
totalCountnumberTotal de subscriptions que batem com o filtro de status (ou todas, se omitido) em todas as páginas.
pagenumberA página retornada.
pageSizenumberO tamanho de página usado.
totalPagesnumberNúmero total de páginas nesse pageSize.

#GET /subscriptions/{id}/signals — Formato de Sinal

GET/subscriptions/{id}/signals

O log de sinais emitidos de uma subscription, paginado — o análogo ao vivo do tradesDetail da Backtesting API.

Parâmetros de query

ParâmetroTipoPadrãoDescrição
pageinteger1Número da página, começando em 1.
pageSizeinteger20Resultados por página. Deve estar entre 1 e 100.
typestring(nenhum)Filtro opcional de correspondência exata: "Entry" ou "Exit". Omita pra retornar os dois.

Campos da resposta

CampoTipoDescrição
itemsarraySinais dessa página, mais recentes primeiro.
items[].candleOpenTimenumberSegundos unix — OpenTime do candle cujo fechamento disparou esse sinal.
items[].typestring"Entry" ou "Exit".
items[].pricenumberPreço de fechamento do candle que disparou.
items[].scorenumberSoma dos pesos de toda condition que avaliou true nesse candle.
items[].conditionsobjectToda condition nomeada da estratégia, mapeada pra se era true nesse candle.
items[].scoreBreakdownobjectPeso por condition que contribuiu pro score — só conditions true contribuem.
items[].stopLossPricenumber | nullSó sinais de Entry. O preço de stop-loss que riskManagement colocaria pra essa entrada, computado na hora — null em sinais de Exit.
items[].takeProfitPricenumber | nullSó sinais de Entry. O preço de take-profit que riskManagement colocaria pra essa entrada — null em sinais de Exit.
totalCountnumberTotal de sinais que batem com o filtro de type (ou todos, se omitido) em todas as páginas.
pagenumberA página retornada.
pageSizenumberO tamanho de página usado.
totalPagesnumberNúmero total de páginas nesse pageSize.

v1 só emite sinais — não há camada de tracking de posição ou execução de ordem aqui. O que você faz com um sinal (abrir um trade, alertar alguém, registrar) é inteiramente sua própria integração.

#Confirmation Sources

Faça uma subscription exigir corroboração de outra antes do próprio sinal contar como real — ex: uma entrada de XRP em M30 só disparando quando uma subscription de BTC reporta tendência neutra, ou quando a própria subscription de tendência em H4 do mesmo ativo concorda. Dois campos em create_subscription fazem uma subscription (A) depender de outra (B) — sem endpoint novo, sem mudança na DSL de nenhuma das duas estratégias.

Campos da requisição

CampoTipoObrigatórioDescrição
rolestringNão"tradeable" (padrão) ou "support". Uma subscription "support" é uma fonte de confirmação pura — ela continua avaliando e emitindo sinais normalmente, mas existe pra ser referenciada no confirmationSources de outras subscriptions, não pra ser operada diretamente.
confirmationSourcesarrayNãoQuando definido, um sinal de Entry/Exit dessa subscription só vira "Confirmed" quando toda entrada aqui bater. Omita pro comportamento atual, incondicional.
confirmationSources[].sourceIdstring (UUID)Sim*O id de outra subscription na sua própria conta. Um sourceId que não existe, não é seu, ou nunca emite um sinal correspondente simplesmente nunca confirma — não falha a criação.
confirmationSources[].signalTypestringNão"entry" (padrão) ou "exit" — qual tipo de sinal da fonte conta como confirmação.
confirmationSources[].validityWindow.countintegerNãoPadrão 1. Quantos candles da própria timeframe da FONTE um sinal correspondente permanece válido. Escala automaticamente com a estratégia que está confirmando — a janela de uma fonte em H4 é medida em candles H4, independente da timeframe de A.
Os dois campos só podem ser definidos na criação — não há como adicionar, remover ou mudar confirmationSources ou role via Atualizar depois da criação, mesmo padrão de assetPair/provider. Pare a subscription e crie uma nova pra mudar o pareamento.

Como a confirmação é decidida

A confirmação olha pra trás, não pra frente: quando o candle de A fecha e um sinal candidato dispara, o EmidLabs checa se a fonte já tem um sinal recente o bastante pra ainda estar dentro da janela de validade — nunca espera um sinal da fonte que ainda não aconteceu. Se A declara mais de uma entrada em confirmationSources, todas precisam bater (E lógico).

Uma exceção estreita: se o próprio sinal de B pro mesmo momento real ainda está sendo processado quando a checagem de A roda (os dois fecham candle por volta do mesmo instante), o veredito "Unconfirmed" ainda pode virar "Confirmed" um instante depois, assim que B alcançar — limitado a um candle da própria timeframe de A, não uma espera geral. Veja os campos de resposta abaixo pra como isso aparece.

Campos de resposta do sinal

CampoTipoDescrição
rolestring"Tradeable" ou "Support", copiado da subscription no momento em que esse sinal foi emitido.
confirmationStatusstring | null"Confirmed" ou "Unconfirmed". null quando a subscription não declara confirmationSources — um sinal comum não é afetado por esse recurso em nenhum ponto.
matchedSourcesarray | nullUma entrada por requirement de confirmationSources que bateu — { sourceId, signalType, signalCandleOpenTime }. Vazio/ausente quando confirmationStatus é "Unconfirmed" ou null.
Um sinal "Unconfirmed" continua sendo persistido e continua aparecendo em GET .../signals — é uma trilha de auditoria, não um candidato descartado silenciosamente. Use confirmationStatus como filtro de query (mesmo nome de parâmetro) pra ver só um dos dois grupos. A entrega pro webhookUrl é onde o bloqueio de verdade acontece: um sinal "Unconfirmed" nunca dispara webhook, então qualquer coisa depois do webhook (uma bridge de execução, um alerta) só vê sinais confirmados.

Quando uma corrida resolve tarde (a "exceção estreita" acima), o mesmo sinal é entregue no seu webhook uma segunda vez, agora "Confirmed" — trate entregas de webhook como identificadas pelo id do sinal, não como exatamente-uma-vez.

#Strategy DSL

Live Execution e Backtesting compartilham exatamente o mesmo DSL e engine de avaliação — uma estratégia que passa num backtest pode ser inscrita ao vivo sem mudanças. Veja a referência completa de Strategy System pros indicadores, conditions, e a lista de funções nativas.

warmupBars ainda importa ao vivo: os primeiros candles depois que uma subscription começa são excluídos da avaliação até acumular histórico suficiente pros seus indicadores estabilizarem — mesma regra do backtesting, só que medida a partir do momento da subscription em vez da data de início do backtest.

#Códigos de erro

Toda resposta de erro tem o mesmo formato: { "error": "<código>", "message": "<texto>" }.

StatusCódigoDescrição
400invalid_payloadO corpo da requisição está malformado, faltando campos obrigatórios, ou o strategySnapshotJson falha na validação.
401api_key_missingO header x-api-key não foi enviado.
401api_key_invalidA API key fornecida é inválida, revogada ou inativa.
403service_not_enabledEssa API key não está escopada pro serviço de live execution — habilite no Console ao criar ou editar a key.
404not_foundA subscription não existe ou não pertence à sua conta.
429rate_limit_exceededMuitas requisições pra essa conta. Reduza o ritmo e tente de novo.