如何回测你自己的交易策略(不用写代码)

回测,就是把你写清楚的买入和退出规则,套到过去的日线数据上,看这套规则在历史上会赚多少、亏多少、最多回撤多深。它回答的不是"这只股票会不会涨",而是"我这套规则的脾气是什么"。不用写代码也能做:只要规则是机器可判定的条件,工具就能替你跑完整段历史。

本文要点

  • 回测至少要看四个数:胜率、盈亏比、最大回撤、夏普比率。只看总收益是最常见的坑。
  • 期望值 = 胜率 × 平均盈利 − 败率 × 平均亏损 − 每笔往返成本。成本一扣,不少"看起来赚钱"的策略会变成负数。
  • 6 个信号里赢了 1 个,说明不了任何事。样本太小时,数字全是噪声。
  • 前视偏差和幸存者偏差都会让回测虚高,要主动排除。
  • 参数在一段数据上调好,一定要拿另一段没碰过的数据再验一次(样本外检验)。

回测在测什么

一次有意义的回测,至少给你四个数:

  • 胜率:多少比例的交易是盈利的。它最直观,但单独看最没用。
  • 盈亏比:所有盈利交易赚的总额 ÷ 所有亏损交易亏的总额。大于 1 才是净赚。胜率低但盈亏比高,照样赚钱;反过来,胜率 70% 但每次赢的只有亏的三分之一,照样亏。
  • 最大回撤(MDD):资金曲线从历史高点最多回落多少。它决定你能不能拿得住——一条年化很高但回撤 60% 的策略,现实里你大概率会在谷底放弃,根本等不到回本。
  • 夏普比率:每承担一单位波动,换来多少超额收益。两条策略总收益一样,夏普高的那条走得更稳,拿着也更舒服。

这四个数要一起看。任何一个单拎出来,都可能被另外三个推翻。

期望值:一笔交易平均值多少钱

把胜率和盈亏大小揉在一起,就是期望值——每做一笔交易,平均能拿到多少。公式很短:

期望值 = 胜率 × 平均盈利 − 败率 × 平均亏损 − 每笔往返成本

拿一个具体例子算。假设回测结果是:胜率 40%,平均盈利 +10%,平均亏损 −5%。每笔买 100 股、股价 100 美元,也就是一笔 10,000 美元。

  • 赢一笔:卖在 110,赚 1,000 美元。
  • 亏一笔:止损在 95,亏 500 美元。
  • 10 笔交易:4 笔赢共 +4,000,6 笔亏共 −3,000,毛利 +1,000,平均每笔 +100 美元(+1%)。

看起来是正的。现在把成本加进来。滑点加佣金加各种税费,一次买卖往返在这个例子里按 1.5% 估(港股会更高,见港股交易费用),每笔 150 美元,10 笔就是 1,500。

  • 净结果:1,000 − 1,500 = −500 美元,平均每笔 −50 美元(−0.5%)。

一条毛期望 +1% 的策略,扣完成本就是负的。这就是为什么回测报告里"是否已扣除成本"比"总收益是多少"更重要。顺手也能算出盈亏比:毛盈亏比 4,000 ÷ 3,000 ≈ 1.33;扣成本后,赢的每笔净 850、亏的每笔净 650,盈亏比变成 3,400 ÷ 3,900 ≈ 0.87,跌到 1 以下。

三步做一次干净的回测

  1. 把规则写成明确条件。 别用"低了买",要用"RSI < 35 且 当日涨幅 > 1.5%"这种机器能判定的条件(见怎么把逻辑写成买入规则)。退出规则同样要写清楚——止损多少、止盈多少、最多持有几天。没有退出规则的回测等于没做。
  2. 用够长、够宽的数据。 至少覆盖一轮完整涨跌,最好包含一次像样的熊市。只测最近一年的牛市,任何"买了就拿着"的规则都会显得很聪明。
  3. 别过度拟合。 参数调到历史上完美,往往只是记住了噪声。一条带 8 个条件、每个条件都精确到小数点后两位的规则,几乎一定是拟合出来的。条件越少、越"钝"的规则,越可能在未来站得住。

两种最常见的偏差

前视偏差(lookahead bias):规则用到了当时还不知道的信息。最典型的是用当天收盘价确认信号,却假设在当天开盘价买入——现实里你看到收盘时,开盘早就过去了。还有一种更隐蔽:用后来修正过的财报数据,去判断当时的估值。干净的做法是:信号在 T 日收盘确认,成交只能算在 T+1 日或更晚。

幸存者偏差(survivorship bias):只用今天还在交易的股票做回测。那些退市、被收购、跌到停牌的股票不在你的名单里,而它们恰恰是策略最容易踩雷的地方。你的股票池是"活下来的赢家",结果自然虚高。完全消除很难,但你至少要知道自己的回测往这个方向偏,别把它当成保守估计。

样本太小,数字就是噪声

假设你的规则在过去两年只触发了 6 次,其中 1 次赢——胜率 17%。这能说明它是烂策略吗?不能。6 次里多赢一次,胜率就变成 33%;多输一次,就是 0%。样本这么小,一次偶然事件就能把结果整个翻过来。

同理,6 次里赢 5 次也说明不了它是好策略。粗略地说,几十笔交易只能看出大方向,上百笔才谈得上比较不同参数。如果你的规则太严、几年才触发几次,要么放宽条件,要么扩大股票池,要么接受"这条规则目前没法被验证"。

样本外检验:留一段数据别碰

