pub struct Args {Show 29 fields
pub cfg_file: Option<String>,
pub config: Option<String>,
pub ip: Option<String>,
pub port: Option<u16>,
pub login_account: Option<String>,
pub login_pwd: Option<String>,
pub login_pwd_md5: Option<String>,
pub login_pwd_file: Option<String>,
pub login_region: Option<LoginRegion>,
pub platform: Option<Platform>,
pub auth_server: Option<String>,
pub device_id: Option<String>,
pub reset_device: bool,
pub setup_only: bool,
pub verify_code: Option<String>,
pub log_level: Option<LogLevel>,
pub websocket_port: Option<u16>,
pub telnet_port: Option<u16>,
pub rest_port: Option<u16>,
pub grpc_port: Option<u16>,
pub rsa_private_key: Option<String>,
pub json_log: bool,
pub lang: Option<String>,
pub rest_keys_file: Option<PathBuf>,
pub grpc_keys_file: Option<PathBuf>,
pub ws_keys_file: Option<PathBuf>,
pub allow_tcp_unauthenticated: bool,
pub audit_log: Option<PathBuf>,
pub tz: Option<String>,
}Expand description
FutuOpenD Rust Gateway — 完全替代 C++ OpenD
Fields§
§cfg_file: Option<String>XML 配置文件路径 (兼容 C++ FutuOpenD.xml)
config: Option<String>TOML 配置文件路径 (v1.4.2+;字段与 CLI 参数对齐, CLI 参数覆盖).
codex 0547 F6 (P3): 字段白名单 (与 XmlConfig schema 一致):
- 登录:
login_account/login_pwd/login_pwd_md5/login_pwd_file/login_region/platform - 监听:
ip/port(aliasapi_port) /rest_port/grpc_port/websocket_port/telnet_port - 安全:
rsa_private_key/rest_keys_file/grpc_keys_file/ws_keys_file/audit_log/allow_tcp_unauthenticated - 系统:
lang/log_level/tz
不能写 TOML 的 CLI-only 字段 (运维 / 调试 / 一次性流程):
device_id / reset_device / setup_only / verify_code /
json_log / inject_auth_failure_every (dev-flags feature only)
任何 unknown field / typo 触发 fatal parse error (BUG-006
deny_unknown_fields), daemon abort. 不再 silent drop.
示例:
login_account = "123456"
ip = "0.0.0.0"
port = 11111
rest_port = 22222
grpc_port = 33333
rest_keys_file = "/etc/futu/keys.json"
audit_log = "/var/log/futu-audit.jsonl"
tz = "Asia/Hong_Kong"ip: Option<String>API 服务监听地址
port: Option<u16>API 服务监听端口
login_account: Option<String>登录账号
login_pwd: Option<String>登录密码明文
login_pwd_md5: Option<String>登录密码 MD5 (32 位小写 hex)
login_pwd_file: Option<String>登录密码从文件读(v1.4.18+)——适用于 systemd LoadCredential= /
Docker secrets 场景。argv 里只有文件路径,不会泄露明文。
文件内容:明文密码(末尾 \n 会被 trim 掉)。
login_region: Option<LoginRegion>后端连接区域 (gz / sh / hk) —— 仅对 --platform futunn 生效
这三个值是 futunn 平台的广州 / 上海 / 香港数据中心标识。
对 --platform moomoo 账户此 flag 会被忽略:daemon 内 commconfig 根据
user_attribution 查 guaranteed_ip 列表覆盖。想切 moomoo 各区用
--platform moomoo + 账号本身决定归属。
v1.4.40 起 clap 封闭 enum 拒绝非法值(v1.4.39 及以前静默接受任意字符串)。
platform: Option<Platform>账号平台(v1.4.14+)—— futunn=牛牛/CN/HK,moomoo=US/SG/AU/JP/CA
同手机号 / 邮箱可以在两边各注册独立账号(不同密码)。默认 futunn。
--auth-server 显式指定 URL 时覆盖 --platform。
auth_server: Option<String>认证服务器 URL(覆盖 --platform 推导的默认值,主要给测试环境用)
device_id: Option<String>设备 ID(16 位 hex)—— 覆盖自动生成/持久化的值。
v1.4.17+ 默认从 ~/.futu-opend-rs/device-{hash}.dat 读(首次随机生成
并写入)。本参数用于显式指定,并更新持久化文件。
如果 device_id 被服务端锁定(error_code=15/21),可用
--reset-device 一键清空文件让下次启动随机生成新值。
reset_device: bool重置 device_id + credentials 文件后再启动(v1.4.17+)
当用户的 device_id 因空验证码 / 多次 SMS 输错被服务端锁定,
所有后续请求都返回 error_code=15 长时间没有登录 无法恢复。
本参数删除 ~/.futu-opend-rs/device-{hash}.dat 和
credentials-{hash}.json,下次 login 重新生成随机 device_id 走
完整首登流程。
setup_only: bool只完成首次设备验证 + 凭据缓存后退出(v1.4.17+)
用于 systemd / Docker / cron 场景:先在前台终端手动跑一次
futu-opend --setup-only 完成 SMS 验证,写入 credentials 文件,然后
生产环境启动时直接走 remember-login 跳过 SMS。
verify_code: Option<String>v1.4.57 外部 UX-04(加拿大同事 SMS + Telegram 中继场景必需): 直接传入 SMS 验证码,跳过 stdin prompt。用于 agent / CI / 远程中继场景 (SMS 验证码通过 Telegram/IM 转发,60 秒失效,直接用 stdin 输入来不及)。
典型用法:
# 1. 先不带 --verify-code 启动触发 SMS(会 fail + 退出,但 SMS 已发)
futu-opend --setup-only --login-account X --login-pwd Y
# 2. 收到 SMS 后立即带验证码重新启动
futu-opend --setup-only --login-account X --login-pwd Y --verify-code 123456log_level: Option<LogLevel>日志级别(v1.4.73 BUG-015: clap ValueEnum 约束有效值 trace/debug/info/warn/error/off, 非法值 parse 阶段拒绝 + 清晰错误,不再 silent 吞 log)
websocket_port: Option<u16>WebSocket 服务监听端口(可选,不指定则不启动 WebSocket)
telnet_port: Option<u16>Telnet 管理端口(可选,不指定则不启动 Telnet)
rest_port: Option<u16>REST API 监听端口(可选,不指定则不启动 REST API)
grpc_port: Option<u16>gRPC 服务监听端口(可选,不指定则不启动 gRPC)
rsa_private_key: Option<String>RSA 私钥文件路径(PEM 格式,启用后 InitConnect 使用 RSA 加解密)
json_log: boolJSON 格式日志
lang: Option<String>界面语言 (chs=简体中文, cht=繁体中文, en=英文)
rest_keys_file: Option<PathBuf>REST API Bearer Token 鉴权:加载 keys.json(futucli gen-key 生成)
不指定时 REST API 无鉴权(保持旧行为,启动 warn)。
grpc_keys_file: Option<PathBuf>gRPC Bearer Token 鉴权:加载 keys.json(futucli gen-key 生成)
不指定时 gRPC 无鉴权。通常与 –rest-keys-file 指向同一文件。
ws_keys_file: Option<PathBuf>核心 WebSocket Bearer Token 鉴权:加载 keys.json
v1.0 起核心 WS(--websocket-port,Futu SDK 使用的 binary WS)支持
握手 + per-message scope 鉴权。客户端用 ?token=<plaintext> query 或
Authorization: Bearer <plaintext> header 传 key。不指定这个 flag 时
WS 无鉴权(legacy 保持兼容,启动 warn)。通常与 --rest-keys-file 指向
同一文件。
allow_tcp_unauthenticated: boolv1.4.104 eli S-001 (P0) fix: native TCP (FTAPI port --port) 显式
允许无 auth 接受连接.
背景: native TCP FTAPI 协议 (Python SDK / C++ OpenD 用) 没有 Authorization header 概念, InitConnect proto 无 Bearer 字段. 加 keystore 后无法做 caller-specific scope 检查.
默认行为 (v1.4.104+): 配置任一 keys file (--rest-keys-file /
--grpc-keys-file / --ws-keys-file) → daemon 关闭 TCP 端口
(fail-closed, 防 v1.4.103 eli S-001 跨 surface bypass).
显式 opt-in 此 flag → 保留 TCP 端口, daemon 启动 loud warn 用户该 端口完全无 auth.
audit_log: Option<PathBuf>审计日志输出:JSONL 文件路径或目录
- 带扩展名的路径(如
/var/log/futu-audit.jsonl)→ 单文件 append - 不带扩展名 / 以
/结尾(如/var/log/futu-audit/)→ 每日滚动, 文件名futu-audit.log+ 日期后缀
只记录 auth / 交易 事件(target = “futu_audit”),常规日志不受影响。
tz: Option<String>v1.4.87 #3 G1: 时区覆盖 (IANA name, 如 “Asia/Hong_Kong” / “America/New_York”)
用于 hours_window 限额检查等 “local time” 语义. 不指定时用系统 TZ
环境变量, 仍未设则用 UTC. 典型场景:
- Daemon 跑在 UTC server 但想 HK 交易时段限额 →
--tz Asia/Hong_Kong - Daemon 跑在 local workstation 且
TZ已正确 → 不用--tz
优先级: --tz flag > TZ env var > UTC.
Trait Implementations§
Source§impl Args for Args
impl Args for Args
Source§fn group_id() -> Option<Id>
fn group_id() -> Option<Id>
ArgGroup::id][crate::ArgGroup::id] for this set of argumentsSource§fn augment_args<'b>(__clap_app: Command) -> Command
fn augment_args<'b>(__clap_app: Command) -> Command
Source§fn augment_args_for_update<'b>(__clap_app: Command) -> Command
fn augment_args_for_update<'b>(__clap_app: Command) -> Command
Command] so it can instantiate self via
[FromArgMatches::update_from_arg_matches_mut] Read moreSource§impl FromArgMatches for Args
impl FromArgMatches for Args
Source§fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>
fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>
Source§fn from_arg_matches_mut(
__clap_arg_matches: &mut ArgMatches,
) -> Result<Self, Error>
fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result<Self, Error>
Source§fn update_from_arg_matches(
&mut self,
__clap_arg_matches: &ArgMatches,
) -> Result<(), Error>
fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error>
ArgMatches to self.Source§fn update_from_arg_matches_mut(
&mut self,
__clap_arg_matches: &mut ArgMatches,
) -> Result<(), Error>
fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error>
ArgMatches to self.Source§impl Parser for Args
impl Parser for Args
§fn parse_from<I, T>(itr: I) -> Self
fn parse_from<I, T>(itr: I) -> Self
§fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
§fn update_from<I, T>(&mut self, itr: I)
fn update_from<I, T>(&mut self, itr: I)
§fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
Auto Trait Implementations§
impl Freeze for Args
impl RefUnwindSafe for Args
impl Send for Args
impl Sync for Args
impl Unpin for Args
impl UnsafeUnpin for Args
impl UnwindSafe for Args
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].