案例二:豆粕与菜粕套利:季节性因素分析、价差驱动因子、套利窗口期判断、实盘模拟

豆粕和菜粕,这两个品种我盯了快十年。说实话,它们就像一对孪生兄弟,但性格又完全不同。豆粕是大哥,体量大、流动性好;菜粕是小弟,波动更剧烈、季节性更强。做它们的套利,说白了就是吃「价差回归」这碗饭。

我个人习惯把这对组合叫做「蛋白双雄」。为什么?因为它们都是饲料蛋白的主要来源,在配方里可以互相替代。但替代不是无条件的,这里面门道很深。

一、季节性因素:为什么每年都有几波确定性行情?

先看一张图,这是我用过去8年数据画的豆菜粕价差走势。

豆粕-菜粕价差季节性走势(2016-2023均值) 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月 均值 价差收窄 价差扩大 5月:菜粕上市 7月:豆粕旺季

看到没有?每年5月到7月,价差会明显收窄。为什么?因为5月菜籽开始上市,菜粕供应增加,价格承压。而豆粕这边,美豆还在生长期,供应偏紧。这一松一紧,价差自然就缩了。

我记得2019年做这个策略时,5月初价差还在800以上,到6月底直接干到500。那一波我吃了将近300点,爽是爽,但中间的回撤也够呛。

核心规律:豆菜粕价差在每年5-7月倾向于收窄,11-1月倾向于扩大。这是由南北半球大豆和菜籽的种植、收获周期决定的。

二、价差驱动因子:除了季节,还有什么在影响?

季节性只是大框架,真正决定入场时机的,是下面这几个因子。

驱动因子 影响方向 监测指标 我的经验阈值
豆粕库存 正相关 港口大豆库存、压榨利润 库存>600万吨时,价差易扩大
菜粕库存 负相关 菜籽到港量、开机率 库存<10万吨时,价差易收窄
豆菜粕价差 均值回归 历史分位数 80%分位以上做空,20%以下做多
饲料需求 同向影响 生猪存栏、水产投苗 水产旺季利好菜粕
替代效应 非线性 蛋白价差比 价差>900时替代加速

这里面有个坑,我踩过。就是只看价差绝对值,不看相对位置。比如价差800,你觉得高了,但历史均值是900,那800其实算低的。所以我现在习惯用Z-score来标准化处理。

我的小技巧:把价差除以豆粕价格,得到「相对价差」。这样能消除绝对价格波动的影响。比如豆粕3000时价差600,和豆粕4000时价差600,意义完全不同。

三、套利窗口期判断:什么时候该动手?

判断窗口期,我有一套自己的流程。说白了就是三个条件同时满足:

  1. 季节性位置对:当前月份在历史季节性规律中处于有利位置
  2. 价差偏离大:当前价差偏离历史均值至少1.5个标准差
  3. 基本面配合:库存、到港量等数据支持方向

举个例子。2022年6月,我看到豆菜粕价差到了750,而历史同期均值是550。偏离了将近200点,超过2个标准差。再看库存,豆粕库存持续下降,菜粕库存却在累积。嗯,这就有意思了。

我当时判断:价差大概率要回归。于是入场做空价差(卖豆粕买菜粕)。持仓了大概3周,价差回到600附近,平仓走人。单笔盈利150点,收益率大概8%。

注意:窗口期判断最怕「假突破」。我曾经在2018年遇到价差冲到900以上,以为要回归,结果继续拉到1100。那笔亏了300点。后来我加了「持仓量确认」这个条件——价差突破时,如果持仓量同步增加,说明趋势有延续性,不要轻易逆势。

四、实盘模拟:手把手走一遍流程

好,理论说完了,咱们来点实际的。假设今天是2023年5月10日,我们来做一次模拟交易。

第一步:数据准备

# 获取近5年豆粕和菜粕主力合约数据
import pandas as pd
import numpy as np
from datetime import datetime

# 模拟数据(实际应从数据库或API获取)
dates = pd.date_range('2018-01-01', '2023-05-10', freq='D')
np.random.seed(42)
m_price = 3000 + np.cumsum(np.random.randn(len(dates)) * 10)
r_price = 2500 + np.cumsum(np.random.randn(len(dates)) * 8)
spread = m_price - r_price

df = pd.DataFrame({
    'date': dates,
    'm_price': m_price,
    'r_price': r_price,
    'spread': spread
})
df.set_index('date', inplace=True)

第二步:计算统计指标

# 计算当前价差的历史分位数和Z-score
current_spread = df['spread'].iloc[-1]
mean_spread = df['spread'].mean()
std_spread = df['spread'].std()
z_score = (current_spread - mean_spread) / std_spread
percentile = (df['spread'] < current_spread).mean() * 100

print(f"当前价差: {current_spread:.0f}")
print(f"历史均值: {mean_spread:.0f}")
print(f"Z-score: {z_score:.2f}")
print(f"分位数: {percentile:.1f}%")

第三步:判断窗口期

# 判断条件
is_season_ok = 5 <= datetime.now().month <= 7  # 季节性有利
is_deviation_ok = abs(z_score) > 1.5  # 偏离足够大
is_fundamental_ok = True  # 假设基本面配合

if is_season_ok and is_deviation_ok and is_fundamental_ok:
    if z_score > 0:
        action = "做空价差:卖豆粕,买菜粕"
    else:
        action = "做多价差:买豆粕,卖菜粕"
    print(f"窗口期确认!建议操作:{action}")
else:
    print("当前不满足窗口条件,观望")

第四步:执行与风控

# 假设做空价差,开仓比例1:1
# 豆粕1手=10吨,菜粕1手=10吨
m_contracts = 1  # 卖1手豆粕
r_contracts = 1  # 买1手菜粕

# 止损设置:价差反向突破2个标准差
stop_loss = current_spread + 2 * std_spread if z_score > 0 else current_spread - 2 * std_spread
print(f"入场价差: {current_spread:.0f}")
print(f"止损价差: {stop_loss:.0f}")
print(f"目标价差: {mean_spread:.0f}(回归均值)")

这套流程我用了好几年,胜率大概在65%左右。别小看这个数字,套利交易追求的是高胜率、低回撤,而不是暴利。

实盘要点:

  • 仓位管理:单笔风险不超过总资金的2%
  • 止损纪律:价差突破2个标准差必须离场
  • 移仓换月:注意主力合约切换,提前一周开始移仓
  • 滑点控制:用限价单,别用市价单

最后说一句。豆菜粕套利看起来简单,但真正赚钱的人不多。为什么?因为大多数人管不住手,看到价差偏离就想进场,结果被假突破反复打脸。记住:等待也是一种交易。

避坑指南:我曾经连续三次在价差偏离1.2个标准差时进场,结果三次都被止损。后来我把阈值提高到1.5,胜率明显提升。阈值太低,容易被噪音干扰;阈值太高,又会错过行情。1.5是我试出来的平衡点。


公众号:蓝海数据掘金营,微信deep3321