Logo hamster-bot Claude novo: MCP
RU EN PT

Carregando…

HTTP API

HTTP API para controlar o bot e o testador: configurações, estratégias, chaves de API das corretoras, posições e ordens, logs, execução do testador e trabalho com seus relatórios. Endereço — o mesmo da interface web: http://<host>:<porta>, a porta é definida pelo campo port em settings_program.json.

91 endpoints

Acesso#

Token de API (recomendado)#

Envie o cabeçalho Authorization: Bearer <api_token> em cada requisição:

curl -H "Authorization: Bearer <api_token>" http://127.0.0.1:5000/api/current/bots

O bot cria o api_token sozinho na primeira inicialização e o guarda em settings_program.json. O token funciona a partir de qualquer endereço e com qualquer valor de auth_telegram, e o login pelo navegador não o redefine. Guarde o token como uma senha: ele dá acesso a tudo, inclusive à negociação e às chaves das corretoras.

Você pode ver e copiar o token na interface web: “Configuração global”, bloco “Token de API e MCP”. Ali também está o botão “Emitir novo”; o token anterior deixa de funcionar imediatamente. Com o login pelo Telegram desativado, esse bloco só funciona a partir da mesma máquina (127.0.0.1). No editor de configuração, no log e na resposta de GET /api/settings/config o token fica oculto (os últimos 4 caracteres ficam visíveis), e não é possível alterá-lo pelo editor nem por POST /api/settings/config.

Novo token pela API: POST /api/settings/api-token/regenerate, resposta { "success": true, "api_token": "..." }.

Sem token, a partir da mesma máquina#

Se o login pelo Telegram estiver desativado ("auth_telegram": false), requisições sem token são aceitas apenas da mesma máquina, em 127.0.0.1 ou localhost:

curl http://127.0.0.1:5000/api/current/bots

De outros endereços sem token a API responde 401. Com o login desativado, a interface web continua aberta a qualquer pessoa que consiga se conectar à porta; portanto, em um servidor com a porta aberta mantenha o login ativado.

Requisições de páginas de outros sites (POST com cabeçalho Origin diferente do endereço do bot) são rejeitadas com 403 — é a proteção contra CSRF. curl, scripts e clientes MCP não enviam o cabeçalho Origin, então isso não os afeta. Se o bot estiver atrás de um proxy reverso, o proxy deve repassar o cabeçalho Host original.

Requisições e respostas#

  • O corpo das requisições POST é JSON em UTF-8 (Content-Type: application/json).
  • Nomes no caminho são codificados em URL: estratégia T4 BTC → /api/settings/strategy/T4%20BTC.
  • Configurações são enviadas e retornadas no mesmo formato dos arquivos JSON do bot.
  • Uma ação bem-sucedida retorna { "success": true, ... }.
  • Um erro retorna { "success": false, "error": "texto do erro" } com um código da tabela Códigos de resposta.
  • O bot é identificado pela conta e pelo nome da estratégia: /{accountName}/{settingsName}. Se a estratégia negocia vários pares, o parâmetro ?symbol= seleciona o par. Sem ele, usa-se o primeiro.

Configurações#

GET/api/settings/config#

A configuração global do programa (settings_program.json). O token do bot do Telegram é mascarado: os primeiros 4 caracteres ficam visíveis. O api_token é mascarado: os últimos 4 caracteres ficam visíveis.

200 Resposta
{
  "name": "MyBot",
  "use_web": true,
  "port": 5000,
  "api_token": "••••••••••••b9c2",
  "telegram": {
    "bot_token": "1234************",
    "id_chat": 123456789
  }
}
Erros
  • 503a configuração ainda não foi carregada
POST/api/settings/config#

Altera a configuração global e a aplica imediatamente. Envie apenas os campos que mudam — os demais permanecem como estão. O token do bot do Telegram, api_token e tester_data_dir não são alterados aqui: esses campos no corpo são ignorados.

Requisição
{ "name": "MyBot", "chart": { "count": 500 } }
200 Resposta
{ "success": true }
Erros
  • 400corpo vazio ou JSON inválido
  • 500falha ao salvar
POST/api/settings/api-token/regenerate#

Emite um novo api_token; o anterior deixa de funcionar imediatamente. É a única resposta da API em que o token aparece por inteiro. Não precisa de corpo.

200 Resposta
{ "success": true, "api_token": "<novo token>" }
Erros
  • 500falha ao salvar
GET/api/settings/hints/{kind}#

Descrições dos campos de configuração — as mesmas dicas que o editor de configurações mostra. {kind}:

  • settings — configurações de estratégias (bot e testador), para todas as estratégias de uma vez;
  • config_tester — a configuração do testador, incluindo parameter_mining, walk_forward e as colunas de reports_history.csv;
  • settings_program — a configuração global.

Parâmetros:

  • ?lang= — en (padrão), ru ou pt;
  • ?filter= — apenas campos cujo caminho contém uma das substrings separadas por vírgula, por exemplo ?filter=zigzag,close_by_margin.
200 Resposta
um objeto “caminho do campo com pontos → descrição”:
{
  "parameter_mining": "List of parameters to mine. Each has a name (parameter path) and either a start/end/step range or a values list...",
  "monte_carlo": "Mining limit: if there are more combinations than this number, a random sample of this size is used..."
}
Erros
  • 404{kind} desconhecido
GET/api/settings/schema#

Quais campos de configuração têm efeito de fato. ?strategy= — código da estratégia (basic.strategy); sem ele — um mapa de todas as estratégias.

200 Resposta ?strategy=zz, resumido
{
  "strategy": "zz", "type": "trend",
  "sections": ["zz"],
  "ignored_sections": ["hd", "zigzag", "mrs2", "..."],
  "position_filter": true, "supported_in_tester": true,
  "conditional_fields": [
    { "fields": ["zz.depth", "zz.detection", "zz.open", "..."], "active_when": "zz.type = ZZ2" },
    { "fields": ["zz.zz6_*"], "active_when": "zz.type = ZZ6" },
    { "fields": ["zz.ma_filter"], "active_when": "zz.use_ma_filter = true" },
    { "fields": ["basic.balance_percentage_long", "basic.risk_long"], "active_when": "basic.use_long = true and basic.lot_long = 0" }
  ],
  "notes": { "zz.zz6_risk_max": "ZZ6 only caps the lot multiplier ..." },
  "tester_ignores": { "basic.leverage": "the tester does not model leverage ..." },
  "shared_fields": ["zz.from_level_price"]
}
  • sections — seções que a estratégia lê; ela não lê as seções de ignored_sections. As seções comuns (basic, options, filter, exchange) não aparecem nas listas.
  • position_filter — a estratégia respeita filter; os campos filter.<nome>.* só têm efeito quando filter.<nome>.use = true.
  • conditional_fields — campos que só têm efeito sob uma condição. Um * no final significa todos os campos com esse início.
  • notes — campos que afetam o resultado apenas em casos extremos (minerá-los costuma gerar linhas idênticas).
  • tester_ignores — campos que o testador não modela.
  • shared_fields — campos da seção que outras estratégias também leem.

Um campo sem regra é considerado efetivo. As mesmas regras geram os warnings ao salvar configurações e ao iniciar o testador.

Erros
  • 404estratégia desconhecida

Estratégias#

GET/api/settings/strategy#

Todas as estratégias do bot.

