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}