← 返回教程库

回测好看实盘亏,差的到底是哪三件事

最后更新 2026-08-18
📚 量化与 AI 投研 📖 回测与实盘为什么对不上 ⏱ 约 22 分钟 R2 · 注意风险
你将学到
  • 说得出回测与实盘之间三处机制级差异各自在哪一环节产生,而不是笼统归因为「滑点」或「运气」
  • 拿到一份回测报告时,能提出五个针对性的追问,判断这份报告有没有隐瞒结构性偏差
  • 理解「同一时刻的同一个指标值,在回测和实盘里可以不是同一个数」这件事为什么成立

有人给你看一份回测报告——就是拿历史行情把一套交易规则重放一遍算出来的成绩单。曲线漂亮,年化好看,回撤温柔(年化就是把这段时间的收益折算成一年的速度;回撤是账户从最高点往下掉过多少)。你半信半疑地按同样的规则真金白银跑了一个月,结果对不上。不是差一点,是感觉像换了一套规则。

这时候最常听到的解释是三个字:滑点呗。滑点,就是你想按这个价成交、真成交时价格已经跑偏了那一点差额。或者更省事的两个字:运气。

我想给你一个更硬的答案。回测和实盘对不上,很大一部分不是玄学,也不是概率波动,而是这两件事从来就不是同一个程序在跑同一套输入。差异藏在具体的环节里,有名字、有位置、能被指出来。这一篇就点名其中三处——它们都不是我的推测,而是开源交易框架把它们当成已知行为,明明白白写进了自己的文档和源码。

先说清楚立场:下面的描述来自我对本地源码与文档快照的阅读,不是我跑通了程序拿到的实测结果。我要给你的是「这个概念在真实系统里长什么样」,不是「照着做就能跑通」。至于回测本身还有哪些更常被讨论的坑(偷看未来,就是算的时候用了当时还不存在的信息;幸存者偏差,就是只统计了活下来的那些样本;过拟合,就是把偶然的杂音当成规律记了下来),什么是回测,回测在骗你什么 已经拆过一轮,这里不重复。这一篇专攻另一类问题:假设你那六个坑一个没踩,回测和实盘依然会对不上,因为还有这三件事。

机制一:回测里你每根 K 线看一眼盘,实盘里你每几秒看一眼

先打个比方

想象你在照看一锅汤,规矩是「一冒泡就关火」。

第一种照看方式:你每小时进厨房一次,掀开盖子看一眼,冒泡就关火,没冒泡就走。 第二种:你搬个凳子坐在灶台前,每几秒瞄一眼。

同样一句「一冒泡就关火」,两种照看方式的结果完全不同。坐在灶台前的那个人,会在汤刚刚起第一个小泡的瞬间就关火;每小时来一次的那个人,看到的往往是已经翻滚了半天的一锅汤。规则一个字没改,但「多久判断一次」变了,做出的动作就变了。

这对你的判断意味着什么

K 线是把一段时间内的价格压缩成的一根柱子——比如一根小时线,就是这一小时内的开盘、最高、最低、收盘四个数。回测通常是按 K 线推进的:每根 K 线出现一次,程序检查一次规则,决定买还是卖。

但实盘不是这么走的。实盘是个不停转的循环,每隔几秒就把整套判断跑一遍。这就意味着,在一根小时线的内部,实盘可能已经做了上百次判断,而回测只做了一次。

对哪些规则影响最大?凡是依赖「此刻的价格」「此刻的浮动盈亏」的规则,都会被放大:

  • 追踪止损(止损线跟着价格上移的那种)在实盘里会被 K 线内部的短暂尖刺触发,而回测按 K 线看,那根尖刺可能被压缩成了一个「最高价」数字,没有触发的机会,或者相反——在回测里被当成触发了,但实盘的那一秒你压根没在那个价位上。
  • 「浮盈超过某个比例就跑」这类离场规则,实盘会在 K 线中途就跑掉,回测要等这根 K 线走完才算数。
  • 反过来,任何「本根 K 线内先跌后涨」的走势,回测只看到最终结果,实盘却真真切切地在中间那一下里做了动作。

结论是:你的规则越依赖盘中的即时状态,回测和实盘的偏差就越大。 一套只在收盘价上做判断的慢策略,受这条影响很小;一套盯着浮盈浮亏做动态调整的策略,受这条影响可能大到让报告失去参考价值。

它在系统里长什么样

freqtrade 是一个公开的自动交易框架,它的文档里把「实盘循环」和「回测循环」分成两段并排写。实盘那段的开头写着:默认情况下这个循环每隔几秒转一圈(配置项 internals.process_throttle_secs,是当前默认值,可以改),每一圈里依次做这些事——拉取未平仓交易(还没卖出、仓位还在手上的那些交易)、算可交易品种清单、下载行情、调用策略的各个回调函数、检查离场、检查加减仓(在已有仓位上再买一点或先卖一点)、检查入场。

