QMT策略交易系统——策略函数交易完全教程
QMT极速策略交易系统——策略函数交易完全教程
本教程从零开始,以“每日定时自动委托国债逆回购”为切入点,带你逐步掌握QMT中策略函数交易的核心技能。
一、开启策略函数交易——从定时国债逆回购开始
1.1 为什么从国债逆回购开始?
国债逆回购是策略函数交易的最佳入门案例,原因有2:
- 逻辑简单:就是每天收盘前把闲置资金以“卖出”方式借出
- 实用性强:每天自动操作,不用再手动惦记
1.2 在QMT中创建Python策略
第一步:进入模型研究界面
打开QMT客户端,点击顶部菜单栏的“模型研究”,进入策略编写环境。
第二步:新建Python策略
点击“新建模型”按钮,在弹出的选项中选择“Python模型”。系统会打开「模型编辑器」,这是QMT专门为策略开发者设计的集成开发环境。
第三步:编写定时逆回购策略代码
在模型编辑器中输入以下完整代码:
# -*- coding: UTF-8 -*-
import time
from datetime import datetime
def init(ContextInfo):
"""初始化函数——策略启动时执行一次"""
# 设置你的资金账号(替换为实际账号)
ContextInfo.account = '你的资金账号'
# 设置逆回购品种(以204001为例,1天期沪市逆回购)
ContextInfo.repo_code = '204001.SH'
# 设置每日执行时间(下午14:50)
ContextInfo.run_time = '14:50'
# 设置最低参与金额(逆回购门槛1000元)
ContextInfo.min_amount = 1000
# 设置预留资金(保留部分资金备用,如新股缴款)
ContextInfo.reserve_amount = 0
# 注册定时任务
ContextInfo.run_time("daily_repo", "1d", ContextInfo.run_time)
def daily_repo(ContextInfo):
"""定时执行逆回购的函数"""
# 1. 获取当前时间,判断是否在工作日交易时段
now = datetime.now()
if now.weekday() >= 5: # 周六(5)、周日(6)不执行
return
# 2. 获取账户可用资金
account_info = ContextInfo.get_account_info()
available = account_info.get('可用金额', 0)
# 3. 判断资金是否满足条件
if available <= ContextInfo.reserve_amount + ContextInfo.min_amount:
print(f"可用资金{available}不足,跳过逆回购")
return
# 4. 计算实际下单金额(取整到1000的整数倍)
trade_amount = int((available - ContextInfo.reserve_amount) // 1000 * 1000)
if trade_amount <= 0:
return
# 5. 获取实时行情,判断收益率是否达到阈值(可选)
# 获取当前逆回购的实时价格(即年化收益率)
tick = ContextInfo.get_full_tick([ContextInfo.repo_code])
if ContextInfo.repo_code in tick:
current_rate = tick[ContextInfo.repo_code]['lastPrice']
# 如果收益率低于2%,暂不操作(可根据需要调整)
if current_rate < 2.0:
print(f"当前收益率{current_rate}%低于阈值2%,暂不操作")
return
# 6. 执行逆回购卖出(核心下单操作)
# 逆回购是“卖出”操作,下单类型为24(股票卖出)
# 数量单位为“张”,1000元=10张
volume = trade_amount // 1000 * 10
result = passorder(
24, # opType: 24=卖出
1101, # orderType: 下单方式
ContextInfo.account, # accountid: 资金账号
ContextInfo.repo_code, # orderCode: 证券代码
5, # prType: 5=最新价
-1, # price: -1表示按prType取价
volume, # volume: 数量
'逆回购', # strategyName: 策略名称
2, # quickTrade: 2=立即下单
'', # userOrderId: 用户自定义ID
ContextInfo # ContextInfo对象
)
if result == 0:
print(f"逆回购下单成功:{trade_amount}元,收益率{current_rate}%")
else:
print(f"逆回购下单失败,错误码:{result}")
def handlebar(ContextInfo):
"""行情驱动函数——每根K线或每个tick触发"""
# 本策略采用定时驱动,handlebar中无需额外逻辑
pass
1.3 策略参数说明
| 参数 | 说明 | 取值示例 |
|---|---|---|
| 逆回购代码 | 沪市以204开头,深市以1318开头 | 204001.SH(1天期沪市)、131810.SZ(1天期深市) |
| 执行时间 | 建议14:30 -15:00之间 | 14:50 |
| 最低金额 | 沪市10万元起,深市1000元起 | 根据实际调整 |
| 收益率阈值 | 低于此值不操作 | 年化2% |
1.4 在QMT中运行策略
第一步:设置基本信息
在模型编辑器中,填写策略名称(如“定时逆回购”)、选择默认周期(日线)、默认品种(任意)。
第二步:编译策略
点击“编译”按钮,检查代码是否有语法错误。编译成功后系统会自动保存。
第三步:添加到模型交易
编译成功后,点击“转到实盘交易”按钮,或切换到“模型交易”界面,点击“新建模拟交易”,选择刚才创建的策略。
第四步:选择运行模式
- 模拟盘:不产生真实交易,仅测试逻辑
- 实盘:产生真实交易信号,发送至柜台
第五步:启动策略
点击“启动”按钮,策略即开始运行。到设定时间(如14:50),策略会自动检查资金并执行逆回购。
二、QMT策略开发基础框架
2.1 策略的三种运行机制
QMT中Python策略有三种运行方式:
| 运行方式 | 触发机制 | 适用场景 |
|---|---|---|
| 逐K驱动 | 每根K线结束时触发handlebar() |
技术指标策略、均线策略 |
| 定时任务 | 设定固定时间触发run_time() |
定时调仓、逆回购、收盘检查 |
| 订阅推送 | 行情变化时实时推送 | 高频交易、事件驱动策略 |
2.2 策略的标准代码结构
def init(ContextInfo):
"""
初始化函数——策略启动时执行一次
用途:设置参数、注册定时任务、订阅行情
"""
# 设置交易参数
ContextInfo.account = '资金账号'
# 注册定时任务
ContextInfo.run_time("函数名", "周期", "执行时间")
# 订阅行情
ContextInfo.subscribe_quote(['股票代码'])
def handlebar(ContextInfo):
"""
行情驱动函数——每根K线或每个tick触发
用途:执行交易逻辑、条件判断
"""
# 获取行情数据
# 执行条件判断
# 调用下单函数
def 自定义定时函数(ContextInfo):
"""
定时任务函数——在设定时间触发
用途:定时执行的操作
"""
# 执行定时任务
2.3 关键概念说明
- init() :整个策略生命周期只执行一次,适合做初始化设置
- handlebar() :每收到一个行情数据就会调用一次,是策略的核心执行入口
- ContextInfo:贯穿整个策略的上下文对象,用于存储状态和调用API
三、核心交易函数——passorder详解
passorder是QMT中最核心的综合下单函数,支持股票、期货、期权、ETF申赎、融资融券等所有交易品种。
3.1 函数完整语法
passorder(opType, orderType, accountid, orderCode, prType, price, volume,
strategyName, quickTrade, userOrderId, ContextInfo)
3.2 参数详解
参数1:opType(操作类型)
| 值 | 说明 | 适用场景 |
|---|---|---|
| 23 | 买入 | 股票、ETF、可转债买入 |
| 24 | 卖出 | 股票、ETF、可转债卖出 |
| 27 | 融资买入 | 融资融券交易 |
| 28 | 融券卖出 | 融资融券交易 |
| 29 | 买券还券 | 融资融券交易 |
| 30 | 直接还券 | 融资融券交易 |
| 31 | 卖券还款 | 融资融券交易 |
| 32 | 直接还款 | 融资融券交易 |
| 48 | 买入开仓 | 股票期权 |
| 49 | 卖出平仓 | 股票期权 |
| 50 | 卖出开仓 | 股票期权 |
| 51 | 买入平仓 | 股票期权 |
| 86 | LOF申购 | 基金 |
| 87 | LOF赎回 | 基金 |
| 92 | 新股申购 | 新股 |
参数2:orderType(下单方式)
常用值 1101,代表单股、单账号、普通、股/手方式下单。
参数3:accountid(资金账号)
填写你的交易资金账号,字符串格式。
参数4:orderCode(证券代码)
格式为“代码.市场”,如 '600000.SH'、'000001.SZ'。
参数5:prType(报价类型)
| 值 | 说明 |
|---|---|
| 3 | 指定价(需填写price参数) |
| 5 | 最新价 |
| 11 | 指定价(同3) |
| 42 | 最优五档即成剩撤(沪市) |
| 43 | 最优五档即成剩转(沪市) |
| 44 | 对手最优价(深市) |
| 45 | 本方最优价(深市) |
参数6:price(委托价格)
- 当
prType=3或11时,填写具体价格 - 当
prType=5时,填-1表示取最新价 - 对于市价单,通常填
0
参数7:volume(委托数量)
- 股票:单位为“股”,100股整数倍
- 逆回购:单位为“张”,10张=1000元
- 期货:单位为“手”
- 期权:单位为“张”
参数8:strategyName(策略名称)
自定义策略名称,用于标识不同策略的下单来源,可选参数。
参数9:quickTrade(快速交易模式)
| 值 | 说明 |
|---|---|
| 0 | K线走完下单(默认) |
| 1 | 立即下单 |
| 2 | 立即下单+实时反馈 |
重点:如果希望策略触发后立刻发出委托,务必设置quickTrade=2。
参数10:userOrderId(用户自定义委托ID)
用于外部系统追踪订单,可选参数。
参数11:ContextInfo
策略上下文对象,必填。
3.3 passorder使用示例
示例1:以最新价买入100股
passorder(23, 1101, '6000000201', '600000.SH', 5, -1, 100,
'测试买入', 2, '', ContextInfo)
示例2:指定价卖出
passorder(24, 1101, account, '000001.SZ', 3, 10.50, 1000,
'指定价卖出', 2, '', ContextInfo)
示例3:逆回购卖出(10万元)
passorder(24, 1101, account, '204001.SH', 5, -1, 1000,
'逆回购', 2, '', ContextInfo)
四、行情数据获取函数
4.1 get_market_data——获取历史行情数据
语法:
ContextInfo.get_market_data(fields, stock_code, period, start_time, end_time,
count, skip_paused, dividend_type)
参数说明:
| 参数 | 说明 | 示例 |
|---|---|---|
| fields | 要获取的字段列表 | ['close','open','high','low','volume'] |
| stock_code | 股票代码列表 | ['600000.SH','000001.SZ'] |
| period | K线周期 | '1d'(日线)、'1m'(分钟) |
| start_time | 开始时间 | '20240101' |
| end_time | 结束时间 | '20241231' |
| count | 获取数量 | 100 |
| skip_paused | 是否跳过停牌 | True/False |
示例:
# 获取最近100根日K线的收盘价
df = ContextInfo.get_market_data(
['close'],
['600000.SH'],
'1d',
count=100
)
4.2 get_full_tick——获取实时行情(全推数据)
语法:
ContextInfo.get_full_tick(stock_list)
示例:
# 获取多只股票的实时行情
tick_data = ContextInfo.get_full_tick(['600000.SH', '000001.SZ'])
for code, data in tick_data.items():
print(f"{code}: 最新价={data['lastPrice']}, 涨跌幅={data['pctChg']}")
返回数据包含:lastPrice(最新价)、open(开盘价)、high(最高价)、low(最低价)、volume(成交量)、amount(成交额)、pctChg(涨跌幅)等。
4.3 subscribe_quote——订阅行情数据
用于持续接收特定股票的实时行情推送。
示例:
# 在init中订阅
ContextInfo.subscribe_quote(['600000.SH', '000001.SZ'])
# 在handlebar中获取订阅的数据
data = ContextInfo.get_subscribe_quote(['600000.SH'])
五、查询函数
5.1 账户资金查询
# 获取账户信息
account_info = ContextInfo.get_account_info()
# 返回:可用金额、总资产、市值、冻结金额等
available = account_info.get('可用金额', 0)
5.2 持仓查询
# 获取当前持仓
positions = ContextInfo.get_positions()
for pos in positions:
print(f"{pos['证券代码']}: {pos['可用数量']}股, 成本价{pos['成本价']}")
5.3 委托查询
# 获取当日委托
orders = ContextInfo.get_orders()
for order in orders:
print(f"委托{order['合同编号']}: {order['证券代码']}, "
f"状态{order['委托状态']}, 已成交{order['成交数量']}")
5.4 成交查询
# 获取当日成交
deals = ContextInfo.get_deals()
for deal in deals:
print(f"成交{deal['成交编号']}: {deal['证券代码']}, "
f"价格{deal['成交价格']}, 数量{deal['成交数量']}")
六、撤单函数
6.1 按合同编号撤单
# 撤销指定委托
ContextInfo.cancel_order('合同编号', '市场代码')
6.2 批量撤单
# 撤销所有未成交委托
orders = ContextInfo.get_orders()
for order in orders:
if order['委托状态'] == '已报' or order['委托状态'] == '部成':
ContextInfo.cancel_order(order['合同编号'], order['交易市场'])
七、函数参数字典速查
7.1 opType(操作类型)速查
| 代码 | 操作 | 代码 | 操作 |
|---|---|---|---|
| 23 | 股票买入 | 24 | 股票卖出 |
| 27 | 融资买入 | 28 | 融券卖出 |
| 29 | 买券还券 | 30 | 直接还券 |
| 31 | 卖券还款 | 32 | 直接还款 |
| 48 | 期权买入开仓 | 49 | 期权卖出平仓 |
| 50 | 期权卖出开仓 | 51 | 期权买入平仓 |
| 86 | LOF申购 | 87 | LOF赎回 |
| 92 | 新股申购 |
7.2 prType(报价类型)速查
| 代码 | 说明 |
|---|---|
| 3 / 11 | 指定价 |
| 5 | 最新价 |
| 42 | 最优五档即成剩撤(沪市) |
| 43 | 最优五档即成剩转(沪市) |
| 44 | 对手最优价(深市) |
| 45 | 本方最优价(深市) |
| 46 | 即时成交剩余撤销(深市) |
| 47 | 最优五档即成剩撤(深市) |
| 48 | 全额成交或撤(深市) |
7.3 quickTrade(快速交易)速查
| 值 | 说明 |
|---|---|
| 0 | K线走完下单(默认) |
| 1 | 立即下单 |
| 2 | 立即下单+实时反馈 |
八、完整策略模板
以下是一个完整的策略模板,涵盖初始化、行情获取、条件判断和下单:
# -*- coding: UTF-8 -*-
def init(ContextInfo):
"""初始化"""
# 设置账号
ContextInfo.account = '你的资金账号'
# 设置股票池
ContextInfo.stocks = ['600000.SH', '000001.SZ']
# 设置参数
ContextInfo.ma_short = 5
ContextInfo.ma_long = 20
# 订阅行情
ContextInfo.subscribe_quote(ContextInfo.stocks)
def handlebar(ContextInfo):
"""主逻辑"""
# 只在最后一根K线执行(避免重复触发)
if not ContextInfo.is_last_bar():
return
# 获取行情
for stock in ContextInfo.stocks:
# 获取历史数据计算均线
df = ContextInfo.get_market_data(
['close'], [stock], '1d', count=ContextInfo.ma_long + 1
)
if df is None or len(df) < ContextInfo.ma_long:
continue
closes = df['close'].values
ma_short = sum(closes[-ContextInfo.ma_short:]) / ContextInfo.ma_short
ma_long = sum(closes[-ContextInfo.ma_long:]) / ContextInfo.ma_long
# 判断买卖信号
if ma_short > ma_long and not ContextInfo.has_position(stock):
# 金叉买入
passorder(23, 1101, ContextInfo.account, stock, 5, -1, 100,
'均线金叉买入', 2, '', ContextInfo)
elif ma_short < ma_long and ContextInfo.has_position(stock):
# 死叉卖出
pos = ContextInfo.get_position(stock)
if pos and pos['可用数量'] > 0:
passorder(24, 1101, ContextInfo.account, stock, 5, -1,
pos['可用数量'], '均线死叉卖出', 2, '', ContextInfo)
九、常见问题与注意事项
9.1 策略运行前提
- 下载Python库:首次使用需在“模型研究”界面点击下载Python库
- 添加资金账号:需在管理端将账号加入白名单
- 数据准备:回测前建议先补充历史数据
9.2 常见错误
| 错误现象 | 可能原因 | 解决方法 |
|---|---|---|
| 逆回购报100009错误 | 代码格式或市场代码错误 | 确认使用204001.SH格式 |
| passorder无响应 | quickTrade未设为2 | 设置quickTrade=2 |
| 账号相关错误 | 账号未添加或未登录 | 检查账号管理中的登录状态 |
9.3 重要提醒
- 模拟盘先行:正式实盘前,务必在模拟盘充分测试
- 注意风险:量化交易存在风险,策略需谨慎设计
- 监控运行:策略启动后应定期检查运行状态和日志输出
本文由 海星量化研究所 作者提供,转载请保留链接和署名!网址:https://qmt.hxquant.com/?id=75
1.本站原创文章,转载需注明文章作者来源。 2.如果文章内容涉及版权问题,请联系我们删除,向本站投稿文章可能会经我们编辑修改。 3.本站对信息准确性或完整性不作保证,亦不对因使用该等信息而引发或可能引发的损失承担任何责任。





