Install
openclaw skills install tbot-controllerOperate TradingBoat/TBOT (TBOT runtime stack) via a controlled automation interface (DB-first queries; lifecycle control on explicit request).
openclaw skills install tbot-controllerThe agent MUST stop and ask for user action if any of the following is true:
--run-it / RUN_IT=1.This skill controls a separate TBOT runtime stack. The reference/runtime implementation is:
This tbot-controller skill does not download or install the runtime for you. If the runtime is missing, the skill will run read-only DB helpers where possible, but status/logs/control actions will fail until the runtime exists.
git clone https://github.com/PlusGenie/openclaw-on-tradingboat.git
cd openclaw-on-tradingboat
docker compose up -d
TBOT_COMPOSE_DIR to the folder that contains docker-compose.yml or compose.yaml.Examples:
export TBOT_COMPOSE_DIR="$HOME/develop/github/openclaw-on-tradingboat"
Or add it to ~/.openclaw/.env / your skill env block in openclaw.json.
.env file for broker credentials and webhook keys.This skill is invoked via a bash entrypoint script. Ensure it is executable:
chmod +x scripts/tbot.sh
This skill uses uv to run Python scripts in an isolated environment and auto-install dependencies from:
{baseDir}/scripts/requirements.txtInstall uv (macOS):
brew install uv
ClawHub packaging note: if you publish this skill, ensure scripts/ (including requirements.txt) is included at the root of the repo.
DB queries do NOT require discovery. Discovery is required only before status/logs/control actions.
OpenClaw must NOT hardcode old paths like ~/ib-gateway-docker.
Always prefer discovery output (usually pointing to openclaw-on-tradingboat).
OpenClaw MUST invoke this skill via:
bash scripts/tbot.sh <mode> <args...>
Valid modes:
ctl — operations control (docker/systemd)json — JSON signal generation (schema-validated) and send to TBOT webhook (non-interactive)status — read-only inspection (probe & discovery)OpenClaw must never call python tbot*.py directly.
When the user says “open TBOT”, “start TBOT”, “TBOT status”, etc., OpenClaw should:
bash scripts/tbot.sh status discover
This step is mandatory because the compose folder may change over time
(for example migrating from ib-gateway-docker to openclaw-on-tradingboat).
ctl commands by injecting env vars:MODE=docker COMPOSE_DIR="<compose_dir>" bash scripts/tbot.sh ctl status
Example expected compose folder:
~/develop/github/openclaw-on-tradingboat>
MODE=systemd SERVICE_NAME="<service_name>" SYSTEMD_USER="<0|1>" bash scripts/tbot.sh ctl status
Notes:
If OpenClaw skips discovery, it may incorrectly report TBOT as DOWN because it is checking an obsolete compose folder.
bash scripts/tbot.sh ctl status
bash scripts/tbot.sh ctl logs --tail 200
Note: With tbot-runtime (example), docker compose typically brings up three containers: ib-gateway-on-tradingboat (gnzsnz/ib-gateway), redis-on-tradingboat, and tbot-on-tradingboat.
Internally:
docker compose ps, docker compose logs --tail=200systemctl --user status <service>, journalctl --user -u <service> -n 200bash scripts/tbot.sh ctl start --run-it
bash scripts/tbot.sh ctl stop --run-it
bash scripts/tbot.sh ctl restart --run-it
Tip: Use MODE=docker + COMPOSE_DIR pointed at tbot-runtime (example) to control the stack via docker compose.
Internally:
docker compose up -d, docker compose downsystemctl --user start <service>, systemctl --user stop <service>json mode is non-interactive by design.
OpenClaw MUST NOT ask the user for webhook details or trading intent if they can be inferred.
Inference rules:
http://127.0.0.1:5001/webhook (override with TBOT_WEBHOOK_URL).env by default (override with WEBHOOK_KEY)orderRef is auto-generated when omittedclose 50 NFLX implies strategy.close, contract=stock, qty=50json mode generates a schema-valid TradingView-style payload and sends it to TBOT via webhook.
Defaults / inference rules (do not ask the user):
http://127.0.0.1:5001/webhook (override with TBOT_WEBHOOK_URL)..env (override with WEBHOOK_KEY).Close_<TICKER>_<QTY>_<epoch_ms>.# Example (user: “close 50 NFLX now”)
TBOT_WEBHOOK_URL="http://127.0.0.1:5001/webhook" \
WEBHOOK_KEY="WebhookReceived:123456" \
bash scripts/tbot.sh json \
--ticker NFLX \
--direction strategy.close \
--contract stock \
--metric qty=50
Guarantees:
alert_webhook_schema.jsonWhen asked to “generate a TradingView webhook JSON”, OpenClaw should output JSON exactly like this shape:
{
"timestamp": 1710000000000,
"ticker": "ES1!",
"currency": "USD",
"timeframe": "5",
"clientId": 1,
"key": "WebhookReceived:123456",
"contract": "future",
"orderRef": "Long#1",
"direction": "strategy.entrylong",
"exchange": "CME",
"lastTradeDateOrContractMonth": "202603",
"multiplier": "50",
"metrics": [
{"name": "entry.limit", "value": 0},
{"name": "entry.stop", "value": 0},
{"name": "exit.limit", "value": 0},
{"name": "exit.stop", "value": 0},
{"name": "qty", "value": 1},
{"name": "price", "value": 5032.25}
]
}
Tip (local-first / zero-config examples): it’s OK to use a placeholder key value in docs.
For real TradingView → TBOT delivery, set it to your actual shared secret (TVWB key).
bash scripts/tbot.sh status db --table orders --format summary --limit 100bash scripts/tbot.sh status db --table alerts --format summary --limit 100bash scripts/tbot.sh status db --table errors --format summary --limit 100bash scripts/tbot.sh status db --table tbot --format summary --limit 100--format json to return raw JSON.TBOTORDERS (same as /orders/data in UI).bash scripts/tbot.sh status portfolio --format summarybash scripts/tbot.sh status errors --format summary --limit 200bash scripts/tbot.sh status errors --group --limit 200bash scripts/tbot.sh status health --base-url http://127.0.0.1:5001Example output (--format summary, orders):
Totals:
- Market value: 284,103.16
- Unrealized PnL: 134,585.15
- Realized PnL: 0.00
TBOT_TIME | ORD_TIME | TICKER | TV_Close | ACTION | TYPE | QTY | LIMIT | STOP | ORDERID | ORDERREF | STATUS | POS | MRKVAL | AVGF | UnrealPnL | RealPnL
----------------+-------------------------+--------+----------+--------+------+-----+-------+------+---------+-----------+-----------+-----+------------+----------+------------+--------
2026-02-05 20:06 | 2026-02-05 20:06:12.345 | TSLA | 399.4796 | BUY | LMT | 455 | 0 | 0 | 12345 | Ptf_TSLA | Portfolio | 455 | 181,763.22 | 187.9038 | 96,266.98 | 0
--db-path /path/to/tbot_sqlite3TBOT_DB_PATH=/path/to/tbot_sqlite3TBOT_DB_OFFICE=/path/to/tbot_sqlite3/home/tbot/tbot_sqlite3 if no volume is set../runtime/database to /home/tbot/database and set TBOT_DB_OFFICE=/home/tbot/database/tbot_sqlite3.tbot-runtime (example)/runtime/database/tbot_sqlite3tbot-runtime (example)/docker-compose.yml, restart TBOT:
MODE=docker COMPOSE_DIR="/path/to/your/tbot-runtime" bash scripts/tbot.sh ctl restart --run-ittbot container may not include sqlite3 CLI; read the DB on the host (preferred) via bind-mount.sqlite3 <path> "SELECT ..."errors --tail (limit), health (HTTP checks for /orders/data + /tbot/data).This skill generates JSON with fields used by TBOT/TradingBoat style alerts:
timestamp (ms since epoch)ticker (e.g., AAPL, ES1!)currency (e.g., USD)timeframe (e.g., 1, 5, 1D)clientId (integer; IBKR client ID)key (TVWB shared key)contract (e.g., stock, forex, crypto, future)orderRef (string identifier)direction (e.g., strategy.entrylong, strategy.entryshort, strategy.exitlong, strategy.exitshort, strategy.close, strategy.close_all)exchange, lastTradeDateOrContractMonth, multiplier (mostly for futures)metrics (array of {name, value})(Uses a placeholder key value for copy-paste. Replace with your real TVWB shared key in production.)
{
"timestamp": 1710000000000,
"ticker": "ES1!",
"currency": "USD",
"timeframe": "5",
"clientId": 1,
"key": "WebhookReceived:123456",
"contract": "future",
"orderRef": "Long#1",
"direction": "strategy.entrylong",
"exchange": "CME",
"lastTradeDateOrContractMonth": "202603",
"multiplier": "50",
"metrics": [
{"name": "entry.limit", "value": 0},
{"name": "entry.stop", "value": 0},
{"name": "exit.limit", "value": 0},
{"name": "exit.stop", "value": 0},
{"name": "qty", "value": 1},
{"name": "price", "value": 5032.25}
]
}
brew install uv