Skip to content

Release Notes

v1.4.26 · 2026-04-17

Broker channel IP pool fix (accounts may have been missing)

Since v1.4.8, broker TCP connections reused Platform IPs and relied on the server to LOGIN_STATUS_REDIR us to the correct broker—but the server doesn't always redirect, so some brokers could land on the wrong server and get_acc_list would return too few or wrong accounts. v1.4.26 aligns with C++ ChannelAddressManager: broker IP pools come from commconfig guaranteed_ip_for_conn keyed by broker_id, so CMD 1001 login connects to the right broker directly and the account list is complete again.

Other changes:

  • futucli account table expands from 3 columns to 8 (Acc ID / Card / Env / Broker / Type / Status / Role / Markets), aligned with the full TrdAcc proto.
  • 4 new MCP tools: futu_get_history_kline (rehab control) / owner_plate (plate membership) / reference (related securities) / option_chain (expiry-grouped call/put).
  • 5 new futucli analysis commands: capital-flow / capital-distribution / market-state / owner-plate / option-chain.
  • Trading bot tutorial adds a "5 minutes: zero to first order" starter section.
  • Fixed: MCP trade tool Protobuf decode failure (get_max_trd_qtys / get_history_orders / get_history_deals).

v1.4.25 · 2026-04-17

MCP + futucli trade/quote capability catch-up (aligned with official py-futu-api)

Benchmarked against FutunnOpen/py-futu-api (54 user-facing methods), this release adds 8 MCP tools + 6 futucli commands:

  • MCP trade extensions: futu_get_max_trd_qtys / order_fee / margin_ratio / history_orders / history_deals — LLM can now compute max position size / fee estimate / margin ratio / audit past fills before placing orders.
  • MCP analysis: futu_get_capital_flow / capital_distribution / market_state — capital flow + market status analysis for LLM.
  • futucli order-write trio: place-order / modify-order / cancel-order — shell-scriptable order placement (real env requires --confirm; default env = simulate for safety).
  • futucli history queries: history-orders / history-deals / max-qtys — ops reconciliation + pre-order sizing.

Three-surface coverage: MCP 37% → 52%, futucli 26% → 37%, REST remains at ~74%. Full matrix in essentials/2026-04-17-1407-api-coverage-matrix.md.

Remaining gaps (option_chain / stock_filter / history_kline / warrant / ipo_list / etc.) scheduled for v1.4.26.

v1.4.24 · 2026-04-17