200 Resposta
[
  {
    "name": "T4 BTC",
    "is_runing": true,
    "exchange": { "name": "binance", "account": "main" },
    "basic": { "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }
  }
]
GET/api/settings/strategy/{name}#

Uma estratégia pelo nome (sem diferenciar maiúsculas de minúsculas).

Erros
  • 404não encontrada
POST/api/settings/strategy/draft#

Rascunho de estratégia com valores padrão para a conta selecionada. Não salva nada: ajuste o resultado e envie para POST /api/settings/strategy.

Requisição
{ "account": "main", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h", "account_type": "UNIFIED" }

Em vez de symbol você pode enviar symbols: ["BTCUSDT", "ETHUSDT"] — uma estratégia em vários pares. time_frame (padrão 1h) e account_type são opcionais.

200 Resposta
um objeto de estratégia
Erros
  • 400estratégia ou par não informados
  • 404conta não encontrada
POST/api/settings/strategy#

Cria ou altera uma estratégia. O corpo é um objeto de estratégia, como em GET /api/settings/strategy/{name}. As alterações se aplicam aos bots em execução imediatamente, e uma estratégia nova inicia imediatamente.

?old_name= — renomear a estratégia old_name para o nome do corpo.

Requisição
POST /api/settings/strategy?old_name=T4%20BTC
200 Resposta
{ "success": true, "name": "T4 BTC v2", "created": false, "warnings": null }

created: true — a estratégia é nova. warnings — campos alterados que a estratégia não lê (veja /api/settings/schema); null — sem observações.

Erros
  • 400name, exchange.name, exchange.account ou basic.strategy vazios, ou o nome contém caracteres inválidos
  • 500falha ao salvar
POST/api/settings/strategy/{name}/copy#

Copia uma estratégia com um novo nome, salva e inicia a cópia.

Requisição
{ "new_name": "T4 ETH", "new_symbol": "ETHUSDT" }

new_symbol é opcional: sem ele, o par permanece o da estratégia de origem.

200 Resposta
{ "success": true, "name": "T4 ETH" }
Erros
  • 404estratégia de origem não encontrada
  • 409já existe uma estratégia com esse nome
POST/api/settings/strategy/from-tester#

Cria uma estratégia do bot a partir de uma configuração verificada do testador. A configuração é copiada como está; exchange.name e exchange.account vêm da conta. Por padrão a estratégia é criada pausada (is_runing: false): o bot a carrega, mas não negocia até que ela seja iniciada (play).

Requisição
{ "folder": "lut_now", "name": "T_BTC", "account": "demo_bybit", "new_name": "T_BTC live", "start": false }
  • folder — pasta de configurações do testador, veja Pasta de configurações na requisição;
  • new_name — nome da estratégia; sem ele — o mesmo da configuração;
  • start: true — iniciar a negociação imediatamente.
200 Resposta
{ "success": true, "name": "T_BTC live", "account": "demo_bybit", "exchange": "bybit", "is_runing": false, "warnings": null }

warnings — como ao salvar uma estratégia, mais um aviso se a configuração foi testada em uma corretora diferente da conta.

Erros
  • 404configuração do testador ou conta não encontradas
  • 409já existe uma estratégia com esse nome
  • 500falha ao salvar
POST/api/settings/strategy/{name}/delete#

Exclui uma estratégia e para seus bots. As ordens e a posição na corretora não são tocadas.

?full=1 — remoção completa: a estratégia é pausada, todas as suas ordens são canceladas, a posição é fechada e só então a estratégia é excluída. Se não for possível cancelar as ordens ou fechar a posição, a estratégia permanece pausada e não é excluída — a posição não ficará sem gerenciamento.

Como desligar uma estratégia corretamente. Em pausa, a posição e as ordens ficam na corretora sem o gerenciamento da estratégia (seus stops, take-profits e saídas), por isso não podem ser abandonadas. A ordem é:

  1. pausar;
  2. cancelar as ordens;
  3. fechar a posição;
  4. excluir a configuração.

?full=1 faz exatamente isso: após a pausa, aguarda o fim do ciclo atual do bot para que ele não coloque uma nova ordem. Manualmente — a mesma ordem, e a pausa não pode ser pulada: um bot em execução recoloca as ordens logo após o cancelamento.

Requisição
POST /api/settings/strategy/T4%20BTC/delete?full=1
200 Resposta
{ "success": true }
Erros
  • 404não encontrada
  • 409com full=1 a estratégia precisa estar em execução
  • 500falha ao cancelar as ordens, fechar a posição ou excluir a estratégia

Contas#

Uma conta é a chave de API da corretora em nome da qual as estratégias negociam.

GET/api/settings/accounts#

Todas as contas.

200 Resposta
[
  {
    "name": "main",
    "exchange": "binance",
    "api_key": "...",
    "api_secret": "...",
    "is_encrypted": true
  }
]
GET/api/settings/accounts/{name}#

Uma conta pelo nome (sem diferenciar maiúsculas de minúsculas).

Erros
  • 404não encontrado
GET/api/settings/accounts/{name}/symbols#

Pares disponíveis na corretora para esta conta.

200 Resposta
["BTCUSDT", "ETHUSDT"]
Erros
  • 404conta não encontrada
POST/api/settings/accounts#

Cria ou altera uma conta. As alterações se aplicam aos bots em execução imediatamente.

?old_name= — renomear a conta old_name para o nome do corpo.

As chaves são enviadas em texto puro. Com "is_encrypted": true o bot as guarda criptografadas. api_key, api_secret, api_passphrase vazios mantêm os valores atuais na alteração; ao mudar is_encrypted, a chave e o segredo precisam ser enviados novamente.

Requisição
{ "name": "main", "exchange": "binance", "api_key": "...", "api_secret": "...", "is_encrypted": true, "open_positions_limiter": 0 }
200 Resposta
{ "success": true, "name": "main", "applied": 3 }

applied — quantos bots em execução receberam a nova chave.

Erros
  • 400name ou exchange não informados, nome inválido ou chaves ausentes ao mudar is_encrypted
  • 500falha ao salvar
POST/api/settings/accounts/{name}/delete#

Exclui uma conta.

200 Resposta
{ "success": true }
Erros
  • 404não encontrado
  • 500falha ao excluir
GET/api/current/accounts/{name}/info#

Dados da conta e da chave vindos da corretora (atualizados a cada hora). É necessário pelo menos um bot em execução nesta conta.

200 Resposta
{
  "name": "main",
  "exchange": "binance",
  "api_key": "abc1****",
  "account_type": "UNIFIED",
  "symbol": "BTCUSDT",
  "ok": true,
  "status": "OK",
  "warnings": [],
  "rows": [ { "name": "Permissions", "value": "..." } ],
  "updated_utc": "2026-10-25T12:00:00Z"
}
Erros
  • 404conta não encontrada
  • 409não há bot em execução na conta
GET/api/current/accounts/{name}/balance-history#

Histórico de saldo da conta. ?max= — no máximo esta quantidade de pontos (padrão 5000).

200 Resposta
{
  "account": "main",
  "total": 12000,
  "points": [ { "time": 1761393600, "margin": 1234.5, "wallet": 1200.0, "positions": "..." } ]
}

time — tempo Unix em segundos, total — quantos pontos o histórico tem no total.

POST/api/current/accounts/{name}/balance-history/compact#

Compacta o histórico de saldo agora, usando as configurações de monitoring (normalmente isso acontece automaticamente).

200 Resposta
{ "success": true, "message": "...", "points_before": 12000, "points_after": 3000, "bytes_before": 512000, "bytes_after": 128000 }

Bots#

Um bot é uma estratégia em execução em um par específico.

GET/api/current/bots#

Resumo de todos os bots.

200 Resposta
[
  {
    "account": "main",
    "exchange": "binance",
    "strategy": "T4 BTC",
    "strategy_code": "zigzag",
    "symbol": "BTCUSDT",
    "time_frame": "1h",
    "is_runing": true,
    "is_live": true,
    "status_text": "...",
    "last_price": 65500.0,
    "last_bar_time": "2026-10-25T12:00:00",
    "last_sync_utc": "2026-10-25T12:00:05Z",
    "sync_missed_cycles": 0,
    "position": { "side": "Buy", "size": 0.01, "entry_price": 65000.0, "cost": 650.0, "unrealized_pnl": 5.0 },
    "orders": 2
  }
]

is_runing: false — o bot está pausado. position: null — sem posição. orders — número de ordens abertas. sync_missed_cycles — quantos ciclos seguidos falharam ao obter dados da corretora.

GET/api/current/balances#

Saldo da carteira e de margem de cada chave de API, separadamente para spot e futuros. ?account= — apenas esta conta.

Requisição
GET /api/current/balances?account=main
200 Resposta
[
  { "account": "main", "exchange": "bybit", "type": "futures", "wallet": 1234.56, "margin": 1180.20 },
  { "account": "main", "exchange": "bybit", "type": "spot", "wallet": 500.00, "margin": 500.00 }
]

wallet — saldo da carteira, margin — saldo de margem, como a corretora os retorna. Para spot, ambos os valores são o saldo em USDT. O saldo vem dos bots em execução: uma conta sem bot em execução não aparece na lista.

GET/api/current/bots/{accountName}/{settingsName}/bars#

Candles do bot. ?limit= — os últimos N candles (padrão 500).

Requisição
GET /api/current/bots/main/T4%20BTC/bars?limit=100
200 Resposta
um array de candles com os campos Timestamp, Open, High, Low, Close, Volume e outros.
Erros
  • 404bot não encontrado
GET/api/current/ubots#

Um retrato completo do estado de todos os bots. O conjunto de campos é detalhado e pode mudar entre versões — para uma integração permanente use GET /api/current/bots, /api/current/positions e /api/current/orders.

GET/api/current/ubots/{accountName}/{settingsName}#

Um retrato completo do estado de um bot (veja a ressalva acima).

Erros
  • 404bot não encontrado
POST/api/bots/pause-all#

Pausa todos os bots.

200 Resposta
{ "success": true, "count": 5 }
POST/api/bots/play-all#

Inicia todos os bots.

200 Resposta
{ "success": true, "count": 5 }
POST/api/bots/{accountName}/{settingsName}/pause#

Pausa uma estratégia (para uma estratégia em vários pares — todos os seus pares): ela para de colocar ordens. A posição aberta e as ordens ficam na corretora sem o gerenciamento da estratégia — depois da pausa, inicie-a novamente ou cancele as ordens e feche a posição (veja exclusão).

Requisição
POST /api/bots/main/T4%20BTC/pause
200 Resposta
{ "success": true, "name": "T4 BTC", "is_runing": false }
Erros
  • 404não encontrada
  • 500falha ao salvar
POST/api/bots/{accountName}/{settingsName}/play#

Inicia uma estratégia pausada.

200 Resposta
{ "success": true, "name": "T4 BTC", "is_runing": true }
Erros
  • 404não encontrada
  • 500falha ao salvar
POST/api/bots/{accountName}/{settingsName}/send-chart#

Envia o gráfico do bot para o Telegram.

200 Resposta
{ "success": true }
Erros
  • 404bot não encontrado
  • 500falha ao gerar ou enviar o gráfico
POST/api/bots/{accountName}/{settingsName}/send-position#

Envia um resumo do bot para o Telegram: saldo, posição, PnL, ordens.

200 Resposta
{ "success": true }
Erros
  • 404bot não encontrado
POST/api/delete/{accountName}/{settingsName}#

Exclui a estratégia do bot e o retira de operação. As ordens e a posição na corretora não são removidas e ficam sem gerenciamento. Para um desligamento seguro use POST /api/settings/strategy/{name}/delete?full=1.

Requisição
POST /api/delete/main/T4%20BTC
200 Resposta
{ "success": true }
Erros
  • 404bot não encontrado
  • 500falha ao excluir

Posições e ordens#

GET/api/current/positions#

Posições de todos os bots.

200 Resposta
[
  {
    "account": "main",
    "exchange": "binance",
    "strategy": "T4 BTC",
    "symbol": "BTCUSDT",
    "position": {
      "Symbol": "BTCUSDT",
      "Side": "Buy",
      "Size": 0.01,
      "EntryPrice": 65000.0,
      "Cost": 650.0,
      "UnrealizedPnl": 12.5,
      "Leverage": 10,
      "Cross": false
    }
  },
  {
    "account": "sub1",
    "exchange": "binance",
    "strategy": "T3 ETH",
    "symbol": "ETHUSDT",
    "position": null
  }
]
GET/api/current/orders#

Ordens abertas de todos os bots.

200 Resposta
[
  {
    "account": "main",
    "exchange": "binance",
    "strategy": "T4 BTC",
    "symbol": "BTCUSDT",
    "order": {
      "Id": "order-123",
      "client_id": "cl-456",
      "Market": "BTCUSDT",
      "Side": "Buy",
      "Type": "Limit",
      "Status": "New",
      "Size": 0.01,
      "filledSize": 0.0,
      "remainingSize": 0.01,
      "Price": 64000.0,
      "TriggerPrice": null,
      "ReduceOnly": false
    }
  }
]
POST/api/trading/market#

Uma ordem a mercado na conta. O par precisa ser negociado por um dos bots desta conta.

Requisição
{ "account": "main", "symbol": "BTCUSDT", "side": "Buy", "size": 0.01 }

side — Buy ou Sell; size — volume nas unidades da corretora para este par.

200 Resposta
{ "success": true, "order_id": "order-123" }
Erros
  • 400side ou size inválidos
  • 404a conta não tem bot com este par
  • 500a corretora rejeitou a ordem
POST/api/positions/{accountName}/{settingsName}/close#

Fecha a posição do bot.

Requisição
POST /api/positions/main/T4%20BTC/close
200 Resposta
{ "success": true }
Erros
  • 404bot não encontrado
POST/api/positions/{accountName}/close-all#

Fecha todas as posições abertas da conta.

200 Resposta
{ "success": true, "count": 3 }

count — quantas posições foram enviadas para fechamento.

POST/api/positions/{accountName}/reduce#

Reduz todas as posições abertas da conta pela porcentagem indicada.

Requisição
{ "percent": 50 }

percent — de 1 a 100.

200 Resposta
{ "success": true, "count": 3 }
POST/api/orders/{accountName}/{settingsName}/{orderId}/cancel#

Cancela uma ordem do bot (normal ou stop).

Requisição
POST /api/orders/main/T4%20BTC/order-123/cancel
200 Resposta
{ "success": true }
Erros
  • 404ordem não encontrada
  • 500a corretora não cancelou a ordem
POST/api/orders/{accountName}/cancel-all#

Cancela todas as ordens da conta.

200 Resposta
{ "success": true, "count": 2 }

count — em quantos bots as ordens foram canceladas.

POST/api/orders/cancel-all#

Cancela todas as ordens em todas as contas.

200 Resposta
{ "success": true, "count": 7 }

Sistema e logs#

GET/api/system/status#

Versão do programa, recursos do servidor e contadores. Os campos pid, exe_path, working_directory, port (a porta em que a requisição chegou) e started_utc identificam de forma única a instância do processo: com eles, um script externo distingue vários bots em execução e percebe um reinício (pid e started_utc mudam).

200 Resposta
{
  "program": "hamster-bot",
  "version": "2026/10/23",
  "name": "MyBot",
  "type": "bot",
  "os": "Linux 6.1",
  "architecture": "X64",
  "machine": "srv1",
  "runtime": ".NET 10.0",
  "processors": 4,
  "pid": 12345,
  "exe_path": "/opt/hamster-bot/hb_c",
  "working_directory": "/opt/hamster-bot",
  "port": 80,
  "started_utc": "2026-10-24T08:00:00Z",
  "uptime_sec": 86400,
  "cpu_percent": 12.5,
  "memory_total_bytes": 8589934592,
  "memory_available_bytes": 4294967296,
  "process_memory_bytes": 314572800,
  "disk": "/",
  "disk_total_bytes": 107374182400,
  "disk_free_bytes": 53687091200,
  "accounts": 2,
  "strategies": 5,
  "bots": 6,
  "bots_running": 5,
  "auto_update_supported": true
}
POST/api/system/shutdown#

Encerra o programa. Disponível apenas com login pelo Telegram. O programa não inicia sozinho: quem reinicia o processo é um supervisor externo (serviço, systemd, script). Para verificar se o supervisor traz o bot de volta 61 segundos após a parada (RestartSec=61, run_service.cmd), use o script tools/check-shutdown-restart.ps1 (ele para o bot em execução). Não existe a ferramenta restart_program. Em geral ela nem é necessária: alterações de estratégias, contas e configurações pela API se aplicam imediatamente aos bots em execução. Atualização com reinício — POST /api/system/update. Após o reinício, confirme por pid e started_utc de /api/system/status que um novo processo subiu. Antes de parar, verifique se não há execução do testador: ela será interrompida, e a fila não é salva.

200 Resposta
{ "success": true } — o programa encerra em meio segundo
Erros
  • 409o login pelo Telegram não está configurado
POST/api/system/update#

Inicia a atualização do programa.

200 Resposta
{ "success": true }
Erros
  • 409a atualização automática não é suportada neste sistema (veja auto_update_supported em /api/system/status)
  • 500a atualização não iniciou
GET/api/logs#

As últimas linhas do log geral. ?tail= — quantas últimas linhas (padrão: todas as disponíveis).

200 Resposta
um array de strings
GET/api/logs/errors#

Erros das últimas ?hours= horas (padrão 24, no máximo 48). ?warnings=1 — junto com os avisos. Se o Telegram não estiver configurado (telegram.id_chat = 0), as mensagens não são enviadas e não há erros “chat not found”: o log recebe o aviso Telegram chat is not set uma vez por execução. Um erro “chat not found” com chat definido significa id de chat ou token incorretos. As repetições já vêm agrupadas: mensagens idênticas de uma mesma origem são unidas em um registro, count — quantas vezes se repetiu em toda a janela guardada (até 48 horas, desde o início do programa), first_utc e last_utc — a primeira e a última ocorrência. Os registros vão dos mais novos para os mais antigos.

?since= — horário UTC (por exemplo 2026-11-02T06:00:00Z; sem fuso horário, é considerado UTC): retornam apenas registros que se repetiram depois dele. Para ver “o que há de novo desde a última vez”, passe o last_utc mais recente da resposta anterior. Se o first_utc de um registro for anterior a since, é um erro antigo que voltou a ocorrer, e count continua sendo o total. Data inválida — 400.

200 Resposta
[
  {
    "level": "Error",
    "first_utc": "2026-10-25T08:00:00Z",
    "last_utc": "2026-10-25T12:00:00Z",
    "count": 3,
    "source": "T4 BTC",
    "message": "...",
    "exception": "..."
  }
]
GET/api/logs/files#

Arquivos de log, os mais novos primeiro; cada dia é um novo arquivo. ?contains= — apenas arquivos cujo nome contém o texto (nome da estratégia, conta, par).

Tipos de log:

  • log da estratégia — log_<data>_<Corretora> <conta> <par> <timeframe> <estratégia> <nome>.log, um por bot: sinais, ordens, preenchimentos, posição, erros da estratégia;
  • log da conta — log_<conta>_<data>.log: saldos e posições da corretora, respostas e erros da API da corretora, limitador de posições, close_by_margin;
  • log geral do programa — log_<data>.log (/api/logs);
  • logs do testador — TESTER_*.log.

O formato da data nos nomes varia, por isso é mais fácil encontrar o arquivo com contains.

200 Resposta
[ { "name": "log_25-10-2026.log", "size": 102400, "modified_utc": "2026-10-25T12:00:00Z" } ]
GET/api/logs/files/{filename}#

Conteúdo do arquivo de log como texto. ?download=1 — baixar como arquivo.

Erros
  • 400nome de arquivo inválido
  • 404arquivo não encontrado

Testador#

O testador executa estratégias com dados históricos. Mineração de parâmetros, testes de estresse e repetições por snapshot rodam um de cada vez. Execuções individuais podem rodar em paralelo. Enquanto os dados históricos são baixados o testador não inicia, e vice-versa — nesses casos a resposta é 409.

Todas as execuções rodam em segundo plano: a resposta vem imediatamente; o andamento e o resultado ficam em GET /api/tester/status.

GET/api/tester/status#

Estado do testador.

200 Resposta
{
  "run": {
    "active": true,
    "status": "Running",
    "started_utc": "2026-10-25T12:00:00Z",
    "finished_utc": null,
    "message": "API mining run",
    "runs_done": 40,
    "runs_total": 120,
    "current_bar": 5000,
    "total_bars": 20000,
    "parallel": false,
    "report_folders": ["T4"],
    "result_files": ["T4/reports_history.csv", "T4/report_optimizer_T4_auto_x_auto_y_20261025_120000.html", "T4/run_snapshot_T4_20261025_115500.json"]
  },
  "wizard_runs": [
    {
      "run_id": "a1b2c3d4",
      "strategies": ["T4 BTC"],
      "status": "Completed",
      "started_utc": "2026-10-25T11:00:00Z",
      "finished_utc": "2026-10-25T11:02:00Z",
      "current_bar": 20000,
      "total_bars": 20000,
      "message": "Completed: 1 strategies.",
      "report_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
      "report_json_path": null,
      "snapshot_path": "T4/run_snapshot_T4_20261025_110000.json",
      "stats": null,
      "warnings": []
    }
  ],
  "download": { "active": false, "status": "Idle", "started_utc": null, "finished_utc": null, "message": "", "result": null },
  "settings_folder": ""
}
  • run — mineração de parâmetros, teste de estresse ou repetição por snapshot. status: Idle, Running, Completed ou Failed; runs_done / runs_total — quantas combinações de parâmetros foram calculadas. report_folders — pastas de resultados da execução atual ou da última dentro de root=report; result_files — arquivos finais já gravados nelas desde o início da execução: reports_history.csv, o HTML consolidado (report_optimizer_*, stress_test_*, walk_forward_*) e o snapshot.
  • queue — execuções em modo completo aguardando sua vez (?queue=1): queue_id, position, message, queued_utc.
  • wizard_runs — execuções individuais. As concluídas ficam visíveis por mais uma hora. As métricas (stats) não vêm aqui — estão em /api/tester/wizard-runs/{run_id}. Execuções de lote ainda não iniciadas têm status: "Queued".
  • batches — lotes de execuções individuais: batch_id, done de total.
  • download — download de dados históricos.
  • settings_folder — a pasta atual de configurações do testador.
GET/api/tester/config#

A configuração do testador (config_tester.json): período, taxas, parâmetros de mineração etc.

POST/api/tester/config#

Salva a configuração do testador. O corpo é a configuração inteira, como em GET /api/tester/config.

200 Resposta
{ "success": true }
Erros
  • 400corpo vazio ou JSON inválido
  • 500falha ao salvar
GET/api/tester/data-coverage#

Quais dados históricos já foram baixados: ?exchange= (obrigatório), ?symbols=A,B (sem ele — todos os pares baixados da corretora), ?start=&end= — o período a verificar.

200 Resposta
[
  {
    "symbol": "ADAUSDT", "downloaded": true, "first_day": "2026-04-09", "last_day": "2026-09-15",
    "days": 67, "gap_days": 93, "size_mb": 1.78,
    "period": { "covered": false, "missing_days": 132, "missing_first": ["2026-03-01", "2026-03-02", "2026-03-03"], "missing_last": "2026-08-30" }
  },
  { "symbol": "NOPEUSDT", "downloaded": false }
]

gap_days — dias sem dados entre o primeiro e o último. period só existe com start e end. Contam apenas os arquivos baixados: o que falta é baixado pela própria execução (UpdateData) ou por download-data.

Erros
  • 400a corretora não é suportada ou apenas um de start / end foi definido
GET/api/tester/exchanges#

Corretoras para as quais o testador consegue baixar dados históricos.

200 Resposta
["bybit", "binance", ...]
GET/api/tester/exchanges/{exchange}/symbols#

Pares da corretora. Uma lista vazia significa que a corretora está indisponível no momento; o par pode ser informado manualmente.

Erros
  • 404o testador não suporta esta corretora

Pasta de configurações na requisição#

Todas as requisições às configurações do testador, execuções e downloads de dados aceitam uma pasta de configurações: ?folder= no endereço ou o campo folder no corpo da execução. É um caminho dentro de tester/settings_strategy, "" é a pasta principal. Sem folder, usa-se a pasta selecionada na interface (POST /api/tester/settings-folder). Esse é um estado compartilhado: um usuário ou uma tarefa paralela pode alterá-lo, por isso scripts e assistentes devem sempre passar folder.

Uma pasta inexistente gera o erro 404. Para criar uma pasta — POST /api/tester/settings-folders.

As configurações podem ter os campos opcionais tags (lista de etiquetas) e owner (autor, por exemplo "MCP"). Eles servem para filtrar configurações na lista e excluí-las em massa.

GET/api/tester/settings#

Configurações de estratégias do testador na pasta. Parâmetros:

  • ?folder= — a pasta;
  • ?mask= — apenas nomes pela máscara (* — quaisquer caracteres, ? — um caractere);
  • ?tag=, ?owner= — apenas com esta etiqueta ou este autor;
  • ?full=1 — configurações inteiras em vez da forma resumida: uma exportação da pasta que /api/tester/settings/import restaura.
200 Resposta
[ { "name": "T4 BTC", "exchange": "bybit", "symbol": "BTCUSDT", "symbols": null, "strategy": "zigzag", "time_frame": "1h", "tags": ["tmp"], "owner": "MCP" } ]
GET/api/tester/settings/{name}#

A configuração inteira do testador. ?folder= — a pasta.

Erros
  • 404não encontrada
POST/api/tester/settings/draft#

Rascunho de configuração do testador com valores padrão. Não salva nada.

Requisição
{ "exchange": "bybit", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }

Em vez de symbol você pode enviar symbols — vários pares. account_type é opcional.

200 Resposta
um objeto de configuração
Erros
  • 400o testador não suporta a corretora, ou estratégia ou par não informados
POST/api/tester/settings#

Salva uma configuração do testador. O corpo é um objeto de configuração. ?old_name= — renomear a configuração old_name. Uma configuração existente com o mesmo nome não é sobrescrita. ?folder= — a pasta. ?owner_default= — o valor de owner se a configuração não tiver um (o MCP passa MCP).

200 Resposta
{ "success": true, "name": "T4 BTC", "folder": "", "warnings": null }

warnings — campos alterados (diferentes do padrão) que não têm efeito: seção de outra estratégia (uma linha por seção), campo de outro zz.type, chave use_* desativada, basic.leverage (o testador não modela alavancagem) — veja /api/settings/schema. null — sem observações. Os avisos não cancelam o salvamento.

O mesmo campo warnings está na resposta da cópia de configuração, e a importação tem warnings pelo nome de cada configuração.

Erros
  • 400campos obrigatórios vazios
  • 409já existe uma configuração com esse nome
  • 500falha ao salvar
POST/api/tester/settings/{name}/copy#

Copia uma configuração do testador na mesma pasta (?folder=), opcionalmente para outra corretora ou par. ?owner_default= — como ao salvar. Para copiar para outra pasta — copy-to-folder.

Requisição
{ "new_name": "T4 BTC binance", "new_exchange": "binance", "new_symbol": "" }

new_exchange e new_symbol vazios mantêm os valores da configuração de origem.

200 Resposta
{ "success": true, "name": "T4 BTC binance" }
Erros
  • 404configuração de origem não encontrada
  • 409o nome já está em uso
POST/api/tester/settings/{name}/delete#

Exclui uma configuração do testador. ?folder= — a pasta. Para excluir muitas configurações de uma vez — delete-matching.

200 Resposta
{ "success": true }
Erros
  • 404não encontrada
GET/api/tester/settings-folder#

A pasta atual de configurações do testador e suas subpastas. As pastas permitem manter vários conjuntos de configurações; "" é a pasta principal.

200 Resposta
{ "path": "", "folders": [ { "name": "2026-10", "settings": 12 } ] }

settings — quantas configurações a pasta tem.

POST/api/tester/settings-folder#

Seleciona a pasta de configurações do testador para a interface e para requisições sem folder.

Requisição
{ "path": "2026-10" }
200 Resposta
{ "success": true, "path": "2026-10" }
Erros
  • 404pasta não encontrada
POST/api/tester/settings-folders#

Cria uma pasta de configurações, inclusive aninhadas. Não muda a pasta selecionada.

Requisição
{ "path": "research/zz_hedge" }
200 Resposta
{ "success": true, "path": "research/zz_hedge", "created": true }

created: false — a pasta já existia.

Erros
  • 400caminho vazio, .. ou caracteres inválidos no nome
POST/api/tester/settings-folders/delete#

Exclui uma pasta de configurações com todo o conteúdo. A pasta principal não pode ser excluída. Se a pasta selecionada for excluída, a principal passa a ser a selecionada.

Requisição
{ "path": "research/zz_hedge" }
200 Resposta
{ "success": true, "deleted_settings": 12 }
Erros
  • 404pasta não encontrada ou é a pasta principal
POST/api/tester/settings/copy-to-folder#

Copia configurações de uma pasta para outra.

Requisição
{ "from": "mrs-bybit", "to": "lut_now", "names": ["C_MU", "T_*"], "on_conflict": "replace" }

Quais configurações copiar — names (nomes ou máscaras), mask ("*" — todas), tag, owner; os filtros se combinam, é preciso pelo menos um. on_conflict — o que fazer se o nome já existir na pasta de destino: skip (padrão), replace ou error (não copiar nada).

200 Resposta
{ "success": true, "copied": ["C_MU"], "replaced": ["T_BTC"], "skipped": [] }
Erros
  • 400sem filtro, nome sem máscara não encontrado, as pastas são iguais ou conflito com on_conflict: "error"
  • 404pasta não encontrada
POST/api/tester/settings/delete-matching#

Exclui configurações da pasta por um filtro.

Requisição
{ "folder": "lut_now", "owner": "MCP", "tag": "tmp" }

Filtros — como em copy-to-folder, é preciso pelo menos um.

200 Resposta
{ "success": true, "folder": "lut_now", "deleted": ["MCP_LZ1"], "not_found": [] }
Erros
  • 400sem filtro
  • 404pasta não encontrada
POST/api/tester/settings/import#

Salva um conjunto de configurações em uma pasta, por exemplo uma exportação de GET /api/tester/settings?full=1.

Requisição
{ "folder": "lut_now", "settings": [ { ... }, { ... } ], "on_conflict": "skip", "owner_default": "MCP" }
200 Resposta
{ "success": true, "folder": "lut_now", "saved": ["T_BTC"], "skipped": [], "warnings": { "T_BTC": ["..."] } }
Erros
  • 400configuração inválida ou conflito com on_conflict: "error"
  • 404pasta não encontrada
GET/api/tester/settings-check#

Verifica as configurações da pasta sem executar — as mesmas observações de warnings ao salvar. ?folder= — a pasta, ?mask= — um nome ou máscara (padrão: todas).

200 Resposta
{
  "folder": "lut_now", "total": 125, "with_warnings": 2,
  "settings": [
    { "name": "T_BTW", "strategy": "zz", "warnings": [
      "zz.zz6_len = 8 is ignored: only when zz.type = ZZ6 (now: zz.type = \"ZZ2\")"
    ] }
  ]
}

Em settings — apenas configurações com observações.

Erros
  • 404pasta não encontrada
POST/api/tester/run#

Mineração de parâmetros de estratégias (seção parameter_mining da configuração do testador).

Requisição
{
  "settings": ["*"],
  "folder": "lut_now",
  "config": { ... },
  "overrides": [
    { "match": "T_*", "mul": { "basic.balance_percentage_long": 2 } },
    { "match": "C_MU", "set": { "basic.use_short": false } },
    { "match": "L_X", "exclude": true }
  ]
}
  • settings — nomes de configurações ou máscaras ("*" — todas as configurações da pasta). Um nome sem máscara que não esteja na pasta é um erro.
  • folder — pasta de configurações, veja Pasta de configurações na requisição.
  • config é opcional: sem ele, usa-se a configuração salva do testador.
  • overrides — ajustes de configurações apenas para esta execução; os arquivos de configurações não mudam. As regras se aplicam em ordem. match — um nome ou máscara (padrão: todas), tag — apenas configurações com esta tag. set substitui valores, mul multiplica números (um campo inteiro continua inteiro), cap_pct depois deles limita basic.balance_percentage_long e _short dessas configurações — um multiplicador de tamanho com teto por par: { "match": "T_*", "mul": { "basic.balance_percentage_long": 2, "basic.balance_percentage_short": 2 }, "cap_pct": 10 }. exclude: true retira configurações da execução. Os campos são caminhos com pontos, como no objeto de configuração. Se o campo não existir em nenhuma configuração correspondente, é um erro (geralmente de digitação); se faltar apenas em parte delas, essas configurações são listadas em not_applied. Os ajustes são gravados no comment da execução e vão para o relatório e o snapshot.
200 Resposta
{
  "success": true,
  "folder": "lut_now",
  "strategies": ["C_MU", "T_BTC"],
  "applied": [ { "name": "T_BTC", "changes": ["basic.balance_percentage_long: 10.0 → 20.0"], "not_applied": [] } ],
  "excluded": ["L_X"]
}

O que pode ser minerado. Qualquer configuração do bot (settings[*].zz.depth, settings[T_*].basic.use_short, settings[NAME].…), qualquer campo da configuração do testador (config_tester.…), settings_program.… e a conta. Para números bastam start/end/step, para os demais (texto, booleanos) defina values.

Triagem de pares. Não é preciso um arquivo de configuração por par: pegue uma configuração-modelo e minere o símbolo como um parâmetro comum. A lista de pares vem de tester_exchange_symbols:

"parameter_mining": [
  {
    "name": "settings[*].basic.symbol",
    "start": 1.0, "end": 1.0, "step": 1.0,
    "values": ["1000BONKUSDT", "1000PEPEUSDT", "AAVEUSDT", "ADAUSDT"]
  }
]

Junto com outros parâmetros (por exemplo, settings[*].zz.depth) isso gera uma grade por par. O símbolo vai para uma coluna de reports_history.csv, então o resumo “par → mediana da grade” é calculado a partir desse arquivo (read_tester_file com columns). tester_download_data baixa os dados de todos os pares minerados. O número de combinações é o produto dos tamanhos das listas de valores: limite-o com monte_carlo.

O testador executa todas as combinações de valores de parameter_mining; se monte_carlo estiver definido, uma amostra aleatória desse tamanho. Verifique o número de combinações com antecedência; para parar uma mineração em andamento — POST /api/tester/stop com full: true. O andamento está em run da resposta de GET /api/tester/status (runs_done de runs_total).

Os resultados vão para uma pasta em report com o nome igual ao name_comment da configuração do testador (caracteres inválidos em nomes de arquivo são trocados por _). A resposta da execução a retorna em report_folders; com walk_forward ativado há também uma segunda pasta <name_comment>_WF_OOS com execuções fora da amostra. Para não misturar experimentos, dê a cada um seu próprio name_comment. Na pasta:

  • reports_history.csv — uma linha por combinação: métricas (TotalPnLPercent, MaxDrawdownPercent, ProfitFactor, WinRate, TradingVolume, …), Strategies (nomes das configurações da execução separados por |), RunTag e uma coluna com o valor de cada parâmetro minerado. Com single_mode, cada linha tem uma configuração, e os blocos de combinações seguem o nome da configuração;
  • um relatório HTML de cada combinação (se report.enable_html_report estiver ativado) e sua versão JSON (se report.enable_json_report estiver ativado); o RunTag da combinação está no nome do arquivo;
  • o relatório consolidado do otimizador report_optimizer_*.html;
  • run_snapshot_<name_comment>_<horário>.json — as configurações exatas e a configuração da execução, veja snapshot-run.

periods — mineração em vários períodos: [["2026-02-01","2026-05-01"], ["2026-05-01","2026-08-01"]]. Cada período é uma execução completa separada na pasta <name_comment>_<início>_<fim>; elas seguem uma após a outra pela fila. A resposta é { "success": true, "periods": [ { "start", "end", "report_folders", "queued", "queue_id", "position" } ], ... }. Para comparar períodos — /api/tester/mining-robustness.

Avisos da execução. A resposta da execução contém warnings (null — sem observações):

  • um parâmetro de parameter_mining que não está nas configurações nem nos arquivos de configuração (erro de digitação: não será aplicado);
  • um campo minerado que as configurações correspondentes não leem (ignored by all N matching settings: todas as combinações darão o mesmo resultado) ou que nem todas leem; condições sobre campos que também são minerados não são verificadas;
  • uma nota sobre um campo que só influencia em casos extremos (zz.zz6_risk_max);
  • um campo de overrides que a configuração não lê.

Os avisos não cancelam a execução.

Execuções individuais e lotes também gravam esses avisos nos resultados da execução (warnings de wizard-runs/{run_id}), e o lote também no warnings geral com o prefixo runs[i] <nome>. A execução por snapshot é verificada da mesma forma.

Mineração de portfólio. Sem single_mode, todas as configurações seguem juntas em cada combinação. Um parâmetro chamado settings[NOME].caminho muda uma configuração, e settings[T_*].caminho muda todas as configurações pela máscara do nome; o restante do conjunto fica como está. Compare as linhas pelo MaxDrawdownPercent e UlcerIndex do portfólio (ative reports_history.ulcer_index).

sides — lados de negociação nesta execução: long (apenas long), short (apenas short), split (cada configuração duas vezes — <nome> [long] e <nome> [short]; com single_mode os lados são minerados separadamente) ou both (como nas configurações).

?queue=1 — se o testador estiver ocupado com outra execução completa ou um download de dados, a execução entra na fila em vez de receber 409. A resposta então é { "success": true, "queued": true, "queue_id": "63a8e791", "position": 1, ... }; a execução inicia sozinha, a fila aparece em queue da resposta de GET /api/tester/status, e para cancelar uma ainda não iniciada — POST /api/tester/queue/{queue_id}/cancel.

Erros
  • 400configuração não encontrada, config, overrides ou sides inválidos
  • 404pasta não encontrada
  • 409o testador já está rodando ou os dados estão sendo baixados (sem ?queue=1)
POST/api/tester/stress#

Teste de estresse: as mesmas configurações em condições de execução piores. O corpo, ?queue=1 e as respostas são como em /api/tester/run, exceto periods (não suportado). Os resultados ficam na pasta <name_comment>_STRESS (report_folders da resposta): linhas de cenários em reports_history.csv e a comparação com a base em stress_test_*.html.

POST/api/tester/queue/{queue_id}/cancel#

Retira da fila uma execução completa que ainda não começou.

200 Resposta
{ "success": true }
Erros
  • 404a execução já começou, foi cancelada ou queue_id é inválido
POST/api/tester/wizard-run#

Uma execução individual de estratégias. O corpo é como em /api/tester/run, incluindo folder e overrides.

200 Resposta
{ "success": true, "run_id": "a1b2c3d4", "folder": "lut_now", "strategies": ["T4 BTC"], "applied": [], "excluded": [] }

Para aguardar a execução e obter suas métricas e caminhos dos relatórios — GET /api/tester/wizard-runs/{run_id}?wait=. O andamento de todas as execuções está em wizard_runs da resposta de GET /api/tester/status.

Erros
  • 400nenhuma das configurações foi encontrada
  • 409os dados estão sendo baixados
POST/api/tester/wizard-batch#

Um lote de execuções individuais: vários conjuntos, cada um em vários períodos, por uma fila com paralelismo limitado. É assim que se comparam variantes e se verifica uma variante em vários períodos com uma única requisição.

Requisição
{
  "folder": "lut_now",
  "config": { ... },
  "periods": [["2026-02-01", "2026-05-01"], ["2026-05-01", "2026-08-01"]],
  "parallel": 2,
  "runs": [
    { "name": "base", "settings": ["*"] },
    { "name": "T x2", "settings": ["*"], "overrides": [ { "match": "T_*", "mul": { "basic.balance_percentage_long": 2 } } ] },
    { "name": "long only", "settings": ["*"], "sides": "long" }
  ]
}

Campos do conjunto — como no corpo de /api/tester/run (settings, folder, config, overrides, sides) mais name e seus próprios periods. O que falta no conjunto vem do lote. Cada conjunto roda em cada período como uma execução separada; sem periods — no período da configuração. parallel — quantas execuções ao mesmo tempo (padrão 2; cada uma mantém seus dados na memória). Um erro em qualquer conjunto rejeita o lote inteiro.

200 Resposta
o mesmo que GET /api/tester/wizard-batches/{batch_id}, logo após entrar na fila.
Erros
  • 400runs vazio, periods inválidos ou erro de conjunto (runs[1]: ...)
  • 404pasta não encontrada
  • 409os dados estão sendo baixados
GET/api/tester/wizard-batches/{batch_id}#

O lote e os resultados de cada execução. ?wait= — quantos segundos (até 240) aguardar o fim do lote inteiro.

Um lote longo (dezenas de execuções) não cabe na resposta em forma completa (o MCP o corta em 200.000 caracteres e o JSON fica inválido), por isso existem a forma compacta e as páginas. Os mesmos parâmetros valem para POST /api/tester/wizard-batch:

ParâmetroDescrição
compact=1cada execução tem apenas name, start, end, run_id, status, run_params, key e os caminhos do relatório (message só nas que falharam). Sem summary, stats, warnings, applied
offset, limituma página da lista runs; limit=0 — apenas contadores. A resposta tem offset, returned e has_more (há próxima página: offset + returned). done, total, failed sempre cobrem o lote inteiro

Se a resposta completa tiver mais de 150.000 caracteres, é substituída pela compacta automaticamente (compact: true na resposta); as páginas offset/limit são mantidas.

key está em toda execução, inclusive na resposta completa: as principais métricas em uma única forma, do summary do relatório JSON ou, se não houver relatório, dos stats finais: pnl, pnl_percent, max_drawdown_percent, max_drawdown_worst_percent (apenas com relatório JSON), trades, volume, fees, profit_factor (apenas com relatório JSON). Não é preciso chamar reports/json em cada execução para obtê-las.

200 Resposta
{
  "batch_id": "31dd7d67", "status": "Completed", "done": 2, "total": 2, "failed": 0, "parallel": 2,
  "started_utc": "2026-10-27T21:31:27Z",
  "compact": false, "offset": 0, "returned": 2, "has_more": false,
  "runs": [
    {
      "name": "T x2", "start": "2026-02-01", "end": "2026-05-01", "run_id": "a99984a8", "status": "Completed",
      "message": "Completed: 12 strategies.",
      "key": { "pnl": 1240.5, "pnl_percent": 12.4, "max_drawdown_percent": 5.2, "max_drawdown_worst_percent": 8.1, "trades": 140, "volume": 520000.0, "fees": 310.2, "profit_factor": 1.6 },
      "summary": { "pnl_percent": 12.4, "max_drawdown_worst_percent": 8.1, "ulcer_index": 2.3, "profit_factor": 1.6, "trades": 140, "monthly": { "2026-02": 3.1 } },
      "stats": null,
      "report_path": "...html", "report_json_path": "...json", "snapshot_path": "...json",
      "warnings": [],
      "applied": [ { "name": "T_BTC", "changes": ["basic.balance_percentage_long: 10.0 → 20.0"], "not_applied": [] } ],
      "excluded": null
    }
  ]
}

summary — como a seção summary do relatório JSON; existe se report.enable_json_report estiver ativado, caso contrário há stats no lugar. As linhas das execuções do lote também vão para reports_history.csv da pasta name_comment (colunas StartDate, EndDate, Strategies). Os lotes ficam guardados por uma hora.

Erros
  • 404lote inexistente: batch_id inválido, passou mais de uma hora ou o programa reiniciou
POST/api/tester/stop#

Para execuções do testador.

Requisição é preciso pelo menos um campo
{ "run_id": "a1b2c3d4", "batch_id": "5e6f7a8b", "full": true, "clear_queue": true }
  • run_id — uma execução individual (wizard-run);
  • batch_id — todas as execuções do lote: as não iniciadas não começam;
  • full: true — a execução completa atual: mineração, teste de estresse, walk-forward, snapshot;
  • clear_queue: true — também retira da fila as execuções completas não iniciadas.

Uma execução em andamento para no próximo candle. Uma execução interrompida não grava relatório nem linha em reports_history: um resultado de parte do período seria enganoso. Uma execução completa mantém as linhas das combinações já calculadas; no modo paralelo os processos filhos terminam. Status: execução completa — Stopped em run da resposta de /api/tester/status, execução individual — Cancelled em wizard-runs/{run_id}. Esta requisição não para o download de dados históricos.

200 Resposta
{ "success": true, "cancelled_runs": ["a1b2c3d4"], "full_run_stopping": true, "cleared_queue": ["63a8e791"], "note": "Stopping: ..." }
Erros
  • 400nenhum campo enviado
  • 404execução ou lote não encontrados
GET/api/tester/wizard-runs/{run_id}#

Uma execução individual por run_id. ?wait= — quantos segundos (até 240) aguardar o término; sem ele a resposta é imediata.

200 Resposta
{
  "run_id": "a82c93c5",
  "strategies": ["T4 BTC", "T4 TSLA"],
  "status": "Completed",
  "started_utc": "2026-10-25T05:26:43Z",
  "finished_utc": "2026-10-25T05:26:50Z",
  "current_bar": 27360,
  "total_bars": 27360,
  "message": "Completed: 2 strategies. 1 warnings.",
  "report_path": "T4/T4_run_001_of_001_system_2_ee8c3c2e.html",
  "report_json_path": "T4/T4_run_001_of_001_system_2_ee8c3c2e.json",
  "snapshot_path": "T4/run_snapshot_T4_20261025_082643.json",
  "stats": { "InitialBalance": 10000.0, "FinalBalance": 9581.25, "TotalPnL": -418.75, "TotalPnLPercent": -4.19, "TotalTrades": 23, "WinRate": 13.04, "MaxDrawdown": 527.89, "MaxDrawdownPercent": 5.26, "TotalFees": 22.2 },
  "warnings": ["T4 TSLA: symbol TSLAUSDT: no data before 2025-09-14 00:00"]
}

status — Running, Completed ou Failed; Running após wait significa que o tempo de espera acabou — consulte novamente. report_path e report_json_path — caminhos dentro de root=report, null se o relatório não foi gravado. snapshot_path — o snapshot da execução: as configurações exatas com que ela rodou. warnings — configurações ignoradas, falta de dados e o motivo de não haver relatório. Se nenhuma configuração iniciar, a execução termina com status: "Failed" e o motivo em message. As execuções concluídas ficam guardadas por uma hora (até o programa reiniciar).

Erros
  • 404execução inexistente: run_id inválido, passou mais de uma hora ou o programa reiniciou
POST/api/tester/snapshot-run#

Repete uma execução a partir de um arquivo snapshot. Cada execução salva um snapshot ao lado do relatório — run_snapshot_<name_comment>_<horário>.json com as seções settings (configurações de todas as estratégias), tester_config e program_config. Os tokens (api_token, telegram.bot_token) não são gravados no snapshot. A execução por snapshot é modo completo: uma de cada vez, como a mineração. O arquivo é selecionado pelos parâmetros ?root=&path=, como nos arquivos do testador.

O corpo é opcional: você pode enviar um snapshot alterado — as alterações valem apenas para esta execução, e o arquivo não muda. O mesmo na interface: Testador, aba “Resultados (arquivos)”, o botão “Executar” ao lado de um snapshot o abre no editor, e os ajustes valem apenas para esta execução.

Requisição
POST /api/tester/snapshot-run?root=report&path=T4/run_snapshot_20261025.json

?queue=1 — entrar na fila se o testador estiver ocupado, como em /api/tester/run.

200 Resposta
{ "success": true }
Erros
  • 400o snapshot não tem configuração do testador ou configurações
  • 404arquivo não encontrado
  • 409o testador já está rodando ou os dados estão sendo baixados
POST/api/tester/download-data#

Baixa dados históricos para todas as configurações da pasta (?folder=). O andamento e o resultado estão em download da resposta de GET /api/tester/status.

ParâmetroDescrição
startInício do período, por exemplo 2026-05-01. Padrão: StartDate da configuração do testador menos WarmupDays
endFim do período. Padrão: o momento atual (UTC). O EndDate da configuração salva não é usado, então não é preciso alterar a configuração para baixar dias recentes
200 Resposta
{ "success": true }

Ao terminar, download.message informa brevemente até que dia há dados no disco, e download.result traz, para cada par, first_day, last_day (o último dia com candles) e days:

"download": {
  "active": false, "status": "Completed", "message": "Data on disk ends at 2026-10-31..2026-10-31 (last day with candles)",
  "result": { "requested_start": null, "requested_end": null,
    "pairs": [ { "symbol": "BTCUSDT", "exchange": "bybit", "first_day": "2025-10-01", "last_day": "2026-10-31", "days": 396 } ] }
}

A fonte publica os candles de um dia fechado com atraso (geralmente após 06:00 UTC): até lá last_day fica um dia atrás, e o download precisa ser repetido depois. Um par sem dados recebe first_day/last_day = null.

Erros
  • 400start ou end não é uma data, ou start não é anterior a end
  • 409um download já está em andamento ou o testador está rodando
GET/api/tester/wizard-results#

Resultados de execuções individuais, os mais novos primeiro. Uma nova execução do mesmo conjunto de configurações substitui o registro anterior; o resultado de uma execução específica está em /api/tester/wizard-runs/{run_id}.

200 Resposta
[
  {
    "runId": "a82c93c5",
    "timestamp": "2026-10-25T05:26:50Z",
    "strategies": ["T4 BTC"],
    "stats": {
      "InitialBalance": 10000.0, "FinalBalance": 9581.25, "TotalPnL": -418.75, "TotalPnLPercent": -4.19,
      "TotalTrades": 23, "WinRate": 13.04, "MaxDrawdown": 527.89, "MaxDrawdownPercent": 5.26, "TotalFees": 22.2
    },
    "chartUrl": "/tester-report/T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
    "report_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
    "report_json_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.json",
    "period": "2025-09-01 .. 2025-09-20",
    "elapsed": "00:00:07"
  }
]

chartUrl — link para o relatório HTML no navegador. report_path — o mesmo relatório como caminho dentro de root=report, para os arquivos do testador e /api/tester/reports/summary. report_json_path — sua versão JSON; o campo só existe se ela foi gravada.

GET/api/tester/files#

Conteúdo de uma pasta do testador. ?root= — report (relatórios, padrão), data (dados históricos: tester/data ou a pasta de tester_data_dir em settings_program.json) ou runs (conjuntos para repetir execuções); ?path= — um caminho dentro dela. ?contains= — apenas nomes com este texto, ?offset= e ?limit= — parte da lista. Primeiro vêm as pastas por nome, depois os arquivos, os mais novos primeiro; total — quantos itens correspondem no total.

200 Resposta
{
  "root": "report",
  "path": "T4",
  "total": 2,
  "offset": 0,
  "items": [
    { "name": "old", "is_dir": true, "size": 204800, "modified_utc": "2026-10-20T10:00:00Z", "snapshot": false, "editable": false },
    { "name": "run_snapshot_20261025.json", "is_dir": false, "size": 51200, "modified_utc": "2026-10-25T12:00:00Z", "snapshot": true, "editable": false }
  ]
}

snapshot: true — o arquivo pode ser executado por /api/tester/snapshot-run. editable: true — o arquivo pode ser alterado por /api/tester/files/save.

Erros
  • 404pasta não encontrada
GET/api/tester/files/download#

Baixa um arquivo (?root=&path=). Relatórios HTML abrem no navegador.

Erros
  • 404arquivo não encontrado
POST/api/tester/files/delete#

Exclui um arquivo ou pasta (?root=&path=).

200 Resposta
{ "success": true }
Erros
  • 400caminho inválido
  • 404não encontrado
  • 409o testador está rodando ou os dados estão sendo baixados
GET/api/tester/files/content#

Conteúdo de um arquivo snapshot ou de um arquivo JSON de runs (?root=&path=).

Erros
  • 404arquivo não encontrado ou não é um snapshot
POST/api/tester/files/save#

Salva um arquivo JSON em runs (?root=runs&path=): altera um existente ou cria um novo. O corpo é o novo conteúdo do arquivo. Se o corpo de um arquivo existente não tiver a seção settings, ela vem do arquivo atual. Um arquivo novo precisa ser um snapshot completo: settings e tester_config não vazios.

É assim que se prepara uma execução para o usuário: na interface (Testador, aba “Resultados (arquivos)”, pasta runs) cada arquivo desse tipo tem os botões “Executar” e “Editar”. Com use_runs na configuração do testador, uma execução completa pela linha de comando (--run-tester) executa todos os .json de runs.

200 Resposta
{ "success": true, "created": false }
Erros
  • 400corpo vazio, JSON inválido ou arquivo novo sem settings / tester_config
  • 404o caminho não está em runs ou não é .json
GET/api/tester/reports/summary#

Resumos de relatórios HTML para comparar execuções: métricas e curva de patrimônio. ?r= — caminho do relatório em report, o parâmetro pode ser repetido.

Requisição
GET /api/tester/reports/summary?r=T4/report.html&r=T4_STRESS/report.html
200 Resposta
[
  {
    "report": "T4/report.html",
    "created": "2026-10-25T12:00:00Z",
    "summary": {
      "name_comment": "T4",
      "start": "2025-01-01T00:00:00",
      "end": "2026-01-01T00:00:00",
      "symbols": ["BTCUSDT"],
      "metrics": { "TotalPnLPercent": 42.1, "MaxDrawdownPercent": 12.3, "ProfitFactor": 1.8, "WinRate": 55.0, "TotalTrades": 120 },
      "equity_t": [1735689600],
      "equity_v": [1000.0]
    }
  }
]

equity_t e equity_v — tempo (Unix, segundos) e saldo dos pontos da curva de patrimônio. summary: null — o relatório não tem resumo.

Erros
  • 400nenhum r enviado
  • 404relatório não encontrado
GET/api/tester/reports/json#

Resultados detalhados de uma execução em JSON compacto. Os mesmos números do relatório HTML, mas o arquivo é dezenas de vezes menor: dezenas de kilobytes em vez de megabytes.

O testador grava <relatório>.json ao lado do relatório HTML se report.enable_json_report estiver ativado na configuração do testador (desativado por padrão). O JSON é gravado mesmo com report.enable_html_report desativado: assim uma grande mineração roda mais rápido e ainda guarda os detalhes de cada combinação.

Parâmetros:

  • ?path= — caminho do relatório em report: um arquivo .json ou seu .html (por exemplo, report_path de wizard-results);
  • ?sections= — apenas estas seções separadas por vírgula, por exemplo ?sections=summary ou ?sections=metrics,by_symbol;
  • ?trades_offset= e ?trades_limit= — parte dos trades.

Seções:

SeçãoConteúdo
summaryresumo de 1–2 KB: PnL, drawdowns (inclusive o não realizado e o pior dos três, como MaxDrawdownPercent em reports_history.csv), Ulcer Index, profit factor, Sharpe, CAGR, trades, win rate, taxas, posição média e máxima, pior mês, retorno mensal. Calculado na leitura a partir de run, metrics e monthly, por isso relatórios antigos também o têm
runname_comment, comment, run_tag, run_params (valores dos parâmetros minerados), período, corretoras, estratégias e pares. O que a execução acrescentou a comment como texto ([overrides: …], [sides: …]) está em campos separados, não é preciso analisar comment com regex: overrides (array de regras como na requisição, sem corte; em comment é cortado em 300 caracteres), sides e a origem da execução: batch_id e name (nome do conjunto) para tester_run_batch e tester_run_single com periods, run_id para execuções do assistente de testes. Sem valor, o campo é null. Execuções pela interface não preenchem esses campos; a repetição por snapshot os obtém do snapshot
metricstoda a tabela de estatísticas do relatório HTML por blocos: PnL, saldo, retorno mensal, trades, preenchimentos, Buy & Hold, risco e exposição, Sharpe, Sortino, CAGR, Calmar, Ulcer Index…
by_symbolresultados por par: trades, win rate, profit factor, PnL, melhor e pior trade, drawdown, Buy & Hold, taxas, volume, tamanho da posição
monthlyretorno mensal, %: { "2025-09": -4.15 }
tradestrades (da abertura da posição até o fechamento total ou a reversão), ordenados pelo horário de fechamento — columns e rows
curvescurvas de saldo (equity) e de posições abertas (open_positions_total, _long, _short), até 500 pontos; t — tempo Unix em segundos, v — valores
dailyvalores no fim de cada dia corrido do período, sem lacunas: days, equity (saldo de margem), position (posição aberta, USDT); strategies — estratégias (configurações) com pares, código, tipo (trend / counter-trend) e tags; pnl e position_by_strategy — um array por estratégia na mesma ordem: a contribuição acumulada ao saldo desde o início do relatório e a posição. Gravado com report.json_daily (ativado por padrão). Em conjuntos grandes a seção é grande — /api/tester/reports/portfolio dá um resumo dela
settingsconfigurações completas das estratégias da execução

Os campos v (versão do formato), created_utc e html_report (nome do relatório HTML ou null) são sempre retornados.

Requisição
GET /api/tester/reports/json?path=T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html&sections=by_symbol,trades&trades_limit=2
200 Resposta
{
  "v": 1,
  "created_utc": "2026-10-25T05:45:34Z",
  "html_report": "T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
  "by_symbol": [
    { "symbol": "BTCUSDT", "strategy": "zigzag", "trades": 23, "win_rate": 13.04, "profit_factor": 0.395, "pnl": -390.14,
      "best_trade": 160.02, "worst_trade": -57.7, "max_drawdown_incl_unrealized": -483.2, "buy_hold_percent": 6.81,
      "fee": 22.2, "volume": 221995.16, "position_avg_percent": 49.31, "position_max_percent": 50.72 }
  ],
  "trades": {
    "count": 23,
    "columns": ["symbol", "side", "open", "close", "holding_hours", "fills", "net_pnl", "mae", "mfe"],
    "rows": [
      ["BTCUSDT", "short", "2025-09-01 00:04", "2025-09-01 07:54", 7.83, 2, -57.6968, -57.6968, 38.8311],
      ["BTCUSDT", "long", "2025-09-01 07:54", "2025-09-01 20:45", 12.85, 2, -46.2855, -50.7967, 26.7293]
    ],
    "offset": 0
  }
}

Em trades: count — número de todos os trades, net_pnl — resultado do trade descontadas as taxas, mae e mfe — o pior e o melhor resultado intermediário do trade (USDT), horário em UTC.

Erros
  • 400o arquivo não é um relatório JSON
  • 404relatório JSON não encontrado
GET/api/tester/reports/portfolio#

Análise de portfólio de uma execução com base na seção daily do seu relatório JSON. As estratégias são reunidas em grupos, e tudo abaixo é calculado por grupo.

Parâmetros:

  • ?path= — um relatório JSON (ou seu .html) em report;
  • ?group_by= — type (padrão: T — tendência, CT — contratendência, pelo código da estratégia), tag (a primeira tag da configuração) ou strategy (cada configuração é um grupo);
  • ?groups={"T":"T_*","CT":"CT_*"} — grupos por máscaras de nome em vez de group_by; configurações sem correspondência vão para other;
  • ?worst_days= — quantos piores dias de cada grupo considerar (padrão 10);
  • ?curves=0, ?leave_one_out=0 — não calcular essas seções.
200 Resposta resumido
{
  "start": "2026-08-01", "end": "2026-09-30", "days": 61, "group_by": "type",
  "groups": [ { "group": "T", "strategies": 1, "names": ["T_BTW"], "pnl": -7294.0, "pnl_percent": -72.94, "worst_day": -4838.3, "max_drawdown_usdt": 15259.83, "position_max": 12752.08 } ],
  "correlation": { "CT": { "CT": 1.0, "T": -0.28 }, "T": { "CT": -0.28, "T": 1.0 } },
  "worst_week": { "start": "2026-08-08", "end": "2026-08-14", "pnl": -7200.62, "pnl_percent": -40.19, "by_group": { "CT": 279.98, "T": -7480.6 } },
  "worst_days": { "T": { "days": 5, "pnl": -12902.51, "portfolio_pnl": -12754.28, "others": { "CT": { "pnl": 148.22, "offset_percent": 1.1 } } } },
  "leave_one_out": {
    "max_drawdown_percent": 83.43, "ulcer": 59.776,
    "groups": { "T": { "pnl": -7294.0, "max_drawdown_percent_without": 1.54, "drawdown_added": 81.89, "ulcer_without": 0.686, "ulcer_added": 59.09 } },
    "strategies": [ { "name": "T_BTW", "group": "T", "pnl": -7294.0, "max_drawdown_percent_without": 1.54, "drawdown_added": 81.89, "ulcer_without": 0.686, "ulcer_added": 59.09 } ]
  },
  "curves": { "days": ["2026-08-01"], "equity": [10754.72], "position": [0], "pnl_by_group": { "T": [0] }, "position_by_group": { "T": [0] } }
}
  • correlation — correlação do PnL diário dos grupos;
  • worst_week — os piores 7 dias seguidos do portfólio e o PnL de cada grupo neles;
  • worst_days — para cada grupo, seus piores dias: seu PnL, o PnL do portfólio e o PnL dos outros grupos nos mesmos dias; offset_percent — que parte da perda outro grupo recuperou (abaixo de zero — aumentou a perda);
  • leave_one_out — drawdown máximo e Ulcer do portfólio sem cada estratégia e sem cada grupo: drawdown_added acima de zero — a estratégia aumenta o drawdown, abaixo de zero — reduz (faz hedge). Substitui uma execução separada do conjunto sem cada estratégia;
  • curves — curvas diárias sem lacunas: saldo, posição, PnL acumulado e posição de cada grupo.

Todos os valores se baseiam no fim do dia: os drawdowns aqui são menores que os intradiários de metrics, e leave_one_out é aproximado — sem a influência das estratégias entre si por margem e limites de posição.

Erros
  • 400o relatório não tem a seção daily (são necessários report.enable_json_report e report.json_daily; relatórios antigos não a têm) ou group_by / groups inválidos
  • 404relatório não encontrado
GET/api/tester/mining-robustness#

Robustez da mineração em vários períodos: a mesma grade parameter_mining, executada em cada período em sua própria pasta (periods em /api/tester/run).

Parâmetros:

  • ?folders=a,b — pastas em report, um período em cada;
  • ?metric= — uma coluna de reports_history.csv, padrão TotalPnLPercent; nas colunas de drawdown, risco e UlcerIndex, quanto menor, melhor;
  • ?base={"settings[*].zz.depth": 12} — o ponto de partida para a comparação;
  • ?top= — quantas combinações mostrar por configuração (padrão 10).

As combinações são pareadas pelos valores dos parâmetros e pela coluna Strategies (com single_mode, cada configuração tem seu próprio ranking). Em cada período calcula-se o platô — a média da métrica na combinação e em suas vizinhas da grade (como na seção de robustez do relatório do otimizador). O ranking é pela média dos platôs dos períodos e depois pelo pior período.

200 Resposta resumido
{
  "metric": "TotalPnLPercent", "lower_is_better": false,
  "periods": ["T4_2026-08-01_2026-08-31", "T4_2026-09-01_2026-09-30"],
  "parameters": ["settings[*].basic.balance_percentage_long"],
  "combinations_common": 5,
  "by_strategies": [
    {
      "strategies": "CT_VELVET|T_BTW",
      "top": [ { "rank": 1, "parameters": { "settings[*].basic.balance_percentage_long": "50" }, "mean_plateau": -42.16, "worst_period": -56.75, "mean": -41.74,
                 "by_period": [ { "period": "T4_2026-08-01_2026-08-31", "metric": -26.72, "plateau": -28.02, "run_tag": "run_005_of_005" } ], "beats_base": true } ],
      "best_by_period": [ { "period": "T4_2026-09-01_2026-09-30", "parameters": { "settings[*].basic.balance_percentage_long": "10" }, "metric": -52.97, "rank_across_periods": 5, "worst_period": -52.97 } ],
      "base": { "rank": 1, "...": "..." },
      "beats_base_count": 1
    }
  ]
}

best_by_period — o melhor ponto de cada período e sua posição no ranking geral: uma posição baixa significa que o ponto está ajustado ao seu período. beats_base — a combinação não é pior que a base em nenhum período.

Erros
  • 400menos de duas pastas, sem coluna de métrica ou combinações de menos para vizinhos
  • 404pasta não encontrada
POST/api/tester/reports/telegram#

Envia um arquivo de relatório do testador para o Telegram — ao chat de notificações do testador (telegram.id_chat da configuração do programa, para onde também vão os resultados das minerações). Só é possível enviar um arquivo de report (.html, .json, .csv, .png, .txt, até 50 MB); não há acesso à negociação nem aos chats das estratégias. A legenda é Tester report: <caminho> e caption.

Requisição
{ "path": "T4/T4_BTCUSDT_20261025.html", "caption": "Melhor variante por drawdown" }
200 Resposta
{ "success": true, "path": "T4/T4_BTCUSDT_20261025.html" }

No máximo um arquivo a cada 10 segundos.

Erros
  • 400o arquivo não é um relatório ou tem mais de 50 MB, telegram.id_chat não definido
  • 404arquivo não encontrado
  • 429com muita frequência
  • 502o Telegram não aceitou o arquivo (o motivo está no log do programa)
GET/api/tester/publish/files#

Arquivos da pasta de relatório que podem ser publicados no site. ?path= — uma pasta em report.

200 Resposta
[ { "name": "reports_history.csv", "size": 10240, "kind": "history" } ]

kind — history (histórico de execuções), snapshot (snapshot da execução) ou summary (relatório consolidado).

Erros
  • 404pasta não encontrada
POST/api/tester/publish#

Envia os arquivos selecionados da pasta de relatório para o site. A publicação aparece após a moderação.

Requisição
{ "path": "T4", "files": ["reports_history.csv"], "contact": "@telegram", "comment": "...", "agree": true }

agree: true — consentimento com os termos de publicação, obrigatório.

200 Resposta
{ "success": true, "sent": ["reports_history.csv"] }
Erros
  • 400sem consentimento ou nenhum arquivo selecionado
  • 404pasta não encontrada
  • 502o site não aceitou a publicação

Códigos de resposta#

CódigoSignificado
200Sucesso
400Requisição inválida: corpo vazio, JSON inválido, campos obrigatórios vazios
401Sem acesso: api_token inválido; cookie ausente, expirado ou substituído por um novo login; requisição sem token que não vem da mesma máquina
403Requisição de uma página de outro site (Origin diferente do endereço do bot)
404Não encontrado
409Conflito: o testador ou um download de dados já está rodando, o nome já está em uso, falta o bot em execução necessário
429Com muita frequência (envio de relatório do testador para o Telegram)
500Erro interno ou erro da corretora
502Um serviço externo não aceitou a requisição
503O programa ainda está iniciando