3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
构建期货的近远期差价因子(通常被称为期限结构因子或展期收益率因子)是商品期货量化策略中非常经典且有效的方法。这个因子的核心逻辑在于捕捉现货溢价(Backwardation)或期货溢价(Contango)的状态。
针对你提到的“合约时间间隔不同,如何选择近月和远月合约”的问题,在实际量化投研中,通常有以下几种主流的处理方案:
由于不同品种的活跃合约月份分布不同(例如螺纹钢通常是1、5、10月活跃,而农产品可能是1、5、9月),直接固定月份做差是不可行的。动态选择合约的常见方案有:
在 JoinQuant 平台上,我们可以利用 get_dominant_future 获取主力合约,利用 get_future_contracts 获取所有合约列表,从而动态定位近月和远月合约。
以下是基于**“主力合约(近月)与主力后第一个合约(远月)”**构建周收益率差价因子的完整 Python 代码示例,你可以将其放在 JoinQuant 的研究环境中运行:
from jqdata import *
import pandas as pd
import numpy as np
import datetime
def get_term_structure_factor(underlying_symbol, date):
"""
计算指定日期某期货品种的近远期差价因子
:param underlying_symbol: 期货品种代码,如 'RB' (螺纹钢)
:param date: 计算日期
:return: 因子值 (近月周收益率 - 远月周收益率)
"""
# 1. 获取当天该品种的所有可交易合约
contracts = get_future_contracts(underlying_symbol, date)
if len(contracts) < 2:
return np.nan
# 2. 获取当天的主力合约作为“近月合约”
dominant = get_dominant_future(underlying_symbol, date)
if not dominant:
return np.nan
# 3. 对合约按交割月份进行排序
# JoinQuant的合约代码格式如 'RB1905.XSGE',直接字符串排序即可按时间先后排列
contracts = sorted(contracts)
try:
dom_idx = contracts.index(dominant)
# 4. 寻找远月合约:取主力合约之后的下一个合约
if dom_idx + 1 < len(contracts):
far_contract = contracts[dom_idx + 1]
else:
return np.nan # 主力已经是最后一个合约,无法计算
except ValueError:
return np.nan
# 5. 获取这两个合约过去一周(5个交易日)的收盘价
# count=6 是为了获取 5天前的价格 和 当天的价格
prices = get_price([dominant, far_contract], end_date=date, count=6, fields=['close'], panel=False)
if prices.empty:
return np.nan
try:
# 提取近月和远月的价格序列
dom_prices = prices[prices['code'] == dominant]['close'].values
far_prices = prices[prices['code'] == far_contract]['close'].values
# 确保数据长度足够
if len(dom_prices) < 6 or len(far_prices) < 6:
return np.nan
# 6. 计算周收益率 (当天价格 / 5天前价格 - 1)
dom_return = dom_prices[-1] / dom_prices[0] - 1
far_return = far_prices[-1] / far_prices[0] - 1
# 7. 计算因子值:近月收益率 - 远月收益率
factor_value = dom_return - far_return
return factor_value
except Exception as e:
return np.nan
# ================= 测试代码 =================
# 获取螺纹钢(RB)在过去一段时间的因子值
test_dates = get_trade_days(start_date='2023-01-01', end_date='2023-01-31')
factor_results = []
for d in test_dates:
val = get_term_structure_factor('RB', d)
factor_results.append({'date': d, 'factor_value': val})
df_factor = pd.DataFrame(factor_results)
print(df_factor.head())
(近月价格/远月价格 - 1) * (365 / 两个合约交割日期的天数差)。这被称为年化展期收益率,在横截面多品种比较时更为科学。get_dominant_future 返回的合约会突变。如果你计算的是“过去5天的收益率”,在换月当天,你获取的“当前主力合约”在5天前可能流动性极差,导致5天前的价格失真。解决方案:在计算收益率时,确保使用的价格序列在过去5天内都有充足的成交量,或者在换月期间平滑过渡。get_price 获取多个合约数据时,注意 panel=False 返回的是 DataFrame,需要按 code 过滤出各自的价格序列,确保近远月价格在时间上是一一对应的。