回调函数(callback)就是「框架在流程走到某一步时,回头调用你写的那段代码」。你把「什么时候该卖」写成一个函数交给框架,框架每转一圈就问你一次。

回测那段的流程明显更短,因为大部分交易动作是模拟的:加载历史数据、算一次指标、算一次进出场信号,然后按 K 线循环模拟成交。

真正值得你划重点的,是这份文档在页面最后放的一条警告。它的意思是:回测中每个回调函数每根 K 线最多被调用一次,而实盘里大多数回调是每轮循环调用一次——原文用的词是这会造成 "backtesting mismatches",直译就是回测不匹配。

我要提醒你注意的是这句话的位置和语气。这不是某个用户在论坛上的抱怨,是框架作者自己在官方文档里主动声明的已知行为。一个成熟系统会把自己的失真点写在说明书上;一份成熟的回测报告也应该主动说明它在这一点上做了什么处理。 顺便说一句,这份文档也提到回测支持切换到更细的 K 线粒度来缓解这个问题——但那只是把「每小时看一眼」改成「每分钟看一眼」,缩小了差距,并没有消灭它。

机制二:回测按贵宾价算账,实盘按你的真实价算账

先打个比方

你在一家批发市场比价,店家给你看一张报价单,上面标的是「一次拿一百箱的价格」。你回家按这张单子算了半天利润,觉得这生意能做。真去进货那天,你只拿得起五箱,柜台报出来的是另一个数。

生意的逻辑没变,商品没变,变的只是你被归到了哪一档价格。而这一档之差,恰好能把一门薄利生意从赚变成亏。

这对你的判断意味着什么

交易手续费在多数交易场所是分档的:交易量越大、等级越高,费率越低。而回测报告在算账时,用的默认往往是「最低那一档」。

为什么这件事比你想的严重?因为手续费不是只收一次。你买入收一次,卖出再收一次,一笔完整的来回要付两遍。 这两遍对不同类型的策略,杀伤力天差地别:

  • 一年只调仓两次的慢策略,来回成本摊到年化里几乎看不见。
  • 一天进出好几次的快策略,一年下来的来回次数可能是几百上千次。这时候每一次多付万分之几,累计起来就是把年化收益整块削掉的量级。

所以这条机制真正的含义不是「回测少算了一点成本」,而是:回测对策略的偏爱程度,和这套策略的换手频率成正比。 换手率(一段时间里你把仓位翻来覆去换了多少遍)越高的策略,回测给它的美颜滤镜就越厚。你看到两份报告,一份年化 20% 的低频、一份年化 40% 的高频,按最低档费率算出来的这个对比,本身就是不公平的对比。

还有个更容易被忽略的角落:模拟盘(用真实行情但不真下单的演练)通常也走同一套「最低档费率」的假设。也就是说,你以为模拟盘是实盘的预演,其实在费率这一项上,它站在回测那一边。 模拟盘跑得好,不构成费率层面的验证。

它在系统里长什么样

同一份 freqtrade 文档里有专门一小节讲费率处理,说的是:所有盈亏计算都包含手续费;回测、超参优化(自动搜索参数组合的过程)和模拟盘这三种模式,用的是交易所的默认费率,也就是最低那一档;而实盘用的是交易所实际收你的费率,包含各种返还与折扣。

配置文档里那个 fee 参数的说明写得更直白:它是回测和模拟盘时用的费率,正常情况下不建议配置,让框架回落到交易所默认值;并且明确注明这个费用每笔交易收两次,买一次、卖一次。命令行还提供了一个覆盖费率的开关,让你在回测时手动喂进自己的真实档位。

这里我特别想让你看见的是设计意图:框架提供了「手动指定费率」的入口,本身就是在承认默认值不等于你的值。 一个入口的存在,等于系统在告诉你「这里有个假设,你可能需要改」。你拿到任何一份回测报告,都该问一句:这份报告在费率这一格里填的,是谁的价格?

机制三:同一时刻的同一个指标,回测和实盘算出来可以不是同一个数

这一条是三个里最反直觉的,也是最值得你花力气理解的。前两条你还能靠常识猜到,这一条不讲清楚,你永远想不到。

先打个比方

你要算一个学生的「平均分」,规则是每次考完就把新成绩混进去更新一次。

老师 A 手上有这个学生从小学到现在的全部成绩,一路算下来,算到今天。 老师 B 是新来的,手上只有最近五次的成绩,从第一次开始算,也算到今天。

今天这一次考试的分数,两位老师拿到的是同一个。但他们算出来的「平均分」不是同一个数。 因为这个平均分不是只看今天,它是从很久以前一路滚过来的,起点不同,滚到今天就不同。

