问题描述
请编写一个期货交易策略,在满足某个条件时买入开仓,在另一个条件满足时卖出平仓。
解决方案
这是一个基于 QMT 平台的期货交易策略示例。
为了演示“满足条件买入开仓,满足另一条件卖出平仓”的逻辑,我编写了一个经典的双均线策略(Dual Moving Average Crossover)。
策略逻辑:
- 买入开仓(做多):当短期均线(例如5日线)上穿长期均线(例如10日线),且当前无持仓时,买入开仓。
- 卖出平仓(平多):当短期均线下穿长期均线,且当前有多头持仓时,卖出平仓。
注意: 代码中使用了 sell_close_tdayfirst 函数,表示平仓时优先平今仓(符合国内期货交易所通常的规则)。
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
"""
初始化函数,策略启动时执行一次
"""
# 1. 设置资金账号 (请替换为您真实的期货资金账号)
ContextInfo.accID = 'YOUR_ACCOUNT_ID'
ContextInfo.set_account(ContextInfo.accID)
# 2. 设置交易标的 (此处以沪深300股指期货主力合约为例)
ContextInfo.target = 'IF00.IF'
# 3. 设置均线参数
ContextInfo.short_period = 5 # 短期均线周期
ContextInfo.long_period = 10 # 长期均线周期
# 4. 设定运行周期 (例如日线 '1d', 分钟线 '1m')
# 注意:实际运行时,周期通常由界面主图周期决定,这里仅作逻辑参考
print("策略初始化完成")
def handlebar(ContextInfo):
"""
K线处理函数,每根K线或每个Tick执行一次
"""
# 获取当前K线索引
index = ContextInfo.barpos
# 如果K线数量不足以计算长期均线,直接返回
if index < ContextInfo.long_period:
return
# 1. 获取历史行情数据 (收盘价)
# 获取过去 long_period + 2 根K线的数据,确保有足够数据计算
data = ContextInfo.get_market_data(
['close'],
stock_code=[ContextInfo.target],
count=ContextInfo.long_period + 2,
period=ContextInfo.period
)
# 检查数据是否获取成功
if data is None or len(data) == 0:
return
# 提取收盘价序列 (pandas Series)
close_series = data[ContextInfo.target]['close']
# 2. 计算均线
ma_short = close_series.rolling(window=ContextInfo.short_period).mean().iloc[-1]
ma_long = close_series.rolling(window=ContextInfo.long_period).mean().iloc[-1]
# 获取上一根K线的均线值(用于判断交叉)
prev_ma_short = close_series.rolling(window=ContextInfo.short_period).mean().iloc[-2]
prev_ma_long = close_series.rolling(window=ContextInfo.long_period).mean().iloc[-2]
# 3. 获取当前持仓状态
position = get_position(ContextInfo.target, ContextInfo.accID)
# 4. 交易逻辑判断
# --- 金叉:短线上穿长线 -> 买入开仓 ---
# 条件:当前短线>长线 且 上一时刻短线<=长线 且 当前无多单
if ma_short > ma_long and prev_ma_short <= prev_ma_long and position == 0:
print(f"产生买入信号: 短期均线({ma_short:.2f}) 上穿 长期均线({ma_long:.2f})")
# 下单:买入开仓,数量1手,使用最新价报价
# 参数说明: buy_open(标的, 数量, 报价类型, 价格, ContextInfo, 账号)
buy_open(ContextInfo.target, 1, "LATEST", 0, ContextInfo, ContextInfo.accID)
# --- 死叉:短线下穿长线 -> 卖出平仓 ---
# 条件:当前短线<长线 且 上一时刻短线>=长线 且 当前有多单
elif ma_short < ma_long and prev_ma_short >= prev_ma_long and position > 0:
print(f"产生平仓信号: 短期均线({ma_short:.2f}) 下穿 长期均线({ma_long:.2f})")
# 下单:卖出平仓 (平今优先),数量1手
# 参数说明: sell_close_tdayfirst(标的, 数量, 报价类型, 价格, ContextInfo, 账号)
sell_close_tdayfirst(ContextInfo.target, 1, "LATEST", 0, ContextInfo, ContextInfo.accID)
# 5. 在图表上画线 (可选,方便回测观察)
ContextInfo.paint('MA_Short', ma_short, -1, 0)
ContextInfo.paint('MA_Long', ma_long, -1, 0)
def get_position(stock_code, account_id):
"""
辅助函数:获取指定合约的多头持仓数量
"""
# 获取持仓列表
positions = get_trade_detail_data(account_id, 'future', 'position')
for pos in positions:
# 找到对应合约
if pos.m_strInstrumentID == stock_code:
# 区分多空方向 (期货中 48=多头, 49=空头)
# 这里只演示做多逻辑,所以只返回多头持仓
if pos.m_nDirection == 48:
return pos.m_nVolume
return 0
代码关键点说明:
- 编码格式:第一行
# -*- coding: gbk -*-是必须的,否则 QMT 可能会出现中文乱码或报错。 init函数:- 你需要将
'YOUR_ACCOUNT_ID'替换为你实际的期货资金账号。 ContextInfo.target设置为你想要交易的合约代码(如IF00.IF代表股指期货主力)。
- 你需要将
handlebar函数:- 这是策略的核心循环,随行情驱动。
- 使用
get_market_data获取历史数据并计算均线。 - 通过比较当前均线和上一时刻均线来判断“金叉”和“死叉”。
- 交易函数:
buy_open: 买入开仓。sell_close_tdayfirst: 卖出平仓。期货交易中区分“平今”和“平昨”,此函数会自动优先平掉今日新开的仓位,如果今日无仓则平昨日老仓,是比较通用的平仓方式。
get_position辅助函数:- QMT 的
ContextInfo对象本身不直接存储简单的持仓数字,需要调用get_trade_detail_data遍历持仓列表来查询当前合约的持仓量,防止重复开仓。
- QMT 的
如何运行:
- 在 QMT 界面进入“模型研究”或“策略编辑器”。
- 新建一个 Python 策略。
- 将上述代码复制进去。
- 修改账号 ID。
- 点击“编译”检查无误后,可以在回测模式下测试,或在实盘模式下运行(请务必先在模拟盘测试)。