《基于商品期货期限结构的交易策略》总结教程并提供一个基于核心思想的Python策略示例

好的,我们来对中信期货的这份《基于商品期货期限结构的交易策略》报告进行说明来源、深度解析、总结教程,并提供一个基于核心思想的Python策略示例。

目录

  1. 报告来源说明
  2. 报告深度解析
    • 2.1 核心概念:商品期货期限结构与展期收益率
    • 2.2 基础策略:基于展期收益率的多空组合
    • 2.3 改进策略:结合动量因子的尝试
      • 2.3.1 双因子打分策略 (TS-Mom1)
      • 2.3.2 双重分组策略 (TS-Mom2)
    • 2.4 核心结论
  3. 策略总结教程
    • 3.1 理论基础
    • 3.2 策略步骤(基础版TS策略)
    • 3.3 关键参数与注意事项
  4. Python策略示例(基础版TS策略)
    • 4.1 策略逻辑
    • 4.2 示例代码
    • 4.3 代码说明与扩展提示
  5. 总结与讨论

1. 报告来源说明

  • 发布机构: 中信期货有限公司 (CITIC Futures Company Limited)
  • 报告类型: 量化专题报告 (Quantitative Special Report)
  • 报告标题: 基于商品期货期限结构的交易策略
  • 发布日期: 2017年12月1日
  • 主要作者: 刘宾、王建伟 等 (中信期货研究咨询部量化组)
  • 核心内容: 该报告旨在研究商品期货的期限结构,利用展期收益率定义该结构,并构建基于此的多空对冲策略。同时,报告还探讨了将动量因子与期限结构因子结合的效果。

2. 报告深度解析

2.1 核心概念:商品期货期限结构与展期收益率

  • 期限结构 (Term Structure): 指同一商品、不同到期月份的期货合约价格与其到期期限之间的关系。它反映了市场对未来供需关系、持有成本、风险溢价等的预期。
    • 远月贴水 (Backwardation): 远期合约价格低于近期合约价格。通常意味着近期供应偏紧或持有成本为负(便利收益高)。
    • 远月升水 (Contango): 远期合约价格高于近期合约价格。通常意味着近期供应充足或持有成本较高(如仓储、资金成本)。
  • 展期收益率 (Roll Yield / Roll Return): 报告采用展期收益率来量化期限结构。其计算公式为:
    Rt = [ln(Pt,n) - ln(Pt,d)] * (365 / (Nt,d - Nt,n))
    • Pt,n: t时刻近月合约价格
    • Pt,d: t时刻远月合约价格
    • Nt,n: t时刻近月合约距离到期日天数
    • Nt,d: t时刻远月合约距离到期日天数
    • 解读: 这个指标衡量了近、远月合约价格差异相对于时间差异的年化比率。
      • Rt > 0: 意味着 ln(Pt,n) > ln(Pt,d)(忽略时间项的微小影响),即近月价格高于远月价格,对应远月贴水 (Backwardation)。理论上,做多这种结构的品种,在合约展期时能获得正收益(低买高卖远近合约)。
      • Rt < 0: 意味着 ln(Pt,n) < ln(Pt,d),即近月价格低于远月价格,对应远月升水 (Contango)。理论上,做空这种结构的品种,在合约展期时能获得正收益(高卖低买远近合约)。
      • |Rt| 绝对值越大,表示贴水或升水程度越深。

