手续费与滑点建模:为什么你的回测是假的

backtest-cost-model - 智策 SmartQuant
结论先行:不含真实手续费和滑点的回测是假的。手续费双边计算、滑点按ATR/价差估算、资金费率逐期结算——不加这三样,盈利策略也会被成本拖成亏损。成本建模是回测可信度的地基,不做=结果自欺欺人。
回测方法 阅读 14 分钟 2026-08-12

绝大多数「回测很漂亮、实盘就亏」的原因不是策略失效,而是成本被算少了或者根本没算。以日均 10 笔、单边总成本 0.1% 计算,一年的成本消耗约为本金的 730%——这不是笔误,而是换手率乘以双边成本的必然结果。

本文要点

  • 手续费必须双边计算:一次完整交易 = 开仓一次 + 平仓一次,费率要乘 2。
  • 年化成本 ≈ 日均交易次数 × 365 × 单边总成本 × 2,这个粗算能在写代码前就淘汰掉大量策略。
  • 滑点没有真实盘口数据时,可用 ATR 的 2%–5% 或典型价差的 1–2 倍作为保守估计。
  • 永续合约多头在牛市中通常持续支付资金费率,年化可达 10%–30%,长期持仓不可忽略。
  • 高频策略对成本最敏感:单边成本从 0.05% 升到 0.1%,日均 10 笔的策略年化就多消耗约 365%。

三类成本,缺一个结论就不成立

加密市场的交易成本可以拆成三块,它们的性质完全不同,不能混在一个数里估。

第一块是手续费,确定性成本,事先知道,按成交名义金额的固定比例收取,区分挂单(maker)和吃单(taker)。第二块是滑点,随机成本,你的委托价与实际成交均价之差,取决于订单大小与当时盘口深度,行情剧烈时会放大数倍。第三块是资金费率,持仓成本,只在永续合约上出现,按持仓时间累积,与交易次数无关。

许多人只算了第一块,而且只算了单边。这就是回测虚高的主要来源。三块里手续费最好估、滑点最难估、资金费率最容易被完全遗忘。

三类交易成本的性质与建模方式
成本类型触发条件典型量级(示例)建模方式对什么策略最致命
手续费每次成交吃单单边 0.04%–0.06%按成交名义金额固定比例,开平各收一次高频、日内多笔
滑点每次成交(市价单尤甚)单边 0.02%–0.10%,极端行情可达 0.5%+ATR 的 2%–5%,或典型价差的 1–2 倍突破类、小市值币种
资金费率持仓跨过结算时点每 8 小时 ±0.01%,年化约 ±11%按持仓名义金额与持仓时长累积长周期持有、套保、网格
借币利息杠杆或做空现货年化 3%–20%(随行情浮动)按借入金额与天数计息杠杆策略、现货做空
费率随交易所与账户等级差别很大,上表数字仅为写回测时的保守起点。正式研究前请查阅自己实际账户的费率页,并按最不利档位建模。

手续费:双边是最容易漏的乘 2

一次完整交易包含两笔成交:开仓和平仓。若单边吃单费率是 0.05%,一次完整往返的手续费就是 0.1%。这个乘 2 是所有成本估算的起点,漏掉它相当于把成本直接砍半。

第二个细节是计费基数。手续费按成交名义金额计算,不是按你的保证金。用 5 倍杠杆开 10000 USDT 名义仓位,只投入 2000 保证金,手续费仍然按 10000 计算,即 5 USDT。相对保证金的费率因此是 0.25% 而不是 0.05%,杠杆把成本按倍数放大了。

第三个细节是 maker 与 taker 的区别。挂单成交费率通常明显低于吃单,有些交易所甚至给挂单返佣。但回测里默认应该按 taker 建模——你以为的限价挂单在实盘里经常因为价格跑掉而被迫改成市价追单,成交率与费率的这个权衡必须在回测阶段就假定最差情况。

# 单笔完整交易的手续费与滑点(名义金额口径)
FEE_TAKER = 0.0005      # 单边 0.05%
SLIP      = 0.0005      # 单边 0.05%

def round_trip_cost(notional: float,
                    fee=FEE_TAKER, slip=SLIP) -> float:
    """返回一次开+平的总成本(USDT)"""
    one_side = notional * (fee + slip)
    return one_side * 2


def annual_cost_ratio(trades_per_day: float,
                      fee=FEE_TAKER, slip=SLIP) -> float:
    """年化成本 / 本金 (假设每次用满仓位, 无杠杆)"""
    per_trade = (fee + slip) * 2          # 双边
    return trades_per_day * 365 * per_trade


for n in (0.2, 1, 5, 10, 30):
    print(f"日均 {n:>4} 笔 -> 年化成本约 "
          f"{annual_cost_ratio(n) * 100:,.0f}% 本金")

