【期货量化实战】豆粕期货量化交易策略(Python完整代码)

一、前言

豆粕是国内期货市场最活跃的农产品期货之一,日成交量常年位居前列。它既有农产品的季节性特征,又受国际市场影响显著,是学习量化交易的理想品种。

本文将介绍:

  • 豆粕期货的基本特性
  • 豆粕行情数据获取
  • 季节性分析方法
  • 豆粕量化交易策略

二、为什么选择天勤量化(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吨/手
特点 成交活跃、波动适中
策略适用 趋势跟踪、突破策略
重要指标 美豆价格、压榨利润

免责声明:本文仅供学习交流使用,不构成任何投资建议。期货交易有风险,入市需谨慎。

更多资源

相关推荐
txinyu的博客2 小时前
C++ 模板元编程 (TMP)
开发语言·c++
memmolo2 小时前
【3D传感技术系列博客】
算法·计算机视觉·3d
不爱编程爱睡觉2 小时前
代码随想录算法训练营第四十三天 | 图论理论基础、深搜理论基础、98. 所有可达路径、广搜理论基础
算法·leetcode·图论·代码随想录
六毛的毛2 小时前
冗余连接II
算法
@汤圆酱2 小时前
【无标题】
python·jmeter
dragoooon342 小时前
C++ 从零实现Json-Rpc 框架
开发语言·c++·rpc
sheji34162 小时前
【开题答辩全过程】以 基于Java的校内美食推荐系统的设计与实现为例,包含答辩的问题和答案
java·开发语言·美食
内存不泄露2 小时前
基于 Spring Boot 的医院预约挂号系统(全端协同)设计与实现
java·vue.js·spring boot·python·flask
Mr -老鬼2 小时前
Rust 知识图-谱基础部分
开发语言·后端·rust