2.2 基础策略:基于展期收益率的多空组合 (TS策略)

  • 理论基础: Keynes 和 Cootner 的理论认为,期限结构反映了套期保值者的净头寸方向,投机者通过承担风险来平衡市场并获取回报。Backwardation 市场(生产商空头套保为主)吸引投机者做多,Contango 市场(消费者多头套保为主)吸引投机者做空。展期收益率可以作为这种预期回报的代理变量。
  • 策略步骤:
    1. 选定品种池: 报告选取了32个流动性较好的国内商品期货品种。
    2. 计算因子: 计算每个品种当前的展期收益率 Rt
    3. 排序分组: 将所有品种按 Rt 从高到低排序。
    4. 构建组合:
      • 多头: 做多 Rt 排名最高的 1/3 品种。
      • 空头: 做空 Rt 排名最低的 1/3 品种。
    5. 资金分配: 多空组合内部采用等权重分配资金。
    6. 杠杆与风控: 使用20%保证金(约5倍杠杆),剩余资金不投资。
    7. 调仓周期: 每隔 H 个交易日,重复步骤 2-6 进行调仓。
    8. 手续费: 考虑 3%% (万分之三) 的双边手续费。
  • 回测结果:
    • 回测区间:2009年1月1日 - 2017年10月31日。
    • 不同调仓周期 H 下均能获得显著超额收益。
    • 最优参数: H = 60 天时表现最佳,年化收益率 16.48%,信息比率 1.23,最大回撤 17.43%。
    • 结论:该基础策略证明了利用商品期货期限结构信息构建多空组合是有效的。

2.3 改进策略:结合动量因子的尝试

报告进一步研究了将市场中常见的动量效应(价格上涨的品种倾向于继续上涨,下跌的继续下跌)与期限结构策略结合的效果。

2.3.1 双因子打分策略 (TS-Mom1)

  • 因子定义:
    • 动量因子:主力合约过去 L 日的收益率。
    • 期限结构因子:当日主力合约的展期收益率 Rt
  • 策略步骤:
    1. 计算每个品种的动量因子值和期限结构因子值。
    2. 分别对两个因子进行排序(或标准化打分)。
    3. 将两个因子的得分(或排名)等权重相加,得到每个品种的总分。
    4. 按总分从高到低排序。
    5. 做多总分最高的 1/3 品种,做空总分最低的 1/3 品种。
    6. 等权分配,H 日调仓,相同杠杆和手续费。
  • 回测结果:
    • 策略表现对参数 LH 非常敏感。
    • 最佳表现出现在 H=80, L=100 时,年化收益 13.19%,信息比率 0.91。
    • 结论: 该策略表现劣于基础的 TS 策略,且稳定性差。简单地将两个因子得分相加未能有效改善策略效果,甚至可能引入噪音。

2.3.2 双重分组策略 (TS-Mom2)

  • 策略逻辑: 试图筛选出期限结构和动量方向一致的品种。例如,做多那些既处于 Backwardation(Rt高)同时价格也在上涨(动量高)的品种;做空那些既处于 Contango(Rt低)同时价格也在下跌(动量低)的品种。
  • 策略步骤:
    1. 计算动量因子(L日收益率)和期限结构因子(Rt)。
    2. 第一次分组: 按展期收益率 Rt 将品种分为两组:高 Rt 组(例如前50%)和低 Rt 组(例如后50%)。
    3. 第二次分组 (组内排序):
      • 在高 Rt 组内,按动量因子从高到低排序,选取动量最高的 1/3 作为多头组合。
      • 在低 Rt 组内,按动量因子从高到低排序,选取动量最低的 1/3 作为空头组合。
    4. 等权分配,H 日调仓,相同杠杆和手续费。
  • 回测结果:
    • 策略表现显著优于 TS-Mom1 策略,且对参数敏感度有所降低。
    • 最佳表现出现在 L=20, H=5 时,年化收益 17.36%,信息比率 1.14,最大回撤 18.54%。
    • 结论: 该策略的年化收益率略高于基础 TS 策略 (17.36% vs 16.48%),但信息比率略低 (1.14 vs 1.23),且波动率和最大回撤有所增加。这表明双重分组方法能提升绝对收益,但风险调整后的收益并未超越单纯的期限结构策略。原因可能在于动量因子本身波动较大。

