Logo hamster-bot Claude новинка: MCP
RU EN PT

Загрузка…

HTTP API

HTTP API для управления ботом и тестером: настройки, стратегии, API-ключи бирж, позиции и ордера, логи, запуск тестера и работа с его отчётами. Адрес — тот же, что у веб-интерфейса: http://<хост>:<порт>, порт задаётся полем port в settings_program.json.

91 эндпоинтов

Доступ#

Токен API (рекомендуется)#

Передавайте в каждом запросе заголовок Authorization: Bearer <api_token>:

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

api_token бот создаёт сам при первом запуске и хранит в settings_program.json. Токен работает с любого адреса и при любом значении auth_telegram, и вход из браузера его не сбрасывает. Храните токен как пароль: с ним доступно всё, включая торговлю и ключи бирж.

Посмотреть и скопировать токен можно в веб-интерфейсе: «Глобальная конфигурация», блок «Токен API и MCP». Там же кнопка «Выпустить новый»; прежний токен сразу перестаёт действовать. При выключенном входе через Telegram этот блок работает только с этой же машины (127.0.0.1). В редакторе конфига, в логе и в ответе GET /api/settings/config токен скрыт (видны последние 4 символа), а через редактор и POST /api/settings/config его изменить нельзя.

Новый токен через API: POST /api/settings/api-token/regenerate, ответ { "success": true, "api_token": "..." }.

Без токена, с той же машины#

Если вход через Telegram выключен ("auth_telegram": false), запросы без токена принимаются только с этой же машины по адресу 127.0.0.1 или localhost:

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

С других адресов без токена API отвечает 401. Веб-интерфейс при выключенном входе по-прежнему открыт любому, кто может подключиться к порту, поэтому на сервере с открытым портом оставляйте вход включённым.

Запросы со страниц других сайтов (POST с заголовком Origin, не совпадающим с адресом бота) отклоняются с кодом 403 — это защита от CSRF. curl, скрипты и MCP-клиенты заголовок Origin не отправляют, их это не касается. Если бот стоит за обратным прокси, прокси должен передавать исходный заголовок Host.

Запросы и ответы#

  • Тело POST-запросов — JSON в кодировке UTF-8 (Content-Type: application/json).
  • Имена в пути URL-кодируются: стратегия T4 BTC → /api/settings/strategy/T4%20BTC.
  • Настройки и конфиги передаются и возвращаются в том же виде, что и в JSON-файлах бота.
  • Успешное действие возвращает { "success": true, ... }.
  • Ошибка возвращает { "success": false, "error": "текст ошибки" } с кодом из таблицы Коды ответов.
  • Бот определяется аккаунтом и именем стратегии: /{accountName}/{settingsName}. Если стратегия торгует несколькими парами, нужную пару выбирает параметр ?symbol=. Без него берётся первая.

Настройки#

GET/api/settings/config#

Глобальный конфиг программы (settings_program.json). Токен Telegram-бота замаскирован: видны первые 4 символа. api_token замаскирован: видны последние 4 символа.

200 Ответ
{
  "name": "MyBot",
  "use_web": true,
  "port": 5000,
  "api_token": "••••••••••••b9c2",
  "telegram": {
    "bot_token": "1234************",
    "id_chat": 123456789
  }
}
Ошибки
  • 503конфиг ещё не загружен
POST/api/settings/config#

Изменяет глобальный конфиг и сразу применяет его. Передавайте только поля, которые меняются, — остальные останутся как были. Токен Telegram-бота, api_token и tester_data_dir здесь не меняются: эти поля в теле игнорируются.

Запрос
{ "name": "MyBot", "chart": { "count": 500 } }
200 Ответ
{ "success": true }
Ошибки
  • 400пустое тело или неверный JSON
  • 500не удалось сохранить
POST/api/settings/api-token/regenerate#

Выпускает новый api_token; прежний сразу перестаёт действовать. Это единственный ответ API, в котором токен виден целиком. Тело не нужно.

200 Ответ
{ "success": true, "api_token": "<новый токен>" }
Ошибки
  • 500не удалось сохранить
GET/api/settings/hints/{kind}#

Описания полей настроек — те же подсказки, что показывает редактор настроек. {kind}:

  • settings — настройки стратегий (бота и тестера), для всех стратегий сразу;
  • config_tester — конфиг тестера, включая parameter_mining, walk_forward и столбцы reports_history.csv;
  • settings_program — глобальный конфиг.

Параметры:

  • ?lang= — en (по умолчанию), ru или pt;
  • ?filter= — только поля, в пути которых есть одна из подстрок через запятую, например ?filter=zigzag,close_by_margin.
200 Ответ
объект «путь поля через точку → описание»:
{
  "parameter_mining": "List of parameters to mine. Each has a name (parameter path) and either a start/end/step range or a values list...",
  "monte_carlo": "Mining limit: if there are more combinations than this number, a random sample of this size is used..."
}
Ошибки
  • 404неизвестный {kind}
GET/api/settings/schema#

Какие поля настроек на что-то влияют. ?strategy= — код стратегии (basic.strategy); без него — карта по всем стратегиям.

200 Ответ ?strategy=zz, сокращённо
{
  "strategy": "zz", "type": "trend",
  "sections": ["zz"],
  "ignored_sections": ["hd", "zigzag", "mrs2", "..."],
  "position_filter": true, "supported_in_tester": true,
  "conditional_fields": [
    { "fields": ["zz.depth", "zz.detection", "zz.open", "..."], "active_when": "zz.type = ZZ2" },
    { "fields": ["zz.zz6_*"], "active_when": "zz.type = ZZ6" },
    { "fields": ["zz.ma_filter"], "active_when": "zz.use_ma_filter = true" },
    { "fields": ["basic.balance_percentage_long", "basic.risk_long"], "active_when": "basic.use_long = true and basic.lot_long = 0" }
  ],
  "notes": { "zz.zz6_risk_max": "ZZ6 only caps the lot multiplier ..." },
  "tester_ignores": { "basic.leverage": "the tester does not model leverage ..." },
  "shared_fields": ["zz.from_level_price"]
}
  • sections — секции, которые читает стратегия; секции из ignored_sections она не читает. Общие секции (basic, options, filter, exchange) в списках не указаны.
  • position_filter — стратегия учитывает filter; поля filter.<имя>.* действуют, только когда filter.<имя>.use = true.
  • conditional_fields — поля, которые действуют только при условии. * в конце — все поля с этим началом.
  • notes — поля, которые влияют на результат только в крайних случаях (перебор по ним часто даёт одинаковые строки).
  • tester_ignores — поля, которых тестер не моделирует.
  • shared_fields — поля секции, которые читают и другие стратегии.

Поле без правила считается действующим. Те же правила дают предупреждения warnings при сохранении настроек и запуске тестера.

Ошибки
  • 404неизвестная стратегия

Стратегии#

GET/api/settings/strategy#

Все стратегии бота.

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

Одна стратегия по имени (без учёта регистра).

Ошибки
  • 404не найдена
POST/api/settings/strategy/draft#

Черновик стратегии со значениями по умолчанию для выбранного аккаунта. Ничего не сохраняет: поправьте результат и отправьте в POST /api/settings/strategy.