更要命的是:这个差别不会随着时间流逝而消失得干干净净,它只是越滚越小。老师 B 手上多攒几十次成绩,差距会收敛到看不出来;但只攒了五次的时候,两个数可以差得离谱。

这对你的判断意味着什么

技术指标里有一大类是「递归」的——今天的值由昨天的值加上今天的新数据推出来,昨天的值又由前天推出来,一路往前追。指数移动平均(EMA,就是把最近这些天的价格做个平均,而且离今天越近的价格算得越重)就是典型代表。

递归意味着:这个指标今天的值,取决于你往前喂了多少根 K 线。 而这恰恰是回测和实盘最不对等的地方:

  • 回测时,你手上是一整段下载好的历史数据,想往前追多久都行。
  • 实盘时,程序只能向交易场所索要有限根历史 K 线,接口有条数上限,还有连续请求次数的限制。

于是在同一个时刻、同一个品种、同一个指标名字下面,回测算出来的数和实盘算出来的数就是两个数

这件事的后果不是「差一点点无所谓」。你的规则里但凡有一条是「指标穿过某个阈值就动手」,那么在阈值附近的那些时刻,一个小小的数值差异就足以让一次交易从「触发」变成「不触发」。而策略的收益往往由少数几笔交易主导——少几笔、多几笔,整条曲线的形状就换了。

这也解释了一个常见的困惑:为什么有人回测和实盘用的是完全相同的一份策略代码,逐字节相同,结果还是对不上?因为代码相同不等于喂进代码的数据长度相同。相同的公式,不同的起点。

它在系统里长什么样

freqtrade 为这件事专门做了一个诊断命令,叫 recursive-analysis(递归分析)。它的文档开头就把问题讲得很朴素:回测能拿到你指定时间范围内的完整数据,而模拟盘和实盘会被交易所愿意给多少数据卡住。

文档里举的例子干净得像一道小学题:假设有个指标叫 steps,规则是第一行为 0,之后每一行等于上一行加一。用最近一千根 K 线来算,最后一行是 999;只用最近五百根来算,最后一行是 499。同一个时刻,同一个公式,两个数。这就是整个问题的最小可复现形态。

这个命令的做法,说穿了就是一句话:不去猜差多少,而是直接算出来给你看。

我读了它的实现源码。逻辑大致是这样:先用你给的完整时间范围算一遍指标,把结果当作基准;然后换一组不同长度的「启动 K 线数」(startup candle count,就是指标开始计算前要预先喂进去的历史 K 线根数),每个长度各算一遍;最后把每一次结果的最后一行拿出来和基准对比,把差异百分比列成一张表。源码里有一个细节我觉得很能说明设计者的态度——如果策略本身声明的启动 K 线数不在候选列表里,它会把这个值补进去一起测,并且排序。也就是说,它保证你自己的那个设定一定会被检验到,而不是只测几个框架预设的值。默认那组候选值是几百到近两千的一串数(是当前默认值,可以自己指定)。

另外,这个命令顺手还做一件事:在指标层面做一次简单的前视检查,也就是查一查指标有没有偷用未来的数据。这两件事被放在一起不是偶然——它们本质上是同一类问题的两面:指标的值,到底取决于哪些数据。

文档里还有两句话,我认为比命令本身更值钱:

第一句,它明确说不要以「方差归零」为目标——方差在这里就是「同一个指标,喂不同长度的历史算出来,两个数差多少」。因为像 EMA 这类天生递归的指标,要把差异压到绝对的零,需要的启动数据长度可能长到不现实。目标是把差异压到「不影响交易决策」的程度,不是压到零。 这是很成熟的工程判断:承认失真无法消灭,转而管理它的量级。

第二句,它老实交代了这个诊断的局限——只比较最后一行的指标数值,至于这点差异到底有没有真的改变你的进出场,命令不负责回答。而且,如果你把指标计算写在了进出场信号的那段代码里,而不是写在专门算指标的那段里,这个命令根本扫不到。

一个诚实的工具会告诉你它测不到什么。 这句话你可以拿去衡量任何给你看报告的人。

三条串起来看:回测和实盘不是同一场比赛

把三条并排放一下,你会发现它们在结构上是同一种东西:

差异出在哪 回测那边 实盘那边 谁受伤最重
判断频率 每根 K 线判一次 每几秒判一次 依赖盘中即时状态的规则
费率档位 最低那一档 你实际那一档,进出各收一次 换手频繁的高频策略
指标启动数据 想喂多长喂多长 被接口条数卡住 阈值型信号、递归类指标

它们没有一个是「谁写错了代码」。三条全是结构性的:只要回测是在离线的完整历史上跑、实盘是在有限视野的实时流上跑,这三处差异就一定存在,区别只在于有没有被测量、有没有被披露。

