第4章:基差计算引擎:Python实现基差实时计算、主力合约自动识别与切换、跨期价差与跨品种价差
各位同学,欢迎来到基差交易实战的核心环节。前面我们聊了基差的定义、逻辑,还有那些让人头疼的细节。但说一千道一万,最终都得落到代码上。这一章,我们就来亲手搭建一个基差计算引擎。
我个人习惯把这类工具叫做“引擎”,因为它得24小时运转,自动处理各种脏活累活。你想想看,手动算基差?那效率太低了,而且容易出错。尤其是主力合约切换那几天,一个不留神,你的数据就全乱了。
核心目标: 构建一个能自动获取行情、识别主力、计算基差、并处理合约切换的Python模块。
4.1 主力合约自动识别:别让“旧合约”坑了你
做基差交易,第一件事就是搞清楚:当前市场上,哪个合约说了算?
主力合约,说白了就是成交量最大、持仓量最大的那个合约。它流动性最好,滑点最小,也最能代表市场情绪。我见过不少新手,拿着一个冷门合约的基差数据做分析,结果跟实际走势完全对不上——嗯,这里要注意,冷门合约的报价经常失真。
那么,怎么用Python自动识别主力合约呢?
我的做法很简单:取每个品种所有上市合约的持仓量,排序,取第一。 但这里有个坑——有些合约刚上市,持仓量很小,但成交量突然放大,这时候要不要切换?
我曾经在螺纹钢上吃过这个亏。当时系统只按持仓量排序,结果一个远月合约持仓量突然暴增,系统立刻切换了过去。但第二天,那个合约的成交量就萎缩了,主力又回到了近月。这一来一回,我的基差数据出现了断层,回测结果直接崩了。
所以,我现在的策略是:持仓量 + 成交量双重确认,并且设置一个“观察期”。
def identify_dominant_contract(data):
"""
自动识别主力合约
data: DataFrame,包含所有合约的持仓量、成交量
"""
# 第一步:按持仓量排序,取前3
top_by_oi = data.sort_values('open_interest', ascending=False).head(3)
# 第二步:按成交量排序,取前3
top_by_vol = data.sort_values('volume', ascending=False).head(3)
# 第三步:取交集,找到持仓量和成交量都靠前的合约
candidates = set(top_by_oi.index) & set(top_by_vol.index)
if len(candidates) == 0:
# 如果没交集,说明市场在切换,保守起见,取持仓量最大的
return top_by_oi.index[0]
# 第四步:如果候选合约跟当前主力不同,需要观察3天
current_dominant = get_current_dominant()
for candidate in candidates:
if candidate != current_dominant:
if check_observation_period(candidate, days=3):
return candidate
return current_dominant
小技巧: 我建议把主力合约的识别结果缓存起来,不要每次计算都重新跑。因为行情数据更新很快,但主力合约不会一天变三次。缓存可以减轻API压力,也避免频繁切换带来的数据抖动。
4.2 基差实时计算:从Tick到分钟线
识别了主力合约,接下来就是算基差。公式很简单:基差 = 现货价格 - 期货价格。但实际落地时,问题就来了——现货价格从哪来?期货价格用哪个?
我个人习惯用中证指数公司发布的现货指数作为现货基准。比如做沪深300的基差,就用000300.SH。如果你做商品,那就得找对应的现货报价平台,比如上海有色网、钢之家这些。
期货价格呢?当然是用我们刚刚识别出来的主力合约的最新成交价。但这里有个细节:是取收盘价,还是取实时价?
我的答案是:都取。 收盘价用于日频分析,实时价用于日内交易。下面这个函数,我把它叫做“基差快照”,每秒都在跑。
def calculate_basis(spot_price, futures_price, contract_multiplier=1):
"""
计算基差
spot_price: 现货价格
futures_price: 期货价格
contract_multiplier: 合约乘数(商品期货需要,股指期货为1)
"""
basis = spot_price - futures_price * contract_multiplier
basis_rate = basis / spot_price * 100 # 基差率,百分比
return {
'basis': round(basis, 2),
'basis_rate': round(basis_rate, 4),
'spot': spot_price,
'futures': futures_price
}
注意: 商品期货的基差计算,一定要考虑合约乘数。比如螺纹钢,一手10吨,期货价格是每吨的价格,但现货价格也是每吨。这时候乘数就是1。但如果是铜,一手5吨,期货报价是每吨,现货也是每吨,乘数还是1。真正需要乘数的是那些报价单位不一致的品种。我见过有人把股指期货的乘数设成300,结果基差算出来几万点,闹了大笑话。
4.3 跨期价差:近月与远月的博弈
跨期价差,就是同一个品种,不同月份合约之间的价差。比如,螺纹钢2401和2405的价差。这个指标在套利交易中非常常用。
计算跨期价差,核心是找到两个合约:一个是近月主力,一个是远月主力。但远月主力怎么定义?我通常取次主力合约,也就是持仓量第二大的那个。
为什么不用第三、第四?因为流动性太差,价差容易被操纵。我曾经在PTA上吃过亏,用了一个流动性很差的远月合约做跨期套利,结果一个几百手的单子就把价差打穿了,止损都来不及。
def calculate_calendar_spread(near_contract, far_contract):
"""
计算跨期价差
near_contract: 近月合约价格
far_contract: 远月合约价格
"""
spread = far_contract - near_contract
# 我习惯把价差归一化,方便不同品种之间比较
spread_normalized = spread / near_contract * 100
return {
'spread': round(spread, 2),
'spread_normalized': round(spread_normalized, 4),
'near': near_contract,
'far': far_contract
}
实战经验: 跨期价差在交割月前一个月波动会急剧放大。因为近月合约面临交割,多空双方都在平仓。这时候做跨期套利,风险很大。我一般会提前两周平掉所有跨期头寸,等交割后再重新建仓。
4.4 跨品种价差:寻找“亲戚”之间的价差
跨品种价差,就是两个不同品种之间的价差。比如,螺纹钢和热卷,豆粕和豆油。这些品种之间往往有产业链关系,价差会围绕一个合理区间波动。
计算跨品种价差,难点在于单位统一。螺纹钢和热卷都是吨价,可以直接减。但如果是豆粕(吨价)和豆油(吨价),虽然单位一样,但压榨利润的计算更复杂,需要引入出油率、出粕率这些参数。
我一般把跨品种价差分为两类:
- 直接价差: 单位相同,直接相减。比如RB-HC。
- 加工利润价差: 需要换算。比如压榨利润 = 豆油价格 × 出油率 + 豆粕价格 × 出粕率 - 大豆价格。
def calculate_cross_commodity_spread(price_a, price_b, ratio=1):
"""
计算跨品种价差
price_a: 品种A的价格
price_b: 品种B的价格
ratio: 换算比例(比如压榨利润中的出油率)
"""
spread = price_a - price_b * ratio
return {
'spread': round(spread, 2),
'price_a': price_a,
'price_b': price_b,
'ratio': ratio
}
避坑指南: 跨品种价差最怕政策干预。比如,国家抛储、调整关税,这些都会瞬间打破原有的价差关系。我曾经在豆粕和豆油的价差上赚了不少,结果一次大豆进口关税调整,价差直接偏离了三个标准差,我的套利头寸亏了20%。从那以后,我每次做跨品种价差,都会先查一下最近有没有政策风险。
4.5 知识体系总览:一张图看懂基差计算引擎
说了这么多,我们来梳理一下整个基差计算引擎的结构。下面这张图,是我自己画的设计草图,你可以把它当作搭建系统的蓝图。
这张图里,数据从左边进来,经过主力合约识别,然后进入基差计算核心。计算完基差之后,再分两条路:一条做跨期价差,一条做跨品种价差。最后所有结果汇总到输出层。
你可能会问:为什么要把跨期和跨品种放在基差计算之后?因为这两个价差都依赖于准确的基差数据。如果基差算错了,后面的价差全是错的。所以,我建议你先确保基差计算模块的准确性,再去做衍生指标。
4.6 实战中的坑与解决方案
最后,我总结几个实战中经常遇到的坑,希望能帮你少走弯路。
| 常见问题 | 原因 | 我的解决方案 |
|---|---|---|
| 主力合约频繁切换 | 持仓量数据抖动,或两个合约持仓量接近 | 设置3天观察期,不立即切换 |
| 基差数据出现跳空 | 主力合约切换时,新旧合约价格不同 | 记录切换日志,回测时做数据对齐 |
| 跨品种价差异常 | 两个品种的报价单位或时间戳不一致 | 统一使用UTC时间,并做单位换算 |
| API数据延迟 | 行情推送有延迟,导致基差计算滞后 | 使用本地缓存,并做时间戳校验 |
嗯,这一章的内容就到这里。基差计算引擎是整套系统的基石,代码量不大,但细节很多。我建议你先把主力合约识别这个模块跑通,再逐步加上跨期和跨品种的计算。别想着一步到位,那样容易出bug。
记住:交易系统,稳定第一,速度第二。 一个偶尔慢半秒但数据准确的引擎,远比一个飞快但经常出错的引擎有价值。