# 日均  0.2 笔 -> 年化成本约      7% 本金
# 日均    1 笔 -> 年化成本约     37% 本金
# 日均    5 笔 -> 年化成本约    183% 本金
# 日均   10 笔 -> 年化成本约    365% 本金
# 日均   30 笔 -> 年化成本约  1,095% 本金
python

滑点:没有盘口数据时怎么估

滑点是委托时的参考价与实际成交均价之差。理想做法是用逐笔成交与盘口快照数据精确模拟,但这类数据体量大、获取成本高,多数个人研究者拿不到。退一步有两种可用的近似方法。

方法一:按 ATR 比例。取 14 周期 ATR,滑点设为 ATR 的 2%–5%。这个方法的逻辑是波动越大、盘口越容易被拉开,滑点自然越高。优点是自适应行情,剧烈波动期会自动加大惩罚;缺点是与订单大小无关。

方法二:按典型价差倍数。用买卖价差的 1–2 倍。BTC 主流合约价差常在万分之一到万分之二之间,山寨币可能到千分之几。这个方法更贴近微观结构,但需要你至少采样过一段真实盘口。

两种方法都建议再叠加一个订单规模惩罚项:当单笔名义金额超过盘口前五档累计量的某个比例时,线性追加滑点。小资金账户可以忽略这一项,资金规模大到能吃穿几档盘口时它就成了主导成本。

def slippage_atr(atr: float, price: float, k: float = 0.03) -> float:
    """按 ATR 比例估滑点, 返回相对价格的比率"""
    return k * atr / price


def slippage_spread(bid: float, ask: float,
                    mult: float = 1.5) -> float:
    mid = (bid + ask) / 2
    return mult * (ask - bid) / 2 / mid


def fill_price(ref_px, side, slip_rate, fee=FEE_TAKER):
    """side: +1 买入, -1 卖出。滑点总是往不利方向"""
    px = ref_px * (1 + side * slip_rate)
    eff = px * (1 + side * fee)     # 把费用折进有效成交价
    return px, eff
滑点建模的方向必须永远不利于自己:买入时加价,卖出时减价。见过不少回测把滑点写成对称随机数,均值为零——这在数学上抹掉了滑点成本,等于没建模。
python

资金费率:持仓越久越贵

永续合约靠资金费率把合约价格锚定在现货附近。当合约价高于现货(市场偏多),多头付钱给空头;反过来空头付多头。多数交易所每 8 小时结算一次,即每天三次。

常态费率约为每次 0.01%,折算年化约 11%。这个数字在温和行情里不算大,但在情绪亢奋期费率可能连续多日达到每次 0.1% 甚至更高,年化超过 100%。对持仓周期以周计的趋势策略来说,这是一笔必须计入的持续支出。

反过来,资金费率也可以是收入。方向中性的套保组合(现货多 + 永续空)赚的正是这笔钱。做这类策略时资金费率是收益来源,建模精度直接决定结论对错,不能用常数近似,必须用历史费率数据逐期结算。

def apply_funding(pos_notional: float, side: int,
                  funding_series, ts_start, ts_end) -> float:
    """结算区间内累计资金费。side=+1 多头, -1 空头。
    funding_series: 索引为结算时点的历史费率(如 0.0001)
    返回值为负表示支出。
    """
    f = funding_series.loc[ts_start:ts_end]
    # 费率为正时多头付钱, 故乘 -side
    return float((-side) * (f * pos_notional).sum())
python

具体演算:成本如何把盈利吃成亏损

下面用一组假设数字演示,全部为示例演算,不代表任何实际策略表现。设一条 15 分钟级别的短线策略,回测区间一年,日均 10 笔完整交易(即约 3650 笔/年),每笔用满账户名义金额,无杠杆。不计成本时年化收益 180%,单笔平均毛收益约 0.049%。

现在逐项加入成本。单边手续费 0.05%、单边滑点 0.05%,一笔往返成本 0.2%(双边各 0.1%)。单笔平均毛利 0.049% 远小于往返成本 0.2%,每笔净结果是亏 0.151%。3650 笔累计下来,账户不是收益打折,而是彻底归零。

这不是极端构造的例子,而是短线策略的常态:信号的平均毛利经常小于往返成本。判断一条策略能否活下来,只需要一步算术——平均单笔毛利是否显著高于往返成本,建议留出至少 2 到 3 倍的余量。

