ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Trading-as-Git:用版本控制思维构建本地量化Agent与风控闭环

Trading-as-Git:用版本控制思维构建本地量化Agent与风控闭环 做量化的朋友应该都经历过那种时刻回测曲线漂亮得像教科书一上实盘就开始漏气连续几天亏损到怀疑人生。我自己就曾被一个趋势策略卡在窄幅震荡里反复打脸账户净值一条直线往下掉那时候才真正想明白一件事——实盘和回测最大的区别不是行情而是“不可回退”。代码写错了可以 revert策略上错仓位却没有 CtrlZ。今天这篇文章聊的 OpenAlice正是围绕这个痛点长出来的一套本地量化 Agent 系统核心设计哲学我称之为 Trading-as-Git把策略生命周期当成代码仓库来管用分支隔离、提交复现、回滚止损来约束每一次实盘进出。内容全部来自我实际搭建和跑过的项目没有课程推销也不堆术语。我会依次拆解为什么用 Git 的思维做交易、本地方案里各 Agent 怎么分工编排、围绕“活得久”设计的闭环风控以及实操中最容易翻车的细节。这套内容适合两类人正在实盘但管不住回撤的手动交易员以及想从“单机脚本”进化到“可演进系统”的量化开发。如果你是前者重点看第 3 章的风控闭环如果你是后者建议从头到尾读一遍里面有不少我在踩坑之后才补上的工程约束。1. 为什么是 Trading-as-Git把策略当仓库管起来1.1 实盘和代码最大的区别没有 CtrlZ做量化的人嘴上常挂着“策略是代码”但很少有人认真想过这句话的另一面代码在本地仓库里怎么改都行哪怕把整个模块删了也能还原真金白银的交易却一旦发生就永远留在账单上。赔掉的每一笔钱都不会像 git revert 那样被历史抹掉。所以我在设计 OpenAlice 时做的第一个决定不是选哪个策略、用什么模型而是把“不可回滚”当成系统设计的第一约束条件。Git 的价值从来不在于“存文件”而在于它让变更变成可追踪、可对比、可回退的版本化事件。交易系统也一样策略参数、特征计算、订单路由、持仓状态每一个环节都该有版本、有提交、有审计。把交易和 Git 类比不是文字游戏而是一种思维方式转换——你不再问“现在策略表现怎么样”而是问“现在实盘跑的是哪个 commit它凭什么待在这个分支上”。1.2 分支、提交、标签策略版本化的三个基元OpenAlice 的仓库约定很简单main分支永远是当前实盘配置research/*是各种实验分支paper/*跑模拟盘prod/*是从 paper 晋升出来的候选版本。每次晋升不是复制文件夹而是merge自动带上研究阶段的 commit message包括回测区间、预期最大回撤、参数文件 hash。这样实盘出问题的时候第一反应不是翻聊天记录找人问“上次改了什么”而是git log看最近一次 merge 发生了什么。我建议每个 commit message 都按固定格式来写机器可读是关键。参考格式是这样的git commit -m strat: rsi_reversion / 2019-2024 回测 / maxDD 8.2% / params7fa3c9e git checkout -b paper/rsi_reversion # 模拟盘观察 7 天后 git checkout prod git merge paper/rsi_reversion --no-ff git tag live/2025-06-01tag用来标记一次真实上线的状态。等哪天策略出现问题你可以直接git diff live/2025-06-01..HEAD看看实盘期间到底改了什么。别小看这一条它能把“复盘靠印象”变成“复盘靠证据”。1.3 prod 分支禁止热改爆仓最经典的肇因最重要的一条纪律一旦 checkout 到 prod所有 Agent 读到的参数都必须来自打包在提交里的文件运行时禁止改。真遇到策略失效正确动作是切回stable分支而不是在 prod 上现场调参。现场调参等于把一个未经回测的版本直接丢向实盘绝大多数爆仓都是这个动作造成的。我见过太多人白天看行情不对劲晚上“灵机一动”改了止损距离第二天继续亏第三天才想起来改回去。这种热改的热知识在于它根本没有经过验证流程而是情绪驱动。OpenAlice 用技术约束来对抗情绪所有策略 Agent 启动时读取的是 Git checkout 出来的参数而不是数据库里的“当前配置”。想改参数可以走一次完整的分支、回测、模拟盘、merge 流程让系统强制你冷静。2. OpenAlice 本地量化 Agent 架构与编排2.1 本地优先的真正理由延迟、密钥与数据主权OpenAlice 为什么坚持本地量化而不是把 Agent 放在云端我总结下来有三个核心理由。一是延迟本地进程直接连交易所的行情和交易接口比多一跳公网转发少一截延迟对高频调仓和熔断撤单尤其关键。二是密钥交易所 API 密钥一旦落到第三方服务器攻击面就变大放在本机并用环境变量注入至少你能控制物理访问。三是数据主权策略权重的中间计算、持仓快照、订单流水都属于敏感数据我不想让它们经过任何外部服务。本地部署还有一个隐藏红利Agent 之间的通信不经过公网风控指令的执行路径短链路断了也能在进程内完成最基础的止损。当然本地部署也有缺点比如机器宕机没人盯着但这可以通过看门狗脚本和独立熔断进程来缓解。2.2 五个 Agent 的分工谁生成、谁审批、谁执行OpenAlice 里运行着五个核心 Agent我把它们的职责列成一张表Agent核心职责关键产出情报 Agent拉取行情、经济日历、新闻做轻量摘要事件包策略 Agent特征计算、信号生成遵守当前 checkout 参数交易意图风控 Agent前置风控计算、仓位控制、签发 PermitToken风控令牌执行 Agent下单、改单、撤单核对成交回报成交回报账本 Agent持久化订单/持仓/净值输出日终快照交易流水这五者的关系不是平等的“同事关系”而是有严格的上下边界。策略 Agent 永远没有下单权限它只能生成“交易意图”——包括交易标的、方向、期望入场价、期望止损价然后提交给风控 Agent。风控 Agent 查完所有规则后签发一个PermitToken执行 Agent 只认带 Token 的指令。执行 Agent 是唯一持有交易所 API 密钥的进程。2.3 事件驱动的编排信号与订单之间的严格边界各 Agent 之间不搞 RPC 大循环而是通过事件总线解耦。我用 Redis Streams 作为通信层原因很简单它自带消费组可以保证每条事件至少被一个消费者处理而且天然支持多生产者多消费者。数据流大致是这样的情报 Agent 把清洗后的行情、日历、新闻推送到market.events策略 Agent 订阅market.events产出候选信号到signal.requests风控 Agent 消费signal.requests校验通过后把PermitToken发布到exec.permit执行 Agent 监听exec.permit完成下单后把成交回报写到exec.fills账本 Agent 消费exec.fills更新持仓和净值快照这套事件流的精髓在于“信号不等于订单”。很多人做量化 Agent 喜欢让 AI 模型直接输出买入指令这是非常危险的。AI 的输出本质上是一个概率分布而不是一个经过合规校验的动作。OpenAlice 用 PermitToken 机制把“生成想法”和“执行动作”彻底隔开即使策略 Agent 被错误数据带偏风控 Agent 仍然能拦住越界的意图。2.4 不是所有环节都需要大模型三七开的智能分配你可能注意到上面这套架构里没有满屏的“智能”。这是刻意为之。很多朋友一上来就买全套 Agent 框架什么都招 AI 处理结果系统复杂到连作者本人都解释不了。我的看法是Agent 的价值不在“全自动写代码”而在把复杂动作拆成可验证的小步骤风控这种对确定性要求极高的环节用传统规则比用 LLM 可靠太多。OpenAlice 的分配原则是三七开七成确定性逻辑信号计算、仓位公式、风控规则、订单路由走传统代码三成允许模糊的任务交给本地部署的 LLM。比如情报 Agent 的新闻摘要、日志归因这些任务我会用本地部署的量化版本模型来做例如 DeepSeek 的量化版本地部署跑在消费级显卡上完全够用。这种选择不是迷信哪个模型而是基于成本、延迟和可解释性的综合权衡。3. 风控闭环四道闸门把爆仓变成异常状态3.1 闭环的含义亏损要反馈到策略本身闭环这个词被用滥了但 OpenAlice 里的“闭环”有非常具体的含义亏损的结果必须回到策略的起点改变下一次交易的先验概率。传统写法是策略产生信号 → 下单 → 等账户亏到某个百分比 → 手动或自动平仓。这其实是个开环——你没有把“这次亏损教会了什么”系统化地写回策略版本里。OpenAlice 的做法是给每个策略维护一份“现实偏差”档案实盘真实成交和回测时的对应成交做逐笔对齐分析记录实际滑点与回测假设滑点的差值、订单链路耗时、以及实盘收益与预期收益的偏离。当偏差累计超过阈值系统自动把该策略从 prod 移到paused/under_review分支。这就是闭环过去的“教训”改变未来的“行为”而不是把错误一遍遍地重复。3.2 前置风控交易意图必须拿到 PermitToken前置风控是四道闸门里最重要的一道它发生在资金真正离手之前。OpenAlice 的风控规则集中在一个risk.yaml文件里每次修改都要通过一次 Git commit不接受运行时热改。给大家看一份我实际在用的配置risk: max_leverage: 2.0 # 总杠杆上限 max_notional_per_position: 0.3 # 单仓位名义价值占净值比例 risk_per_trade: 0.01 # 单笔风险占净值比例 daily_loss_limit: 0.03 # 日亏损 3% 触发熔断 max_drawdown_kill: 0.08 # 连续回撤 8% 强制空仓 cooldown_minutes: 120 # 熔断后冷却 2 小时 blacklist: [] # 禁止交易标的仓位计算我采用的是最常见的“固定风险预算”法。公式是数量 账户净值 × risk_per_trade / |entry - stop|假设净值 10 万单笔风险 1%入场价 100、止损价 95那么这笔交易最多亏 1000 元每股风险是 5 元数量就是 200 股。然后还要过名义价值限额200 × 100 2 万小于 3 万的限额通过。如果算出来超出名义限额就取名义限额对应的最大数量。这套计算不复杂但它逼着你在下单之前就把“最多亏多少”定死而不是等浮亏变大之后再慌。3.3 盘中熔断独立进程的撤单与冻结盘中监控不能依赖策略进程——策略可能因为 bug 崩溃也可能因为行情冲击而卡死。OpenAlice 把盘中熔断做成一个独立 daemon监听每笔成交和实时仓位计算当日盈亏。触发熔断条件后它只做一件事调用交易所的批量撤单接口同时向所有 Agent 广播“风控冻结”事件。策略 Agent 收到后停止产生新意图已经挂着的单子全部撤掉。这个熔断 daemon 连 LLM 都不跑代码量非常小只保留必要的交易所客户端、事件总线和状态机。极端行情里它必须活下来所以依赖越少越好。我的建议是把它当成“家里总闸”来设计不要跟其他 Agent 共用进程也不要共用一套配置加载逻辑。注意熔断进程的 API 密钥应该和交易密钥相互独立只授予撤单和 ping 权限。这样即使策略侧密钥泄露熔断进程依然能作为最后一道物理闸门继续工作。3.4 事后归因谁该被暂停谁可以继续每天日终账本 Agent 会生成一份“风险账单”包括当天实际成交的滑点与回测假设滑点的差值、下单链路耗时、每个策略的实盘收益与预期收益的偏离。OpenAlice 会自动计算一个经验法则如果某个策略连续 N 天的实际收益低于预期收益 2 个标准差系统就把该策略移入paused/under_review分支并发通知。这里的一个细节是自动暂停不代表所有策略全被下架。暂停一个策略是成本暂停所有策略是恐慌。系统需要区分“个别策略失效”和“整体市场环境恶化”。所以 OpenAlice 同时维护一个全局状态只有全局回撤超过阈值时才触发全市场空仓否则只是暂停问题策略。这样既保护了资金又保留了其他策略继续盈利的机会。4. 本地部署实操与踩坑实录4.1 最小可运行的目录结构与启动顺序如果你想动手复现这套架构我建议从最小结构开始不要上来就搞 Kubernetes。目录长这样就够了alice/ # git 仓库根目录 strategies/ # 策略代码与参数文件 agents/ # 五个 Agent 的入口 risk/ # 风控规则与熔断进程 data/ # 本地行情缓存 storage/ # sqlite 账本 runbook/ # 运维脚本启动顺序有讲究先启动账本 Agent再启动风控 Agent然后才是情报 Agent、策略 Agent、执行 Agent。这个顺序的核心是让后面所有 Agent 从一开始就处于被记录、被约束的状态。如果策略 Agent 先启动它在风控 Agent 还没就绪的窗口期产生了信号就会因为没有 PermitToken 而被挡在执行环节之外——这正说明了 Token 机制的价值。技术上Python 3.11 加上 Redis、SQLite、Git 2.35 就够了。Agent 之间用 Redis Streams 通信账本 Agent 持久化到 SQLite熔断 daemon 可以独立成一个 systemd service。4.2 实盘校准回测小仓位跑通再放大很多人实盘上来就复制回测参数这几乎等于裸奔。正确做法是在 paper 分支上缩小仓位跑 2 到 4 周期间只核对一件事实际成交质量和回测假设是否在同一量级。比如回测假设滑点 0.1%实盘第一次统计出来是 0.6%那你该做的不是叹息市场难做而是把回测引擎的滑点参数改成 0.6% 后重新回测。这种“用实盘校准回测”的循环才是 Trading-as-Git 里最值钱的部分。校准不是一次性动作而是每次实盘数据积累到一定量后都要做。我习惯每两周跑一次校准脚本将最新实盘成交记录与回测模拟在同一时点的执行结果做对比把偏差滚入下一版参数。这样策略不是越来越偏离现实而是越来越贴近现实。4.3 常见问题速查表现象最常见根因处理动作订单长时间没有成交回报交易所接口限流或权限不足停止下单检查 API 权限与限流状态周末/节假日的假信号情报 Agent 读到过期日历缓存在事件包里加 valid_from/valid_to 时间窗一次成交后滑点远大于回测走市价单且流动性不足改为限价单加超时撤单机制熔断触发却频繁被策略重启熔断信号没有持久化用 Redis 的持久化 key策略启动时先检查策略参数被意外修改有人热改配置文件改为强制读取 Git checkout 参数Agent 进程崩溃后没恢复缺少看门狗与状态快照给关键 Agent 加 systemd 自动重启与心跳这几条都是我实际踩过或者帮朋友排查过的。尤其是“熔断触发却频繁被策略重启”这条特别阴险熔断 daemon 向事件总线发了冻结信号但策略 Agent 因为某种原因重启了重启后没有读取 Redis 里的持久化冻结状态又开始交易。修复方式很简单就是让所有 Agent 启动时的第一件事是检查风控状态 key而不是直接开始干活。4.4 防“自己人拆风控”规则 hash 与密钥隔离风控规则最容易在自己人手里失效。比如某天你心情不好觉得“今天情况特殊把日亏损限额改到 5% 吧”——这种操作必须被系统拦住。OpenAlice 的约束是修改 risk 配置必须走一次新的 Git commit且需要管理人签名。运行中的风控 Agent 每小时把自己的规则 hash 写入账本一旦发现与 Git 仓库 HEAD 不一致就拒绝签发新的 PermitToken直到规则重新对齐。密钥管理同样不能放松。API 密钥永远不写进仓库执行 Agent 的密钥从环境变量加载熔断 daemon 的极简密钥和交易密钥物理隔离放在不同的配置目录。另外我强烈建议给交易所 API 设置 IP 白名单只允许本地机器的出口 IP 访问就算密钥泄露出去了攻击者也用不了。最后的干货一次差点爆仓的教训项目做到第四个月的时候我踩过一次最深的坑现在回想起来后背还是发凉。某天凌晨券商那边的接口字段语义突然变了本该被当作“限价止损单”处理的指令被交易所端理解为“市价单”直接以当时的最差价格成交净值瞬间掉了 6%。那一刻系统里所有常规风控都在正常工作限额没超、熔断没触发、Token 也签发了但没有任何一层检查“接口字段语义”和“实际订单类型”是否匹配。后来 OpenAlice 加了一条硬规则执行 Agent 在每次下单前必须核对交易所返回的订单类型字段是否与意图一致不一致就拒发订单并告警。这逻辑不复杂但它在关键时刻比十个 AI 总结都有用。我的体会是量化系统的风险往往不是来自策略不够聪明而是来自基础层某个没人注意的假定悄悄失效。Trading-as-Git 帮我把“版本可追溯”做扎实了但真正让人睡好觉的还是那些尽量少依赖外部变化的确定性校验规则。
返回列表