10. 日历套利识别:如何识别不同到期日之间的套利机会

日历套利,说白了就是利用同一标的、不同到期日的期权合约之间的定价偏差来赚钱。我刚开始做期权交易那会儿,总觉得这玩意儿挺玄乎——同一个股票,不同月份的价格还能差出套利空间来?后来踩过几次坑才明白,市场有时候真的会「犯糊涂」。

10.1 日历套利的底层逻辑

先想一个问题:为什么不同到期日的期权价格会有差异?

核心原因就一个——时间价值衰减的速度不一样。近月合约的时间价值衰减快,远月合约衰减慢。正常情况下,这种差异会体现在价格上,形成一条平滑的期限结构曲线。

但市场有时候会抽风。比如某天突然出了个消息,近月合约被爆炒,远月合约还没反应过来。这时候,近月合约就贵了,远月合约相对便宜。你想想看,这不就是机会吗?

日历套利的本质:做多时间价值衰减慢的合约,做空时间价值衰减快的合约,赚取两者之间的时间价值差。

10.2 识别套利机会的三个关键指标

我在项目中遇到过不少假信号,后来总结出三个必须看的指标:

  1. 隐含波动率期限结构——不同到期日的IV是否出现异常扭曲
  2. 日历价差的理论值——实际价格与理论价格之间的偏离程度
  3. 持仓成本与资金占用——别光看收益,忘了算成本

10.3 实战:用Python扫描日历套利机会

嗯,这里直接上代码。我个人习惯用Python做实时扫描,逻辑其实不复杂:

import numpy as np
import pandas as pd
from scipy.stats import norm

def black_scholes_price(S, K, T, r, sigma, option_type='call'):
    """计算欧式期权理论价格"""
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    
    if option_type == 'call':
        price = S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
    else:
        price = K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)
    return price

def find_calendar_arbitrage(chain_data, S, r=0.03):
    """
    扫描日历套利机会
    chain_data: DataFrame, 包含到期日T, 行权价K, 市场价market_price, 类型type
    """
    opportunities = []
    
    for i in range(len(chain_data)):
        for j in range(i+1, len(chain_data)):
            opt1 = chain_data.iloc[i]
            opt2 = chain_data.iloc[j]
            
            # 只比较相同行权价、相同类型的合约
            if opt1['K'] != opt2['K'] or opt1['type'] != opt2['type']:
                continue
            
            T1, T2 = opt1['T'], opt2['T']
            if T1 >= T2:  # 确保T1是近月
                T1, T2 = T2, T1
                opt1, opt2 = opt2, opt1
            
            # 计算理论价差
            sigma_avg = (opt1.get('iv', 0.2) + opt2.get('iv', 0.2)) / 2
            theoretical_price1 = black_scholes_price(S, opt1['K'], T1, r, sigma_avg, opt1['type'])
            theoretical_price2 = black_scholes_price(S, opt2['K'], T2, r, sigma_avg, opt2['type'])
            theoretical_spread = theoretical_price2 - theoretical_price1
            
            # 实际价差
            actual_spread = opt2['market_price'] - opt1['market_price']
            
            # 偏离度判断
            deviation = (actual_spread - theoretical_spread) / theoretical_spread
            
            if abs(deviation) > 0.05:  # 偏离超过5%视为机会
                opportunities.append({
                    'K': opt1['K'],
                    'type': opt1['type'],
                    'near_month': T1,
                    'far_month': T2,
                    'theo_spread': round(theoretical_spread, 4),
                    'actual_spread': round(actual_spread, 4),
                    'deviation_pct': round(deviation*100, 2),
                    'action': '做多价差' if actual_spread < theoretical_spread else '做空价差'
                })
    
    return pd.DataFrame(opportunities)

# 使用示例
# chain = pd.DataFrame({...})  # 加载期权链数据
# result = find_calendar_arbitrage(chain, S=100)
# print(result[result['deviation_pct'].abs() > 5])

10.4 日历套利的核心逻辑图

下面这张图是我自己总结的,把整个识别流程串起来了:

日历套利识别流程 第一步:数据获取 获取不同到期日期权链 第二步:配对筛选 相同行权价、相同类型 第三步:理论计算 BS模型计算理论价差 第四步:偏差计算 实际价差 vs 理论价差 → 偏离度 第五步:机会判断 偏离度 > 5% 视为套利机会 做多日历价差 实际价差 < 理论价差 做空日历价差 实际价差 > 理论价差 注:偏离度 = (实际价差 - 理论价差) / 理论价差 × 100%

10.5 避坑指南

我曾经吃过一次大亏,在这里必须提醒你:

⚠️ 日历套利最大的坑——流动性陷阱

远月合约的流动性通常很差,买卖价差可能吃掉你所有利润。我建议:

  • 只做近月合约流动性好的品种
  • 远月合约的买卖价差不能超过理论利润的30%
  • 先用模拟盘跑两周,再上实盘

💡 我的个人习惯:

每天开盘前跑一遍扫描程序,重点关注偏离度超过8%的配对。如果同时出现3个以上机会,优先选近月合约剩余期限在7-14天的——这个区间的时间价值衰减最快,套利效率最高。

10.6 实战案例:某ETF的日历套利

拿我最近做的一个案例来说吧。某ETF当时价格100元,近月(15天到期)和远月(45天到期)的平值看涨期权出现了明显偏差:

合约 行权价 到期日 理论价 市场价 价差
近月Call 100 15天 2.15 2.35 +0.20(偏贵)
远月Call 100 45天 3.80 3.65 -0.15(偏便宜)
日历价差(远月-近月) 1.65 1.30 偏离 -21.2%

实际价差1.30,理论价差1.65,偏离了21%。这意味着什么?远月合约相对近月合约被低估了。操作上就是:买入远月Call,卖出近月Call,做多日历价差。

持有到近月到期,只要标的没出现剧烈波动,这个价差就会回归。那次我拿了12天,价差从1.30回到了1.55,净赚0.25个点,扣除手续费还有15%的收益。

10.7 什么时候该放弃?

不是所有偏离都值得做。我给自己定了三条红线:

  • 偏离度小于5%——大概率是噪音,不够覆盖交易成本
  • 远月合约的隐含波动率比近月高太多——可能有你不知道的利空消息
  • 临近财报或重大事件——日历套利最怕事件风险,波动率会瞬间扭曲

说白了,日历套利赚的是「时间」的钱,不是「方向」的钱。一旦市场预期发生突变,时间价值规律就会被打破。嗯,这个分寸感,得靠实盘慢慢磨出来。


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