示例演算:逐项加入成本后的年化结果(假设数字,非实际策略)
成本设定单笔净收益年化结果(示例)结论
零成本(理想)+0.049%约 +180%回测报告上的漂亮数字
仅单边手续费 0.05%-0.001%约 -3%只算单边就已经不赚了
双边手续费 0.1%-0.051%接近全部亏光漏掉乘 2 结论完全反转
双边手续费 + 双边滑点 0.2%-0.151%远快于归零策略不成立
同上但日均降到 1 笔、单笔毛利 0.6%+0.40%约 +340%(示例)低频高毛利才有生存空间

最后一行给出了唯一的出路:要么提高单笔毛利,要么降低交易频率。提高毛利通常意味着持仓更久、目标更远;降低频率意味着更严格的信号过滤。两者都会减少交易次数,而这正是成本约束下的正确方向。

把成本加进你的引擎很简单,实现细节见从零搭建最小回测引擎;加完之后一定要重新做参数扫描,因为最优参数会明显向低频方向移动,相关方法见过拟合识别

本节所有收益率、亏损率均为假设条件下的示例演算,用于说明成本的量级效应,不是历史回测结果,更不构成收益承诺或投资建议。实际成本因交易所、账户等级、币种流动性、行情状态而异,可能显著高于上表设定。

把成本当成设计约束而不是事后扣减

多数人的流程是:先做出漂亮曲线,最后加成本,发现不行再回头调。这个顺序浪费大量时间,因为成本会改变最优参数本身,事后加的结果并不是「打折版」而是完全不同的策略。

更有效的做法是把成本前置:写策略之前先做一次上一节那样的餐巾纸算术,估出这条思路需要多少单笔毛利才能存活。若你的信号显然达不到,直接换思路,不必写代码。这一步通常只要五分钟,能省掉几天。

参数扫描也要在含成本条件下做。含成本的最优参数往往比零成本版本更慢、更保守、交易更少,而这个版本才是真正可执行的。同一套参数在零成本下最优、含成本下崩掉,是很常见的现象。

  • 先算再写:估算需要的单笔毛利门槛,判断思路是否有生存空间。
  • 参数扫描含成本:不要拿零成本最优参数去加成本验证。
  • 做敏感度:把成本乘 1.5 倍和 2 倍再跑,若结论反转说明余量不足。
  • 记录换手率:把年化换手率作为一等指标输出,它直接决定成本量级。
  • 实盘对账:小资金跑几周后,用真实成交明细反推实际成本,回填进回测参数。
最后一条最有价值。实盘跑四到八周后,你会拿到自己账户在自己订单规模下的真实滑点分布,这个数字比任何经验值都准。拿它回填回测参数,之后所有研究的地基都会踏实很多。

什么是常见问题?

回测里滑点设多少算合理?

没有普适值,取决于币种流动性与你的订单规模。研究阶段建议对 BTC、ETH 等主流品种用单边 0.03%–0.05%,中小市值币种用 0.1% 以上,并额外跑一次两倍滑点的敏感度测试。若结论在两倍滑点下反转,说明策略余量不足,不应上实盘。

用限价挂单能省下手续费,回测能按 maker 费率算吗?

不建议。限价单存在不成交风险,而未成交的往往正是行情快速走开的那些机会——也就是最赚钱的那批信号。按 maker 建模会同时低估成本和高估成交率,双重乐观。稳妥做法是按 taker 建模,把省下的费用当成实盘的意外收益。

现货策略是不是就不用管资金费率了?

现货没有资金费率,但若使用杠杆或做空,会有借币利息,年化通常在 3%–20% 区间且随行情浮动。逻辑与资金费率相同:持仓时间越长,这项成本占比越高,长周期策略必须计入。

年化成本 365% 这个数字是不是算错了?

没有算错,它是换手率的结果而非亏损率。日均 10 笔往返,每笔往返成本 0.2%,一年 3650 笔,累计手续费支出就达本金的 730%——文中 365% 对应的是单边 0.05% 的口径。这笔钱由每笔交易的毛利来支付,因此关键比较对象是「平均单笔毛利 vs 往返成本」,而不是与年化收益直接相减。

风险提示:量化交易同样存在亏损风险。本站所有策略、信号、收益数据均为历史回测数据,不构成收益承诺,也不构成投资建议。加密货币波动剧烈,请先用小资金验证,并遵守所在地法律法规。

📺 相关视频

Don't apply for quant trading if you can't answer this
Don't apply for quant trading if you can't answer this
量化必答面试题(Coding Jesus)
📚 参考来源
Google AI 优化指南(2026-06更新)

developers.google.com/search/docs/fundamentals/ai-optimization-guide — Google官方对生成式AI搜索优化的指引。

SE Ranking AI引用研究

seranking.com/blog/ai-search-research/ — AI答案引用来源研究(44%引用来自页面前30%)。

量化分析维基百科

en.wikipedia.org/wiki/Quantitative_analysis_(finance) — 量化分析的基础定义与学术脉络。