FutuOpenD.xml Configuration Reference¶
Every tag FutuOpenD v10.11.7108 understands, documented with examples. Start with the FutuOpenD.xml.template in the repo root — it's pre-wired with env-var substitution and sensible defaults.
Disclaimer: This is an unofficial community packaging. Not affiliated with, endorsed by, or supported by Futu Securities or moomoo.
New in v10.10+ — Login Changed¶
Breaking change: As of v10.10.7008, FutuOpenD no longer reads <login_account> or <login_pwd_md5> from FutuOpenD.xml. Credentials must now be passed via CLI arguments:
The futuopend Docker image handles this automatically — set FUTU_ACCOUNT in your environment and the entrypoint passes the correct CLI args. No credentials need to be in FutuOpenD.xml any more.
On first run, FutuOpenD enters interactive login mode, caches your credentials locally, and on subsequent runs logs in automatically via remember-login.
New in v10.10+¶
- Search API — keyword search to find any asset by ticker, name, or keyword
- Search API — news, announcements, and ratings search (one keyword, results from all sources)
- Chart Indicators — all technical indicators supported in Mai Language and Python
- Comprehensive Options Analysis — IV/HV, Put/Call Ratio, 0DTE Options, Upcoming Earnings, Seller Dashboard
- Market Fundamentals API — Institutional Tracker, Macroeconomic Data, Dividend & Earnings Calendars, Industry Chain, Market Movers, Fed Rate Projections
- Config schema unchanged —
FutuOpenD.xmlbyte-identical to 10.7.6708
The One Rule¶
FutuOpenD uses lowercase XML tag names. The root element is <futu_opend>. Tags like <IP>, <Port>, or <LoginAccount> (uppercase or CamelCase) are silently ignored. When in doubt, lowercase it.
Minimal Working Config¶
This is everything you need for a functional session (credentials are handled automatically by the entrypoint):
<?xml version="1.0" encoding="utf-8"?>
<futu_opend>
<!-- TCP API — bind locally -->
<ip>127.0.0.1</ip>
<api_port>11111</api_port>
<!-- RSA key — required for trading or remote access -->
<rsa_private_key>/run/secrets/rsa_key.txt</rsa_private_key>
<!-- Behaviour -->
<lang>en</lang>
<log_level>info</log_level>
<pdt_protection>1</pdt_protection>
<dtcall_confirmation>1</dtcall_confirmation>
</futu_opend>
Add whatever you need from the sections below. Everything else is optional.
Account & Authentication¶
v10.10+ note:
<login_account>and<login_pwd_md5>are no longer read fromFutuOpenD.xml. SetFUTU_ACCOUNTas an environment variable — the entrypoint passes your credentials via CLI arguments automatically.
Remember-Login (v10.10+)¶
FutuOpenD v10.10+ uses a remember-login mechanism:
- First run: OpenD enters interactive login mode, prompts for account and password, caches credentials locally
- Subsequent runs: OpenD logs in automatically using the cached credentials
This means you only enter your password once — after the first successful login, the Docker data volume persists the session and FutuOpenD reuses it on every restart.
Your FUTU_ACCOUNT environment variable tells FutuOpenD which account to log in with. No password needed in config.
Important: The Docker data volume (
futuopend-data) stores the cached session. Do not delete it — otherwise FutuOpenD will require interactive login again on next start.
When re-verification is triggered: - New IP or device detected by Futu's servers - Futu invalidates the device whitelist (server-side, hours to days) - You will need to submit a new SMS/CAPTCHA code via Telnet port 22222
<rsa_private_key>¶
Path to your RSA private key file. Required for trading when <ip> is anything other than 127.0.0.1.
Get one from the Futu OpenAPI Dashboard → Manage Key → generate and download. Then copy it to secrets/rsa_key.txt and chmod 600.
Network & Protocol¶
<ip> — TCP API bind address¶
Controls which interfaces FutuOpenD listens on.
| Value | Who can reach it |
|---|---|
127.0.0.1 | Local processes only (default, safest) |
0.0.0.0 | Anyone on the network — set this for remote access |
<!-- Local dev — only this machine -->
<ip>127.0.0.1</ip>
<!-- Cloud VM or remote SDK -->
<ip>0.0.0.0</ip>
Security: When you set
<ip>0.0.0.0</ip>, you must also set<rsa_private_key>. Trading calls get rejected without it. Quote-only works without encryption.
<api_port> — TCP API port¶
Defaults to 11111. Only change it if something else already owns that port.
<websocket_ip> / <websocket_port> — WebSocket¶
The WebSocket endpoint. Leave <websocket_port> unset to disable.
<websocket_key_md5>¶
WebSocket clients use this MD5 hex string to authenticate. If unset, any client can connect (subject to RSA rules for trading calls).
<!-- Generate with: echo -n "your_secret_key" | md5sum | cut -d' ' -f1 -->
<websocket_key_md5>YOUR_32CHAR_MD5_HASH_HERE</websocket_key_md5>
<websocket_private_key> / <websocket_cert> — TLS/SSL¶
Both must be set together to enable WSS. Required when WebSocket crosses an untrusted network.
Generate a self-signed cert (fine for testing):
openssl req -x509 -newkey rsa:4096 \
-keyout secrets/key.pem -out secrets/cert.pem \
-days 365 -nodes -subj "/CN=futuopend"
# Strip the password — FutuOpenD can't handle encrypted keys
openssl rsa -in secrets/key.pem -out secrets/key_nopass.pem
<websocket_private_key>/run/secrets/ws_key_nopass.pem</websocket_private_key>
<websocket_cert>/run/secrets/ws_cert.pem</websocket_cert>
Behaviour & Tuning¶
<log_level>¶
How chatty are the logs?
| Value | Use it when |
|---|---|
debug | First setup, chasing connection issues |
info | Normal day-to-day running (default) |
warning | You want less noise |
error | Production, keep it quiet |
fatal | Only catastrophic failures get logged |
no | Logging disabled entirely — don't use during setup |
<log_path>¶
Custom log directory. Leave unset to use FutuOpenD's default.
<push_proto_type>¶
Format for pushed subscription data.
| Value | Format | Best for |
|---|---|---|
0 | Protocol Buffers | Production (compact, fast) |
1 | JSON | Debugging (human-readable) |
<qot_push_frequency>¶
Cap push frequency in milliseconds per subscription. Does not affect K-line pushes. Leave unset for unlimited.
<!-- One push per second — reduces bandwidth on high-activity subscriptions -->
<qot_push_frequency>1000</qot_push_frequency>
<price_reminder_push>¶
Receive price alert notifications pushed from Futu's server.
<price_reminder_push>1</price_reminder_push> <!-- on (default) -->
<price_reminder_push>0</price_reminder_push> <!-- off -->
<auto_hold_quote_right>¶
If another terminal kicks you off your quote rights, should FutuOpenD automatically try to reclaim them for 10 seconds?
<auto_hold_quote_right>1</auto_hold_quote_right> <!-- auto-reclaim (default) -->
<auto_hold_quote_right>0</auto_hold_quote_right> <!-- manual re-login -->
<telnet_ip> / <telnet_port>¶
Enable the Telnet debug console — required for first-login SMS/CAPTCHA verification. Inside a container it must bind 0.0.0.0 so the published host port can reach it.
The shipped FutuOpenD.xml.template enables this by default (${FUTU_TELNET_IP:-0.0.0.0} / ${FUTU_TELNET_PORT:-22222}).
Warning: Telnet is plaintext. Keep the host port firewalled/localhost-bound and never expose
22222to untrusted networks.
Language & Locale¶
<lang>¶
| Value | Language |
|---|---|
en | English |
chs | Simplified Chinese |
<future_trade_api_time_zone>¶
Required for futures trading. Sets the time zone for timestamps in futures API responses.
<future_trade_api_time_zone>UTC+8</future_trade_api_time_zone> <!-- HK, Singapore -->
<future_trade_api_time_zone>UTC+9</future_trade_api_time_zone> <!-- Japan -->
<future_trade_api_time_zone>UTC+11</future_trade_api_time_zone> <!-- Sydney -->
<future_trade_api_time_zone>UTC-5</future_trade_api_time_zone> <!-- New York -->
<future_trade_api_time_zone>UTC-6</future_trade_api_time_zone> <!-- Chicago -->
US Market Protections¶
Applicable only to Futu US / moomoo US accounts.
<pdt_protection>¶
Pattern Day Trade Protection — blocks orders that would trigger PDT status.
<pdt_protection>1</pdt_protection> <!-- active (recommended) -->
<pdt_protection>0</pdt_protection> <!-- disabled -->
PDT protection helps, but doesn't eliminate risk. If your equity drops below $25,000 and you're flagged as a PDT, you can't open new positions until you deposit funds.
<dtcall_confirmation>¶
Day-Trading Call Warning — blocks orders that would exhaust your DT buying power.
<dtcall_confirmation>1</dtcall_confirmation> <!-- active (recommended) -->
<dtcall_confirmation>0</dtcall_confirmation> <!-- disabled -->
A triggered DT Call requires depositing the full call amount to clear.
Environment Variable Substitution¶
FutuOpenD does not expand environment variables itself. The image's entrypoint renders ${VAR_NAME} placeholders with envsubst at container start, using the values Docker injects. Use ${VAR} only — the ${VAR:-default} syntax is not supported.
<rsa_private_key>${FUTU_RSA_KEY}</rsa_private_key>
<ip>${FUTU_IP}</ip>
<log_level>${FUTU_LOG_LEVEL}</log_level>
Defaults come from docker-compose.yaml/.env, and the entrypoint exports fallbacks for any variable that is unset.
Via Docker Compose:
services:
futuopend:
environment:
FUTU_ACCOUNT: "12345678"
FUTU_RSA_KEY: "/run/secrets/rsa_key.txt"
FUTU_IP: "0.0.0.0"
FUTU_LOG_LEVEL: "debug"
Via docker run:
docker run \
-e FUTU_ACCOUNT=12345678 \
-e FUTU_RSA_KEY=/run/secrets/rsa_key.txt \
shing1211/futuopend:latest
Note:
FUTU_ACCOUNTis required for v10.10+ remember-login. No password needed — credentials are cached after first interactive login and reused automatically.
Supported variables¶
| Variable | Maps to | Default |
|---|---|---|
FUTU_ACCOUNT | CLI -login_account arg | (required for remember-login) |
FUTU_RSA_KEY | <rsa_private_key> | (required for trading) |
FUTU_IP | <ip> | 0.0.0.0 |
FUTU_TELNET_IP | <telnet_ip> | 0.0.0.0 |
FUTU_TELNET_PORT | <telnet_port> | 22222 |
FUTU_API_PORT | <api_port> | 11111 |
FUTU_WS_PORT | CLI -websocket_port | (unset — WebSocket off) |
FUTU_LOG_LEVEL | <log_level> | info |
FUTU_LANG | <lang> | en |
FUTU_PUSH_PROTO | <push_proto_type> | 0 (protobuf) |
FUTU_FUTURE_TZ | <future_trade_api_time_zone> | UTC+8 |
FUTU_AREA_CODE | CLI -area_code | +852 |
First-Time Login: Phone Verification in Docker¶
FutuOpenD 10.10+ has no non-interactive password login. The account is cached after one successful login; after that FUTU_ACCOUNT + remember-login works. So the first login must be interactive (with a TTY) or completed via the Telnet 2FA interface.
Do not set
FUTU_ACCOUNTfor the very first login. WithFUTU_ACCOUNTset on an empty volume, OpenD tries remember-login, finds no cached credential, and exits:登录失败,找不到记住密码信息,请使用账号密码登录.
First login (one time)¶
Run interactively with FUTU_ACCOUNT unset, enter account/password, and choose remember:
If Futu then challenges the device (new IP/device), it prints Waiting for phone verify code, please input by telnet... — continue with the Telnet steps below. The cached session is written to the futuopend-data volume.
Once logged in, set FUTU_ACCOUNT in .env and start normally:
How verification flows¶
- On first run (empty data volume) or a new device, Futu sends an SMS or requires CAPTCHA
- OpenD waits:
Waiting for phone verify code, please input by telnet... - You submit the code via Telnet → validation → credentials cached → remember-login active
Step 1 — Start and watch the logs¶
Two things can happen:
Option A — Remember-login succeeds immediately:
You're in. Skip to Step 5.
Option B — Phone/CAPTCHA verification is triggered:
[INFO] Waiting for phone verify code, please input by telnet...
[INFO] Use command: input_phone_verify_code -code=123456
Step 2 — Submit the verification code¶
Use the helper (requires nc):
For CAPTCHA instead of SMS:
# Copy the CAPTCHA image out of the container
docker cp futuopend:/home/futuopend/.com.futunn.FutuOpenD/F3CNN/PicVerifyCode.png ./PicVerifyCode.png
# Then submit it
./scripts/verify_code.sh --pic YOUR_CODE
Or raw netcat:
echo "input_phone_verify_code -code=123456" | nc 127.0.0.1 22222
echo "input_pic_verify_code -code=YOUR_CODE" | nc 127.0.0.1 22222
Step 3 — Confirm success¶
Look for:
Step 4 — Subsequent runs¶
After the first successful login, FutuOpenD uses remember-login automatically:
[entrypoint] Starting FutuOpenD with remember-login for account: 12345678
[INFO] Login succeeded. Account: 12345678
No verification needed — credentials are cached in the futuopend-data Docker volume.
Troubleshooting: re-verification triggered¶
If you see the verification prompt again on a subsequent run, it means Futu's server invalidated the device whitelist. This can happen when:
- You're on a new IP or network
- Futu reset device registrations server-side
- The data volume was deleted
Simply submit a new verification code as in Step 2 above. Your existing session will be replaced with a fresh one.
Complete Config Example¶
<?xml version="utf-8"?>
<futu_opend>
<!-- Remote access: bind to all interfaces -->
<ip>0.0.0.0</ip>
<api_port>11111</api_port>
<!-- WebSocket on 11112 -->
<websocket_ip>0.0.0.0</websocket_ip>
<websocket_port>11112</websocket_port>
<!-- RSA key — required for trading or remote access -->
<rsa_private_key>${FUTU_RSA_KEY}</rsa_private_key>
<!-- Behaviour -->
<lang>en</lang>
<log_level>info</log_level>
<push_proto_type>0</push_proto_type>
<!-- US market guards -->
<pdt_protection>1</pdt_protection>
<dtcall_confirmation>1</dtcall_confirmation>
<!-- Uncomment for WSS (TLS) -->
<!-- <websocket_private_key>/run/secrets/ws_key_nopass.pem</websocket_private_key> -->
<!-- <websocket_cert>/run/secrets/ws_cert.pem</websocket_cert> -->
<!-- Telnet for first-login verification commands -->
<telnet_ip>0.0.0.0</telnet_ip>
<telnet_port>22222</telnet_port>
</futu_opend>
This project is an unofficial community packaging. It is not affiliated with, endorsed by, or supported by Futu Securities or moomoo. All trademarks belong to their respective owners.