1. 先想清楚:你到底是来赚钱的,还是来赌手气的
我见过太多人做量化,路径几乎一模一样:看到一个策略源码,回测拉满年化80%,兴奋得睡不着,直接丢进实盘,前两周赚得得意忘形,第三周一根阴线打穿止损,心态崩了,反手加仓想回本,然后账户就剩个零头。
这种故事听多了之后,你会明白一件事——多数人暴仓,不是因为策略不好,而是因为压根没有把“交易”当成一个工程问题来对待。
OpenAlice 这个名字,代表的是一整套思路:把交易策略当成代码工程项目去管理,用 Git 的语义去管理策略版本、回测结果、实盘镜像和风控规则。这就是所谓的 Trading-as-Git。再叠加一个本地运行的量化 Agent 负责数据采集、策略调度、信号生成和异常监控,最后用一套硬性风控闭环把“人脑发热”这个不可控因素挡在系统之外。
这篇文章适合谁?已经会写一点 Python 策略、但苦于回测能赚钱一实盘就翻车的个人量化者;也适合想从“手动改参数碰运气”升级为“本地自动化 Agent 流水线”的团队。我会把架构拆开,把风控闭环的每一道闸门怎么设、参数怎么算、坑在哪里都讲透。
先说结论:你缺的不是一个更聪明的策略,而是一套不给愚蠢留余地的系统。
2. 盲目实盘为什么注定暴仓:三个致命伤逐个拆
2.1 回测失真:你看到的利润根本不存在
这个问题和策略本身无关,和你怎么回测有关。
最常见的回测失真,第一是未来函数。比如你在某个 K 线收盘的瞬间用了当天收盘后才会公布的成交明细去更新信号,或者用了整个区间的数据去算归一化参数,回测当然漂亮,实盘当然翻车。第二是偷价。用下一根 K 线的最高价做止损触发判定,回测里的止损点永远精准得可怕,实盘里滑点和延迟会直接吞掉你的利润。第三是过拟合。你把参数调到刚好适配某一段历史行情,亏的时候安慰自己“市场风格变了”,实际上是你把随机噪声当成了规律。
OpenAlice 在做的事情,就是把回测结果跟策略代码的每一个版本进行强绑定。你每一次修改策略,哪怕只是把均线从 20 改成 21,都会留下一个不可篡改的版本记录,并对应生成一份新的回测报告。系统会告诉你,这个版本比上一个版本到底提升了什么、牺牲了什么、在哪个市场阶段表现变差了。这种“可追溯性”很朴素,但绝大多数人没有。
你可以试试一个方法:把最近两年的行情切成三段,一段用来调参,一段用来验证,一段留作“考卷”。调参时只在第一段上做优化,第二段只做一次性验证,第三段交给系统全自动跑——如果第三段的表现和第一段差得很远,说明你的策略稳定性有问题,而不是行情有问题。
2.2 仓位失控:赔率很好,但你下注的重量不对
就算策略本身是正的数学期望,仓位控制错了,照样能暴仓。
举个例子,假设你有 10 万本金,连续五次亏损,每次亏 10%,账户还剩 59049 元。要回到 10 万,需要涨 69.4%。注意,回本所需的涨幅不是 50%,而是近 70%。这就是亏损的不对称性——亏得越深,回来越难。
很多人想用凯利公式来解决仓位问题。凯利公式 f = (bp - q) / b 确实告诉你最优下注比例,但它有个前提:你的胜率和赔率都是精确估计的。实际问题在于,多数个人量化者的胜率估计误差大得惊人,而且遇到极端行情时,实际赔率会远低于回测赔率。直接用全凯利下注,等于在误差边缘反复横跳。
更稳妥的方式是半分凯利甚至四分之一凯利,同时叠加单笔风险限额。我建议的单笔风险控制是:单笔头寸的风险金额不超过账户净值的 1%。比如 10 万账户,单笔止损距离是 2%,那么这笔交易的仓位应该控制在 5 万市值以内,因为 5 万 × 2% = 1000 元 = 账户的 1%。
OpenAlice 的风控闭环里,这类计算会被硬编码成规则,实盘下单前自动校验,仓位超限的单子根本不会发出去。这不是“建议”,是系统的强制逻辑。
2.3 策略漂移与情绪化改参:你的策略早就不认识自己了
第三种暴仓方式最隐蔽,也最常见——策略漂移。
你今天觉得均线参数 20 好,明天看盘觉得 30 更稳,后天亏了钱觉得还是 10 更敏感。来回调参两周之后,你的“策略”已经变成了一个你自己都说不清楚的混合体。回测报告是过期的,参数逻辑是混乱的,你甚至忘了自己在哪个版本加了哪些条件。
这就是代码版本管理要解决的问题。用 Git 来管理策略的好处是:每一次修改都有记录,每一次实盘部署都必须基于一个明确的标签(tag),任何未经验证的新改动,都没有资格进入实盘环境。
我曾经见过一个团队,交易脚本放在共享文件夹里,文件名叫“final_v2_真的最终版_再改是狗.py”。这不是段子,是真的。而这个文件里其实有 27 处分散到不同函数里的魔法数字,没人说得清每一个数字为什么存在。后来我把这套东西迁到 Git 仓库,配合策略卡管理,所有参数集中到配置中心,魔法数字全部消除,模型性能、回撤、换手率、胜率全部落到策略卡的指标区里。从此再也没有人需要靠猜去理解一个策略。
3. Trading-as-Git:把策略版本化做成一件理所当然的事
3.1 把“策略镜像”当作不可变部署单元
我们需要先理解一个工程概念:不可变部署。传统 Git 仓库管理代码,只有分支和提交。但交易策略有一个特殊需求——实盘运行中的策略必须是一个不可变的镜像,不能热改参数,不能动态换逻辑。
OpenAlice 的做法是:每次策略改进都通过 Git 提交产生一个新版本,回测验证通过后,系统会基于这个提交构建一个只读的策略镜像。这个镜像包含完整的策略代码、依赖声明、配置文件、回测结果摘要和风险评级。实盘环境只能从镜像启动,盘中你无法修改镜像内部任何参数。想改?可以,先回测,再构建新镜像,然后切换。
这个过程,和你在 AWS 上对一个 Docker 镜像做滚动更新是一个思路。你永远不会在容器内部临时改代码,你只会构建一个新镜像再重新部署。交易也一样。盘中手痒想改止损线?那是系统禁止的操作,你需要回到 Git 工作流里走完整流程。
这里有个很实用的设计:每个策略镜像应该记录自己的“血缘关系”——我是从哪个父镜像改过来的,改了什么,回测结果产生了哪些变化。这样当你发现某个镜像在实盘里表现异常时,可以快速对比它和上一个镜像的差异,是参数变动导致的恶化,还是行情风格不匹配,一目了然。
3.2 每次提交都是一次可重复的回测
Git 提交信息通常会写“fix bug”或“update param”,但这种信息对交易复盘几乎没有价值。建议你强制约定提交信息的格式,把交易语义嵌进去。
我常用的提交格式:
[param] MA窗口: 20 -> 40 [logic] 新增突破确认条件: 收盘价超过20日高点后才开仓 [risk] 单笔风险: 1% -> 0.75%结合 Git Hook(尤其是 pre-commit),可以做到提交时自动拒绝不合格的提交,比如没有任何回测结果文件,或者回测最大回撤超过设定的安全阈值,直接不让提交通过。把质量标准前置到写代码的那一刻,而不是等策略上线了才发现问题。
另外,每次提交后自动触发回测任务,并把回测报告生成成 PDF 或者 HTML,归档到独立的 reports 目录。回测报告里必须包含三个指标:年化收益、最大回撤、收益回撤比。这三个指标比单纯看年化收益可靠得多。最大回撤决定你晚上睡不睡得着,收益回撤比决定你值不值得拿真金白银去赌。
3.3 分支策略模拟“策略竞选”
我在实际使用中建立了一套分支管理习惯:
- main 分支:随时可以部署到实盘的稳定策略。
- backtest/xxx 分支:新点子、新尝试,跑完回测,数据说话。
- research/xxx 分支:纯粹好奇的探索性研究,允许失败。
候选策略在 backtest 分支跑出足够好的成绩后,合并到 main,构建新镜像,进入实盘观察池。观察池里同时跑它的旧版本和新版本,用小资金并行运行一段时间,看真实行情下的表现和回测差异有多大。这种做法叫“影子部署”或“并行运行”,在量化里非常有效,因为回测再精确也模拟不了真实的滑点、延迟和市场心理。
合并到 main 不是免费午餐,必须过三道门:回测报告通过了,参数敏感性分析通过(意思是主流参数附近的表现没有剧烈抖动),以及策略卡信息补全了。这道流程看起来繁琐,但真正的价值在于它把“上线一个新策略”变成了一件有仪式感、有门槛、有记录的事。
4. 本地量化 Agent 架构:你自己不上夜班,让 Agent 替你值班
4.1 数据采集与存储:本地优先,不依赖任何云服务
Agent 的第一个职责,是把数据管起来。
我个人偏好本地优先的架构:数据存 SQLite 或 Parquet 文件,采集任务用定时调度器驱动。为什么不全用云?因为本地数据是你的私有资产,不依赖第三方服务稳定性,也不存在数据外泄问题。尤其涉及真实交易账户数据时,本地存储是底线。
以国内 A 股日线加分钟线为例,全部股票三年数据,用 Parquet 列式存储,磁盘占用也就几个 GB,一台普通 PC 完全扛得住。关键是数据要有统一的 schema,每张表都带上更新时间戳,任何数据源异常都能快速定位是哪一天的数据出了问题。
4.2 策略调度与执行:Harness 负责流程,Agent 负责决策
聊到 Agent 架构,很多人分不清 Harness 和 Agent 的区别。我给出一个简单的定义:Harness 是固定的执行脚手架,它定义了任务流程的骨架,但没有任何决策能力;Agent 是在 Harness 之上运行的智能体,它读取市场状态、策略信号和风控规则,做出“现在要不要开仓、开多少、什么时候平仓”的决策。
Harness 通常负责:定时扫描行情,唤醒策略,计算信号,执行止损止损单,生成日志。Agent 负责:根据多个策略信号的综合得分给出交易建议,分析当前账户风险敞口是否超限,甚至在大盘指数出现罕见波动时暂停所有策略。一层管流程,一层管判断,两者解耦,各自职责清晰。
具体实现上,我常用的配置是一个调度器(比如 APScheduler 或系统 crontab),按策略各自的时间周期触发任务,任务内先拉取最新行情,然后跑策略信号,再到风控引擎做最终的指令核验。核验通过的才允许进入交易执行层。
4.3 信号看板:让 Agent 把话“说”给你听
本地量化 Agent 不能只是一个黑盒子,它必须有一个能看懂的人机界面。参考一个我做过的小型移动仪表盘项目,核心看板字段可以拆成这样:
| 模块 | 展示内容 | 用途 |
|---|---|---|
| 主力资金 | 当日净流入、五日累计、大单占比 | 判断资金方向是否与信号共振 |
| 多空博弈 | 主动买盘/卖盘比例、委比变化 | 实时衡量买卖力量强弱 |
| 筹码分布 | 获利盘比例、套牢盘集中区、筹码集中度 | 判断当前价格位置的抛压大小 |
| 龙虎榜/北向 | 龙虎榜净买入、北向资金流向 | 观察聪明钱的去向 |
| 异动监控 | 大单异动、超大单流入、对倒出货特征 | 提前察觉异常资金行为 |
这些字段放到一个轮询刷新的 JSON 接口里,几秒更新一次,手机上随时看一眼,心里就有数。但重点是:看板只是辅助你理解 Agent 的决策逻辑,真正执行下单的永远是风控过的程序,而不是你的临时判断。
4.4 本地大模型的辅助与数据安全边界
最近很多人开始尝试本地部署量化模型来辅助复盘,比如让本地大模型读持仓记录、读行情新闻摘要,生成当日的复盘报告。这个方向很有意思,只要坚持本地部署,就能避免把账户数据放到第三方接口里,安全性高得多。
我实测过用本地量化版模型处理交易日志的效果:给它一段当天的买卖记录和行情走势摘要,它能生成“今天的亏损来源于开盘阶段追高,建议下一交易日观察 10:30 前的量能再决定是否进场”这类有实际参考价值的复盘建议。这跟你刷到的大 V 观点完全不同,因为它是基于你自己的交易数据生成的,逻辑可追溯。
不过要提醒一下,本地部署模型时要注意显存和量化位数的选择。一个 7B 级别的模型用 INT4 量化部署在消费级显卡上,生成质量已经足够处理复盘任务,完全没必要追求太大参数量的模型。
5. 风控闭环:从“事后悔恨”到“事前阻止”
5.1 事前风控:开仓之前,先过三道闸门
风控闭环的第一层,是开仓前的校验。这部分写在代码里是硬逻辑,顺序不能乱:
第一道闸门:账户风险敞口检查。当前总仓位 + 准备开的新仓位,合计占用保证金比例是否超高?如果总敞口超过设定的安全阈值(比如 60%),无论策略信号多强烈,直接拒绝开仓。
第二道闸门:单笔风险金额检查。用我前面说的 1% 原则,“风险金额 = 仓位市值 × 止损距离百分比”,如果结果超过账户净值的 1%,程序会直接拆单或降低仓位,确保单笔亏损可控。
第三道闸门:策略状态检查。策略是否处于暂停状态?该标的是否在禁用名单里?顺手还要检查市场状态——现在是午休时间吗?当天是否是国债逆回购到期日?这些琐碎但关键的条件,缺一个都可能出事故。
这些闸门全部通过后,信号才会转化为实际委托单。这样设计的核心逻辑在于:人脑在开盘时间是被情绪劫持的,而程序不会。
5.2 事中风控:止损、熔断、跟踪止盈都要自动化
实盘开始后,Agent 必须担任“冷面监工”的角色。
固定止损必须挂在交易所端,而不是程序内存里。为什么?因为程序可能崩溃、断网、被操作系统杀掉,但交易所端的止损单会一直生效。这是用系统级能力兜底,比任何软件逻辑都可靠。
其次设置熔断机制。我习惯设定账户级回撤熔断:账户净值从日内高点回撤超过 4%,立即停止开任何新仓;从阶段高点回撤超过 8%,强制平掉所有风险仓位,账户进入冷静期。这等于给整个账户上了一道保险丝,避免连续性亏损演变成灾难性暴仓。
跟踪止盈可以单独做一个规则:当持仓盈利超过 ATR(平均真实波幅)的 3 倍时,止损线上移到成本价上方一个 ATR 的位置,锁定利润。这个逻辑可以用移动平均线或者布林带做简化版,但核心思想一致——利润必须通过规则去保护,而不是靠“我感觉差不多该跑了”。
5.3 事后风控:自动复盘与异常归档
每天收盘后,Agent 应该自动生成一份复盘报告,内容包括当日每笔交易的执行价格、滑点、持仓时间、盈亏归因。重点不是看赚了多少,而是看每一笔交易是否按照策略计划执行了。
我把异常交易分成三类:滑点异常(实际成交价与信号价差距超过阈值)、执行延迟异常(信号产生到成交时间超过阈值)、策略漂移异常(实际持仓与计划持仓不一致)。每一类异常都必须自动归档到异常交易数据库,并触发一条告警。如果连续三天出现同一类异常,系统会建议暂停对应策略,检查执行链路。
复盘报告里还应该包含一个非常关键的对比:当日实盘结果与前一天策略镜像记录的“预期计划”。如果实盘行为偏离计划超过一个明确比例,系统会标记这个策略为不稳定,并在第二天降低其仓位分配。这套机制能有效地把“策略的表现问题”和“执行的问题”剥离开来。
5.4 风控参数怎么定:一套可以抄作业的初始值
我给出一个比较稳妥的初始风控参数表,你可以根据自身情况调整:
| 参数 | 建议初始值 | 说明 |
|---|---|---|
| 单笔风险 | 账户净值 1% | 亏损可控,连亏 20 次只回撤约 18% |
| 单标的仓位上限 | 总资产的 15% | 防止单一标的风险过度集中 |
| 总保证金占用上限 | 账户的 60% | 留出足够的波动缓冲空间 |
| 日内最大亏损熔断 | 账户净值 4% | 触发后当日禁止开新仓 |
| 阶段最大回撤熔断 | 账户净值 8% | 触发后强制降仓、进入冷静期 |
| 止损单设置 | 交易所端原生止损 | 程序端也要有备份好逻辑 |
| 异常滑点阈值 | 信号价的 0.2% | 超过则标记并告警 |
这套参数的核心思路是:先用 1% 的单笔风险硬性控制账户生死线,再用 4% 和 8% 的两档熔断控制连续性风险,最后用仓位上限防止冲动集中下注。这是经过实战验证的稳健初始配置,比绝大多数人用的“凭感觉定仓位”要靠谱得多。
6. 常见问题与排查技巧实录
6.1 问题速查表
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| 回测结果和实盘差距很大 | 未来函数、偷价、忽略滑点和手续费 | 检查 K 线边界取值逻辑,加上滑点和手续费模型再跑一遍 |
| Agent 的定时任务没有触发 | 调度器时区配置错误、系统休眠、crontab 环境变量缺失 | 检查系统时区和 crontab 日志,显式声明 Python 解释器路径 |
| 策略提交后回测一直失败 | 数据缺失、依赖版本漂移、路径写死 | 用 Docker 固定依赖环境,数据完整性先校验再跑 |
| 盘中信号和推送不一致 | Agent 内存中缓存了旧行情 | 强制每次信号计算前刷新行情源,并记录数据时间戳 |
| 止损触发平仓后策略还在下单 | 止损后没有同步更新策略内部状态 | 平仓信号与策略状态机做联动,平仓后标记该标的为“当日不可重开” |
| 实盘滑点超预期 | 流动性和行情落差、下单时机太急 | 拆单执行,用 TWAP/VWAP 算法分散冲击成本 |
6.2 三个我踩过的大坑
第一个坑:策略文件里的路径写的是相对路径,但定时任务用 cron 跑的时候当前工作目录是根目录,运行直接报错。后来所有路径都改成显式的项目根目录拼接,并加了一层启动前自检。
第二个坑:用了云数据库存交易记录,有一天数据库服务告警导致 Agent 启动失败,结果错过一整天的行情。这件事之后我把核心交易数据全部迁移到本地 SQLite,并用文件备份,数据主权完全自己掌控。
第三个坑:实盘环境里接了多个数据源,其中一个数据据点更新失败,返回了旧数据。程序没察觉,用旧数据跑出了信号,结果跟实时行情差了十万八千里。从此所有行情数据必须强制检查时间戳,超过 3 秒视为过期数据,直接拒绝使用。
6.3 一个小技巧:给策略做“健康体检”
每个月抽一天,把当前实盘运行的策略镜像拿回历史数据上重新跑一次“月度体检”。体检内容很简单:用最近一年的行情模拟走一遍,看策略的模拟表现是否仍然符合当初回测时的水平区间。如果模拟结果与回测时的关键指标偏差超过 20%,说明市场环境已经明显变化,这个策略需要重新评估,而不是继续无脑运行。
这个动作花费的时间很少,但能让你在策略失效的早期就发现问题,而不是等它亏到你怀疑人生才反应过来。
7. 最后再分享一点实际操作中的感受
整套系统搭完之后,我最明显的变化是心态。以前手里有仓位,总忍不住打开行情软件刷价格,晚上甚至做梦都在想着“要不要手动止损”。现在系统接管了止损、仓位和熔断,我的工作变成了制定规则、审核镜像、更新策略,盘中的那些“手痒时刻”被彻底隔离了。
这其实才是 Trading-as-Git 和本地 Agent 架构最值钱的地方——它不是帮你赚更多钱,而是帮你防止做出让你回到解放前的蠢决定。
如果你也打算开始搭这套东西,我建议你先别急着把策略写得多复杂。先跑通最小闭环:一个策略文件、一个 Git 仓库、一个行情采集脚本、一个简单的风控校验模块。跑通了,再逐步加上 Agent 调度、信号看板、自动复盘。体系是长出来的,不是一步到位的。
还有一个小细节值得分享:我每周五收盘后会做一次全账户的 Git diff 审查,把本周所有策略变更、参数调整、交易记录全部过一遍,看看哪里漂移了、哪个决策当时是心浮气躁做的。这种定期的“元复盘”,比任何单一风控指标都更能帮助你成为一个真正合格的量化交易者。