TBOT 控制器:通过 Openclaw Skills 管理 TradingBoat 运行时

作者:互联网

2026-03-30

AI教程

什么是 TBOT 控制器?

TBOT 控制器是一个旨在桥接 AI 代理与 TradingBoat (TBOT) 运行时栈的技术接口。作为 Openclaw Skills 生态系统的一部分,它提供了一种安全优先的方法来管理盈透证券 (IBKR) 自动交易设置。它强调数据库优先策略,这意味着在尝试更具侵入性的发现操作之前,它会先查询本地 SQLite 数据库以获取投资组合和订单数据。

该技能在构建时充分考虑了可靠性,处理从监控容器健康状况到生成经过模式验证的 TradingView 风格 JSON 负载的所有事务。对于使用 Openclaw Skills 的开发人员来说,它是通过专业的基于 CLI 的工作流程维护高频或算法交易环境而无需手动干预的重要工具。

下载入口:https://github.com/openclaw/skills/tree/main/skills/plusgenie/tbot-controller

安装与下载

1. ClawHub CLI

从源直接安装技能的最快方式。

npx clawhub@latest install tbot-controller

2. 手动安装

将技能文件夹复制到以下位置之一

全局模式 ~/.openclaw/skills/ 工作区 /skills/

优先级:工作区 > 本地 > 内置

3. 提示词安装

将此提示词复制到 OpenClaw 即可自动安装。

请帮我使用 Clawhub 安装 tbot-controller。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。

TBOT 控制器 应用场景

  • 从 TBOT 数据库监控实时投资组合快照和未实现盈亏。
  • 在明确确认的情况下,通过 Docker Compose 或 systemd 控制 TBOT 服务生命周期。
  • 通过跟踪和分组活动容器的日志来排查交易错误。
  • 生成并发送用于自动执行交易的 TradingView 风格 Webhook JSON 信号。
TBOT 控制器 工作原理
  1. 发现:该技能通过检查 TBOT_COMPOSE_DIR 等环境变量或搜索 docker-compose 文件来识别 TBOT 运行时位置。
  2. 检查:它查询本地 SQLite 数据库以检索最新的警报、订单和系统状态,而不会中断运行时。
  3. 验证:对于交易信号,它会生成 JSON 负载并根据 alert_webhook_schema.json 进行验证,以确保经纪商兼容性。
  4. 执行:仅在提供明确的 --run-it 标志时执行启动、停止或重启等生命周期操作,确保人工干预的安全性。

TBOT 控制器 配置指南

要将其集成到您的 Openclaw Skills 工作流程中,请确保您已安装 tbot-runtime 并准备好 uv 包管理器。

# 安装所需的 uv 包管理器
brew install uv

# 克隆推荐的运行时栈
git clone https://github.com/PlusGenie/openclaw-on-tradingboat.git

# 配置技能位置
export TBOT_COMPOSE_DIR="$HOME/path/to/openclaw-on-tradingboat"

# 为入口点脚本设置权限
chmod +x scripts/tbot.sh

TBOT 控制器 数据架构与分类体系

该技能与核心 SQLite 表交互,并基于特定分类生成结构化 JSON 信号。

表/实体 描述
orders 跟踪历史和活跃的 IBKR 订单及成交状态
alerts 记录通过 Webhook 接口接收的 TradingView 信号
errors 对系统和经纪商级别的错误日志进行分类和存储
tbot 管理核心运行时状态和心跳元数据

信号负载遵循 TradingView Webhook 标准,包括 ticker、方向(例如 strategy.entrylong)、合约类型等必填字段,以及用于价格和数量的 metrics 数组。

name: tbot-controller
version: 1.0.0
author: PlusGenie
tags: [openclaw, tbot, tradingboat, trading, docker, ibkr]
description: Operate TradingBoat/TBOT (TBOT runtime stack) via a controlled automation interface (DB-first queries; lifecycle control on explicit request).
metadata: {"openclaw":{"emoji":"???","requires":{"bins":["uv"]},"install":[{"id":"uv-brew","kind":"brew","formula":"uv","bins":["uv"],"label":"Install uv (brew)"}]}}