Запрос
{ "account": "main", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h", "account_type": "UNIFIED" }

Вместо symbol можно передать symbols: ["BTCUSDT", "ETHUSDT"] — стратегия на несколько пар. time_frame (по умолчанию 1h) и account_type необязательны.

200 Ответ
объект стратегии
Ошибки
  • 400не указаны стратегия или пара
  • 404аккаунт не найден
POST/api/settings/strategy#

Создаёт или изменяет стратегию. Тело — объект стратегии, как в GET /api/settings/strategy/{name}. Изменения сразу применяются к работающим ботам, новая стратегия сразу запускается.

?old_name= — переименовать стратегию old_name в имя из тела.

Запрос
POST /api/settings/strategy?old_name=T4%20BTC
200 Ответ
{ "success": true, "name": "T4 BTC v2", "created": false, "warnings": null }

created: true — стратегия новая. warnings — изменённые поля, которые стратегия не читает (см. /api/settings/schema); null — замечаний нет.

Ошибки
  • 400не заполнены name, exchange.name, exchange.account или basic.strategy либо имя содержит недопустимые символы
  • 500не удалось сохранить
POST/api/settings/strategy/{name}/copy#

Копирует стратегию под новым именем, сохраняет и запускает копию.

Запрос
{ "new_name": "T4 ETH", "new_symbol": "ETHUSDT" }

new_symbol необязателен: без него пара остаётся как у исходной стратегии.

200 Ответ
{ "success": true, "name": "T4 ETH" }
Ошибки
  • 404исходная стратегия не найдена
  • 409стратегия с таким именем уже есть
POST/api/settings/strategy/from-tester#

Создаёт стратегию бота из проверенной настройки тестера. Настройка копируется как есть; exchange.name и exchange.account берутся от аккаунта. По умолчанию стратегия создаётся на паузе (is_runing: false): бот её загружает, но не торгует, пока её не запустят (play).

Запрос
{ "folder": "lut_now", "name": "T_BTC", "account": "demo_bybit", "new_name": "T_BTC live", "start": false }
  • folder — папка настроек тестера, см. Папка настроек в запросе;
  • new_name — имя стратегии; без него — как у настройки;
  • start: true — сразу запустить торговлю.
200 Ответ
{ "success": true, "name": "T_BTC live", "account": "demo_bybit", "exchange": "bybit", "is_runing": false, "warnings": null }

warnings — как у сохранения стратегии, плюс предупреждение, если настройку проверяли на другой бирже, чем у аккаунта.

Ошибки
  • 404настройка тестера или аккаунт не найдены
  • 409стратегия с таким именем уже есть
  • 500не удалось сохранить
POST/api/settings/strategy/{name}/delete#

Удаляет стратегию и останавливает её ботов. Ордера и позиция на бирже при этом не трогаются.

?full=1 — полное удаление: стратегия ставится на паузу, все её ордера отменяются, позиция закрывается, и только потом стратегия удаляется. Если отменить ордера или закрыть позицию не удалось, стратегия остаётся на паузе и не удаляется — позиция не останется без управления.

Как правильно отключить стратегию. Позиция и ордера на паузе остаются на бирже без управления стратегией (её стопов, тейков и выходов), поэтому их нельзя бросать. Порядок:

  1. пауза;
  2. снять ордера;
  3. закрыть позицию;
  4. удалить настройку.

?full=1 делает именно это: после паузы ждёт завершения текущего цикла бота, чтобы он не успел выставить новый ордер. Вручную — тот же порядок, и паузу пропускать нельзя: работающий бот выставит ордера заново сразу после отмены.

Запрос
POST /api/settings/strategy/T4%20BTC/delete?full=1
200 Ответ
{ "success": true }
Ошибки
  • 404не найдена
  • 409для full=1 стратегия должна быть запущена
  • 500не удалось отменить ордера, закрыть позицию или удалить стратегию

Аккаунты#

Аккаунт — это API-ключ биржи, от имени которого торгуют стратегии.

GET/api/settings/accounts#

Все аккаунты.

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

Один аккаунт по имени (без учёта регистра).

Ошибки
  • 404не найден
GET/api/settings/accounts/{name}/symbols#

Пары, доступные на бирже для этого аккаунта.

200 Ответ
["BTCUSDT", "ETHUSDT"]
Ошибки
  • 404аккаунт не найден
POST/api/settings/accounts#

Создаёт или изменяет аккаунт. Изменения сразу применяются к работающим ботам.

?old_name= — переименовать аккаунт old_name в имя из тела.

Ключи передаются открытым текстом. При "is_encrypted": true бот хранит их зашифрованными. Пустые api_key, api_secret, api_passphrase при изменении оставляют текущие значения; при смене is_encrypted ключ и секрет нужно передать заново.

Запрос
{ "name": "main", "exchange": "binance", "api_key": "...", "api_secret": "...", "is_encrypted": true, "open_positions_limiter": 0 }
200 Ответ
{ "success": true, "name": "main", "applied": 3 }

applied — сколько работающих ботов получили новый ключ.

Ошибки
  • 400не указаны name или exchange, недопустимое имя или не хватает ключей при смене is_encrypted
  • 500не удалось сохранить
POST/api/settings/accounts/{name}/delete#

Удаляет аккаунт.

200 Ответ
{ "success": true }
Ошибки
  • 404не найден
  • 500не удалось удалить
GET/api/current/accounts/{name}/info#

Данные аккаунта и ключа с биржи (обновляются раз в час). Нужен хотя бы один запущенный бот на этом аккаунте.

200 Ответ
{
  "name": "main",
  "exchange": "binance",
  "api_key": "abc1****",
  "account_type": "UNIFIED",
  "symbol": "BTCUSDT",
  "ok": true,
  "status": "OK",
  "warnings": [],
  "rows": [ { "name": "Permissions", "value": "..." } ],
  "updated_utc": "2026-10-25T12:00:00Z"
}
Ошибки
  • 404аккаунт не найден
  • 409на аккаунте нет запущенного бота
GET/api/current/accounts/{name}/balance-history#

История баланса аккаунта. ?max= — не больше стольких точек (по умолчанию 5000).

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

time — Unix-время в секундах, total — сколько точек всего в истории.

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

Сжимает историю баланса сейчас по настройкам monitoring (обычно это происходит автоматически).

200 Ответ
{ "success": true, "message": "...", "points_before": 12000, "points_after": 3000, "bytes_before": 512000, "bytes_after": 128000 }

Боты#

Бот — это запущенная стратегия на конкретной паре.

GET/api/current/bots#

Сводка по всем ботам.

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

is_runing: false — бот на паузе. position: null — позиции нет. orders — число открытых ордеров. sync_missed_cycles — сколько циклов подряд не удалось получить данные с биржи.

GET/api/current/balances#

Баланс кошелька и маржи по каждому API-ключу, отдельно для спота и фьючерсов. ?account= — только этот аккаунт.

Запрос
GET /api/current/balances?account=main
200 Ответ
[
  { "account": "main", "exchange": "bybit", "type": "futures", "wallet": 1234.56, "margin": 1180.20 },
  { "account": "main", "exchange": "bybit", "type": "spot", "wallet": 500.00, "margin": 500.00 }
]

wallet — баланс кошелька, margin — маржинальный баланс, как их отдаёт биржа. Для спота оба значения — баланс в USDT. Баланс берётся у запущенных ботов: аккаунт без запущенного бота в список не попадает.

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

Свечи бота. ?limit= — последние N свечей (по умолчанию 500).

Запрос
GET /api/current/bots/main/T4%20BTC/bars?limit=100
200 Ответ
массив свечей с полями Timestamp, Open, High, Low, Close, Volume и др.
Ошибки
  • 404бот не найден
GET/api/current/ubots#

Полный снимок состояния всех ботов. Набор полей подробный и может меняться между версиями — для постоянной интеграции используйте GET /api/current/bots, /api/current/positions и /api/current/orders.

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

Полный снимок состояния одного бота (см. оговорку выше).

Ошибки
  • 404бот не найден
POST/api/bots/pause-all#

Ставит на паузу всех ботов.

200 Ответ
{ "success": true, "count": 5 }
POST/api/bots/play-all#

Запускает всех ботов.

200 Ответ
{ "success": true, "count": 5 }
POST/api/bots/{accountName}/{settingsName}/pause#

Ставит стратегию на паузу (для стратегии на несколько пар — все её пары): она перестаёт выставлять ордера. Открытая позиция и ордера остаются на бирже без управления стратегией — после паузы либо снова запустите её, либо снимите ордера и закройте позицию (см. удаление).

Запрос
POST /api/bots/main/T4%20BTC/pause
200 Ответ
{ "success": true, "name": "T4 BTC", "is_runing": false }
Ошибки
  • 404не найдена
  • 500не удалось сохранить
POST/api/bots/{accountName}/{settingsName}/play#

Запускает стратегию, поставленную на паузу.

200 Ответ
{ "success": true, "name": "T4 BTC", "is_runing": true }
Ошибки
  • 404не найдена
  • 500не удалось сохранить
POST/api/bots/{accountName}/{settingsName}/send-chart#

Отправляет график бота в Telegram.

200 Ответ
{ "success": true }
Ошибки
  • 404бот не найден
  • 500не удалось построить или отправить график
POST/api/bots/{accountName}/{settingsName}/send-position#

Отправляет в Telegram сводку по боту: баланс, позиция, PnL, ордера.

200 Ответ
{ "success": true }
Ошибки
  • 404бот не найден
POST/api/delete/{accountName}/{settingsName}#

Удаляет стратегию бота и убирает бота из работы. Ордера и позиция на бирже не снимаются и остаются без управления. Для безопасного отключения используйте POST /api/settings/strategy/{name}/delete?full=1.

Запрос
POST /api/delete/main/T4%20BTC
200 Ответ
{ "success": true }
Ошибки
  • 404бот не найден
  • 500не удалось удалить

Позиции и ордера#

GET/api/current/positions#

Позиции всех ботов.

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

Открытые ордера всех ботов.

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

Рыночный ордер на аккаунте. Пара должна торговаться одним из ботов этого аккаунта.

Запрос
{ "account": "main", "symbol": "BTCUSDT", "side": "Buy", "size": 0.01 }

side — Buy или Sell; size — объём в единицах биржи для этой пары.

200 Ответ
{ "success": true, "order_id": "order-123" }
Ошибки
  • 400неверные side или size
  • 404на аккаунте нет бота с этой парой
  • 500биржа не приняла ордер
POST/api/positions/{accountName}/{settingsName}/close#

Закрывает позицию бота.

Запрос
POST /api/positions/main/T4%20BTC/close
200 Ответ
{ "success": true }
Ошибки
  • 404бот не найден
POST/api/positions/{accountName}/close-all#

Закрывает все открытые позиции аккаунта.

200 Ответ
{ "success": true, "count": 3 }

count — сколько позиций отправлено на закрытие.

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

Сокращает все открытые позиции аккаунта на заданный процент.

Запрос
{ "percent": 50 }

percent — от 1 до 100.

200 Ответ
{ "success": true, "count": 3 }
POST/api/orders/{accountName}/{settingsName}/{orderId}/cancel#

Отменяет один ордер бота (обычный или стоп-ордер).

Запрос
POST /api/orders/main/T4%20BTC/order-123/cancel
200 Ответ
{ "success": true }
Ошибки
  • 404ордер не найден
  • 500биржа не отменила ордер
POST/api/orders/{accountName}/cancel-all#

Отменяет все ордера аккаунта.

200 Ответ
{ "success": true, "count": 2 }

count — у скольких ботов отменены ордера.

POST/api/orders/cancel-all#

Отменяет все ордера на всех аккаунтах.

200 Ответ
{ "success": true, "count": 7 }

Система и логи#

GET/api/system/status#

Версия программы, ресурсы сервера и счётчики. Поля pid, exe_path, working_directory, port (порт, на который пришёл запрос) и started_utc однозначно определяют экземпляр процесса: по ним внешний скрипт отличает несколько запущенных ботов и замечает перезапуск (меняются pid и started_utc).

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

Завершает программу. Доступно только при входе через Telegram. Сама программа не запустится: перезапуск процесса делает внешний супервизор (служба, systemd, скрипт). Проверить, что супервизор поднимает бота через 61 секунду после остановки (RestartSec=61, run_service.cmd), можно скриптом tools/check-shutdown-restart.ps1 (останавливает работающий бот). Инструмента restart_program нет. Он обычно и не нужен: изменения стратегий, аккаунтов и настроек через API применяются к работающим ботам сразу. Обновление с перезапуском — POST /api/system/update. После перезапуска убедитесь по pid и started_utc из /api/system/status, что поднялся новый процесс. Перед остановкой проверьте, что нет прогона тестера: он прервётся, а очередь не сохраняется.

200 Ответ
{ "success": true } — программа завершится через полсекунды
Ошибки
  • 409вход через Telegram не настроен
POST/api/system/update#

Запускает обновление программы.

200 Ответ
{ "success": true }
Ошибки
  • 409автообновление на этой системе не поддерживается (см. auto_update_supported в /api/system/status)
  • 500обновление не запустилось
GET/api/logs#

Последние строки общего лога. ?tail= — сколько последних строк (по умолчанию все доступные).

200 Ответ
массив строк
GET/api/logs/errors#

Ошибки за последние ?hours= часов (по умолчанию 24, не больше 48). ?warnings=1 — вместе с предупреждениями. Если Telegram не настроен (telegram.id_chat = 0), сообщения не отправляются и ошибок «chat not found» нет: в лог один раз за запуск пишется предупреждение Telegram chat is not set. Ошибка «chat not found» при заданном чате означает неверный id чата или токен. Повторы уже сгруппированы: одинаковые сообщения одного источника объединены в одну запись, count — сколько раз повторилось за всё хранимое окно (до 48 часов, с запуска программы), first_utc и last_utc — первое и последнее появление. Записи идут от свежих к старым.

?since= — время UTC (например 2026-11-02T06:00:00Z; без часового пояса считается UTC): вернутся только записи, повторявшиеся после него. Для проверки «что нового с прошлого раза» передайте самый поздний last_utc из предыдущего ответа. Если first_utc записи раньше since, это старая ошибка, которая случилась снова, а count остаётся общим. Неверная дата — 400.

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

Файлы логов, свежие первыми; каждый день — новый файл. ?contains= — только файлы, в имени которых есть текст (имя стратегии, аккаунта, пара).

Виды логов:

  • лог стратегии — log_<дата>_<Биржа> <аккаунт> <пара> <таймфрейм> <стратегия> <имя>.log, по одному на бота: сигналы, ордера, исполнения, позиция, ошибки стратегии;
  • лог аккаунта — log_<аккаунт>_<дата>.log: балансы и позиции с биржи, ответы и ошибки API биржи, лимитер позиций, close_by_margin;
  • общий лог программы — log_<дата>.log (/api/logs);
  • логи тестера — TESTER_*.log.

Формат даты в именах разный, поэтому файл удобнее искать через contains.

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

Содержимое файла лога как текст. ?download=1 — скачать файлом.

Ошибки
  • 400недопустимое имя файла
  • 404файл не найден

Тестер#

Тестер прогоняет стратегии на исторических данных. Перебор параметров, стресс-тест и повтор по snapshot выполняются по одному. Одиночные прогоны можно запускать параллельно. Пока загружаются исторические данные, тестер не запускается, и наоборот — в этих случаях ответ 409.

Все запуски работают в фоне: ответ приходит сразу, ход и результат — в GET /api/tester/status.

GET/api/tester/status#

Состояние тестера.

200 Ответ
{
  "run": {
    "active": true,
    "status": "Running",
    "started_utc": "2026-10-25T12:00:00Z",
    "finished_utc": null,
    "message": "API mining run",
    "runs_done": 40,
    "runs_total": 120,
    "current_bar": 5000,
    "total_bars": 20000,
    "parallel": false,
    "report_folders": ["T4"],
    "result_files": ["T4/reports_history.csv", "T4/report_optimizer_T4_auto_x_auto_y_20261025_120000.html", "T4/run_snapshot_T4_20261025_115500.json"]
  },
  "wizard_runs": [
    {
      "run_id": "a1b2c3d4",
      "strategies": ["T4 BTC"],
      "status": "Completed",
      "started_utc": "2026-10-25T11:00:00Z",
      "finished_utc": "2026-10-25T11:02:00Z",
      "current_bar": 20000,
      "total_bars": 20000,
      "message": "Completed: 1 strategies.",
      "report_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
      "report_json_path": null,
      "snapshot_path": "T4/run_snapshot_T4_20261025_110000.json",
      "stats": null,
      "warnings": []
    }
  ],
  "download": { "active": false, "status": "Idle", "started_utc": null, "finished_utc": null, "message": "", "result": null },
  "settings_folder": ""
}
  • run — перебор параметров, стресс-тест или повтор по snapshot. status: Idle, Running, Completed или Failed; runs_done / runs_total — сколько комбинаций параметров посчитано. report_folders — папки результатов текущего или последнего прогона внутри root=report; result_files — итоговые файлы, уже записанные в них с начала прогона: reports_history.csv, сводный HTML (report_optimizer_*, stress_test_*, walk_forward_*) и snapshot.
  • queue — запуски полного режима, ждущие своей очереди (?queue=1): queue_id, position, message, queued_utc.
  • wizard_runs — одиночные прогоны. Завершённые видны ещё час. Метрики (stats) здесь не передаются — они в /api/tester/wizard-runs/{run_id}. У прогонов пакета, ещё не начатых, status: "Queued".
  • batches — пакеты одиночных прогонов: batch_id, done из total.
  • download — загрузка исторических данных.
  • settings_folder — текущая папка настроек тестера.
GET/api/tester/config#

Конфиг тестера (config_tester.json): период, комиссии, параметры перебора и т. д.

POST/api/tester/config#

Сохраняет конфиг тестера. Тело — конфиг целиком, как в GET /api/tester/config.

200 Ответ
{ "success": true }
Ошибки
  • 400пустое тело или неверный JSON
  • 500не удалось сохранить
GET/api/tester/data-coverage#

Какие исторические данные уже скачаны: ?exchange= (обязательно), ?symbols=A,B (без него — все скачанные пары биржи), ?start=&end= — период для проверки.

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

gap_days — дни без данных между первым и последним. period есть только при start и end. Учитываются только скачанные файлы: недостающее докачивает сам прогон (UpdateData) или download-data.

Ошибки
  • 400биржа не поддерживается или задан только один из start / end
GET/api/tester/exchanges#

Биржи, для которых тестер умеет загружать исторические данные.

200 Ответ
["bybit", "binance", ...]
GET/api/tester/exchanges/{exchange}/symbols#

Пары биржи. Пустой список — биржа сейчас недоступна; пару можно указать вручную.

Ошибки
  • 404тестер не поддерживает эту биржу

Папка настроек в запросе#

Все запросы к настройкам тестера, запуски и загрузка данных принимают папку настроек: ?folder= в адресе или поле folder в теле запуска. Это путь внутри tester/settings_strategy, "" — основная папка. Без folder используется папка, выбранная в интерфейсе (POST /api/tester/settings-folder). Это общее состояние: его может сменить пользователь или параллельная задача, поэтому скриптам и ассистентам лучше всегда передавать folder.

Несуществующая папка — ошибка 404. Создать папку — POST /api/tester/settings-folders.

У настройки могут быть необязательные поля tags (список меток) и owner (автор, например "MCP"). По ним настройки отбираются в списке и удаляются разом.

GET/api/tester/settings#

Настройки стратегий тестера в папке. Параметры:

  • ?folder= — папка;
  • ?mask= — только имена по маске (* — любые символы, ? — один символ);
  • ?tag=, ?owner= — только с этой меткой или этим автором;
  • ?full=1 — настройки целиком вместо краткой формы: выгрузка папки, которую восстанавливает /api/tester/settings/import.
200 Ответ
[ { "name": "T4 BTC", "exchange": "bybit", "symbol": "BTCUSDT", "symbols": null, "strategy": "zigzag", "time_frame": "1h", "tags": ["tmp"], "owner": "MCP" } ]
GET/api/tester/settings/{name}#

Настройка тестера целиком. ?folder= — папка.

Ошибки
  • 404не найдена
POST/api/tester/settings/draft#

Черновик настройки тестера со значениями по умолчанию. Ничего не сохраняет.

Запрос
{ "exchange": "bybit", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }

Вместо symbol можно передать symbols — несколько пар. account_type необязателен.

200 Ответ
объект настройки
Ошибки
  • 400тестер не поддерживает биржу либо не указаны стратегия или пара
POST/api/tester/settings#

Сохраняет настройку тестера. Тело — объект настройки. ?old_name= — переименовать настройку old_name. Существующая настройка с тем же именем не перезаписывается. ?folder= — папка. ?owner_default= — значение owner, если в настройке его нет (MCP передаёт MCP).

200 Ответ
{ "success": true, "name": "T4 BTC", "folder": "", "warnings": null }

warnings — изменённые (не как по умолчанию) поля, которые ни на что не влияют: секция другой стратегии (одна строка на секцию), поле другого zz.type, выключенный включатель use_*, basic.leverage (тестер плечо не моделирует) — см. /api/settings/schema. null — замечаний нет. Сохранение предупреждения не отменяют.

То же поле warnings есть в ответе копирования настройки, а у импорта — warnings по имени каждой настройки.

Ошибки
  • 400не заполнены обязательные поля
  • 409настройка с таким именем уже есть
  • 500не удалось сохранить
POST/api/tester/settings/{name}/copy#

Копирует настройку тестера в той же папке (?folder=), при желании — на другую биржу или пару. ?owner_default= — как у сохранения. Скопировать в другую папку — copy-to-folder.

Запрос
{ "new_name": "T4 BTC binance", "new_exchange": "binance", "new_symbol": "" }

Пустые new_exchange и new_symbol оставляют значения исходной настройки.

200 Ответ
{ "success": true, "name": "T4 BTC binance" }
Ошибки
  • 404исходная настройка не найдена
  • 409имя занято
POST/api/tester/settings/{name}/delete#

Удаляет настройку тестера. ?folder= — папка. Удалить много настроек разом — delete-matching.

200 Ответ
{ "success": true }
Ошибки
  • 404не найдена
GET/api/tester/settings-folder#

Текущая папка настроек тестера и её вложенные папки. Папки позволяют держать несколько наборов настроек; "" — основная папка.

200 Ответ
{ "path": "", "folders": [ { "name": "2026-10", "settings": 12 } ] }

settings — сколько настроек в папке.

POST/api/tester/settings-folder#

Выбирает папку настроек тестера для интерфейса и для запросов без folder.

Запрос
{ "path": "2026-10" }
200 Ответ
{ "success": true, "path": "2026-10" }
Ошибки
  • 404папка не найдена
POST/api/tester/settings-folders#

Создаёт папку настроек, вложенные тоже. Выбранную папку не меняет.

Запрос
{ "path": "research/zz_hedge" }
200 Ответ
{ "success": true, "path": "research/zz_hedge", "created": true }

created: false — папка уже была.

Ошибки
  • 400пустой путь, .. или недопустимые символы в имени
POST/api/tester/settings-folders/delete#

Удаляет папку настроек со всем содержимым. Основную папку удалить нельзя. Если удалена выбранная папка, выбранной становится основная.

Запрос
{ "path": "research/zz_hedge" }
200 Ответ
{ "success": true, "deleted_settings": 12 }
Ошибки
  • 404папка не найдена или это основная папка
POST/api/tester/settings/copy-to-folder#

Копирует настройки из одной папки в другую.

Запрос
{ "from": "mrs-bybit", "to": "lut_now", "names": ["C_MU", "T_*"], "on_conflict": "replace" }

Какие настройки копировать — names (имена или маски), mask ("*" — все), tag, owner; фильтры сочетаются, нужен хотя бы один. on_conflict — что делать, если имя в папке назначения уже есть: skip (по умолчанию), replace или error (ничего не копировать).

200 Ответ
{ "success": true, "copied": ["C_MU"], "replaced": ["T_BTC"], "skipped": [] }
Ошибки
  • 400нет фильтра, имя без маски не найдено, папки совпадают или конфликт при on_conflict: "error"
  • 404папка не найдена
POST/api/tester/settings/delete-matching#

Удаляет настройки папки по фильтру.

Запрос
{ "folder": "lut_now", "owner": "MCP", "tag": "tmp" }

Фильтры — как у copy-to-folder, нужен хотя бы один.

200 Ответ
{ "success": true, "folder": "lut_now", "deleted": ["MCP_LZ1"], "not_found": [] }
Ошибки
  • 400нет фильтра
  • 404папка не найдена
POST/api/tester/settings/import#

Сохраняет набор настроек в папку, например выгрузку GET /api/tester/settings?full=1.

Запрос
{ "folder": "lut_now", "settings": [ { ... }, { ... } ], "on_conflict": "skip", "owner_default": "MCP" }
200 Ответ
{ "success": true, "folder": "lut_now", "saved": ["T_BTC"], "skipped": [], "warnings": { "T_BTC": ["..."] } }
Ошибки
  • 400неверная настройка или конфликт при on_conflict: "error"
  • 404папка не найдена
GET/api/tester/settings-check#

Проверка настроек папки без запуска — те же замечания, что warnings при сохранении. ?folder= — папка, ?mask= — имя или маска (по умолчанию все).

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

В settings — только настройки с замечаниями.

Ошибки
  • 404папка не найдена
POST/api/tester/run#

Перебор параметров стратегий (раздел parameter_mining конфига тестера).

Запрос
{
  "settings": ["*"],
  "folder": "lut_now",
  "config": { ... },
  "overrides": [
    { "match": "T_*", "mul": { "basic.balance_percentage_long": 2 } },
    { "match": "C_MU", "set": { "basic.use_short": false } },
    { "match": "L_X", "exclude": true }
  ]
}
  • settings — имена настроек или маски ("*" — все настройки папки). Имя без маски, которого нет в папке, — ошибка.
  • folder — папка настроек, см. Папка настроек в запросе.
  • config необязателен: без него используется сохранённый конфиг тестера.
  • overrides — правки настроек только на этот запуск; файлы настроек не меняются. Правила применяются по порядку. match — имя или маска (по умолчанию все), tag — только настройки с этим тегом. set заменяет значения, mul умножает числа (целое поле остаётся целым), cap_pct после них ограничивает basic.balance_percentage_long и _short этих настроек — множитель размера с потолком на пару: { "match": "T_*", "mul": { "basic.balance_percentage_long": 2, "basic.balance_percentage_short": 2 }, "cap_pct": 10 }. exclude: true убирает настройки из запуска. Поля — пути через точку, как в объекте настройки. Если поля нет ни в одной подходящей настройке, это ошибка (обычно опечатка); если его нет только у части, эти настройки перечислены в not_applied. Правки записываются в comment прогона и попадают в отчёт и snapshot.
200 Ответ
{
  "success": true,
  "folder": "lut_now",
  "strategies": ["C_MU", "T_BTC"],
  "applied": [ { "name": "T_BTC", "changes": ["basic.balance_percentage_long: 10.0 → 20.0"], "not_applied": [] } ],
  "excluded": ["L_X"]
}

Что можно перебирать. Любую настройку бота (settings[*].zz.depth, settings[T_*].basic.use_short, settings[NAME].…), любое поле конфига тестера (config_tester.…), settings_program.… и аккаунта. Для чисел достаточно start/end/step, для остальных (текст, логические) задаётся values.

Скрининг пар. Файл настроек на каждую пару не нужен: берётся одна настройка-шаблон, а символ перебирается как обычный параметр. Список пар — из tester_exchange_symbols:

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

Вместе с другими параметрами (например, settings[*].zz.depth) получается сетка на каждую пару. Символ попадает в столбец reports_history.csv, так что сводку «пара → медиана по сетке» считают по этому файлу (read_tester_file с columns). Данные для всех перебираемых пар скачивает tester_download_data. Число комбинаций равно произведению длин списков значений: ограничивайте его monte_carlo.

Тестер прогоняет все комбинации значений из parameter_mining; если задан monte_carlo, то случайную выборку такого размера. Заранее проверяйте число комбинаций; остановить запущенный перебор — POST /api/tester/stop с full: true. Ход — в run ответа GET /api/tester/status (runs_done из runs_total).

Результаты попадают в папку report с именем, равным name_comment конфига тестера (недопустимые в имени файла символы заменяются на _). Ответ на запуск возвращает её в report_folders; при включённом walk_forward там же вторая папка <name_comment>_WF_OOS с прогонами вне выборки. Чтобы эксперименты не смешивались, давайте каждому свой name_comment. В папке:

  • reports_history.csv — по строке на комбинацию: метрики (TotalPnLPercent, MaxDrawdownPercent, ProfitFactor, WinRate, TradingVolume, …), Strategies (имена настроек прогона через |), RunTag и столбец со значением каждого перебираемого параметра. При single_mode в каждой строке одна настройка, блоки комбинаций идут по имени настройки;
  • HTML-отчёт каждой комбинации (если включён report.enable_html_report) и его JSON-версия (если включён report.enable_json_report); RunTag комбинации есть в имени файла;
  • сводный отчёт оптимизатора report_optimizer_*.html;
  • run_snapshot_<name_comment>_<время>.json — точные настройки и конфиг запуска, см. snapshot-run.

periods — перебор на нескольких периодах: [["2026-02-01","2026-05-01"], ["2026-05-01","2026-08-01"]]. Каждый период — отдельный полный прогон в папку <name_comment>_<начало>_<конец>; они идут друг за другом через очередь. Ответ — { "success": true, "periods": [ { "start", "end", "report_folders", "queued", "queue_id", "position" } ], ... }. Сравнить периоды — /api/tester/mining-robustness.

Предупреждения запуска. Ответ на запуск содержит warnings (null — замечаний нет):

  • параметр parameter_mining, которого нет ни в настройках, ни в конфигах (опечатка: он не применится);
  • перебираемое поле, которое подходящие настройки не читают (ignored by all N matching settings: все комбинации дадут одинаковый результат) или читают не все; условия по полям, которые сами перебираются, не проверяются;
  • заметка о поле, которое влияет только в крайних случаях (zz.zz6_risk_max);
  • поле из overrides, которое настройка не читает.

Предупреждения запуск не отменяют.

Одиночные прогоны и пакеты пишут эти предупреждения и в итоги прогона (warnings у wizard-runs/{run_id}), пакет — ещё и в общий warnings с префиксом runs[i] <имя>. Запуск по snapshot проверяется так же.

Портфельный перебор. Без single_mode все настройки идут вместе в каждой комбинации. Параметр с именем settings[ИМЯ].путь меняет одну настройку, а settings[T_*].путь — все настройки по маске имени; остальной набор остаётся как есть. Сравнивайте строки по портфельным MaxDrawdownPercent и UlcerIndex (включите reports_history.ulcer_index).

sides — стороны торговли на этот запуск: long (только лонг), short (только шорт), split (каждая настройка дважды — <имя> [long] и <имя> [short]; при single_mode стороны майнятся отдельно) или both (как в настройках).

?queue=1 — если тестер занят другим полным прогоном или загрузкой данных, запуск встаёт в очередь, а не получает 409. Ответ тогда — { "success": true, "queued": true, "queue_id": "63a8e791", "position": 1, ... }; запуск начнётся сам, очередь видна в queue ответа GET /api/tester/status, отменить ещё не начатый — POST /api/tester/queue/{queue_id}/cancel.

Ошибки
  • 400настройка не найдена, неверный config, overrides или sides
  • 404папка не найдена
  • 409тестер уже работает или загружаются данные (без ?queue=1)
POST/api/tester/stress#

Стресс-тест: те же настройки в ухудшенных условиях исполнения. Тело, ?queue=1 и ответы — как у /api/tester/run, кроме periods (не поддерживается). Результаты — в папке <name_comment>_STRESS (report_folders ответа): строки сценариев в reports_history.csv и сравнение с базой в stress_test_*.html.

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

Убирает из очереди полный запуск, который ещё не начался.

200 Ответ
{ "success": true }
Ошибки
  • 404запуск уже начался, отменён или queue_id неверный
POST/api/tester/wizard-run#

Одиночный прогон стратегий. Тело — как у /api/tester/run, включая folder и overrides.

200 Ответ
{ "success": true, "run_id": "a1b2c3d4", "folder": "lut_now", "strategies": ["T4 BTC"], "applied": [], "excluded": [] }

Дождаться прогона и получить его метрики и пути к отчётам — GET /api/tester/wizard-runs/{run_id}?wait=. Ход всех прогонов — в wizard_runs ответа GET /api/tester/status.

Ошибки
  • 400не найдено ни одной из настроек
  • 409загружаются данные
POST/api/tester/wizard-batch#

Пакет одиночных прогонов: несколько наборов, каждый на нескольких периодах, через одну очередь с ограничением параллельности. Так сравнивают варианты и проверяют вариант на нескольких периодах одним запросом.

Запрос
{
  "folder": "lut_now",
  "config": { ... },
  "periods": [["2026-02-01", "2026-05-01"], ["2026-05-01", "2026-08-01"]],
  "parallel": 2,
  "runs": [
    { "name": "base", "settings": ["*"] },
    { "name": "T x2", "settings": ["*"], "overrides": [ { "match": "T_*", "mul": { "basic.balance_percentage_long": 2 } } ] },
    { "name": "long only", "settings": ["*"], "sides": "long" }
  ]
}

Поля набора — как в теле /api/tester/run (settings, folder, config, overrides, sides) плюс name и свои periods. Чего нет в наборе, берётся из пакета. Каждый набор идёт на каждом периоде отдельным прогоном; без periods — на периоде конфига. parallel — сколько прогонов одновременно (по умолчанию 2; каждый держит свои данные в памяти). Ошибка в любом наборе отклоняет весь пакет.

200 Ответ
то же, что GET /api/tester/wizard-batches/{batch_id}, сразу после постановки в очередь.
Ошибки
  • 400пустой runs, неверные periods или ошибка набора (runs[1]: ...)
  • 404папка не найдена
  • 409загружаются данные
GET/api/tester/wizard-batches/{batch_id}#

Пакет и итоги каждого прогона. ?wait= — сколько секунд (до 240) ждать завершения всего пакета.

Длинный пакет (десятки прогонов) в полном виде не помещается в ответ (MCP режет его на 200 000 символов, и JSON становится невалидным), поэтому есть сокращение и страницы. Те же параметры у POST /api/tester/wizard-batch:

ПараметрОписание
compact=1у каждого прогона только name, start, end, run_id, status, run_params, key и пути отчёта (message только у упавших). Без summary, stats, warnings, applied
offset, limitстраница списка runs; limit=0 — только счётчики. В ответе offset, returned и has_more (есть следующая страница: offset + returned). done, total, failed всегда по всему пакету

Если полный ответ длиннее 150 000 символов, он заменяется компактным автоматически (compact: true в ответе); страницы offset/limit при этом сохраняются.

key есть в каждом прогоне, в том числе в полном ответе: главные метрики в одном виде, из summary JSON-отчёта, а если отчёта нет, из итоговых stats: pnl, pnl_percent, max_drawdown_percent, max_drawdown_worst_percent (только при JSON-отчёте), trades, volume, fees, profit_factor (только при JSON-отчёте). Вызывать reports/json на каждый прогон ради них не нужно.

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

summary — как раздел summary JSON-отчёта; он есть, если включён report.enable_json_report, иначе вместо него stats. Строки прогонов пакета попадают и в reports_history.csv папки name_comment (столбцы StartDate, EndDate, Strategies). Пакеты хранятся час.

Ошибки
  • 404пакета нет: неверный batch_id, прошло больше часа или программа перезапускалась
POST/api/tester/stop#

Останавливает прогоны тестера.

Запрос нужно хотя бы одно поле
{ "run_id": "a1b2c3d4", "batch_id": "5e6f7a8b", "full": true, "clear_queue": true }
  • run_id — одиночный прогон (wizard-run);
  • batch_id — все прогоны пакета: ещё не начатые не стартуют;
  • full: true — текущий полный прогон: перебор, стресс-тест, walk-forward, snapshot;
  • clear_queue: true — ещё и убрать из очереди не начатые полные прогоны.

Идущий прогон останавливается на следующей свече. Прерванный прогон не пишет ни отчёт, ни строку reports_history: результат за часть периода ввёл бы в заблуждение. У полного прогона строки уже посчитанных комбинаций остаются; в параллельном режиме дочерние процессы завершаются. Статусы: полный прогон — Stopped в run ответа /api/tester/status, одиночный — Cancelled в wizard-runs/{run_id}. Загрузку исторических данных этот запрос не останавливает.

200 Ответ
{ "success": true, "cancelled_runs": ["a1b2c3d4"], "full_run_stopping": true, "cleared_queue": ["63a8e791"], "note": "Stopping: ..." }
Ошибки
  • 400не передано ни одного поля
  • 404прогон или пакет не найден
GET/api/tester/wizard-runs/{run_id}#

Одиночный прогон по run_id. ?wait= — сколько секунд (до 240) ждать завершения; без него ответ сразу.

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

status — Running, Completed или Failed; Running после wait значит, что время ожидания вышло, — запросите снова. report_path и report_json_path — пути внутри root=report, null, если отчёт не записан. snapshot_path — snapshot прогона: точные настройки и конфиг, с которыми он шёл. warnings — пропущенные настройки, нехватка данных и причина, по которой нет отчёта. Если не запустилась ни одна настройка, прогон завершается со status: "Failed" и причиной в message. Завершённые прогоны хранятся час (до перезапуска программы).

Ошибки
  • 404прогона нет: неверный run_id, прошло больше часа или программа перезапускалась
POST/api/tester/snapshot-run#

Повторяет прогон по snapshot-файлу. Каждый запуск сохраняет snapshot рядом с отчётом — run_snapshot_<name_comment>_<время>.json с разделами settings (настройки всех стратегий), tester_config и program_config. Токены (api_token, telegram.bot_token) в snapshot не записываются. Запуск по snapshot — полный режим: один за раз, как перебор. Файл выбирается параметрами ?root=&path=, как в файлах тестера.

Тело необязательно: можно передать изменённый snapshot — изменения действуют только на этот запуск, файл не меняется. То же в интерфейсе: Тестер, вкладка «Результаты (файлы)», кнопка «Запустить» рядом со snapshot открывает его в редакторе, и правки идут только в этот запуск.

Запрос
POST /api/tester/snapshot-run?root=report&path=T4/run_snapshot_20261025.json

?queue=1 — встать в очередь, если тестер занят, как у /api/tester/run.

200 Ответ
{ "success": true }
Ошибки
  • 400в snapshot нет конфига тестера или настроек
  • 404файл не найден
  • 409тестер уже работает или загружаются данные
POST/api/tester/download-data#

Загружает исторические данные для всех настроек папки (?folder=). Ход и итог — в download ответа GET /api/tester/status.

ПараметрОписание
startНачало периода, например 2026-05-01. По умолчанию StartDate конфига тестера минус WarmupDays
endКонец периода. По умолчанию текущий момент (UTC). EndDate сохранённого конфига не используется, поэтому для докачки свежих дней конфиг менять не нужно
200 Ответ
{ "success": true }

После окончания download.message кратко пишет, по какой день данные есть на диске, а download.result содержит по каждой паре first_day, last_day (последний день со свечами) и days:

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

Свечи закрытого дня источник публикует с задержкой (обычно после 06:00 UTC): до этого last_day остаётся на день раньше, загрузку нужно повторить позже. Пара без данных получает first_day/last_day = null.

Ошибки
  • 400start или end не дата, либо start не раньше end
  • 409загрузка уже идёт или работает тестер
GET/api/tester/wizard-results#

Результаты одиночных прогонов, свежие первыми. Новый прогон того же набора настроек заменяет его прежнюю запись; результат конкретного прогона — в /api/tester/wizard-runs/{run_id}.

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

chartUrl — ссылка на HTML-отчёт для браузера. report_path — тот же отчёт как путь внутри root=report, для файлов тестера и /api/tester/reports/summary. report_json_path — его JSON-версия; поле есть, только если она записана.

GET/api/tester/files#

Содержимое папки тестера. ?root= — report (отчёты, по умолчанию), data (исторические данные: tester/data или папка из tester_data_dir в settings_program.json) или runs (наборы для повторных прогонов); ?path= — путь внутри неё. ?contains= — только имена с этим текстом, ?offset= и ?limit= — часть списка. Сначала идут папки по имени, затем файлы, свежие первыми; total — сколько всего элементов подходит.

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

snapshot: true — файл можно запустить через /api/tester/snapshot-run. editable: true — файл можно изменить через /api/tester/files/save.

Ошибки
  • 404папка не найдена
GET/api/tester/files/download#

Скачивает файл (?root=&path=). HTML-отчёты открываются в браузере.

Ошибки
  • 404файл не найден
POST/api/tester/files/delete#

Удаляет файл или папку (?root=&path=).

200 Ответ
{ "success": true }
Ошибки
  • 400недопустимый путь
  • 404не найдено
  • 409работает тестер или загружаются данные
GET/api/tester/files/content#

Содержимое snapshot-файла или JSON-файла из runs (?root=&path=).

Ошибки
  • 404файл не найден или не является snapshot
POST/api/tester/files/save#

Сохраняет JSON-файл в runs (?root=runs&path=): изменяет существующий или создаёт новый. Тело — новое содержимое файла. Если у существующего файла в теле нет раздела settings, он берётся из текущего файла. Новый файл должен быть полным snapshot: непустой settings и tester_config.

Так готовят прогон для пользователя: в интерфейсе (Тестер, вкладка «Результаты (файлы)», папка runs) у каждого такого файла есть кнопки «Запустить» и «Изменить». При use_runs в конфиге тестера полный прогон из командной строки (--run-tester) запускает все .json из runs.

200 Ответ
{ "success": true, "created": false }
Ошибки
  • 400пустое тело, неверный JSON или новый файл без settings / tester_config
  • 404путь не в runs или не .json
GET/api/tester/reports/summary#

Сводки HTML-отчётов для сравнения прогонов: метрики и кривая доходности. ?r= — путь отчёта в report, параметр можно повторять.

Запрос
GET /api/tester/reports/summary?r=T4/report.html&r=T4_STRESS/report.html
200 Ответ
[
  {
    "report": "T4/report.html",
    "created": "2026-10-25T12:00:00Z",
    "summary": {
      "name_comment": "T4",
      "start": "2025-01-01T00:00:00",
      "end": "2026-01-01T00:00:00",
      "symbols": ["BTCUSDT"],
      "metrics": { "TotalPnLPercent": 42.1, "MaxDrawdownPercent": 12.3, "ProfitFactor": 1.8, "WinRate": 55.0, "TotalTrades": 120 },
      "equity_t": [1735689600],
      "equity_v": [1000.0]
    }
  }
]

equity_t и equity_v — время (Unix, секунды) и баланс точек кривой доходности. summary: null — у отчёта нет сводки.

Ошибки
  • 400не передан ни один r
  • 404отчёт не найден
GET/api/tester/reports/json#

Подробные результаты одного прогона в компактном JSON. Те же числа, что в HTML-отчёте, но файл в десятки раз меньше: несколько десятков килобайт вместо мегабайтов.

Тестер пишет <отчёт>.json рядом с HTML-отчётом, если в конфиге тестера включено report.enable_json_report (по умолчанию выключено). JSON пишется и при выключенном report.enable_html_report: так большой перебор идёт быстрее и всё равно сохраняет детали каждой комбинации.

Параметры:

  • ?path= — путь отчёта в report: файл .json или его .html (например, report_path из wizard-results);
  • ?sections= — только эти разделы через запятую, например ?sections=summary или ?sections=metrics,by_symbol;
  • ?trades_offset= и ?trades_limit= — часть сделок.

Разделы:

РазделСодержимое
summaryсводка на 1–2 КБ: PnL, просадки (в том числе нереализованная и худшая из трёх, как MaxDrawdownPercent в reports_history.csv), Ulcer Index, profit factor, Sharpe, CAGR, сделки, win rate, комиссии, средняя и максимальная позиция, худший месяц, доходность по месяцам. Считается при чтении из run, metrics и monthly, поэтому есть и у старых отчётов
runname_comment, comment, run_tag, run_params (значения перебираемых параметров), период, биржи, стратегии и пары. Что запуск дописал в comment текстом ([overrides: …], [sides: …]), лежит отдельными полями, разбирать comment регуляркой не нужно: overrides (массив правил как в запросе, без обрезки, в comment он обрезается до 300 символов), sides, а также откуда прогон: batch_id и name (имя набора) для tester_run_batch и tester_run_single с periods, run_id для прогонов мастера. Если значения нет, поле null. Запуски из интерфейса эти поля не заполняют, повтор по snapshot берёт их из snapshot
metricsвся таблица статистики HTML-отчёта по блокам: PnL, баланс, доходность по месяцам, сделки, исполнения, Buy & Hold, риск и экспозиция, Sharpe, Sortino, CAGR, Calmar, Ulcer Index…
by_symbolитоги по каждой паре: сделки, win rate, profit factor, PnL, лучшая и худшая сделка, просадка, Buy & Hold, комиссии, объём, размер позиции
monthlyдоходность по месяцам, %: { "2025-09": -4.15 }
tradesсделки (от открытия позиции до полного закрытия или переворота), отсортированные по времени закрытия, — columns и rows
curvesкривые баланса (equity) и открытых позиций (open_positions_total, _long, _short), до 500 точек; t — Unix-время в секундах, v — значения
dailyзначения на конец каждого календарного дня периода, без пропусков: days, equity (Margin-баланс), position (открытая позиция, USDT); strategies — стратегии (настройки) с парами, кодом, типом (trend / counter-trend) и тегами; pnl и position_by_strategy — по массиву на стратегию в том же порядке: накопленный с начала отчёта вклад в баланс и позиция. Пишется при report.json_daily (включено по умолчанию). Для больших наборов раздел большой — сводку по нему даёт /api/tester/reports/portfolio
settingsполные настройки стратегий прогона

Поля v (версия формата), created_utc и html_report (имя HTML-отчёта или null) возвращаются всегда.

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

В trades: count — число всех сделок, net_pnl — результат сделки за вычетом комиссий, mae и mfe — худший и лучший промежуточный результат сделки (USDT), время — UTC.

Ошибки
  • 400файл не является JSON-отчётом
  • 404JSON-отчёт не найден
GET/api/tester/reports/portfolio#

Портфельная аналитика прогона по разделу daily его JSON-отчёта. Стратегии собираются в группы, по группам считается всё, что ниже.

Параметры:

  • ?path= — JSON-отчёт (или его .html) в report;
  • ?group_by= — type (по умолчанию: T — трендовые, CT — контртрендовые, по коду стратегии), tag (первый тег настройки) или strategy (каждая настройка — своя группа);
  • ?groups={"T":"T_*","CT":"CT_*"} — группы по маскам имён вместо group_by; настройки без совпадения попадают в other;
  • ?worst_days= — сколько худших дней каждой группы брать (по умолчанию 10);
  • ?curves=0, ?leave_one_out=0 — не считать эти разделы.
200 Ответ сокращённо
{
  "start": "2026-08-01", "end": "2026-09-30", "days": 61, "group_by": "type",
  "groups": [ { "group": "T", "strategies": 1, "names": ["T_BTW"], "pnl": -7294.0, "pnl_percent": -72.94, "worst_day": -4838.3, "max_drawdown_usdt": 15259.83, "position_max": 12752.08 } ],
  "correlation": { "CT": { "CT": 1.0, "T": -0.28 }, "T": { "CT": -0.28, "T": 1.0 } },
  "worst_week": { "start": "2026-08-08", "end": "2026-08-14", "pnl": -7200.62, "pnl_percent": -40.19, "by_group": { "CT": 279.98, "T": -7480.6 } },
  "worst_days": { "T": { "days": 5, "pnl": -12902.51, "portfolio_pnl": -12754.28, "others": { "CT": { "pnl": 148.22, "offset_percent": 1.1 } } } },
  "leave_one_out": {
    "max_drawdown_percent": 83.43, "ulcer": 59.776,
    "groups": { "T": { "pnl": -7294.0, "max_drawdown_percent_without": 1.54, "drawdown_added": 81.89, "ulcer_without": 0.686, "ulcer_added": 59.09 } },
    "strategies": [ { "name": "T_BTW", "group": "T", "pnl": -7294.0, "max_drawdown_percent_without": 1.54, "drawdown_added": 81.89, "ulcer_without": 0.686, "ulcer_added": 59.09 } ]
  },
  "curves": { "days": ["2026-08-01"], "equity": [10754.72], "position": [0], "pnl_by_group": { "T": [0] }, "position_by_group": { "T": [0] } }
}
  • correlation — корреляция дневного PnL групп;
  • worst_week — худшие 7 дней подряд для портфеля и PnL каждой группы в них;
  • worst_days — для каждой группы её худшие дни: её PnL, PnL портфеля и PnL остальных групп в эти же дни; offset_percent — какую долю убытка отыграла другая группа (меньше нуля — добавила убыток);
  • leave_one_out — максимальная просадка и Ulcer портфеля без каждой стратегии и без каждой группы: drawdown_added больше нуля — стратегия добавляет просадку, меньше нуля — снижает её (хеджирует). Заменяет отдельный прогон набора без каждой стратегии;
  • curves — дневные кривые без пропусков: баланс, позиция, накопленный PnL и позиция каждой группы.

Все величины — по значениям на конец дня: просадки здесь меньше внутридневных из metrics, а leave_one_out приближённый — без влияния стратегий друг на друга через маржу и лимиты позиций.

Ошибки
  • 400у отчёта нет раздела daily (нужны report.enable_json_report и report.json_daily; у старых отчётов его нет) или неверные group_by / groups
  • 404отчёт не найден
GET/api/tester/mining-robustness#

Устойчивость перебора на нескольких периодах: одна и та же сетка parameter_mining, прогнанная на каждом периоде в свою папку (periods у /api/tester/run).

Параметры:

  • ?folders=a,b — папки в report, по периоду в каждой;
  • ?metric= — столбец reports_history.csv, по умолчанию TotalPnLPercent; столбцы просадки, риска и UlcerIndex — чем меньше, тем лучше;
  • ?base={"settings[*].zz.depth": 12} — исходная точка для сравнения;
  • ?top= — сколько комбинаций показать на каждую настройку (по умолчанию 10).

Комбинации сопоставляются по значениям параметров и столбцу Strategies (при single_mode у каждой настройки свой рейтинг). На каждом периоде считается плато — среднее метрики по комбинации и её соседям на сетке (как в разделе устойчивости отчёта оптимизатора). Рейтинг — по среднему плато периодов, затем по худшему периоду.

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

best_by_period — лучшая точка каждого периода и её место в общем рейтинге: низкое место значит, что точка подогнана под свой период. beats_base — комбинация не хуже базовой ни на одном периоде.

Ошибки
  • 400меньше двух папок, нет столбца метрики или слишком мало комбинаций для соседей
  • 404папка не найдена
POST/api/tester/reports/telegram#

Отправляет файл отчёта тестера в Telegram — в чат уведомлений тестера (telegram.id_chat конфига программы, туда же приходят итоги переборов). Отправить можно только файл из report (.html, .json, .csv, .png, .txt, до 50 МБ); к торговле и чатам стратегий доступа нет. Подпись — Tester report: <путь> и caption.

Запрос
{ "path": "T4/T4_BTCUSDT_20261025.html", "caption": "Лучший вариант по просадке" }
200 Ответ
{ "success": true, "path": "T4/T4_BTCUSDT_20261025.html" }

Не чаще одного файла в 10 секунд.

Ошибки
  • 400файл не отчёт или больше 50 МБ, не задан telegram.id_chat
  • 404файл не найден
  • 429слишком часто
  • 502Telegram не принял файл (причина в логе программы)
GET/api/tester/publish/files#

Файлы папки отчёта, которые можно опубликовать на сайт. ?path= — папка в report.

200 Ответ
[ { "name": "reports_history.csv", "size": 10240, "kind": "history" } ]

kind — history (история прогонов), snapshot (snapshot прогона) или summary (сводный отчёт).

Ошибки
  • 404папка не найдена
POST/api/tester/publish#

Отправляет выбранные файлы папки отчёта на сайт. Публикация появляется после модерации.

Запрос
{ "path": "T4", "files": ["reports_history.csv"], "contact": "@telegram", "comment": "...", "agree": true }

agree: true — согласие с условиями публикации, обязательно.

200 Ответ
{ "success": true, "sent": ["reports_history.csv"] }
Ошибки
  • 400нет согласия или не выбраны файлы
  • 404папка не найдена
  • 502сайт не принял публикацию

Коды ответов#

КодЗначение
200Успех
400Неверный запрос: пустое тело, неверный JSON, не заполнены обязательные поля
401Нет доступа: неверный api_token; cookie отсутствует, устарел или заменён новым входом; запрос без токена не с этой же машины
403Запрос со страницы другого сайта (Origin не совпадает с адресом бота)
404Не найдено
409Конфликт: тестер или загрузка данных уже работают, имя занято, нет нужного запущенного бота
429Слишком часто (отправка отчёта тестера в Telegram)
500Внутренняя ошибка или ошибка биржи
502Внешний сервис не принял запрос
503Программа ещё запускается