这是防过度拟合最实用的手段。把历史数据按时间切成两段:前面一段(比如 2019–2023)用来调参数,后面一段(2024 至今)在调完之前一次都不看。参数定好后,再在后面这段上跑一遍。

  • 如果样本外的胜率、盈亏比和样本内差不太多,规则大概抓到了真东西。
  • 如果样本内很漂亮、样本外一塌糊涂,那就是拟合了噪声——回去减条件,别回去加条件。

另一种切法是按市场切:在美股上调好的参数,原样拿到港股或 A 股上跑。跨市场还站得住的规则,通常更稳。

在 Stock Compass 里怎么设

Stock Compass 的回测是 Pro 功能。它把你自己写的买入 / 退出规则跑在日线数据上,一次最多 500 个标的,输出胜率、盈亏比、最大回撤和每笔交易明细。它不连接券商、不下单、也不推荐股票——跑的只是你的规则。

下面是一条可以直接回测的示例策略:

{
  "name": "20日突破 + 趋势过滤",
  "market": "us",
  "rules": {
    "buy": {
      "v": 2,
      "outerOp": "OR",
      "groups": [
        {
          "innerOp": "AND",
          "conditions": [
            { "indicator": "is_20d_breakout", "operator": "==", "value": 1 },
            { "indicator": "adx_14", "operator": ">", "value": 25 },
            { "indicator": "vol_vs_avg20d", "operator": ">", "value": 1.5 }
          ]
        }
      ]
    },
    "add": { "v": 2, "outerOp": "OR", "groups": [] },
    "trim": { "v": 2, "outerOp": "OR", "groups": [] },
    "exit": {
      "v": 2,
      "outerOp": "OR",
      "groups": [
        { "innerOp": "AND", "conditions": [ { "indicator": "floating_loss_pct", "operator": ">", "value": 5 } ] },
        { "innerOp": "AND", "conditions": [ { "indicator": "floating_gain_pct", "operator": ">", "value": 15 } ] },
        { "innerOp": "AND", "conditions": [ { "indicator": "holding_days", "operator": ">", "value": 40 } ] }
      ]
    }
  }
}

每个条件一句话:

  • is_20d_breakout == 1:今天收盘创 20 日新高。
  • adx_14 > 25:ADX 高于 25,说明有趋势在,不是横盘里的假突破(见用 ADX 过滤假突破)。
  • vol_vs_avg20d > 1.5:量比超过 1.5 倍,突破有量配合。
  • floating_loss_pct > 5:浮亏超过 5% 就止损。
  • floating_gain_pct > 15:浮盈超过 15% 就止盈。
  • holding_days > 40:持有超过 40 个交易日还没触发上面两条,时间到,离场。

三组退出条件之间是 OR,任何一条满足就退出。回测跑完,先看交易笔数够不够,再看扣成本后的期望值是不是正的,最后看最大回撤自己能不能扛。

另外,你日常收到的每条信号,Stock Compass 都会在信号历史里记录 T+1、T+5、T+10 的实际涨跌(不含成本)。这相当于一个持续进行的样本外检验——规则一旦上线,它在真实未来上的表现会自动累积起来。

常见错误

  • 只看总收益。 年化 40% 但回撤 60% 的策略,你扛不到回本。四个数一起看。
  • 忘记扣成本。 上面的例子已经证明,1.5% 的往返成本能把正期望打成负的。
  • 信号当天成交。 用收盘价确认信号却按当天价格成交,是最常见的前视偏差。
  • 样本太小就下结论。 6 笔交易的胜率没有任何意义,不管是 1/6 还是 5/6。
  • 反复调参直到好看。 调完样本内又去调样本外,样本外就不再是样本外了。

小结

回测不是为了找到"完美策略",而是为了在下注前,先知道这套规则的脾气:它多久出一次手、赢面多大、亏起来多深、扣完成本还剩不剩。把规则写清楚,把成本算进去,留一段数据别碰,交易笔数够了再下结论。先验证,再执行。

常见问题

回测胜率多高才算好?

单看胜率没意义。40% 胜率、每次赢的是亏的两倍,照样赚钱;70% 胜率、每次亏的是赢的三倍,照样亏。胜率要和盈亏比、扣成本后的期望值、最大回撤一起看。

回测赚钱,实盘就一定赚吗?

不一定。回测有滑点、手续费、幸存者偏差、前视偏差、过度拟合等陷阱,而且每一个都往好看的方向偏。回测能帮你排除明显烂的规则、理解一套规则的脾气,但不是未来收益的预测。

回测需要多长的历史数据?

至少要覆盖一轮完整涨跌,最好包含一次像样的熊市;同时交易笔数要够——几十笔是底线,想比较不同参数得上百笔。如果规则在整个区间里只触发几次,不管覆盖多少年,结果都是噪声。

怎么判断自己是不是过度拟合了?

把数据按时间切成两段,只在前一段调参数,调完后在没看过的后一段跑一次。如果样本外的数字比样本内差很多,就是拟合了噪声。条件多、参数调得很精细的规则最容易出这个问题,解决办法是减条件,不是加条件。

Stock Compass 的回测和信号历史有什么区别?

回测(Pro 功能)把你的买入 / 退出规则跑在过去的日线数据上,一次最多 500 个标的,输出胜率、盈亏比、最大回撤。信号历史则是记录你的规则往后每天实际发出的信号,并在 T+1、T+5、T+10 给出实际涨跌(不含成本)——一个是往回看,一个是往前持续验证。两者都不连接券商、不下单。