What this skill does

  • Query TBOT sqlite DB for alerts/orders/errors/portfolio (DB-first)
  • Start/stop TradingBoat/TBOT (docker compose or systemd)
  • Fetch health/status (containers, ports, basic checks) only when explicitly requested
  • Read recent logs only when explicitly requested

Safety rules

  • Default to read-only operations (status/logs) unless user explicitly requests a control action.
  • For any state-changing action (start/stop/restart/send), require explicit confirmation via the flag --run-it or environment variable RUN_IT=1. The controller will refuse execution otherwise.
  • Never print secrets (webhook keys, tokens). Redact them.

Refusal criteria (must-stop conditions)

The agent MUST stop and ask for user action if any of the following is true:

  • Runtime location is unknown and discovery cannot uniquely resolve it.
  • The TBOT database path cannot be found or opened read-only.
  • A request would start/stop/restart services or send signals without --run-it / RUN_IT=1.
  • A request implies destructive DB changes (DROP/TRUNCATE/ALTER) or “run arbitrary SQL”.

Prerequisites (first-time users)

This skill controls a separate TBOT runtime stack. The reference/runtime implementation is:

  • openclaw-on-tradingboat (TBOT runtime stack): https://github.com/PlusGenie/openclaw-on-tradingboat

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.

  1. Clone the runtime repo:
git clone https://github.com/PlusGenie/openclaw-on-tradingboat.git
cd openclaw-on-tradingboat
  1. Ensure you can start it manually (outside this skill). For Docker Compose based installs, this typically means:
docker compose up -d
  1. Tell this skill where the runtime lives (recommended):
  • Set 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.

Configure runtime secrets (outside this skill)

  • TBOT typically uses a .env file for broker credentials and webhook keys.
  • Do not commit secrets to git.
  • If you are unsure whether the runtime is set to paper or live, this skill must refuse to execute any trade/action until you confirm which it is.

Install / script permissions

This skill is invoked via a bash entrypoint script. Ensure it is executable:

chmod +x scripts/tbot.sh

Python deps (OpenClaw-native)

This skill uses uv to run Python scripts in an isolated environment and auto-install dependencies from:

  • {baseDir}/scripts/requirements.txt

Install 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.

IMPORTANT: DB-first, discovery only for status/control

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).

Commands

Entry point (required)

OpenClaw MUST invoke this skill via:

bash scripts/tbot.sh  

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.

Probe & Discovery (read-only, only for status/control)

When the user says “open TBOT”, “start TBOT”, “TBOT status”, etc., OpenClaw should:

  1. Try discovery first (read-only):
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).

  1. If discovery returns a resolved runtime, run ctl commands by injecting env vars:
  • Docker example:
MODE=docker COMPOSE_DIR="" bash scripts/tbot.sh ctl status

Example expected compose folder:

~/develop/github/openclaw-on-tradingboat> 
  • systemd example:
MODE=systemd SERVICE_NAME="" SYSTEMD_USER="<0|1>" bash scripts/tbot.sh ctl status
  1. Only if discovery cannot resolve a single runtime, ask one precise question:
  • Docker Compose: “What is the folder containing docker-compose.yml/compose.yaml? (Usually this is the tbot-runtime (example) folder.)”
  • systemd: “What is the service name (and is it --user)?”

Notes:

  • Discovery must remain read-only (no starting/stopping).
  • Use discovery output as the authoritative suggestion for MODE/COMPOSE_DIR/SERVICE_NAME.

Why this matters

If OpenClaw skips discovery, it may incorrectly report TBOT as DOWN because it is checking an obsolete compose folder.

Status (read-only, only if requested)

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: docker compose ps, docker compose logs --tail=200
  • systemd: systemctl --user status , journalctl --user -u -n 200

Control (explicit confirmation required)

