NarrowGate:Python 研究与纯 C++ 实盘架构
公开范围说明:NarrowGate 的具体研究内容、实验方案、生产策略实现、实效参数及结果不公开。本文保留为历史架构记录,不代表当前部署或公开源码范围,部分源码链接可能不可用。对研究或课题感兴趣、有疑问的朋友,欢迎邮件私聊:xuantan650@gmail.com。
NarrowGate 现在把研究与实盘分开:Python 负责研究、训练、回测编排和分析,独立 C++ 程序负责实盘行情、推理、策略、订单和账户恢复。实盘不再是 Python 主循环加扩展,也不通过 Python 子进程运行策略。
截至本次更新,原生 Linux 程序已完成选定账户的部署、状态恢复、真实输入暖机及订单链运行检查,旧 Python 生产入口和启动器已退役。离线配置、策略和协议参考库仍供研究与差分测试使用,分别归属 narrowgate、strategy、features 与 execution,不再混放在 live 内。旧 Python 网络客户端和激活链不作为第二套服务保留。这是运行与源码职责边界,不等于所有可选政策、任意账户与完整历史轨迹均已证明一致。
本文重写此前累积的扩展与性能实验叙述,不沿用旧环境的性能倍数。
一、共享计算与实盘应用分开
cpp/narrowgate_cpp/ 共享计算核、研究原生实现
live/native/ 实盘连接、控制器、订单与持久恢复
live/CMakeLists.txt 独立实盘构建入口
strategy/ Python 策略参考与研究消费者
features/ 特征定义和参考实现
models/ 模型及回测相关实现
narrowgate/replay/ 研究回放编排与执行
narrowgate/migration/ 显式离线配置/账户转换,不启动实盘
research/ 实验合同、政策与分析这次拆分不是把一个大文件从 cpp 搬到 live。报价计算、深簿、特征、订单状态和会计等可共享组件留在 cpp;网络会话、实盘运行顺序、对账与恢复由 live/native 装配。研究不能反向依赖实盘应用。
研究侧仍可使用原生加速与 Python 绑定,但独立实盘构建关闭它们。原生模型推理通过 LightGBM C API 完成,不启动 Python 解释器。
cmake --preset native -S live
cmake --build build/live --parallel 2
ctest --test-dir build/live --output-on-failure
build/live/bin/narrowgate_live capabilities能力查询只说明二进制编译了什么,不代表某个账户已获授权或就绪。实际交易入口是携带显式私有配置的 run,不能把它当作离线演示。
二、对齐实际 B0 调用,而不是函数名字
迁移容易出现一种隐蔽错误:两个实现都有同名指标和参数,却由不同上游输入驱动。逐个函数翻译正确,完整策略仍可能不同。
2026-10-26 绑定补充:公开的 narrowgate.native_quote_strategy_config.v2 显式选择 B0_20261026_01 / LOCAL_DYNAMIC。共享 depth_quote_policy 在原始报价边界生成深簿修正,非零修正仍经过原 pair floor/cap,然后才进入取整、post-only 和后续规则。对称 20 档局部几何、60 秒时间加权参考密度与 5 秒固定绝对价格区间端点比较是不同定义;端点变化不是已识别新增/撤销委托,缺失分量对动作中性,不伪造零观测。详见固定版本原生指南。这说明源码与配置支持,不单独证明此刻某远端进程已加载,更不证明新政策盈利。
选定 B0 的真实 prepared-input 调用没有传入可选的成交强度和平方收益反馈。通用执行器支持这些输入,不代表这个 B0 使用了它们。原生程序若在每个 bar 自动接上这些反馈,就会改变流动性、普通改单间隔或 BER 行为。
因此当前绑定采用 B0 实际配置的普通报价间隔、流动性基线与 100 ms 等待,不因“已经实现了一个模块”就自动启用。预测方差、历史滚动方差、振幅以及归一化分母也分别核对,不用名称近似代替单位和来源。普通报价周期、100 ms 等待和深簿历史窗口都不是 risk_horizon_s 或 AS 的剩余终点;原生迁移本身没有引入倒计时。
空成交秒也是输入语义:B0 在日历窗口中保留空值,不能跳过空秒后把两侧价格直接相减。原生风险方差按 B0 的 60 秒窗口、九个有效相邻差值、样本方差与前向保持计算;模型特征和其他历史消费者不随之改写。
完整顺序同样重要:先消费成交和持久撤单义务,处理安全/减仓动作,再判断普通报价或终态续接;随后读取新鲜输入、推理、风险与报价计算,最后提交订单意图。风险状态包括冷却、每日损失、历史回撤和库存生命周期,不只是当前仓位数量。
三、撤单后续接不应再等一个报价周期
普通报价时钟与撤单终态续接不是同一件事。原订单确实终结后,续接应及时处理,不能重新等待普通五秒周期。若续接与到期普通决策碰撞,续接优先,普通决策延后 100 ms,且不提前消耗普通报价时钟。
订单接纳和真正发送也不是同一时刻。已接纳的异步 FIFO 请求不能因为后来一次被动报价反馈更新就被无声取消,更不能凭空多出一秒失效期限。与此同时,真实 UNKNOWN、账户/钱包不确定或持久化失败必须继续阻止不安全发送。
单边撤单不应误触发全局屏障。批量撤单 HTTP 成功也不能伪造所有订单已终结:只有原订单的终态得到证明、无剩余写入且账户就绪,才释放全局屏障。这样既不抢跑,也不无故再等一次周期 REST 对账。
零成交的 NEW/CANCELED 只是订单状态变化,不能每次都作废钱包现金状态;真实成交或无法解释的累计成交则必须重新核账。这些细节会直接改变实际报撤单节奏,比单个报价函数快多少更重要。
四、连接、行情可用和账户可用分别判断
逐笔成交、部分盘口、bookTicker、独立深簿和私有流有各自连接与代际。收到消息不等于输入连续,socket 建立也不等于模型暖机完成。
深簿在拉取快照时继续缓存增量,安装时核对代际与序列,只发布最终同步状态。迟到旧快照不能复活失效盘口,缓存中间状态不能倒填成曾经可见。未知价位与已知零数量分别保留。
原生首增量桥接和保守覆盖与旧 Python 深簿参考存在明确差异,不能藏在“完全一致”四个字里。基线输入对齐与所有候选深盘口分支验收是不同范围。
私有回报、HTTP 返回与 REST 对账可能乱序。FILLED 先到不能被迟到 NEW 重新打开;累计成交不能再次当逐笔成交入账;响应丢失不代表交易所未执行。未知写入按原订单身份核实,不换新身份盲目重发。限流退避和账户恢复也分别处理。
五、恢复同一个账户周期
持久恢复携带仓位成本、未摊销开仓费、已实现盈亏、冷却期限、每日风险基准、回撤峰值、生命周期状态、预测时钟和成交去重边界。会计状态与消费游标一起提交,避免重启后重复记账或漏记。
资金费进入钱包现金核对;策略风险则按选定 B0 的执行后会计口径处理,不能因为钱包变动就擅自改变风险 PnL 定义。费用原币金额与估值依据保留,缺失手续费不当成零。
如果旧进程根本没有保存完整历史,查询仓位与均价不能恢复不存在的历史。可由所有者明确授权建立新的风险统计周期,但必须把旧周期盈亏排除并说明重置边界,不能声称完成了历史迁移。此后的普通重启必须恢复这个周期,不能再次初始化。
正常切换流程是:
- 正常停止旧服务,停止新增风险。
- 撤单,消费并发成交,确认无挂单并完成最终账户核对。
- 保留现有仓位和持久状态。
- 启动原生服务,恢复同一状态,查询实际账户。
- 同步最新行情、完成暖机后恢复报价。
不是靠更复杂的启动仪式提高可靠性,而是让正常停止/启动本身拥有明确的账户语义。
六、验证必须说明覆盖范围
| 检查 | 支持的结论 | 不能替代 |
|---|---|---|
| 组件与 Python 参考差分 | 已测输入的计算、状态与缺失语义 | 任意市场完整路径一致 |
| 合成完整控制器测试 | 普通时钟、续接、FIFO 与屏障顺序 | 真实网络延迟分布 |
| 非零账户与故障恢复测试 | 已测 WAL、费用、风险与去重恢复 | 所有历史账户迁移 |
| TLS/HTTP/WebSocket 回环 | 分片、超时、断线、未知响应等传输边界 | 真实交易所长期运行 |
| 选定账户实际激活 | 状态恢复、暖机与订单链已运行 | 盈利或无缺陷证明 |
私有模型未提供而跳过的测试,不能计作模型通过。回测采用采样延迟,实盘采用真实网络事件;相同计算和顺序不意味着两个环境产生相同成交。当前验证没有把全量 captured-wire/完整账户路径的穷尽一致性写成已完成。
七、下一步性能工作有清晰边界
以后研究继续主要使用 Python,实盘优化集中在完整 C++ 进程。接收、盘口发布、特征、推理、决策、排队、HTTP 和私有回报分别测量,不把局部函数速度当作整条链延迟。
交易所不可直接观察的生效时刻仍需声明代理假设,不能以 RTT/2 冒充实测。回测运行耗时与回测中的模拟延迟也不能混为一谈。
旧 Python 生产入口的退役不意味着删除研究参考、冻结发布包或历史证据。职责清晰、实际调用一致、可恢复的账户状态,才是后续优化可以依赖的起点。