所以真正的问题从来不是「怎么让回测和实盘完全一致」——做不到。问题是**「这份报告有没有把自己的失真量测出来给我看」**。前者是幻想,后者是可执行的尽调——尽调就是掏钱之前,把该查的事一项项查清楚。

顺带说一句,这三条只是这一卷的入口。判断频率、费率、指标启动期,后面各会有专门一篇往下挖,这里先给你一张全局地图。

收口:拿到一份回测报告,该追问的五个问题

这五个问题按可操作性排的,你可以直接照着问。它们不需要你会写代码,只需要你听得懂对方的回答有没有绕开。

第一问:这套规则依赖盘中的即时价格吗?如果依赖,回测是按什么粒度模拟的? 如果对方的策略里有追踪止损、动态止盈(赚到设定幅度就主动了结,且这个幅度会随行情变)、按浮盈调仓这类东西,而回测是按整根 K 线推进的,那这份报告在时间分辨率上就是虚的。追问一句「有没有用更细的 K 线粒度复核过,差多少」,答不上来说明没做。

第二问:手续费按哪一档算的?你自己实际是哪一档? 这个问题最好答也最容易露馅。正确的回答应该是一个明确的数字来源,以及「我按自己真实那一档重跑过一遍,年化从 A 变成 B」。如果对方说「费率影响不大」而拿不出重跑结果,那就是没算过。换手越频繁,这个回答越关键。

第三问:指标的启动数据长度是多少?实盘环境拿得到这么多吗? 如果对方从没听说过这个问题,那么第三条机制在他的报告里就是完全未经测量的裸露风险。诚实的回答是:我测过不同启动长度下指标末值的差异,在我的设定下差异是某个量级,不足以改变进出场。

第四问:报告里的成交价是怎么来的?有没有假设「想成交就能成交」? 这条和前三条互补。回测里的成交往往是理想化的:报个价就成了,不排队、不拒单、不影响价格。真实市场里,你的单子要排队,冷门品种可能挂着没人接,量大了还会把价格推走。追问一句「如果每笔成交价都往不利方向挪一点,曲线还剩多少」——扛不住这一挪的策略,本来就不该上。

第五问:这份报告有没有写出它自己测不到什么? 这一问是元问题,也是我最看重的一问。前四问对方都能应付,但一份从头到尾只有优点、没有一句「本报告未能覆盖」的成绩单,本身就是最大的警号。一个人愿不愿意说出自己方法的边界,比他的年化数字更能说明他的水平。 上面提到的那个诊断命令都要在文档里老实写「我只比对最后一行,改没改变进出场我不负责」——凭什么一份向你推销的报告可以什么都不用交代?

⚠️ 风险提示

本节讲的是回测与实盘之间的机制差异,不构成任何投资建议、买卖信号或收益承诺。把这三条全部处理干净,也只是让报告变得不那么失真,它依然不能预测未来。 任何拿一条回测曲线向你承诺收益的人,都该被高度警惕——尤其是当他连自己方法的边界都说不出来的时候。完整风险提示见 免责声明

小结

  • 回测和实盘对不上,很大一部分不是运气,是三处结构性差异:判断频率、费率档位、指标启动期
  • 判断频率:回测按 K 线判一次,实盘每几秒判一次。规则越依赖盘中即时状态,偏差越大;开源框架把这条当作已知行为写进了官方文档。
  • 费率档位:回测、超参优化和模拟盘常用交易场所的最低档费率,实盘用你真实那一档,且买卖各收一次。换手越频繁,回测的美颜滤镜越厚。
  • 指标启动期:递归类指标的当前值取决于往前喂了多少根 K 线,回测喂得多、实盘被接口卡住喂得少,同一时刻算出来不是同一个数。成熟的做法是测量差异并把它压到不影响决策,而不是妄想归零。
  • 拿到报告先问五个问题:模拟粒度、费率档位、指标启动长度、成交价假设、以及这份报告承认自己测不到什么
  • 想补回测本身那六个更基础的坑(偷看未来、幸存者偏差、过拟合等),回到 什么是回测,回测在骗你什么;想亲手体会一遍回测是怎么做出来的,看 写一个最简策略回测

一句话说完这篇:纸上练兵和真上战场,用的不是同一张地图、不是同一块表、也不是同一个价目表,所以打出来的结果本来就不该一样——聪明的做法不是逼它们一样,而是先问清楚差在哪、差多少。

内容有错、看不懂、或想看下一篇?告诉我们 →

本文为投资教育整理,不构成任何投资建议;不荐个股/基金、不预测点位、不承诺收益。关键数据与结论请结合权威来源自行验证,并见风险免责声明