Broker channel reconnect + runtime dynamic management

  • Broker channel auto-reconnect: Platform channels have reconnect-on-heartbeat-exit since v1.4.12, but per-broker channels didn't — a broker disconnect left that broker "zombie" until opend restart. v1.4.24 spawns a reconnect watcher per broker that, on heartbeat exit, re-logs-in via CMD 1001 using the cached broker_client_sig/key (valid ~30 min), skipping HTTP auth. Exponential backoff 3-60s, 6 attempts before giving up (Platform reconnect will rebuild all brokers).
  • CMD 20177 runtime broker diff: when server pushes "valid broker list changed," we now actually diff vs current brokers map: removed brokers get dropped from the map and TCP closed; added brokers emit WARN (can't auto-build due to one-shot auth_code — Platform reconnect or opend restart required).

Supporting change: new BrokerConnMeta cache stores each broker's BrokerAuth + last TCP addr (post-redirect) for reconnect reuse.

v1.4.23 · 2026-04-17

Broker-change push handlers (aligned with C++ OnRecvBrokerChangePush / OnRecvValidBrokerListChangePush)

  • CMD 20177 CidStatusChangePush: when the server pushes "your cid's valid broker list has changed" (triggered when user opens/closes a broker in the app), the client automatically re-fetches CMD 20176 GetValidBrokerList. Logs emit the new broker_ids.
  • CMD 9429 BrokerChangePush: the legacy "main broker change" signal. C++ has deprecated the downstream reaction; we mirror the conservative behavior and only log.

Known limitation: receiving 20177 + re-fetching 20176 gets the new list, but we do not rebuild broker channels on the fly (newly-opened brokers won't auto-connect). Opend users rarely open new brokers at runtime; this is deferred until needed.

v1.4.22 · 2026-04-17

C++ alignment cleanup: forced_ip / svr_time offset / CMD 20176 / setup-only speedup

  • forced_ip_for_conn support: CommConfig's "emergency forced IP" mechanism. Server pushes a single IP with expiry; client bypasses all fallback and uses it directly — meant for gradual rollout or server failover. Aligned with C++ ParseForcedIpConfig.
  • svr_time offset correction: TOTP seed switched from "local time" to "server time" (offset captured from auth response). CommConfig requests no longer fail when local clock drifts > 30s; WARN emitted on skew. Aligned with C++ INNBiz_SvrTime.
  • CMD 20176 GetValidBrokerList alignment: C++ deprecated the old 9419 main-broker protocol in favor of 20176 as broker validity source of truth. We now send 20176 after Platform login and diff the result against HTTP auth's auth_code_list, warning on mismatch.
  • --setup-only 5-6x speedup: previously ran the entire initialization (~14s) before exiting. v1.4.22 returns immediately after auth succeeds — measured at 2.4s on-device. Much faster for systemd / Docker / cron first-launch setup.

v1.4.21 · 2026-04-17

4 login-path bugs caught during v1.4.20 on-device verification

  • CMD 1321 conn_identify is invalid — overseas accounts fail to fetch ConnIP list: conn_identity field was hardcoded to 1 (CN), so HK / US / SG / AU / JP accounts all got rejected. Now derived from user_attribution (HK=6 / US=2 / SG=3 / AU=4 / JP=5).
  • CommConfig guaranteed_ip_for_conn parse failure: v1.4.20 assumed the server always returns a "JSON-in-JSON string" for this field, but the server also returns arrays or null directly for some accounts → parse failed with EOF while parsing. Now handles all three shapes gracefully.
  • remember-login wrongly fell back to password auth when server requested SMS: server returning code=20 require_device_verify on expired cached credentials is a normal SMS flow, not an error. v1.4.20 treated it as error → fallback to password auth → two rapid authority requests hit server-side rate limit → got misleading ret_type=15. Fixed: remember-login path now also invokes the SMS handler.
  • ret_type=15 error hint no longer blames "device_id poisoning" uniformly: 15 has 3 distinct causes (poisoning / rate-limit / account-level state). The hint now walks users through them in order.

v1.4.20 · 2026-04-17

CommConfig dynamic IP pool — aligned with C++ FutuOpenD's official channel

  • Platform IP pool gains a new top-priority layer: CommConfig. After successful login, we actively call /v2/conf/select_all on api.futunn.com / api.moomoo.com and merge the server-pushed fresh IPs (guaranteed_ip_for_conn) to the front of the pool. This is the same channel C++ FutuOpenD uses — fresher than DNS, more authoritative than hardcoded lists.
  • Final IP priority chain: CommConfig (server-pushed) → DNS (public domain resolution) → Hardcoded (v1.4.11 baseline). Any layer failing falls back to the next — startup is never blocked.
  • Periodic background refresh: opend spawns a background task that re-fetches CommConfig on the limit_time cadence returned by the server (clamped to 5 min – 2 h). Long-running instances automatically pick up fresh IPs without a restart; reconnects use the cached snapshot.
  • TOTP auth_token: 6-digit code generated via Google OTP SHA1 to authenticate to the Futu API. Algorithm aligned with C++ GenGoogleOTPCode_SHA1 and validated against RFC 6238 standard test vectors.

v1.4.19 · 2026-04-17

DNS-resolved IP pool + diagnostic messages + security hardening

  • Platform IP pool gains DNS resolution: at startup we resolve the six per-region domains (hkconn.futunn.com, usconn.moomoo.com, etc.) and put the returned IPs in front of the connection pool. When Futu rotates server IPs, we pick them up automatically. The hardcoded IP list stays as fallback.
  • Platform IP pool exhausted error now includes firewall diagnosis: when every IP is unreachable, the log tells you "this is almost certainly an outbound firewall issue (port 9595 blocked)" with a reproducer command.
  • Login password in-memory protection: AuthConfig gains ZeroizeOnDrop — heap memory is scrubbed on drop, shrinking the exposure window to core-dump / memory-dump attackers.
  • Dependency audit cleared: removed obsolete crates, upgraded transitive deps; cargo audit goes from "1 CVE + 3 unmaintained warnings" to 0 blocking alerts.

v1.4.18 · 2026-04-17

Login password — secure storage

  • futucli set-login-pwd --account <ID> stores the password once in the OS keychain; subsequent futu-opend launches no longer need --login-pwd. Nothing leaks to ps aux, shell history, or config-file backups.
  • New --login-pwd-file <path> — Docker secrets / systemd LoadCredential friendly.
  • Legacy --login-pwd still works but now prints a WARN prompting you to migrate.

v1.4.17 · 2026-04-17

device_id lifecycle overhaul + staged production deployment

  • ~/.futu-opend-rs/ now holds all credentials, so launching from different working directories no longer triggers repeated SMS verification.
  • New --setup-only: run once in the foreground to complete SMS verification; subsequent systemd / Docker launches skip SMS.
  • New --reset-device: one-shot cleanup when the server has locked your device_id.
  • Wrong SMS code → automatically rotate device_id and retry (up to 2 times). No more "one typo and you're stuck forever".

v1.4.11–v1.4.16 · 2026-04-17 (login-stability sprint)

8 releases in one day fixing the login pipeline. User-visible changes:

  • Overseas accounts no longer hit CN IPs: IP pool now picked per account attribution (CN / HK / US / SG / AU / JP).
  • Faster cold-start: 3 IPs are tried in parallel — the first one that handshakes wins. First-screen latency drops from "10-second timeout on the slow IP" to "~200ms RTT of the fastest IP".
  • New --platform <futunn|moomoo>: when the same phone number has independent accounts on both platforms, this flag disambiguates.
  • moomoo account login fixed: previously --platform moomoo + a phone number returned "account/password mismatch" (actually an internal header issue); fixed in v1.4.15.
  • Empty SMS code guard: background-mode runs used to read empty from stdin → submit empty code → device_id permanently locked. Now blocked.
  • Multi-instance port conflict detection: running a futunn + moomoo instance side by side now warns about port collisions.

v1.4.10 · 2026-04-16

  • Gateway connect timeout tightened from Linux's 127-second default to 10 seconds — fail fast.
  • Auto-fallback to other IPs in the same pool when one is unreachable.

v1.4.8–v1.4.9 · 2026-04-16

Broker channel shipped

  • Account list, positions, and orders now flow through a dedicated broker channel, matching the official Futu OpenD architecture.
  • Supports 7 brokers: Futu HK / US / SG / AU / JP / MY / CA.

Earlier versions

v1.0–v1.4.7 changes were mostly internal refactors and protocol alignment with no impact on user-facing call conventions. If you are upgrading from an older version:

  1. Run futu-opend --setup-only once to initialize the v1.4.17+ credentials layout.
  2. Consider migrating scripts from --login-pwd to futucli set-login-pwd (v1.4.18).
  3. All other CLI flags remain compatible — no changes needed.

Feedback

Bug reports / feature requests: Contact