4、成本归因基础:交易成本分解、冲击成本、滑点成本、佣金与税费

做量化策略,很多人上来就盯着Alpha、夏普比率。但我得说一句大实话:交易成本才是吃掉利润的隐形杀手。尤其是做商品期货,杠杆高、频率快,成本稍微没算准,回测里漂亮的曲线,实盘直接变成心电图。

我个人习惯,在搭建任何策略之前,先把成本模型搭好。说白了,你赚的钱,有一半可能是给交易所和滑点打工的。今天我们就来拆解一下,交易成本到底由哪些部分构成。

交易成本归因框架 总交易成本 显性成本 佣金 + 税费 + 交割费 冲击成本 订单簿深度 × 成交量 滑点成本 延迟 + 流动性不足 隐性成本 机会成本 + 市场影响 虚线表示隐性成本难以精确测量,需用模型估算

4.1 交易成本分解:别小看每一笔

交易成本可以分成两大类:显性成本隐性成本。显性成本就是你直接付出去的钱,比如佣金、印花税、过户费。隐性成本则更隐蔽——冲击成本、滑点、延迟成本,这些在回测里很容易被忽略。

我记得有一次帮朋友复盘一个螺纹钢的日内策略,回测年化收益30%,实盘跑了两个月只剩8%。一查,问题全出在成本上。回测时我用了固定滑点1跳,但实盘里遇到行情剧烈波动,滑点经常跑到3-4跳。这就是典型的隐性成本没算够。

核心公式:
总交易成本 = 佣金 + 税费 + 冲击成本 + 滑点成本 + 持仓成本(隔夜利息/仓储费)

4.2 冲击成本:你的订单就是市场的噪音

冲击成本,说白了就是你的订单对市场价格造成的影响。你买得越多,价格被你推得越高;你卖得越多,价格被你砸得越低。这个成本在回测里是算不出来的,因为回测假设你的订单不影响市场。

我一般用这个公式估算冲击成本:

# 冲击成本估算模型(基于订单簿深度)
def impact_cost(volume, avg_depth, spread):
    """
    volume: 你的交易量(手)
    avg_depth: 订单簿前5档平均深度(手)
    spread: 当前买卖价差(tick)
    """
    impact_ratio = volume / (avg_depth * 5)  # 超过5档深度就算大单
    cost = impact_ratio * spread * 0.5       # 线性近似
    return min(cost, spread * 2)             # 上限设为2个spread

嗯,这里要注意:冲击成本不是线性的。小单子几乎没影响,但一旦你的单子超过了订单簿第一档的深度,价格就会开始往不利方向移动。我在做铁矿石策略时,发现只要单笔超过50手,冲击成本就开始显著上升。

我的经验: 对于流动性好的品种(螺纹、铁矿、PTA),冲击成本可以按0.5-1个tick估算。对于流动性差的品种(比如某些冷门化工品),冲击成本可能高达3-5个tick。建议先用历史订单簿数据回测一下。

4.3 滑点成本:你看到的价,不是你成交的价

滑点成本跟冲击成本有点像,但本质不同。滑点是因为延迟流动性不足导致的成交价格偏离。你下单的时候看到买一价是5000,等你的单子到了交易所,买一可能已经变成5002了。

为什么会这样?因为网络延迟、交易所撮合排队、对手方撤单。尤其是在快市行情下,滑点会急剧放大。

我曾经做过一个测试:在橡胶期货上,用市价单下单100手,统计了1000次交易。结果发现,平均滑点达到1.8个tick,最大滑点达到7个tick。这个数据让我重新审视了策略的止损逻辑——如果止损单触发时滑点太大,止损就变成了摆设。

品种 平均滑点(tick) 最大滑点(tick) 建议回测滑点
螺纹钢 0.8 3 1
铁矿石 1.2 5 1.5
PTA 0.6 2 1
沪铜 1.5 6 2
避坑指南: 我曾经在回测中只设了1个tick的滑点,结果实盘时遇到行情跳空,滑点直接飙到10个tick。建议在回测中至少设置2-3个tick的保守滑点,尤其是对于高频策略。

4.4 佣金与税费:看似小钱,积少成多

佣金和税费是显性成本,相对容易计算。但很多人会忽略一个细节:不同期货公司的佣金标准不一样,而且可以谈。

我个人的习惯是,在策略开发阶段就按交易所标准的1.5倍来算佣金。为什么?因为实盘时你拿到的佣金可能比交易所标准高,而且还有各种杂费(比如交割费、仓单费)。

商品期货的主要费用包括:

  • 交易手续费: 按成交金额的万分之几收取,不同品种差异很大。比如螺纹钢是万分之一,沪铜是万分之零点五。
  • 印花税: 商品期货目前没有印花税,但股指期货有。
  • 交割费: 如果你持仓进入交割月,需要缴纳交割费。对于投机策略,建议在交割月前平仓。
  • 仓储费/持仓费: 部分品种有隔夜持仓费,比如原油、燃料油。
# 佣金与税费计算示例
def calc_trade_cost(price, volume, commission_rate=0.0001):
    """
    price: 成交价格
    volume: 成交量(手)
    commission_rate: 手续费率(默认万分之一)
    """
    turnover = price * volume * 10  # 假设每手10吨
    commission = turnover * commission_rate
    # 商品期货无印花税
    total_cost = commission
    return total_cost
关键提醒: 对于高频策略(每天交易10次以上),佣金成本会迅速累积。假设每手佣金5元,每天交易100手,一个月就是1.5万元。这笔钱在回测里可能只是一个小数字,但在实盘里就是实打实的利润流失。

4.5 综合成本模型:把一切串起来

好了,现在我们把所有成本串成一个完整的模型。我个人习惯在策略回测中,直接用一个函数来计算每笔交易的总成本:

def total_cost_model(price, volume, side, market_depth, spread, latency_ms):
    """
    综合交易成本模型
    side: 'buy' or 'sell'
    market_depth: 订单簿前5档平均深度
    spread: 当前价差(tick)
    latency_ms: 网络延迟(毫秒)
    """
    # 1. 显性成本
    commission = price * volume * 10 * 0.0001  # 万分之一手续费
    tax = 0  # 商品期货无印花税
    
    # 2. 冲击成本
    impact_ratio = volume / (market_depth * 5)
    impact = impact_ratio * spread * 0.5
    impact = min(impact, spread * 2)
    
    # 3. 滑点成本(基于延迟和流动性)
    slippage_base = 0.5 * spread  # 基础滑点
    latency_factor = latency_ms / 100  # 每100ms延迟增加0.5个tick滑点
    slippage = slippage_base + latency_factor * 0.5 * spread
    
    # 4. 总成本(以价格单位表示)
    total_cost_per_unit = commission / (volume * 10) + impact + slippage
    return total_cost_per_unit

这个模型虽然简单,但已经能覆盖大部分场景。你想想看,如果回测时连这些成本都没算进去,那出来的结果基本就是自欺欺人。

我的建议: 在策略开发初期,先用一个保守的成本模型(比如固定2个tick滑点 + 万分之一手续费)。等策略跑通了,再根据实盘数据逐步优化成本参数。别一开始就追求精确,先保证不亏钱。

最后说一句:成本归因不是一次性的工作。随着市场环境变化,流动性、波动率、佣金政策都会变。我每季度都会重新评估一次成本模型,看看有没有需要调整的地方。毕竟,赚到的钱,只有装进口袋的才是真的


专注资料整理