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.
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": "..." }.
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.
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.
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.
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.
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.
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..."
}
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.
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.
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.
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).
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 é:
pausar;
cancelar as ordens;
fechar a posição;
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
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.
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.
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.
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.
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).
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.
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).
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 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.
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.
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.
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.
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.
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
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.
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.
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).
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.
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.
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.
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).
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).
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.
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:
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)
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.
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.
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.
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.
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âmetro
Descrição
compact=1
cada 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, limit
uma 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.
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
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.
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
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
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âmetro
Descrição
start
Início do período, por exemplo 2026-05-01. Padrão: StartDate da configuração do testador menos WarmupDays
end
Fim 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
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}.
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.
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.
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
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
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ção
Conteúdo
summary
resumo 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
run
name_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
metrics
toda 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_symbol
resultados por par: trades, win rate, profit factor, PnL, melhor e pior trade, drawdown, Buy & Hold, taxas, volume, tamanho da posição
monthly
retorno mensal, %: { "2025-09": -4.15 }
trades
trades (da abertura da posição até o fechamento total ou a reversão), ordenados pelo horário de fechamento — columns e rows
curves
curvas de saldo (equity) e de posições abertas (open_positions_total, _long, _short), até 500 pontos; t — tempo Unix em segundos, v — valores
daily
valores 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
settings
configuraçõ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§ions=by_symbol,trades&trades_limit=2
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.
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.
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
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.
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
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" }