2.4 核心结论

  1. 商品期货的期限结构蕴含丰富的市场信息,可以通过展期收益率量化。
  2. 基于展期收益率构建的多空对冲策略(做多高 Rt,做空低 Rt)能够长期获得显著的超额收益 (Alpha)。
  3. 将动量因子与期限结构因子结合:
    • 简单的双因子打分方式 (TS-Mom1) 效果不佳,甚至可能劣化表现。
    • 双重分组方式 (TS-Mom2) 可以在一定程度上提升年化收益率,但同时也放大了波动和回撤,风险调整后收益并未超越基础 TS 策略。
  4. 总体而言,期限结构因子本身是一个强大且有效的 Alpha 来源。

3. 策略总结教程

本教程基于报告中的基础版 TS 策略。

3.1 理论基础

利用商品期货近远月合约的价差(期限结构)来预测未来收益。相信高展期收益率(Backwardation)的品种未来倾向于上涨(或展期带来正收益),低展期收益率(Contango)的品种未来倾向于下跌(或展期带来负收益)。通过做多前者、做空后者来构建市场中性(理想情况下)的投资组合,赚取 Alpha。

3.2 策略步骤(基础版TS策略)

  1. 确定投资宇宙: 选择一组流动性较好的商品期货品种(如报告中的32个)。
  2. 获取数据: 在每个调仓日 t,获取所有品种的:
    • 近月合约收盘价 (Pt,n)
    • 远月合约收盘价 (Pt,d)
    • 近月合约剩余到期天数 (Nt,n)
    • 远月合约剩余到期天数 (Nt,d)
    • 注意: 近月/远月合约的选择需要一致的标准,例如选择流动性最好的两个合约,或者固定选择第一、第二(或更远)交割月份的合约,并处理好合约换月问题。
  3. 计算展期收益率 (Roll Yield): 对每个品种,使用公式 Rt = [ln(Pt,n) - ln(Pt,d)] * (365 / (Nt,d - Nt,n)) 计算 Rt
  4. 排序: 将所有品种按照计算得到的 Rt 从高到低进行排序。
  5. 分组:
    • 多头组: 选出 Rt 最高的 N/3 个品种 (N为品种总数)。
    • 空头组: 选出 Rt 最低的 N/3 个品种。
  6. 下单/持仓调整:
    • 根据多头组和空头组名单,调整持仓。
    • 资金分配: 在多头组合内部和空头组合内部,通常采用等权重分配资金。即,如果总资金为 M,保证金比例为 P,则多头总名义价值为 M / (2 * P),空头总名义价值也为 M / (2 * P)。每个多头品种分配 (M / (2 * P)) / (N/3) 的名义价值,每个空头品种也类似。
  7. 持仓: 保持仓位,直到下一个调仓日。
  8. 重复: 每隔 H 个交易日(如报告中的60天),重复步骤 2-7。

3.3 关键参数与注意事项

  • 品种选择: 流动性是关键,避免无法成交或冲击成本过大。
  • 近/远月合约定义: 需要明确且一致的规则,并处理好主力合约换月时的因子计算和持仓切换。报告未详述具体合约选择方法,实际操作中需仔细定义。
  • 调仓周期 (H): 报告显示 H=60 较优,但历史最优不代表未来。可根据市场情况或进一步研究调整。周期太短会增加交易成本,太长可能错过信息变化。
  • 分组比例: 报告使用 1/3,也可以测试其他比例(如 1/4, 1/5)。
  • 资金管理/杠杆: 报告使用 20% 保证金(5倍杠杆),风险较高。实际应用中需根据自身风险承受能力调整。
  • 交易成本: 必须考虑手续费和滑点。
  • 数据质量: 准确的收盘价和到期日信息至关重要。

4. Python策略示例(基础版TS策略)

这是一个简化的概念性示例,演示核心逻辑,省略了真实交易中的许多复杂细节(如数据获取、合约选择、换月处理、实际下单接口、滑点等)。

