Environment variables reference¶
This page lists all FUTU_* environment variables supported by the daemon
(futu-opend), CLI (futucli), and MCP (futu-mcp), with purpose, default
values, and matching CLI flags.
Credentials¶
| Env var | Purpose | Default | Matching CLI flag |
|---|---|---|---|
FUTU_ACCOUNT |
Login-account hint. futucli unlock-trade / futu-mcp can use it to select account-scoped trade-password keychain entries when --trade-pwd-account is not set; helper scripts also use it to start the daemon |
(as needed) | Prefer daemon --login-account <ACCOUNT> |
FUTU_PWD |
Login password (plaintext or 32-hex MD5, auto-detected) | (required or use CLI flag) | --login-pwd <PWD> |
FUTU_TRADE_PWD |
Trade unlock password (futucli unlock / MCP unlock) | (as needed) | --trade-pwd <PWD> |
FUTU_TRADE_PWD_ACCOUNT |
Account hint for account-scoped trade-password keychain lookup | (as needed) | --trade-pwd-account <ACCOUNT> |
FUTU_API_KEY |
Bearer token used by futucli stock-note-labels, stock-notes, and set-stock-note with OpenD REST, and by tape-reading CLI commands with native binary WebSocket |
(as needed in secure KeyStore mode) | futucli ... --api-key <KEY> |
FUTU_MCP_API_KEY |
Process-wide default API key for futu-mcp --keys-file stdio scope mode; HTTP scope mode never uses it as a fallback and requires a valid Authorization: Bearer on every /mcp request |
(required for stdio scope mode; not used by HTTP) | futu-mcp --api-key <KEY> |
FUTU_MCP_OPEND_REST_URL |
OpenD REST base URL that futu-mcp guarded real-money write tools (group orders / algorithm orders / position actions) forward to when the daemon disables raw TCP in secure KeyStore mode; unset means those write tools refuse |
(as needed; secure deployments only) | futu-mcp --opend-rest-url <URL> |
Security tip: Prefer systemd EnvironmentFile=/etc/futu-opend.env
(mode 0600) to avoid leaking plaintext to shell history / ps aux.
MCP protocol diagnostics¶
| Env var | Purpose | Default | Matching CLI flag |
|---|---|---|---|
FUTU_MCP_PROTOCOL_DIAGNOSTICS |
Enable MCP protocol conformance diagnostic tools while retaining authentication; --keys-file mode requires qot:read. Precedence is CLI, environment, TOML protocol_diagnostics, then default; explicit false disables it |
false |
futu-mcp --protocol-diagnostics[=true\|false] |
Connection addresses¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_GATEWAY |
MCP / futucli daemon gRPC address | 127.0.0.1:11111 |
FUTU_REST_URL |
futucli daemon REST URL | http://127.0.0.1:11112 |
FUTU_WS_URL |
Native binary WebSocket URL (ws:// / wss://) for tape-reading CLI queries and subscriptions, equivalent to --ws-url; supply the caller key through --api-key / FUTU_API_KEY |
No default; must be supplied explicitly |
FUTU_MCP_TAPE_WS_URL |
Native binary WebSocket URL for futu-mcp tape reads and stream subscriptions, equivalent to --tape-ws-url; preserves caller permissions and market restrictions and still requires a valid Bearer key |
No default; unset rejects corresponding reads or new streams |
FUTU_ADDR |
Used by examples/live_test for daemon address | 127.0.0.1:11111 |
Upstream CA and proxy¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_UPSTREAM_CA_FILE |
Explicit trusted PEM certificates appended to Mozilla roots for ordinary upstream HTTP and WebTCP | Unset; environment and system CA stores are not loaded |
FUTU_UPSTREAM_PROXY |
HTTP proxy URL for ordinary upstream HTTPS, WebTCP and backend TCP; accepts http:// only and percent-encoded URI userinfo for authentication |
Unset; existing HTTP environment-proxy and direct TCP behavior remain |
Settings freeze on first use; restart the daemon after changing them. Missing, empty or invalid certificate files and unsupported proxy settings fail closed. Certificate chains, validity periods and names remain verified.
An explicit proxy overrides inherited HTTP_PROXY, HTTPS_PROXY and NO_PROXY. HTTPS, WebTCP and backend TCP use CONNECT; denial or timeout never falls back to a direct connection. A custom http:// authentication origin retains HTTP forwarding. HTTPS CONNECT uses the domain, so a retry-IP override does not guarantee the proxy connects to that IP. A proxy that allows only port 443 may reject backend TCP ports.
Through an explicit proxy, WebTCP sends SNI matching its certificate verification name so an intercepting proxy can select the correct certificate. The CONNECT target still comes from the existing connection configuration. Direct WebTCP connections do not send SNI; both paths strictly verify certificates.
For platform login, write_completed (INFO) confirms only that the complete local frame was written and flushed; write_failed (WARN) reports failure of that operation. Correlate requests using serial_no, connection_generation and endpoint_fingerprint. frame_bytes is the frame length, never a partial byte count on failure. These logs omit bodies, accounts, raw endpoints and opaque error text. A subsequent timeout with received_bytes=0 requires proxy or backend records to establish forwarding and response progress; local completion does not prove backend receipt.
When a VM already provides a trusted CA file and HTTP proxy, select them explicitly:
export FUTU_UPSTREAM_CA_FILE="$SSL_CERT_FILE"
export FUTU_UPSTREAM_PROXY="$HTTPS_PROXY"
futu-opend --setup-only
Confirm these variables are nonempty, the trusted PEM is readable and the proxy URL uses http://. Supply credential-bearing settings through a protected environment file. Either setting can be used independently. Local REST/MCP TLS, update checks and native Bank transports use their existing configuration.
Browser entrypoints / Metrics security¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_REST_ALLOWED_ORIGINS |
REST CORS Origin allowlist, comma-separated; * / any / all means development wildcard |
With REST keys configured: loopback only. Legacy unauth mode keeps wildcard compatibility |
FUTU_WS_ALLOWED_ORIGINS |
WebSocket handshake Origin allowlist, comma-separated | Loopback Origin only when unset; non-browser clients without Origin skip this check |
FUTU_METRICS_PUBLIC=1 |
Revert /metrics to public access and plaintext key_id labels |
By default /metrics follows auth posture and redacts key_id labels |
Production guidance:
- Browser UI deployments should set exact origins such as
https://app.example.com. - Use
FUTU_METRICS_PUBLIC=1only when the metrics port is protected by firewall / sidecar controls.
Long-running daemon hardening (v1.4.103+)¶
Compatibility env opt-in, default OFF. You can also enable the same behavior
with futu-opend --client-sig-proactive-refresh /
--client-sig-reactive-refresh, or TOML
client_sig_proactive_refresh = true /
client_sig_reactive_refresh = true. See
long-running daemon deployment guide
for details.
| Env var | Purpose | Default | Risk |
|---|---|---|---|
FUTU_CLIENT_SIG_PROACTIVE_REFRESH=1 |
Proactively refresh client_sig 1h before expiry |
OFF | Low — single refresh action; validate server acceptance on a non-critical account first |
FUTU_CLIENT_SIG_REACTIVE_REFRESH=1 |
Reactive refresh after tcp_login persistent failures (≥3) | OFF | Medium — ret_type=15 semantics not exclusively "client_sig invalid" (includes rate limiting / risk control); in multi-account daemon, misfire may affect other accounts; safe for single-account |
FUTU_QOT_RELOGIN_BACKOFF_MS |
QOT login-health self-heal ladder, four millisecond values: fail0,fail1,fail2,fail3+ |
60000,120000,240000,600000 |
Medium — useful for real-machine verification / long-run diagnostics; avoid overly frequent production relogin |
FUTU_WEBSIG_REFRESH |
Master switch for proactive WebSig refresh. Set only to 0 / false / no / off for emergency rollback, then restart the daemon |
ON | High — when disabled, an expired WebSig can recover only through failure-driven reconnect / ticket replacement |
FUTU_SESSION_KEY_REFRESH |
Control the C++-aligned periodic TCP session-key refresh actor; a refresh failure invalidates the connection and enters the unified reconnect path | ON; disabled only by 0 / false / no / off |
Low — emergency opt-out; normal operation does not need this variable |
FUTU_WEBTCP_SITE_CONFIG_REFRESH |
Enable the periodic WebTCP site-config refresh timer; the initial fetch and commconfig-target-change refresh still run when disabled | OFF; enabled only by 1 / true / yes / on |
Low — last-good remains active |
When to flip the two client-sig switches to default ON: after enough real
deployments show that FUTU_CLIENT_SIG_PROACTIVE_REFRESH and
FUTU_CLIENT_SIG_REACTIVE_REFRESH do not trigger extra rate limiting or
risk-control behavior. These two switches remain experimental opt-in; this note
does not apply to the WebSig and session-key refresh rows that are already
default-on.
Client (CLI / SDK / MCP)¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_CLI_AUTO_IDEM=1 |
futucli auto-derives idempotency_key (param hash) for place-order/modify/cancel | OFF |
FUTU_UPDATE_CHECK_URL |
Override URL for futucli version --check / futucli doctor version.json update checks |
unset uses https://futuapi.com/version.json; unavailable, non-2xx, or schema-incompatible manifests fail closed |
Startup and local caches¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_STOCK_LIST_STARTUP_WAIT_SECS |
Seconds to wait for the first stock-list sync before ready when the local list is empty; background sync continues after timeout | 3; 0 disables the wait |
FUTU_LANGUAGE_PACK_CACHE_DIR |
Root directory for the language-pack manifest and last-good cache | futu-opend-rs/language-packs under the OS cache directory |
Quote quota diagnostics¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_HISTORY_KLINE_CLOUD_SYNC |
Whether to synchronize used historical K-line quota with official OpenD/App; accepts only true / false |
true; use --history-kline-cloud-sync false or history_kline_cloud_sync = false to enter local-only compatibility mode |
FUTU_HISTORY_KL_QUOTA_MAX |
Override for the max unique stocks allowed in one local historical K-line quota period; unset follows the account's dynamic quota | unset (cold-start fallback 100) |
FUTU_HISTORY_KL_QUOTA_PERIOD_SECS |
Historical K-line quota period length, in seconds | 604800 (7 days) |
Note: the historical K-line total quota prefers the account quota returned after login by backend request, matching the value shown in official OpenD UI. FUTU_HISTORY_KL_QUOTA_MAX is only an explicit override for debugging or stress tests; before the dynamic quota arrives, Rust uses the C++ cold-start default 100 as a fail-closed fallback.
Trade diagnostics¶
FUTU_TRADE_PUSH_DIAGNOSTICS is off by default and freezes on first use. Set it to 1, true, yes, or on to enable it. Use INFO logging and daemon --json-log; a receiver using this Rust SDK must also enable the variable and initialize INFO-level JSON logs. Restart the corresponding process after changes.
Diagnostics correlate notification parsing, requery, cache decisions, subscription/permission filtering, native TCP/WS writing and receiver stages. Writing, frame receipt, integrity checks and local queue admission are separate facts; admission does not prove application consumption. REST WebSocket/gRPC records stop at adapter handoff, and other SDKs need matching receiver fields. The packaged scripts/trade_push_diagnostics.py reads local JSONL files and requires an explicit daemon/receiver run binding in a verified common connection observation window. Cross-run frame collisions remain ambiguous; unmatched receiver observations retain unknown server association. Share its allowlisted summary rather than ordinary raw logs, which may contain business data. No new trades are needed.
| Env var | Purpose | Default |
|---|---|---|
FUTU_HISTORY_ORDER_AUDIT=1 |
Enable history-orders backend-row filtering / projection audit logs for investigating Rust vs official C++ history-order count or field differences | OFF |
FUTU_TRADE_PUSH_DIAGNOSTICS |
Correlate trade notifications through native TCP/WS writers and this Rust SDK receiver using INFO JSON logs | OFF |
Account setting switches¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_ACCOUNT_FUNDING_SETTINGS_WRITES |
Allow explicit changes to account financing, currency-exchange and automatic-exchange settings; independent of --extended-data-writes, with original account capabilities, caller permissions and result readback checks still required |
OFF; enabled only by 1 or case-insensitive true |
Testing / Chaos engineering¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_E2E_SIM_ACC |
E2E test sim account | (test-only) |
FUTU_E2E_SIM_PWD |
E2E test sim password | (test-only) |
FUTU_E2E_SIM_PLATFORM |
E2E test platform (futunn / moomoo) |
futunn |
FUTU_CHAOS_ENABLE=1 |
chaos test fault-injection toggle | OFF |
FUTU_MULTI_VERSION_GUARD_STRICT=1 |
multi_version_smoke.sh strict mode (binary fingerprint diff → exit 1) | (set by ship.sh A9) |
Release tooling¶
| Env var | Purpose |
|---|---|
FUTU_MULTI_VERSION_GUARD_STRICT=1 |
Forced by ship.sh A9; fingerprint diff blocks release |
FUTU_MV_CACHE_DIR |
Cache directory for historical binaries downloaded by scripts/multi_version_smoke.sh |
Build metadata¶
| Env var | Purpose | Default |
|---|---|---|
FUTU_OPEND_RS_GIT_SHA |
Override the git SHA compiled into device_alias / version diagnostics |
build script reads git rev-parse --short HEAD |
Naming convention¶
FUTU_<SUBSYSTEM>_<FEATURE>_<ACTION>=<VALUE>:
FUTU_prefix — shared namespace for daemon / CLI / SDK- subsystem:
CLIENT_SIG/TRADE/CLI/E2E/CHAOSetc - feature/action: describes the functionality itself, no internal ticket
numbers exposed (for example, use
PROACTIVE_REFRESHinstead ofINTERNAL_123) - value: follow the matching row; accepted boolean values and default states vary by switch
Precedence vs CLI flags¶
The general order is CLI flag > env var > config file > built-in default;
feature-specific compatibility rules are documented in their table rows.
FUTU_HISTORY_KLINE_CLOUD_SYNC uses CLI > config file > env > default true.
Example: FUTU_PWD=foo futu-opend --login-pwd bar uses bar (CLI flag).