第26章 基差交易的绩效归因:Brinson归因、因子归因、交易成本归因、策略改进方向

做基差交易的朋友,最怕什么?

怕赚了钱不知道为啥赚,亏了钱不知道为啥亏。

我见过太多人,回测曲线漂亮得不行,实盘一跑就变形。为什么?因为绩效归因没做好。你连钱是怎么来的都不清楚,怎么敢上仓位?

这一章,我们就来拆解基差交易的绩效归因。说白了,就是给策略做「体检」——看看哪些地方做对了,哪些地方在拖后腿。

26.1 Brinson归因:拆解超额收益的来源

Brinson归因最早用在股票组合上,但用在基差交易里,一样好使。

它的核心逻辑很简单:把总收益拆成三部分——配置收益、选券收益、交互收益。

基差交易中的Brinson三因子:

  • 配置收益:你选择做多哪个品种、做空哪个品种带来的收益
  • 选券收益:同一品种内,你选的具体合约带来的超额
  • 交互收益:配置和选券的交叉影响

举个例子。你同时做多IC主力合约、做空IF主力合约。如果IC涨得比IF多,配置收益就是正的。但如果你选的是IC次月合约而不是主力合约,次月合约涨得更多,那这部分就是选券收益。

我个人习惯用Python写一个简单的Brinson分解函数。代码不长,但很实用:

def brinson_decomposition(portfolio_returns, benchmark_returns, 
                          portfolio_weights, benchmark_weights):
    """
    基差交易的Brinson归因
    portfolio_returns: 组合各品种收益率
    benchmark_returns: 基准各品种收益率
    """
    # 配置收益
    allocation = (portfolio_weights - benchmark_weights) * benchmark_returns
    # 选券收益
    selection = benchmark_weights * (portfolio_returns - benchmark_returns)
    # 交互收益
    interaction = (portfolio_weights - benchmark_weights) * \
                  (portfolio_returns - benchmark_returns)
    
    return {
        'allocation': allocation.sum(),
        'selection': selection.sum(),
        'interaction': interaction.sum(),
        'total': (allocation + selection + interaction).sum()
    }

嗯,这里要注意:基准怎么选?我一般用「等权做多所有品种」作为基准。这样配置收益就能反映出你主动偏离基准的能力。

26.2 因子归因:找到驱动收益的底层逻辑

Brinson归因告诉你「赚了多少钱」,因子归因告诉你「为什么赚」。这是两个层次的问题。

基差交易的因子归因,我通常关注这几个因子:

因子名称 含义 计算方式
基差动量因子 基差趋势的延续性 过去N日基差变化率
基差均值回复因子 基差偏离历史均值的程度 当前基差 - 历史均值
波动率因子 基差波动带来的交易机会 基差标准差
流动性因子 合约流动性对滑点的影响 持仓量/成交量

我在项目中遇到过这样的情况:一个基差策略回测年化收益20%,但因子归因一做,发现80%的收益来自基差动量因子。这意味着什么?意味着策略本质上就是个趋势跟踪策略。一旦基差趋势反转,策略就会大幅回撤。

因子归因的代码实现,我习惯用线性回归:

import statsmodels.api as sm

def factor_attribution(returns, factor_data):
    """
    returns: 策略日收益率序列
    factor_data: 各因子暴露度 DataFrame
    """
    X = sm.add_constant(factor_data)
    model = sm.OLS(returns, X).fit()
    
    # 因子贡献 = 因子暴露 * 因子收益率
    factor_contribution = model.params[1:] * factor_data.mean()
    
    return {
        'factor_contribution': factor_contribution,
        'r_squared': model.rsquared,
        'residual': model.resid.std()
    }

R方很重要。如果R方太低,说明还有重要的因子没抓到。我曾经有个策略R方只有0.3,后来发现是忽略了「交割日效应」这个因子——交割日前后的基差行为完全不同。

避坑指南:因子之间可能存在多重共线性。比如基差动量因子和基差均值回复因子,在趋势行情里相关性很高。做归因前,先算一下因子间的相关系数矩阵。我一般设阈值0.7,超过的就合并或剔除一个。

26.3 交易成本归因:别让手续费吃掉你的利润

交易成本归因,是基差交易里最容易忽略、也最致命的一环。

你想想看,基差交易的利润本来就不厚。一个跨期套利,基差从5个点回归到0,毛利也就5个点。如果双边手续费加滑点吃掉3个点,那实际利润就只剩2个点了。

交易成本归因,我把它拆成三块:

  • 显性成本:手续费、印花税、过户费。这些是固定的,好算。
  • 隐性成本:滑点、冲击成本。这些是变动的,难算。
  • 机会成本:保证金占用、资金成本。这个容易被忽略。

我建议用「实际成交价 vs 理论成交价」的差值来估算滑点。代码实现:

def slippage_analysis(trade_records, theoretical_prices):
    """
    trade_records: 实际成交记录
    theoretical_prices: 理论成交价(如盘口中间价)
    """
    trade_records['slippage'] = abs(
        trade_records['actual_price'] - theoretical_prices
    )
    
    avg_slippage = trade_records['slippage'].mean()
    total_slippage_cost = avg_slippage * trade_records['volume'].sum()
    
    return {
        'avg_slippage_per_trade': avg_slippage,
        'total_slippage_cost': total_slippage_cost,
        'slippage_ratio': total_slippage_cost / trade_records['pnl'].sum()
    }

警告:滑点估算一定要用实盘数据,别用回测数据。回测里的滑点假设往往太乐观。我见过一个策略,回测滑点设了0.5个tick,实盘滑点平均1.8个tick——直接导致策略从盈利变成亏损。

26.4 策略改进方向:从归因结果出发

归因做完了,下一步就是改进。我总结了几条常见的改进路径:

  1. 如果配置收益低:说明品种选择有问题。试试加入更多品种,或者用机器学习做品种筛选。
  2. 如果选券收益低:说明合约选择不够精细。可以考虑加入「主力合约切换」信号,或者做跨期价差的动态调整。
  3. 如果因子归因R方低:说明还有重要因子没抓到。试试加入「市场情绪因子」或「资金流向因子」。
  4. 如果交易成本占比高:降低交易频率,或者改用限价单代替市价单。

我个人最常用的是「分层改进法」:先改成本最高的那块,再改次高的。别想着一次把所有问题都解决,那样反而容易顾此失彼。

举个例子。我有个学生做螺纹钢基差交易,归因后发现交易成本占了总利润的60%。他第一反应是优化策略参数,想提高胜率。我说别急,先把成本降下来。后来他把交易频率从每天10次降到每天3次,滑点成本直接砍了一半。策略从亏损变成了微利。

你看,有时候改进方向不在策略本身,而在执行层面。

知识体系总览

下面这张图,把基差交易绩效归因的完整框架画出来了。你可以把它当作一个检查清单——每次复盘策略时,按这个流程走一遍。

基差交易绩效归因框架 策略总收益 Brinson归因 因子归因 交易成本归因 配置收益 选券收益 交互收益 基差动量 均值回复 波动率/流动性 显性成本 隐性成本 机会成本 策略改进方向 归因 → 诊断 → 改进,形成闭环

最后说一句:绩效归因不是一次性工作。我建议每季度做一次全面归因,每月做一次快速归因。市场在变,策略也在变,归因结果能帮你及时发现问题。

嗯,这一章的内容就到这里。归因做得好,策略才能走得远。


公众号:蓝海资料掘金营,微信deep3321