Logo hamster-bot
RU EN PT

Loading…

API and MCP

Control the bot from scripts, programs and AI assistants

HTTP API for managing the bot and the tester: settings, strategies, exchange API keys, positions and orders, logs, running the tester and working with its reports. The bot also works as an MCP server — an AI assistant can check the bot's state, run research in the tester and manage strategies on its own.

The address is the same as the web interface: http://<host>:<port>. The port is set by the port field in settings_program.json.

Access Requests and responses Endpoints Tester MCP for AI assistants Response codes

Access

API token (recommended)

Send the Authorization: Bearer <api_token> header with every request:

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

The bot creates api_token itself on first start and stores it in settings_program.json. The token works from any address and with any auth_telegram value, and a browser login does not reset it.

You can view and copy the token in the web interface: "Global Config", the "API and MCP token" block. The "Issue new" button is there too — the old token stops working immediately. With Telegram login disabled, this block works only from the same machine (127.0.0.1).

In the config editor, in the log and in the GET /api/settings/config response the token is masked (the last 4 characters are visible), and it cannot be changed through the editor or POST /api/settings/config. A new token via the API: POST /api/settings/api-token/regenerate, response { "success": true, "api_token": "..." }.

⚠️ Keep the token like a password: it gives access to everything, including trading and exchange keys.

Without a token, from the same machine

If Telegram login is disabled ("auth_telegram": false), requests without a token are accepted only from the same machine at 127.0.0.1 or localhost:

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

From other addresses without a token the API returns 401. With login disabled the web interface is still open to anyone who can connect to the port, so keep login enabled on a server with an open port.

Requests from other websites

A POST with an Origin header that does not match the bot's address is rejected with 403 — this is CSRF protection. curl, scripts and MCP clients do not send Origin, so this does not affect them. If the bot is behind a reverse proxy, the proxy must pass the original Host header.

Login cookie

Instead of the token you can send the hamster-bot-token cookie if Telegram login is enabled:

  1. POST /htmx/login/get-token — the bot sends a one-time code to Telegram.
  2. POST /htmx/login/verify with the form token_enter=<code> — the response contains the header Set-Cookie: hamster-bot-token=...
  3. Send the cookie with requests: curl -b "hamster-bot-token=<value>" ...

The cookie is valid for up to 10 days. Only the latest login is valid: a new login (including from a browser) invalidates the previous cookie.

Requests and responses

  • POST request bodies are UTF-8 JSON (Content-Type: application/json).
  • Names in the path are URL-encoded: strategy T4 BTC → /api/settings/strategy/T4%20BTC.
  • Settings and configs are sent and returned in the same form as in the bot's JSON files.
  • A successful action returns { "success": true, ... }, an error returns { "success": false, "error": "error text" } with a code from the response codes table.
  • A bot is identified by account and strategy name: /{accountName}/{settingsName}. If the strategy trades several pairs, the ?symbol= parameter picks the pair; without it the first one is used.

Example: create a strategy from a draft with default values.

curl -X POST http://127.0.0.1:5000/api/settings/strategy/draft \
  -H "Content-Type: application/json" \
  -d '{ "account": "main", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }'

The draft saves nothing: edit the returned object and send it to POST /api/settings/strategy — the strategy is saved and starts right away.

curl -X POST http://127.0.0.1:5000/api/bots/main/T4%20BTC/pause
{ "success": true, "name": "T4 BTC", "is_runing": false }

Endpoints

Under each endpoint description there is a collapsed request and response example.

Settings

GET/api/settings/configGlobal config (settings_program.json). The Telegram bot token is masked: the first 4 characters are visible. api_token is masked: the last 4 characters are visible
Example
{
  "name": "MyBot",
  "use_web": true,
  "port": 5000,
  "api_token": "••••••••••••b9c2",
  "telegram": {
    "bot_token": "1234************",
    "id_chat": 123456789
  }
}
POST/api/settings/configChange the config: send only the fields that change, applied immediately. The Telegram bot token and api_token are not changed here: these fields in the body are ignored
Example

