Skip to main content

futucli/cli/commands/
key.rs

1//! Key-management clap argument structs split from commands.rs.
2
3use std::path::PathBuf;
4
5use clap::Args;
6
7#[derive(Args)]
8pub struct GenKeyArgs {
9    /// 人读 ID(审计日志用,必须唯一)
10    #[arg(long)]
11    pub(crate) id: String,
12
13    /// 授予的 scope,逗号分隔(v1.4.34+ 补齐 admin;详见 --help 的
14    /// scopes 长说明)
15    #[arg(
16        long,
17        long_help = "\
18授予的 scope,逗号分隔。
19
20可选(v1.4.34+ 已补齐 admin):
21
22  qot:read         行情读(订阅 / 报价 / K 线 / 摆盘)
23  acc:read         交易账户只读(资金 / 持仓 / 订单历史)
24  trade:simulate   模拟盘下单 / 改单 / 撤单
25  trade:real       实盘下单 / 改单 / 撤单(高风险)
26  trade:unlock     解锁交易(/api/unlock-trade / futu_unlock_trade)
27  admin            v1.4.32+ daemon 生命周期:/api/admin/status /
28                   /api/admin/reload / /api/admin/shutdown
29
30多个 scope 用逗号分隔,例如:
31  --scopes qot:read,acc:read
32  --scopes qot:read,trade:simulate
33  --scopes admin                   # daemon 运维专用 key"
34    )]
35    pub(crate) scopes: String,
36
37    /// keys.json 路径。默认(按 OS):macOS ~/Library/Application Support/futu/keys.json / Linux ~/.config/futu/keys.json / Windows %APPDATA%/futu/keys.json
38    #[arg(long)]
39    pub(crate) keys_file: Option<PathBuf>,
40
41    /// 过期时间: Nd / Nh / Nm 或 RFC3339(如 2026-12-31T23:59:59Z)
42    #[arg(long)]
43    pub(crate) expires: Option<String>,
44
45    /// 备注
46    #[arg(long)]
47    pub(crate) note: Option<String>,
48
49    /// 允许的市场,逗号分隔(如 HK,US)
50    #[arg(long)]
51    pub(crate) allowed_markets: Option<String>,
52
53    /// 允许的品种白名单,逗号分隔(MARKET.CODE 格式,如 HK.00700,HK.09988)
54    #[arg(long)]
55    pub(crate) allowed_symbols: Option<String>,
56
57    /// 单笔订单金额上限
58    #[arg(long)]
59    pub(crate) max_order_value: Option<f64>,
60
61    /// 单日累计金额上限
62    #[arg(long)]
63    pub(crate) max_daily_value: Option<f64>,
64
65    /// 允许交易的时间窗口(服务器本地时区)HH:MM-HH:MM,跨午夜如 22:00-04:00
66    #[arg(long)]
67    pub(crate) hours_window: Option<String>,
68
69    /// 每 60s 最多下单次数(滑动窗口速率限制)
70    ///
71    /// 单笔金额 / 日累计之外再加一层防 spray-and-pray:
72    /// 假设攻击者拿到一把 `max_order_value = 50` 的 key,没速率限制的话
73    /// 一分钟能刷 N 千单;加了这个就被钳制在 `max_orders_per_minute` 内。
74    #[arg(long)]
75    pub(crate) max_orders_per_minute: Option<u32>,
76
77    /// 允许的交易方向白名单,逗号分隔
78    ///
79    /// 典型用法:`--allowed-trd-sides SELL` → 只允许平仓 bot 卖;
80    /// 值:`BUY` / `SELL` / `SELL_SHORT` / `BUY_BACK`(大小写敏感)。
81    /// 改单 / 撤单路径不带 side,不受此限制(避免误伤运维操作)。
82    #[arg(long)]
83    pub(crate) allowed_trd_sides: Option<String>,
84
85    /// v1.4.35: 允许的 acc_id 白名单,逗号分隔(如 `10001,10002`)
86    ///
87    /// **operational safety**:该 key 只能对这些 acc_id 发 trade / unlock / query
88    /// 操作;超出列表的 acc_id 直接 403。None / 空 → 不限(向后兼容)。
89    ///
90    /// 典型用法(多 agent 隔离):
91    ///   `--allowed-acc-ids 10001,10002` → bot-A 只能动 10001/10002
92    ///   `--allowed-acc-ids 10003`       → bot-B 只能动 10003
93    ///
94    /// 注意:这是 **operational** 隔离(防 agent bug / LLM 幻觉 / key 泄露
95    /// 爆炸半径),对**纯现金策略**用户实质等同财务隔离。真·财务隔离(融资 /
96    /// 期权组合 / 跨品种保证金)需要多 union card,见 CLAUDE.md 隔离层级。
97    #[arg(long)]
98    pub(crate) allowed_acc_ids: Option<String>,
99
100    /// v1.4.103 (B10): per-key card_num 白名单, 逗号分隔.
101    ///
102    /// 接受 **4 位 suffix** (App 显示的 "保证金综合账户(`<card-suffix>`)"
103    /// 末 4 位) 或 **16 位完整 card_num** (e.g. `<full-card-num>`).
104    /// 示例为 synthetic placeholder, 不是真实账户信息. daemon 启动后通过
105    /// GetAccList **resolve** → **合并**进 `allowed_acc_ids` (内部仍用 u64).
106    ///
107    /// **设计动机**: App 用户看到的是 card_num, 不是内部 `acc_id`. 直接
108    /// 写 4 位 / 16 位避免先调 /api/accounts 拿映射.
109    ///
110    /// 典型用法 (与 --allowed-acc-ids 等价但用 App 可见的号码):
111    ///   --allowed-card-nums <card-suffix>      → 末 4 位匹配的账户
112    ///   --allowed-card-nums <full-card-num>    → 完整 card_num
113    ///   --allowed-card-nums <suffix-A>,<suffix-B>  → 多个 (e.g. HK + US 各一)
114    ///
115    /// 多 suffix 撞 (短 4 位 match 多账户) → daemon 启动 log warn + skip
116    /// (loud, 不静默接受). 找不到 → log warn + skip (cache load 后可补).
117    #[arg(long)]
118    pub(crate) allowed_card_nums: Option<String>,
119
120    /// 将 key 绑定到本机(软绑定:读 machine-id 计算指纹)
121    ///
122    /// 设置后 key 只能在本机使用;复制到别的机器会被拒。
123    /// 可以和 `--bind-machines` 同时用来同时允许多台机器。
124    #[arg(long)]
125    pub(crate) bind_this_machine: bool,
126
127    /// 追加绑定其他机器(需要对方先跑 `futucli machine-id --for-key <id>` 拿指纹)
128    ///
129    /// 逗号分隔的 64 位 hex 指纹列表,如:
130    ///   --bind-machines aabb...,ccdd...
131    #[arg(long)]
132    pub(crate) bind_machines: Option<String>,
133}