常见坑位速查(UX-06/07/10)¶
本页回答跨 surface 参数格式差异、错误码 sim vs real 差异、 unlock pwd_md5 字段歧义三类常踩但无专门文档的问题。 v1.4.60+ 新加。
1. 跨 surface 参数格式速查(UX-07)¶
同一个字段在不同 surface 有不同命名 / 不同格式,一不小心就混用失败。
code / symbol 字段¶
| Surface | 字段名 | 格式 | 例子 |
|---|---|---|---|
REST /api/* |
code |
带 market prefix | "US.MSFT" / "HK.00700" |
gRPC futu.Trade |
code |
带 market prefix | 同上 |
CLI futucli |
--code |
不带 prefix(配 --market 用) |
--market US --code MSFT |
MCP futu_* tools |
symbol |
带 market prefix | "US.MSFT" |
market / trd_market 字段¶
| Surface | 字段 | 类型 | 数值对照 |
|---|---|---|---|
| REST / gRPC | trd_market |
数字 int32 |
1=HK, 2=US, 3=CN, 4=HKCC, 5=Futures, 6=SG, 15=JP |
| CLI | --market |
字符串 | HK / US / CN / HKCC / Futures / SG / JP |
| MCP | market |
字符串 | 同 CLI |
跨 surface 换 surface 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
v1.4.60 起,daemon 对所有 surface 统一 strip prefix¶
入口层 derive_security_type / derive_sec_market / is_futures_code /
is_option_code / parse_option_dte / cache key 构造都会自动剥 HK. / US.
等前缀,所以带不带前缀都能 work(REST 带前缀 + CLI 不带前缀的文化差异
不再致命)。
但建议遵循 surface 惯例(上表),避免日后 daemon 升级时出奇怪 regression。
2. 错误码 sim vs real 差异(UX-06)¶
重要:sim 账户和 real 账户对同一个 invalid 请求可能返不同错误行为, 用 sim 测出来的结果不一定代表 real 会 work。
典型差异¶
| 场景 | sim 行为 | real 行为 | 教训 |
|---|---|---|---|
下单 symbol 格式错 (US.MSFT v1.4.56 之前) |
两种格式都返 -1 generic | 带 prefix 失败 / 不带 prefix 成功 | sim 看不出 prefix bug |
| trd_env 不匹配(real acc + trd_env=0) | v1.4.50 之前不校验 | backend 拒 | sim 误通 |
不存在的 acc_id (999999) |
返空列表 | backend "Nonexisting acc_id" | sim 误导"账户无资产" |
| 期货 prefix 识别错 (v1.4.56-57 之前) | 两种可能都返 -1 | 精确 110005 合约不一致 | sim 覆盖不到 |
规则¶
- 开发用 sim(安全、不真花钱)
- P0 验证必须 real 至少过一次(对齐 C++ OpenD 行为)
- 外部 reviewer 回归建议同时测 sim + real 双验证
v1.4.51 起 daemon 加强 sim vs real 一致性¶
- trd_env 必校验(v1.4.51 BUG-7)
- acc_id 存在性必校验(v1.4.51 BUG-8)
- camelCase / snake_case normalize(v1.4.45 serde drop 防御)
但不能 100% 消除差异 —— backend 层 sim 和 real 是不同服务路径。
3. unlock_trade.pwd_md5 字段歧义(UX-10)¶
UnlockTradeReq.pwd_md5 字段名暗示要 MD5 hash,但不清楚:
- 是否真要 hash?还是明文?
- 如果 hash,hash 什么?小写 hex 还是 upper?
真相¶
必须是 pwd 的 MD5 hash,小写 hex,32 字符。
Why MD5(对齐 C++ OpenD)¶
- backend 历史设计:cipher 协议用 pwd_md5 不是明文 pwd
v1.4.6+Rust daemon 对齐- 如果传明文密码,backend 签名校验失败返 generic error(不会告诉你字段格式错)
如何生成¶
CLI helper(推荐):
Python:
Rust:
常见错误¶
- ❌ 传明文密码(如
"fuTUnn!ryA88") → daemon 返 generic error,不 block 但没 成功 unlock - ❌ MD5 大写 hex(如
"0FE6...")→ backend 校验失败(不同 byte repr) - ❌ SHA1 / SHA256 hash 代替 MD5 → 同样失败
- ❌ 带 salt 的 hash → 同样失败(backend 不加 salt 算 pwd_md5)
- ✅ 纯 MD5, 32 char 小写 hex(如
"a1b2c3d4e5f6789012345678901234ab")
v1.4.60+ 强化 error 提示(未来 v1.4.60+ 可能加)¶
目前 daemon 对非 32-char hex 输入只是透传 backend,backend 返 generic error。 未来可能在 daemon 入口 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)");
}
相关文档¶
guide/cli.md— CLI 命令完整列表guide/rest.md— REST API 端点guide/mcp.md— MCP tools 列表changelog.md— 版本更新历史