Request:

{ "name": "MyBot", "chart": { "count": 500 } }

Response:

{ "success": true }
POST/api/settings/api-token/regenerateIssue a new api_token, the old one stops working immediately. The only API response where the token is shown in full. No body needed
Example
{ "success": true, "api_token": "<new token>" }
GET/api/settings/hints/{kind}Settings field descriptions: settings, config_tester, settings_program. Parameters ?lang= (en, ru, pt), ?filter=
Example

Request:

GET /api/settings/hints/config_tester?filter=parameter_mining,monte_carlo

Response — an object "dotted field path → description":

{
  "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..."
}

Strategies

GET/api/settings/strategyAll bot strategies
Example
[
  {
    "name": "T4 BTC",
    "is_runing": true,
    "exchange": { "name": "binance", "account": "main" },
    "basic": { "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }
  }
]
GET/api/settings/strategy/{name}One strategy by name (case-insensitive)
POST/api/settings/strategy/draftDraft with default values for an account, saves nothing
Example

Request:

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

Instead of symbol you can send symbols: ["BTCUSDT", "ETHUSDT"] — a multi-pair strategy. time_frame (default 1h) and account_type are optional. The response is a strategy object.

POST/api/settings/strategyCreate or change a strategy, changes apply immediately. ?old_name= — rename
Example

Request (the body is a strategy object):

POST /api/settings/strategy?old_name=T4%20BTC

Response (created: true — the strategy is new):

{ "success": true, "name": "T4 BTC v2", "created": false }
POST/api/settings/strategy/{name}/copyCopy under a new name, saved and started
Example

Request (new_symbol is optional):

{ "new_name": "T4 ETH", "new_symbol": "ETHUSDT" }

Response:

{ "success": true, "name": "T4 ETH" }
POST/api/settings/strategy/{name}/deleteDelete a strategy, orders and position are left untouched. ?full=1 — cancel orders and close the position first
Example

Request:

POST /api/settings/strategy/T4%20BTC/delete?full=1

Response:

{ "success": true }

If with full=1 the orders could not be cancelled or the position could not be closed, the strategy stays paused and is not deleted — the position is never left unmanaged.

Accounts (exchange API keys)

GET/api/settings/accountsAll accounts
Example
[
  {
    "name": "main",
    "exchange": "binance",
    "api_key": "...",
    "api_secret": "...",
    "is_encrypted": true
  }
]
GET/api/settings/accounts/{name}One account
GET/api/settings/accounts/{name}/symbolsPairs available on the exchange for the account
Example
["BTCUSDT", "ETHUSDT"]
POST/api/settings/accountsCreate or change an account, keys are sent in plain text. ?old_name= — rename
Example

Request:

{ "name": "main", "exchange": "binance", "api_key": "...", "api_secret": "...", "is_encrypted": true, "open_positions_limiter": 0 }

Response (applied — how many running bots got the new key):

{ "success": true, "name": "main", "applied": 3 }

With "is_encrypted": true the bot stores the keys encrypted. Empty api_key, api_secret, api_passphrase keep the current values when changing; when is_encrypted changes, the key and secret must be sent again.

POST/api/settings/accounts/{name}/deleteDelete an account
GET/api/current/accounts/{name}/infoAccount and key data from the exchange, updated hourly (needs a running bot on the account)
Example
{
  "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"
}
GET/api/current/accounts/{name}/balance-historyBalance history, ?max= — at most this many points (default 5000)
Example
{
  "account": "main",
  "total": 12000,
  "points": [ { "time": 1761393600, "margin": 1234.5, "wallet": 1200.0, "positions": "..." } ]
}

time — Unix time in seconds, total — how many points the history has in total.

POST/api/current/accounts/{name}/balance-history/compactCompact the balance history now using the monitoring settings
Example
{ "success": true, "message": "...", "points_before": 12000, "points_after": 3000, "bytes_before": 512000, "bytes_after": 128000 }

Bots

GET/api/current/botsSummary of all bots: status, price, position, order count, exchange sync
Example
[
  {
    "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 — the bot is paused. position: null — no position. orders — number of open orders. sync_missed_cycles — how many cycles in a row failed to get data from the exchange.

GET/api/current/balancesWallet and margin balance per key, spot and futures separately. ?account=
Example

Request:

GET /api/current/balances?account=main

Response:

[
  { "account": "main", "exchange": "bybit", "type": "futures", "wallet": 1234.56, "margin": 1180.20 },
  { "account": "main", "exchange": "bybit", "type": "spot", "wallet": 500.00, "margin": 500.00 }
]

For spot both values are the USDT balance. Balances come from running bots: an account without a running bot is not listed.

GET/api/current/bots/{accountName}/{settingsName}/barsBot candles, ?limit= — last N (default 500)
Example

Request:

GET /api/current/bots/main/T4%20BTC/bars?limit=100

The response is an array of candles with fields Timestamp, Open, High, Low, Close, Volume and others.

GET/api/current/ubots
/api/current/ubots/{accountName}/{settingsName}
Full state snapshot. The format may change between versions — for a permanent integration use bots, positions, orders
POST/api/bots/pause-all
/api/bots/play-all
Pause / start all bots
Example
{ "success": true, "count": 5 }
POST/api/bots/{accountName}/{settingsName}/pause
/api/bots/{accountName}/{settingsName}/play
Pause / start a strategy (for a multi-pair strategy — all its pairs)
Example

Request:

POST /api/bots/main/T4%20BTC/pause

Response (for play — "is_runing": true):

{ "success": true, "name": "T4 BTC", "is_runing": false }
POST/api/bots/{accountName}/{settingsName}/send-chartSend the bot chart to Telegram
POST/api/bots/{accountName}/{settingsName}/send-positionSend a summary to Telegram: balance, position, PnL, orders

Positions and orders

GET/api/current/positionsPositions of all bots
Example
[
  {
    "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/ordersOpen orders of all bots
Example
[
  {
    "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/marketMarket order on an account. The pair must be traded by one of the account's bots
Example

Request (side — Buy or Sell; size — volume in exchange units):

{ "account": "main", "symbol": "BTCUSDT", "side": "Buy", "size": 0.01 }

Response:

{ "success": true, "order_id": "order-123" }
POST/api/positions/{accountName}/{settingsName}/closeClose the bot's position
Example

Request:

POST /api/positions/main/T4%20BTC/close

Response:

{ "success": true }
POST/api/positions/{accountName}/close-allClose all positions of the account
Example
{ "success": true, "count": 3 }

count — how many positions were sent for closing.

POST/api/positions/{accountName}/reduceReduce all positions of the account by percent (1–100)
Example

Request:

{ "percent": 50 }

Response:

{ "success": true, "count": 3 }
POST/api/orders/{accountName}/{settingsName}/{orderId}/cancelCancel one order (regular or stop order)
Example

Request:

POST /api/orders/main/T4%20BTC/order-123/cancel

Response:

{ "success": true }
POST/api/orders/{accountName}/cancel-allCancel all orders of the account
Example
{ "success": true, "count": 2 }

count — for how many bots orders were cancelled.

POST/api/orders/cancel-allCancel all orders on all accounts
Example
{ "success": true, "count": 7 }

System and logs

GET/api/system/statusProgram version, server resources, bot counters
Example
{
  "program": "hamster-bot",
  "version": "2026/10/23",
  "name": "MyBot",
  "type": "bot",
  "os": "Linux 6.1",
  "architecture": "X64",
  "machine": "srv1",
  "runtime": ".NET 8.0",
  "processors": 4,
  "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/shutdownShut down the program (only with Telegram login)
POST/api/system/updateStart a program update (see auto_update_supported in the status)
GET/api/logsLatest lines of the main log (array of strings), ?tail=
GET/api/logs/errorsErrors for the last ?hours= hours (default 24, up to 48), ?warnings=1 — with warnings
Example
[
  {
    "level": "Error",
    "first_utc": "2026-10-25T08:00:00Z",
    "last_utc": "2026-10-25T12:00:00Z",
    "count": 3,
    "source": "T4 BTC",
    "message": "...",
    "exception": "..."
  }
]

Identical messages are merged, count — how many times it repeated.

GET/api/logs/filesLog files, newest first
Example
[ { "name": "log_25-10-2026.log", "size": 102400, "modified_utc": "2026-10-25T12:00:00Z" } ]
GET/api/logs/files/{filename}Log file contents as text, ?download=1 — download

Tester

GET/api/tester/statusTester state: runs, single runs, data download
Example
{
  "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
  },
  "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."
    }
  ],
  "download": { "active": false, "status": "Idle", "started_utc": null, "finished_utc": null, "message": "" },
  "settings_folder": ""
}

run — parameter mining, stress test or snapshot replay; status: Idle, Running, Completed or Failed; runs_done / runs_total — how many combinations are done. wizard_runs — single runs, finished ones stay visible for 5 more minutes. download — historical data download. settings_folder — current tester settings folder.

GET POST/api/tester/configTester config (config_tester.json): period, fees, mining parameters. POST — the whole config
GET/api/tester/exchanges
/api/tester/exchanges/{exchange}/symbols
Exchanges with historical data and their pairs. An empty pair list means the exchange is unavailable right now
Example
["bybit", "binance", ...]
GET/api/tester/settings
/api/tester/settings/{name}
Tester strategy settings in the current folder
Example
[ { "name": "T4 BTC", "exchange": "bybit", "symbol": "BTCUSDT", "symbols": null, "strategy": "zigzag", "time_frame": "1h" } ]
POST/api/tester/settings/draftSettings draft, saves nothing
Example

Request:

{ "exchange": "bybit", "symbol": "BTCUSDT", "strategy": "zigzag", "time_frame": "1h" }

Instead of symbol you can send symbols — several pairs. account_type is optional. The response is a settings object.

POST/api/tester/settingsSave settings, ?old_name= — rename. Existing settings with the same name are not overwritten
Example
{ "success": true, "name": "T4 BTC" }
POST/api/tester/settings/{name}/copy
/api/tester/settings/{name}/delete
Copy (also to another exchange or pair) / delete
Example

copy request (empty new_exchange and new_symbol keep the source values):

{ "new_name": "T4 BTC binance", "new_exchange": "binance", "new_symbol": "" }

Response:

{ "success": true, "name": "T4 BTC binance" }
GET POST/api/tester/settings-folderCurrent tester settings folder and switching to another one ("" — the main folder)
Example

GET — response (settings — how many settings are in the folder):

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

POST — request:

{ "path": "2026-10" }

POST — response:

{ "success": true, "path": "2026-10" }
POST/api/tester/runParameter mining (parameter_mining)
Example

Request (config is optional — without it the saved tester config is used):

{ "settings": ["T4 BTC", "T4 ETH"], "config": { ... } }

Response:

{ "success": true }
POST/api/tester/stressStress test: the same settings under worse execution conditions. Body and responses as for /api/tester/run
POST/api/tester/wizard-runSingle run. Body as for /api/tester/run
Example
{ "success": true, "run_id": "a1b2c3d4" }

Progress is in wizard_runs of the tester status by run_id, metrics are in wizard-results.

POST/api/tester/snapshot-runRepeat a run from a snapshot file (?root=&path=). The body is optional: a modified snapshot applies only to this run
Example
POST /api/tester/snapshot-run?root=report&path=T4/run_snapshot_20261025.json
POST/api/tester/download-dataDownload historical data for all tester settings
GET/api/tester/wizard-resultsSingle run results, newest first: metrics and report paths
Example
[
  {
    "runId": "a82c93c5",
    "timestamp": "2026-10-25T05:26:50Z",
    "strategies": ["T4 BTC"],
    "stats": {
      "InitialBalance": 10000.0, "FinalBalance": 9581.25, "TotalPnL": -418.75, "TotalPnLPercent": -4.19,
      "TotalTrades": 23, "WinRate": 13.04, "MaxDrawdown": 527.89, "MaxDrawdownPercent": 5.26, "TotalFees": 22.2
    },
    "chartUrl": "/tester-report/T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
    "report_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html",
    "report_json_path": "T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.json",
    "period": "2025-09-01 .. 2025-09-20",
    "elapsed": "00:00:07"
  }
]

chartUrl — link to the HTML report for the browser. report_path — the same report as a path inside root=report. report_json_path — its JSON version, if written.

GET/api/tester/filesTester folders: ?root=report|data|runs&path=
Example
{
  "root": "report",
  "path": "T4",
  "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 — the file can be run via snapshot-run. editable: true — the file can be changed via files/save.

GET POST/api/tester/files/download
/api/tester/files/delete
/api/tester/files/content
/api/tester/files/save
Download, delete, read a snapshot, save JSON in runs (?root=&path=)
GET/api/tester/reports/summaryReport summaries for comparison: metrics and equity curve, ?r= can be repeated
Example

Request:

GET /api/tester/reports/summary?r=T4/report.html&r=T4_STRESS/report.html

Response:

[
  {
    "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 and equity_v — time (Unix, seconds) and balance of the equity curve points. summary: null — the report has no summary.

GET/api/tester/reports/jsonDetailed run results in compact JSON: ?path=, ?sections=, ?trades_offset=, ?trades_limit=
Example

Request:

GET /api/tester/reports/json?path=T4/T4_run_001_of_001_BTCUSDT_1h_ee8c3c2e.html&sections=by_symbol,trades&trades_limit=2

Response:

{
  "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
  }
}

In trades: count — total number of trades, net_pnl — trade result after fees, mae and mfe — worst and best intermediate trade result (USDT), times in UTC. The fields v, created_utc and html_report are always returned.

GET/api/tester/publish/filesFiles of a report folder that can be published on the website, ?path=
Example
[ { "name": "reports_history.csv", "size": 10240, "kind": "history" } ]

kind — history (run history), snapshot (run snapshot) or summary (summary report).

POST/api/tester/publishSend the selected files to the website, the publication appears after moderation
Example

Request (agree: true — consent to the publication terms, required):

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

Response:

{ "success": true, "sent": ["reports_history.csv"] }

Tester via API

  • All runs work in the background: the response comes immediately, progress and result are in GET /api/tester/status.
  • Parameter mining, stress test and snapshot replay run one at a time. Single runs can run in parallel. While historical data is downloading the tester does not start, and vice versa — the response is 409.
  • A running mining job cannot be stopped, so check the number of combinations in advance (or set monte_carlo — a random sample).
  • Mining results go to report/<name_comment>: reports_history.csv with the metrics of each combination, HTML and JSON reports, the optimizer summary report. Give each experiment its own name_comment.
  • The JSON report (report.enable_json_report) has the same numbers as the HTML report but is dozens of times smaller: sections run, metrics, by_symbol, monthly, trades, curves, settings.

MCP for AI assistants

The bot works as an MCP server (Model Context Protocol): an AI assistant — Claude and other MCP clients — can check the bot's state, run the tester and manage strategies on its own. MCP tools mirror the API and follow the same access rules.

Enabling

MCP is off by default. Enable it in settings_program.json:

{ "use_mcp": true }

The change takes effect immediately, no restart needed. It can also be done via the API: POST /api/settings/config with the body { "use_mcp": true }. While MCP is off, /mcp returns 404.

Address: http://127.0.0.1:<port>/mcp, Streamable HTTP transport.

Connecting to Claude Code

claude mcp add --transport http hamster-bot http://127.0.0.1:5000/mcp --header "Authorization: Bearer <api_token>"

Or in the project's .mcp.json file:

{
  "mcpServers": {
    "hamster-bot": {
      "type": "http",
      "url": "http://127.0.0.1:5000/mcp",
      "headers": { "Authorization": "Bearer <api_token>" }
    }
  }
}

Other clients connect to the same address if they support Streamable HTTP and custom request headers.

Access and safety

  • Access is the same as for the API (see Access): the Authorization: Bearer <api_token> header from any address; without it — the hamster-bot-token cookie with login enabled, or only from the same machine with login disabled. Otherwise /mcp returns 401.
  • To connect from another machine, use the server address instead of 127.0.0.1. The token is then sent in plain text, so over the internet connect through an HTTPS proxy or an SSH tunnel.
  • Tools that trade on the exchange, start trading or irreversibly change data are marked as destructive (destructiveHint) — the client asks for confirmation before calling them: market orders, closing positions, cancelling orders, starting bots, saving and deleting strategies and keys, changing the config, shutting down and updating the program.
  • Reading state is marked as safe (readOnlyHint).

Tools

Settingsget_config, update_config, get_field_hints
Strategieslist_strategies, get_strategy, draft_strategy, save_strategy, copy_strategy, delete_strategy
Accountslist_accounts, get_account, get_account_symbols, save_account, delete_account, get_account_info, get_balance_history, compact_balance_history
Botslist_bots, get_balances, get_bot_bars, get_bot_state, pause_all_bots, play_all_bots, pause_bot, play_bot, send_chart_to_telegram, send_position_to_telegram
Positions and orderslist_positions, list_orders, market_order, close_position, close_all_positions, reduce_positions, cancel_order, cancel_account_orders, cancel_all_orders
System and logsget_system_status, shutdown_program, update_program, get_log, get_errors, list_log_files, read_log_file
Testertester_status, get_tester_config, save_tester_config, tester_exchanges, tester_exchange_symbols, list_tester_settings, get_tester_settings, draft_tester_settings, save_tester_settings, copy_tester_settings, delete_tester_settings, get_tester_settings_folder, set_tester_settings_folder, tester_run_mining, tester_run_stress, tester_run_single, tester_run_snapshot, tester_download_data, tester_wizard_results, list_tester_files, read_tester_file, save_tester_file, delete_tester_file, tester_report_summaries, read_tester_report, tester_publish_files, tester_publish

An API error is returned to the assistant as a tool error with code and text, for example HTTP 404: {"success":false,"error":"Strategy not found"}. Very long responses are truncated to 200,000 characters. For long CSV files read_tester_file has the tail_lines and contains parameters. To compare runs use tester_report_summaries, for details of a single run — read_tester_report.

Research in the tester

The assistant can research a strategy on its own. The tester works on historical data and does not trade on the exchange. A typical flow:

  1. get_field_hints — learn what the strategy settings and tester config fields mean, including the parameter_mining syntax.
  2. draft_tester_settings, save_tester_settings — create settings for the exchange, pair and timeframe.
  3. save_tester_config — set the period, fees, parameter_mining and a new name_comment; enable report.enable_json_report.
  4. tester_download_data — download candles and wait for completion in tester_status.
  5. tester_run_single or tester_run_mining — test one combination or all of them: results in tester_wizard_results or <name_comment>/reports_history.csv.
  6. read_tester_report — analyze a run: per-pair totals, months, trades.
  7. tester_report_summaries, tester_run_stress — compare the best variants and check their robustness (also walk_forward in the config).

Example prompt for the assistant: "Find the zigzag length for BTCUSDT 1h on Bybit over the last three months. Compare the best variants by drawdown and check them with a stress test".

Response codes

200Success
400Bad request: empty body, invalid JSON, required fields missing
401No access: invalid api_token; cookie missing, expired or replaced by a new login; request without a token not from the same machine
403Request from another website's page (Origin does not match the bot's address)
404Not found
409Conflict: tester or data download already running, name taken, required bot not running
500Internal error or exchange error
502External service rejected the request
503The program is still starting