# TroiaQuants — API de negociação

Ponte entre seus programas e as contas das corretoras: conta, posições, ordens, histórico, cotações ao vivo, envio de ordens e cadastro das contas.

## Acesso

Crie sua conta no app da TroiaQuants e gere uma **chave de API**. Mande a chave em cada chamada: `Authorization: Bearer <chave>` (ou `X-API-Key: <chave>`). As contas de corretora se cadastram no app ou aqui (`POST /accounts`).

- A chave só enxerga as suas contas.
- Toda chave lê. A permissão **Negociação** envia ordens; a permissão **Contas** cadastra, altera e remove contas de corretora; a permissão **Backtests** escreve experts e roda backtests nos servidores da plataforma (cada um custa créditos). Sem a permissão, a resposta é 403.
- Tudo de uma conta fica em `/accounts/<CONTA>/...`, onde `<CONTA>` é o número da conta na corretora: `/accounts/67312128/positions`.

## Convenções

- **Horários:** cada servidor trabalha no horário que a corretora escolheu (a XP usa o de Brasília) e o guarda como se fosse UTC. Todo campo de tempo segue essa regra.
- **Volumes** em lotes (ações: múltiplos de 100; mini índice: 1 contrato). **Preços** absolutos, não em pontos.

## Erros

Uma chamada recusada responde com o status HTTP do motivo e o corpo `{ "error", "code" }`: `error` diz em palavras (em inglês) o que deu errado, `code` diz o mesmo em número, para o programa decidir sem ler texto.

| `code` | Status | Significado |
|---|---|---|
| -2 | 400, 409 | Parâmetro inválido ou faltando |
| -4 | 404 | Conta, ativo ou rota que não existe |
| -6 | 401, 403 | Chave ausente, inválida ou revogada; ou sem a permissão Contas |
| -8 | 403 | A chave não tem a permissão Negociação |
| -7 | 501 | A conta ou o ativo usa algo que o gateway ainda não faz |
| -10003 | 503 | A conta não está conectada à corretora |
| -10005 | 504 | A corretora não respondeu a tempo |
| -10000 | 500, 503 | Falha do próprio gateway |
| -3 | 429 | A conta já guarda os negócios de tantos ativos quantos pode (`POST /accounts/{login}/trades/{symbol}/keep`): pedir de novo não adianta enquanto ela não deixar de guardar outro |
| -1 | 429, 502 | Qualquer outra falha, e o limite de chamadas |

Uma **ordem recusada não é erro**: `POST /order` responde 200 com o resultado e o código de retorno da recusa (tabela abaixo).

## Limites

Cada chave tem a sua cota, que se refaz a cada segundo:

- **Chamadas:** 50 por segundo, com até 100 de uma vez. Acima disso a resposta é 429, com o cabeçalho `Retry-After` dizendo em quantos segundos tentar de novo.
- **Ordens:** 10 por segundo, com até 20 de uma vez, contadas à parte. Acima disso a ordem não é enviada e a resposta é um resultado com o código de retorno 10024, como as outras recusas.
- **Tempo real:** 30 conexões por usuário (a que passar é fechada com o código 4429), 500 tópicos por conexão e 20 mensagens por segundo por conexão.

## Tempo real (WebSocket)

Conecte em `wss://<gateway>/stream?api_key=<chave>` (ou mande a chave no cabeçalho). Ao conectar chega `{"type":"ready"}`.

1. Assine: `{"action":"subscribe","topics":["tick.67312128.EURUSD.","trade.67312128."]}`.
2. A resposta `{"type":"subscribed","topics":[...],"rejected":[...]}` diz o que foi aceito. Cada recusado vem como `{ "topic", "error", "code" }`, com os códigos da tabela de erros.
3. Cada mensagem chega como `{"topic","data"}`.
4. Para parar: `{"action":"unsubscribe","topics":[...]}`.

