跳转至

常见坑位速查(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 → CLIcode="US.MSFT" trd_market=2--market US --code MSFT
  • CLI → MCP--market US --code MSFTsymbol="US.MSFT"
  • MCP → RESTsymbol="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(推荐):

echo -n "your-trade-password" | md5sum
# 或 macOS:
echo -n "your-trade-password" | md5

Python

import hashlib
pwd_md5 = hashlib.md5(b"your-trade-password").hexdigest()

Rust

use md5::{Md5, Digest};
let pwd_md5 = format!("{:x}", Md5::digest(b"your-trade-password"));

常见错误

  • ❌ 传明文密码(如 "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)");
}


相关文档