bash 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: docker compose up -d, docker compose down
  • systemd: systemctl --user start , systemctl --user stop

JSON signal generation (generate + send)

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:

  • Webhook URL default: http://127.0.0.1:5001/webhook (override with TBOT_WEBHOOK_URL)
  • Webhook key is read from the TBOT runtime .env by default (override with WEBHOOK_KEY)
  • orderRef is auto-generated when omitted
  • Natural language like close 50 NFLX implies strategy.close, contract=stock, qty=50

json mode generates a schema-valid TradingView-style payload and sends it to TBOT via webhook.

Defaults / inference rules (do not ask the user):

  • Webhook URL: default http://127.0.0.1:5001/webhook (override with TBOT_WEBHOOK_URL).
  • Webhook key: read from runtime .env (override with WEBHOOK_KEY).
  • orderRef: if not provided, auto-generate Close___.
  • Close intent: inferred automatically; do not prompt the user.
# Example (user: “close 50 NFLX now”)
TBOT_WEBHOOK_URL="http://127.0.0.1:5001/webhook" r
WEBHOOK_KEY="WebhookReceived:123456" r
bash scripts/tbot.sh json r
  --ticker NFLX r
  --direction strategy.close r
  --contract stock r
  --metric qty=50

Guarantees:

  • Output is validated against alert_webhook_schema.json
  • Unsupported directions or metrics fail fast
  • No network calls or broker actions are performed
  • This generator is independent of the gateway container image (e.g., gnzsnz/ib-gateway).

Copy-paste JSON output (expected schema shape)

When 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).

DB inspection (read-only, primary)

  • Preferred (via this skill, DB-first):
    • bash scripts/tbot.sh status db --table orders --format summary --limit 100
    • bash scripts/tbot.sh status db --table alerts --format summary --limit 100
    • bash scripts/tbot.sh status db --table errors --format summary --limit 100
    • bash scripts/tbot.sh status db --table tbot --format summary --limit 100
    • Use --format json to return raw JSON.
  • Portfolio/positions are derived from TBOTORDERS (same as /orders/data in UI).

Read-only helpers (DB-first)

  • Portfolio snapshot:
    • bash scripts/tbot.sh status portfolio --format summary
  • Errors tail (with grouping):
    • bash scripts/tbot.sh status errors --format summary --limit 200
    • bash scripts/tbot.sh status errors --group --limit 200
  • Health checks (HTTP):
    • bash scripts/tbot.sh status health --base-url http://127.0.0.1:5001

Example 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 resolution (first match wins):
    • --db-path /path/to/tbot_sqlite3
    • TBOT_DB_PATH=/path/to/tbot_sqlite3
    • TBOT_DB_OFFICE=/path/to/tbot_sqlite3
  • DB location notes:
    • Inside the container, TBOT may create the DB at /home/tbot/tbot_sqlite3 if no volume is set.
    • Recommended: bind-mount ./runtime/database to /home/tbot/database and set TBOT_DB_OFFICE=/home/tbot/database/tbot_sqlite3.
    • With the bind-mount, the host path is:
      • tbot-runtime (example)/runtime/database/tbot_sqlite3
  • After updating tbot-runtime (example)/docker-compose.yml, restart TBOT:
    • MODE=docker COMPOSE_DIR="/path/to/your/tbot-runtime" bash scripts/tbot.sh ctl restart --run-it
  • Container note:
    • The tbot container may not include sqlite3 CLI; read the DB on the host (preferred) via bind-mount.
  • Fallback (manual):
    • sqlite3 "SELECT ..."

Known gaps & intended fixes (tracked)

  • Discovery can miss running docker compose stacks; use DB-first commands for portfolio instead of discovery.
  • Add explicit subcommands (planned): errors --tail (limit), health (HTTP checks for /orders/data + /tbot/data).
  • Add a single-line summary mode (planned): totals + top 3 positions + biggest losing position.

Data signal: TradingView-style webhook JSON generator

Required fields

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})

Example payload

(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}
  ]
}