| Tópico | Conteúdo |
|---|---|
| `tick.<CONTA>.<ATIVO>.` | Cada cotação nova, no formato de [Tick](#model/tick), mais `seq` e `epoch`. Ao assinar, chega uma vez a última cotação conhecida. Atualizações só das estatísticas do dia (máxima, mínima, número de negócios) não contam como cotação nova e não são enviadas. `seq` numera as mensagens do tópico (de 1 em 1, cada ativo da conta à parte, contando todas: negócios, cotações e a da assinatura): um salto diz que mensagens se perderam no caminho. `epoch` é a vida do gateway: muda quando ele reinicia, e a numeração recomeça. Os negócios perdidos podem ser relidos em `GET /accounts/{login}/trades/{symbol}`, depois de pedidos em `POST /accounts/{login}/trades/{symbol}/keep` |
| `book.<CONTA>.<ATIVO>.` | O livro inteiro a cada mudança, no formato de [Book](#model/book) |
| `candle.<CONTA>.<ATIVO>.<TEMPO>.` | O candle em andamento a cada negócio, no formato de [Candle](#model/candle) mais `symbol` e `timeframe`. Quando o período termina, chega uma última vez com `in_progress: false`: é o candle fechado. Exemplo: `candle.50389039.WINZ26.M5.` |
| `transaction.<CONTA>.` | Cada transação da conta: `{ "trans", "request", "result", "deal", "order", "position" }`. `trans` descreve a transação (tipos abaixo); `request` (formato de [TradeRequest](#model/traderequest)) e `result` (formato do resultado de `/order`) só vêm no tipo 10 (resultado de pedido). Para o robô não precisar consultar: `deal` (formato de `/history/deals`) nas transações de negócio, `order` (formato de `/orders`) nas de ordem e de histórico, `position` (formato de `/positions`, volume 0 quando fechou) nas de negócio e de posição. O que não se aplica vem `null` |
| `trade.<CONTA>.` | Algo mudou em ordens, posições, negócios ou saldo. Uma mensagem por operação, já com o estado novo: `{ "seq", "account", "positions", "orders" }` nos formatos de `/account`, `/positions` e `/orders` (`account` vem `null` se o gateway não consegue calcular patrimônio e margem, como num modo de margem não suportado). Conta, posições e ordens são do mesmo instante. `seq` numera as mensagens `trade.` e `account.` da conta na ordem em que o estado foi lido: maior é mais novo, e as duas de uma mesma leitura têm o mesmo número. Recomeça quando a plataforma reinicia. Também chega ao assinar e depois de cada reconexão, com o estado recarregado da corretora |
| `account.<CONTA>.` | O mesmo conteúdo de `trade.`, mas também quando as cotações mudam o preço atual e o lucro das posições (e com eles o patrimônio e a margem livre), no máximo a cada 0,2 s. Também chega ao assinar |
| `connection.<CONTA>.` | Estado da conexão com a corretora: `{ "status", "connected", "last_error", "reason", "retry_at", "attempts", "last_outage" }`, os mesmos campos de `/ping` e de `GET /accounts`. Chega ao assinar e a cada mudança. `reason` diz por que a conta não está conectada (formato de [StatusReason](#model/statusreason)); `last_outage`, a última vez que ela esteve fora. O gateway derruba e refaz a conexão sozinho se a corretora ficar 15 segundos sem responder. Com `status` igual a `auth_failed`, a corretora recusou as credenciais e o gateway parou de tentar: troque as credenciais da conta no app ou em `PATCH /accounts/{login}`. Depois de uma reconexão chega um `trade.` com o estado novo; o que aconteceu durante a queda (ordem executada, stop atingido) não chega como `transaction.`, então releia o histórico se precisar |
| `error.<CONTA>.` | O que uma assinatura não conseguiu acompanhar: `{ "topic", "code", "error" }`. `code` é `unknown_symbol` para um ativo que a corretora não tem, ou `failed` quando, com a conta conectada, a assinatura falhou três vezes seguidas (sem conexão, o gateway tenta de novo a cada 5 segundos até conectar). Depois do erro o gateway não tenta mais: assine de novo para tentar |

Tipos de transação (`trans.type`): 0 ordem nova, 1 ordem alterada, 2 ordem saiu das pendentes, 3 ordem entrou no histórico, 4 alterada no histórico, 5 removida do histórico, 6 negócio novo, 7 negócio alterado, 8 negócio removido, 9 posição alterada sem negócio (stop e alvo), 10 resultado de um pedido.

- Tópicos funcionam como prefixo: `tick.<CONTA>.` recebe todos os ativos já assinados da conta, mas não assina nenhum novo.
- **Mesmo número em duas corretoras** (uma conta à vista e uma de futuros da Binance, por exemplo): ponha o servidor depois do número, codificado como numa URL e com os pontos como `%2E`: `tick.67312128@Binance%2EFutures.BTCUSDT.`. As mensagens chegam com o tópico assim. Sem o servidor, o número sozinho é recusado com o tópico certo na mensagem. O SDK faz isso sozinho quando a conta é aberta com o servidor (`client.account(login, { server })`).
- Use o ponto no final, por exemplo `tick.50389039.WINZ26.`. Ele evita que `tick.50389039.VALE3` receba também `VALE3F`.
- Ao assinar, o gateway assina o ativo na corretora sozinho e envia na hora o último dado conhecido.
- **Ativos sem uso:** o gateway deixa de acompanhar na corretora o ativo que ninguém assina em tempo real nem consulta há 10 minutos, desde que a conta não tenha posição ou ordem nele. A próxima consulta ou assinatura volta a acompanhá-lo. Para soltar antes: `DELETE /accounts/<CONTA>/symbol/<ATIVO>`.
- **Livro de um ativo por vez:** a corretora só transmite o livro ao vivo de um ativo por conta. Assinar `book.` de outro ativo troca o livro transmitido para ele, para todos os assinantes da conta.
- Um cliente lento perde mensagens: se elas se acumulam, as novas são descartadas até ele alcançar.

```python
import asyncio, json, websockets

async def main():
    async with websockets.connect("wss://<gateway>/stream?api_key=tq_...") as ws:
        await ws.send(json.dumps({"action": "subscribe", "topics": ["tick.50389039.WINZ26.", "trade.50389039."]}))
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("topic", "").startswith("tick."):
                print("cotação", msg["data"]["bid"], msg["data"]["ask"], msg["data"]["last"])

asyncio.run(main())
```

## Códigos de retorno das ordens

| Código | Significado |
|---|---|
| 10008 | Ordem colocada |
| 10009 | Executado |
| 10010 | Executado em parte |
| 10004 | Nova cotação (requote) |
| 10006 | Recusado |
| 10012 | Sem resposta a tempo |
| 10013 | Pedido inválido (também: ordem não encontrada ou que já não está pendente) |
| 10014 | Volume inválido |
| 10015 | Preço inválido |
| 10016 | Stop/alvo inválido (lado errado ou perto demais do preço) |
| 10017 | Negociação desabilitada no ativo |
| 10018 | Mercado fechado |
| 10019 | Saldo insuficiente |
| 10022 | Validade da ordem não aceita pelo ativo, ou sem data de validade |
| 10024 | Ordens demais em pouco tempo: a ordem não foi enviada |
| 10025 | Nada a alterar: os valores já são esses |
| 10030 | Preenchimento não aceito pelo ativo |
| 10031 | Sem conexão com o servidor |
| 10035 | Tipo de ordem não aceito pelo ativo |
| 10036 | Posição já fechada ou não encontrada |
| 10042 | Ativo só aceita compra (venda só para fechar) |
| 10043 | Ativo só aceita venda (compra só para fechar) |
| 10044 | Ativo só aceita fechar posições |

## Limitações

- A corretora não recebe o **número mágico** (`magic`): o gateway guarda o de cada ordem que envia e o mostra na ordem (o do pedido que a criou), no negócio (o da sua ordem) e na posição (o da ordem que a abriu). Ordens feitas fora do gateway (app da corretora, celular) têm 0.
- Patrimônio e margem são calculados só para contas no modo de margem com posições independentes (`margin_mode` 2), sem regras de alavancagem, e com ativos na moeda da conta.
- O servidor só manda **candles já fechados**. O gateway monta o candle em andamento com os minutos fechados e os negócios que recebe ao vivo. Na primeira consulta ou assinatura de um ativo, os negócios do minuto atual anteriores a ela não são conhecidos: o candle desse minuto pode vir com volume menor e abertura, máxima e mínima diferentes. A partir do minuto seguinte, bate com o servidor. Ativos com gráfico pelo preço de compra (não é o caso da B3) ficam sem o candle em andamento.
- O **livro de ofertas** ao vivo é de um ativo por vez (veja acima).

A descrição OpenAPI completa está em `/openapi.json`.

# Rotas

## Estado

Saúde do gateway e da conexão.

### GET /health — Processo no ar

Respostas:

- 200: O processo responde. (`object`)

### POST /links — Um endereço que abre um arquivo sem a chave

Para um navegador, uma planilha ou o código de um agente de IA que não manda a chave: um endereço que abre um arquivo seu por uma hora, só para ler, e só aquele endereço com aquela consulta. Vale para os arquivos de um backtest (`/backtests/{id}/files/deals.csv`...) e para os candles e negócios da B3 como planilha (`/exchanges/B3/candles/WIN%40N?timeframe=M1&from=2026-01-01&to=2026-06-30&format=csv`). Trate o endereço como a chave: quem tiver, abre o arquivo enquanto ele vale.

Corpo (application/json): object

- `path` (string, obrigatório): O endereço do arquivo, a partir da barra.

Respostas:

- 201: O endereço. (`object`)
- 400: O endereço não é de um arquivo. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /key — A chave desta chamada

O que a chave de API usada na chamada pode fazer além de ler: `trade` (Negociação) envia ordens, `accounts` (Contas) cadastra, altera e remove contas de corretora, `backtests` (Backtests) escreve experts e roda backtests nos servidores. Ligar um expert ao vivo pede `trade`.

Respostas:

- 200: A chave. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /key — Revogar a chave desta chamada

A chave usada na chamada para de funcionar na hora, como ao revogar no app. Não dá para desfazer.

Respostas:

- 204: Revogada.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /accounts/{login}/ping — Conexão com a corretora

Se a conexão cai, o gateway tenta de novo sozinho: a primeira tentativa na hora, as seguintes depois de 2, 5, 10, 30 e 60 s (30 e 60 s quando a corretora responde que o servidor dela está indisponível). Abrir a conexão e fazer o login têm 10 s cada; quando a corretora tem mais de um endereço, ele usa o primeiro que responde. Se a corretora recusa o login (senha ou chave de API errada, por exemplo), ele para de tentar: troque as credenciais da conta no app ou em `PATCH /accounts/{login}`. `reason` diz por que a conta não está conectada, e de quem é o problema: da corretora ou da plataforma.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: `ok` diz se o gateway está conectado e autenticado na corretora. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Contas de corretora

Catálogo de corretoras e servidores, e cadastro das suas contas. Cada servidor pede um tipo de credencial: `auth` (`user` e `password`; em contas de terminal, o usuário é o número da conta), `api-key-secret` (`key` e `secret`) ou `api-token` (`token`).

### GET /brokers — Corretoras

As corretoras disponíveis e os métodos de integração de cada uma.

Respostas:

- 200: Corretoras. (`Broker[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /servers — Servidores

Os servidores de cada corretora, com o método e o tipo de credencial que pedem. O nome do servidor é o que se manda em `POST /accounts`.

Respostas:

- 200: Servidores. (`Server[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /accounts — Suas contas

Todas as suas contas de corretora, ativas ou não, com o estado da conexão: os números para usar em `/accounts/{login}/...`.

Respostas:

- 200: Contas. (`BrokerAccount[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /accounts — Cadastrar conta

Cadastra uma conta de corretora sua e conecta na hora. As credenciais são conferidas (na corretora, quando o método permite) e guardadas criptografadas; nunca voltam nas respostas. Precisa da permissão **Contas**.

Corpo (application/json): object

- `server` (string, obrigatório): Nome do servidor (veja `GET /servers`).
- `credentials` (Credentials, obrigatório)
- `enabled` (boolean): Padrão: ativa.

Respostas:

- 201: A conta cadastrada. (`BrokerAccount`)
- 400: Credenciais que não servem para o tipo do servidor, ou recusadas pela corretora (o motivo vem em `error`). (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Contas. (`Error`)
- 404: Servidor desconhecido. (`Error`)
- 409: A conta já está cadastrada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### PATCH /accounts/{login} — Alterar conta

Ativa ou desativa a conta, ou troca as credenciais (todas as do tipo, da mesma conta). Ativar ou trocar reconecta; desativar desconecta. Precisa da permissão **Contas**.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Corpo (application/json): object

- `enabled` (boolean)
- `credentials` (Credentials)

Respostas:

- 200: A conta alterada. (`BrokerAccount`)
- 400: Nada para mudar, ou credenciais que não servem ou são de outra conta. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Contas. (`Error`)
- 404: Conta não encontrada entre as suas. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /accounts/{login} — Remover conta

Tira a conta da plataforma (a conta na corretora continua existindo). Uma conta com histórico gravado não é removida: desative. Precisa da permissão **Contas**.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 204: Removida.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Contas. (`Error`)
- 404: Conta não encontrada entre as suas. (`Error`)
- 409: A conta tem histórico gravado (desative), ou o número existe em duas corretoras (informe `server`). (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Conta

Conta, posições e ordens abertas, mantidas atualizadas pelos avisos do servidor.

### GET /accounts/{login}/account — Conta, patrimônio e margem

Conta com saldo, patrimônio, margem e margem livre calculados do mesmo jeito que o terminal da corretora. Lucro, patrimônio e margem livre acompanham cada cotação dos ativos com posição aberta.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Conta. (`AccountInfo`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 501: Modo de margem ou ativo que o gateway ainda não calcula. (`Error`)
- 502: Não foi possível calcular: falha no servidor. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/trades — Conta, posições e ordens do mesmo momento

Uma leitura só, igual às mensagens `trade` e `account` em tempo real. Traz a conta, as posições, as ordens pendentes, a margem de cada ativo (`margins`) e o modo de margem da conta (`margin_mode`: 0 netting, 1 bolsa, 2 hedging). A conta vem nula onde patrimônio e margem ainda não são calculados, como em contas netting e de bolsa do MetaTrader 5. O modo de margem vem sempre: numa conta netting cada ativo tem uma posição só, dividida pelos experts que o operam.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Conta, posições e ordens. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/positions — Posições abertas

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (consulta, string): Só deste ativo.
- `group` (consulta, string): Filtro pelo nome do ativo, como em `/symbols`: `*` é curinga, `!` exclui e as condições vão separadas por vírgula, inclusões primeiro. Exemplos: `WIN*`, `VALE3,PETR4`, `*,!EURUSD`.
- `ticket` (consulta, integer): Só a posição com este número. Como no pacote Python, é ignorado quando vem `symbol`.

Respostas:

- 200: Posições. (`Position[]`)
- 400: Número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/orders — Ordens pendentes

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (consulta, string): Só deste ativo.
- `group` (consulta, string): Filtro pelo nome do ativo, como em `/symbols`: `*` é curinga, `!` exclui e as condições vão separadas por vírgula, inclusões primeiro. Exemplos: `WIN*`, `VALE3,PETR4`, `*,!EURUSD`.
- `ticket` (consulta, integer): Só a ordem com este número. Como no pacote Python, é ignorado quando vem `symbol`.

Respostas:

- 200: Ordens. (`Order[]`)
- 400: Número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/positions/total — Quantidade de posições

Como `positions_total()` do pacote Python.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Quantidade. (`integer`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/orders/total — Quantidade de ordens pendentes

Como `orders_total()` do pacote Python.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Quantidade. (`integer`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/version — Versões

Como `version()` do pacote Python: a versão do gateway e o build do servidor de negociação da conta (`null` enquanto não conectada), com o servidor e a corretora.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Versões. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /accounts/{login}/reconnect — Reconectar agora

Não existe no pacote Python (lá, `initialize` e `login`). Conecta a conta de novo agora, em vez de esperar a próxima tentativa. Depois de credenciais recusadas, troque-as antes em `PATCH /accounts/{login}`: a troca já reconecta. Precisa do escopo de negociação.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Reconectando. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /accounts/{login}/time — Relógio do servidor da corretora

Não existe no pacote Python (no MQL5: TimeTradeServer). A hora do servidor agora, em segundos Unix como os horários de negócios, ordens e candles vêm escritos (o relógio do servidor lido como se fosse UTC), e quanto ele está à frente do UTC (`offset`, em segundos, em quartos de hora). Um horário da corretora menos `offset` é o momento real; assim um app mostra os horários no fuso de quem lê.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: A hora do servidor e a diferença para o UTC. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

## Mercado

Cotação, livro de ofertas e candles. Para receber cotações e livro em tempo real, use o WebSocket (veja a introdução).

### GET /accounts/{login}/price/{symbol} — Última cotação

Na primeira chamada para um ativo, o gateway assina o ativo e espera até 5 segundos pela primeira cotação. As seguintes respondem na hora. Séries contínuas (como `WDO$`) não são negociáveis e só trazem o último preço.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo. Codifique `$` como `%24`.

Respostas:

- 200: Cotação. (`Tick`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Ativo inexistente. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: Nenhuma cotação chegou a tempo. (`Error`)

### GET /accounts/{login}/symbol/{symbol} — Dados do ativo

Tudo sobre o ativo: contrato, passo de preço, lotes, regras de negociação, cotação e estatísticas do dia. Assina o ativo: o gateway passa a acompanhar suas cotações.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo. Codifique `$` como `%24`.

Respostas:

- 200: Dados do ativo. (`SymbolInfo`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Ativo inexistente. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### DELETE /accounts/{login}/symbol/{symbol} — Deixar de acompanhar o ativo

O gateway deixa de acompanhar o ativo na corretora: cotações, candles em andamento e livro. Responde `false` enquanto alguém assina o ativo em tempo real (pare de assinar antes) ou a conta precisa dele: posição ou ordem no ativo, ou nele se converte o lucro de uma. Sem isso, o gateway solta sozinho o ativo que ninguém usa há 10 minutos. Não precisa da permissão Negociação.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo.

Respostas:

- 200: `true` se deixou de acompanhar (ou não acompanhava). (`boolean`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/symbols — Lista de ativos

Tudo sobre cada ativo cujo nome casa com o filtro, no formato de [SymbolInfo](#model/symbolinfo). Não assina os ativos: os que o gateway não acompanha vêm com `select` e `visible` falsos e sem cotação. Até 5.000 ativos por consulta (as opções de um papel dão cerca de 3.500); acima disso, responde 400 pedindo um filtro mais específico.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `group` (consulta, string): Filtro por nome: `*` é curinga, `!` exclui e as condições vão separadas por vírgula, inclusões primeiro. Sem `*`, o nome precisa ser exato. Diferencia maiúsculas. Exemplos: `WIN*`, `PETR4*`, `WIN*,!*$*`. Sem filtro, todos os ativos (passa do limite).

Respostas:

- 200: Ativos, na ordem da lista do servidor. (`SymbolInfo[]`)
- 400: Mais ativos do que o limite: use um filtro mais específico. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/symbols/total — Quantidade de ativos

Quantos ativos a corretora lista. Com `selected=true`, só os que o gateway acompanha (as cotações assinadas).

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `selected` (consulta, boolean): `true` para contar só os ativos assinados.

Respostas:

- 200: Quantidade. (`integer`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/book/{symbol} — Livro de ofertas

O servidor só transmite o livro ao vivo de **um ativo por vez**. Pedir o livro de outro ativo troca o livro acompanhado para ele (cerca de 200 ms), e o anterior deixa de ser atualizado, inclusive para quem assina `book.` no WebSocket.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo.

Respostas:

- 200: Livro. (`Book`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Ativo inexistente. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: O livro não chegou a tempo. (`Error`)

### DELETE /accounts/{login}/book/{symbol} — Parar o livro de ofertas

Para o livro do ativo na corretora. Responde `false` enquanto alguém assina `book.` do ativo em tempo real, ou quando o livro acompanhado é de outro ativo. Não precisa da permissão Negociação.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo.

Respostas:

- 200: `true` se parou. (`boolean`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/candles/{symbol} — Candles

Candles do mais antigo para o mais novo. Quando o intervalo chega até agora, o último é o candle em andamento (`in_progress: true`), montado pelo gateway. Para usar só candles fechados, descarte esse. Sem `from`, devolve os últimos `count` candles, pulando noites, fins de semana e feriados.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo.
- `timeframe` (consulta, string): Tempo gráfico. Padrão: `M1`.
- `count` (consulta, integer): Quantos candles (até 100000). Padrão: 100 quando não há `from`; com `from`, limita aos últimos `count` do intervalo. `to` com `count` equivale a `copy_rates_from` do pacote Python.
- `start_pos` (consulta, integer): Como `copy_rates_from_pos`: pula os `start_pos` candles mais recentes (0 é o que está se formando) e devolve os `count` anteriores. Não vai junto com `from`.
- `from` (consulta, string): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`).
- `to` (consulta, string): Fim, no mesmo formato. Padrão: agora.

Respostas:

- 200: Candles. (`Candle[]`)
- 400: Tempo gráfico, data ou quantidade inválidos. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Ativo inexistente. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### POST /accounts/{login}/trades/{symbol}/keep — Guardar os negócios recentes de um ativo

Não existe no pacote Python. Pede ao gateway que guarde, a partir de agora, os negócios (cotações com `flags` 8, último) que ele publica no tópico `tick.<CONTA>.<ATIVO>.`, para quem perder mensagens do tempo real relê-las em `GET /accounts/{login}/trades/{symbol}`: um cliente lento perde mensagens, e uma série que depende de cada negócio (o Renko por negócio do SDK) não pode perdê-las. O pedido vale 5 minutos: peça de novo antes (o SDK pede a cada minuto). Por padrão, o gateway guarda os 10 minutos mais recentes de cada ativo, e no total até 500.000 negócios de todos os ativos pedidos, saindo os mais velhos primeiro. Responde a vida do gateway (`epoch`, a das mensagens) e o número atual do tópico (`seq`, o da última mensagem; 0 antes da primeira): todo negócio depois dele fica guardado. Não assina o ativo: só vale para um ativo que a conta já acompanha (assine o tópico no tempo real e espere a primeira mensagem), e até 100 ativos por conta ao mesmo tempo. Qualquer chave pede; não precisa da corretora conectada.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo. Codifique `$` como `%24`.

Respostas:

- 200: Guardando. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada (não cadastrada, desativada ou de outro usuário), ou ativo que a conta não acompanha: nenhuma cotação dele saiu ainda no tempo real desta conta. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: A conta já guarda os negócios de 100 ativos: `code` -3, e pedir de novo não adianta enquanto ela não deixar de guardar outro. Com `code` -1, chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /accounts/{login}/trades/{symbol} — Reler os negócios recentes de um ativo

Não existe no pacote Python. Os negócios que o gateway guardou do tópico `tick.<CONTA>.<ATIVO>.` depois de um número (`seq` das mensagens), do mais antigo para o mais novo, até o número do tópico no momento do pedido (os seguintes chegam pelo tempo real), cada um como a mensagem do tempo real (sem `epoch`). Só os negócios: cotações sem negócio e mensagens da assinatura que se perderam não são relidas. `cut` diz que o pedido começa antes do que está guardado (o ativo foi pedido depois, os negócios saíram por idade ou pelo total, ou o pedido de guardar venceu): negócios entre `after` e `first` podem ter se perdido. Um `epoch` diferente do das mensagens diz que o gateway reiniciou: os números recomeçaram e o que veio antes se perdeu. Não precisa da corretora conectada.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório): Código do ativo. Codifique `$` como `%24`.
- `after` (consulta, integer): O último `seq` recebido: vêm os negócios depois dele. Padrão: 0 (todos os guardados).

Respostas:

- 200: Os negócios guardados depois do número. (`object`)
- 400: `after` não é um número inteiro. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Ordens

Envio, alteração e cancelamento de ordens.

### POST /accounts/{login}/order/check — Conferir um pedido sem enviar (order_check)

Faz as mesmas conferências do envio e calcula a conta como ficaria com o pedido, como a janela de ordem do terminal: margem, margem livre e nível de margem depois dele. Nada vai à corretora. `retcode` 0 ("Done") quando passa, 10019 quando falta dinheiro, o código da recusa nos outros casos. 501 onde o gateway ainda não calcula a conta.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Corpo (application/json): OrderRequest

Respostas:

- 200: A conferência. (`object`)
- 400: Pedido sem `action`. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 501: A conta ainda não é calculada para esta corretora ou modo de margem. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/calc/margin — Margem de um negócio (order_calc_margin)

A margem que um negócio toma sozinho, na moeda da conta. `type` é o tipo da ordem (0 compra, 1 venda, ou uma pendente).

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `type` (consulta, integer, obrigatório)
- `symbol` (consulta, string, obrigatório)
- `volume` (consulta, number, obrigatório)
- `price` (consulta, number, obrigatório)

Respostas:

- 200: A margem. (`object`)
- 400: Falta tipo, ativo, volume ou preço. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 501: A conta ainda não é calculada para esta corretora ou modo de margem. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/calc/profit — Lucro de um negócio entre dois preços (order_calc_profit)

O que um negócio de `type` (0 compra, 1 venda) e `volume` ganha ou perde de `price_open` a `price_close`, na moeda da conta.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `type` (consulta, integer, obrigatório)
- `symbol` (consulta, string, obrigatório)
- `volume` (consulta, number, obrigatório)
- `price_open` (consulta, number, obrigatório)
- `price_close` (consulta, number, obrigatório)

Respostas:

- 200: O lucro. (`object`)
- 400: Falta tipo, ativo, volume ou preço. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 501: A conta ainda não é calculada para esta corretora ou modo de margem. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/stops — Stops virtuais dos experts

O stop e o alvo de cada expert ficam com o gateway, que fecha a posição do expert quando o preço chega (pelo último negócio, depois do filtro de cotações), com uma ordem a mercado com o número mágico dele, mesmo com o expert parado. Numa conta netting (uma posição por ativo na corretora, dividida pelos experts que operam o ativo), vale para todo ativo: o gateway fecha só o volume daquele expert e mantém na posição da corretora um stop de proteção mais largo. Numa conta hedging (uma posição por ordem), vale para os ativos de bolsa (os da B3): a posição é fechada pelo ticket dela, e o stop de proteção, 50% além do stop do expert, vai com a ordem. `order` 0: os da posição do expert; o ticket de uma ordem pendente: os que ela leva quando for executada. `position`: numa conta hedging, o ticket da posição (0 numa conta netting).

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Os stops. (`object[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### POST /accounts/{login}/stops — Pôr ou tirar os stops virtuais de um expert

Em conta netting, e em conta hedging para os ativos de bolsa (409 nos outros: lá o stop vai na ordem, como sempre, e o preço da corretora é o mercado). Precisa da permissão de negociar. `sl` e `tp` 0 tiram os stops; `order` diz que valem para a posição que aquela ordem pendente abrir; numa conta hedging, `position` diz de qual posição são (um dos dois é obrigatório). Numa conta hedging, quem põe o stop por aqui cuida do stop de proteção na corretora: o gateway não mexe nele.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Corpo (application/json): object

- `magic` (integer, obrigatório)
- `symbol` (string, obrigatório)
- `order` (integer)
- `position` (integer)
- `sl` (number)
- `tp` (number)

Respostas:

- 200: Os stops como ficaram. (`object`)
- 400: Número mágico, ativo ou preço inválido; numa conta hedging, sem `position` nem `order`. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### POST /accounts/{login}/order — Enviar pedido

A resposta é sempre o resultado ([OrderSendResult](#model/ordersendresult)), com o código em `retcode` e o pedido recebido em `request`. Chega quando o servidor dá o resultado definitivo (até 30 segundos).

Ao mudar stop e alvo (`action` 6 de uma posição, ou 7 de uma ordem), o que não vier no pedido fica como está, e `0` remove; como no terminal web. Com a conta pausada (`POST /pause`), toda ordem volta recusada com 10027 sem ir à corretora.

Antes de enviar, o gateway faz as mesmas conferências que o terminal: volume fora das regras do ativo, validade não aceita ou sem data, preenchimento ou tipo de ordem que o ativo não aceita, ativo desabilitado ou só compra/só venda/só fechamento, ordem pendente do lado errado do mercado ou fora do limite de preço do dia, stop/alvo do lado errado ou perto demais do preço, alteração sem mudança, ativo, ordem ou posição inexistente. Uma recusa volta como qualquer outro resultado, com o código de retorno da recusa (tabela na introdução) e, em `comment`, o motivo em detalhe (por exemplo, `WINZ26 does not take ORDER_TIME_GTC; it takes ORDER_TIME_DAY, ORDER_TIME_SPECIFIED_DAY`). As conferências contra o preço de mercado usam a última cotação; um ativo ainda sem cotação é assinado e espera até 0,5 s por ela, e sem cotação essas conferências ficam para o servidor.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Corpo (application/json): OrderRequest

Respostas:

- 200: Resultado, do servidor ou da recusa do gateway (10024 quando passa do limite de ordens). Sucesso quando `retcode` é 10008, 10009 ou 10010. (`OrderSendResult`)
- 400: Pedido sem `action`. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 502: Falha inesperada no gateway. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### POST /accounts/{login}/pause — Pausar a conta

A partir daqui toda ordem da conta é recusada com o código 10027, venha de onde vier (experts, app, chaves de API); o que já foi enviado continua, e os stops dos experts que o gateway vigia continuam disparando. Com `flatten: true`, fecha tudo antes: cancela as ordens pendentes e encerra as posições, e responde quantas e o que a corretora recusou. Precisa do escopo de negociação.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Corpo (application/json): object

- `flatten` (boolean): Também cancelar as ordens e encerrar as posições.

Respostas:

- 200: Desde quando está pausada, e o que foi fechado. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: Pausada, mas sem conexão para fechar o que está aberto. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### POST /accounts/{login}/resume — Retomar a conta

A conta volta a enviar ordens. Precisa do escopo de negociação.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.

Respostas:

- 200: Retomada. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Histórico

Negócios e ordens encerradas.

### GET /accounts/{login}/history/deals/total — Quantidade de negócios

Como `history_deals_total(date_from, date_to)` do pacote Python: quantos negócios no período. `from` e `to` são obrigatórios.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `from` (consulta, string, obrigatório): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`). Padrão: 31 dias antes de `to`.
- `to` (consulta, string, obrigatório): Fim, no mesmo formato de `from`. Padrão: amanhã. Uma data sem hora é a meia-noite em que o dia começa: `to=2026-09-29` vai até o fim do dia 28 e deixa o dia 29 de fora; para incluí-lo, use `to=2026-09-30` ou `to=2026-09-29T23:59:59`.

Respostas:

- 200: Quantidade. (`integer`)
- 400: Sem `from` ou `to`, ou data inválida. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/history/orders/total — Quantidade de ordens encerradas

Como `history_orders_total(date_from, date_to)` do pacote Python: quantas ordens encerradas no período. `from` e `to` são obrigatórios.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `from` (consulta, string, obrigatório): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`). Padrão: 31 dias antes de `to`.
- `to` (consulta, string, obrigatório): Fim, no mesmo formato de `from`. Padrão: amanhã. Uma data sem hora é a meia-noite em que o dia começa: `to=2026-09-29` vai até o fim do dia 28 e deixa o dia 29 de fora; para incluí-lo, use `to=2026-09-30` ou `to=2026-09-29T23:59:59`.

Respostas:

- 200: Quantidade. (`integer`)
- 400: Sem `from` ou `to`, ou data inválida. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/ledger — A parte de cada expert

Numa conta netting a corretora guarda uma posição só por ativo, somando as ordens de todos os experts: a ordem com que um expert entra pode aparecer na corretora como saída da posição de outro. Aqui vai a parte de cada um, contada pelos negócios gravados de cada número mágico (0: ordens de nenhum expert): `positions`, a posição aberta de cada um, com o stop e o alvo virtuais dele; `deals`, o que cada negócio do período fez com a parte de cada um (`entry` 0 abriu ou aumentou, 1 reduziu ou fechou, 2 virou de lado), com o resultado (`profit`) e a fatia dos custos (`commission`); `results`, o total do período por expert; `symbols`, por ativo, a posição da corretora (`real`), a soma das partes (`virtual`) e o que nenhum negócio gravado explica (`unexplained`). Volumes com sinal: comprado positivo. Nas outras contas, 409: lá cada posição e negócio já é de um expert só.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `from` (consulta, string): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`). Padrão: 31 dias antes de `to`.
- `to` (consulta, string): Fim, no mesmo formato de `from`. Padrão: amanhã. Uma data sem hora é a meia-noite em que o dia começa: `to=2026-09-29` vai até o fim do dia 28 e deixa o dia 29 de fora; para incluí-lo, use `to=2026-09-30` ou `to=2026-09-29T23:59:59`.

Respostas:

- 200: As partes. (`object`)
- 400: Data inválida. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/history/deals — Negócios

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `from` (consulta, string): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`). Padrão: 31 dias antes de `to`.
- `to` (consulta, string): Fim, no mesmo formato de `from`. Padrão: amanhã. Uma data sem hora é a meia-noite em que o dia começa: `to=2026-09-29` vai até o fim do dia 28 e deixa o dia 29 de fora; para incluí-lo, use `to=2026-09-30` ou `to=2026-09-29T23:59:59`.
- `group` (consulta, string): Filtro pelo nome do ativo, como em `/symbols`: `*` é curinga, `!` exclui e as condições vão separadas por vírgula, inclusões primeiro. Exemplos: `WIN*`, `VALE3,PETR4`, `*,!EURUSD`.
- `ticket` (consulta, integer): Só os negócios da ordem com este número. Sem `from` e `to`, procura em todo o histórico.
- `position` (consulta, integer): Só os da posição com este número. Sem `from` e `to`, procura em todo o histórico.

Respostas:

- 200: Negócios no intervalo. (`Deal[]`)
- 400: Data ou número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /accounts/{login}/history/orders — Ordens encerradas

Ordens executadas, canceladas ou expiradas no intervalo.

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `from` (consulta, string): Início, na hora do servidor: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`). Padrão: 31 dias antes de `to`.
- `to` (consulta, string): Fim, no mesmo formato de `from`. Padrão: amanhã. Uma data sem hora é a meia-noite em que o dia começa: `to=2026-09-29` vai até o fim do dia 28 e deixa o dia 29 de fora; para incluí-lo, use `to=2026-09-30` ou `to=2026-09-29T23:59:59`.
- `group` (consulta, string): Filtro pelo nome do ativo, como em `/symbols`: `*` é curinga, `!` exclui e as condições vão separadas por vírgula, inclusões primeiro. Exemplos: `WIN*`, `VALE3,PETR4`, `*,!EURUSD`.
- `ticket` (consulta, integer): Só a ordem com este número. Sem `from` e `to`, procura em todo o histórico.
- `position` (consulta, integer): Só os da posição com este número. Sem `from` e `to`, procura em todo o histórico.

Respostas:

- 200: Ordens no intervalo. (`Order[]`)
- 400: Data ou número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Conta não conectada: não cadastrada, desativada ou de outro usuário. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

## B3

O histórico da B3 guardado pela plataforma a partir dos arquivos públicos da bolsa: todos os negócios de WIN, WDO, IND, DOL (por contrato e na série contínua, como `WIN@N`) e das 20 ações mais negociadas, desde 15/09/2026. Qualquer chave lê, sem conta em corretora, e um backtest roda nele com `source: "B3"`. Horários na hora de Brasília. Os negócios não trazem a melhor oferta de compra e venda: só o preço de cada negócio.

### GET /exchanges/B3/symbols — Ativos da B3

As séries contínuas dos futuros (`WIN@N`, `IND@N`, `WDO@N`, `DOL@N`), os contratos guardados (`WINZ26`) e as ações, com o primeiro e o último dia guardados (`null` quando ainda não há nenhum).

Respostas:

- 200: Ativos. (`object[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/B3/symbol/{symbol} — Regras de um ativo da B3

Como `symbol_info`, de uma tabela da plataforma: casas decimais, ponto, menor variação e quanto ela vale (em reais, por contrato ou ação), lote e passo de volume, spread de um tick. Os preços são os dos negócios (`chart_mode` 1).

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo. Codifique `@` como `%40`.

Respostas:

- 200: Regras. (`SymbolInfo`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/B3/candles/{symbol} — Candles da B3

Candles montados dos negócios: abertura, máxima, mínima e fechamento, `tick_volume` (negócios) e `real_volume` (contratos ou ações). Os tempos gráficos maiores saem dos de 1 minuto. Na série contínua, cada dia vem do contrato que ela segue, com os preços como foram negociados (sem ajuste). Até 366 dias por chamada e 100 000 candles; com `format=csv`, o ano inteiro como planilha para baixar, sem limite de candles (veja `POST /links` para um endereço que abre sem a chave).

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.
- `timeframe` (consulta, string): Tempo gráfico. Padrão: `M1`.
- `from` (consulta, string, obrigatório): Início, na hora de Brasília: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`).
- `to` (consulta, string, obrigatório): Fim, no mesmo formato.
- `format` (consulta, string): `json` (padrão) ou `csv`: o arquivo para baixar, separado por vírgula, com ponto decimal e `datetime` ao lado do horário.

Respostas:

- 200: Candles; com `format=csv`, a planilha (`time,datetime,open,high,low,close,tick_volume,real_volume`). (`Candle[]`)
- 400: Tempo gráfico ou período inválidos. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/B3/ticks/{symbol} — Negócios da B3, hora a hora

As horas de negócios do período, cada uma com o endereço do seu arquivo (assinado por uma hora), quantos negócios e o tamanho. Na série contínua, as horas do contrato que ela segue em cada dia. Até 31 dias por chamada. O SDK abre os arquivos (`tq.exchange("B3").copy_ticks_range`). Com `format=csv`, os próprios negócios como planilha para baixar, até 7 dias por chamada: `last` é o preço e `volume` os contratos ou ações (a bolsa não tem `bid` nem `ask`, que vêm 0).

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.
- `from` (consulta, string, obrigatório): Início, na hora de Brasília.
- `to` (consulta, string, obrigatório): Fim, no mesmo formato.
- `format` (consulta, string): `json` (padrão) ou `csv`: o arquivo para baixar, separado por vírgula, com ponto decimal e `datetime` ao lado do horário.

Respostas:

- 200: Horas; com `format=csv`, a planilha dos negócios (`time,datetime,time_msc,bid,ask,last,volume,flags`). (`object`)
- 400: Período inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/B3/series/{symbol} — O contrato que a série segue hoje

O contrato do futuro que a série contínua segue hoje (dia de Brasília), o seguinte e o dia em que ele vence: o que uma execução na série opera. A série troca no primeiro pregão depois de um em que o contrato seguinte negociou mais, o mesmo critério dos testes; antes do arquivo do dia chegar (depois do pregão), conta o que cada contrato negociou no último dia guardado. Nunca um contrato que já venceu.

Parâmetros:

- `symbol` (caminho, string, obrigatório): A série: WIN@N, IND@N, WDO@N ou DOL@N.

Respostas:

- 200: O contrato. (`object`)
- 400: Não é uma série contínua. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo, ou nenhum dia dele ainda. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/B3/rolls/{symbol} — Trocas de contrato da série contínua

Quando a série contínua trocou de contrato no período: no primeiro pregão depois de um em que o contrato seguinte negociou mais contratos que o atual. Num backtest, o que estiver aberto na troca é fechado no último preço do contrato antigo, com os custos de um negócio comum, e as ordens pendentes são canceladas. Vazio para um contrato ou uma ação.

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.
- `from` (consulta, string, obrigatório): Início, na hora de Brasília.
- `to` (consulta, string, obrigatório): Fim, no mesmo formato.

Respostas:

- 200: Trocas. (`object[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Binance

O histórico da Binance guardado pela plataforma a partir dos arquivos públicos dela (data.binance.vision): todos os negócios do mercado à vista de BTCUSDT, ETHUSDT e EURUSDT, um dia UTC por vez, desde 01/07/2025. Qualquer chave lê, sem conta, e um backtest roda nele com `source: "BINANCE"`. Horários UTC; 1 lote é 1 BTC (ou 1 ETH), de 0,001 em 0,001, e os preços em USDT andam de 0,01 em 0,01 (no EURUSDT, 1 lote é 1 euro, de 0,1 em 0,1, e o preço anda de 0,0001 em 0,0001); e lucros em USDT contados como dólares. Os negócios trazem quem agrediu (`flags`: 32, `TICK_FLAG_BUY`, o comprador tomou a oferta; 64, `TICK_FLAG_SELL`, o vendedor bateu na compra), mas não a melhor oferta de compra e venda. As rotas são as da B3 (`/symbols`, `/symbol`, `/candles`, `/ticks`, `/rolls`), em `/exchanges/BINANCE`; não há série contínua.

### GET /exchanges/BINANCE/symbols — Ativos da Binance

BTCUSDT, ETHUSDT e EURUSDT, do mercado à vista, com o primeiro e o último dia guardados (dias UTC; `null` quando ainda não há nenhum).

Respostas:

- 200: Ativos. (`object[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/BINANCE/symbol/{symbol} — Regras de um ativo da Binance

Como `symbol_info`, de uma tabela da plataforma: 2 casas, ponto e menor variação de 0,01 (o `tickSize` do mercado à vista), 1 lote = 1 BTC (ou 1 ETH), de 0,001 em 0,001 (no EURUSDT: 4 casas e 0,0001, 1 lote = 1 euro, de 0,1 em 0,1), lucros em USDT contados como dólares (`currency_profit` `USD`), spread de um tick, preços dos negócios (`chart_mode` 1). Sem margem própria (`trade_calc_mode` 33, `margin_initial` 0): num teste, só a de `costs.margin`.

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.

Respostas:

- 200: Regras. (`SymbolInfo`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/BINANCE/candles/{symbol} — Candles da Binance

Como `/exchanges/B3/candles/{symbol}`, em UTC: `tick_volume` é o número de negócios agregados (`aggTrades`) e `real_volume` o volume em BTC (ou ETH).

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.
- `timeframe` (consulta, string): Tempo gráfico. Padrão: `M1`.
- `from` (consulta, string, obrigatório): Início, em UTC: segundos Unix ou data sem fuso (`2026-09-29` ou `2026-09-29T10:00`).
- `to` (consulta, string, obrigatório): Fim, no mesmo formato.
- `format` (consulta, string): `json` (padrão) ou `csv`: o arquivo para baixar, separado por vírgula, com ponto decimal e `datetime` ao lado do horário.

Respostas:

- 200: Candles; com `format=csv`, a planilha. (`Candle[]`)
- 400: Tempo gráfico ou período inválidos. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /exchanges/BINANCE/ticks/{symbol} — Negócios da Binance, hora a hora

Como `/exchanges/B3/ticks/{symbol}`, em horas UTC: até 31 dias por chamada, ou com `format=csv` os próprios negócios, até 7 dias. `last` é o preço, `volume` a quantidade em BTC (ou ETH), `bid` e `ask` vêm 0, e `flags` diz quem agrediu: 56 (último, volume e `TICK_FLAG_BUY`) quando o comprador tomou a oferta, 88 (`TICK_FLAG_SELL`) quando o vendedor bateu na compra.

Parâmetros:

- `symbol` (caminho, string, obrigatório): Código do ativo.
- `from` (consulta, string, obrigatório): Início, em UTC.
- `to` (consulta, string, obrigatório): Fim, no mesmo formato.
- `format` (consulta, string): `json` (padrão) ou `csv`: o arquivo para baixar, separado por vírgula, com ponto decimal e `datetime` ao lado do horário.

Respostas:

- 200: Horas; com `format=csv`, a planilha dos negócios (`time,datetime,time_msc,bid,ask,last,volume,flags`). (`object`)
- 400: Período inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: A plataforma não guarda este ativo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Experts e backtests

Seus experts (robôs escritos com o SDK `@troiaquants/sdk`) e os backtests e otimizações deles nos servidores da plataforma. Os servidores atendem todos os usuários com poucos testes ao mesmo tempo, divididos de forma justa: um pedido pode esperar a vez. Cada backtest no servidor custa créditos, debitados quando ele termina bem; um que falha ou é cancelado não custa nada. Ler é com qualquer chave; escrever experts e rodar backtests pede a permissão **Backtests**.

### GET /experts — Seus experts

Os experts guardados na sua conta, sem o arquivo (veja `GET /experts/{id}`).

Respostas:

- 200: Experts. (`ExpertSummary[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /experts — Guardar um expert

Guarda um arquivo de expert. O arquivo é lido numa área isolada do servidor, sem rede: o nome (o `title` da classe, quando `name` não vem) e os parâmetros (`input`) saem dele. Precisa da permissão **Backtests**.

Corpo (application/json): object

- `code` (string, obrigatório): O arquivo: um módulo JavaScript que exporta uma classe que estende `Expert` e só importa `@troiaquants/sdk`. Até 512 KB.
- `name` (string): Nome; o do arquivo quando não vem.
- `file_name` (string): Nome do arquivo (`.js`); feito do nome quando não vem.
- `notes` (ExpertNotesInput)

Respostas:

- 201: O expert guardado. (`Expert`)
- 400: O arquivo não pôde ser lido (o motivo vem em `error`). (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 409: Já há 100 experts na conta. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /experts/{id} — Um expert, com o arquivo

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do expert.

Respostas:

- 200: O expert. (`Expert`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é um expert seu. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### PATCH /experts/{id} — Alterar um expert

Uma versão nova do arquivo (os parâmetros são lidos de novo), outro nome, outro nome de arquivo ou as anotações (`notes`: cada uma que vier substitui a anterior, as outras ficam; anotações não são versão nova e não reiniciam nada). Um arquivo diferente sobe `code_version` em 1, e o expert que estiver rodando recomeça sozinho com ele em até 15 segundos, como ao recompilar no terminal: `OnDeinit` recebe `REASON_RECOMPILE` (2), e o `OnInit` da versão nova roda com os mesmos parâmetros. As posições e ordens ficam como estão. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do expert.

Corpo (application/json): object

- `code` (string): O arquivo novo.
- `name` (string): Nome.
- `file_name` (string): Nome do arquivo.
- `notes` (ExpertNotesInput)

Respostas:

- 200: O expert alterado. (`Expert`)
- 400: O arquivo não pôde ser lido, ou nada para mudar. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é um expert seu. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /experts/{id} — Remover um expert

Remove o expert e os backtests dele. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do expert.

Respostas:

- 204: Removido.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é um expert seu. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /credits — Seus créditos

O saldo, o que os backtests esperando ou rodando no servidor reservam, o que sobra e quanto custa um backtest no servidor.

Respostas:

- 200: Créditos. (`Credits`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /backtests — Seus backtests

Do mais novo ao mais antigo, os feitos no app (no seu computador ou no servidor) e pela API, sem o relatório (veja `GET /backtests/{id}`).

Parâmetros:

- `expert_id` (consulta, integer): Só os deste expert.
- `limit` (consulta, integer): Quantos (padrão 50, até 200).
- `before_id` (consulta, integer): Os anteriores a este id, para a próxima página.

Respostas:

- 200: Backtests. (`Backtest[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /backtests — Rodar um backtest no servidor

Põe o backtest na fila dos servidores da plataforma e responde na hora, com `status: queued`. Acompanhe com `GET /backtests/{id}` até `done` (com o relatório), `failed` (com o motivo em `error`) ou `cancelled`. Os candles vêm da corretora da conta indicada, que precisa estar conectada. Custa os créditos de `backtest_cost` (`GET /credits`), reservados enquanto espera e debitados só se terminar bem. Com `processed_on: local`, guarda um backtest que já rodou no seu computador (pelo SDK), com o relatório, sem custo; o corpo pode vir comprimido (`Content-Encoding: gzip`), até 16 MB descomprimido. Precisa da permissão **Backtests**.

Corpo (application/json): object

- `expert_id` (integer, obrigatório): O expert.
- `source` (string): `B3`: o histórico da própria bolsa, guardado pela plataforma (veja as rotas `/exchanges/B3`), sem conta. `BINANCE`: o da Binance, BTCUSDT, ETHUSDT e EURUSDT do mercado à vista (rotas `/exchanges/BINANCE`), também sem conta. Sem ele, os candles vêm da corretora de `login`.
- `login` (integer): Número da conta de onde vêm os candles (sem `source`).
- `server` (string): Servidor da conta; só quando o mesmo número existe em duas corretoras.
- `symbol` (string, obrigatório): Ativo.
- `timeframe` (string): Tempo gráfico do expert (padrão M1).
- `from` (string, obrigatório): Primeiro dia, na hora do servidor da corretora.
- `to` (string, obrigatório): Último dia (inclusive).
- `deposit` (number): Depósito inicial (padrão 10 000), na moeda da conta (com `source`, a dos lucros do ativo): os resultados saem nela.
- `model` (string): `ohlc_m1` (padrão): cotações geradas dos candles de 1 minuto. `open_prices`: só a abertura de cada candle do tempo gráfico. `real_ticks`: as cotações gravadas pela plataforma.
- `inputs` (object): Valores dos parâmetros do expert; os que faltam ficam no padrão. Um parâmetro de ativo (`type: symbol`) é o nome de um ativo do histórico do teste (o expert lê e opera os dois, numa fila só de cotações), ou `{ login, server, symbol }` (ou `{ account_id, symbol }`): um ativo noutra conta, de qualquer corretora. O teste opera em cada conta escolhida, cada uma simulada à parte, com o mesmo depósito, no relógio da sua corretora (as cotações de todas postas num relógio só), e o relatório traz `accounts`: cada conta, e no topo o total. Até 5 contas.
- `costs` (object): Os custos do teste. Sem eles, só o spread: o relatório avisa em `warnings`.
- `processed_on` (string): `server` (padrão): roda nos servidores. `local`: já rodou no seu computador; vem com `report`.
- `report` (object): Com `local`: o relatório do SDK (`BacktestReport`).
- `currency` (string): Com `local`: a moeda dos lucros do ativo.
- `seconds` (number): Com `local`: quanto o teste levou.

Respostas:

- 201: Na fila (ou, com `local`, guardado e terminado). (`Backtest`)
- 400: Parâmetros que não servem (o motivo vem em `error`). (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 402: Créditos insuficientes. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: O expert ou a conta não são seus. (`Error`)
- 429: Já há 50 backtests seus esperando ou rodando no servidor. (`Error`)

### GET /backtests/{id} — Um backtest, com o relatório

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do backtest.

Respostas:

- 200: O backtest; `report` vem quando ele terminou bem. (`Backtest`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é um backtest seu. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /backtests/{id} — Apagar um backtest

Apaga um backtest que já terminou. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do backtest.

Respostas:

- 204: Apagado.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é um backtest seu. (`Error`)
- 409: Ele ainda espera ou roda: cancele antes. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /backtests/{id}/files/robot/{name} — Um arquivo que o expert escreveu no teste

O que o expert escreveu com `FileOpen` e `FileWrite` durante o teste, como escreveu (o relatório lista em `files` cada nome). Também por um endereço de `POST /links`.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do backtest.
- `name` (caminho, string, obrigatório): O nome do arquivo.

Respostas:

- 200: O arquivo. (`string`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: O teste não é seu, ou o expert não escreveu esse arquivo. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /backtests/{id}/files/{file} — Um arquivo do relatório

As listas longas do relatório de um backtest terminado, como arquivos para baixar: `deals.csv` (todos os negócios), `orders.csv` (todas as ordens), `equity.csv` (a curva de saldo e patrimônio) e `journal.txt` (as últimas 1000 linhas do diário). As planilhas vêm separadas por vírgula, com ponto decimal, os campos pelos nomes de `GET /backtests/{id}` e `datetime` ao lado do horário, na hora do servidor. `POST /links` dá um endereço que abre o arquivo sem a chave.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do backtest.
- `file` (caminho, string, obrigatório): O arquivo.

Respostas:

- 200: O arquivo. (`string`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é um backtest seu, ou o arquivo não existe. (`Error`)
- 409: O backtest ainda não terminou bem: os arquivos vêm com o relatório. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /backtests/{id}/cancel — Cancelar um backtest

Para um backtest que espera ou roda no servidor. Não custa nada. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do backtest.

Respostas:

- 200: Cancelado. (`Backtest`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é um backtest seu. (`Error`)
- 409: Ele já tinha terminado. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /optimizations — Suas otimizações

Do mais novo ao mais antigo, as feitas no app (no seu computador ou no servidor) e pela API: o que foi pedido, quantas combinações foram testadas, a melhor e o que custou.

Parâmetros:

- `expert_id` (consulta, integer): Só as deste expert.

Respostas:

- 200: Otimizações. (`Optimization[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations — Otimizar no servidor

O mesmo backtest com várias combinações de parâmetros, nos servidores da plataforma. Responde na hora, com `status: queued`; acompanhe com `GET /optimizations/{id}` e veja as melhores com `GET /optimizations/{id}/passes`. Cada combinação testada custa os créditos de `backtest_cost`, debitados quando ela termina (uma que falha não custa nada); quando o saldo não paga a próxima, a otimização para e pode continuar depois (`/resume`). Com `dry_run: true`, só responde quantas combinações e testes ela teria e o máximo que custaria. Com `processed_on: local`, guarda uma otimização que roda no seu computador (pelo SDK), sem custo: as combinações chegam por `POST /optimizations/{id}/passes` e o fim por `PATCH /optimizations/{id}`. Precisa da permissão **Backtests**.

Corpo (application/json): object

- `expert_id` (integer, obrigatório): O expert.
- `source` (string): Como em `POST /backtests`.
- `login` (integer): Conta de onde vêm os candles (sem `source`).
- `server` (string): Servidor da conta, quando o número existe em duas corretoras.
- `symbol` (string, obrigatório): Ativo.
- `timeframe` (string): Tempo gráfico (padrão M1).
- `from` (string, obrigatório): Primeiro dia.
- `to` (string, obrigatório): Último dia (inclusive).
- `deposit` (number): Depósito inicial (padrão 10 000).
- `model` (string): Como em `POST /backtests`.
- `ranges` (object[], obrigatório): Os parâmetros que variam: `{ name, start, step, stop }` (números) ou `{ name, values }` (lista).
- `fixed` (object): Valores dos outros parâmetros (os que faltam ficam no padrão). Um parâmetro de ativo pode ser `{ login, server, symbol }`: um ativo noutra conta, fixo (não varia na busca), como em `POST /backtests`.
- `method` (string): `genetic` (padrão): testa poucas e mistura as melhores. `complete`: todas as combinações (até 100 000).
- `criterion` (string): Como medir a melhor (padrão `sharpe_ratio`); `custom` é o que o `OnTester` do expert devolve.
- `seed` (integer): Os dados da busca genética; a mesma semente faz o mesmo caminho (sorteada quando falta).
- `costs` (object): Os custos do teste. Sem eles, só o spread: o relatório avisa em `warnings`.
- `forward` (string): A conferência fora da amostra: o trecho final guardado da busca, `1/2`, `1/3` ou `1/4` dos dias do período, ou a partir de um dia. A busca roda só antes dele; depois as melhores rodam de novo nele, cada uma custando um teste, e cada combinação conferida traz `forward` com os números dela ali.
- `forward_top` (integer): Quantas das melhores conferir (padrão 10, até 100).
- `max_tests` (integer): No máximo quantos testes: a otimização para ao chegar nele. Sem ele, a busca genética faz até 3.200 (64 por geração, 50 gerações; costuma parar antes). Em `complete`, menor que o número de combinações é recusado.
- `processed_on` (string): `server` (padrão): roda nos servidores. `local`: roda no seu computador, que manda as combinações.
- `dry_run` (boolean): Só calcula o tamanho e o custo máximo, sem rodar.

Respostas:

- 200: Com `dry_run`: `combinations`, `tests` (o máximo de testes que ela pode rodar), `cost_per_test`, `max_credits` (o máximo que pode custar), o saldo (`credits`), onde começa o histórico da corretora no período (`history_from`) e os avisos (`warnings`: por exemplo, o histórico começa depois do pedido).
- 201: Na fila (ou, com `local`, rodando), com o `plan` (o mesmo do `dry_run`). (`Optimization`)
- 400: Parâmetros que não servem, ou que o expert não tem (o motivo vem em `error`). (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 402: O saldo não paga uma combinação. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: O expert ou a conta não são seus. (`Error`)
- 429: Já há 2 otimizações suas esperando ou rodando no servidor. (`Error`)

### GET /optimizations/{id} — Uma otimização

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Respostas:

- 200: A otimização. (`Optimization`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### PATCH /optimizations/{id} — Mudar o estado de uma otimização

De uma que roda no seu computador: `running` (continua), `stopped`, `done` ou `failed` (com o motivo em `error`). De uma no servidor: `stopped` ou `queued` (como `/stop` e `/resume`). Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Corpo (application/json): object

- `status` (string, obrigatório): O novo estado.
- `error` (string): Com `failed`: por que os testes não rodaram.

Respostas:

- 200: A otimização. (`Optimization`)
- 400: Um estado que não serve para ela. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /optimizations/{id} — Apagar uma otimização

Apaga uma otimização e as combinações dela. Uma que espera ou roda no servidor precisa ser parada antes. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Respostas:

- 204: Apagada.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 409: Ela ainda espera ou roda: pare antes. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations/{id}/forward — Guardar a conferência

A conferência de uma otimização com `processed_on: local` e `forward`: as melhores combinações testadas de novo no trecho guardado, até 100. Cada resultado: `index` (o número da combinação, em dígitos num texto), `statistics` (os 42 números; vazio se falhou), `value` (pelo critério) e `error`. Mandar de novo substitui. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Corpo (application/json): object

- `results` (object[], obrigatório)

Respostas:

- 200: `checked`: quantas foram guardadas.
- 400: Resultados que não servem, ou de uma combinação não testada. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 409: Ela roda no servidor, ou foi pedida sem conferência. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /optimizations/{id}/passes — As combinações testadas

As combinações testadas, da melhor para a pior pelo critério da otimização: os parâmetros, os 42 números do teste (`statistics`, pelos índices `STAT_*`) e o motivo de uma que falhou. Todas saem de página em página com `offset`; o `tested` da otimização diz quantas são.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.
- `limit` (consulta, integer): Quantas (padrão 20, até 500).
- `offset` (consulta, integer): Quantas pular, das melhores: 500 traz a página seguinte às 500 primeiras (padrão 0).

Respostas:

- 200: Combinações.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations/{id}/passes — Guardar combinações testadas

As combinações que o seu computador testou desde a última vez, de uma otimização com `processed_on: local`: até 200 por vez. Uma que já estava guardada é ignorada, então mandar de novo não faz mal. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Corpo (application/json): object

- `passes` (object[], obrigatório): Cada uma: `index` (o número da combinação, em dígitos num texto: pode passar do que um número guarda com exatidão), `inputs`, `statistics` (os 42 números, pelos índices `STAT_*`; vazio se falhou), `value` (a posição pelo critério) e `error`.

Respostas:

- 200: `added` (as novas) e `tested` (o total).
- 400: Combinações que não servem. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Backtests. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 409: Ela roda no servidor, que manda as combinações. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations/{id}/stop — Parar uma otimização

Para de testar combinações no servidor; o que foi testado fica guardado. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Respostas:

- 200: Parada. (`Optimization`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 409: Ela não estava rodando. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations/{id}/resume — Continuar uma otimização

Volta à fila do servidor e continua das combinações que já tem, sem testar nenhuma de novo. Precisa da permissão **Backtests** e de saldo para uma combinação.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Respostas:

- 200: Na fila. (`Optimization`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 402: O saldo não paga uma combinação. (`Error`)
- 409: Ela já está na fila, rodando ou terminada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /optimizations/{id}/robustness — Testar a robustez de uma combinação

Testa de novo, nos servidores, uma combinação da otimização (`inputs`; a melhor quando falta), no trecho que ela buscou, cada teste custando os créditos de um backtest. `kind: neighbors`: todas as combinações a `reach` passos dela na grade (1 a 3). `kind: costs`: ela `runs` vezes (10 a 500, padrão 50), cada sorteio com os custos entre as duas pontas de `costs` (`{ slippage: [0, 3] }`, escorregamento e spread em ticks inteiros; sem ele, dos custos da otimização até piores). É uma otimização de todas as combinações, com `robustness` nas configurações. Com `dry_run: true`, só o tamanho e o custo. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da otimização.

Corpo (application/json): object

- `kind` (string, obrigatório)
- `inputs` (object)
- `reach` (integer): Passos de cada lado (neighbors).
- `runs` (integer): Sorteios (costs).
- `costs` (object): As duas pontas de cada custo: `commission`, `fee_percent`, `slippage`, `spread`.
- `dry_run` (boolean)

Respostas:

- 200: Com `dry_run`: `combinations`, `tests`, `cost_per_test`, `max_credits` e o saldo.
- 201: A otimização de robustez, na fila. (`Optimization`)
- 400: Um tipo, um alcance ou custos que não servem. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma otimização sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /walk-forwards — Janelas que avançam

Os walk forwards, do mais novo ao mais antigo, cada um com as rodadas: os trechos, a otimização da rodada, a melhor combinação e o que ela fez onde operou (`best.forward`). `?expert_id=` filtra por expert.

Parâmetros:

- `expert_id` (consulta, integer): Só os deste expert.

Respostas:

- 200: Walk forwards.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /walk-forwards — Rodar janelas que avançam

Corta o período em rodadas: cada uma otimiza `search_months` meses e opera a melhor combinação nos `check_months` seguintes; a rodada seguinte começa esse tanto depois. Recebe o que `POST /optimizations` recebe, menos `forward` e `forward_top`. Nos servidores as rodadas rodam uma depois da outra, e cada uma custa o que a otimização dela custa, mais um teste para operar a melhor. Com `dry_run: true`, só as rodadas, os testes e o custo máximo. Com `processed_on: local`, guarda janelas que o seu computador roda (pelo SDK): cada rodada é uma otimização com `walk_forward_id` e `walk_forward_round`. Precisa da permissão **Backtests**.

Corpo (application/json): object

- `search_months` (integer, obrigatório): Quantos meses cada rodada otimiza (1 a 60).
- `check_months` (integer, obrigatório): Quantos meses a melhor de cada rodada opera depois (1 a 24).

Respostas:

- 200: Com `dry_run`: `rounds`, `tests`, `cost_per_test`, `max_credits` e o saldo.
- 201: As janelas, com a primeira rodada na fila (ou, com `local`, rodando).
- 400: Meses que não cabem no período, ou o que a otimização recusaria. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /walk-forwards/{id} — Ver janelas que avançam

Onde as janelas estão e as rodadas: em cada uma, a melhor combinação, os números dela na busca (`statistics`) e onde operou depois (`forward`).

Parâmetros:

- `id` (caminho, integer, obrigatório): Id das janelas.

Respostas:

- 200: As janelas.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não são janelas suas. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### PATCH /walk-forwards/{id} — Mudar o estado das janelas

Das que o seu computador roda: `running`, `stopped`, `done` ou `failed` com `error`. Das do servidor: `stopped` ou `running` de novo (como `/stop` e `/resume`). Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id das janelas.

Respostas:

- 200: As janelas.
- 400: Um estado que não serve para elas. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /walk-forwards/{id} — Apagar janelas que avançam

Apaga as janelas e as otimizações das rodadas. As que rodam no servidor precisam ser paradas antes. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id das janelas.

Respostas:

- 204: Apagadas.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 409: Elas ainda rodam: pare antes. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /walk-forwards/{id}/stop — Parar janelas que avançam

Para a rodada que espera ou roda no servidor, e as janelas com ela; o que foi testado fica guardado. Precisa da permissão **Backtests**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id das janelas.

Respostas:

- 200: Paradas.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 409: Elas não estavam rodando. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /walk-forwards/{id}/resume — Continuar janelas que avançam

Continua no servidor da rodada em que parou. Precisa da permissão **Backtests** e de saldo para um teste.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id das janelas.

Respostas:

- 200: Rodando de novo.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 402: O saldo não paga um teste. (`Error`)
- 409: Elas já rodam, ou terminaram. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /backtests/portfolio — Testes juntos numa carteira

Backtests já terminados (de 2 a 20, na mesma moeda) juntos, como robôs rodando lado a lado: cada teste, o conjunto (`whole`: o que cada um depositou somado, as curvas somadas, o lucro, a maior queda e os números dessa soma pelas constantes `STAT_*`; a curva com até 2000 pontos) e o quanto eles andam juntos (`correlation`: a correlação do resultado de cada dia entre cada par, de -1 sempre opostos a 1 sempre juntos; `null` com menos de 3 dias em comum). Não roda teste novo e não custa créditos. Testes que não se cruzam no tempo vêm com um aviso. Qualquer chave lê.

Corpo (application/json): object

- `ids` (integer[], obrigatório): Os ids dos backtests.

Respostas:

- 200: A carteira. (`object`)
- 400: Menos de 2 ou mais de 20 testes, um que não terminou, ou moedas diferentes. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Um dos testes não é seu. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## IA

Modelos de IA que a plataforma oferece, para processar dados por créditos. Um modelo de decisão (hoje `typesafe-ai/jev`) lê um **estado** (os dados: um texto, um objeto JSON ou partes dos dois) e responde **perguntas** tipadas sobre ele, várias de uma vez: `choice` escolhe uma das opções, `score` dá uma posição numa escala de níveis e `boolean` dá a probabilidade de sim, cada uma com as probabilidades por trás. Um expert faz o mesmo no código, com `this.ai_decide`, ao vivo e no backtest. Cada chamada custa créditos (o custo do modelo vezes o preço da plataforma; `GET /ai/models` diz o preço por milhão de tokens), quase sempre uma fração de um, e fica registrada com os tokens e os créditos em `GET /ai/usage`. Qualquer chave chama.

### GET /ai/models — Modelos de IA

Os modelos oferecidos: o que cada um faz, os tipos de pergunta que responde, os limites de tokens e o preço agora em créditos por milhão de tokens (`price` null enquanto a IA não estiver aberta).

Respostas:

- 200: Modelos. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /ai/decide — Perguntar a um modelo de IA

O modelo lê o estado e responde as perguntas. Cada chamada custa créditos (`credits`, com até 6 casas: as frações somam, e cada crédito inteiro sai do saldo) e fica no consumo; sem saldo, responde 402 antes de chamar o modelo. Uma pergunta que o modelo recusa vem como `{ "type": "refusal" }`, e as outras valem. `origin`, `expert_id`, `backtest_id` e `optimization_id` dizem de onde vem a chamada, para o consumo de cada expert: quem roda o expert diz (o SDK faz isso sozinho).

Corpo (application/json): object

- `model` (string, obrigatório): O modelo (veja `GET /ai/models`).
- `state` (string | object | object[], obrigatório): Os dados: um texto, um objeto JSON, ou uma lista de partes `{ "type": "text", "text" }` e `{ "type": "json", "value" }`, na ordem.
- `questions` (object, obrigatório): As perguntas pelo nome (letras, números, `_ . -`), de 1 a 32. Cada uma tem `type` e `instructions` (o que julgar, opcional), e `criteria`: em `choice`, `{ opção: descrição }` (de 1 a 64 opções; a descrição pode ser null); em `score`, a lista dos níveis do mais baixo (índice 0) ao mais alto; em `boolean` (opcional), `{ "true": ..., "false": ... }`.
- `origin` (string): De onde vem: um expert ao vivo, um backtest, um teste de otimização, ou uma chamada própria (`api`, o padrão).
- `expert_id` (integer): O expert a que a chamada pertence.
- `backtest_id` (integer): O backtest nos servidores que a fez.
- `optimization_id` (integer): A otimização que a fez.

Respostas:

- 200: As respostas e o custo. (`AiDecision`)
- 400: Pedido malformado (o que está errado vem em `error`), ou recusado pelo modelo. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 402: Sem créditos. (`Error`)
- 404: Modelo desconhecido, ou expert, backtest ou otimização que não são seus. (`Error`)
- 429: O modelo está ocupado: tente de novo em instantes. (`Error`)
- 502: O modelo falhou (a chamada fica registrada, sem custo). (`Error`)
- 503: A IA não está disponível agora, ou ainda não foi aberta. (`Error`)
- 504: O modelo não respondeu a tempo. (`Error`)

### GET /ai/usage — Consumo de IA

O que as chamadas consumiram num período (padrão: os últimos 30 dias), de todos os experts ou de um: o total, por modelo, por expert (`expert_id` null: chamadas sem expert, ou de um removido), por origem e por dia (os dias do seu fuso), e as chamadas, da mais nova para a mais antiga. As que falharam aparecem, sem custo.

Parâmetros:

- `from` (consulta, string): Início: segundos Unix, um momento ISO com fuso, ou um dia `YYYY-MM-DD` (desde o começo dele, no seu fuso).
- `to` (consulta, string): Fim, do mesmo jeito (um dia vai até o fim dele). Padrão: agora.
- `expert_id` (consulta, integer): Só deste expert.
- `limit` (consulta, integer): Quantas chamadas listar (padrão 50, até 500; 0 só as somas).
- `before_id` (consulta, integer): As chamadas antes desta, para a próxima página.

Respostas:

- 200: Consumo. (`AiUsage`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Experts ao vivo

Seus experts rodando numa conta de corretora. Pela API (e por um agente de IA) um expert roda sempre nos servidores da plataforma e continua com todos os computadores desligados: ninguém garante que o app esteja aberto em algum lugar. Um expert guardado pela API roda só nos servidores, também quando ligado pelo app. A hora nos servidores custa créditos (`GET /runs` diz o preço e quantas horas o saldo paga); sem créditos o expert para, e as posições e ordens ficam como estão. Ler é com qualquer chave; ligar, parar, pausar e zerar pede a permissão **Negociação**.

### GET /runs — Suas execuções

Todas as execuções dos seus experts, as que rodam primeiro: o mesmo expert roda quantas vezes você quiser, cada execução com o seu id (a conta, o ativo, o tempo gráfico, o número mágico e os parâmetros dela). E o custo dos servidores: o preço da hora de uma execução (`credits_per_hour`, 0 enquanto não é cobrado), quantas rodam lá e quantas horas os créditos livres pagam.

Respostas:

- 200: Execuções. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /experts/{id}/runs — Ligar uma execução nova de um expert

Uma execução nova do expert, nos servidores da plataforma, que a assumem em até 15 segundos: o mesmo expert pode rodar ao mesmo tempo em outra conta, ativo ou número mágico. O que não vier é o que a execução mais nova dele usou, ou o que o expert guarda; sem `magic`, o primeiro número livre na conta a partir de 1000 mais o id do expert. O ativo é conferido na corretora na hora (um contrato vencido é recusado). Depois de ligar, veja `GET /runs/{id}`: `alive` diz que ela já roda, e `status: failed` com `error` diz por que não começou. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id do expert.

Corpo (application/json): object

- `account_id` (integer): A conta (o id de `GET /accounts`).
- `login` (integer): Ou o número da conta.
- `server` (string): O servidor, quando o número está em duas corretoras.
- `symbol` (string): O ativo, como a corretora chama. `WIN@N`, `WDO@N`, `IND@N` ou `DOL@N` seguem o contrato vigente do futuro da B3 (`GET /exchanges/B3/series/{symbol}`): a execução opera nele e, no dia em que a série troca de contrato, assim que o contrato velho volta a ser negociado, a plataforma fecha o que ela tem nele e a recomeça no novo. Num contrato fixo, ela fica nele, com um aviso dias antes do vencimento. O mesmo vale para um parâmetro de ativo.
- `timeframe` (string): O tempo gráfico: M1, M5, M15, M30, H1, H4, D1...
- `magic` (integer): O número mágico, que separa as ordens da execução. Duas execuções nunca têm o mesmo numa conta.
- `inputs` (object): Os valores dos parâmetros, por nome. Um parâmetro de ativo (`type: symbol`) é `{ login, server, symbol }` ou `{ account_id, symbol }`: um ativo numa conta de qualquer corretora; a execução opera em cada conta escolhida, com o mesmo número mágico. Sem a conta e o ativo da execução, valem os do primeiro parâmetro de ativo.
- `limits` (object): Limites de risco, na moeda da primeira conta: `daily_loss` (perda máxima do dia, fechada e aberta, desde a meia-noite do seu fuso) e `max_drawdown` (queda máxima do resultado a partir de um pico desde que ligou); 0 tira. Ao chegar num deles, a plataforma zera a execução e a para (`limit_hit` diz qual).
- `place` (string): Sempre `cloud`: pela API um expert não roda num computador.

Respostas:

- 201: A execução, enviada aos servidores. (`ExpertRun`)
- 400: Falta a conta, o ativo ou o tempo gráfico de um expert que nunca rodou. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: O expert, a conta ou o ativo não existem. (`Error`)
- 409: O expert está desativado, ou outra execução tem esse número mágico na conta. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /runs/{id} — Uma execução

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Respostas:

- 200: A execução. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma execução sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### PATCH /runs/{id} — Mudar uma execução

Troca o que a execução usa: a conta, o ativo (um contrato novo na rolagem), o tempo gráfico, o número mágico ou os parâmetros. Rodando, ela recomeça com isso em até 15 segundos, com o mesmo id e as posições e ordens como estão (`settings_version` sobe, e `running_settings` mostra quando ela já roda com a nova); parada, vale para quando ligar de novo. Antes de trocar o ativo ou a conta com posição aberta, zere (`/flatten`): a posição antiga fica sem ninguém cuidar. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Corpo (application/json): object

- `account_id` (integer): A conta (o id de `GET /accounts`).
- `login` (integer): Ou o número da conta.
- `server` (string): O servidor, quando o número está em duas corretoras.
- `symbol` (string): O ativo, como a corretora chama.
- `timeframe` (string): O tempo gráfico: M1, M5, M15, M30, H1, H4, D1...
- `magic` (integer): O número mágico, que separa as ordens da execução. Duas execuções nunca têm o mesmo numa conta.
- `inputs` (object): Os valores dos parâmetros, por nome. Um parâmetro de ativo (`type: symbol`) é `{ login, server, symbol }` ou `{ account_id, symbol }`: um ativo numa conta de qualquer corretora; a execução opera em cada conta escolhida, com o mesmo número mágico. Sem a conta e o ativo da execução, valem os do primeiro parâmetro de ativo.
- `limits` (object): Limites de risco, na moeda da primeira conta: `daily_loss` (perda máxima do dia, fechada e aberta, desde a meia-noite do seu fuso) e `max_drawdown` (queda máxima do resultado a partir de um pico desde que ligou); 0 tira. Ao chegar num deles, a plataforma zera a execução e a para (`limit_hit` diz qual).
- `place` (string): Sempre `cloud`: pela API um expert não roda num computador.

Respostas:

- 200: A execução. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: A execução, a conta ou o ativo não existem. (`Error`)
- 409: Outra execução tem esse número mágico na conta. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### DELETE /runs/{id} — Remover uma execução

Remove uma execução parada, com o diário dela. Os negócios dela continuam no histórico da conta, e o número mágico fica livre na conta. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Respostas:

- 204: Removida.
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Não é uma execução sua. (`Error`)
- 409: Ela está rodando: pare antes. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /runs/{id}/start — Ligar de novo uma execução

Liga de novo nos servidores uma execução parada ou que falhou, com as mudanças pedidas (os mesmos campos de `PATCH /runs/{id}`). Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Corpo (application/json): object

- `account_id` (integer): A conta (o id de `GET /accounts`).
- `login` (integer): Ou o número da conta.
- `server` (string): O servidor, quando o número está em duas corretoras.
- `symbol` (string): O ativo, como a corretora chama.
- `timeframe` (string): O tempo gráfico: M1, M5, M15, M30, H1, H4, D1...
- `magic` (integer): O número mágico, que separa as ordens da execução. Duas execuções nunca têm o mesmo numa conta.
- `inputs` (object): Os valores dos parâmetros, por nome. Um parâmetro de ativo (`type: symbol`) é `{ login, server, symbol }` ou `{ account_id, symbol }`: um ativo numa conta de qualquer corretora; a execução opera em cada conta escolhida, com o mesmo número mágico. Sem a conta e o ativo da execução, valem os do primeiro parâmetro de ativo.
- `limits` (object): Limites de risco, na moeda da primeira conta: `daily_loss` (perda máxima do dia, fechada e aberta, desde a meia-noite do seu fuso) e `max_drawdown` (queda máxima do resultado a partir de um pico desde que ligou); 0 tira. Ao chegar num deles, a plataforma zera a execução e a para (`limit_hit` diz qual).
- `place` (string): Sempre `cloud`: pela API um expert não roda num computador.

Respostas:

- 200: A execução, enviada aos servidores. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: A execução, a conta ou o ativo não existem. (`Error`)
- 409: O expert está desativado, ou ela roda no app de outro aparelho. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /runs/{id}/stop — Parar uma execução

Para onde ela estiver rodando, em até 15 segundos. As posições e ordens dela ficam como estão (veja `/flatten`). Ela continua na lista, para ligar de novo (`/start`) ou remover. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Respostas:

- 200: A execução, parada. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 404: Não é uma execução sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /runs/{id}/pause — Pausar uma execução

Ela continua rodando, mas não abre posição nova: fechar, mudar stop e alvo e cancelar ordens passam. Com `cancel_pending`, as ordens pendentes dela são canceladas. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Corpo (application/json): object

- `cancel_pending` (boolean): Cancelar também as ordens pendentes dela.

Respostas:

- 200: A execução. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 409: A execução não está rodando. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /runs/{id}/resume — Retomar uma execução pausada

Volta a abrir posições. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Respostas:

- 200: A execução. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 409: A execução não está rodando. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /runs/{id}/flatten — Zerar uma execução

Cancela as ordens pendentes e fecha as posições dela (pelo número mágico, na conta dela). Com `pause`, pausa antes. Precisa da permissão **Negociação**.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.

Corpo (application/json): object

- `pause` (boolean): Pausar antes de zerar.

Respostas:

- 200: A execução. (`ExpertRun`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 403: A chave de API não tem a permissão Negociação. (`Error`)
- 409: A execução não está rodando. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /runs/{id}/journal — O diário de uma execução

O que ela imprimiu, as ordens que mandou e como foram, e os erros: as últimas 500 linhas, depois da linha `after`.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.
- `after` (consulta, integer): Só as linhas depois deste id.

Respostas:

- 200: Linhas. (`object[]`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### GET /runs/{id}/statistics — Os números de uma execução ao vivo

Os mesmos números de um backtest (`statistics`, pela posição das constantes `STAT_*`: lucro, fator de lucro, rebaixamento do saldo e do patrimônio, sequências de ganhos e perdas, Sharpe...), do que a execução fez ao vivo na conta dela, pelo número mágico dela. Numa conta netting, só a parte dela de cada negócio (veja `GET /accounts/{login}/ledger`). O saldo começa em `base`, o saldo da conta quando o período começou, de onde contam as porcentagens; o patrimônio soma o que as posições dela fazem, avaliadas a cada candle do tempo gráfico dela (`equity_from_prices` falso quando os preços de algum ativo não puderam ser lidos: lá o patrimônio só conta nos negócios). Retiradas, nível de margem e OnTester ficam 0. Uma posição aberta antes do período conta inteira no período em que fecha, como no histórico da corretora. Os números que os relatórios dos testadores acrescentam, os mesmos do relatório de um backtest, em `metrics`: % de operações com ganho (`win_rate`), ganho e perda médios e a razão entre eles, quantas nem ganharam nem perderam, segundos com a posição aberta (`holding_min`, `holding_average`, `holding_max`), quanto cada operação chegou a ir a favor e contra antes de sair, em dinheiro (`mfe_average`, `mae_average`, e as correlações com o resultado; `null` onde os preços não foram acompanhados), o maior tempo para o saldo voltar a um pico (`recovery_max`; `recovery_open` verdadeiro quando o saldo terminou abaixo do pico, e aí esse tempo pode ser o que ainda corre) e sem nada aberto (`flat_max`), em segundos de pregão (com cotações), `sortino_ratio`, `ulcer_index`, `z_score`, `ahpr`, `ghpr`, `lr_correlation`, `lr_standard_error`, `trades_per_day`, `profit_per_month`, e `by_hour` (24), `by_weekday` (7, domingo primeiro) e `by_month` (12): entradas, operações fechadas, ganhas, perdidas e resultado, pela hora do servidor; aqui, quanto cada operação foi a favor e contra sai dos candles. Precisa da conta conectada.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.
- `from` (consulta, string): Início, na hora do servidor: segundos Unix ou data sem fuso. Padrão: o primeiro negócio dela na conta.
- `to` (consulta, string): Fim, na hora do servidor. Padrão: agora.

Respostas:

- 200: Os números. (`object`)
- 400: Data inválida. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma execução sua. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: A conta não está conectada. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /runs/{id}/compare — Uma execução ao lado de um teste dos mesmos dias

O que a execução fez na conta dela, operação por operação, ao lado de um backtest dos mesmos dias: cada posição do teste com a da conta do mesmo lado cuja entrada está a menos de um candle do tempo gráfico dela (de 2 a 15 minutos), as que só um dos lados fez (`so_teste`, `so_vivo`) e as ainda abertas (`aberta`, fora das contas). As operações do teste antes de a execução ligar pela última vez (`since`) ficam de fora (`before` diz quantas). Os resultados ao vivo e no teste (`live`, `test`, `diff`, só o que fechou), quantas do teste aconteceram ao vivo (`same` de `test_trades`), de onde vem a diferença (`causes`: `entrada`, `saida`, `stop`, `alvo`, `custos`, `so_teste`, `so_vivo`, que somam `diff`), cada par (`pairs`: os dois lados com entrada, saída, preços e resultado, e num par dos dois a diferença da entrada, da saída e dos custos em dinheiro e em ticks e o atraso da saída em segundos) e as duas curvas somadas a cada fechamento (`curve`). O teste é o de `backtest_id`, ou o mais novo terminado do expert feito com a conta, o ativo, o tempo gráfico e os parâmetros da execução nesses dias; sem um, responde 404 dizendo qual rodar. Não roda teste nem gasta créditos. Horários na hora do servidor. Precisa da conta conectada.

Parâmetros:

- `id` (caminho, integer, obrigatório): Id da execução.
- `backtest_id` (consulta, integer): O teste a comparar (um terminado). Sem ele, o mais novo feito com as configurações da execução nesses dias.
- `from` (consulta, string): Primeiro dia, na hora do servidor (2026-10-22). Padrão: o dia em que ela ligou pela última vez.
- `to` (consulta, string): Último dia, incluído. Padrão: hoje.

Respostas:

- 200: A comparação. (`object`)
- 400: Dia inválido, ou o teste não terminou bem. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Não é uma execução sua, ou não há teste dela nesses dias. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: A conta não está conectada. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

### GET /notices — Os avisos dos seus robôs

O que a plataforma avisa sem que ninguém olhe: uma execução que falhou ou parou sozinha (erro do robô, sem créditos, limite de risco atingido), uma ordem recusada pela corretora, uma conta sem conexão depois das tentativas rápidas de reconectar (cerca de 2 minutos: uma queda que volta antes disso não é aviso) ou com a senha recusada, uma execução esperando lugar no servidor, e cada posição de um robô que fechou, com o resultado. Um aviso do mesmo tipo para a mesma execução vem no máximo a cada 10 minutos (menos o de posição fechada: cada posição é um): uma ordem recusada de novo e de novo é um aviso só; o diário da execução (`GET /runs/{id}/journal`) tem todas as linhas. Também vão como notificação nos celulares e computadores do usuário e por e-mail, nos tipos que ele escolhe em Perfil, no app. Os mais novos primeiro. Qualquer chave lê.

Parâmetros:

- `after` (consulta, integer): Só os que vieram depois deste id: para conferir de tempos em tempos o que chegou.
- `unread` (consulta, boolean): `true`: só os ainda não vistos.
- `kinds` (consulta, string): Só estes tipos, separados por vírgula: `error,refused,warning` são os que pedem atenção (os de Precisa de você, no app).
- `limit` (consulta, integer): Quantos, até 100. Padrão: 50.

Respostas:

- 200: Os avisos. (`object[]`)
- 400: Número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

### POST /notices/read — Marcar os avisos como vistos

Todos até o id `up_to`, ou todos quando ele não vem. No app eles saem de Precisa de você. Qualquer chave marca.

Corpo (application/json): object

- `up_to` (integer): Até este id.

Respostas:

- 200: Quantos foram marcados. (`object`)
- 400: Número inválido. (`Error`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)

## Ativos

### GET /accounts/{login}/symbol/{symbol}/sessions — Horários de cotação e de negociação

Não existe no pacote Python (no MQL5: SymbolInfoSessionQuote e SymbolInfoSessionTrade). Para cada dia da semana, domingo primeiro, as sessões em minutos do dia no horário do servidor (`from` e `to`), e se o ativo negocia e cota agora pelo relógio do servidor. Algumas corretoras mandam o dia inteiro para todos os ativos (a XP manda 00:00 a 24:00 de segunda a sexta).

Parâmetros:

- `login` (caminho, integer, obrigatório): Número da conta.
- `server` (consulta, string): Servidor da conta. Só é preciso quando o mesmo número de conta existe em duas corretoras.
- `symbol` (caminho, string, obrigatório)

Respostas:

- 200: As sessões e o estado agora. (`object`)
- 401: Chave de API ausente, inválida ou revogada. (`Error`)
- 404: Ativo inexistente na corretora. (`Error`)
- 409: O mesmo número de conta existe em duas corretoras: informe `server`. (`Error`)
- 429: Chamadas demais: tente de novo depois dos segundos em `Retry-After`. (`Error`)
- 503: O gateway ainda não está conectado ao servidor da corretora. (`Error`)
- 504: A corretora não respondeu a tempo. (`Error`)

# Modelos

## Optimization

- `id` (integer): Id.
- `expert_id` (integer): O expert.
- `processed_on` (string): Onde roda: no computador do usuário (app ou SDK, grátis) ou nos servidores.
- `settings` (object): O que foi pedido: `account_id`, `symbol`, `timeframe`, `from`, `to`, `deposit`, `model`, `ranges`, `fixed`, `method`, `criterion` (0 saldo, 1 fator de lucro, 2 retorno esperado, 3 queda, 4 recuperação, 5 Sharpe, 6 do expert), `seed`, `total` (combinações possíveis).
- `status` (string): Na fila (só no servidor), rodando, parada (pelo usuário ou, no servidor, sem saldo, com o motivo em `error`), terminada ou com falha.
- `tested` (integer): Combinações testadas.
- `credits` (integer): O que custou até agora.
- `error` (string): Por que parou ou falhou.
- `best` (object): A melhor combinação até agora: `inputs`, `statistics`, `value`.
- `created_at` (string): Pedida em.
- `updated_at` (string): Atualizada em.

## ExpertInput

Um parâmetro, como o expert o declara (`input`).

- `name` (string): Nome no arquivo.
- `type` (string): `int`, `double`, `bool`, `string` ou `enum`.
- `default`: Valor padrão.
- `label` (string): Rótulo.
- `min` (number): Mínimo.
- `max` (number): Máximo.
- `step` (number): Passo.
- `options` (array): Opções de um `enum`.

## ExpertSummary

- `id` (integer): Id.
- `name` (string): Nome.
- `file_name` (string): Nome do arquivo.
- `size` (integer): Bytes do arquivo.
- `inputs` (ExpertInput[])
- `settings` (object): O que a última execução no app usou.
- `origin` (string): Onde foi guardado: `app`, no app (roda no computador do usuário ou nos servidores); `api`, pela API ou por um agente de IA (roda só nos servidores).
- `code_version` (integer): A versão do arquivo: começa em 1 e sobe a cada arquivo diferente guardado.
- `created_at` (string): Criado em.
- `updated_at` (string): Alterado em.

## ExpertRun

Uma execução de um expert: o mesmo expert roda quantas vezes você quiser, cada execução com o seu id.

- `id` (integer): Id da execução.
- `expert_id` (integer): O expert.
- `expert_name` (string): O nome dele.
- `account_id` (integer): A conta.
- `symbol` (string): O ativo.
- `timeframe` (string): O tempo gráfico.
- `magic` (integer): O número mágico.
- `inputs` (object): Os valores dos parâmetros.
- `place` (string): Onde roda: `cloud`, nos servidores da plataforma; `pc`, no app aberto no computador do usuário.
- `status` (string): Rodando (ou a caminho), parado, ou falhou.
- `error` (string): Por que falhou, ou por que parou (sem créditos, por exemplo).
- `alive` (boolean): Quem roda deu sinal de vida há menos de 90 segundos.
- `started_at` (string): Ligada pela última vez em.
- `ended_at` (string): Terminou em.
- `credits` (integer): O que custou nos servidores desde que ligou.
- `paid_until` (string): Até quando a hora nos servidores está paga.
- `comment` (string): O que ele mostra com `Comment`.
- `orders` (object): Ordens enviadas (`sent`), executadas (`done`) e recusadas (`refused`).
- `paused_at` (string): Pausado desde; null quando não.
- `disabled` (boolean): O expert está desativado.
- `code_version` (integer): A versão do arquivo do expert agora.
- `running_version` (integer): A versão do arquivo com que ela está rodando; null até quem roda dizer. Menor que `code_version`: ela recomeça com a nova em até 15 segundos.
- `settings_version` (integer): Conta as mudanças do que ela usa (`PATCH /runs/{id}`).
- `running_settings` (integer): A versão das mudanças com que ela está rodando; null até quem roda dizer. Menor que `settings_version`: ela recomeça com as mudanças em até 15 segundos.
- `created_at` (string): Quando a execução foi criada.
- `account_ids` (integer[]): Todas as contas em que ela opera: a dela primeiro, depois as dos parâmetros de ativo.
- `limits` (object): Os limites de risco (`daily_loss`, `max_drawdown`).
- `limit_hit` (string): O limite que ela atingiu (foi zerada e parada); null enquanto nenhum.

## Expert

Os campos de ExpertSummary, mais:

- `code` (string): O arquivo.
- `notes` (ExpertNotes)

## ExpertNotes

O que se sabe do expert, em texto (até 50 mil caracteres cada), para quem vai mexer nele: um agente de IA lê antes de alterar, testar ou otimizar e reescreve ao terminar, com o que fez e o que não fez, citando os números dos backtests e otimizações.

- `strategy` (string): Estratégia: como funciona, a lógica de que veio e os ativos que opera.
- `research` (string): Pesquisa e testes: estudos, pesquisas e otimizações feitos, o que ajudou, o que não fez sentido e o que falta testar.
- `risk` (string): Risco e margem: margem necessária, tamanho de posição e limites de perda recomendados.

## ExpertNotesInput

Anotações a gravar: cada uma que vier substitui a anterior inteira; as que não vêm ficam como estão. Até 50 mil caracteres cada.

- `strategy` (string): Estratégia.
- `research` (string): Pesquisa e testes.
- `risk` (string): Risco e margem.

## AiModel

- `id` (string): O nome do modelo nas chamadas.
- `name` (string): Nome.
- `kind` (string): `decision`: responde perguntas tipadas sobre um estado (`POST /ai/decide`).
- `description` (string): O que faz.
- `question_types` (string[]): Os tipos de pergunta que responde.
- `max_tokens` (integer): Tokens de uma chamada, ao todo.
- `context_tokens` (integer): Tokens do estado mais a pergunta mais longa.
- `input` (string[]): O que lê.
- `price` (object | null): Créditos por milhão de tokens agora: lidos (`input`), lidos do cache do modelo (`cached_input`, null quando ele não tem) e escritos (`output`). Null enquanto a IA não estiver aberta.

## AiTokens

- `input_tokens` (integer): Lidos.
- `cached_tokens` (integer): Dos lidos, os que vieram do cache do modelo.
- `output_tokens` (integer): Escritos.

## AiDecision

- `id` (integer): A chamada, como `GET /ai/usage` a lista.
- `model` (string): O modelo.
- `answers` (object): Uma resposta por pergunta, pelo nome dela: `choice` com `choice` (a opção mais provável) e `probabilities`; `score` com `score` (de 0 ao número de níveis − 1, fracionário) e `probabilities` (por índice do nível); `boolean` com `probability` (de sim, de 0 a 1); `refusal` quando o modelo recusou.
- `usage` (AiTokens)
- `credits` (number): O que custou, com até 6 casas.
- `balance` (integer): O saldo depois.
- `ms` (integer): Quanto o modelo levou, em milissegundos.

## AiUsageTotals

- `calls` (integer): Chamadas.
- `failed` (integer): Das quais falharam (sem custo).
- `input_tokens` (integer): Lidos.
- `cached_tokens` (integer): Do cache.
- `output_tokens` (integer): Escritos.
- `credits` (number): Créditos.

## AiUsage

- `from` (string): Início (UTC).
- `to` (string): Fim (UTC).
- `timezone` (string): Seu fuso, dos dias.
- `totals` (AiUsageTotals)
- `by_model` (AiUsageTotals[]): Por modelo (com `model`).
- `by_expert` (AiUsageTotals[]): Por expert (com `expert_id` e `expert_name`).
- `by_origin` (AiUsageTotals[]): Por origem (com `origin`: `live`, `backtest`, `optimization`, `api`).
- `by_day` (AiUsageTotals[]): Por dia do seu fuso (com `day`).
- `calls` (object[]): As chamadas, da mais nova: `id`, `at` (UTC), `origin`, `expert_id`, `backtest_id`, `optimization_id`, `model`, `status` (`done` ou `failed`), `questions`, os tokens, `credits`, `ms` e `error`.

## Credits

- `credits` (integer): Saldo.
- `reserved` (integer): Reservado pelos backtests esperando ou rodando no servidor.
- `available` (integer): O que sobra para novos backtests.
- `backtest_cost` (integer): Quanto custa um backtest no servidor.

## Backtest

- `id` (integer): Id.
- `expert_id` (integer): O expert.
- `expert_name` (string): O nome do expert quando o backtest foi feito.
- `processed_on` (string): Onde rodou: `local`, no computador do usuário (pelo app ou pelo SDK, grátis); `server`, nos servidores da plataforma.
- `settings` (object): O que foi testado: `account_id`, `login`, `server`, `symbol`, `timeframe`, `from`, `to`, `deposit`, `model`, `inputs`.
- `status` (string): Na fila, rodando, terminado, falhou ou cancelado.
- `progress` (number): Andamento, de 0 a 1.
- `error` (string): Por que falhou.
- `credits` (integer): O que custou.
- `currency` (string): Moeda dos valores.
- `seconds` (number): Quanto levou.
- `created_at` (string): Pedido em.
- `started_at` (string): Começou em.
- `finished_at` (string): Terminou em.
- `result` (object): Os números principais, quando terminou: `balance`, `profit`, `profit_factor`, `trades`, `wins`, `losses`, `max_drawdown`, `max_drawdown_percent`.
- `report` (object): Só em `GET /backtests/{id}`: o relatório completo do SDK (`BacktestReport`): os números (`statistics`, pelos índices `STAT_*`), os que os relatórios dos testadores acrescentam (`metrics`: % de operações com ganho (`win_rate`), ganho e perda médios e a razão entre eles, quantas nem ganharam nem perderam, segundos com a posição aberta (`holding_min`, `holding_average`, `holding_max`), quanto cada operação chegou a ir a favor e contra antes de sair, em dinheiro (`mfe_average`, `mae_average`, e as correlações com o resultado; `null` onde os preços não foram acompanhados), o maior tempo para o saldo voltar a um pico (`recovery_max`; `recovery_open` verdadeiro quando o saldo terminou abaixo do pico, e aí esse tempo pode ser o que ainda corre) e sem nada aberto (`flat_max`), em segundos de pregão (com cotações), `sortino_ratio`, `ulcer_index`, `z_score`, `ahpr`, `ghpr`, `lr_correlation`, `lr_standard_error`, `trades_per_day`, `profit_per_month`, e `by_hour` (24), `by_weekday` (7, domingo primeiro) e `by_month` (12): entradas, operações fechadas, ganhas, perdidas e resultado, pela hora do servidor; ausente em testes antigos), os negócios, as ordens, a curva de patrimônio e o diário do expert. Como numa corretora, a conta tem margem, e o stop out da corretora (o nível que a conta informa; sem nível, o patrimônio em zero) fecha tudo e encerra o teste ali: `stop_out` diz por quê (`reason`: `stop_out`, ou `no_margin` quando, sem nada aberto, o patrimônio não pagava mais a margem do menor lote e a conta não operava mais), quando (`time`), a quantos % do período (`percent`), com que patrimônio (`equity`) e margem (`margin`), e o nível (`mode` 0 em % da margem, 1 em dinheiro; `level`). Num teste em várias contas, `accounts` traz o relatório de cada conta (`name`, `login`, `currency`, `report`, com os horários da corretora dela), e o relatório é o total: todos os negócios (o ativo de outra conta com a conta depois de uma barra, no relógio da conta do teste), a soma das curvas e os números dessa soma; com moedas diferentes nada é somado e o topo é o da conta do teste.

## Broker

- `id` (integer): Id da corretora.
- `name` (string): Nome.
- `website` (string): Site.
- `country` (string): País (ISO).
- `providers` (Method[]): Métodos de integração.

## Method

- `provider` (string): Código do método.
- `provider_name` (string): Nome do método.
- `credential_type` (string): `auth`, `api-key-secret` ou `api-token`.
- `user_label` (string): Como chamar o usuário de uma credencial `auth`, quando o método dá um nome a ele.

## Server

- `id` (integer): Id do servidor.
- `name` (string): Nome, o que se manda ao cadastrar.
- `type` (string): `demo` ou `real`.
- `broker` (string): Corretora.
- `provider` (string): Código do método.
- `provider_name` (string): Nome do método.
- `credential_type` (string): Tipo de credencial que pede.
- `user_label` (string): Nome do usuário, se o método der.

## Credentials

Os campos do tipo de credencial do servidor: `auth` → `user` e `password`; `api-key-secret` → `key` e `secret`; `api-token` → `token`. Outros campos são ignorados.

- `user` (string): auth
- `password` (string): auth
- `key` (string): api-key-secret
- `secret` (string): api-key-secret
- `token` (string): api-token

## BrokerAccount

- `login` (integer): Número da conta na corretora.
- `server` (string): Servidor.
- `server_type` (string): `demo` ou `real`.
- `broker` (string): Corretora.
- `provider` (string): Código do método.
- `provider_name` (string): Nome do método.
- `credential_type` (string): Tipo de credencial.
- `user_label` (string): Nome do usuário, se o método der.
- `credential_hint` (string): O que se pode mostrar das credenciais: o usuário ou o começo da chave.
- `enabled` (boolean): Ativa (conectada pelo gateway).
- `status` (string): `connecting` (primeira tentativa), `authenticated`, `disconnected` (caiu ou falhou, tentando de novo), `auth_failed` (credenciais recusadas) ou `disabled`.
- `connected` (boolean): Logada na corretora agora.
- `last_error` (LastError | null): Por que a última tentativa falhou.
- `reason` (StatusReason | null): Por que a conta não está conectada; `null` quando está.
- `retry_at` (string | null): Quando sai a próxima tentativa (ISO); `null` com uma em andamento.
- `attempts` (integer): Quantas tentativas falharam em seguida.
- `last_outage` (Outage | null): A última vez que a conta esteve fora, depois que voltou.
- `ping_ms` (integer): Quanto a corretora demorou para responder à última verificação da conexão, em ms; null se não conectada.
- `created_at` (string): Quando foi cadastrada (ISO).

## Error

- `error` (string, obrigatório): O que deu errado, em inglês.
- `code` (integer): O mesmo em número: -2 parâmetro inválido, -3 a conta já guarda os negócios de ativos demais, -4 não existe, -6 chave recusada, -7 ainda não suportado, -8 a chave não pode negociar, -10003 conta sem conexão com a corretora, -10005 a corretora não respondeu a tempo, -10000 falha do gateway, -1 outra falha.

## StatusReason

Por que a conta não está conectada, e o que o gateway encontrou ao tentar.

- `code` (string): Motivo, de uma lista fechada. Da corretora: `broker_closed` ela encerrou a conexão; `broker_silent` parou de responder; `broker_unreachable` nenhum endereço dela aceita conexão; `broker_unavailable` respondeu que o servidor está indisponível (costuma ser manutenção); `credentials_refused` recusou as credenciais. Da plataforma: `platform_network` a rede da plataforma está fora; `platform_restart` a plataforma parou ou reiniciou. `unknown` quando não deu para saber.
- `description` (string): O que aconteceu, em inglês. Quando as tentativas encontram outra coisa depois da queda, vem depois de "; now:".
- `since` (string): Desde quando a conta está fora (ISO).
- `servers` (object | null): Os endereços da corretora e quantos aceitam conexão; `null` se não foram testados.
- `internet` (boolean | null): Se algo fora da plataforma respondeu, perguntado quando nenhum endereço da corretora respondeu; `null` se não foi perguntado.

## Outage

Uma vez que a conta esteve fora.

- `started_at` (string): Quando caiu (ISO).
- `ended_at` (string): Quando voltou (ISO).
- `reason` (string): Motivo: os códigos de StatusReason.
- `description` (string): O que aconteceu, em inglês.
- `attempts` (integer): Quantas tentativas falharam até voltar.
- `servers` (object | null): Os endereços da corretora e quantos aceitavam conexão.

## LastError

Por que a conexão ou o login falhou.

- `code` (integer): Código do erro: -1 falha, -6 login recusado, -10003 sem conexão, -10005 o servidor não respondeu.
- `server_code` (integer): Código da corretora. Contas de terminal: 2 servidor indisponível, 3 conta ou senha inválida, 5 falta o código de uso único (OTP), 104 conexão fechada, 408 o servidor não respondeu. Contas por API: o código de erro da corretora (na Binance, -2015 chave recusada, -1022 assinatura inválida).
- `description` (string): Mensagem do terminal da corretora, em inglês.

## Tick

Cotação com o nome do ativo.

- `symbol` (string): Ativo.
- `time` (integer): Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_msc` (integer): Mesmo horário em milissegundos.
- `bid` (number): Melhor oferta de compra.
- `ask` (number): Melhor oferta de venda.
- `last` (number): Último negócio.
- `volume` (number): Volume do último negócio, em lotes.
- `flags` (integer): O que mudou nesta cotação (soma): 2 compra, 4 venda, 8 último, 16 volume, 32 negócio comprador, 64 negócio vendedor.

## AccountInfo

Conta: dados, saldo, patrimônio e margem.

- `login` (integer): Número da conta.
- `trade_mode` (integer): 0 demonstração, 1 competição, 2 real.
- `leverage` (integer): Alavancagem.
- `limit_orders` (integer): Máximo de ordens pendentes; 0 sem limite. O protocolo web não informa o limite (o terminal de mesa mostra o da corretora, por exemplo 100), então vem sempre 0; o servidor recusa o excesso com o código 10033.
- `margin_so_mode` (integer): Níveis de chamada de margem e stop out: 0 em porcentagem, 1 em dinheiro.
- `trade_allowed` (boolean): A conta pode negociar (falso com senha de investidor, negociação bloqueada pela corretora ou conta só leitura).
- `trade_expert` (boolean): A corretora permite robôs nesta conta.
- `margin_mode` (integer): 0 compensação, 1 bolsa, 2 posições independentes (hedging).
- `currency_digits` (integer): Casas decimais da moeda.
- `fifo_close` (boolean): Posições só podem ser fechadas na ordem em que foram abertas.
- `balance` (number): Saldo.
- `credit` (number): Crédito.
- `profit` (number): Lucro flutuante das posições abertas (com swap), acompanhando cada cotação.
- `equity` (number): Patrimônio: saldo + crédito + lucro flutuante.
- `margin` (number): Margem usada.
- `margin_free` (number): Margem livre.
- `margin_level` (number): Nível de margem em %; 0 quando não há margem usada.
- `margin_so_call` (number): Nível de chamada de margem.
- `margin_so_so` (number): Nível de stop out.
- `margin_initial` (number): Margem inicial reservada (contas em modo bolsa; 0 nas demais, como no terminal).
- `margin_maintenance` (number): Margem de manutenção (contas em modo bolsa; 0 nas demais).
- `assets` (number): Ativos (contas em modo bolsa; 0 nas demais).
- `liabilities` (number): Passivos (contas em modo bolsa; 0 nas demais).
- `commission_blocked` (number): Comissão acumulada no dia e no mês, ainda não cobrada.
- `name` (string): Titular.
- `server` (string): Nome do servidor.
- `currency` (string): Moeda da conta.
- `company` (string): Corretora.

## Position

Posição aberta (`TradePosition`).

- `ticket` (integer): Número da posição.
- `time` (integer): Abertura. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_msc` (integer): Mesmo horário em milissegundos.
- `time_update` (integer): Última alteração. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_update_msc` (integer): Mesmo horário em milissegundos.
- `type` (integer): 0 comprada, 1 vendida.
- `magic` (integer): Magic da ordem que abriu a posição; 0 se ela não veio do gateway.
- `identifier` (integer): Igual a `ticket`.
- `reason` (integer): Origem: 0 cliente (terminal), 1 celular, 2 web, 3 robô.
- `volume` (number): Lotes.
- `price_open` (number): Preço de abertura.
- `sl` (number): Stop; 0 sem stop.
- `tp` (number): Alvo; 0 sem alvo.
- `price_current` (number): Preço atual, acompanhando cada cotação. Ações e futuros da B3: último negócio. Outros mercados: posição comprada pelo bid, vendida pelo ask.
- `swap` (number): Swap.
- `profit` (number): Lucro flutuante ao preço atual, na moeda da conta, calculado como o terminal.
- `symbol` (string): Ativo.
- `comment` (string): Comentário da ordem que abriu a posição.
- `external_id` (string): Código na bolsa.

## Order

Ordem (`TradeOrder`), pendente ou do histórico.

- `ticket` (integer): Número da ordem.
- `time_setup` (integer): Criação. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_setup_msc` (integer): Mesmo horário em milissegundos.
- `time_done` (integer): Execução ou cancelamento; 0 se pendente. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_done_msc` (integer): Mesmo horário em milissegundos.
- `time_expiration` (integer): Validade quando `type_time` é 2 ou 3. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `type` (integer): 0 compra, 1 venda, 2 compra limitada, 3 venda limitada, 4 compra stop, 5 venda stop, 6 compra stop limitada, 7 venda stop limitada.
- `type_time` (integer): Validade: 0 até cancelar, 1 no dia, 2 até `time_expiration`, 3 até o fim do dia de `time_expiration`.
- `type_filling` (integer): Preenchimento: 0 tudo ou nada (FOK), 1 o que der e cancela o resto (IOC), 2 o que der e mantém o resto (RETURN), 3 só entra no livro, sem executar na chegada (BOC).
- `state` (integer): 0 iniciada, 1 colocada, 2 cancelada, 3 parcial, 4 executada, 5 recusada, 6 expirada.
- `magic` (integer): Magic do pedido que criou a ordem; 0 se ela não veio do gateway.
- `position_id` (integer): Posição relacionada.
- `position_by_id` (integer): Posição oposta num fechamento por outra posição. Sempre 0: o protocolo web não informa.
- `reason` (integer): Origem: 0 cliente (terminal), 1 celular, 2 web, 3 robô, 4 stop, 5 alvo, 6 stop out.
- `volume_initial` (number): Lotes pedidos.
- `volume_current` (number): Lotes ainda pendentes.
- `price_open` (number): Preço da ordem.
- `sl` (number): Stop.
- `tp` (number): Alvo.
- `price_current` (number): Preço atual do ativo, acompanhando cada cotação nas pendentes. Ações e futuros da B3: último negócio. Outros mercados: ask nas compras, bid nas vendas.
- `price_stoplimit` (number): Preço limite de ordens stop limitadas.
- `symbol` (string): Ativo.
- `comment` (string): Comentário.
- `external_id` (string): Código na bolsa.

## Deal

Negócio (`TradeDeal`).

- `ticket` (integer): Número do negócio.
- `order` (integer): Ordem que gerou o negócio.
- `time` (integer): Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_msc` (integer): Mesmo horário em milissegundos.
- `type` (integer): 0 compra, 1 venda, 2 depósito/saque, 3 crédito, 4 cobrança, 5 correção, 6 bônus, 7 comissão, 12 juros, 15 dividendo, 17 imposto.
- `entry` (integer): 0 abertura, 1 fechamento, 2 inversão, 3 fechamento por posição oposta.
- `magic` (integer): Magic da ordem do negócio; 0 se ela não veio do gateway.
- `position_id` (integer): Posição afetada.
- `reason` (integer): Origem: 0 cliente (terminal), 1 celular, 2 web, 3 robô, 4 stop, 5 alvo, 6 stop out.
- `volume` (number): Lotes.
- `price` (number): Preço.
- `commission` (number): Comissão.
- `swap` (number): Swap.
- `profit` (number): Resultado financeiro (no fechamento).
- `fee` (number): Taxa.
- `symbol` (string): Ativo.
- `comment` (string): Comentário.
- `external_id` (string): Código na bolsa.

## OrderRequest

Pedido de negociação. Os campos usados dependem de `action`.

- `action` (integer, obrigatório): 1 a mercado (abrir, ou fechar com `position`); 5 ordem pendente; 6 mudar stop/alvo de uma posição; 7 alterar ordem pendente; 8 cancelar ordem pendente; 10 encerrar uma posição contra uma oposta.
- `magic` (integer): Número mágico (identificação do robô). O gateway o guarda e o mostra na ordem, nos negócios e na posição que ela criar.
- `symbol` (string): Ativo. Obrigatório para 1 (ao abrir) e 5; nos demais vem da posição ou da ordem.
- `volume` (number): Lotes. Obrigatório para 1 e 5; ao fechar, o padrão é a posição inteira.
- `type` (integer): Tipo da ordem (veja `Order.type`). Para fechar uma posição, use o tipo oposto ao dela.
- `price` (number): Preço da ordem pendente, ou novo preço ao alterar (7). Ignorado a mercado na bolsa.
- `stoplimit` (number): Preço limite de ordens stop limitadas (tipos 6 e 7).
- `sl` (number): Stop. Arredondado para o passo de preço do ativo.
- `tp` (number): Alvo. Arredondado para o passo de preço do ativo.
- `deviation` (integer): Desvio máximo do preço, em pontos, nas execuções por pedido e instantânea. Sem efeito na execução de bolsa.
- `type_filling` (integer): Preenchimento (veja `Order.type_filling`). Padrão: 2 (RETURN) na execução de bolsa; na execução a mercado, o primeiro que o ativo aceitar. Ordens stop vão sempre como RETURN.
- `type_time` (integer): Validade (veja `Order.type_time`). Padrão: 0 quando o ativo aceita, senão 1. O mini índice só aceita 1.
- `expiration` (integer): Validade para `type_time` 2 e 3. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `comment` (string): Comentário, até 32 caracteres. Use para identificar o robô.
- `position` (integer): Posição a fechar (1), mudar (6) ou encerrar (10).
- `position_by` (integer): Posição oposta para `action` 10.
- `order` (integer): Ordem a alterar (7) ou cancelar (8).

## Candle

Candle. Não tem o `spread` do pacote Python: o servidor da corretora não manda o spread dos candles, nem no histórico nem ao vivo, e o gateway não inventa um.

- `time` (integer): Abertura do candle. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `open` (number): Abertura.
- `high` (number): Máxima.
- `low` (number): Mínima.
- `close` (number): Fechamento.
- `tick_volume` (integer): Número de negócios.
- `real_volume` (number): Volume negociado, em lotes (ações ou contratos).
- `in_progress` (boolean): `true` no candle que ainda está se formando (o último, quando o intervalo chega até agora).

## SymbolInfo

Dados do ativo. Campos que o servidor da corretora não preenche vêm com 0 ou vazios, como `isin` e os limites de oscilação.

- `custom` (boolean): Sempre `false`.
- `chart_mode` (integer): Preço dos candles: 0 compra, 1 último negócio (a B3 usa 1).
- `select` (boolean): O gateway acompanha as cotações do ativo, como estar na Observação do Mercado. `/symbol` assina o ativo, então lá vem sempre `true`; em `/symbols` pode vir `false`.
- `visible` (boolean): Igual a `select`.
- `session_deals` (integer): Negócios na sessão (contagem da bolsa; difere de `tick_volume` dos candles).
- `session_buy_orders` (integer): Ordens de compra na sessão.
- `session_sell_orders` (integer): Ordens de venda na sessão.
- `volume` (integer): Volume do último negócio, em lotes.
- `volumehigh` (integer): Maior volume de um negócio no dia.
- `volumelow` (integer): Menor volume de um negócio no dia.
- `time` (integer): Última cotação. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `digits` (integer): Casas decimais do preço.
- `spread` (integer): Diferença entre venda e compra, em pontos.
- `spread_float` (boolean): Spread flutuante.
- `ticks_bookdepth` (integer): Níveis do livro de ofertas.
- `trade_calc_mode` (integer): Cálculo de margem e lucro: 32 ações, 33 futuros, 35 opções.
- `trade_mode` (integer): 0 negociação desabilitada, 1 só compra, 2 só venda, 3 só fechamento, 4 livre.
- `start_time` (integer): Início da negociação; 0 se não houver. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `expiration_time` (integer): Vencimento; 0 se não vence. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `trade_stops_level` (integer): Distância mínima de stop e alvo, em pontos.
- `trade_freeze_level` (integer): Distância que congela ordens e posições, em pontos.
- `trade_exemode` (integer): Execução: 0 por pedido, 1 instantânea, 2 a mercado, 3 pela bolsa.
- `swap_mode` (integer): Modo de swap: 0 sem swap, 1 em pontos, 2 na moeda base, 3 na moeda da margem, 4 na moeda da conta.
- `swap_rollover3days` (integer): Dia do swap triplo (0 domingo … 6 sábado).
- `margin_hedged_use_leg` (boolean): Margem de hedge pelo lado maior.
- `expiration_mode` (integer): Validades aceitas (soma): 1 até cancelar, 2 no dia, 4 até data, 8 até fim do dia da data.
- `filling_mode` (integer): Preenchimentos aceitos além do RETURN (soma): 1 tudo ou nada, 2 o que der e cancela o resto, 4 só entra no livro (BOC).
- `order_mode` (integer): Tipos de ordem aceitos (soma): 1 mercado, 2 limitada, 4 stop, 8 stop limitada, 16 stop de proteção (SL), 32 alvo (TP), 64 fechar por oposta.
- `order_gtc_mode` (integer): Duração das ordens "até cancelar": 0 até cancelar, 1 até o fim do dia, 2 até o fim do dia exceto stop e alvo.
- `option_mode` (integer): Opções: 0 europeia, 1 americana.
- `option_right` (integer): Opções: 0 compra (call), 1 venda (put).
- `bid` (number): Compra.
- `bidhigh` (number): Maior compra do dia.
- `bidlow` (number): Menor compra do dia.
- `ask` (number): Venda.
- `askhigh` (number): Maior venda do dia.
- `asklow` (number): Menor venda do dia.
- `last` (number): Último negócio.
- `lasthigh` (number): Máxima do dia.
- `lastlow` (number): Mínima do dia.
- `volume_real` (number): `volume` com casas decimais.
- `volumehigh_real` (number): `volumehigh` com casas decimais.
- `volumelow_real` (number): `volumelow` com casas decimais.
- `option_strike` (number): Preço de exercício da opção.
- `point` (number): Menor variação de preço representável.
- `trade_tick_value` (number): Valor de um passo de preço para 1 lote, na moeda da conta.
- `trade_tick_value_profit` (number): Igual a `trade_tick_value` (ativos na moeda da conta).
- `trade_tick_value_loss` (number): Igual a `trade_tick_value` (ativos na moeda da conta).
- `trade_tick_size` (number): Passo de preço (5 pontos no mini índice, R$ 0,01 em ações).
- `trade_contract_size` (number): Tamanho do contrato.
- `trade_accrued_interest` (number): Juros acumulados (títulos).
- `trade_face_value` (number): Valor de face (títulos).
- `trade_liquidity_rate` (number): Taxa de liquidez da margem.
- `volume_min` (number): Lote mínimo.
- `volume_max` (number): Lote máximo.
- `volume_step` (number): Passo do lote.
- `volume_limit` (number): Volume máximo somado de posições e ordens; 0 sem limite.
- `swap_long` (number): Swap de compra.
- `swap_short` (number): Swap de venda.
- `margin_initial` (number): Margem inicial por lote.
- `margin_maintenance` (number): Margem de manutenção por lote.
- `session_volume` (number): Volume negociado na sessão, em lotes.
- `session_turnover` (number): Financeiro da sessão.
- `session_interest` (number): Contratos em aberto.
- `session_buy_orders_volume` (number): Volume das ordens de compra.
- `session_sell_orders_volume` (number): Volume das ordens de venda.
- `session_open` (number): Abertura da sessão.
- `session_close` (number): Fechamento da sessão anterior.
- `session_aw` (number): Preço médio ponderado da sessão.
- `session_price_settlement` (number): Preço de ajuste.
- `session_price_limit_min` (number): Limite mínimo de preço da sessão.
- `session_price_limit_max` (number): Limite máximo de preço da sessão.
- `margin_hedged` (number): Margem de hedge por lote.
- `price_change` (number): Variação em % sobre o fechamento anterior, pela compra, como o terminal da corretora.
- `price_volatility` (number): Volatilidade.
- `price_theoretical` (number): Preço teórico da opção.
- `price_greeks_delta` (number): Delta.
- `price_greeks_theta` (number): Theta.
- `price_greeks_gamma` (number): Gama.
- `price_greeks_vega` (number): Vega.
- `price_greeks_rho` (number): Rô.
- `price_greeks_omega` (number): Ômega.
- `price_sensitivity` (number): Sensibilidade.
- `basis` (string): Ativo-objeto.
- `category` (string): Categoria.
- `currency_base` (string): Moeda base.
- `currency_profit` (string): Moeda do lucro.
- `currency_margin` (string): Moeda da margem.
- `bank` (string): Sempre vazio.
- `description` (string): Descrição.
- `exchange` (string): Bolsa.
- `formula` (string): Sempre vazio.
- `isin` (string): ISIN.
- `name` (string): Código.
- `page` (string): Página do ativo.
- `path` (string): Caminho na árvore de ativos.
- `subscription_delay` (integer): Minutos de atraso das cotações deste ativo para esta conta; 0 em tempo real. Com atraso, preços, candles e o tópico `tick.` usam só as cotações atrasadas, como o terminal da corretora.

## BookLevel

Um preço do livro (`BookInfo`).

- `type` (integer): 1 venda, 2 compra, 3 venda a mercado, 4 compra a mercado.
- `price` (number): Preço.
- `volume` (number): Quantidade ofertada, em lotes.

## Book

Livro de ofertas.

- `symbol` (string): Ativo.
- `time` (integer): Última mudança. Hora do servidor (Brasília) em segundos Unix, como se fosse UTC.
- `time_msc` (integer): Mesmo horário em milissegundos.
- `book` (BookLevel[]): Do maior preço para o menor: vendas em cima, compras embaixo, como o `market_book_get`.

## OrderSendResult

Resultado de um pedido, com o pedido recebido.

- `retcode` (integer): Código de retorno (veja a tabela na introdução).
- `deal` (integer): Negócio gerado; 0 se nenhum.
- `order` (integer): Ordem criada ou afetada.
- `volume` (number): Lotes executados ou colocados.
- `price` (number): Preço de execução.
- `bid` (number): Compra no momento.
- `ask` (number): Venda no momento.
- `comment` (string): Comentário do servidor; sem ele, a descrição do código ("Request completed", "Invalid stops in the request"...). Numa recusa do gateway antes de enviar, o motivo em detalhe.
- `request_id` (integer): Número do pedido nesta sessão.
- `retcode_external` (integer): Código de retorno do sistema externo; sempre 0 no protocolo web.
- `request` (TradeRequest): O pedido como foi recebido (`TradeRequest`), com todos os campos: os que não vieram ficam 0 ou vazios.

## TradeRequest

Pedido como foi recebido, com todos os campos de [OrderRequest](#model/orderrequest).

- `action` (integer)
- `magic` (integer)
- `order` (integer)
- `symbol` (string)
- `volume` (number)
- `price` (number)
- `stoplimit` (number)
- `sl` (number)
- `tp` (number)
- `deviation` (integer)
- `type` (integer)
- `type_filling` (integer)
- `type_time` (integer)
- `expiration` (integer)
- `comment` (string)
- `position` (integer)
- `position_by` (integer)