4.1 策略逻辑

  1. 模拟时间循环。
  2. 在每个调仓日:
    • 获取模拟的各品种近/远月价格和到期天数。
    • 计算所有品种的展期收益率。
    • 排序并确定做多和做空的品种列表。
    • (可选)打印或记录当期持仓。

4.2 示例代码

import pandas as pd
import numpy as np

def calculate_roll_yield(near_price, far_price, near_days_to_expiry, far_days_to_expiry):
    """
    计算展期收益率 (Roll Yield)
    Args:
        near_price (float): 近月合约价格
        far_price (float): 远月合约价格
        near_days_to_expiry (int): 近月合约剩余到期天数
        far_days_to_expiry (int): 远月合约剩余到期天数
    Returns:
        float: 年化展期收益率, 如果分母为0或负数则返回NaN
    """
    time_diff = far_days_to_expiry - near_days_to_expiry
    if time_diff <= 0:
        return np.nan # 避免除以0或负数

    # 使用对数价格计算,更符合金融习惯
    log_price_diff = np.log(near_price) - np.log(far_price)

    # 年化
    roll_yield = log_price_diff * (365.0 / time_diff)
    return roll_yield

def get_simulated_data(date, commodities):
    """
    模拟获取指定日期的数据
    Args:
        date (pd.Timestamp): 当前模拟日期
        commodities (list): 商品列表
    Returns:
        pd.DataFrame: 包含价格和到期天数的数据框
                      Columns: ['near_price', 'far_price', 'near_dte', 'far_dte']
                      Index: commodities
    """
    # --- 这是模拟数据生成部分,真实应用中需要替换为实际数据接口 ---
    data = {}
    base_near_dte = 30 # 假设近月合约基准剩余30天
    base_far_dte = 90  # 假设远月合约基准剩余90天

    for comm in commodities:
        # 模拟价格和到期天数,加入随机性
        # 模拟 Backwardation (近>远) 和 Contango (近<远)
        price_ratio = np.random.uniform(0.95, 1.05) # 近/远价比率
        far_p = 4000 + np.random.randn() * 100 # 模拟远月价格
        near_p = far_p * price_ratio
        near_dte = max(1, base_near_dte + np.random.randint(-5, 5)) # 保证dte > 0
        far_dte = max(near_dte + 1, base_far_dte + np.random.randint(-10, 10)) # 保证 far_dte > near_dte

        data[comm] = {
            'near_price': near_p,
            'far_price': far_p,
            'near_dte': near_dte,
            'far_dte': far_dte
        }
    # --------------------------------------------------------------------
    return pd.DataFrame.from_dict(data, orient='index')


# --- 策略参数 ---
commodity_list = ['螺纹钢', '热卷', '铁矿石', '焦煤', '焦炭', '沪铜', '沪铝', '沪锌', '沪镍', '黄金', '白银', '豆粕', '玉米', '郑油', '棕榈油', 'PTA', '橡胶', '沥青'] # 示例品种
holding_period = 60 # 持仓周期 (交易日)
portfolio_size_ratio = 1/3 # 做多/做空组合占总品种数的比例

# --- 模拟回测 ---
start_date = pd.to_datetime('2010-01-01')
end_date = pd.to_datetime('2011-12-31') # 模拟运行两年
trade_dates = pd.date_range(start_date, end_date, freq='B') # 假设交易日为工作日

rebalance_dates = trade_dates[::holding_period] # 每隔 holding_period 天进行调仓

portfolio_log = {} # 记录每个调仓日的持仓

