Skip to content

keys.json fields

{
  "version": 1,        // fixed at 1 for now; future schema changes bump this
  "keys": [
    { /* KeyRecord */ }
  ]
}

KeyRecord fields

Field Type Required Description
id string Human-readable name, unique within keys.json; shown as key_id in audit
hash string SHA-256 hex of the plaintext key
scopes ["qot:read", "acc:read", ...] What this key can do
limits object — (empty = unlimited) Limits, see table below
allowed_machines [fp, ...] / null null = no binding; [] = frozen; [fp1,fp2] = whitelist
created_at RFC3339 timestamp Creation time
expires_at RFC3339 / null null = never expires
note string Free-form note

limits fields

Field Type Description
allowed_markets ["HK","US","CN","HKCC",...] / null Market whitelist
allowed_symbols ["HK.00700","US.AAPL"] / null Symbol whitelist
allowed_trd_sides ["BUY","SELL","SELL_SHORT","BUY_BACK"] / null Direction whitelist
max_order_value float / null Per-order cap (qty × price, in local currency)
max_daily_value float / null Daily rolling cap (resets at UTC midnight)
max_orders_per_minute u32 / null Rate limit (60-second sliding window)
hours_window "HH:MM-HH:MM" / null Time window (local timezone; cross-midnight written as 22:00-04:00)

null / omitted = unlimited.

Scope strings

Scope What it unlocks
qot:read Quote read + subscribe
acc:read Account read-only
trade:simulate Simulated trading writes
trade:real Real trading writes
trade:unlock Used by the MCP futu_unlock_trade tool (v1.4+)

Examples

Minimal read-only

{
  "id": "research",
  "hash": "a1b2...",
  "scopes": ["qot:read"],
  "created_at": "2026-04-15T10:00:00Z"
}

Tightly-limited simulation bot

{
  "id": "sim-bot",
  "hash": "c4d5...",
  "scopes": ["qot:read", "acc:read", "trade:simulate"],
  "limits": {
    "allowed_markets": ["HK"],
    "allowed_symbols": ["HK.00700", "HK.09988"],
    "max_order_value": 100000,
    "max_daily_value": 500000,
    "max_orders_per_minute": 3,
    "hours_window": "09:30-16:00",
    "allowed_trd_sides": ["SELL"]
  },
  "allowed_machines": ["fp_bot_host_abc123"],
  "created_at": "2026-04-15T10:00:00Z",
  "expires_at": "2026-05-15T10:00:00Z",
  "note": "simulated take-profit sell bot"
}

Operations

All mutations go through futucli — do not edit the file by hand (atomic writes avoid concurrent corruption; hand-writing SHA-256 hashes is error-prone):

futucli gen-key ...               # add
futucli list-keys                 # list
futucli revoke-key <id>           # remove
futucli bind-key <id> ...         # edit allowed_machines

After editing, kill -HUP the gateway / MCP to hot-reload.