Common Pitfalls Quick Reference (UX-06/07/10)¶
This page answers three categories of commonly-hit but previously-undocumented issues: cross-surface parameter format differences, sim vs real error code differences, and unlock
pwd_md5field ambiguity. Added in v1.4.60+.
1. Cross-surface parameter format (UX-07)¶
The same field has different names / formats across surfaces. Mixing up causes silent failures.
code / symbol field¶
| Surface | Field | Format | Example |
|---|---|---|---|
REST /api/* |
code |
With market prefix | "US.MSFT" / "HK.00700" |
gRPC futu.Trade |
code |
With market prefix | Same |
CLI futucli |
--code |
Without prefix (with --market) |
--market US --code MSFT |
MCP futu_* tools |
symbol |
With market prefix | "US.MSFT" |
market / trd_market field¶
| Surface | Field | Type | Values |
|---|---|---|---|
| REST / gRPC | trd_market |
int32 |
1=HK, 2=US, 3=CN, 4=HKCC, 5=Futures, 6=SG, 15=JP |
| CLI | --market |
String | HK / US / CN / HKCC / Futures / SG / JP |
| MCP | market |
String | Same as CLI |
Cross-surface conversion checklist¶
- REST → CLI:
code="US.MSFT" trd_market=2→--market US --code MSFT - CLI → MCP:
--market US --code MSFT→symbol="US.MSFT" - MCP → REST:
symbol="US.MSFT"→code="US.MSFT" trd_market=2
Since v1.4.60, daemon strips prefixes uniformly¶
All entry-level functions (derive_security_type / derive_sec_market /
is_futures_code / is_option_code / parse_option_dte / cache key) now
automatically strip HK. / US. prefixes at entry. So with or without
prefix works.
But we recommend following surface conventions (table above) to avoid regressions if daemon behavior changes in future.
2. sim vs real error code differences (UX-06)¶
Important: sim accounts and real accounts may return different errors for the same invalid request. Testing on sim does not guarantee real will work.
Typical differences¶
| Scenario | sim behavior | real behavior | Lesson |
|---|---|---|---|
Wrong symbol format (US.MSFT pre-v1.4.56) |
Both formats returned -1 generic | With-prefix fails / without-prefix works | sim couldn't catch prefix bug |
| trd_env mismatch (real acc + trd_env=0) | Pre-v1.4.50: not validated | Backend rejected | sim false pass |
Non-existent acc_id (999999) |
Returned empty list | Backend "Nonexisting acc_id" | sim misled "no assets" |
| Futures prefix mis-identification (pre-v1.4.56-57) | Both possible returned -1 | Exact 110005 field mismatch | sim couldn't catch |
Rules¶
- Development: use sim (safe, no real money)
- P0 verification: must pass real at least once (C++ OpenD alignment)
- External reviewer regression: recommend testing sim + real both
Since v1.4.51, daemon enforces sim vs real consistency¶
- trd_env validation required (v1.4.51 BUG-7)
- acc_id existence validation required (v1.4.51 BUG-8)
- camelCase / snake_case normalize (v1.4.45 serde drop defense)
But cannot eliminate 100% — backend-level sim vs real are different service paths.
3. unlock_trade.pwd_md5 field ambiguity (UX-10)¶
UnlockTradeReq.pwd_md5 field name suggests MD5 hash, but is unclear on:
- Is it a hash, or plaintext?
- If hash, hash of what? Lowercase hex or uppercase?
The truth¶
Must be MD5 hash of trade password, lowercase hex, 32 characters.
Why MD5 (aligned with C++ OpenD)¶
- Backend historical design: cipher protocol uses
pwd_md5, not plaintext - Rust daemon aligned since
v1.4.6+ - If you send plaintext, backend signature check fails and returns generic error (won't tell you the field format is wrong)
How to generate¶
CLI helper (recommended):
Python:
Rust:
Common mistakes¶
- ❌ Plaintext password (like
"fuTUnn!ryA88") → daemon returns generic error, unlock didn't succeed - ❌ MD5 uppercase hex (like
"0FE6...") → backend check fails (different byte repr) - ❌ SHA1 / SHA256 instead of MD5 → fails
- ❌ Hash with salt → fails (backend doesn't salt)
- ✅ Pure MD5, 32-char lowercase hex (like
"a1b2c3d4e5f6789012345678901234ab")
Future v1.4.60+ may add stricter error hints¶
Currently daemon passes invalid pwd_md5 to backend; backend returns generic error. Future may add entry-check:
if pwd_md5.len() != 32 || !pwd_md5.chars().all(|c| c.is_ascii_hexdigit()) {
return error("unlock_trade.pwd_md5 must be 32-char lowercase hex (MD5 hash)");
}
Related docs¶
guide/cli.md— CLI command listguide/rest.md— REST API endpointsguide/mcp.md— MCP tools listchangelog.md— Version history