for current_date in trade_dates:
    if current_date in rebalance_dates:
        print(f"--- Rebalancing on {current_date.strftime('%Y-%m-%d')} ---")

        # 1. 获取数据
        current_data = get_simulated_data(current_date, commodity_list)
        # print("Current Market Data:")
        # print(current_data)

        # 2. 计算展期收益率
        current_data['roll_yield'] = current_data.apply(
            lambda row: calculate_roll_yield(row['near_price'], row['far_price'], row['near_dte'], row['far_dte']),
            axis=1
        )
        # print("\nCalculated Roll Yields:")
        # print(current_data['roll_yield'].sort_values(ascending=False))


        # 3. 排序和分组
        # 剔除无法计算展期收益率的品种
        valid_data = current_data.dropna(subset=['roll_yield'])
        if valid_data.empty:
            print("Warning: No valid roll yield data available.")
            long_list = []
            short_list = []
        else:
            sorted_data = valid_data.sort_values(by='roll_yield', ascending=False)
            n_commodities = len(sorted_data)
            group_size = max(1, int(n_commodities * portfolio_size_ratio)) # 每组至少1个

            long_list = sorted_data.head(group_size).index.tolist()
            short_list = sorted_data.tail(group_size).index.tolist()

        print(f"\nLong Portfolio ({len(long_list)}): {long_list}")
        print(f"Short Portfolio ({len(short_list)}): {short_list}")

        # 记录当期持仓
        portfolio_log[current_date] = {'long': long_list, 'short': short_list}

    # (在实际回测中,这里需要根据持仓计算每日损益 PnL)
    pass

print("\n--- Simulation Finished ---")
# print("\nPortfolio Log:")
# print(portfolio_log)

4.3 代码说明与扩展提示

  • calculate_roll_yield 函数: 实现了报告中的展期收益率公式。注意处理了分母(时间差)为零或负数的情况。
  • get_simulated_data 函数: 这是关键的模拟部分。它生成了随机的、符合基本逻辑(如远月到期日晚于近月)但没有真实市场模式的价格和到期日数据。在实际应用中,必须替换为可靠的数据源接口,获取真实的近月/远月合约价格和到期日。
  • 主循环: 模拟按交易日推进时间。
  • 调仓逻辑: 在预设的调仓日 (rebalance_dates) 执行:获取数据 -> 计算因子 -> 排序 -> 分组(确定多空名单)。
  • 简化:
    • 没有计算 PnL、净值曲线、各项绩效指标(年化收益、波动率、夏普比率、最大回撤等)。
    • 没有处理合约换月(这在真实期货策略中至关重要)。当近月合约即将到期时,需要将因子计算和持仓转移到新的近月/远月合约对上。
    • 没有考虑保证金、杠杆、交易成本、滑点。
    • 品种列表是固定的,实际中可能需要根据流动性动态调整。
    • 近月/远月的定义是模糊的(通过模拟数据随意指定),实际需要明确规则。
  • 扩展方向:
    • 接入真实历史数据源 (如 Wind, Tushare, 米筐, UQER 等)。
    • 实现详细的合约选择和换月逻辑。
    • 构建完整的回测框架,计算净值、收益、风险指标。
    • 加入交易成本和滑点模拟。
    • 实现资金管理和风险控制模块(如杠杆控制、止损)。
    • 尝试报告中的 TS-Mom2 策略(增加动量计算和双重排序逻辑)。

5. 总结与讨论

中信期货的这份报告清晰地展示了商品期货期限结构作为一个有效的 Alpha 来源,其核心逻辑在于利用市场对未来供需和持有成本的预期差进行交易。基于展期收益率的基础多空策略在历史回测中表现稳健。

虽然结合动量因子的尝试(尤其是双重分组)能在特定参数下提升绝对收益,但也增加了策略的复杂性和风险。这提示我们,因子叠加并非总能带来 1+1>2 的效果,需要仔细验证其有效性和稳健性。

对于量化交易者而言,这份报告提供了一个有价值的策略思路。要将其转化为实盘策略,关键在于处理好数据获取、合约选择与换月、交易成本、风险控制等细节问题。提供的 Python 示例代码可以作为一个起点,帮助理解核心逻辑,但距离实盘应用还有很长的路要走。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值