快速开始 | 迅投知识库 迅投知识库 首页 API API 投研新手教程 QMT新手教程 内置Python XtQuant文档 VBA 数据字典 数据字典 快速开始 股票数据 行业概念数据 指数数据 期货数据 期权数据 场内基金数据 债券数据 常见问题 场景化示例 迅投因子 数据浏览器 策略迁移 策略迁移 聚宽策略 客服QQ: 810315303 联系方式: 18309226715 视频教程 视频教程 投研端教程 迅投学堂 在新窗口打开 投研平台 在新窗口打开 迅投社区 在新窗口打开 迅投官网 在新窗口打开 注册 登录 智能助手加载中... 首页 API API 投研新手教程 QMT新手教程 内置Python XtQuant文档 VBA 数据字典 数据字典 快速开始 股票数据 行业概念数据 指数数据 期货数据 期权数据 场内基金数据 债券数据 常见问题 场景化示例 迅投因子 数据浏览器 策略迁移 策略迁移 聚宽策略 客服QQ: 810315303 联系方式: 18309226715 视频教程 视频教程 投研端教程 迅投学堂 在新窗口打开 投研平台 在新窗口打开 迅投社区 在新窗口打开 迅投官网 在新窗口打开 内置Python 快速开始 一、概述 二、场景需求 回测模型 实盘模型 三、运行机制对比 逐 K 线驱动:handlebar 事件驱动 :subscribe 订阅推送 定时任务 :run_time 定时运行 不同机制匹配不同场景需求 四、逐 K 线驱动(handlebar)示例 回测示例-基于 handlebar 实盘示例-基于 handlebar 五、事件驱动(subscribe)示例 实盘示例-基于 subscribe 六、定时任务(run_time)示例 实盘示例-基于 run_time 使用须知 界面操作 变量约定 数据结构 系统函数 行情函数 交易函数 成交回报实时主推函数 引用函数 绘图函数 枚举常量 完整示例 常见问题 # 一、概述 QMT 极速策略交易系统,以下简称 QMT 系统 ,内置了 3.6 版本 的 python 运行环境,提供 行情数据 与 交易下单 两大核心功能。通过编写 python 脚本,可以完成指标计算,策略编写,策略回测,实盘下单等需求。 # 二、场景需求 QMT 系统支持 回测模型 与 实盘模型 。 回测模型: 指在历史 k 线上,自左向右逐根遍历 k 线,以模拟的资金账号记录每日的买卖信号,持仓盈亏,最终展示策略在历史上的净值走势结果。 实盘模型: 指在盘中收取最新的动态行情,即时发送买卖信号到交易所,判断委托状态,需要实时重复报撤的模型。 两类模型分别有各自的注意点: # 回测模型 回测是遍历固定的历史数据: 首先需要下载历史行情,首次下载可以在界面左上角,点击 操作 ,选择 数据管理 补充行情,选择回测的周期,如 日线 ,所需的板块数据,如 沪深A股板块 ,时间范围选择 全部 ,下载完整历史行情 其次设置每日定时更新,可以点击客户端右下角 行情 按钮,在 批量下载 界面选择需要每天更新的数据,勾选 定时下载 选项,之后每天在指定时间会自动下载行情数据到本地 回测模型取本地数据遍历,不需要向服务器订阅实时行情,应使用 get_market_data_ex 函数,指定 subscribe 参数为 False ,来读取本地行情数据。 回测模型的撮合规则为,指定交易价格在当前k线高低点间的,按指定价格撮合,超过高低点的,按当前 k 线收盘价撮合。委托数量大于可用数量时,按可用数量撮合。 回测模型右侧的基本信息,如默认周期,默认主图,在 我的界面 点击回测时会生效。在行情界面k线下点击回测,以当前 k 线的周期,品种为准。回测必须以 副图模式 执行,不要选择主图 /主图叠加. # 实盘模型 当你回测结束,你需要开始实盘模型,注意这里提到的实盘,指的是接收未来 K 线的数据,生成策略信号,进行交易下单。 提示 实盘模型也分 模拟柜台模拟交易 和 真实柜台实盘交易 两种。具体请参考 如何配置账号 在新窗口打开 你要运行实盘模型,QMT 系统提供两种交易模式: 默认的交易模式为 逐 k 线生效 ( passorder 函数 快速交易 quicktrade 参数填 0 即默认值),适用与需要在盘中模拟历史上逐 k 线的效果需求。例如选择一分钟周期,将下单判断,下单函数放在 handlebar 函数内,盘中主图每个分笔 (三秒一次)会触发一次 handlebar 函数调用,系统会暂存当前 handlebar 产生的下单信号。三秒后下一个分笔到达时,如果是新的一分钟 k 线的第一个分笔,判断上一个分笔为前一根k线最后分笔,会将暂存的交易信号发送给交易所,完成交易。如到达的下一个分笔不是新一根 k 线的,则判定当前 k 线未完成,丢弃暂存的交易信号。1 分钟 k 线情形,每根k线内会有 20 个分笔,前 19 个分笔产生的信号会被丢弃,最后一个分笔的信号,会在下一根k线,首个分笔到达时,延迟三秒发出。系统自带的 ContxtInfo 也做了同样的等待,回退处理,逐 k 线模式的交易记录可以保存在 ContextInfo 对象的属性中。详细说明参见 常见问题:系统对象ContextInfo 逐K线保存的机制 QMT 系统也支持立即下单的交易模式, passorder 函数的 快速交易 quicktrade 参数填 2 ,可以在运行后立刻发出委托,不对信号进行等待,丢弃的操作。此时需要用普通的全局变量(如自定义一个 Class a() )保存委托状态,不能存在 ContextInfo 的属性里。参见 使用快速交易参数委托 、 调整至目标持仓Demo 实盘的撮合规则以交易所为准。股票品种的话,价格不能超过 2% 的价格笼子否则废单。数量超过可用数量时会废单。 实盘模型需要在模型交易界面执行。模型交易界面,选择新建策略交易,添加需要的模型。运行模式可以选择 模拟 或 实盘 。 选择 模拟信号模式 ,在策略信号界面显示买卖信号,不实际发出委托。具体请参考 模拟信号模式 选择 实盘交易模式 ,显示的策略信号会实际发出到交易所。具体请参考 实盘交易模式 提示 运行模式的 模拟 和 实盘 ,与您使用的账号实际是 实盘账号(真实交易所柜台) 或是 模拟账号(模拟交易柜台) 无关。相关账号申请需要联系您做所在券商的工作人员,或者购买 投研端账号 在新窗口打开 获取模拟柜台撮合服务。 # 三、运行机制对比 QMT 系统提供两大类(事件驱动与定时任务),共三种运行机制。 # 逐 K 线驱动: handlebar handlebar 是 主图历史 k 线 + 盘中订阅推送 。运行开始时,所选周期历史 k 线从左向右每根触发一次 handlebar 函数调用。盘中时,主图品种每个新分笔数据到达,触发一次 handlebar 函数调用。 提示 盘中分笔驱动,但是逐 K 线生效。请参考 常见问题:系统对象ContextInfo 逐K线保存的机制 # 事件驱动 : subscribe 订阅推送 盘中订阅指定品种的分笔数据,新分笔到达时,触发指定的回调函数。 # 定时任务 : run_time 定时运行 指定固定的时间间隔,持续触发指定的回调函数. # 不同机制匹配不同场景需求 机制 分类 特点 匹配需求 逐 K 线运行( handlebar ) 事件驱动 同时支持历史回测和盘中可模拟逐K线效果 在实盘中模拟逐K线运行的效果 订阅推送( subscribe ) 事件驱动 盘中行情分笔触发函数调用 盘中随分笔行情判断交易 定时运行( run_time ) 定时任务 固定间隔触发调用 盘中固定时间间隔判断交易 # 四、逐 K 线驱动(handlebar)示例 因此,结合不同场景需求(回测或实盘),针对不同的机制(定时任务或事件驱动),我们分别给出回测与实盘的完整示例,复制到策略编辑器中即可使用。 在编写策略前,有以下注意事项: 警告 在编写一个策略时,首先需要在代码的最前一行写上: #coding:gbk 统一脚本的编码格式是 GBK 缩进需要统一 全部统一为 ···· 或者 -> # 回测示例-基于 handlebar 回测的操作流程请参考: 界面操作-策略回测 复制代码以下代码到策略编辑器: python #coding:gbk #导入常用库 import pandas as pd import numpy as np import talib #示例说明:本策略,通过计算快慢双均线,在金叉时买入,死叉时做卖出 点击回测运行 主图选择要交易的股票品种 def init ( C ): #init handlebar函数的入参是ContextInfo对象 可以缩写为C #设置测试标的为主图品种 C.stock = C.stockcode + ' . ' + C.market #line1和line2分别为两条均线期数 C.line1 = 10 #快线参数 C.line2 = 20 #慢线参数 #accountid为测试的ID 回测模式资金账号可以填任意字符串 C.accountid = " testS " def handlebar ( C ): #当前k线日期 bar_date = timetag_to_datetime(C.get_bar_timetag(C.barpos), ' %Y%m %d %H%M%S ' ) #回测不需要订阅最新行情使用本地数据速度更快 指定subscribe参数为否. 如果回测多个品种 需要先下载对应周期历史数据 local_data = C.get_market_data_ex([ ' close ' ], [C.stock], end_time = bar_date, period = C.period, count = max (C.line1, C.line2), subscribe = False ) close_list = list (local_data[C.stock].iloc[ : , 0 ]) #将获取的历史数据转换为DataFrame格式方便计算 #如果目前未持仓,同时快线穿过慢线,则买入8成仓位 if len (close_list) < 1 : print (bar_date, ' 行情不足 跳过 ' ) line1_mean = round (np.mean(close_list[ - C.line1 : ]), 2 ) line2_mean = round (np.mean(close_list[ - C.line2 : ]), 2 ) print ( f " { bar_date } 短均线 { line1_mean } 长均线 { line2_mean } " ) account = get_trade_detail_data( ' test ' , ' stock ' , ' account ' ) account = account[ 0 ] available_cash = int (account.m_dAvailable) holdings = get_trade_detail_data( ' test ' , ' stock ' , ' position ' ) holdings = {i.m_strInstrumentID + ' . ' + i.m_strExchangeID : i.m_nVolume for i in holdings} holding_vol = holdings[C.stock] if C.stock in holdings else 0 if holding_vol == 0 and line1_mean > line2_mean: vol = int (available_cash / close_list[ - 1 ] / 100 ) * 100 #下单开仓 passorder( 23 , 1101 , C.accountid, C.stock, 5 , - 1 , vol, C) print ( f " { bar_date } 开仓" ) C.draw_text( 1 , 1 , ' 开 ' ) #如果目前持仓中,同时快线下穿慢线,则全部平仓 elif holding_vol > 0 and line1_mean < line2_mean: #状态变更为未持仓 C.holding = False #下单平仓 passorder( 24 , 1101 , C.accountid, C.stock, 5 , - 1 , holding_vol, C) print ( f " { bar_date } 平仓" ) C.draw_text( 1 , 1 , ' 平 ' ) 基础信息设置 请参考 基础信息-字段描述 回测参数设置 请参考 回测参数-字段描述 # 实盘示例-基于 handlebar 实盘的操作流程请参考: 界面操作-模型交易 复制代码以下代码到策略编辑器: python #coding:gbk # 导入包 import pandas as pd import numpy as np import datetime """ 示例说明:双均线实盘策略,通过计算快慢双均线,在金叉时买入,死叉时做卖出 """ class a (): pass A = a() #创建空的类的实例 用来保存委托状态 def init ( C ): A.stock = C.stockcode + ' . ' + C.market #品种为模型交易界面选择品种 A.acct = account #账号为模型交易界面选择账号 A.acct_type = accountType #账号类型为模型交易界面选择账号 A.amount = 10000 #单笔买入金额 触发买入信号后买入指定金额 A.line1 = 17 #快线周期 A.line2 = 27 #慢线周期 A.waiting_list = [] #未查到委托列表 存在未查到委托情况暂停后续报单 防止超单 A.buy_code = 23 if A.acct_type == ' STOCK ' else 33 #买卖代码 区分股票 与 两融账号 A.sell_code = 24 if A.acct_type == ' STOCK ' else 34 print ( f '双均线实盘示例 { A.stock } { A.acct } { A.acct_type } 单笔买入金额 { A.amount } ' ) def handlebar ( C ): #跳过历史k线 if not C.is_last_bar(): return now = datetime.datetime.now() now_time = now.strftime( ' %H%M%S ' ) # 跳过非交易时间 if now_time < ' 093000 ' or now_time > " 150000 " : return account = get_trade_detail_data(A.acct, A.acct_type, ' account ' ) if len (account) == 0 : print ( f '账号 { A.acct } 未登录 请检查' ) return account = account[ 0 ] available_cash = int (account.m_dAvailable) #如果有未查到成交 查询成交 if A.waiting_list: found_list = [] deals = get_trade_detail_data(A.acct, A.acct_type, ' deal ' ) for deal in deals: if deal.m_strRemark in A.waiting_list: found_list.append(deal.m_strRemark) A.waiting_list = [i for i in A.waiting_list if i not in found_list] if A.waiting_list: print ( f "当前有未查到委托 { A.waiting_list } 暂停后续报单" ) return holdings = get_trade_detail_data(A.acct, A.acct_type, ' position ' ) holdings = {i.m_strInstrumentID + ' . ' + i.m_strExchangeID : i.m_nCanUseVolume for i in holdings} #获取行情数据 data = C.get_market_data_ex([ " close " ],[A.stock], period = ' 1d ' , count = max (A.line1, A.line2) + 1 ) close_list = data[A.stock].values if len (close_list) < max (A.line1, A.line2) + 1 : print ( ' 行情长度不足(新上市或最近有停牌) 跳过运行 ' ) return pre_line1 = np.mean(close_list[ - A.line1 - 1 : - 1 ]) pre_line2 = np.mean(close_list[ - A.line2 - 1 : - 1 ]) current_line1 = np.mean(close_list[ - A.line1 : ]) current_line2 = np.mean(close_list[ - A.line2 : ]) #如果快线穿过慢线,则买入委托 当前无持仓 买入 vol = int (A.amount / close_list[ - 1 ] / 100 ) * 100 #买入数量 向下取整到100的整数倍 if A.amount < available_cash and vol >= 100 and A.stock not in holdings and pre_line1 < pre_line2 and current_line1 > current_line2: #下单开仓 ,参数说明可搜索PY交易函数 passorder msg = f "双均线实盘 { A.stock } 上穿均线 买入 { vol } 股" passorder(A.buy_code, 1101 , A.acct, A.stock, 14 , - 1 , vol, ' 双均线实盘 ' , 2 , msg, C) print (msg) A.waiting_list.append(msg) #如果快线下穿慢线,则卖出委托 if A.stock in holdings and holdings[A.stock] > 0 and pre_line1 > pre_line2 and current_line1 < current_line2: msg = f "双均线实盘 { A.stock } 下穿均线 卖出 { holdings[A.stock] } 股" passorder(A.sell_code, 1101 , A.acct, A.stock, 14 , - 1 , holdings[A.stock], ' 双均线实盘 ' , 2 , msg, C) print (msg) A.waiting_list.append(msg) 警告 对于立刻下单的模型需要用普通的全局变量来保存状态不能ContextInfo对象存详细说明参考 常见问题:系统对象ContextInfo 逐K线保存的机制 更多示例请参见 完整示例 # 五、事件驱动(subscribe)示例 # 实盘示例-基于 subscribe python #coding:gbk class a (): pass A = a() A.bought_list = [] account = ' testaccount ' def init ( C ): #下单函数的参数需要 ContextInfo对象 在init中定义行情回调函数 可以用到init函数的入参 不用手动传入 def callback_func ( data ): #print(data) for stock in data: current_price = data[stock][ ' close ' ] pre_price = data[stock][ ' preClose ' ] ratio = current_price / pre_price - 1 print (stock, C.get_stock_name(stock), ' 当前涨幅 ' , ratio) if ratio > 0 and stock not in A.bought_list: msg = f "当前涨幅 { ratio } 大于0 买入100股" print (msg) #下单函数passorder 安全起见处于注释状态 需要实际测试下单交易时再放开 #passorder(23, 1101, account, stock, 5, -1, 100, '订阅下单示例', 2, msg, C) A.bought_list.append(stock) stock_list = [ ' 600000.SH ' , ' 000001.SZ ' ] for stock in stock_list: C.subscribe_quote(stock, period = ' 1d ' , callback = callback_func) # 六、定时任务(run_time)示例 # 实盘示例-基于 run_time python #coding:gbk import time, datetime class a (): pass A = a() def init ( C ): A.hsa = C.get_stock_list_in_sector( ' 沪深A股 ' ) A.vol_dict = {} for stock in A.hsa: A.vol_dict[stock] = C.get_last_volume(stock) A.bought_list = [] C.run_time( " f " , " 1nSecond " , " 2019-10-14 13:20:00 " ) def f ( C ): t0 = time.time() now = datetime.datetime.now() full_tick = C.get_full_tick(A.hsa) total_market_value = 0 total_ratio = 0 count = 0 for stock in A.hsa: ratio = full_tick[stock][ ' lastPrice ' ] / full_tick[stock][ ' lastClose ' ] - 1 if ratio > 0.09 and stock not in A.bought_list: msg = f " { now } { stock } { C.get_stock_name(stock) } 当前涨幅 { ratio } 大于5% 买入100股" #下单示例 安全起见处于注释状态 需要实际测试下单时可以放开 #passorder(23, 1101, account, stock, 5, -1, 100, '示例策略', 2, msg, C) A.bought_list.append(stock) market_value = full_tick[stock][ ' lastPrice ' ] * A.vol_dict[stock] total_ratio += ratio * market_value total_market_value += market_value count += 1 total_ratio /= total_market_value total_ratio *= 100 print ( f ' { now } 当前A股加权涨幅 { round (total_ratio, 2 ) } % 函数运行耗时 { round (time.time() - t0, 5 ) } 秒' ) 上次更新: 邀请注册送VIP优惠券 分享下方的内容给好友、QQ群、微信群,好友注册您即可获得VIP优惠券 玩转qmt,上迅投qmt知识库 登录后获取 使用须知