一、前言
豆粕是国内期货市场最活跃的农产品期货之一,日成交量常年位居前列。它既有农产品的季节性特征,又受国际市场影响显著,是学习量化交易的理想品种。
本文将介绍:
- 豆粕期货的基本特性
- 豆粕行情数据获取
- 季节性分析方法
- 豆粕量化交易策略
二、为什么选择天勤量化(TqSdk)
开发量化交易策略需要功能完整的框架。**天勤量化(TqSdk)**是目前国内最适合个人投资者的期货量化平台:
| 功能 | 说明 |
|---|---|
| 模拟交易 | 内置TqSim模拟盘,无需开户即可测试 |
| 回测功能 | 支持历史数据回测 |
| 实盘对接 | 一套代码模拟实盘通用 |
| 多账户 | 支持同时管理多个账户 |
安装方法:
bash
pip install tqsdk
重要提示:建议先使用模拟盘充分测试策略,确认无误后再考虑实盘交易。
三、豆粕期货基础
3.1 合约信息
| 属性 | 说明 |
|---|---|
| 交易所 | 大连商品交易所(DCE) |
| 代码 | m(如DCE.m2509) |
| 交易单位 | 10吨/手 |
| 最小变动 | 1元/吨 |
| 保证金 | 约8%左右 |
| 交易时间 | 日盘+夜盘 |
3.2 豆粕特点
| 特点 | 说明 |
|---|---|
| 成交活跃 | 流动性好,滑点小 |
| 波动适中 | 日内波动稳定 |
| 季节性强 | 受播种收获季节影响 |
| 关联性高 | 与美豆、豆油关联紧密 |
3.3 影响因素
| 因素 | 影响方式 |
|---|---|
| 美豆价格 | 国际定价基准 |
| 压榨利润 | 油厂开工影响供给 |
| 生猪存栏 | 饲料需求主要来源 |
| 进口数据 | 大豆到港量影响 |
| 天气因素 | 美国大豆产区天气 |
四、获取豆粕行情数据
4.1 基础行情获取
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:获取豆粕期货实时行情
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth
api = TqApi(auth=TqAuth("快期账户", "快期密码"))
# 豆粕主力合约
SYMBOL = "DCE.m2509"
quote = api.get_quote(SYMBOL)
print("=" * 60)
print(f"豆粕期货行情 - {SYMBOL}")
print("=" * 60)
count = 0
while count < 20:
api.wait_update()
if api.is_changing(quote, "last_price"):
print(f"最新价: {quote.last_price:.0f} | "
f"涨跌: {quote.last_price - quote.pre_close:.0f} | "
f"买一: {quote.bid_price1:.0f}({quote.bid_volume1}) | "
f"卖一: {quote.ask_price1:.0f}({quote.ask_volume1}) | "
f"持仓: {quote.open_interest:.0f}")
count += 1
api.close()
4.2 获取K线数据
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:获取豆粕K线数据
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth
import pandas as pd
api = TqApi(auth=TqAuth("快期账户", "快期密码"))
SYMBOL = "DCE.m2509"
# 获取日K线
klines = api.get_kline_serial(SYMBOL, duration_seconds=86400, data_length=60)
api.wait_update()
print("=" * 60)
print(f"豆粕期货日K线 - {SYMBOL}")
print("=" * 60)
# 转换时间格式
df = klines.copy()
df['date'] = pd.to_datetime(df['datetime'], unit='ns').dt.strftime('%Y-%m-%d')
print(df[['date', 'open', 'high', 'low', 'close', 'volume']].tail(10))
# 计算统计信息
print("\n统计信息:")
print(f"平均价格: {df['close'].mean():.2f}")
print(f"价格波动: {df['close'].std():.2f}")
print(f"最高价格: {df['high'].max():.0f}")
print(f"最低价格: {df['low'].min():.0f}")
print(f"平均成交量: {df['volume'].mean():.0f}")
api.close()
五、豆粕量化策略
5.1 突破策略
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:豆粕突破策略
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth, TqSim
from tqsdk.lib import TargetPosTask
from tqsdk.tafunc import hhv, llv
# ============ 策略参数 ============
SYMBOL = "DCE.m2509"
PERIOD = 20 # 突破周期
LOTS = 1 # 交易手数
STOP_LOSS_RATIO = 0.02 # 止损比例
# ============ 初始化 ============
api = TqApi(TqSim(init_balance=100000), auth=TqAuth("快期账户", "快期密码"))
klines = api.get_kline_serial(SYMBOL, duration_seconds=60*15, data_length=PERIOD+5)
quote = api.get_quote(SYMBOL)
position = api.get_position(SYMBOL)
target_pos = TargetPosTask(api, SYMBOL)
print("=" * 60)
print("豆粕突破策略启动")
print("=" * 60)
print(f"合约: {SYMBOL}")
print(f"突破周期: {PERIOD}")
print("-" * 60)
entry_price = 0
while True:
api.wait_update()
if api.is_changing(klines.iloc[-1], "datetime"):
# 计算通道
high_line = hhv(klines["high"], PERIOD).iloc[-2]
low_line = llv(klines["low"], PERIOD).iloc[-2]
close = klines.iloc[-1]["close"]
current_pos = position.pos_long - position.pos_short
# 突破上轨做多
if close > high_line and current_pos <= 0:
target_pos.set_target_volume(LOTS)
entry_price = close
print(f"【突破做多】价格={close:.0f} 上轨={high_line:.0f}")
# 突破下轨做空
elif close < low_line and current_pos >= 0:
target_pos.set_target_volume(-LOTS)
entry_price = close
print(f"【突破做空】价格={close:.0f} 下轨={low_line:.0f}")
# 止损逻辑
if current_pos > 0 and entry_price > 0:
if close < entry_price * (1 - STOP_LOSS_RATIO):
target_pos.set_target_volume(0)
print(f"【止损平多】入场={entry_price:.0f} 现价={close:.0f}")
entry_price = 0
elif current_pos < 0 and entry_price > 0:
if close > entry_price * (1 + STOP_LOSS_RATIO):
target_pos.set_target_volume(0)
print(f"【止损平空】入场={entry_price:.0f} 现价={close:.0f}")
entry_price = 0
print(f"\r价格={close:.0f} 上轨={high_line:.0f} 下轨={low_line:.0f} "
f"持仓={current_pos}", end="")
5.2 均线趋势策略
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:豆粕均线趋势策略
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth, TqSim
from tqsdk.lib import TargetPosTask
from tqsdk.tafunc import ma
# ============ 策略参数 ============
SYMBOL = "DCE.m2509"
FAST_PERIOD = 5
MID_PERIOD = 10
SLOW_PERIOD = 20
LOTS = 1
# ============ 初始化 ============
api = TqApi(TqSim(init_balance=100000), auth=TqAuth("快期账户", "快期密码"))
klines = api.get_kline_serial(SYMBOL, duration_seconds=60*30, data_length=SLOW_PERIOD+5)
position = api.get_position(SYMBOL)
target_pos = TargetPosTask(api, SYMBOL)
print("=" * 60)
print("豆粕均线趋势策略")
print("=" * 60)
while True:
api.wait_update()
if api.is_changing(klines.iloc[-1], "datetime"):
# 计算三条均线
ma_fast = ma(klines["close"], FAST_PERIOD).iloc[-1]
ma_mid = ma(klines["close"], MID_PERIOD).iloc[-1]
ma_slow = ma(klines["close"], SLOW_PERIOD).iloc[-1]
close = klines.iloc[-1]["close"]
current_pos = position.pos_long - position.pos_short
# 多头排列做多
if ma_fast > ma_mid > ma_slow and close > ma_fast:
if current_pos <= 0:
target_pos.set_target_volume(LOTS)
print(f"\n【多头排列】做多 价格={close:.0f}")
# 空头排列做空
elif ma_fast < ma_mid < ma_slow and close < ma_fast:
if current_pos >= 0:
target_pos.set_target_volume(-LOTS)
print(f"\n【空头排列】做空 价格={close:.0f}")
# 均线缠绕时观望
else:
if current_pos != 0:
target_pos.set_target_volume(0)
print(f"\n【均线缠绕】平仓观望")
print(f"\rMA{FAST_PERIOD}={ma_fast:.0f} MA{MID_PERIOD}={ma_mid:.0f} "
f"MA{SLOW_PERIOD}={ma_slow:.0f} 持仓={current_pos}", end="")
5.3 日内波动策略
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:豆粕日内波动策略
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth, TqSim
from tqsdk.lib import TargetPosTask
from tqsdk.tafunc import atr
# ============ 策略参数 ============
SYMBOL = "DCE.m2509"
ATR_PERIOD = 14
ATR_MULTI = 1.5 # ATR倍数
LOTS = 1
# ============ 初始化 ============
api = TqApi(TqSim(init_balance=100000), auth=TqAuth("快期账户", "快期密码"))
klines = api.get_kline_serial(SYMBOL, duration_seconds=60*5, data_length=ATR_PERIOD+10)
quote = api.get_quote(SYMBOL)
position = api.get_position(SYMBOL)
target_pos = TargetPosTask(api, SYMBOL)
print("=" * 60)
print("豆粕日内波动策略")
print("=" * 60)
# 记录开盘价
open_price = None
today_high = 0
today_low = float('inf')
while True:
api.wait_update()
if api.is_changing(klines.iloc[-1], "datetime"):
close = klines.iloc[-1]["close"]
high = klines.iloc[-1]["high"]
low = klines.iloc[-1]["low"]
# 更新日内高低点
today_high = max(today_high, high)
today_low = min(today_low, low)
# 计算ATR
tr = klines["high"] - klines["low"]
atr_value = tr.rolling(ATR_PERIOD).mean().iloc[-1]
# 首次获取开盘价
if open_price is None:
open_price = klines.iloc[-1]["open"]
# 计算突破点
upper = open_price + atr_value * ATR_MULTI
lower = open_price - atr_value * ATR_MULTI
current_pos = position.pos_long - position.pos_short
# 向上突破
if close > upper and current_pos <= 0:
target_pos.set_target_volume(LOTS)
print(f"\n【向上突破】做多 价格={close:.0f} 上轨={upper:.0f}")
# 向下突破
elif close < lower and current_pos >= 0:
target_pos.set_target_volume(-LOTS)
print(f"\n【向下突破】做空 价格={close:.0f} 下轨={lower:.0f}")
# 回归中轴平仓
if current_pos > 0 and close < open_price:
target_pos.set_target_volume(0)
print(f"\n【回归中轴】平多")
elif current_pos < 0 and close > open_price:
target_pos.set_target_volume(0)
print(f"\n【回归中轴】平空")
print(f"\r开盘={open_price:.0f} ATR={atr_value:.0f} "
f"上={upper:.0f} 下={lower:.0f} 持仓={current_pos}", end="")
六、策略回测
python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
功能:豆粕策略回测
说明:本代码仅供学习参考
"""
from tqsdk import TqApi, TqAuth, TqBacktest
from tqsdk.lib import TargetPosTask
from tqsdk.tafunc import ma
from datetime import date
# ============ 回测参数 ============
SYMBOL = "DCE.m2405"
START_DATE = date(2024, 1, 1)
END_DATE = date(2024, 6, 30)
# ============ 策略参数 ============
FAST = 5
SLOW = 20
# ============ 初始化 ============
api = TqApi(
backtest=TqBacktest(start_dt=START_DATE, end_dt=END_DATE),
auth=TqAuth("快期账户", "快期密码")
)
klines = api.get_kline_serial(SYMBOL, duration_seconds=60*60, data_length=SLOW+5)
account = api.get_account()
position = api.get_position(SYMBOL)
target_pos = TargetPosTask(api, SYMBOL)
print("=" * 60)
print(f"豆粕策略回测 {START_DATE} ~ {END_DATE}")
print("=" * 60)
initial_balance = account.balance
try:
while True:
api.wait_update()
if api.is_changing(klines.iloc[-1], "datetime"):
ma_fast = ma(klines["close"], FAST)
ma_slow = ma(klines["close"], SLOW)
# 金叉做多
if ma_fast.iloc[-2] < ma_slow.iloc[-2] and ma_fast.iloc[-1] > ma_slow.iloc[-1]:
target_pos.set_target_volume(1)
# 死叉做空
if ma_fast.iloc[-2] > ma_slow.iloc[-2] and ma_fast.iloc[-1] < ma_slow.iloc[-1]:
target_pos.set_target_volume(-1)
except BacktestFinished:
pass
finally:
# 输出回测结果
print("\n" + "=" * 60)
print("回测结果")
print("=" * 60)
print(f"初始资金: {initial_balance:.2f}")
print(f"期末资金: {account.balance:.2f}")
print(f"总收益: {account.balance - initial_balance:.2f}")
print(f"收益率: {(account.balance - initial_balance) / initial_balance * 100:.2f}%")
api.close()
七、风险提示
| 风险类型 | 说明 |
|---|---|
| 政策风险 | 进口政策、补贴政策变化 |
| 供需风险 | 大豆产量、压榨量波动 |
| 关联风险 | 美豆价格、汇率波动 |
| 季节风险 | 播种收获期波动加剧 |
八、总结
| 要点 | 内容 |
|---|---|
| 合约代码 | DCE.m |
| 交易单位 | 10吨/手 |
| 特点 | 成交活跃、波动适中 |
| 策略适用 | 趋势跟踪、突破策略 |
| 重要指标 | 美豆价格、压榨利润 |
免责声明:本文仅供学习交流使用,不构成任何投资建议。期货交易有风险,入市需谨慎。
更多资源: