如果你也曾在实盘账户里尝到过“手痒”和“不服输”的滋味,那你看到 OpenAlice 这个名字时应该会跟我一样好奇。OpenAlice 是一个把 Trading-as-Git 作为设计哲学的开源本地量化 Agent 框架:所有策略、参数、风控规则都放进 Git 仓库里管理,Agent 在本地负责读取行情、生成信号、执行交易,而每一次改参数、每一次上线、每一次回滚都像提交代码一样有迹可循。这套思路真正解决的,不是“预测得更准”,而是“亏得有原因、亏得有底线、亏完还能复盘到具体某一笔”。这篇文章适合在实盘里吃过亏的交易者、想搭量化框架的开发工程师,也适合正在研究本地 Agent 架构、想搞清楚风控闭环该落在哪个环节的产品和技术同学。
1. 为什么是 Trading-as-Git:把交易系统当成代码库治理
1.1 盲目实盘暴仓的三个典型病灶
我观察过不少从主观交易转向量化的人,最先被淘汰的往往不是策略不行,而是交易行为不可控。第一个病灶是“没有证据”。下单的时候凭盘感,等亏损了再回看 K 线,怎么都记不起当时触发信号的依据是什么。第二个病灶是“没有熔断”。浮亏 2% 时不走,3% 时想扛一扛,5% 时已经不敢停,最后账户被一次极端行情带走。第三个病灶是“没有回滚”。程序改了某个参数后连亏三笔,想回到原来的行为,却只记得大概改过哪个变量,完全无法复现。
这三个问题放到软件开发里,就是典型的“没有版本管理、没有自动化测试、没有部署回滚”。Git 早就把代码工程这条路走通了,那交易系统为什么不能用同一套方法?Trading-as-Git 的核心就是把策略代码、参数配置、风控规则、甚至数据版本都当成仓库里的资产,让每一次行为变更都有 commit、有 diff、有 tag。你不需要赌“这次一定对”,只需要保证“错了能定位、能还原”。
1.2 Trading-as-Git 到底在说哪件事
Trading-as-Git 不是一个具体软件,而是 OpenAlice 架构的第一性原则。它把软件工程里已经成熟的 Git 工作流,映射到量化交易的每个环节:
- 策略因子,对应代码仓库里的
factors/目录,每个因子有独立测试; - 策略参数和风控阈值,对应
configs/risk.yaml,必须有提交记录; - 某一版本的策略上线,对应打 tag,比如
v0.3.0-live; - 想试新思路,对应开分支
experiment/xxx,先跑回测再决定要不要合并; - 上线后发现数据源有问题,对应
git revert,把交易行为退回到上一个稳定版本。
这个比喻听起来很简单,但它改变了 Agent 的工作方式。传统的量化 Agent 是“策略装在脑子里,执行靠手脚”;Trading-as-Git 的 Agent 是“策略存在仓库里,执行靠一个严格遵循仓库当前状态的进程”。Agent 不拥有决策权,它只执行仓库里已经被验证过的规则。想让 Agent 改变行为,第一步不是去改代码,而是先提交一个 commit,再走验证流程。这种做法天然地把“冲动交易”挡在了系统外面。
1.3 本地量化 Agent:为什么不在云端跑
可能有人会问,既然要自动化,为什么 OpenAlice 坚持本地部署,而不是放到云端服务器上跑?我拆完这个项目后,觉得有三点是刻意设计的。
第一是延迟。本地部署可以让行情数据的接收、信号计算、订单发送都在一个低延迟网络环境内完成,避免由于公网波动导致“信号出来了,指令却迟到”的后果。第二是隐私与安全。交易所 API key、持仓数据、策略细节都只留在本机,不经过任何第三方中转。第三是可干预性。本地 Agent 可以直接被停止,可以一键断网,可以手动撤单,这对还在实盘初期、需要时刻保留人工干预能力的人非常重要。
当然,本地量化不是没有缺点,机器宕机、断电、网络中断都需要额外预案。这个我会在后面的实操部分展开讲。整体上,OpenAlice 选择本地作为默认运行环境,更多是为了“风控闭环不依赖外部资源”这个原则。
2. OpenAlice 的本地量化 Agent 架构拆解
2.1 数据接入层:先有可靠数据,才有可信策略
量化系统里最容易被忽略的就是数据层。OpenAlice 把数据接入当作独立模块,而不是策略脚本里的一个函数。它由定时任务从行情源拉取历史 K 线、实时 tick、成交明细和部分财务数据,经过清洗后统一落成 parquet 或 SQLite 格式,并打上data_version。每个策略 commit 会记录它依赖的数据版本,回测时用相同的数据版本,避免“同一个策略,两次回测结果不一致”。
这一层能做到什么程度?我见过不少人在本地搭环境时,直接把交易所 API 下载的数据随便存成 CSV,时间戳混着时区,除权没有处理,导致信号在回测中看起来很漂亮,实盘却一塌糊涂。OpenAlice 的做法是用统一的 UTC 毫秒时间戳、统一的字段命名,数据写入前做重复值和缺失值检查,并生成数据完整性校验和。这个设计对新手可能觉得“过度工程”,但当你要回放某个异常行情日、复盘那几分钟到底发生了什么时,版本化数据是唯一能依靠的现场。
2.2 策略仓库:Agent 的行为快照
OpenAlice 的默认仓库结构并不复杂,但每层都有明确边界。我整理过这样一个最小目录:
strategies/ factors/ # 因子定义 entry_models/ # 入场模型 exit_models/ # 出场模型 configs/ strategy.yaml # 策略参数 risk.yaml # 风控参数 execution.yaml # 下单参数 data/ snapshot/ # 不可变数据快照 logs/ trades/ # 交易日志 tests/ backtest/ # 回测用例其中最关键的是,configs/risk.yaml不属于策略工程师个人所有,它在 Git 仓库里需要单独的权限保护。因为 OpenAlice 的风控闭环有一个前提:决策 Agent 不能自己修改限制自己的规则。如果同一个进程既能改策略又能改风控,那风控就只是摆设。策略仓库通过分支权限、commit 签名、合并审核等方式,让风控参数的变更像生产环境配置一样被严格管理。
2.3 Agent 执行引擎:信号如何变成订单
OpenAlice 的执行引擎是一个事件循环:接收到新的行情事件,把它交给策略模块计算信号,信号进入风控模块校验,校验通过后再交给执行模块发送订单。这里的 Agent 与“harness”有一个容易混淆的点:harness 通常只是调度的壳,负责拉起进程、喂数据、收集结果,而 Agent 是能根据状态做出决策的单元。OpenAlice 里,Agent 的“智能”完全来自仓库中的策略版本,不为某一个模型加戏;真正干活的是风控模块的硬约束。
执行引擎还有一个容易被忽略的细节:订单幂等。每次生成订单时,Agent 会为订单生成一个全局唯一的client_order_id,并在本地数据库中记录。如果网络超时,Agent 不会盲目重发同一笔订单,而是先查询这个订单的状态,再决定是否重发。这个设计避免了最常见的“网卡一下,重复下单”事故。多个策略同时运行时,执行引擎还会用一个共享仓位管理器汇总总仓位,避免 A 策略开了 2 个 BTC、B 策略又开 2 个 BTC,最终超出账户总仓位上限。
2.4 本地 Agent 的运行沙箱与进程隔离
Agent 跑在本地,不意味着它可以为所欲为。OpenAlice 会为策略代码提供受限运行环境:文件系统只读、网络访问只允许白名单域名、进程资源占用有限。策略脚本里哪怕有人故意写一个死循环,也不会拖垮整个交易系统。这种“沙箱”思想在 Agent 安全的话题里经常被讨论,但真正落实到本地量化 Agent 的项目其实不多。
风控模块则单独跑在一个独立进程中,通过本地 IPC 或消息队列接收交易请求和账户状态。这样即便策略进程崩溃,风控进程仍然可以继续监控账户,并在触发熔断条件时直接发送止损指令。这就是为什么说 OpenAlice 的风控闭环不是功能插件,而是独立于 Agent 的守护层。
3. 风控闭环:四道闸门把暴仓挡在门外
3.1 第一道闸门:交易前检查
任何订单在发出前,都要先过一遍 pre-trade risk。OpenAlice 的configs/risk.yaml里会有类似这样的配置:
risk: max_position_size: 0.2 # 单币资金占比上限 max_open_positions: 5 # 最大同时持仓数 risk_per_trade: 0.01 # 单笔最大风险 1% max_leverage: 3 # 最大杠杆 forbidden_symbols: [] min_liquidity_threshold: 5000 # 5s 深度阈值这里有个需要理解的计算:单笔最大风险 1% 并不是说这笔交易最多亏损本金的 1%,而是用止损距离反推仓位。假设账户本金 10 万 USDT,风险预算 1000 USDT,策略在 100000 的价格买入,止损设在 99000,止损距离 1000 USDT。那么可开仓数量就是1000 / 1000 = 1,也就是 1 个 BTC。如果止损距离是 200 USDT,则可以买 5 个。这种仓位计算方式,比“感觉仓位轻一点”可靠得多,因为它把亏损固定住了。
如果订单不能通过这些检查,Agent 会记录拒绝原因并发送告警,而不是直接强行下单。我见过很多系统把 pre-trade 做成 “if 风控 not passed then pass anyway” 的摆设,OpenAlice 的做法是风控拒绝的订单永远无法到达交易所,这是物理层面的约束。
3.2 第二道闸门:实时监控和动态熔断
pre-trade 再严格,也无法覆盖市场瞬间反转。OpenAlice 的实时监控服务会以固定频率读取账户权益、持仓、浮盈浮亏,并计算两类关键指标:日内回撤和整体回撤。日内回撤指今天从最高权益到当前权益的跌幅;整体回撤指从历史最高权益到当前权益的跌幅。
熔断规则可以设置成阶梯式:
| 回撤触发线 | 动作 |
|---|---|
| 日内回撤 3% | 告警,禁止新开仓 |
| 日内回撤 5% | 自动减掉一半仓位 |
| 日内回撤 8% | 全部平仓,关闭当天交易 |
| 整体回撤 12% | 锁定所有策略,等待人工复核 |
为什么用动态回撤而不是固定盈利回撤?因为账户权益会随市场波动,如果固定“亏损 5% 就停”,在权益已经创新高之后很容易被正常的波动扫出局。动态回撤永远锚定“当前周期的最高点”,能更准确反映账户真实的回撤风险。这个模块是独立进程,即使策略进程因 bug 卡死,熔断逻辑依然可以生效。
3.3 第三道闸门:事后审计与 Git 回滚
交易发生之后,OpenAlice 会把每一笔订单、每一次信号、每一次风控拒绝都写进结构化的审计日志。日志字段大约包括:策略 commit hash、参数版本、数据版本、信号详情、下单时间、成交价格、滑点、延迟等。这意味着复盘一个亏损日时,你可以像读代码历史一样,把当天的所有决策链还原出来。
如果发现某次异常亏损源于一个糟糕的参数改动,或者一个错误的数据版本,就可以直接回滚。回滚有两种用法:一种是git revert <commit>把代码状态退回去,另一种是用git checkout <tag>临时切到验证过的稳定版本。关键是,logs/trades里记录的 commit hash 能让你知道“当前跑的是哪一版代码”,而不是靠记忆猜。
3.4 第四道闸门:人工干预通道与紧急回调
再完善的风控闭环,都要给“人”留一个最高优先级入口。OpenAlice 默认设计了一键暂停、一键清仓、一键恢复三个命令。暂停是停止开新仓,已持仓继续按策略管理;清仓是把所有仓位按市价单平掉;恢复是重新载入当前仓库版本继续执行。这三个命令都会记录到审计日志,并且需要二次确认。
还有一个容易被忽略的细节:当策略进程和风控进程同时发现冲突时,以风控进程的指令为准。比如策略认为应该继续加仓,但风控发现整体回撤已经超过阈值,那么风控进程会直接平仓,并记录一条 reason。人工干预通道就是为了解决“机器完全自动时,谁来按最后那个急停按钮”的问题。
4. 实操:从零把一个策略接进 OpenAlice
4.1 环境准备与安装
先说运行环境。OpenAlice 的核心执行引擎当前默认支持 Python 3.10+,同时我会建议把 Rust 工具链装上,因为部分数据解析和事件循环模块是用 Rust 编译的,没有工具链也可以从预编译 wheel 安装。安装本身不复杂:
git clone <openalice_repo_url> cd openalice python -m venv .venv source .venv/bin/activate pip install -r requirements.txt python openalice init --name risklab初始化命令会创建一个包含上面目录结构的 Git 仓库,并生成默认配置文件。接下来就按照“先建仓库,再给系统录入交易所凭据”的顺序。交易所 API key 我建议只放在本地.env文件里,并且设置读取权限为当前用户可读写;千万不要提交到 Git,否则一旦仓库泄露,等于把风控大门钥匙交出去了。
4.2 把你的第一版策略写成配置
OpenAlice 的策略不一定要写一大段 Python 代码,它允许先用声明式 YAML 定义策略,让新手也能跑通。一个最简单的双均线交叉策略可以是这样:
strategy: name: ma_cross timeframe: 1h entry: rule: crossover fast_window: 10 slow_window: 30 exit: rule: crossunder risk: stop_loss_atr_multiplier: 2.0 take_profit_atr_multiplier: 3.0把文件放到configs/strategy.yaml,然后执行git add . && git commit -m "feat: add ma_cross v1"。这一步的作用不是“存档”,而是让策略的状态第一次成为可回滚的快照。之后每一次改动都遵循同样的流程:开分支、改配置、跑回测、合并、打 tag。
4.3 用 Git 工作流管理策略迭代
我强烈建议新手从一上手就养成“实验分支”的习惯。想试一个新参数组合,不是直接改main分支的配置,而是:
git checkout -b experiment/ma_cross_trail # 修改 configs/strategy.yaml git commit -m "experiment: use trailing stop" openalice backtest --branch experiment/ma_cross_trail回测通过后,再回到main合并,并打上下一个版本的 tag。这里有个反直觉的地方:打 tag 不是只在“上线赚钱”时做,而是在“准备接受实盘验证”时做。比如v0.1.0-live可能是一个亏损版本,但它仍然是一个里程碑,因为它记录了“这一次尝试的全部状态”。亏损版本同样值得保存,否则你无法在事后准确回答“当时为什么亏这么多”。
4.4 回测、模拟盘、实盘的三段式验证
OpenAlice 把验证过程拆成三段,每一段必须通过上一段的检查:
- 回测:用历史数据验证策略,输出收益率、最大回撤、夏普比率和交易频次;
- 模拟盘:接入交易所的 testnet 或 paper trading,用小金额或模拟资金跑 2~4 周,确认订单执行、风控触发路径都正常;
- 实盘小资金:只有在模拟盘没有出现风控漏触发的情况下,才开始用很小比例的本金实盘,并开启所有熔断规则。
这个过程真的会过滤掉大量“看起来很好、跑起来就废”的策略。我有一次把一个回测年化很好的策略丢进模拟盘,结果因为本地环境时区问题,每天第一根 K 线的入场信号都晚了几秒,模拟盘里连续一周都是微小亏损。要不是有模拟盘这一段,实盘账户早就替我交了学费。
5. 常见问题与避坑手册
5.1 时间戳时区不一致,导致信号错位
本地量化最常见也最坑的问题,就是行情数据里同时存在 UTC 和本地时间。比如数据库里用本地时区,但交易所返回的时间戳是 UTC,两个时间不校准,策略会在错误的 K 线上计算信号,回测结果和实盘行为完全对不上。解决办法只有一个:系统内部统一用 UTC 毫秒时间戳,所有展示层再转换成本地时间。数据写入前加检查,发现时间偏移不一致就拒绝入库,而不是静默容忍。
5.2 回测不考虑手续费和滑点,实盘必然变脸
回测里手续费设成零、滑点设成零,这属于给自己制造惊喜。OpenAlice 的默认回测配置里会按交易对参数注入一个保守成本模型,比如单边手续费 0.05%,滑点按最近 1 分钟平均买卖价差的 50% 估算。如果你的策略是高频小赚、每天几十笔,手续费和滑点加在一起会直接吃掉利润。我用一个简单的算法验证:假设每天交易 20 次,每次单边成本 0.05%,一天来回就是 2% 的成本,一个月 22 个交易日就是 44%,任何毛利低于这个成本线的策略都活不下去。所以,只看毛利就上实盘的时代可以结束了。
5.3 Agent 重复下单与订单幂等
网络超时是最难排查的故障之一。请求发出后交易所可能已经成交,但客户端没收到回执。如果不做幂等,Agent 会再发一个相同的订单,结果造成双倍仓位。OpenAlice 的解决办法是每笔订单生成唯一的client_order_id,并在本地数据库中记录状态。发送前先查本地状态,如果已经存在且状态不明,就向交易所查询后再决定下一步。这是一个非常小却保命的细节。
5.4 风控规则被策略绕过
如果风控模块和策略模块位于同一个进程、同一个权限空间,那么策略代码完全可以在某个分支里把风控阈值改掉。这不是恶意,可能是工程师为了方便调试留下的后门。OpenAlice 把风控模块独立成另一个进程,并且配置文件对策略进程只读。策略进程无法动态修改风控参数,只能通过仓库的变更审核流程来调整。这就是我前面说的“做题的人不能自己改评分标准”。
5.5 手动干预之后,Agent 状态没有同步
有些用户看到账户浮盈很高,忍不住手动平了一部分仓,但 Agent 内部的持仓状态还是旧的,结果下一次风控检查算出来的仓位比例、回撤数字全部失真,甚至触发错误操作。正确的做法是:任何人工干预之后,先执行一次openalice sync --from-exchange,让 Agent 从交易所重新拉取最新持仓和权益,再继续自动运行。别跳过这一步,否则系统会基于错误状态做决策。
5.6 数据源故障时,Agent 必须进入降级模式
本地量化不是只要机器在跑就万事大吉,行情源可能断流、交易所 API 可能超时。OpenAlice 的做法是在 Agent 中加入“降级模式”感知:如果连续 N 个心跳周期没有收到行情,就停止开新仓,已持仓保持不动;如果行情恢复,再重新评估持仓和风控状态。最忌讳的是数据断了,策略还按最后一块数据强行出信号,那基本等于蒙眼下单。
注意:第一次实盘前,一定确认
configs/risk.yaml里的熔断阈值是你自己在冷静状态下写下来的,而不是盘中临时调的。盘中调风控,等于给暴仓开门。
我这里最后再多说一句:把 Trading-as-Git 当成口号很容易,真正难的是接受“Agent 只是仓库状态的执行者”这个设定。我在本地跑 OpenAlice 大半年,最大的体会不是它帮我多赚了多少,而是它让我每一笔亏损都能被解释、被回放、被避免。朋友来找我看策略,我第一句话永远是:先给我看你的 Git 提交历史,再谈你的收益曲线。能做到这一点的系统,即便不完美,至少不会在暴仓时让你连自己是怎么亏的都不知道。