4. 期限结构指标构建:近月-远月价差、加权期限斜率、期限结构曲率、库存与期限结构的关系

好,咱们进入正题。

前面几章我们把期限结构的基础讲透了,也聊了聊背后的仓储理论。这一章,我带你亲手把这些指标造出来。说白了,就是把市场情绪、供需矛盾这些抽象的东西,变成一行行能跑、能回测的Python代码。

我个人习惯,做量化交易最忌讳的就是「玄学」。你跟我说感觉要涨,我不信。你把近月-远月价差拉出来,把斜率算清楚,把曲率画出来,再跟库存数据一比对——嗯,这时候我才觉得靠谱。

4.1 近月-远月价差:最直接的信号

这个指标最简单,也最暴力。

近月合约价格减去远月合约价格,正的就是Backwardation,负的就是Contango。但这里有个坑——你选哪两个月份?

我建议用「主力连续合约」和「次主力连续合约」。比如铜,主力通常是当月或次月,远月选3个月后的合约。这样价差信号比较稳定,不会因为换月被来回打脸。

# 计算近月-远月价差
def calc_near_far_spread(df, near_col='close_near', far_col='close_far'):
    """
    df: DataFrame,包含近月和远月收盘价
    返回: Series,价差序列
    """
    spread = df[near_col] - df[far_col]
    return spread

# 使用示例
spread = calc_near_far_spread(data)
print(f"最新价差: {spread.iloc[-1]:.2f} 元/吨")
实战小技巧: 我在做沪铝的时候发现,价差绝对值受价格水平影响很大。铜价5万时价差200,和铜价7万时价差200,意义完全不同。建议做「标准化价差」——用价差除以近月价格,得到百分比。

4.2 加权期限斜率:把整条曲线压成一个数

近月-远月价差只用了两个点,信息量有限。加权期限斜率,是把整条期限结构曲线拟合成一条直线,斜率就是这条线的倾斜程度。

怎么算?用线性回归。把合约的到期时间(以月为单位)作为X,价格作为Y,拟合出来的系数就是斜率。

import numpy as np
from sklearn.linear_model import LinearRegression

def calc_term_slope(prices, tenors):
    """
    prices: list,各合约价格
    tenors: list,对应合约的到期时间(月)
    返回: float,斜率值
    """
    X = np.array(tenors).reshape(-1, 1)
    y = np.array(prices)
    model = LinearRegression().fit(X, y)
    slope = model.coef_[0]
    return slope

# 举个例子
prices = [68500, 68200, 67900, 67600]  # 近月到远月
tenors = [1, 2, 3, 4]  # 1个月到4个月
slope = calc_term_slope(prices, tenors)
print(f"期限斜率: {slope:.2f} 元/月")

斜率正数,说明远月更贵,市场看涨远期(Contango)。斜率负数,说明近月更贵,市场看涨近期(Backwardation)。

嗯,这里要注意:斜率的大小本身也有意义。斜率从-50变成-20,说明Backwardation在缓解,可能是个反转信号。我曾在锌的交易中吃过这个甜头。

4.3 期限结构曲率:捕捉曲线的「弯腰」程度

斜率告诉你曲线往哪边倾斜,曲率告诉你曲线弯不弯。

你想想看,有时候近月价格很高,远月价格也很高,但中间月份价格偏低——这就是典型的「U型」曲线。这种结构往往意味着近端供应紧张,远端预期宽松,中间在博弈。

曲率的计算,我习惯用二次项拟合。在回归方程里加一个到期时间的平方项,它的系数就是曲率。

def calc_term_curvature(prices, tenors):
    """
    计算期限结构曲率
    返回: (slope, curvature) 元组
    """
    X = np.array(tenors).reshape(-1, 1)
    X2 = np.array(tenors).reshape(-1, 1) ** 2
    X_poly = np.hstack([X, X2])
    
    model = LinearRegression().fit(X_poly, prices)
    slope = model.coef_[0]
    curvature = model.coef_[1]
    return slope, curvature

# 示例
slope, curvature = calc_term_curvature(prices, tenors)
print(f"斜率: {slope:.2f}, 曲率: {curvature:.4f}")
核心逻辑: 曲率为正,曲线向上凸(U型);曲率为负,曲线向下凹(倒U型)。正曲率+负斜率,往往是库存极低、近月逼仓的典型特征。

4.4 库存与期限结构的关系:验证信号真伪

指标造出来了,但光看价格曲线还不够。我吃过最大的亏,就是只看期限结构不看库存。

有一次,铜的期限结构显示强烈的Backwardation,我直接做多近月。结果呢?库存其实在悄悄累积,Backwardation只是暂时的交割品不足,不是真正的供需紧张。后来价格暴跌,我被狠狠教育了一顿。

从那以后,我养成了一个习惯:把期限结构指标和库存数据放在一起看。

期限结构状态 库存变化 信号含义 交易建议
Backwardation(价差为正) 库存下降 真实供需紧张 做多近月,或做多价差
Backwardation(价差为正) 库存上升 可能是逼仓或结构性问题 谨慎,等待库存拐点
Contango(价差为负) 库存上升 真实供需宽松 做空近月,或做空价差
Contango(价差为负) 库存下降 可能是远期悲观过度 关注反转机会

怎么把库存数据整合进来?我一般会算一个「库存-价差偏离度」指标:

def calc_inventory_spread_divergence(spread, inventory, window=20):
    """
    计算库存与价差的偏离度
    正数表示价差相对于库存偏高,负数表示偏低
    """
    spread_z = (spread - spread.rolling(window).mean()) / spread.rolling(window).std()
    inv_z = (inventory - inventory.rolling(window).mean()) / inventory.rolling(window).std()
    divergence = spread_z - inv_z
    return divergence
避坑指南: 我曾经用LME的库存数据直接对上期所的价格,结果发现两者根本不匹配。不同交易所的库存统计口径不同,交割品牌也不同。一定要用同一交易所、同一品种的库存数据。

4.5 知识体系总览

下面这张图,是我做这套指标时的整体思路。你可以把它当成一个检查清单:

期限结构指标构建 · 知识体系 期限结构指标体系 近月-远月价差 加权期限斜率 期限结构曲率 库存与期限结构 主力-次主力 标准化处理 线性回归 斜率信号 二次项拟合 U型/倒U型 库存变化方向 偏离度指标 四个指标交叉验证,构建完整交易信号

你看,这四个指标不是孤立的。近月-远月价差给你方向,斜率给你趋势强度,曲率告诉你市场结构是否健康,库存数据帮你验证信号真伪。四个指标交叉验证,胜率才能上去。

我个人习惯,每天开盘前花5分钟跑一遍这四个指标。如果四个指标方向一致,那就是重仓信号。如果出现分歧,比如价差看多但库存看空,那就减仓观望。

好了,指标造出来了,下一章我们聊聊怎么用这些指标构建具体的交易策略。记住,工具再好,用不对也是白搭。


专注资料整理