第一次使用 QuantX

QuantX 文档围绕两套独立策略平台组织:QMT 内置 Python 与 PTrade。先确认实际使用的平台,再进入对应目录,避免混用生命周期、行情和交易函数。

本章目标

  • 找到与你的策略平台对应的文档。
  • 从客户端、数据、策略、回测逐步学习。
  • 遇到报错时,能够按函数名、错误信息和运行环境检索。

推荐学习顺序

确认平台 → 准备客户端和权限 → 认识界面 → 准备数据 → 创建策略 → 输出日志 → 回测 → 模拟检查 → 交易前验收

文档的使用方式

左侧目录用于切换主题,右侧目录用于跳转当前文章章节。每篇正式文章还有独立地址,便于搜索引擎和 AI 精确定位、引用。

如何确认准备完成

你应当能够登录目标平台、进入策略模块、确认目标业务权限,并运行一个只输出日志的最小策略。进入真实交易之前,还需要完成回测、模拟检查和风险控制。

量化交易基础概念

行情与策略

行情是策略使用的价格、成交量及相关市场数据。策略是把数据、条件、仓位和风险规则写成可重复执行的程序。

信号、委托与成交

信号表示策略认为应该采取某个动作;委托是向模拟撮合或交易柜台提交的订单;成交表示订单已经实际匹配。产生信号不代表一定产生委托,产生委托也不代表一定成交。

资金与持仓

资金决定可买规模,持仓记录已经持有的证券及可用数量。策略下单前必须检查资金、持仓、最小交易单位和重复订单。

回测、模拟与交易

回测在历史数据上验证逻辑;模拟或信号模式在实时行情中检查触发节奏;交易任务可能连接真实账户。三种环境的数据、撮合和权限不同,结果不能直接等同。

风险控制

风险控制包括仓位上限、单笔规模、止损或退出规则、异常停机、重复委托保护和人工接管。回测收益不能替代这些控制。

QMT 与 PTrade 怎么选

QMT 内置 Python 与 PTrade 都能编写和回测 Python 策略,但它们是两套独立平台,函数名称、生命周期、数据结构和交易接口不能混用。

先看实际入口

如果服务机构向你提供迅投 QMT 客户端,并要求在模型研究或模型交易中运行 Python,选择 QMT 内置 Python 文档。如果提供的是 PTrade 策略、回测与交易页面,选择 PTrade 文档。

代码识别

QMT 内置 Python 常见入口为 init(ContextInfo)handlebar(ContextInfo);PTrade 常见入口为 initialize(context)handle_data(context, data)

选择原则

  • 以实际已经开通的平台和账号权限为准。
  • 以目标券商能够提供的行情、业务和交易环境为准。
  • 不因为某个平台存在同名 Python 库,就推断接口能够互换。
  • 迁移策略时重新核对生命周期、代码尾缀、数据返回结构与订单语义。

回测、模拟与真实交易

回测

回测读取历史行情并使用模拟资金和撮合规则运行策略。它适合验证代码路径和研究假设,但会受到数据完整性、手续费、滑点、成交限制和未来数据风险影响。

模拟或信号运行

模拟环境使用实时或近实时行情检查策略触发节奏。信号模式可能只展示信号,不产生真实委托;仿真交易则可能使用模拟柜台。具体含义以目标平台为准。

真实交易

真实交易连接实际资金账户,委托可能发送到交易柜台。进入前应确认账号、权限、交易开关、资金和持仓检查、重复委托保护、异常停止和人工接管方案。

逐级验收

日志探针 → 历史回测 → 实时信号 → 小范围仿真 → 明确授权后的真实交易

每一级都要保存可解释的日志,不能因为上一级正常就跳过下一级检查。

版本、权限与获取说明

客户端获取

QMT 和 PTrade 的客户端或访问入口通常由实际服务机构提供。应通过券商或原开通渠道获取,不使用来源不明的安装包、账号或远程环境。

权限差异

不同机构可能对行情等级、历史数据、Tick、Level2、业务类型、回测、仿真和真实交易设置不同权限。某个函数出现在文档中,不代表当前账号一定可用。

费率信息

费率不单独构成技术文档主目录。涉及佣金、最低收费和其他交易费用时,应标明券商、账户、业务、核验日期和来源,避免把临时营销信息写成长期规则。

文档版本

每篇正式技术文档应记录适用平台、运行环境、来源、最后核验时间和更新记录。平台升级后,应重新检查函数签名、返回结构、运行时间与权限边界。

miniQMT 说明

本知识库的 QMT 主体只介绍 QMT 内置 Python。miniQMT 不设独立目录,仅在常见问题中用于解释历史资料或识别接口混用。

快速开始

一、概述

QMT 极速策略交易系统,以下简称 QMT 系统,内置了 3.6 版本python 运行环境,提供行情数据交易下单两大核心功能。通过编写 python 脚本,可以完成指标计算,策略编写,策略回测,实盘下单等需求。

二、场景需求

QMT 系统支持回测模型实盘模型

内置API 回测模型 实盘模型
内置API 回测模型 实盘模型

回测模型: 指在历史 k 线上,自左向右逐根遍历 k 线,以模拟的资金账号记录每日的买卖信号,持仓盈亏,最终展示策略在历史上的净值走势结果。

实盘模型: 指在盘中收取最新的动态行情,即时发送买卖信号到交易所,判断委托状态,需要实时重复报撤的模型。

两类模型分别有各自的注意点:

回测模型

  1. 回测是遍历固定的历史数据:
    内置API 操作 数据管理 下载全部
    内置API 操作 数据管理 下载全部
    内置API 批量下载
    内置API 批量下载
    • 首先需要下载历史行情,首次下载可以在界面左上角,点击操作,选择数据管理补充行情,选择回测的周期,如日线,所需的板块数据,如沪深A股板块,时间范围选择全部,下载完整历史行情
    • 其次设置每日定时更新,可以点击客户端右下角行情按钮,在批量下载界面选择需要每天更新的数据,勾选定时下载选项,之后每天在指定时间会自动下载行情数据到本地
  2. 回测模型取本地数据遍历,不需要向服务器订阅实时行情,应使用 get_market_data_ex函数,指定subscribe参数为False,来读取本地行情数据。
  3. 回测模型的撮合规则为,指定交易价格在当前k线高低点间的,按指定价格撮合,超过高低点的,按当前 k 线收盘价撮合。委托数量大于可用数量时,按可用数量撮合。
内置API 基本信息 回测参数
内置API 基本信息 回测参数
  1. 回测模型右侧的基本信息,如默认周期,默认主图,在我的界面点击回测时会生效。在行情界面k线下点击回测,以当前 k 线的周期,品种为准。回测必须以副图模式执行,不要选择主图 /主图叠加.

实盘模型

当你回测结束,你需要开始实盘模型,注意这里提到的实盘,指的是接收未来 K 线的数据,生成策略信号,进行交易下单。

提示

实盘模型也分模拟柜台模拟交易真实柜台实盘交易两种。具体请参考如何配置账号在新窗口打开

  1. 你要运行实盘模型,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. 实盘的撮合规则以交易所为准。股票品种的话,价格不能超过 2% 的价格笼子否则废单。数量超过可用数量时会废单。
  3. 实盘模型需要在模型交易界面执行。模型交易界面,选择新建策略交易,添加需要的模型。运行模式可以选择模拟实盘
    • 选择模拟信号模式,在策略信号界面显示买卖信号,不实际发出委托。具体请参考模拟信号模式
    • 选择实盘交易模式,显示的策略信号会实际发出到交易所。具体请参考实盘交易模式
提示

运行模式的模拟实盘,与您使用的账号实际是实盘账号(真实交易所柜台)或是模拟账号(模拟交易柜台)无关。相关账号申请需要联系您做所在券商的工作人员,或者购买投研端账号在新窗口打开获取模拟柜台撮合服务。

三、运行机制对比

QMT 系统提供两大类(事件驱动与定时任务),共三种运行机制。

内置API 三种机制对比
内置API 三种机制对比

逐 K 线驱动:handlebar

handlebar主图历史 k 线+盘中订阅推送。运行开始时,所选周期历史 k 线从左向右每根触发一次handlebar函数调用。盘中时,主图品种每个新分笔数据到达,触发一次handlebar函数调用。

提示

盘中分笔驱动,但是逐 K 线生效。请参考常见问题:系统对象ContextInfo 逐K线保存的机制

事件驱动 :subscribe 订阅推送

盘中订阅指定品种的分笔数据,新分笔到达时,触发指定的回调函数。

定时任务 :run_time 定时运行

指定固定的时间间隔,持续触发指定的回调函数.

不同机制匹配不同场景需求

内置API 不同机制匹配不同场景需求
内置API 不同机制匹配不同场景需求
机制 分类 特点 匹配需求
逐 K 线运行(handlebar 事件驱动 同时支持历史回测和盘中可模拟逐K线效果 在实盘中模拟逐K线运行的效果
订阅推送(subscribe 事件驱动 盘中行情分笔触发函数调用 盘中随分笔行情判断交易
定时运行(run_time 定时任务 固定间隔触发调用 盘中固定时间间隔判断交易

四、逐 K 线驱动(handlebar)示例

因此,结合不同场景需求(回测或实盘),针对不同的机制(定时任务或事件驱动),我们分别给出回测与实盘的完整示例,复制到策略编辑器中即可使用。

在编写策略前,有以下注意事项:

警告

在编写一个策略时,首先需要在代码的最前一行写上: #coding:gbk 统一脚本的编码格式是GBK

缩进需要统一 全部统一为····或者->

回测示例-基于 handlebar

回测的操作流程请参考:界面操作-策略回测

复制代码以下代码到策略编辑器:

#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

实盘的操作流程请参考:界面操作-模型交易

复制代码以下代码到策略编辑器:

#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

#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

#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)}秒')

使用须知

安装路径的选择

在安装 QMT 软件时,请不要安装在C盘,以避免因权限问题导致的使用问题

若是只能安装到C盘,请在启动时选择以管理员权限启动

下载python库

初次使用 QMT 时,请确保补全所需的 Python 库。安装完毕后,不要忘记重启客户端。

提示

在盘中,下载速度会很慢,建议盘前或盘后更新。

下载python库
下载python库

关于ContextInfo

由于底层机制的限制,ContextInfo中存储的变量值将会回滚,即在对ContextInfo中的变量进行修改之后,在下一次handlebar调用时,这些修改将不会保留。具体细节请参阅常见问题在新窗口打开。因此,在完全理解ContextInfo机制之前,请避免在其中存储任何变量。

推荐用法

class G(): pass

g = G()

def init(ContextInfo):
    g.stock_list = ['000001.SZ']

def handlebar(ContextInfo):
    g.stock_list.append('600000.SH')

错误用法

警告

下面的示例请勿使用

def init(ContextInfo):
    ContextInfo.stock_list = ['000001.SZ']

def handlebar(ContextInfo):
    ContextInfo.stock_list.append('600000.SH')

关于线程和进程

QMT中,python无法使用多线程和多进程,而且所有策略都在同一线程中执行,所以策略中应该尽量避免阻塞类的写法,否则会影响其他策略的执行。

主图解析

如下图所示,策略执行依赖于K线图。这里所说的主图即是K线图,策略正是在K线图上运行,也是由它驱动的(也有非K线驱动的策略写法,详见快速入门)。

K线回放:策略在客户端运行时会从第一根K线开始,依次调用handlebar函数,直至最后一根K线。并且在盘中,每一个新的行情快照都会触发一次handlebar函数调用(无论主图的周期如何)。如果想要过滤掉某些K线,可以设置右侧的快速计算,或使用ContextInfo. is_last_bar ()函数进行过滤。

内置API K线回放
内置API K线回放

策略运行无反应/运行报错提示 "run script failed! "

最快解决方法是点击右上角布局按钮,选择恢复默认布局

如果策略运行后无任何反应,首先检查客户端是否有其他策略正在运行,如果有,请先将其停止,然后重试。检查方法如下图所示:

内置API 停止策略1
内置API 停止策略1
内置API 停止策略2
内置API 停止策略2
内置API 停止策略3
内置API 停止策略3
内置API 停止策略4
内置API 停止策略4
提示

最后建议重启客户端

数据下载

QMT提供了许多接口来依赖数据下载功能。客户端的数据下载功能如下图所示:

而且,在批量下载中可以设置定时下载,这样可以方便地每天自动下载当日的行情数据。

内置API 数据下载1
内置API 数据下载1
内置API 定时下载
内置API 定时下载

界面操作

新建策略

模型创建方法有三种:

方法一,在【模型研究】界面,使用系统预置的各种示例模型,点击后方“编辑”按钮,并在弹出的【策略编辑器】中以此示例模型代码为基础进行编写。

新建策略 方法一
新建策略 方法一

我的主页-编辑模型

方法二,在【模型研究】界面,点击新建模型,选择 Python 模型,在弹出的【策略编辑器】中从头到尾编写一个用户自己的量化模型。

新建策略 方法二
新建策略 方法二

模型研究-新建模型

方法三,在模型管理面板右键,选择新建模型,并选择 Python 模型。

新建策略 方法三
新建策略 方法三

模型管理-新建模型

导入导出策略

QMT系统支持将策略以加密的模式进行导出或导入,用户可以便捷的迁移系统本地策略。

Snipaste 2022-08-10 18-32-20
Snipaste 2022-08-10 18-32-20

方式一.模型研究界面导入导出

Snipaste 2022-08-10 18-43-19
Snipaste 2022-08-10 18-43-19

方式二.模型研究界面导入导出

策略编写

【策略编辑器】是迅投专门为模型开发者设计的,集成了模型列表、函数列表、函数帮助、模型基本信息、参数设置、回测参数等多个部分,拥有代码高亮、自动补全等便捷功能于一体的便捷的模型编辑、开发环境。

image12
image12

模型编辑页面 右侧可选择策略默认的周期、品种

编写 Python 策略需在开始时定义编码格式,如 gbk

之后可选择导入第三方库,所选第三方库要在券商管理端白名单内才可运行。

Init 方法和 handlebar 方法的定义是必须的。Init 方法会在策略运行开始时调用一次,用以初始化所需对象(包裹在 ContextInfo 对象中传递),设定股票池等。

image13
image13

Handlebar 方法会在历史 K 线上逐 K 线调用,系统会保存函数所做更改。

在盘中交易时间,handlebar 函数会随行情推送(tick 数据)被调用,当一个 tick 数据为所在 K 线最后一个 tick 时,此 tick 调用的 handlebar 所做的更改会被系统保存,如有交易指令,会在下一根K 线的第一个 tick 到来时发送;其他 tick 可以打印运行结果,但 handlebar 所做更改不会被保存,也不会发送交易信号。

编写创建完模型后,对应模型的基本信息和回测参数进行设置。

基本信息-字段描述

字段 描述
名称 填写模型名称
快捷码 默认根据模型名称自动生成拼音首字母拼写,如需自定义可以手动进行更改,用于键盘精灵快速引用模型
说明 简单的说明模型功能
分类 保存当前模型到某个分类下面
位置 模型回测或运行时的位置,有副图、主图叠加、主图三种显示位置
默认周期 点击模型回测或运行时的默认主图周期,可手动切换
默认品种 点击模型回测或运行时的默认主图品种,可手动切换
复权方式 提供不复权、前复权、后复权、等比前复权、等比后复权 5 种复权方式
快速计算 限制计算范围,默认为 0 时模型运行会从模型设置的默认品种(主图)的第一根 K 线开始计算,设置为 n 则从当前 K 线再往前 n 个 K 线开始计算
刷新间隔 用来设置策略运行的时间间隔。设置了刷新间隔,即每隔一段时间策略按照当前行情运行一次
加密公式 加密后的公式只有输入密码才可以查看源代码
凭密码导出公式 此项只有在开启 “加密公式” 后才能生效,生效后只能使用密码导出到本地
用法注释 简短的说明模型使用的一些注意项,可不填
image14
image14

策略编辑器-基本信息

回测模式指策略以历史行情为依据进行运算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表现。

回测参数-字段描述

字段 描述
**开始时间
结束时间** 设置模型回测时间区间
基准 设置模型收益的参考基准
初始资金 设置模型回测的初始资金
保证金比例 设置期货的保证金比例
滑点 设置回测撮合时的滑点,模拟真实交易的冲击成本
手续费类型 支持按成交额比例或者固定值计算手续费
买入印花税 设置买入印花税比例
卖出印花税 设置卖出印花税比例
最低佣金 设置单笔交易的最低佣金数额
买入佣金 设置买入标的时的佣金比例
平昨佣金 设置股票、期货平昨佣金比例
平今佣金 设置期货平今佣金比例
最大成交比例 控制回测中最大成交量不超过同期成交量*最大成交比例。可以点击此参数旁边的'?'按钮了解详情
image15
image15

策略编辑器-回测参数

使用者也可在参数设置中设置好参数值,参数名为变量名,模型中可以调用。最新值为变量默认值,运行/回测模式使用。

其中最小 / 最大 / 步长项,为遍历参数。初始项可不填。最小 / 最大都是包含在遍历区间内的,如图所示三个变量,测评时会遍历(20-3+1)[(160-140)/10+1][(-150+250)/10+1] 种组合。

image16
image16

策略编辑器-参数设置

点击公式测评,可选择回测模式支持的指标,如单位净值,最大回撤等,作为评价标准。

image17
image17

策略编辑器-公式评测

点击优化,评测结果弹窗显示不同参数变量组合下的回测结果,根据结果选择最优参数组合。可点击所需指标进行排序。需要注意的是,在测评之前,需要针对所选品种和周期补充数据。

image18
image18

补充数据

在创建用户的模型之前,用户应使用客户端提供的“数据管理”功能,选择并补充模型所需的相应市场、品种以及对应周期的历史数据。

image19
image19

操作-数据管理

策略运行

策略编写完毕后,点击编译,可保存策略。编译按钮在 Python 策略中只起保存功能,不会检查语法与引用的正误。之后点击运行可以看到策略运行效果(如有错误,会在日志输出的位置报错)。

image20
image20

策略编辑器-运行

如当前系统所处界面为“行情”界面或“交易”界面,点击运行之前,需在行情中手动设置好 K 线品种和周期,点击运行后,策略即可在当前主图下运行,如下图所示。

image21
image21

策略运行状态之一

如系统当前界面处于“我的主页”界面或“模型研究”和“模型交易”等非行情界面,点击运行时,会基于策略编辑器 - 基本信息中所设置的默认周期和默认品种运行。

image22
image22

策略运行状态之二

当选择的运行位置为副图时, 如想关闭策略,将主图下方策略运行的附图关闭即可。

image24
image24

关闭运行中的策略之一

image25
image25

关闭运行中的策略之二

当选择的运行位置为主图叠加时,如想关闭策略,在主图上右键单击取消叠加指标即可。

当选择的运行位置为主图时,键盘精灵输入KLINE即可结束模型运行。

关闭运行中的策略之三

点击策略编辑器上放的停止按钮

stop
stop

策略调试

如果策略运行不成功,需要进行策略调试这一步。当运行出错时,报错信息会显示在日志输出面板,以供修改调试之用。

image26
image26

策略调试-输出日志

独立python进程

注意

在您充分理解软件使用前,不建议开启该功能

勾选此功能后,程序将把代码作为main执行脚本,不会触发init,handlebar等函数

反之,系统会import策略,按规则触发init handlebar等函数

内置API 独立python
内置API 独立python

策略回测

对某一策略编译成功后,点击回测,可以通过日志输出查看模型基于历史行情数据回测情况和表现。

在回测之前,需要设置好策略回测运行的主图品种和周期,以及相关的回测参数。回测主图和周期可以在策略编辑器-基本信息中进行设置,回测开始和结束时间、基准、费率等可以在策略编辑器 - 回测参数中设置。

用户在回测前,需根据此策略回测运行的主图、周期和时间,在【数据管理】中对行情数据进行下载补充。如回测时间设置为 20180930 至 20190530 ,运行主图为 SZ.000001 平安银行日线,补充数据时可进行如下设置。

image27
image27

操作-数据管理

如果回测正常的话,主界面会跳转到模型设置的默认标的和默认周期界面,并输出模型绩效分析结果。

image28
image28

策略编辑器-模型回测

此时,可最小化或者关闭【策略编辑器】,并对回测结果进行分析,随着光标在 K 线主图上的移动,右边回测结果展示窗口会动态显示截止光标所在当日的绩效分析结果(包括年化收益,基准年化收益,单位净值,下方差,信息比率,夏普比率,波动率,索提诺比率,阿尔法系数,贝塔系数,跟踪误差,最大回撤,胜率等)、当日买入、当日卖出、持仓列表。

以上列表均可鼠标右键复制和导出数据。

image29
image29

回测结果分析-回测结果随十字光标移动动态展示

如需根据模型生成的买入、卖出列表进行手工交易,则可直接点击“买入'或“卖出'按钮,系统会弹出下单界面由用户进行确认后进行普通交易下单或算法交易下单。交易方式可点击卖出按钮右侧的普通交易进行切换设置。

image30
image30

回测结果买入

副图回测指标:提供图形化的展示,除去绩效分析的相关指标外,用户可以通过编辑模型代码自定义输出一些特色指标,鼠标右键可以选择复制模型运行结果(每一天的数据)。

image31
image31

回测结果分析-附图指标输出

另外,回测结果还提供了持仓分析、历史板块汇总、操作明细、日志输出等信息,方便用户进行深入分析。

说明

持仓分析: 可查看光标所在当天持仓的行业分布,展示在相关行业的市值情况、盈利情况、权重以及股票数量情况,鼠标右键可以复制和导出数据;可切换对比基准,和模型持仓进行对比。

历史板块汇总: 可查看模型自回测日期以来到光标所在日期该模型交易标的的汇总信息,包括累计盈亏、累计交易量、累计交易额、持仓天数等;点击选择板块,可以自行选择其常用板块进行板块的各项数据累计汇总;汇总数据均可以进行排序,鼠标右键可以复制和导出数据。

操作明细: 可查看模型回测的历史每一笔交易的明细。

日志输出: 可用于调试输出模型回测和运行情况。

image32
image32

回测结果分析-绩效分析、当日买入、当日卖出、当日持仓

image33
image33

回测结果分析-持仓分析

image34
image34

回测结果分析-历史品种汇总、历史板块汇总

image35
image35

回测结果分析-操作明细、日志输出

回测、运行两种模式的区别

在模型编辑器中,有“回测”和“运行”两个按钮,分别代表两种模式,它们之间的区别如下:

(1)回测模式指策略以历史行情为依据,以回测参数中的开始时间、结束时间为回测时间区间进行运算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表现。

(2)运行模式指策略根据实时行情信号进行运算,以主图行情开始时间到当前时间为运行区间,进行策略的模拟运行,但不进行真实的委托。

注意

如果需要向模拟/实盘柜台发送真实的委托,请将策略加入到“模型交易”中。

配置/获取模拟账号

注意
  1. 券商QMT的模拟账号通常联系对应券商解决相关问题
  2. 以下均为迅投模拟账号相关指南
  3. 迅投模拟账号的格式如下
    1. 股票账号:200xxxx
    2. 期货账号:100xxxx
    3. 期权账号:600xxxx
提示
  1. 新用户注册投研账号,可获得 14 天模拟仿真交易体验
  2. VIP权限用户可以通过用户中心 - 下载中心的客户端进行模拟交易,交易支持股票/期货/股票期权三个市场
  1. 投研服务平台在新窗口打开登录您的投研账号,如您没有投研账号,请先注册在新窗口打开
  2. 点击右上角的用户中心,选择下方栏目的模拟撮合按钮,可以看到您的投研模拟账号
模拟账号
模拟账号
  1. VIP权限用户可以通过用户中心 - 下载中心的客户端进行模拟交易,交易支持股票/期货/股票期权三个市场
模拟交易环境说明
模拟交易环境说明
  1. 客户端配置账号
交易账号登录
交易账号登录

自动导出交易记录

内置API 自动导出交易记录
内置API 自动导出交易记录

操作界面快捷键

操作 描述
SHIFT+Q 分时 K线 附图变量查看器
SHIFT+G k线 附图组合模型持仓界面
SHIFT+L k线 锁定十字线
SHIFT+S 星空图
CTRL+Windows键 快速唤起多屏
CTRL+O 分时 K线 叠加品种
CTRL+Z 分时 K线 添加自选
CTRL+M 跳转到多股同列界面
CTRL+X 跳转到多周期同列界面
CTRL+ K线 多股同列 向左快捷移动十字线
CTRL+ K线 多股同列 向右快捷移动十字线
CTRL+R k线 移动十字线到当前界面结尾
CTRL+V k线 切换复权方式为等比前复权/不复权
CTRL+B k线 切换复权方式为等比后复权/不复权
CTRL+A 分时 k线 浏览列表 样板股分析
CTRL+E 分时 k线 浏览列表 预警雷达
ALT+数字 (1~9) 分时 K线 设置附图指标数量
ALT+ 分时 K线 显示走势图
ALT+ 分时 K线 显示走势图
F3 切换到上证指数分时图
F4 切换到深证成指分时图
F5 切换到分时/K线图
F6 切换到“我的自选”板块浏览列表
F8 K线 循环切换周期
F10 个股切换财务数据界面,指数切换到成分股界面

策略编辑器快捷键

操作 描述
Ctrl+C 复制
Ctrl+X 剪切
Ctrl+V 粘贴
Ctrl+Q 多行注释
Ctrl+Z 撤消
Ctrl+Y 恢复
Ctrl+A 全选
Ctrl+F 键查找对话框启动
Ctrl+D 复制并粘贴当行
Ctrl+L 删除当前行
Ctrl+T 当行向上移动一行
Ctrl+S 保存文件

创建第一个 QMT Python 策略

QMT 内置 Python 策略在“模型研究”中创建。你可以编辑系统示例,也可以新建一个空白 Python 模型。

新建步骤

  1. 登录 QMT 客户端并进入“模型研究”。
  2. 点击“新建模型”,选择“Python 模型”;也可以在模型管理面板右键新建。
  3. 输入模型名称,在策略编辑器中设置默认品种、默认周期和运行位置。
  4. 编写 init(ContextInfo)handlebar(ContextInfo)
  5. 点击“编译”保存模型。
编译按钮的含义

迅投官方界面说明指出,Python 策略中的“编译”按钮主要用于保存,不会完整检查语法和引用是否正确。错误通常会在点击“运行”或“回测”后显示在日志输出面板。

最小代码

# coding:gbk

def init(ContextInfo):
    print('INIT_OK')

def handlebar(ContextInfo):
    if ContextInfo.is_last_bar():
        print('HANDLEBAR_OK barpos=%s' % ContextInfo.barpos)

创建完成的判断标准

  • 模型能够保存并再次打开。
  • 基本信息中已经设置目标品种和周期。
  • 代码同时包含 inithandlebar
  • 点击运行后,日志面板能看到 INIT_OK;有 K 线驱动时还能看到 HANDLEBAR_OK

运行第一个 QMT 策略

“运行”使用当前或默认主图的行情驱动策略,用于检查代码能否进入生命周期和输出结果,不等同于模型交易。

运行步骤

  1. 保存策略代码。
  2. 如果当前位于行情或交易界面,先选择主图证券与周期。
  3. 如果当前位于模型研究等非行情界面,确认模型基本信息中的默认品种和默认周期。
  4. 点击“运行”。
  5. 查看日志输出面板。

最小验收日志

INIT_OK
HANDLEBAR_OK barpos=...

只出现 INIT_OK 时,优先检查主图品种、周期和本地行情数据。完全没有日志时,先确认运行的是刚刚保存的模型,而不是旧副本。

运行与真实委托的边界

策略编辑器中的“运行”用于实时行情下的模拟运行。需要向模拟或实盘柜台发送委托时,应在完成回测与信号检查后,将模型加入“模型交易”,并再次确认账号、运行模式和交易开关。

QMT 第一次回测

QMT 回测会在本地历史 K 线上逐根运行策略,并使用模拟资金账号记录委托、成交、持仓和净值。

回测前准备

  • 在模型基本信息中设置默认主图品种、默认周期和复权方式。
  • 在回测参数中设置开始时间、结束时间、基准、初始资金、手续费、滑点和最大成交比例。
  • 在“操作 → 数据管理”中下载覆盖回测区间的对应历史行情。
  • 确认代码已保存,并能在日志中输出初始化标记。

执行回测

  1. 打开目标模型。
  2. 再次核对主图、周期和回测区间。
  3. 点击“回测”。
  4. 查看日志输出,确认策略逐根处理 K 线。
  5. 回测完成后检查绩效分析、当日买卖、持仓、操作明细和日志。

如何判断回测成功

回测成功不等于策略有效。技术验收至少包括:没有未处理异常;运行区间正确;日志中的日期和 K 线持续变化;委托、成交与持仓能够相互对应;绩效面板能够显示结果。

不要只看收益率

年化收益率、夏普比率和最大回撤属于研究结果。还需要核对基准、费用、滑点、成交比例、数据完整性和未来数据风险,不能把一次回测结果当作未来收益承诺。

运行 QMT 模拟信号

模拟信号模式接收未来实时 K 线并显示策略买卖信号,但不实际发送委托。它适合放在历史回测与模型交易之间,用来检查实时触发节奏。

开始前检查

  • 历史回测已经能够完整运行。
  • 实时行情连接正常。
  • 主图品种、周期和复权方式与预期一致。
  • 策略日志能够区分初始化、无信号和产生信号三种状态。

重点观察

  • handlebar 是否按预期的行情节奏触发。
  • 信号是否只在设计的 K 线或时点出现。
  • 重启策略后,状态是否符合设计。
  • 日志中的证券、时间、价格和信号原因是否完整。

模拟信号没有真实成交和柜台回报,不能用它证明真实委托一定能够成交。

进入 QMT 模型交易

模型交易用于让策略接收实时行情,并根据所选运行模式处理交易指令。它可能连接模拟或真实交易账号,因此必须与策略编辑器中的普通“运行”明确区分。

进入前的最低条件

  • 回测已经通过技术验收,并核对费用、滑点与成交限制。
  • 模拟信号运行稳定,日志可以解释每次信号。
  • 账号类型、账号状态和交易权限已经确认。
  • 下单代码有显式交易开关、重复委托保护、资金与持仓检查。
  • 已准备停止策略和人工接管方案。

操作路径

  1. 进入“模型交易”。
  2. 新建策略交易并添加目标模型。
  3. 选择账号、品种和运行模式。
  4. 核对是否允许真实委托。
  5. 先以最小风险范围运行,观察初始化、行情、信号、委托回报和持仓。
真实资金风险

模型交易可能产生真实委托。页面文档只能说明通用流程,券商客户端版本、账号权限和交易柜台限制必须以实际服务机构及目标客户端为准。

策略运行机制

本章深入讲解 QMT 内置 Python 的策略运行机制,包括生命周期、回调函数和运行模式。

策略生命周期

QMT 策略从启动到停止,经历以下阶段:

加载策略 → 调用 init() → 等待行情 → 调用 handlebar() → 策略停止

生命周期详解

  1. 加载阶段:QMT 读取策略文件,检查语法
  2. 初始化阶段:调用 init(ContextInfo),仅执行一次
  3. 运行阶段:每根 K 线触发 handlebar(ContextInfo)
  4. 停止阶段:用户手动停止或客户端关闭
提示

init 函数中适合做一次性初始化工作,如设置股票池、初始化变量等。

核心回调函数

init

def init(ContextInfo):
    """策略初始化,仅调用一次"""
    # 设置股票池
    ContextInfo.set_universe(['000001.SZ'])
    # 初始化全局变量
    ContextInfo.counter = 0

handlebar

def handlebar(ContextInfo):
    """每根 K 线触发一次"""
    # 获取当前 K 线数据
    close = ContextInfo.get_close_price()
    # 判断是否为最新 K 线
    if ContextInfo.is_last_bar():
        print(f'最新收盘价: {close}')

回调执行顺序

init() → handlebar(K线1) → handlebar(K线2) → ... → handlebar(K线N)

运行模式

回测模式

  • 使用历史数据
  • 按时间顺序逐根回放 K 线
  • 不产生真实委托
  • 可查看收益曲线和统计指标

模拟信号模式

  • 使用实时行情
  • 产生模拟委托信号
  • 不执行真实交易
  • 适合验证策略实时表现

真实交易模式

  • 使用实时行情
  • 产生真实委托
  • 涉及真实资金
  • 需要充分测试后使用
注意

从回测切换到真实交易前,务必经过模拟信号模式的充分验证。

K 线触发机制

触发时机

handlebar 在每根 K 线完成时触发:

  • 日线策略:每个交易日收盘后触发
  • 分钟线策略:每根分钟 K 线结束时触发
  • Tick 策略:每个 Tick 数据到达时触发

is_last_bar 判断

def handlebar(ContextInfo):
    # 回测模式下,所有 K 线都会触发
    # 模拟/实盘模式下,只有最新的 K 线需要处理
    if not ContextInfo.is_last_bar():
        return  # 跳过历史 K 线
    
    # 处理最新 K 线
    close = ContextInfo.get_close_price()
    print(f'最新价格: {close}')

多周期触发

如果策略订阅了多个周期的数据,handlebar 会按各周期分别触发。

ContextInfo 对象

ContextInfo 是策略运行的核心上下文对象,贯穿整个生命周期。

常用属性

属性 类型 说明
stockcode str 当前品种代码
period str 当前周期
timetag int 当前 K 线时间戳
barpos int 当前 K 线位置
do_back_test bool 是否回测模式

常用方法

# 设置股票池
ContextInfo.set_universe(['000001.SZ', '600000.SH'])

# 获取收盘价
close = ContextInfo.get_close_price()

# 判断是否最新 K 线
is_last = ContextInfo.is_last_bar()

# 获取历史数据
history = ContextInfo.get_history_data('close', 20)

# 自定义变量存储
ContextInfo.my_var = '自定义数据'

策略状态管理

全局变量

ContextInfo 上挂载自定义变量,可在不同回调间共享:

def init(ContextInfo):
    ContextInfo.position = {}  # 持仓字典
    ContextInfo.last_signal = None  # 上次信号

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    # 读取上次信号
    if ContextInfo.last_signal:
        print(f'上次信号: {ContextInfo.last_signal}')
    # 更新信号
    ContextInfo.last_signal = 'buy'

持久化

策略重启后,ContextInfo 上的自定义变量会丢失。需要持久化的数据应保存到文件:

import json

def save_state(ContextInfo):
    """保存策略状态"""
    state = {'position': ContextInfo.position}
    with open('strategy_state.json', 'w') as f:
        json.dump(state, f)

def load_state(ContextInfo):
    """加载策略状态"""
    try:
        with open('strategy_state.json', 'r') as f:
            state = json.load(f)
            ContextInfo.position = state['position']
    except FileNotFoundError:
        ContextInfo.position = {}

错误处理

常见错误类型

  • 数据获取错误:品种不存在、数据未下载
  • 交易接口错误:权限不足、资金不够
  • 语法/运行时错误:代码 bug、类型错误

错误处理最佳实践

def handlebar(ContextInfo):
    try:
        close = ContextInfo.get_close_price()
        if close is None:
            print('警告:获取收盘价失败')
            return
        # 策略逻辑...
    except Exception as e:
        print(f'策略异常: {e}')

变量约定

函数命名规则

  • 函数名以 get_ 开头的,表示数据来源于客户端内存
  • 函数名以 query_ 开头的,表示数据是向服务查询

账号类型说明

  • 'FUTURE' - 期货账号
  • 'STOCK' - 股票账号
  • 'CREDIT' - 信用账号
  • 'FUTURE_OPTION' - 期货期权
  • 'STOCK_OPTION' - 股票期权
  • 'HUGANGTONG' - 沪港通
  • 'SHENGANGTONG' - 深港通

symbol_code - 代码表示

迅投代码(symbol_code)是迅投平台统一用于表示交易标的的代码 其格式为:交易标的代码.交易所代码,例如深圳证券交易所的平安银行,迅投代码为000001.SZ(不区分大小写)。代码表示可以在迅投研终端的行情列表或者按键精灵中查询。

迅投研终端示例
迅投研终端示例

交易所代码

目前迅投研支持国内12个交易所,12个交易所的代码缩写如下:

交易所名称 迅投简称 显示后缀
上海证券交易所 SH SH
深圳证券交易所 SZ SZ
北京证券交易所 BJ BJ
香港证券交易所 HK HK
沪港通 HGT HGT
深港通 SGT SGT
中国金融期货交易所 IF CFFEX
上海期货交易所 SF SHFE
大连商品交易所 DF DCE
郑州商品交易所 ZF CZCE
上海国际能源交易中心 INE INE
广州期货交易所 GF GFEX

迅投研系统目前支持一站式获取全球多市场数据,详情链接:全球市场数据在新窗口打开

全球行情展示
全球行情展示

交易标的代码

交易标的代码是指交易所给出的交易标的代码, 包括股票(如 600000), 期货(如 rb2011), 期权(如 10002498), 指数(如 000001), 基金(如 510300)等代码。

注意

对于期货合约代码来说,我们仅对market做了简化处理,symbol仍遵守交易所标准命名规则,且严格区分大小写,例如AP401.ZF不能写成ap401.ZF,rb2401.SF不能写成RB2401.SF

symbol示例

市场中文名 市场代码 示例代码 显示后缀 证券简称
上交所 SH 600000.SH SH 浦发银行
深交所 SZ 000001.SZ SZ 平安银行
北交所 BJ 830779.BJ BJ 武汉蓝电
中金所 IF IC2311.IF CFFEX 中证 500 指数 2023 年 11 月期货合约
上期所 SF rb2311.SF SHFE 螺纹钢 2023 年 11 月期货合约
大商所 DF m2311.DF DCE 豆粕 2023 年 11 月期货合约
郑商所 ZF FG305.ZF CZCE 玻璃 2023 年 5 月期货合约
上海国际能源交易中心 INE sc2311.INE INE 原油 2023 年 11 月期货合约
广期所 GF lc2405.GF GFEX 碳酸锂 2024 年 05 月期货合约
上证期权 SHO 10005334.SHO SH 50ETF购12月2650
深证期权 SZO 90002114.SZO SZ 深证100ETF沽12月2700
板块指数 BKZS 290001.BKZS BKZS 工业品期货板块指数

期货主力连续合约

仅支持回测模式下交易,期货主力连续合约为量价数据的简单拼接,未做平滑处理,如rb00.SF螺纹钢主连合约,其他[主连合约代码请参考](期货数据 | 迅投知识库 (thinktrader.net))

期货加权连续合约

仅支持回测模式下交易,期货加权连续合约为迅投按照一定规则加权合成的连续合约,相比主力连续合约更加平滑,如rbJQ00.SF,其他[加权合约代码参考](期货数据 | 迅投知识库 (thinktrader.net))

mode - 模式选择

迅投研终端中,策略可以以四种模式运行,分别为调试运行模式回测模式,模拟信号模式,实盘交易模式,模式需要在运行策略时手动选择

调试运行模式

调试运行模式需要在策略编辑界面点击编辑栏上方的运行,该模式下策略会以实时行情进行运算,但迅投研终端不会记录交易信号

迅投研终端示例
迅投研终端示例

回测模式

回测模式需要在策略编辑界面点击编辑栏上方的回测,该模式下策略会以右侧栏设定的回测周期推进行情进行运算,回测模式下,发生的交易会被记录在回测结果页面

迅投研终端示例
迅投研终端示例

模拟信号模式

模拟信号模式需要在策略交易界面,在左侧策略文件栏中选择要进行计算运行的策略,点击右侧圆形按钮选择模拟,点击三角形运行按钮后策略会以实时行情进行运算,该模式下调用的下单函数(passorder)不会产生实际交易,仅会记录交易信号在下方的策略信号栏中

迅投研终端示例
迅投研终端示例

实盘交易模式

实盘交易模式需要在策略交易界面,在左侧策略文件栏中选择要进行计算运行的策略,点击右侧圆形按钮选择实盘,点击三角形运行按钮后策略会以实时行情进行运算,该模式下调用的下单函数(passorder)会对账户实际下单,同时交易信号会记录在下方的策略信号栏中

迅投研终端示例
迅投研终端示例

ContextInfo - 上下文对象

ContextInfo.start/ContextInfo.end - 回测开始/结束时间

注意

一、此属性只在回测模式生效;

二、仅在init中设置生效,应在init中设置完毕;

三、缺省值为策略编辑界面设定的回测时间范围;

四、回测起止时间也可在策略编辑器的回测参数面板中设置,若两处同时设置,则以代码中设置的值为准;

五、结束时间小于等于开始时间则计算范围为空。

释义

可通过此属性设定回测开始/结束的时间,以%Y-%m-%d %H:%M:%S格式传入

原型

ContextInfo.start # 回测开始时间属性
ContextInfo.end # 回测结束时间属性

返回值none

示例

# coding:gbk
def init(ContextInfo):
	ContextInfo.start = "2017-01-01 00:00:00"# 回测开始时间为 2017-01-01
	ContextInfo.end = "2020-01-01 00:00:00"# 回测结束时间为 2020-01-01
def handlebar(ContextInfo):
	# 打印输出当前回测时间
	print(timetag_to_datetime(ContextInfo.get_bar_timetag(ContextInfo.barpos), "%Y-%m-%d %H%M%S"))
2017-01-03 103000
2017-01-03 113000
2017-01-03 140000
2017-01-03 150000
2017-01-04 103000
2017-01-04 113000
2017-01-04 140000
2017-01-04 150000
2017-01-05 103000
2017-01-05 113000
...

ContextInfo.capital - 设定回测初始资金

注意

此函数只支持回测模式。回测初始资金也可在策略编辑器的回测参数面板中设置,若两处同时设置,则以代码中设置的值为准。

释义 设定回测初始资金,支持读写,默认为 1000000

原型

ContextInfo.capital = 10000000 # 设定ContextInfo.capital 值为10000000

返回值float类型的数值,代表当前策略设定的回测金额

示例

# coding:gbk
def init(ContextInfo):
    ContextInfo.capital = 10000000
def handlebar(ContextInfo):
    print(ContextInfo.capital)
10000000.0
10000000.0
10000000.0
...

ContextInfo.period - 获取当前周期

释义 获取当前周期,即基本信息中设置的默认周期,只读

原型

ContextInfo.period

返回string,返回值含义:

含义
'1d' 日线
'1m' 1分钟线
'3m' 3分钟线
'5m' 5分钟线
'15m' 15分钟线
'30m' 30分钟线
'1h' 小时线
'1w' 周线
'1mon' 月线
'1q' 季线
'1hy' 半年线
'1y' 年线

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.period)
1d

ContextInfo.barpos - 获取当前运行到 K 线索引号

释义

获取主图当前运行到的 K 线索引号,只读,索引号从0开始

原型

ContextInfo.barpos

返回值int类型值,代表着当前K线的索引号

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.barpos)
0
1
2
3
4
5
...

ContextInfo.time_tick_size - 获取当前图 K 线数目

释义

获取当前图 K 线bar的数量,只读

原型

ContextInfo.time_tick_size

返回值int

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.time_tick_size)
5297
5297
5297
5297
5297
5297
...

ContextInfo.stockcode - 获取当前图代码

释义

获取当前主图代码,只读

原型

ContextInfo.stockcode

返回值string:对应主图代码

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.stockcode)
000300
000300
000300
000300
000300
...

ContextInfo.market - 获取当前主图市场

释义

获取当前主图市场,只读

原型

ContextInfo.market

返回值string:对应主图市场

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.market)
SH
SH
SH
SH
SH
...

ContextInfo.dividend_type - 获取当前主图复权处理方式

释义

获取当前主图复权处理方式

原型

ContextInfo.dividend_type

返回值string,返回值含义:

含义
'none' 不复权
'front' 向前复权
'back' 向后复权
'front_ratio' 等比向前复权
'back_ratio' 等比向后复权

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.dividend_type)
front_ratio
front_ratio
front_ratio
front_ratio
front_ratio
...

ContextInfo.benchmark - 获取回测基准标的

注意

该属性只在回测模式可用

释义 获取回测基准的代码,只读

原型

ContextInfo.benchmark

返回值string

示例

# coding:gbk
def init(ContextInfo):
    pass
def handlebar(ContextInfo):
    print(ContextInfo.benchmark)
000300.SH
000300.SH
000300.SH
000300.SH
000300.SH
...

ContextInfo.do_back_test - 表示当前是否为回测模式

释义

表示当前是否为回测模式,只读,默认值为 False

原型

ContextInfo.do_back_test

返回值bool

行情与数据获取

本页按任务列出常用行情函数。右侧目录直接显示函数名;点击函数标题下方的链接,可进入对应独立 API 页面查看完整参数、返回说明、运行环境和官方来源。

历史与 K 线数据

ContextInfo.get_market_data_ex

推荐用于获取单个或多个证券的 K 线、Tick 和历史行情数据,可指定字段、周期、起止时间、数量及复权方式。

调用语法

ContextInfo.get_market_data_ex(
    fields=[], stock_code=[], period='follow',
    start_time='', end_time='', count=-1,
    dividend_type='follow', fill_data=True, subscribe=True,
)

关键参数

参数 类型 说明
fields list 数据字段,如 openhighlowclosevolumeamount
stock_code list[str] 合约代码列表,如 ['000001.SZ', '600000.SH']
period str tick1m5m15m1h1d1wl2quote
start_time str 开始时间,格式为 YYYYMMDDYYYYMMDDhhmmss
end_time str 结束时间;空字符串表示截止到最新数据
count int 返回的数据条数,-1 表示按时间范围获取
dividend_type str nonefrontbackfront_ratioback_ratio
fill_data bool 是否填充缺失数据
subscribe bool 是否同时订阅行情;只读本地数据时设为 False

返回值

返回以证券代码为键的 dict。每个证券通常对应一个 pandas.DataFrame,索引为时间,列为所请求字段。

使用注意

  • 不建议在 init 中调用;在 init 中只能读取本地已有数据。
  • 历史数据为空时,先检查对应证券和基础周期是否已下载。
  • Level-2 周期需要对应行情权限。
  • subscribe=False 不会发起订阅,只读取本地已有数据。
def handlebar(ContextInfo):
    data = ContextInfo.get_market_data_ex(
        fields=['open', 'high', 'low', 'close', 'volume'],
        stock_code=['000001.SZ'],
        period='1d',
        count=20,
        dividend_type='front',
        fill_data=True,
        subscribe=False,
    )
    print(data)

查看 ContextInfo.get_market_data_ex 完整参数与返回说明

download_history_data

将指定证券、周期和时间范围的历史行情下载到本地。历史数据为空时,应先确认客户端已完成数据下载。

调用语法与参数

download_history_data(stockcode, period, startTime, endTime)
参数 类型 说明
stockcode str 证券代码,如 600000.SH
period str 基础周期支持 tick1m5m1d
startTime str 起始时间,可为空
endTime str 结束时间,可为空

返回值为 None。获取 15m 等合成周期历史数据时,应下载其基础周期,例如 15m5m 合成。

download_history_data('000001.SZ', '1d', '20240101', '20241231')

查看 download_history_data 完整说明

ContextInfo.get_history_data(不推荐)

旧版历史行情接口。官方目录已标记为“不推荐”,新代码优先使用 ContextInfo.get_market_data_ex

调用语法与返回值

ContextInfo.get_history_data(len, period, field, dividend_type=0, skip_paused=True)

调用前需要先通过 ContextInfo.set_universe() 设置股票池。返回 dict,键为证券代码,值为按时间从早到晚排列的行情列表。

history = ContextInfo.get_history_data(20, '1d', 'close', 0, True)

查看 ContextInfo.get_history_data 兼容说明

实时与全推行情

ContextInfo.get_full_tick

主动获取指定证券的最新全推快照,适合读取最新价、成交量和买卖盘等实时字段。

调用语法与返回值

ContextInfo.get_full_tick(stock_code=[])

stock_code 为证券代码列表。返回外层以证券代码为键的 dict,每个值为该证券最新 Tick 字段字典。

该函数不能用于回测,只能获取最新分笔,不能获取历史分笔。

ticks = ContextInfo.get_full_tick(['000001.SZ', '600000.SH'])
print(ticks.get('000001.SZ'))

查看 ContextInfo.get_full_tick 完整字段说明

ContextInfo.subscribe_whole_quote

订阅证券列表的全推行情。适合需要行情变化后持续处理数据的场景;不再使用时应取消订阅。

调用语法与返回值

ContextInfo.subscribe_whole_quote(code_list, callback=None)

code_list 可以是市场列表(如 ['SH', 'SZ'])或证券代码列表。callback 接收增量推送数据。函数返回整数订阅号,后续用于取消订阅。

def on_quote(data):
    print(data)

subscription = ContextInfo.subscribe_whole_quote(
    ['000001.SZ', '600000.SH'],
    on_quote,
)

查看 ContextInfo.subscribe_whole_quote 完整说明

ContextInfo.unsubscribe_quote

根据订阅返回的标识取消行情订阅,避免策略停止使用数据后仍保留无效订阅。

调用语法

ContextInfo.unsubscribe_quote(subId)

subId 是订阅函数返回的整数订阅号。应先判断订阅号有效,再执行取消操作。

ContextInfo.unsubscribe_quote(subscription)

查看 ContextInfo.unsubscribe_quote 完整说明

证券与板块数据

ContextInfo.get_stock_list_in_sector

获取指定板块的成分证券列表,可用于建立股票池或批量请求行情。

调用语法与返回值

ContextInfo.get_stock_list_in_sector(sectorname, realtime)

sectorname 是客户端板块名称,支持官方板块与自定义板块。返回证券代码列表,例如 ['000001.SZ', '600000.SH']。当前官方原型列出 realtime 参数,但官方示例省略了该参数,可能存在客户端版本差异;使用时应以实际版本为准。官方说明要求在 after_inithandlebar 中调用。

stocks = ContextInfo.get_stock_list_in_sector('沪深300', True)
print(stocks[:10])

查看 ContextInfo.get_stock_list_in_sector 完整说明

选择函数

需求 推荐函数
获取历史 K 线或多证券行情 ContextInfo.get_market_data_ex
获取最新全推快照 ContextInfo.get_full_tick
持续接收全推行情 ContextInfo.subscribe_whole_quote
取消行情订阅 ContextInfo.unsubscribe_quote
下载本地历史数据 download_history_data
获取板块成分 ContextInfo.get_stock_list_in_sector

版本、权限和不同运行模式的限制,请以对应函数独立页面中的官方说明为准。

交易与账户

本章介绍 QMT 内置 Python 的交易接口和账户管理功能。

下单接口

order_volume

按数量下单:

# 买入 100 股
order_id = ContextInfo.order_volume(
    stockcode='000001.SZ',
    volume=100,
    priceType=11,     # 限价单
    price=10.5,        # 限价价格
    orderType=1,       # 1=买入, 2=卖出
    ContextInfo=ContextInfo,
)

order_value

按金额下单:

# 买入约 10000 元的股票
order_id = ContextInfo.order_value(
    stockcode='000001.SZ',
    value=10000,
    priceType=11,
    price=10.5,
    orderType=1,
    ContextInfo=ContextInfo,
)

order_target

按目标数量下单(自动计算差额):

# 调仓到 1000 股
order_id = ContextInfo.order_target(
    stockcode='000001.SZ',
    target_volume=1000,
    priceType=11,
    price=10.5,
    ContextInfo=ContextInfo,
)

order_target_value

按目标金额下单:

# 调仓到约 50000 元
order_id = ContextInfo.order_target_value(
    stockcode='000001.SZ',
    target_value=50000,
    priceType=11,
    price=10.5,
    ContextInfo=ContextInfo,
)

价格类型

priceType 说明 适用场景
0 最优五档即时成交剩撤销 快速成交
5 最优价 不限价格
11 限价单 精确控制价格
12 最新价 跟随最新价
14 市价 立即成交

限价单示例

# 以 10.5 元限价买入
ContextInfo.order_volume(
    stockcode='000001.SZ',
    volume=100,
    priceType=11,
    price=10.5,
    orderType=1,
    ContextInfo=ContextInfo,
)

市价单示例

# 以市价买入
ContextInfo.order_volume(
    stockcode='000001.SZ',
    volume=100,
    priceType=14,
    price=0,       # 市价时 price 不起作用
    orderType=1,
    ContextInfo=ContextInfo,
)

撤单

# 撤销指定订单
ContextInfo.cancel(order_id, ContextInfo)

# 撤销某品种的所有未成交订单
ContextInfo.cancel('000001.SZ', ContextInfo)

# 撤销所有未成交订单
ContextInfo.cancel('', ContextInfo)

账户查询

获取账户信息

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    # 获取账户信息
    account = ContextInfo.get_account()
    
    print(f'总资产: {account.m_dBalance}')
    print(f'可用资金: {account.m_dAvailable}')
    print(f'持仓市值: {account.m_dPositionValue}')
    print(f'冻结资金: {account.m_dFrozenCash}')

账户字段说明

字段 说明
m_dBalance 总资产
m_dAvailable 可用资金
m_dPositionValue 持仓市值
m_dFrozenCash 冻结资金
m_dProfit 当日盈亏

持仓查询

获取持仓信息

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    # 获取所有持仓
    positions = ContextInfo.get_positions()
    
    for stock, pos in positions.items():
        print(f'{stock}: 持仓{pos.m_nVolume}股, 可用{pos.m_nCanUseVolume}股')

持仓字段说明

字段 说明
m_nVolume 持仓数量
m_nCanUseVolume 可用数量
m_dOpenPrice 持仓成本价
m_dProfit 持仓盈亏
m_dMarketValue 持仓市值

查询指定品种持仓

# 查询指定品种的持仓
pos = ContextInfo.get_position('000001.SZ')
if pos and pos.m_nVolume > 0:
    print(f'持仓: {pos.m_nVolume}股')

交易状态管理

检查交易时间

def is_trading_time(ContextInfo):
    """判断当前是否在交易时间内"""
    from datetime import datetime
    now = datetime.now()
    hour = now.hour
    minute = now.minute
    
    # 上午 9:30-11:30
    if hour == 9 and minute >= 30:
        return True
    if hour == 10:
        return True
    if hour == 11 and minute <= 30:
        return True
    
    # 下午 13:00-15:00
    if hour == 13 or hour == 14:
        return True
    if hour == 15 and minute == 0:
        return True
    
    return False

交易限制检查

注意

下单前应检查以下条件:

  • 是否在交易时间内
  • 可用资金是否充足
  • 可用持仓是否充足(卖出时)
  • 是否达到涨跌停限制
def safe_buy(ContextInfo, stock, volume, price):
    """安全买入"""
    account = ContextInfo.get_account()
    cost = volume * price
    
    if account.m_dAvailable < cost:
        print(f'资金不足: 需要{cost}, 可用{account.m_dAvailable}')
        return None
    
    return ContextInfo.order_volume(
        stockcode=stock,
        volume=volume,
        priceType=11,
        price=price,
        orderType=1,
        ContextInfo=ContextInfo,
    )

委托查询

获取当日委托

# 获取当日所有委托
orders = ContextInfo.get_orders()
for order in orders:
    print(f'委托: {order.m_strStockCode} {order.m_nVolume}股 状态:{order.m_nOrderStatus}')

委托状态

状态码 说明
50 委托已提交
55 委托已确认
56 委托部分成交
57 委托全部成交
58 委托已撤
59 委托部分撤

委托回报与状态管理

本章介绍 QMT 内置 Python 的委托回报机制和订单状态管理。

委托回报回调

order_callback

当委托状态发生变化时触发:

def order_callback(ContextInfo, order_info):
    """委托状态变化回调"""
    print(f'委托回报: {order_info.m_strStockCode}')
    print(f'  方向: {"买入" if order_info.m_nOrderType == 1 else "卖出"}')
    print(f'  数量: {order_info.m_nVolume}')
    print(f'  价格: {order_info.m_dPrice}')
    print(f'  状态: {order_info.m_nOrderStatus}')
    print(f'  委托号: {order_info.m_strOrderSysID}')

deal_callback

当委托成交时触发:

def deal_callback(ContextInfo, deal_info):
    """成交通知回调"""
    print(f'成交回报: {deal_info.m_strStockCode}')
    print(f'  方向: {"买入" if deal_info.m_nOrderType == 1 else "卖出"}')
    print(f'  成交数量: {deal_info.m_nVolume}')
    print(f'  成交价格: {deal_info.m_dPrice}')
    print(f'  成交编号: {deal_info.m_strTradeID}')

订单状态详解

状态流转

委托提交 → 已确认 → 部分成交 → 全部成交
                  → 已撤销
                  → 部分成交 + 部分撤销

状态码对照表

状态码 常量名 说明
50 ORDER_SUBMITTED 委托已提交
55 ORDER_CONFIRMED 委托已确认
56 ORDER_PARTIALLY_FILLED 部分成交
57 ORDER_FILLED 全部成交
58 ORDER_CANCELLED 已撤销
59 ORDER_PARTIALLY_CANCELLED 部分撤销

状态判断

def order_callback(ContextInfo, order_info):
    status = order_info.m_nOrderStatus
    
    if status == 57:
        print(f'订单全部成交: {order_info.m_strStockCode}')
        # 更新持仓记录
        update_position(ContextInfo, order_info)
    elif status == 56:
        print(f'订单部分成交: {order_info.m_strStockCode}')
        # 记录部分成交
        record_partial_fill(ContextInfo, order_info)
    elif status == 58:
        print(f'订单已撤销: {order_info.m_strStockCode}')
        # 清理未成交记录
        cleanup_pending_order(ContextInfo, order_info)

订单信息对象

order_info 字段

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型(1=买, 2=卖)
m_nVolume int 委托数量
m_dPrice float 委托价格
m_nOrderStatus int 委托状态
m_strOrderSysID str 委托编号
m_nTradedVolume int 已成交数量
m_dTradedAmount float 已成交金额

deal_info 字段

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型
m_nVolume int 成交数量
m_dPrice float 成交价格
m_strTradeID str 成交编号
m_strOrderSysID str 关联委托编号

订单管理策略

订单跟踪

def init(ContextInfo):
    # 订单跟踪字典
    ContextInfo.pending_orders = {}  # order_id -> order_info
    ContextInfo.filled_orders = []   # 已完成订单列表

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    # 检查超时未成交订单
    check_pending_orders(ContextInfo)

def order_callback(ContextInfo, order_info):
    order_id = order_info.m_strOrderSysID
    
    if order_info.m_nOrderStatus in [57, 58, 59]:
        # 订单结束(全部成交/已撤/部分撤)
        if order_id in ContextInfo.pending_orders:
            del ContextInfo.pending_orders[order_id]
        ContextInfo.filled_orders.append(order_info)
    else:
        # 更新订单状态
        ContextInfo.pending_orders[order_id] = order_info

def check_pending_orders(ContextInfo):
    """检查超时未成交订单"""
    from datetime import datetime, timedelta
    
    now = datetime.now()
    for order_id, order in list(ContextInfo.pending_orders.items()):
        # 超时 5 分钟未成交则撤单
        if hasattr(order, 'submit_time'):
            elapsed = now - order.submit_time
            if elapsed > timedelta(minutes=5):
                ContextInfo.cancel(order_id, ContextInfo)
                print(f'超时撤单: {order_id}')

防止重复下单

def safe_order(ContextInfo, stock, volume, price, order_type=1):
    """安全下单,防止重复"""
    # 检查是否已有该品种的未成交订单
    for order_id, order in ContextInfo.pending_orders.items():
        if order.m_strStockCode == stock:
            print(f'{stock} 已有未成交订单,跳过')
            return None
    
    # 下单
    order_id = ContextInfo.order_volume(
        stockcode=stock,
        volume=volume,
        priceType=11,
        price=price,
        orderType=order_type,
        ContextInfo=ContextInfo,
    )
    
    if order_id:
        ContextInfo.pending_orders[order_id] = {
            'm_strStockCode': stock,
            'submit_time': datetime.now(),
        }
    
    return order_id

错误处理

常见委托错误

def order_callback(ContextInfo, order_info):
    status = order_info.m_nOrderStatus
    
    if status == 50 and order_info.m_strErrorInfo:
        # 委托被拒绝
        print(f'委托被拒绝: {order_info.m_strErrorInfo}')
        handle_rejection(ContextInfo, order_info)

def handle_rejection(ContextInfo, order_info):
    """处理委托被拒绝"""
    error = order_info.m_strErrorInfo
    
    if '资金不足' in error:
        print('错误:资金不足,请减少委托数量')
    elif '权限' in error:
        print('错误:交易权限不足')
    elif '涨跌停' in error:
        print('错误:触及涨跌停限制')
    else:
        print(f'未知错误: {error}')
技巧

在模拟环境中充分测试委托回报处理逻辑,确保各种状态都能正确处理后再用于实盘。

完整示例

获取行情示例

按品种划分

两融

#coding:gbk
def init(C):
	
	r = get_assure_contract('123456789')
	if len(r) == 0:
		print('未取到担保明细')
	else:
		finable = [o.m_strInstrumentID+'.'+o.m_strExchangeID for o in r if o.m_eFinStatus==48]
		print('可融资买入标的:', finable)

按功能划分

订阅K线全推

提示
  1. K线全推需要VIP权限在新窗口打开,非VIP用户请勿使用此功能

订阅全市场1m周期K线

#coding:gbk

import pandas as pd
import numpy as np

def init(C):
	stock_list = C.get_stock_list_in_sector("沪深A股")
	sub_num_dict = {i:C.subscribe_quote(
		stock_code = i, 
		period = '1m',  
		dividend_type = 'none',
		result_type = 'dict',  # 回调函数的行情数据格式
		callback = call_back  # 指定一个自定义的函数接收行情,自定义的函数只能有一个位置参数
		) for i in stock_list}

def call_back(data):
	print(data)

获取N分钟周期K线数据

提示
  1. 获取历史N分钟数据前,需要先下载历史数据
  2. 1m以上,5m以下的数据,是通过1m数据合成的
  3. 5m以上,1d以下的数据,是通过5m数据合成的
  4. 1d以上的数据,是通过1d的数据合成的
#coding:gbk

import pandas as pd
import numpy as np

def init(C):

	# start_date = '20231001'# 格式"YYYYMMDD",开始下载的日期,date = ""时全量下载
	start_date = '20231001'# 格式"YYYYMMDD",开始下载的日期,date = ""时增量下载
	end_date = "" # 格式同上,下载结束时间
	period = "3m" # 数据周期
	need_download = 1 # 取数据是空值时,将need_download赋值为1,确保正确下载了历史数据
	# code_list = ["110052.SH"] # 可转债
	# code_list = ["rb2401.SF", "FG403.ZF"] # 期货列表
	# code_list = ["HO2310-P-2500.IF"] # 期权列表
	code_list = ["000001.SZ", "600519.SH"] # 股票列表
	
	# 判断要不要下载数据
	if need_download:
		my_download(code_list, period, start_date, end_date)
	# 取数据
	data = C.get_market_data_ex([],code_list,period = period, start_time = start_date, end_time = end_date,dividend_type = "back_ratio")

	print(data)# 行情数据查看
	print(C.get_instrumentdetail(code_list[0])) # 合约信息查看
	
def hanldebar(C):
	return

def my_download(stock_list,period,start_date = '', end_date = ''):
	'''
	用于显示下载进度
	'''
	if "d" in period:
		period = "1d"
	elif "m" in period:
		if int(period[0]) < 5:
			period = "1m"
		else:
			period = "5m"
	elif "tick" == period:
		pass
	else:
		raise KeyboardInterrupt("周期传入错误")


	n = 1
	num = len(stock_list)
	for i in stock_list:
		print(f"当前正在下载{n}/{num}")
		
		download_history_data(i,period,start_date, end_date)
		n += 1
	print("下载任务结束")

获取2小时行情数据

提示
  1. 获取历史N分钟数据前,需要先下载历史数据
  2. 1m以上,5m以下的数据,是通过1m数据合成的
  3. 5m以上,1d以下的数据,是通过5m数据合成的
  4. 1d以上的数据,是通过1d的数据合成的
  5. 本示例是获取120分钟周期,需要先下载5分钟周期
#coding:gbk

def after_init(ContextInfo):
    stock = '000012.SZ'
    #下载历史5分钟行情(2小时周期是接口由基础周期5m合并)
    download_history_data(stock, '5m', '20260101', '')
    
    
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
	stock = '000012.SZ'
    # 获取120分钟线(2小时线)数据
    data = ContextInfo.get_market_data_ex(
        ['open', 'high', 'low', 'close', 'volume'], [stock], period='2h'
        , start_time='20260101', end_time='', count=-1
        , dividend_type='follow', fill_data=False
        , subscribe = True
    )
    print(data)

获取 Lv1 行情数据

本示例用于说明如何通过函数获取行情数据。

#coding:gbk
# get_market_data_ex(subscribe=True)有订阅股票数量限制
# 即stock_list参数的数量不能超过500

# get_market_data_ex(subscribe=False) 该模式下(非订阅模式),接口会从本地行情文件里获取数据,不会获取动态行情数,且不受订阅数限制,但需要提前下载数据
# 下载数据在 操作/数据管理/补充数据选项卡里,按照页面提示下载数据

# get_market_data_ex(subscribe=True) 该模式下(订阅模式),受订阅数量上限限制,可以取到动态行情

# 建议每天盘后增量补充对应周期的行情

import time


def init(C):
	C.stock = C.stockcode + '.' + C.market
	# 获取指定时间的k线
	price = C.get_market_data_ex(['open','high','low','close'], [C.stock], start_time='', end_time='',period='1d', subscribe=False)
	print(price[C.stock].head())


def handlebar(C):

	bar_timetag = C.get_bar_timetag(C.barpos)
	bar_date = timetag_to_datetime(bar_timetag, '%Y%m%d%H%M%S')
	print('获取截至到%s为止前5根k线的开高低收等字段:'%(bar_date))
	# 获取截至今天为止前30根k线
	price = C.get_market_data_ex(
					[], [C.stock], 
					end_time=bar_date,
					period=C.period, 
					subscribe=True, 
					count=5,
					)
	print(price[C.stock].to_dict('dict'))

获取 Lv2 数据(需要数据源支持)

使用该函数后,会定期查询最新数据,并进行数据返回。

#coding:gbk
def init(C):
	C.sub_nums  = []

	C.stock = C.stockcode+'.'+C.market
	for field in ['l2transaction', 'l2order', 'l2transactioncount', 'l2quote']:
		num = C.subscribe_quote(C.stock, period=field,
							dividend_type='follow',
							)
		
		C.sub_nums.append(num)

def handlebar(C):
	if not C.is_last_bar():
		return
	price = C.get_market_data_ex([],[C.stock],period='l2transaction',count=10)[C.stock]
	price_dict = price.to_dict('index')
	print(price_dict)
	for pos, t in enumerate(price_dict):
		print(f" 逐笔成交:{pos+1} 时间:{price_dict[t]['stime']}, 时间戳:{price_dict[t]['time']}, 成交价:{price_dict[t]['price']}, \
成交量:{price_dict[t]['volume']}, 成交额:{price_dict[t]['amount']} \
成交记录号:{price_dict[t]['tradeIndex']}, 买方委托号:{price_dict[t]['buyNo']},\
卖方委托号:{price_dict[t]['sellNo']}, 成交类型:{price_dict[t]['tradeType']}, \
成交标志:{price_dict[t]['tradeFlag']}, ")

	price = C.get_market_data_ex([],[C.stock],period='l2quote',count=10)[C.stock]
	price_dict = price.to_dict('index')
	print(price_dict)
	for pos, t in enumerate(price_dict):
		print(f" 十档快照:{pos+1} 时间:{price_dict[t]['stime']}, 时间戳:{price_dict[t]['time']}, 最新价:{price_dict[t]['lastPrice']}, \
开盘价:{price_dict[t]['open']}, 最高价:{price_dict[t]['high']} 最低价:{price_dict[t]['low']}, 成交额:{price_dict[t]['amount']},\
成交总量:{price_dict[t]['volume']}, 原始成交总量:{price_dict[t]['pvolume']}, 证券状态:{price_dict[t]['stockStatus']}, 持仓量:{price_dict[t]['openInt']},\
成交笔数:{price_dict[t]['transactionNum']},前收盘价:{price_dict[t]['lastClose']},多档委卖价:{price_dict[t]['askPrice']},多档委卖量:{price_dict[t]['askVol']},\
多档委买价:{price_dict[t]['bidPrice']},多档委买量:{price_dict[t]['bidVol']}")


	price = C.get_market_data_ex([],[C.stock],period='l2order',count=10)[C.stock]
	price_dict = price.to_dict('index')
	for pos, t in enumerate(price_dict):
		print(f" 逐笔委托:{pos+1} 时间:{price_dict[t]['stime']}, 时间戳:{price_dict[t]['time']}, 委托价:{price_dict[t]['price']}, \
委托量:{price_dict[t]['volume']}, 委托号:{price_dict[t]['entrustNo']} \
委托类型:{price_dict[t]['entrustType']}, 委托方向:{price_dict[t]['entrustDirection']},\
")
# 委托类型: 0:未知 1: 买入,2: 卖出,3: 撤单


	price = C.get_market_data_ex([],[C.stock],period='l2transactioncount',count=10)[C.stock]
	price_dict = price.to_dict('index')
	for pos, t in enumerate(price_dict):
		print('大单统计:', price_dict[t])

def stop(C):
	for num in C.sub_nums:
		C.unsubscribe_quote(num)
{'20240220150000.000': {'amount': 2946.0, 'buyNo': 33949158, 'price': 9.82, 'sellNo': 33860170, 'seq': 33952658, 'stime': '20240220150000.000', 'time': 1708412400000, 'tradeFlag': 1, 'tradeIndex': 33952658, 'tradeType': 0, 'volume': 300}}
 逐笔成交:1 时间:20240220150000.000, 时间戳:1708412400000, 成交价:9.82, 成交量:300, 成交额:2946.0 成交记录号:33952658, 买方委托号:33949158,卖方委托号:33860170, 成交类型:0, 成交标志:1, 
{'20240220145839.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [12462, 666, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [12462, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145839.000', 'stockStatus': 8, 'time': 1708412319000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145848.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [12587, 586, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [12587, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145848.000', 'stockStatus': 8, 'time': 1708412328000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145857.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [13735, 2880, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [13735, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145857.000', 'stockStatus': 8, 'time': 1708412337000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145906.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [14206, 2650, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [14206, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145906.000', 'stockStatus': 8, 'time': 1708412346000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145915.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [14410, 2671, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [14410, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145915.000', 'stockStatus': 8, 'time': 1708412355000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145924.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [15925, 1564, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [15925, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145924.000', 'stockStatus': 8, 'time': 1708412364000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145933.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [16241, 1873, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [16241, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145933.000', 'stockStatus': 8, 'time': 1708412373000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145942.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [17643, 529, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [17643, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145942.000', 'stockStatus': 8, 'time': 1708412382000, 'transactionNum': 52246, 'volume': 1105052}, '20240220145951.000': {'amount': 1080809029.2600002, 'askPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'askVol': [18262, 620, 0, 0, 0, 0, 0, 0, 0, 0], 'bidPrice': [9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 'bidVol': [18262, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 18, 'pvolume': 110505198, 'settlementPrice': 0.0, 'stime': '20240220145951.000', 'stockStatus': 8, 'time': 1708412391000, 'transactionNum': 52246, 'volume': 1105052}, '20240220150000.000': {'amount': 1098987813.26, 'askPrice': [9.82, 9.83, 9.84, 9.85, 9.86, 9.87, 9.879999999999999, 9.889999999999999, 9.899999999999999, 9.909999999999998], 'askVol': [5810, 13718, 16260, 14328, 5391, 7251, 11538, 5153, 5390, 1508], 'bidPrice': [9.81, 9.8, 9.790000000000001, 9.780000000000001, 9.770000000000001, 9.760000000000002, 9.750000000000002, 9.740000000000002, 9.730000000000002, 9.720000000000002], 'bidVol': [2123, 6962, 8252, 3011, 3118, 2448, 5289, 3242, 9223, 6510], 'high': 9.84, 'lastClose': 9.81, 'lastPrice': 9.82, 'lastSettlementPrice': 0.0, 'low': 9.73, 'open': 9.790000000000001, 'openInt': 15, 'pvolume': 112356398, 'settlementPrice': 0.0, 'stime': '20240220150000.000', 'stockStatus': 5, 'time': 1708412400000, 'transactionNum': 52729, 'volume': 1123564}}
 十档快照:1 时间:20240220145839.000, 时间戳:1708412319000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[12462, 666, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[12462, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:2 时间:20240220145848.000, 时间戳:1708412328000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[12587, 586, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[12587, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:3 时间:20240220145857.000, 时间戳:1708412337000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[13735, 2880, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[13735, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:4 时间:20240220145906.000, 时间戳:1708412346000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[14206, 2650, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[14206, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:5 时间:20240220145915.000, 时间戳:1708412355000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[14410, 2671, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[14410, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:6 时间:20240220145924.000, 时间戳:1708412364000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[15925, 1564, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[15925, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:7 时间:20240220145933.000, 时间戳:1708412373000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[16241, 1873, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[16241, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:8 时间:20240220145942.000, 时间戳:1708412382000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[17643, 529, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[17643, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:9 时间:20240220145951.000, 时间戳:1708412391000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1080809029.2600002,成交总量:1105052, 原始成交总量:110505198, 证券状态:8, 持仓量:18,成交笔数:52246,前收盘价:9.81,多档委卖价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委卖量:[18262, 620, 0, 0, 0, 0, 0, 0, 0, 0],多档委买价:[9.82, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],多档委买量:[18262, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 十档快照:10 时间:20240220150000.000, 时间戳:1708412400000, 最新价:9.82, 开盘价:9.790000000000001, 最高价:9.84 最低价:9.73, 成交额:1098987813.26,成交总量:1123564, 原始成交总量:112356398, 证券状态:5, 持仓量:15,成交笔数:52729,前收盘价:9.81,多档委卖价:[9.82, 9.83, 9.84, 9.85, 9.86, 9.87, 9.879999999999999, 9.889999999999999, 9.899999999999999, 9.909999999999998],多档委卖量:[5810, 13718, 16260, 14328, 5391, 7251, 11538, 5153, 5390, 1508],多档委买价:[9.81, 9.8, 9.790000000000001, 9.780000000000001, 9.770000000000001, 9.760000000000002, 9.750000000000002, 9.740000000000002, 9.730000000000002, 9.720000000000002],多档委买量:[2123, 6962, 8252, 3011, 3118, 2448, 5289, 3242, 9223, 6510]
 逐笔委托:1 时间:20240220145956.680, 时间戳:1708412396680, 委托价:9.83, 委托量:1500, 委托号:33949047 委托类型:1, 委托方向:1,
 逐笔委托:2 时间:20240220145956.730, 时间戳:1708412396730, 委托价:9.82, 委托量:500, 委托号:33949086 委托类型:1, 委托方向:1,
 逐笔委托:3 时间:20240220145956.770, 时间戳:1708412396770, 委托价:9.8, 委托量:300000, 委托号:33949126 委托类型:1, 委托方向:2,
 逐笔委托:4 时间:20240220145956.810, 时间戳:1708412396810, 委托价:9.82, 委托量:300, 委托号:33949158 委托类型:1, 委托方向:1,
 逐笔委托:5 时间:20240220145957.180, 时间戳:1708412397180, 委托价:9.8, 委托量:18600, 委托号:33949592 委托类型:1, 委托方向:2,
 逐笔委托:6 时间:20240220145957.580, 时间戳:1708412397580, 委托价:9.82, 委托量:100, 委托号:33949982 委托类型:1, 委托方向:2,
 逐笔委托:7 时间:20240220145958.300, 时间戳:1708412398300, 委托价:9.8, 委托量:84700, 委托号:33950549 委托类型:1, 委托方向:2,
 逐笔委托:8 时间:20240220145958.320, 时间戳:1708412398320, 委托价:9.83, 委托量:1200, 委托号:33950573 委托类型:1, 委托方向:1,
 逐笔委托:9 时间:20240220145958.450, 时间戳:1708412398450, 委托价:9.81, 委托量:83800, 委托号:33950686 委托类型:1, 委托方向:2,
 逐笔委托:10 时间:20240220145959.100, 时间戳:1708412399100, 委托价:9.83, 委托量:1300, 委托号:33951170 委托类型:1, 委托方向:2,
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124399721.0, 'bidMediumVolmue': 127143, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12867, 'bidSmallAmount': 81248200.0, 'bidSmallVolmue': 83072, 'ddx': 0.0, 'ddy': 4.03, 'ddz': -0.02, 'netOrder': -374, 'netWithdraw': 16, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120132514.0, 'offMediumVolmue': 122938, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13948, 'offSmallAmount': 97078349.0, 'offSmallVolmue': 99424, 'stime': '20240220145636.000', 'time': 1708412196000, 'unactiveBidBigAmount': 181050089.0, 'unactiveBidBigVolmue': 185301, 'unactiveBidMediumAmount': 166479412.0, 'unactiveBidMediumVolmue': 170418, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 89966179.0, 'unactiveBidSmallVolmue': 92168, 'unactiveOffBigAmount': 177098765.0, 'unactiveOffBigVolmue': 180907, 'unactiveOffMediumAmount': 170938705.0, 'unactiveOffMediumVolmue': 174590, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13979, 'withdrawOff': 9278, 'zjbyBig': 7872534, 'zjbyMedium': 4267206, 'zjbyMost': -1888909, 'zjbyNetInflow': -5579317, 'zjbySmall': -15830148}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124399721.0, 'bidMediumVolmue': 127143, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12867, 'bidSmallAmount': 81248200.0, 'bidSmallVolmue': 83072, 'ddx': 0.0, 'ddy': 4.03, 'ddz': -0.02, 'netOrder': -374, 'netWithdraw': 12, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120132514.0, 'offMediumVolmue': 122938, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13950, 'offSmallAmount': 97112684.0, 'offSmallVolmue': 99459, 'stime': '20240220145638.000', 'time': 1708412198000, 'unactiveBidBigAmount': 181084424.0, 'unactiveBidBigVolmue': 185336, 'unactiveBidMediumAmount': 166479412.0, 'unactiveBidMediumVolmue': 170418, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 89966179.0, 'unactiveBidSmallVolmue': 92168, 'unactiveOffBigAmount': 177098765.0, 'unactiveOffBigVolmue': 180907, 'unactiveOffMediumAmount': 170938705.0, 'unactiveOffMediumVolmue': 174590, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13981, 'withdrawOff': 9280, 'zjbyBig': 7872534, 'zjbyMedium': 4267206, 'zjbyMost': -1888909, 'zjbyNetInflow': -5613652, 'zjbySmall': -15864483}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12872, 'bidSmallAmount': 81264894.0, 'bidSmallVolmue': 83089, 'ddx': 0.0, 'ddy': 4.06, 'ddz': -0.02, 'netOrder': -5, 'netWithdraw': 13, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120318904.0, 'offMediumVolmue': 123128, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13962, 'offSmallAmount': 97206860.0, 'offSmallVolmue': 99555, 'stime': '20240220145642.000', 'time': 1708412202000, 'unactiveBidBigAmount': 181363028.0, 'unactiveBidBigVolmue': 185620, 'unactiveBidMediumAmount': 166479412.0, 'unactiveBidMediumVolmue': 170418, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 89968141.0, 'unactiveBidSmallVolmue': 92170, 'unactiveOffBigAmount': 177369797.0, 'unactiveOffBigVolmue': 181183, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13987, 'withdrawOff': 9283, 'zjbyBig': 7872534, 'zjbyMedium': 4180980, 'zjbyMost': -1888909, 'zjbyNetInflow': -5777360, 'zjbySmall': -15941965}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12872, 'bidSmallAmount': 81264894.0, 'bidSmallVolmue': 83089, 'ddx': 0.0, 'ddy': 4.06, 'ddz': -0.02, 'netOrder': -5, 'netWithdraw': 11, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120503332.0, 'offMediumVolmue': 123316, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13963, 'offSmallAmount': 97206860.0, 'offSmallVolmue': 99555, 'stime': '20240220145643.000', 'time': 1708412203000, 'unactiveBidBigAmount': 181363028.0, 'unactiveBidBigVolmue': 185620, 'unactiveBidMediumAmount': 166562797.0, 'unactiveBidMediumVolmue': 170503, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90069184.0, 'unactiveBidSmallVolmue': 92273, 'unactiveOffBigAmount': 177369797.0, 'unactiveOffBigVolmue': 181183, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13989, 'withdrawOff': 9283, 'zjbyBig': 7872534, 'zjbyMedium': 3996552, 'zjbyMost': -1888909, 'zjbyNetInflow': -5961788, 'zjbySmall': -15941965}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12873, 'bidSmallAmount': 81274714.0, 'bidSmallVolmue': 83099, 'ddx': 0.0, 'ddy': 4.07, 'ddz': -0.02, 'netOrder': 248, 'netWithdraw': 12, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120503332.0, 'offMediumVolmue': 123316, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13967, 'offSmallAmount': 97279454.0, 'offSmallVolmue': 99629, 'stime': '20240220145648.000', 'time': 1708412208000, 'unactiveBidBigAmount': 181363028.0, 'unactiveBidBigVolmue': 185620, 'unactiveBidMediumAmount': 166635391.0, 'unactiveBidMediumVolmue': 170577, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90069184.0, 'unactiveBidSmallVolmue': 92273, 'unactiveOffBigAmount': 177379617.0, 'unactiveOffBigVolmue': 181193, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13992, 'withdrawOff': 9290, 'zjbyBig': 7872534, 'zjbyMedium': 3996552, 'zjbyMost': -1888909, 'zjbyNetInflow': -6024562, 'zjbySmall': -16004739}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12875, 'bidSmallAmount': 81313012.0, 'bidSmallVolmue': 83138, 'ddx': 0.0, 'ddy': 4.07, 'ddz': -0.02, 'netOrder': 248, 'netWithdraw': 17, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120556306.0, 'offMediumVolmue': 123370, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13968, 'offSmallAmount': 97279454.0, 'offSmallVolmue': 99629, 'stime': '20240220145650.000', 'time': 1708412210000, 'unactiveBidBigAmount': 181565114.0, 'unactiveBidBigVolmue': 185826, 'unactiveBidMediumAmount': 166479412.0, 'unactiveBidMediumVolmue': 170418, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90076051.0, 'unactiveBidSmallVolmue': 92280, 'unactiveOffBigAmount': 177417915.0, 'unactiveOffBigVolmue': 181232, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13997, 'withdrawOff': 9292, 'zjbyBig': 7872534, 'zjbyMedium': 3943578, 'zjbyMost': -1888909, 'zjbyNetInflow': -6039238, 'zjbySmall': -15966441}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12877, 'bidSmallAmount': 81323814.0, 'bidSmallVolmue': 83149, 'ddx': 0.0, 'ddy': 4.07, 'ddz': -0.02, 'netOrder': -6373, 'netWithdraw': 16, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120611242.0, 'offMediumVolmue': 123426, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13971, 'offSmallAmount': 97326542.0, 'offSmallVolmue': 99677, 'stime': '20240220145654.000', 'time': 1708412214000, 'unactiveBidBigAmount': 181565114.0, 'unactiveBidBigVolmue': 185826, 'unactiveBidMediumAmount': 166528462.0, 'unactiveBidMediumVolmue': 170468, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90129025.0, 'unactiveBidSmallVolmue': 92334, 'unactiveOffBigAmount': 177428717.0, 'unactiveOffBigVolmue': 181243, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 13999, 'withdrawOff': 9299, 'zjbyBig': 7872534, 'zjbyMedium': 3888642, 'zjbyMost': -1888909, 'zjbyNetInflow': -6130460, 'zjbySmall': -16002727}
大单统计: {'bidBigAmount': 152925991.0, 'bidBigVolmue': 156226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12877, 'bidSmallAmount': 81323814.0, 'bidSmallVolmue': 83149, 'ddx': 0.0, 'ddy': 4.09, 'ddz': -0.02, 'netOrder': -6373, 'netWithdraw': 15, 'offBigAmount': 145053456.0, 'offBigVolmue': 148447, 'offMediumAmount': 120611242.0, 'offMediumVolmue': 123426, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13976, 'offSmallAmount': 97372649.0, 'offSmallVolmue': 99724, 'stime': '20240220145656.000', 'time': 1708412216000, 'unactiveBidBigAmount': 181565114.0, 'unactiveBidBigVolmue': 185826, 'unactiveBidMediumAmount': 166577512.0, 'unactiveBidMediumVolmue': 170518, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90126082.0, 'unactiveBidSmallVolmue': 92331, 'unactiveOffBigAmount': 177428717.0, 'unactiveOffBigVolmue': 181243, 'unactiveOffMediumAmount': 170784531.0, 'unactiveOffMediumVolmue': 174433, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 109991285.0, 'unactiveOffSmallVolmue': 112357, 'withdrawBid': 14002, 'withdrawOff': 9302, 'zjbyBig': 7872534, 'zjbyMedium': 3888642, 'zjbyMost': -1888909, 'zjbyNetInflow': -6176567, 'zjbySmall': -16048834}
大单统计: {'bidBigAmount': 153907941.0, 'bidBigVolmue': 157226, 'bidMediumAmount': 124499885.0, 'bidMediumVolmue': 127245, 'bidMostAmount': 177571807.0, 'bidMostVolmue': 181294, 'bidNumber': 12881, 'bidSmallAmount': 81386627.0, 'bidSmallVolmue': 83213, 'ddx': 0.0, 'ddy': 4.09, 'ddz': -0.02, 'netOrder': -324, 'netWithdraw': 9, 'offBigAmount': 145951071.0, 'offBigVolmue': 149362, 'offMediumAmount': 120611242.0, 'offMediumVolmue': 123426, 'offMostAmount': 179460717.0, 'offMostVolmue': 183675, 'offNumber': 13980, 'offSmallAmount': 97419737.0, 'offSmallVolmue': 99772, 'stime': '20240220145659.000', 'time': 1708412219000, 'unactiveBidBigAmount': 181946723.0, 'unactiveBidBigVolmue': 186215, 'unactiveBidMediumAmount': 167049373.0, 'unactiveBidMediumVolmue': 170999, 'unactiveBidMostAmount': 104229355.0, 'unactiveBidMostVolmue': 106597, 'unactiveBidSmallAmount': 90217315.0, 'unactiveBidSmallVolmue': 92424, 'unactiveOffBigAmount': 178280111.0, 'unactiveOffBigVolmue': 182110, 'unactiveOffMediumAmount': 170956296.0, 'unactiveOffMediumVolmue': 174608, 'unactiveOffMostAmount': 78116964.0, 'unactiveOffMostVolmue': 79881, 'unactiveOffSmallAmount': 110012889.0, 'unactiveOffSmallVolmue': 112379, 'withdrawBid': 14003, 'withdrawOff': 9304, 'zjbyBig': 7956869, 'zjbyMedium': 3888642, 'zjbyMost': -1888909, 'zjbyNetInflow': -6076507, 'zjbySmall': -16033109}
大单统计: {'bidBigAmount': 156870635.0, 'bidBigVolmue': 160243, 'bidMediumAmount': 126389253.0, 'bidMediumVolmue': 129169, 'bidMostAmount': 180761343.0, 'bidMostVolmue': 184542, 'bidNumber': 12970, 'bidSmallAmount': 81947349.0, 'bidSmallVolmue': 83784, 'ddx': 0.0, 'ddy': 4.21, 'ddz': -0.02, 'netOrder': 7661, 'netWithdraw': 9, 'offBigAmount': 148570065.0, 'offBigVolmue': 152029, 'offMediumAmount': 123102576.0, 'offMediumVolmue': 125963, 'offMostAmount': 182394933.0, 'offMostVolmue': 186663, 'offNumber': 14111, 'offSmallAmount': 98951657.0, 'offSmallVolmue': 101332, 'stime': '20240220150000.000', 'time': 1708412400000, 'unactiveBidBigAmount': 184733639.0, 'unactiveBidBigVolmue': 189053, 'unactiveBidMediumAmount': 168611735.0, 'unactiveBidMediumVolmue': 172590, 'unactiveBidMostAmount': 108729861.0, 'unactiveBidMostVolmue': 111180, 'unactiveBidSmallAmount': 90943995.0, 'unactiveBidSmallVolmue': 93164, 'unactiveOffBigAmount': 180480773.0, 'unactiveOffBigVolmue': 184351, 'unactiveOffMediumAmount': 174386422.0, 'unactiveOffMediumVolmue': 178101, 'unactiveOffMostAmount': 79344464.0, 'unactiveOffMostVolmue': 81131, 'unactiveOffSmallAmount': 111756921.0, 'unactiveOffSmallVolmue': 114155, 'withdrawBid': 14003, 'withdrawOff': 9304, 'zjbyBig': 8300569, 'zjbyMedium': 3286676, 'zjbyMost': -1633589, 'zjbyNetInflow': -7050651, 'zjbySmall': -17004307}

此方法在发起订阅后,会自动收到所订阅数据,订阅方需要记录订阅函数返回的订阅号,并在不需要订阅时调用unsubscribe_quote反订阅数据,释放资源。

#coding:gbk

def l2_quote_callback(data):
	for s in data:
		print('lv2快照:',s, data[s])

def l2transaction_callback(data):
	for s in data:
		print('逐笔成交',s, data[s])


def l2order_callback(data):
	for s in data:
		print('逐笔委托',s, data[s])

def l2quoteaux_callback(data):
	for s in data:
		print('行情快照补充',s, data[s])


def l2transactioncount_callback(data):
	for s in data:
		print('大单统计',s, data[s])


def l2orderqueue_callback(data):
	for s in data:
		print('委买委卖队列',s, data[s])


def init(C):
	C.stock = C.stockcode + '.' + C.market

	# Level2 逐笔快照
	C.subscribe_quote(C.stock, 'l2quote', result_type='dict', callback=l2_quote_callback)
	# Level2 行情快照补充
	C.subscribe_quote(C.stock, 'l2quoteaux', result_type='dict', callback=l2quoteaux_callback)
	# Level2 逐笔成交
	C.subscribe_quote(C.stock, 'l2transaction', result_type='dict', callback=l2transaction_callback)
	# Level2 逐笔委托
	C.subscribe_quote(C.stock, 'l2order', result_type='dict', callback=l2order_callback)
	# Level2大单统计
	C.subscribe_quote(C.stock, 'l2transactioncount', result_type='dict', callback=l2transactioncount_callback)
	# Level2委买委卖队列
	C.subscribe_quote(C.stock, 'l2orderqueue', result_type='dict', callback=l2orderqueue_callback)

def handlebar(C):
	return
行情快照补充 000001.SZ {'time': 1708412400000, 'stime': '20240220150000.000', 'avgBidPrice': 9.59, 'totalBidQuantity': 109458, 'avgOffPrice': 10.22, 'totalOffQuantity': 246790, 'withdrawBidQuantity': 0, 'withdrawBidAmount': 0.0, 'withdrawOffQuantity': 0, 'withdrawOffAmount': 0.0}
lv2快照: 000001.SZ {'time': 1708412400000, 'stime': '20240220150000.000', 'lastPrice': 9.82, 'amount': 1098987813.26, 'volume': 1123564, 'pvolume': 112356398, 'openInt': 15, 'stockStatus': 5, 'lastSettlementPrice': 0.0, 'open': 9.790000000000001, 'high': 9.84, 'low': 9.73, 'settlementPrice': 0.0, 'lastClose': 9.81, 'transactionNum': 52729, 'askPrice': [9.82, 9.83, 9.84, 9.85, 9.86, 9.87, 9.879999999999999, 9.889999999999999, 9.899999999999999, 9.909999999999998], 'bidPrice': [9.81, 9.8, 9.790000000000001, 9.780000000000001, 9.770000000000001, 9.760000000000002, 9.750000000000002, 9.740000000000002, 9.730000000000002, 9.720000000000002], 'askVol': [5810, 13718, 16260, 14328, 5391, 7251, 11538, 5153, 5390, 1508], 'bidVol': [2123, 6962, 8252, 3011, 3118, 2448, 5289, 3242, 9223, 6510]}
委买委卖队列 000001.SZ {'time': 1708412400000, 'stime': '20240220150000.000', 'bidLevelPrice': 9.81, 'bidLevelVolume': [604, 5, 115, 10, 9, 5, 10, 1, 2, 12, 8, 5, 4, 50, 40, 100, 10, 5, 100, 52, 26, 29, 20, 2, 20, 5, 10, 10, 10, 115, 5, 239, 388, 6, 68, 23], 'offerLevelPrice': 9.82, 'offerLevelVolume': [58, 5, 10, 10, 5, 10, 30, 10, 8, 4, 65, 2, 10, 1, 1, 15, 20, 5, 20, 19, 39, 29, 20, 7, 20, 126, 4, 2, 30, 20, 30, 2, 50, 3, 1, 10, 90, 10, 1, 4, 10, 10, 20, 5, 5, 2, 104, 2, 4, 65]}
大单统计 000001.SZ {'time': 1708412400000, 'stime': '20240220150000.000', 'bidNumber': 12970, 'bidMostVolmue': 184542, 'bidBigVolmue': 160243, 'bidMediumVolmue': 129169, 'bidSmallVolmue': 83784, 'offNumber': 14111, 'offMostVolmue': 186663, 'offBigVolmue': 152029, 'offMediumVolmue': 125963, 'offSmallVolmue': 101332, 'bidMostAmount': 180761343.0, 'bidBigAmount': 156870635.0, 'bidMediumAmount': 126389253.0, 'bidSmallAmount': 81947349.0, 'offMostAmount': 182394933.0, 'offBigAmount': 148570065.0, 'offMediumAmount': 123102576.0, 'offSmallAmount': 98951657.0, 'ddx': 0.0, 'ddy': 4.21, 'ddz': -0.02, 'zjbyNetInflow': -7050651, 'zjbyMost': -1633589, 'zjbyBig': 8300569, 'zjbyMedium': 3286676, 'zjbySmall': -17004307, 'netOrder': 7661, 'netWithdraw': 9, 'withdrawBid': 14003, 'withdrawOff': 9304, 'unactiveBidMostVolmue': 111180, 'unactiveBidBigVolmue': 189053, 'unactiveBidMediumVolmue': 172590, 'unactiveBidSmallVolmue': 93164, 'unactiveOffMostVolmue': 81131, 'unactiveOffBigVolmue': 184351, 'unactiveOffMediumVolmue': 178101, 'unactiveOffSmallVolmue': 114155, 'unactiveBidMostAmount': 108729861.0, 'unactiveBidBigAmount': 184733639.0, 'unactiveBidMediumAmount': 168611735.0, 'unactiveBidSmallAmount': 90943995.0, 'unactiveOffMostAmount': 79344464.0, 'unactiveOffBigAmount': 180480773.0, 'unactiveOffMediumAmount': 174386422.0, 'unactiveOffSmallAmount': 111756921.0}

使用 Lv1 全推数据计算全市场涨幅

#coding:gbk

import time

class a():pass

A = a()

def init(C):
	A.hsa = C.get_stock_list_in_sector('沪深A股') + C.get_stock_list_in_sector('京市A股')
	print('股票池大小', len(A.hsa))
	A.vol_dict = {}
	for stock in A.hsa:
			A.vol_dict[stock] = C.get_last_volume(stock)
	C.run_time("f","3nSecond","2019-10-14 13:20:00")


def to_zw(a):
	'''0.中文价格字符串'''
	import numpy as np
	if np.isnan(a):
			return '问题数据'
	if abs(a) < 1000:
			print(a, str(round(int(a) / 1000.0, 2)) + "千")
			return str(round(int(a) / 1000.0, 2)) + "千"
	if abs(a) < 10000:
			return str(int(a))[0] + "千"
	if abs(a) < 100000000:
			return str(int(a))[:-4] + "万" + str(int(a))[-4]
	return f"{int(a / 100000000)}亿"



def f(C):
	t0 = time.time()
	full_tick = C.get_full_tick(A.hsa)
	total_market_value = 0
	total_ratio = 0
	count = 0
	total_amount = 0
	ratio_list = []
	for stock in A.hsa:
			ratio = full_tick[stock]['lastPrice'] / full_tick[stock]['lastClose'] - 1
			amount = full_tick[stock]['amount']
			total_amount += amount
			rise_price = round(full_tick[stock]['lastClose'] *1.2,2) if stock[0] == '3' or stock[:3] == '688' else round(full_tick[stock]['lastClose'] *1.1,2)
			#如果要打印涨停品种
			#if abs(full_tick[stock]['lastPrice'] - rise_price) <0.01:
			#        print(f"涨停品种 {stock} {C.get_stock_name(stock)}")
			market_value = full_tick[stock]['lastPrice'] * A.vol_dict[stock]
			total_ratio += ratio * market_value
			total_market_value += market_value
			count += 1
			ratio_list.append(ratio)
	#print(count)
	total_ratio /= total_market_value
	total_ratio *= 100
	middle  = int(len(ratio_list) / 2)
	middle_ratio = ratio_list[middle]
	rise_num = len([i for i in ratio_list if i > 0])
	down_num = len([i for i in ratio_list if i < 0])
	print(f'A股加权涨幅 {round(total_ratio,2)}% 涨幅中位数 {round(middle_ratio,2)}% {rise_num}个上涨 {down_num}个下跌 成交金额 {to_zw(total_amount)} 耗时{round(time.time()- t0,5)}秒')

在行情回调函数里处理动态行情

ContextInfo.subscribe_quote - 订阅行情函数说明 行情回调函数字段说明

#coding:gbk

sub_nums = []


def init(C):
	global sub_nums

	# def on_quote(data1, data2): # 错误写法
	def on_quote(data):
		for s in data:
			q = data[s]
			print(type(q), q)
			
	stocks = [C.stockcode + '.' + C.market]  # 获取到当前主图股票代码
	for s in stocks:
		num = C.subscribe_quote(s, period='1d',  
						  dividend_type='none',
						  result_type='dict',  # 回调函数的行情数据格式
						  callback=on_quote  # 指定一个自定义的函数接收行情,自定义的函数只能有一个位置参数
						)
		sub_nums.append(num)


def stop(C):
	# 反订阅
	for num in sub_nums:
		C.unsubscribe_quote(num)

python写入扩展数据

# coding:gbk
'''
python写扩展数据,投研接口
'''

def init(C):
    # 创建扩展数据
    extencd_name  = 'test' # 创建名为test的扩展数据
    create_extend_data# (父节点, 扩展数据名称, 是否覆盖)
    C.extencd_name = create_extend_data('扩展数据', extencd_name, True)
    

def handlebar(C):
    if C.is_last_bar():
        data = {'SH600177': 0.43, 'SZ000767': 0.18, 'SH600362': 0.27, 'SH600171': 0.25, 'SH600170': 0.18, 'SH600073': 0.13, 'SZ000768': 0.17, 'SH600282': 0.19, 'SH600601': 0.42, 'SH600569': 0.26, 'SZ000401': 0.21, 'SH600602': 0.17, 'SZ000806': 0.13, 'SZ000807': 0.15, 'SH600608': 0.08, 'SH600874': 0.09, 'SZ000825': 0.44, 'SZ000652': 0.19, 'SH600078': 0.11, 'SH600871': 0.1, 'SZ000573': 0.1, 'SZ000520': 0.14, 'SH600879': 0.43, 'SZ000960': 0.2, 'SH600597': 0.21, 'SZ000550': 0.1, 'SH600591': 0.14, 'SZ000059': 0.13, 'SH600215': 0.12, 'SZ000968': 0.11, 'SZ000969': 0.14, 'SZ000568': 0.22, 'SH600598': 0.22, 'SH600028': 1.85, 'SH600270': 0.27, 'SH600060': 0.22, 'SH600062': 0.15, 'SH600779': 0.14, 'SH600997': 0.2, 'SZ000707': 0.12, 'SH600068': 0.16, 'SH600770': 0.14, 'SZ000680': 0.14, 'SH600674': 0.1, 'SH600675': 0.25, 'SZ000488': 0.28, 'SZ000012': 0.11, 'SH600863': 0.17, 'SZ000429': 0.17, 'SH600027': 0.32, 'SH600866': 0.13, 'SH600001': 0.43, 'SZ000636': 0.11, 'SH600900': 2.73, 'SH600600': 0.31, 'SH600895': 0.26, 'SH600029': 0.43, 'SH600020': 0.24, 'SH600205': 0.39, 'SH600688': 0.76, 'SH600207': 0.1, 'SZ000970': 0.3, 'SZ000601': 0.19, 'SH600200': 0.35, 'SZ000975': 0.08, 'SZ000538': 0.39, 'SZ000422': 0.14, 'SZ000858': 0.88, 'SZ000651': 0.44, 'SH600780': 0.21, 'SH600007': 0.11, 'SH600016': 2.36, 'SZ000866': 0.84, 'SH600267': 0.12, 'SH600266': 0.16, 'SH600786': 0.27, 'SZ000406': 0.39, 'SH600269': 0.47, 'SZ000528': 0.19, 'SH600694': 0.51, 'SZ000786': 0.14, 'SH600004': 0.4, 'SH600663': 0.25, 'SH600662': 0.21, 'SH600548': 0.11, 'SH600383': 0.42, 'SH600357': 0.12, 'SH600705': 0.13, 'SH600812': 0.18, 'SH600707': 0.06, 'SZ000895': 0.49, 'SZ000898': 0.68, 'SZ000400': 0.17, 'SZ000607': 0.1, 'SH600894': 0.1, 'SH600418': 0.4, 'SZ000061': 0.15, 'SH600653': 0.31, 'SZ000682': 0.17, 'SZ000543': 0.07, 'SZ000541': 0.25, 'SH600377': 0.12, 'SZ000949': 0.06, 'SH600256': 0.17, 'SH600006': 0.23, 'SH600005': 1.13, 'SH600790': 0.1, 'SH600797': 0.2, 'SH600002': 0.51, 'SH600795': 0.49, 'SH600000': 1.64, 'SH600652': 0.17, 'SH600121': 0.13, 'SH600123': 0.3, 'SH600125': 0.27, 'SH600126': 0.12, 'SH600008': 0.51, 'SZ000016': 0.14, 'SH600550': 0.24, 'SH600718': 0.16, 'SH600654': 0.2, 'SZ000157': 0.2, 'SH600808': 0.42, 'SZ000666': 0.1, 'SH600805': 0.11, 'SZ000527': 0.39, 'SH600717': 0.5, 'SH600399': 0.07, 'SZ000828': 0.14, 'SZ000959': 0.17, 'SZ000729': 0.29, 'SH600098': 0.43, 'SZ000886': 0.09, 'SZ000099': 0.13, 'SZ000800': 0.29, 'SH600096': 0.29, 'SZ001872': 0.17, 'SH600091': 0.12, 'SZ000956': 0.41, 'SH600887': 0.63, 'SH600886': 0.2, 'SH600884': 0.12, 'SH600308': 0.32, 'SH600309': 0.64, 'SH600881': 0.21, 'SH600307': 0.14, 'SZ000069': 0.8, 'SZ000068': 0.1, 'SH600153': 0.19, 'SZ000792': 0.55, 'SZ000060': 0.38, 'SZ000002': 2.25, 'SZ000001': 1.25, 'SH600138': 0.1, 'SH600649': 0.44, 'SH600015': 0.99, 'SZ000533': 0.07, 'SZ000009': 0.24, 'SH600408': 0.09, 'SZ000778': 0.23, 'SH600643': 0.17, 'SH600642': 0.71, 'SH600832': 0.71, 'SZ000089': 0.36, 'SZ000088': 0.44, 'SZ000539': 0.3, 'SH600835': 0.19, 'SH600726': 0.09, 'SH600010': 0.42, 'SH600724': 0.16, 'SH600839': 0.61, 'SH600011': 0.38, 'SH600012': 0.27, 'SH600089': 0.23, 'SH600088': 0.12, 'SH600087': 0.12, 'SH600085': 0.38, 'SZ000927': 0.2, 'SZ000920': 0.11, 'SZ000962': 0.13, 'SZ000559': 0.16, 'SH600050': 2.98, 'SZ000708': 0.09, 'SZ000503': 0.36, 'SZ000839': 0.44, 'SZ000717': 0.28, 'SZ000100': 0.31, 'SZ000036': 0.18, 'SZ000878': 0.24, 'SZ000511': 0.09, 'SZ000410': 0.19, 'SH600033': 0.24, 'SH600108': 0.13, 'SZ000031': 0.21, 'SZ000507': 0.09, 'SH600104': 0.78, 'SZ002024': 0.45, 'SH600102': 0.18, 'SH600103': 0.14, 'SH600100': 0.41, 'SH600019': 2.84, 'SH600009': 1.5, 'SH600639': 0.19, 'SZ000709': 0.34, 'SH600820': 0.14, 'SZ000571': 0.1, 'SH600739': 0.13, 'SH600631': 0.25, 'SH600021': 0.24, 'SH600635': 0.22, 'SH600637': 0.15, 'SZ000733': 0.09, 'SZ000780': 0.09, 'SH600210': 0.25, 'SZ000939': 0.12, 'SZ000937': 0.26, 'SZ000875': 0.15, 'SZ000933': 0.22, 'SZ000932': 0.51, 'SZ000659': 0.15, 'SZ000930': 0.38, 'SH600320': 0.8, 'SZ000822': 0.17, 'SZ000726': 0.14, 'SZ000727': 0.1, 'SZ000725': 0.13, 'SH600380': 0.14, 'SH600030': 0.63, 'SH600031': 0.16, 'SH600036': 3.93, 'SH600037': 0.62, 'SH600035': 0.16, 'SH600058': 0.2, 'SH600110': 0.13, 'SH600508': 0.19, 'SZ000402': 0.62, 'SH600115': 0.1, 'SH600117': 0.13, 'SZ000423': 0.22, 'SH600348': 0.34, 'SZ000518': 0.14, 'SH600500': 0.26, 'SH600660': 0.37, 'SH600057': 0.09, 'SH600744': 0.12, 'SH600747': 0.11, 'SH600740': 0.09, 'SH600741': 0.17, 'SH600621': 0.11, 'SZ000698': 0.14, 'SH600851': 0.19, 'SZ000900': 0.28, 'SH600854': 0.1, 'SH600868': 0.25, 'SH600428': 0.3, 'SZ000630': 0.36, 'SH600811': 0.3, 'SZ000735': 0.1, 'SZ000737': 0.09, 'SZ000066': 0.19, 'SH600331': 0.25, 'SH600183': 0.27, 'SH600333': 0.1, 'SZ000581': 0.25, 'SZ000425': 0.11, 'SZ000983': 0.49, 'SH600236': 0.25, 'SH600026': 0.45, 'SH600339': 0.08, 'SH600231': 0.16, 'SH600188': 0.27, 'SH600022': 0.2, 'SH600166': 0.08, 'SH600350': 0.37, 'SH600519': 1.14, 'SZ000063': 1.49, 'SH600690': 0.44, 'SZ000758': 0.24, 'SH600296': 0.26, 'SH601607': 0.17, 'SHT00018': 0.8, 'SZ000039': 0.78, 'SZ000599': 0.1, 'SH600198': 0.21, 'SZ000917': 0.15, 'SZ000916': 0.22, 'SZ000912': 0.21, 'SH600190': 0.11, 'SH600196': 0.25, 'SH600583': 0.54, 'SH600581': 0.12, 'SZ000027': 0.6, 'SZ000629': 0.52, 'SH600585': 0.32, 'SZ000021': 0.26, 'SZ000625': 0.25, 'SZ000623': 0.18, 'SZ000024': 0.42, 'SH600221': 0.13, 'SH600220': 0.17}
        timetag = C.get_bar_timetag(C.barpos)
        stock_list = list(data.keys())
        print(stock_list)

        #设置需要写入的扩展数据股票列表
        #reset_extend_data_stock_list(扩展数据名称, 股票列表)
        reset_extend_data_stock_list(C.extencd_name, stock_list)
        # 执行写入扩展数据
        # set_extend_data_value(扩展数据名称,时间戳(毫秒),数据)
        set_extend_data_value(C.extencd_name, timetag, data)  
        print('写入完成')

扩展数据展示

扩展数据
扩展数据

每1分钟统计一次市场涨跌情况

# coding:gbk
import datetime as dt
def on_timer(ContextInfo):
    ls = globals().get("stock_list")
    now_time = dt.datetime.now().strftime("%Y%m%d %H:%M:%S")
    # 取tick数据
    ticks = ContextInfo.get_full_tick(ls)
    
    # 涨跌统计,并去除停牌股
    profit_ls = [i for i in ticks if ticks[i]["lastPrice"] > ticks[i]["lastClose"] and ticks[i]["openInt"] != 1]
    loss_ls = [i for i in ticks if ticks[i]["lastPrice"] < ticks[i]["lastClose"] and ticks[i]["openInt"] != 1]
    print(f"{now_time}: 涨家数{len(profit_ls)}; 跌家数{len(loss_ls)}")

def init(ContextInfo):
    globals()["stock_list"] = get_stock_list_in_sector("沪深京A股")
    # 自2023-12-31 23:59:59后每60s运行一次on_timer
    tid=ContextInfo.schedule_run(on_timer,'20231231235959',3,dt.timedelta(seconds=60),'my_timer')
    # 取消任务组为"my_timer"的任务
    # # ContextInfo.cancel_schedule_run('my_timer')

    # 关于schedule_run函数的用法请阅读文档http://dict.thinktrader.net/innerApi/system_function.html?id=7zqjlm#contextinfo-schedule-run-%E8%AE%BE%E7%BD%AE%E5%AE%9A%E6%97%B6%E5%99%A8
    

交易下单示例

按品种划分

股票

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    # 单股单账号股票最新价买入 100 股(1 手)   
    passorder(23, 1101, 'test', '600000.SH', 5, 0, 100, '',1,'',ContextInfo)
    # 单股单账号股票最新价卖出 100 股(1 手)   
    passorder(24, 1101, 'test', '600000.SH', 5, 0, 100, '',1,'',ContextInfo)
    # 单股单账号沪市股票市价买入 100 股(1 手),沪市市价存在保护限价,Price参数为保护限价,买入为投资者能够接受的最高买价,填0会自动填为涨停价
    passorder(23, 1101, 'test', '600000.SH', 42, 0, 100, '',1,'',ContextInfo)
    # 单股单账号沪市股票市价卖出 100 股(1 手),沪市市价存在保护限价,Price参数为保护限价,卖出为投资者能够接受的最低卖价,填0会自动填为跌停价
    passorder(24, 1101, 'test', '600000.SH', 42, 0, 100, '',1,'',ContextInfo)
    # 单股单账号京市股票最新价买入 101 股(1 手零 1 股)   
    passorder(23, 1101, 'test', '430047.BJ', 5, 0, 101, '',1,'',ContextInfo)
    # 单股单账号京市股票最新价卖出 101 股(1 手零 1 股)  
    passorder(24, 1101, 'test', '430047.BJ', 5, 0, 101, '',1,'',ContextInfo)

基金

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return

    # 申购 中证500指数ETF  
    passorder(60, 1101, 'test', '510030.SH', 5, 0, 1, 2, ContextInfo)  
    
    # 赎回 中证500指数ETF
    passorder(61, 1101, 'test', '510030.SH', 5, 0, 1, 2, ContextInfo)  

两融

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    target = '000001.SZ'
    # 单股单账号股票指定价担保品买入 100 股(1 手)  
    passorder(33, 1101, 'test', target, 11, 7, 100, ContextInfo)
    # 单股单账号股票指定价融资买入 100 股(1 手)  
    passorder(27, 1101, 'test', target, 11, 7, 100, ContextInfo)

期货

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
	
    # 单股单账号期货最新价开多螺纹钢2401 10 手
	target = 'rb2401.SF'
    passorder(0, 1101, 'test', target, 5, -1, 10, 1, ContextInfo)

    
    # 单股单账号期货指定价开空甲醇2401 10 手
	target = 'MA401.ZF'
    passorder(3, 1101, 'test', target, 11, 3000, 10, 1, ContextInfo)


    #期货四键平多300股指2311,优先平今 2手
	target = 'IF2311.IF'
	passorder(6, 1101, 'test', target, 5, -1, 2, 1, ContextInfo)
    

期权

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
	target = '10005330.SHO' # 50ETF购12月2450合约

    # 单股单账号用最新价买入开仓期权合约target 2张
    passorder(50, 1101, 'test', target, 5, -1, 2, 1, ContextInfo)
    
    # 单股单账号用最新价卖出平仓期权合约target 2张
    passorder(51, 1101, 'test', target, 5, -1, 2, 1, ContextInfo)

新股申购

#coding:gbk
def init(C):
	ipoStock=get_ipo_data("STOCK")#返回新股信息
	print(ipoStock)
	accont = '123456789'
	for stock in ipoStock:
		ipo_price = ipoStock[stock]['issuePrice'] # 发行价
		maxPurchaseNum = ipoStock[stock]['maxPurchaseNum'] # 可申购额度
		passorder(23,1101, accont, stock,11,ipo_price, maxPurchaseNum,'新股申购',2,stock,C)

债券

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    # 单股单账号最新价可转债买入 20张
    passorder(23, 1101, 'test', '128123.SZ', 5, -1, 10, 1, ContextInfo)
    

ETF

#coding:gbk
def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    # 单股单账号 最新价买入上证etf 2000份
    passorder(23, 1101, 'test', '510050.SH', 5, -1, 2000, ContextInfo)
   

组合交易

一键买卖(一篮子下单)

功能描述: 该示例演示如何用python进行一揽子股票买卖的交易操作

代码示例:

#coding:gbk

def init(C):
	
	table=[
			{'stock':'600000.SH','weight':0.11,'quantity':100,'optType':23},
			{'stock':'600028.SH','weight':0.11,'quantity':200,'optType':24},
		]
	basket={'name':'basket1','stocks':table}
	set_basket(basket)
	# 按篮子数量下单, 下2份 # 即下两倍篮子
	pice = 2
	passorder(35,  #一键买卖
			2101,  # 表示按股票数量下单
			account,
			'basket1',  # 篮子名称
			5, # 最新价下单
			1,  # 价格,最新价时 该参数无效,需要填任意数占位
			pice, # 篮子份数
			'',2,'strReMark',C)
	
	# 按篮子权重下单
	table=[
			{'stock':'600000.SH','weight':0.4,'quantity':0,'optType':23}, # 40%
			{'stock':'600028.SH','weight':0.6,'quantity':0,'optType':24}, # 60%
		]
	basket={'name':'basket2','stocks':table}
	set_basket(basket)
	# 按组合权重 总额10000元
	money = 10000
	passorder(35,2102,account,'basket2',5,1,money,'',2,'strReMark',C)

组合套利交易

提示

accountIDorderType 特殊设置)

用法

释义

参数

参数名称 描述
accountID 'stockAccountID, futureAccountID'
orderCode 'basketName, futureName'
hedgeRatio 套利比例(0 ~ 2 之间值,相当于 %0 至 200% 套利)
volume 份数 \ 资金 \ 比例
orderType 参考下方orderType-下单方式(特殊设置)

orderType - 下单方式(特殊设置)

编号 项目
2331 组合、套利、合约价值自动套利、按组合股票数量方式下单
2332 组合、套利、按合约价值自动套利、按组合股票权重方式下单
2333 组合、套利、按合约价值自动套利、按账号可用方式下单

示例



按功能划分

passorder 下单函数

本示例用于演示K线走完下单及立即下单的参数写法差异,旨在帮助您了解如何快速实现下单操作。

#coding:gbk
c = 0
s = '000001.SZ'
def init(ContextInfo):
	# 立即下单 用最新价买入股票s 100股,且指定投资备注
	passorder(23,1101,account,s,5,0,100,'1',2,'tzbz',ContextInfo) 
	pass


def handlebar(ContextInfo):
	if not ContextInfo.is_last_bar():
		#历史k线不应该发出实盘信号 跳过
		return

	if ContextInfo.is_last_bar():
		global c
		c +=1 
		if c ==1:
			# 用14.00元限价买入股票s 100股
			passorder(23,1101,account,s,11,14.00,100,1,ContextInfo)  # 当前k线为最新k线 则立即下单
			# 用最新价限价买入股票s 100股
			passorder(23,1101,account,s,5,-1,100,0,ContextInfo)  # K线走完下单
			# 用最新价限价买入股票s 1000元
			passorder(23, 1102, account, s, 5, 0,1000, 2, ContextInfo)  # 不管是不是最新K线,立即下单

集合竞价下单

本示例演示了利用定时器函数和passorder下单函数在集合竞价期间以指定价买入平安银行100股。

#coding:gbk

import time
c = 0
s = '000001.SZ'
def init(ContextInfo):
	# 设置定时器,历史时间表示会在一次间隔时间后开始调用回调函数 比如本例中 5秒后会后第一次触发myHandlebar调用 之后五秒触发一次
	ContextInfo.run_time("myHandlebar","5nSecond","2019-10-14 13:20:00")


def myHandlebar(ContextInfo):
	global c
	now = time.strftime('%H%M%S')
	if c ==0 and '092500' >= now >= '091500':
		c += 1
		passorder(23,1101,account,s,11,14.00,100,2,ContextInfo) # 立即下单

def handlebar(ContextInfo):
	return

止盈止损示例

#coding:gbk

"""
1.账户内所有股票,当股价低于买入价10%止损卖出。
2.账户内所有股票,当股价高于前一天的收盘价10%时,开始监控一旦股价炸板(开板),以买三价卖出
"""

def init(C):
	C.ratio = 1
	if accountType == 'STOCK':
		C.sell_code = 24
	if accountType == 'CREDIT':
		C.sell_code = 34
	C.spare_list = C.get_stock_list_in_sector('不卖品种')

def handlebar(C):
	if not C.is_last_bar():
		return
	holdings = get_trade_detail_data(account, accountType, 'position')
	stock_list = [holding.m_strInstrumentID + '.' + holding.m_strExchangeID for holding in holdings]
	if stock_list:
		full_tick = C.get_full_tick(stock_list)
		for holding in holdings:
			stock = holding.m_strInstrumentID + '.' + holding.m_strExchangeID
			rate = holding.m_dProfitRate
			volume = holding.m_nCanUseVolume
			if not volume >= 100:
				continue
			if stock in C.spare_list:
				continue
			if rate < -0.1:
				msg = f'{stock} 盈亏比例 {rate} 小于-10% 卖出 {volume}股'
				print(msg)
				passorder(C.sell_code, 1101, account, stock, 14, -1, volume, '减仓模型', 2, msg, C)
				continue
			if stock in full_tick:
				current_price = full_tick[stock]['lastPrice']
				pre_price = full_tick[stock]['lastClose']
				high_price = full_tick[stock]['high']
				stop_price = pre_price * 1.2 if stock[:2] in ['30', '68'] else pre_price * 1.1
				stop_price = round(stop_price, 2)
				ask_price_3 = full_tick[stock]['bidPrice'][2]
				if not ask_price_3:
					print(f"{stock} {full_tick[stock]} 未取到三档盘口价 请检查客户端右下角 行情界面 是否选择了五档行情 本次跳过卖出")
					continue
				if high_price == stop_price and current_price < stop_price:
					msg = f"{stock} 涨停后 开板 卖出 {volume}股"
					print(msg)
					passorder(C.sell_code, 1101, account, stock, 14, -1, volume, '减仓模型', 2, msg, C)
					continue

passorder 下算法单函数

本示例由于演示如何下达算法单,具体算法参数请参考迅投投研平台客户端参数说明。

#coding:gbk
import time

def init(C):
	userparam={
	'OrderType':1,  #表示要下算法
	'PriceType':0, # 卖5价下单
	'MaxOrderCount':12, # 最大委托次数
	'SuperPriceType':0,  # 超价类型,0表示按比例
	'SuperPriceRate':0.02,  # 超价2%下单
	'VolumeRate':0.1,  # 单笔下单比率 每次拆10%
	'VolumeType': 10,  # 单笔基准量类型
	'SingleNumMax':1000000,  # 单笔拆单最大值
	'PriceRangeType':0,  # 波动区间类型
	'PriceRangeRate':1,  # 波动区间值
	'ValidTimeType':1,  # 有效时间类型 1 表示按执行时间
	'ValidTimeStart':int(time.time()),  # 算法开始时间
	'ValidTimeEnd':int(time.time()+60*60),  # 算法结束时间
	'PlaceOrderInterval':10, # 报撤间隔
	'UndealtEntrustRule':0, # 未成委托处理数值 用卖5加挂单
	}
	target_vol = 2000000  # 股, 算法目标总量
	algo_passorder(23, 1101, account, '600000.SH', -1, -1, target_vol, '', 2, '普通算法', userparam, C)
	print('finish')
def handlebar(C):
	pass

如何使用投资备注

投资备注功能是模型下单时指定的任意字符串(长度小于24),即passorder的userOrderId参数,可以用于匹配委托或成交。有且只有passorder, algo_passorder, smart_algo_passorder下单函数支持投资备注功能。

# encoding:gbk

note = 0

def get_new_note():
	global note
	note += 1
	return str(note)

def init(ContextInfo):
	ContextInfo.set_account(account)
	passorder(23, 1101, account, '000001.SZ', 5 ,0, 100, '', 2, get_new_note(), ContextInfo)

	orders = get_trade_detail_data(account, accountType, 'order')
	remark = [o.m_strRemark for o in orders]
	sysid_list = [o.m_strOrderSysID for o in orders]
	print(remark)



def handlebar(C):
	pass


def order_callback(C, O):
	print(O.m_strRemark, O.m_strOrderSysID)

    
def deal_callback(C, D):
	print(D.m_strRemark, D.m_strOrderSysID)

如何获取委托持仓及资金数据

本示例用于演示如何通过函数获取指定账户的委托、持仓、资金数据。

#coding:gbk


def to_dict(obj):
	attr_dict = {}
	for attr in dir(obj):
		try:
			if attr[:2] == 'm_':
				attr_dict[attr] = getattr(obj, attr)
		except:
			pass
	return attr_dict


def init(C):
	pass
	#orders, deals, positions, accounts = query_info(C)


def handlebar(C):
	if not C.is_last_bar():
		return
	orders, deals, positions, accounts = query_info(C)


def query_info(C):
	orders = get_trade_detail_data('8000000213', 'stock', 'order')
	for o in orders:
		print(f'股票代码: {o.m_strInstrumentID}, 市场类型: {o.m_strExchangeID}, 证券名称: {o.m_strInstrumentName}, 买卖方向: {o.m_nOffsetFlag}',
		f'委托数量: {o.m_nVolumeTotalOriginal}, 成交均价: {o.m_dTradedPrice}, 成交数量: {o.m_nVolumeTraded}, 成交金额:{o.m_dTradeAmount}')


	deals = get_trade_detail_data('8000000213', 'stock', 'deal')
	for dt in deals:
		print(f'股票代码: {dt.m_strInstrumentID}, 市场类型: {dt.m_strExchangeID}, 证券名称: {dt.m_strInstrumentName}, 买卖方向: {dt.m_nOffsetFlag}', 
		f'成交价格: {dt.m_dPrice}, 成交数量: {dt.m_nVolume}, 成交金额: {dt.m_dTradeAmount}')

	positions = get_trade_detail_data('8000000213', 'stock', 'position')
	for dt in positions:
		print(f'股票代码: {dt.m_strInstrumentID}, 市场类型: {dt.m_strExchangeID}, 证券名称: {dt.m_strInstrumentName}, 持仓量: {dt.m_nVolume}, 可用数量: {dt.m_nCanUseVolume}',
		f'成本价: {dt.m_dOpenPrice:.2f}, 市值: {dt.m_dInstrumentValue:.2f}, 持仓成本: {dt.m_dPositionCost:.2f}, 盈亏: {dt.m_dPositionProfit:.2f}')


	accounts = get_trade_detail_data('8000000213', 'stock', 'account')
	for dt in accounts:
		print(f'总资产: {dt.m_dBalance:.2f}, 净资产: {dt.m_dAssureAsset:.2f}, 总市值: {dt.m_dInstrumentValue:.2f}', 
		f'总负债: {dt.m_dTotalDebit:.2f}, 可用金额: {dt.m_dAvailable:.2f}, 盈亏: {dt.m_dPositionProfit:.2f}')

	return orders, deals, positions, accounts

使用快速交易参数委托

本例展示如何使用快速交易参数(quickTrade)立刻进行委托。

#coding:gbk

def after_init(C):
	#account变量是模型交易界面 添加策略时选择的资金账号 不需要手动填写
	#快速交易参数(quickTrade )填2 passorder函数执行后立刻下单 不会等待k线走完再委托。 可以在after_init函数 run_time函数注册的回调函数里进行委托 
	msg = f"投资备注字符串 用来区分不同委托"
	passorder(23, 1101, account, '600000.SH', 5, -1, 200, '测试下单', 2, msg, C)

调整至目标持仓

本示例由于演示如何调仓。

#encoding:gbk

'''
调仓到指定篮子
'''

import pandas as pd
import numpy as np
import time
from datetime import timedelta,datetime

#自定义类 用来保存状态 
class a():pass
A=a()
A.waiting_dict =  {}
A.all_order_ref_dict = {}
#撤单间隔 单位秒 超过间隔未成交的委托撤回重报
A.withdraw_secs = 30
#定义策略开始结束时间 在两者间时进行下单判断 其他时间跳过
A.start_time = '093000'
A.end_time = '150000'

def init(C):
	'''读取目标仓位 字典格式 品种代码:持仓股数, 可以读本地文件/数据库,当前在代码里写死'''
	A.final_dict = {"600000.SH" :10000, '000001.SZ' : 20000}
	'''设置交易账号 acount accountType是界面上选的账号 账号类型'''
	A.acct = account
	A.acct_type = accountType
	#定时器 定时触发指定函数
	C.run_time("f","1nSecond","2019-10-14 13:20:00","SH")


def f(C):
	'''定义定时触发的函数 入参是ContextInfo对象'''
	#记录本次调用时间戳
	t0 = time.time()
	final_dict=A.final_dict
	#本次运行时间字符串
	now = datetime.now()
	now_timestr = now.strftime("%H%M%S")
	#跳过非交易时间
	if now_timestr < A.start_time or now_timestr > A.end_time:
		return
	#获取账号信息
	acct = get_trade_detail_data(A.acct, A.acct_type, 'account')
	if len(acct) == 0:
		print(A.acct, '账号未登录 停止委托')
		return
	acct = acct[0]
	#获取可用资金
	available_cash = acct.m_dAvailable
	print(now, '可用资金', available_cash)
	#获取持仓信息
	position_list = get_trade_detail_data(A.acct, A.acct_type, 'position')
	#持仓数据 组合为字典
	position_dict = {i.m_strInstrumentID + '.' + i.m_strExchangeID : int(i.m_nVolume) for i in position_list}
	position_dict_available = {i.m_strInstrumentID + '.' + i.m_strExchangeID : int(i.m_nCanUseVolume) for i in position_list}
	#未持有的品种填充持股数0
	not_in_position_stock_dict = {i : 0 for i in final_dict if i not in position_dict}
	position_dict.update(not_in_position_stock_dict)
	#print(position_dict)
	stock_list = list(position_dict.keys())
	# print(stock_list)
	#获取全推行情
	full_tick = C.get_full_tick(stock_list)
	#print('fulltick', full_tick)
	#更新持仓状态记录
	refresh_waiting_dict(C)
	#撤超时委托
	order_list = get_trade_detail_data(A.acct, 'stock', 'order')
	if '091500'<= now_timestr <= '093000':#指定的范围內不撤单
		pass
	else:
		for order in order_list:
			#非本策略 本次运行记录的委托 不撤
			if order.m_strRemark not in A.all_order_ref_dict:
				continue
			#委托后 时间不到撤单等待时间的 不撤
			if time.time() - A.all_order_ref_dict[order.m_strRemark] < A.withdraw_secs:
				continue
			#对所有可撤状态的委托 撤单
			if order.m_nOrderStatus in [48,49,50,51,52,55,86,255]:
				print(f"超时撤单 停止等待 {order.m_strRemark}")
				cancel(order.m_strOrderSysID,A.acct,'stock',C)
	#下单判断
	for stock in position_dict:
		#有未查到的委托的品种 跳过下单 防止超单
		if stock in A.waiting_dict:
			print(f"{stock} 未查到或存在未撤回委托 {A.waiting_dict[stock]} 暂停后续报单")
			continue
		if stock in position_dict.keys():
			#print(position_dict[stock],target_vol,'1111')
			#到达目标数量的品种 停止委托
			target_vol = final_dict[stock] if stock in final_dict else 0
			if int(abs(position_dict[stock] - target_vol)) == 0:
				print(stock, C.get_stock_name(stock), '与目标一致')
				continue
			#与目标数量差值小于100股的品种 停止委托
			if abs(position_dict[stock] - target_vol) < 100:
				print(f"{stock} {C.get_stock_name(stock)} 目标持仓{target_vol} 当前持仓{position_dict[stock]} 差额小于100 停止委托")
				continue
			#持仓大于目标持仓 卖出
			if position_dict[stock]>target_vol:
				vol = int((position_dict[stock] - target_vol)/100)*100
				if stock not in position_dict_available:
					continue
				vol = min(vol, position_dict_available[stock])
				#获取买一价
				print(stock,'应该卖出')
				buy_one_price = full_tick[stock]['bidPrice'][0]
				#买一价无效时 跳过委托
				if not buy_one_price > 0:
					print(f"{stock} {C.get_stock_name(stock)} 取到的价格{buy_one_price}无效,跳过此次推送")
					continue
				print(f"{stock} {C.get_stock_name(stock)} 目标股数{target_vol} 当前股数{position_dict[stock]}")
				msg = f"{now.strftime('%Y%m%d%H%M%S')}_{stock}_sell_{vol}股"
				print(msg)
				#对手价卖出
				passorder(24,1101,A.acct,stock,14,-1,vol,'调仓策略',2,msg,C)
				A.waiting_dict[stock] = msg
				A.all_order_ref_dict[msg] = time.time()
			#持仓小于目标持仓 买入
			if position_dict[stock]<target_vol:
				vol = int((target_vol-position_dict[stock])/100)*100
				#获取卖一价
				sell_one_price = full_tick[stock]['askPrice'][0]
				#卖一价无效时 跳过委托
				if not sell_one_price > 0:
					print(f"{stock} {C.get_stock_name(stock)} 取到的价格{sell_one_price}无效,跳过此次推送")
					continue
				target_value = sell_one_price * vol
				if target_value > available_cash:
					print(f"{stock} 目标市值{target_value} 大于 可用资金{available_cash} 跳过委托")
					continue
				print(f"{stock} {C.get_stock_name(stock)} 目标股数{target_vol} 当前股数{position_dict[stock]}")
				msg = f"{now.strftime('%Y%m%d%H%M%S')}_{stock}_buy_{vol}股"
				print(msg)
				#对手价买入
				passorder(23,1101,A.acct,stock,14,-1,vol,'调仓策略',2,msg,C)
				A.waiting_dict[stock] = msg
				A.all_order_ref_dict[msg] = time.time()
				available_cash -= target_value
	#打印函数运行耗时 定时器间隔应大于该值
	print(f"下单判断函数运行完成 耗时{time.time() - t0}秒")


def refresh_waiting_dict(C):
	"""更新委托状态 入参为ContextInfo对象"""
	#获取委托信息
	order_list = get_trade_detail_data(A.acct,A.acct_type,'order')
	#取出委托对象的 投资备注 : 委托状态
	ref_dict = {i.m_strRemark : int(i.m_nOrderStatus) for i in order_list}
	del_list = []
	for stock in A.waiting_dict:
		if A.waiting_dict[stock] in ref_dict and ref_dict[A.waiting_dict[stock]] in [56, 53, 54]:
			#查到对应投资备注 且状态为成交 / 已撤 / 部撤, 从等待字典中删除
			print(f'查到投资备注 {A.waiting_dict[stock]},的委托 状态{ref_dict[A.waiting_dict[stock]]} (56已成 53部撤 54已撤)从等待等待字典中删除')
			del_list.append(stock)
		if A.waiting_dict[stock] in ref_dict and ref_dict[A.waiting_dict[stock]] == 57:
			#委托状态是废单的 也停止等待 从等待字典中删除 
			print(f"投资备注为{A.waiting_dict[stock]}的委托状态为废单 停止等待")
			del_list.append(stock)
	for stock in del_list:
		del A.waiting_dict[stock]

获取融资融券账户可融资买入标的

#coding:gbk
def init(C):
	
	r = get_assure_contract('123456789')
	if len(r) == 0:
		print('未取到担保明细')
	else:
		finable = [o.m_strInstrumentID+'.'+o.m_strExchangeID for o in r if o.m_eFinStatus==48]
		print('可融资买入标的:', finable)

获取两融账号信息示例

#coding:gbk

def init(C):
	account_str = '11800028'
	credit_account = query_credit_account(account_str, 1234, C)

def credit_account_callback(C,seq,result):
	print('可买担保品资金', result.m_dAssureEnbuyBalance)

直接还款示例

该示例演示使用python进行融资融券账户的还款操作。

#coding:gbk  


def init(ContextInfo):
	# 用passorder函数进行融资融券账号的直接还款操作

	money = 10000  #还款金额
	#account='123456'
	s = '000001.SZ'  # 代码填任意股票,占位用
	passorder(32, 1101, account, s, 5, 0, money, 2, ContextInfo)
	# passorder(75, 1101, account, s, 5, 0, money, 2, ContextInfo) 专项直接还款

交易数据查询示例

#coding:gbk


def to_dict(obj):
	attr_dict = {}
	for attr in dir(obj):
		try:
			if attr[:2] == 'm_':
				attr_dict[attr] = getattr(obj, attr)
		except:
			pass
	return attr_dict


def init(C):
	pass
	#orders, deals, positions, accounts = query_info(C)


def handlebar(C):
	if not C.is_last_bar():
		return
	orders, deals, positions, accounts = query_info(C)


def query_info(C):
	orders = get_trade_detail_data('8000000213', 'stock', 'order')
	for o in orders:
		print(f'股票代码: {o.m_strInstrumentID}, 市场类型: {o.m_strExchangeID}, 证券名称: {o.m_strInstrumentName}, 买卖方向: {o.m_nOffsetFlag}',
		f'委托数量: {o.m_nVolumeTotalOriginal}, 成交均价: {o.m_dTradedPrice}, 成交数量: {o.m_nVolumeTraded}, 成交金额:{o.m_dTradeAmount}')


	deals = get_trade_detail_data('8000000213', 'stock', 'deal')
	for dt in deals:
		print(f'股票代码: {dt.m_strInstrumentID}, 市场类型: {dt.m_strExchangeID}, 证券名称: {dt.m_strInstrumentName}, 买卖方向: {dt.m_nOffsetFlag}', 
		f'成交价格: {dt.m_dPrice}, 成交数量: {dt.m_nVolume}, 成交金额: {dt.m_dTradeAmount}')

	positions = get_trade_detail_data('8000000213', 'stock', 'position')
	for dt in positions:
		print(f'股票代码: {dt.m_strInstrumentID}, 市场类型: {dt.m_strExchangeID}, 证券名称: {dt.m_strInstrumentName}, 持仓量: {dt.m_nVolume}, 可用数量: {dt.m_nCanUseVolume}',
		f'成本价: {dt.m_dOpenPrice:.2f}, 市值: {dt.m_dInstrumentValue:.2f}, 持仓成本: {dt.m_dPositionCost:.2f}, 盈亏: {dt.m_dPositionProfit:.2f}')


	accounts = get_trade_detail_data('8000000213', 'stock', 'account')
	for dt in accounts:
		print(f'总资产: {dt.m_dBalance:.2f}, 净资产: {dt.m_dAssureAsset:.2f}, 总市值: {dt.m_dInstrumentValue:.2f}', 
		f'总负债: {dt.m_dTotalDebit:.2f}, 可用金额: {dt.m_dAvailable:.2f}, 盈亏: {dt.m_dPositionProfit:.2f}')

	return orders, deals, positions, accounts

证券、财务与衍生品数据

本章介绍 QMT 内置 Python 中证券基本信息、财务数据和衍生品数据的获取方法。

证券基本信息

获取股票信息

# 获取股票基本信息
info = ContextInfo.get_stock_info('000001.SZ')
# info 包含:名称、上市日期、所属行业等

获取证券类型

# 判断证券类型
sec_type = ContextInfo.get_security_type('000001.SZ')
# 返回值:stock(股票), fund(基金), bond(债券), index(指数) 等

获取上市状态

# 检查是否已上市
is_listed = ContextInfo.is_stock_listed('000001.SZ')

财务数据

获取财务指标

# 获取财务数据
financial = ContextInfo.get_financial_data(
    ['000001.SZ'],
    ['PE', 'PB', 'ROE', '净利润'],
    '20231231',  # 报告期
    '20231231',
)

常用财务指标

指标 说明 数据类型
PE 市盈率 float
PB 市净率 float
ROE 净资产收益率 float
EPS 每股收益 float
净利润 净利润 float
营业收入 营业收入 float
总资产 总资产 float
负债合计 总负债 float

获取利润表

# 获取利润表数据
income = ContextInfo.get_income_data(
    '000001.SZ',
    '20231231',
)

获取资产负债表

# 获取资产负债表数据
balance = ContextInfo.get_balance_sheet_data(
    '000001.SZ',
    '20231231',
)

指数数据

获取指数成分股

# 获取沪深300成分股
stocks = ContextInfo.get_stock_list_in_sector('沪深300')
print(f'沪深300成分股数量: {len(stocks)}')

# 获取中证500成分股
stocks = ContextInfo.get_stock_list_in_sector('中证500')

获取指数权重

# 获取指数成分权重
weights = ContextInfo.get_index_weights('000300.SH', '20241201')
# weights: {stock_code: weight, ...}

常用指数代码

指数名称 代码
上证指数 000001.SH
深证成指 399001.SZ
沪深300 000300.SH
中证500 000905.SH
创业板指 399006.SZ

板块数据

获取板块列表

# 获取所有板块
sectors = ContextInfo.get_sector_list()
for sector in sectors:
    print(sector)

获取板块成分股

# 获取指定板块的成分股
stocks = ContextInfo.get_stock_list_in_sector('银行')
stocks = ContextInfo.get_stock_list_in_sector('半导体')

获取板块分类

分类 说明
申万行业 申万一级行业分类
证监会行业 证监会行业分类
概念板块 热门概念板块

行权与分红

获取除权除息信息

# 获取除权除息数据
dividend = ContextInfo.get_dividend_data('000001.SZ', '20200101', '20241201')

获取复权数据

# 前复权
close_fq = ContextInfo.get_history_data('close', 20, '', True, 1)
# 后复权
close_bq = ContextInfo.get_history_data('close', 20, '', True, 2)
提示

回测时建议使用前复权数据,避免除权除息造成的价格跳变。

衍生品数据

期货数据

# 获取期货合约信息
info = ContextInfo.get_instrument_detail('IF2412.CCFX')
# 包含:合约乘数、保证金率、交割日等

期权数据

# 获取期权合约信息
info = ContextInfo.get_instrument_detail('10004868.SH')
# 包含:行权价、到期日、标的等

期货连续合约

合约代码 说明
IF.CCFX 沪深300主力连续
IC.CCFX 中证500主力连续
IH.CCFX 上证50主力连续

数据下载管理

批量下载

def init(ContextInfo):
    # 批量下载多个品种的数据
    stocks = ['000001.SZ', '600000.SH', '510050.SH']
    for stock in stocks:
        ContextInfo.do_download_history_data(
            stock, '1d', '20200101', '20241201'
        )

数据更新检查

技巧

定期检查数据更新,确保使用最新数据:

# 检查最后一条数据的日期
closes = ContextInfo.get_history_data('close', 1)
if closes:
    last_date = ContextInfo.get_bar_timetag(ContextInfo.barpos)
    print(f'数据最后日期: {last_date}')

模型扩展、板块与绘图

本章介绍 QMT 内置 Python 的模型扩展、自定义指标和图表绘制功能。

自定义指标

创建自定义指标

def init(ContextInfo):
    ContextInfo.set_universe(['000001.SZ'])
    # 注册自定义指标
    ContextInfo.bindBindbar('MY_MA', 'my_ma')

def my_ma(ContextInfo, index_info):
    """自定义均线指标"""
    closes = ContextInfo.get_history_data('close', 20)
    if closes and len(closes) >= 20:
        ma = sum(closes[-20:]) / 20
        index_info.set_value(ma)

指标参数

def init(ContextInfo):
    # 注册带参数的指标
    ContextInfo.bindBindbar('MY_MACD', 'my_macd', 
        params={'short': 12, 'long': 26, 'signal': 9})

def my_macd(ContextInfo, index_info):
    short = index_info.get_param('short')
    long_period = index_info.get_param('long')
    signal = index_info.get_param('signal')
    
    closes = ContextInfo.get_history_data('close', long_period + signal)
    if not closes or len(closes) < long_period + signal:
        return
    
    # 计算 MACD
    ema_short = calc_ema(closes, short)
    ema_long = calc_ema(closes, long_period)
    dif = ema_short - ema_long
    index_info.set_value(dif)

def calc_ema(data, period):
    """计算指数移动平均"""
    multiplier = 2 / (period + 1)
    ema = data[0]
    for price in data[1:]:
        ema = price * multiplier + ema * (1 - multiplier)
    return ema

模型扩展

使用内置 talib 库

import talib

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    closes = ContextInfo.get_history_data('close', 50)
    if not closes or len(closes) < 50:
        return
    
    closes_array = np.array(closes)
    
    # 计算技术指标
    ma20 = talib.SMA(closes_array, timeperiod=20)
    rsi = talib.RSI(closes_array, timeperiod=14)
    macd, signal, hist = talib.MACD(closes_array)
    
    print(f'MA20: {ma20[-1]}, RSI: {rsi[-1]}')

可用的 talib 指标

指标 函数 说明
SMA talib.SMA 简单移动平均
EMA talib.EMA 指数移动平均
RSI talib.RSI 相对强弱指标
MACD talib.MACD MACD 指标
KDJ talib.STOCH 随机指标
BOLL talib.BBANDS 布林带
ATR talib.ATR 真实波幅

自定义计算函数

import numpy as np

def calc_bollinger(closes, period=20, num_std=2):
    """计算布林带"""
    closes = np.array(closes)
    ma = np.mean(closes[-period:])
    std = np.std(closes[-period:])
    
    upper = ma + num_std * std
    lower = ma - num_std * std
    
    return upper, ma, lower

def calc_kdj(highs, lows, closes, period=9):
    """计算 KDJ 指标"""
    highs = np.array(highs[-period:])
    lows = np.array(lows[-period:])
    closes = np.array(closes[-period:])
    
    highest = np.max(highs)
    lowest = np.min(lows)
    
    rsv = (closes[-1] - lowest) / (highest - lowest) * 100
    return rsv

板块管理

获取板块列表

# 获取所有板块
sectors = ContextInfo.get_sector_list()
for s in sectors:
    print(s)

获取板块成分

# 获取板块成分股
stocks = ContextInfo.get_stock_list_in_sector('沪深300')
print(f'成分股数量: {len(stocks)}')

自定义板块

# 创建自定义板块
ContextInfo.add_sector('MY_STOCKS', ['000001.SZ', '600000.SH'])

# 获取自定义板块成分
stocks = ContextInfo.get_stock_list_in_sector('MY_STOCKS')

图表绘制

基本绘图

import matplotlib
matplotlib.use('Agg')  # 使用非交互式后端
import matplotlib.pyplot as plt

def draw_chart(closes, title='价格走势'):
    """绘制价格走势图"""
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(closes, label='收盘价')
    ax.set_title(title)
    ax.set_xlabel('日期')
    ax.set_ylabel('价格')
    ax.legend()
    ax.grid(True)
    
    # 保存图片
    fig.savefig('chart.png', dpi=150, bbox_inches='tight')
    plt.close(fig)
    print('图表已保存到 chart.png')

在策略中使用绘图

def handlebar(ContextInfo):
    if not ContextInfo.is_last_bar():
        return
    
    closes = ContextInfo.get_history_data('close', 60)
    if not closes or len(closes) < 60:
        return
    
    # 每 20 天画一次图
    if ContextInfo.barpos % 20 == 0:
        draw_chart(closes, f'{ContextInfo.stockcode} 价格走势')

绘制 K 线图

from matplotlib.patches import Rectangle

def draw_candlestick(opens, highs, lows, closes, title='K线图'):
    """绘制 K 线图"""
    fig, ax = plt.subplots(figsize=(12, 6))
    
    for i in range(len(closes)):
        # 判断涨跌
        color = 'red' if closes[i] >= opens[i] else 'green'
        
        # 画实体
        rect = Rectangle(
            (i, min(opens[i], closes[i])),
            0.6,
            abs(closes[i] - opens[i]),
            facecolor=color,
            edgecolor=color,
        )
        ax.add_patch(rect)
        
        # 画影线
        ax.plot([i + 0.3, i + 0.3], [lows[i], highs[i]], color=color, linewidth=0.5)
    
    ax.set_title(title)
    ax.set_xlabel('交易日')
    ax.set_ylabel('价格')
    fig.savefig('candlestick.png', dpi=150, bbox_inches='tight')
    plt.close(fig)

数据导出

导出 CSV

import csv

def export_to_csv(ContextInfo):
    """导出策略数据到 CSV"""
    closes = ContextInfo.get_history_data('close', 20)
    
    with open('output.csv', 'w', newline='', encoding='utf-8') as f:
        writer = csv.writer(f)
        writer.writerow(['日期', '收盘价'])
        for i, close in enumerate(closes):
            writer.writerow([i, close])
    
    print('数据已导出到 output.csv')
提示

QMT 内置的 matplotlib 使用 Agg 后端,无法实时显示图表,只能保存为图片文件。

数据结构与枚举

本章列出 QMT 内置 Python 中的核心数据结构和枚举常量,供开发时查阅。

ContextInfo 对象

ContextInfo 是策略运行的核心上下文对象。

属性

属性 类型 说明
stockcode str 当前品种代码
period str 当前周期(如 '1d', '5m')
timetag int 当前 K 线时间戳
barpos int 当前 K 线位置索引
do_back_test bool 是否处于回测模式
bar_size int K 线数量
run_time str 策略运行时间

方法 - 数据获取

方法 参数 返回值 说明
get_close_price() - float 收盘价
get_open_price() - float 开盘价
get_high_price() - float 最高价
get_low_price() - float 最低价
get_volume() - int 成交量
get_money() - float 成交额
get_last_price(stock) stock: str float 最新价
get_history_data(field, count, stock) field, count, stock list 历史数据
get_market_data(fields, stocks, period, count) - dict 市场数据

方法 - 交易

方法 参数 返回值 说明
order_volume(...) stockcode, volume, priceType, price, orderType str 按数量下单
order_value(...) stockcode, value, priceType, price, orderType str 按金额下单
order_target(...) stockcode, target_volume, priceType, price str 调仓到目标数量
order_target_value(...) stockcode, target_value, priceType, price str 调仓到目标金额
cancel(order_id, ContextInfo) order_id - 撤单
get_account() - Account 获取账户信息
get_positions() - dict 获取所有持仓
get_position(stock) stock: str Position 获取指定品种持仓
get_orders() - list 获取当日委托

方法 - 配置

方法 参数 说明
set_universe(stocks) stocks: list 设置股票池
get_universe() - 获取股票池
is_last_bar() - 是否为最新 K 线
do_download_history_data(stock, period, start, end) - 下载历史数据

Account 对象

账户信息对象,通过 ContextInfo.get_account() 获取。

字段 类型 说明
m_dBalance float 总资产
m_dAvailable float 可用资金
m_dPositionValue float 持仓市值
m_dFrozenCash float 冻结资金
m_dProfit float 当日盈亏
m_dFetchBalance float 可取资金
m_strAccountID str 资金账号
m_strBrokerID str 服务机构代码

Position 对象

持仓信息对象,通过 ContextInfo.get_position()ContextInfo.get_positions() 获取。

字段 类型 说明
m_strStockCode str 品种代码
m_nVolume int 持仓数量
m_nCanUseVolume int 可用数量
m_nFrozenVolume int 冻结数量
m_dOpenPrice float 持仓成本价
m_dProfit float 持仓盈亏
m_dMarketValue float 持仓市值
m_dProfitRatio float 盈亏比例

Order 对象

委托信息对象,通过 ContextInfo.get_orders()order_callback 获取。

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型(1=买, 2=卖)
m_nVolume int 委托数量
m_dPrice float 委托价格
m_nOrderStatus int 委托状态
m_strOrderSysID str 委托编号
m_nTradedVolume int 已成交数量
m_dTradedAmount float 已成交金额
m_strErrorInfo str 错误信息

枚举常量

委托类型 (orderType)

说明
1 买入
2 卖出

价格类型 (priceType)

说明
0 最优五档即时成交剩撤销
5 最优价
11 限价单
12 最新价
14 市价

委托状态 (orderStatus)

说明
50 委托已提交
55 委托已确认
56 部分成交
57 全部成交
58 已撤销
59 部分撤销

周期代码 (period)

说明
1d 日线
1m 1 分钟
5m 5 分钟
15m 15 分钟
30m 30 分钟
60m 60 分钟
tick Tick

复权类型

说明
0 不复权
1 前复权
2 后复权

回调函数

函数名 触发时机 参数
init(ContextInfo) 策略启动时 ContextInfo
handlebar(ContextInfo) 每根 K 线 ContextInfo
order_callback(ContextInfo, order_info) 委托状态变化 ContextInfo, Order
deal_callback(ContextInfo, deal_info) 成交回报 ContextInfo, DealInfo
before_init(ContextInfo) init 之前 ContextInfo
after_init(ContextInfo) init 之后 ContextInfo

DealInfo 对象

成交回报信息对象,通过 deal_callback 获取。

字段 类型 说明
m_strStockCode str 品种代码
m_nOrderType int 委托类型
m_nVolume int 成交数量
m_dPrice float 成交价格
m_strTradeID str 成交编号
m_strOrderSysID str 关联委托编号
m_dAmount float 成交金额
m_dCommission float 手续费

常见问题

Python环境相关

安装第三方 Python 库报错

问题描述:

"ImportError:Forbidden:Moduleopenpyxl not in whitelist!"

问题解答:

该报错是由于券商后台开启了 Python 库白名单,若您使用的是券商提供的QMT终端,请联系您的所属券商开通对应 Python 库白名单权限即可。

启动策略时pandas库报错

报错信息1 :NameError: name 'pandas' is not defined

解答:

该报错是指当前环境下没有找到pandas库

解决方法

  1. 请在设置-模型设置中检查正确设置了路径,正确路径应指向{安装目录}\bin.x64
正确路径参考
正确路径参考
  1. 请检查是否已经下载了python环境
下载python环境
下载python环境

报错信息2 :AttributeError: module 'pandas' has no attribute 'core'

解答:

该报错是由于在pandas导入中被强行中断导致的

解决方法

重启客户端

对第三方库的支持

QMT Python API 提供基于 Python 3.6 规范的标准量化投资策略应用程序接口,本文档示例代码基于 Python 3.6 规范。我司主要通过以下两种方式对外提供:

系统自带的 Python 环境

QMT 系统的安装包默认自带 Python 运行环境。用户安装完迅投客户端后,默认可以直接使用Python。在这个打包的Python环境中,迅投除了提供标准的 Python api 带的库外,还集成了如下一些第三方库:

名称 说明
NumPy NumPy (Numeric Python) 提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库。专为进行严格的数字处理而产生。
Pandas Python Data Analysis Library 或 Pandas 是基于 NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。Pandas 提供了大量能使我们快速便捷地处理数据的函数和方法。
Patsy 一个线性模型分析和构建工具库。
SciPy SciPy 函数库在 NumPy 库的基础上增加了众多的数学、科学以及工程计算中常用的库函数。例如线性代数、常微分方程数值求解、信号处理、图像处理、稀疏矩阵等等。
Statsmodels Python 的统计建模和计量经济学工具包,包括一些描述统计、统计模型估计和推断。
TA_Lib 称作技术分析库,是一种广泛用在程序化交易中进行金融市场数据的技术分析的函数库。它提供了多种技术分析的函数,可以大大方便我们量化投资中编程工作,内容包括:多种指标,如 ADX, MACD, RSI, 布林轨道等;K 线形态识别,如黄昏之星,锤形线等等。

第三方库导入指引

除迅投提供的标准 Python api 和集成的部分第三方库,用户也可自己在 Python 官网下载其他所需第三方库,使用方式如下:

(1)本地安装Python环境,下载python3.6,Python官网:https://www.python.org/downloads/release/python-360/

(2)安装位置:C:\Python36

​ 新增环境变量:我的电脑--属性--高级系统设置--高级--环境变量---path:C:\Python36;C:\Python36\Scripts

wps1
wps1

(3)Python环境检查

​ Win+R 打开运行,输入 cmd

wps2
wps2

​ 检查Python变量

(4)安装第三方库

​ 安装前先确认客户端安装目录,根据个人电脑进行调整。

​ 安装时若遇到下面错误提示,请执行 pip 更新命令 python -m pip install --upgrade pip

image-20210318151342044
image-20210318151342044

​ 安装三方库命令 pip install openpyxl -t E:\QMT交易端20962\bin.x64\Lib\site-packages

image-20210318151401916
image-20210318151401916

(5)检查安装结果

​ 安装位置\bin.x64\Lib\site-packages检查安装库

image-20210318151523278
image-20210318151523278

业务规则相关

交易所委托数量规则

  1. 科创板,连续交易时段限价单笔最大是10万股,市价单笔最大是5万股,盘后定价交易单笔最大量是100万股,200股起,1股递增。
  2. 创业板,连续交易时段限价单笔最大30万股,市价单笔最大15万股,100股起,100股递增。
  3. 主板,6和0开头的,连续交易时段单笔最大100万股,100股起,100股递增。

策略运行相关

在策略没有勾选终端启动后自动运行的情况下,策略自动启动运行

情况一

策略被运行于行情界面的副图上,随客户端启动被启动

解决方法

在右上角的页面布局中选择恢复默认布局,并重启客户端

恢复默认布局
恢复默认布局

情况二

交易日切换/行情断线重连时,所有挂着的模型会被重新运行,这是正常的

策略回测相关

QMT在回测时如何选择复权方式

解答

回测是为了更贴近历史数据,但实际中各类配股、增发的动作,会造成价格的异常波动,为了避免这样的波动对回测的影响,我们推荐用户在回测中使用等比前复权价,这样在回测过程中,无需考虑配股、增发带来的变化,始终以统一标准的价格进行买卖,方便的同时也能得到更贴合历史数据的回测收益和表现。

交易相关

系统对象 ContextInfo 逐 k 线保存的机制

机制说明

ContextInfo是由底层维护并传递给inithandlebar等系统函数的参数,同一个 bar(不是 bar 里面的 tick,下同)内ContextInfo本质上是同一个变量且对其进行的修改只会对本次handlebar调用的下文所起作用。handlebar里对ContextInfo做的修改在该 bar 结束后才会进行保存,也就是说,对ContextInfo做的修改会在下一个 bar 体现出来。

具体来说,ContextInfo不同于一般 python 对象,做了逐 k 线更新设计,盘中主图品种每个 Level 1 分笔到达会触发handlebar函数调用,但只有 k 线结束时最后一个分笔触发的handlebar调用,对ContextInfo的修改才有效。

每次handlebar函数调用前会对ContextInfo对象进行深拷贝, 下一次分笔行情到来时,如果新的分笔不是新 k 线 bar 第一个分笔,则判断上一个分笔不是k线最后分笔,ContextInfo对象被回退为之前深拷贝的那个。

ContextInfo对象逐k线更新机制设计的目的,是为了在盘中时模拟k线的效果,只在k线结束的分笔触发的handlebar函数运行时生效一次,丢弃所有其他分笔的修改。

影响

该机制有两个影响,一是在ContextInfo对象中存数据每次分笔到达时会被深拷贝,拖慢策略运行;二是ContextInfo适用于记录逐k线生效的交易信号(quickTrade参数传0),不适宜立刻下单的情况。

如不需要模拟k线效果,希望调用交易函数后立刻下单,quickTrade参数可以传2, 下单记录可以用普通的全局变量保存, 不能存在ContextInfo对象的属性里(实现可以参考实盘示例7-调整至目标持仓Demo)。

快速交易参数 quickTrade

下单函数passorder有可选参数快速交易quickTrade, 默认为0

  • 0,只在k线结束分笔时调用passorder产生有效信号,其他情况调用不产生信号。
  • 1,在当前k线为最新k线时调用passorder函数产生有效信号, 历史k线调用不产生信号。
  • 2,任何情况下调用passorder都产生有效信号,不会丢弃任何一次调用的信号。
  • 如果在定时器注册的回调函数,行情回调函数, after_init函数中调用下单函数,需要传2,确保不会漏单。
  • passorder以外的下单函数不能指定快速交易参数,效果与传0passorder一致。

下单与回报相关

  1. 为保证以尽快的速度执行交易信号, qmt 客户端提供的交易接口是异步的, 以快速交易参数填2passorder函数为例,调用后会立刻发出委托, 然后返回。不会等待委托回报, 也不会阻塞python线程的运行。
  2. 委托/成交/持仓/账号信息的更新, 是在客户端后台进行的, python策略中无法手动控制。python提供的取账号信息接口 get_trade_detail_data, 与四种交易回调函数, 都是从客户端本地缓存中读取数据 / 触发调用,不是调用时查询柜台再返回。客户端本地缓存状态定期接收柜台推送刷新,有交易主推的柜台50ms一次,没有交易主推的柜台1-6秒一次。 不能认为get_trade_detail_data查到的状态是与柜台完全一致的, 比如卖出委托后立刻查询, 不会查到对应委托, 可用资金也不会变多。
  3. 实盘策略需要设计盘中保存/更新委托状态的机制。常见的做法是用全局变量字典保存委托状态, 给每一笔委托独立的投资备注作为字典的key,委托状态作为字典的value, 下单后默认设置为待报, 之后查到委托后更新状态。如果某品种股票存在待报状态委托, 暂停该品种后续报单, 防止发生超单的情况。(实现可以参考实盘示例7-调整至目标持仓Demo)
  4. QMT 所有策略是在同一个线程中被调用的,任意一个策略阻塞线程(死循环 sleep 加锁等操作)会导致所有策略的执行被阻塞,所以不能在策略里写等待操作。如需要多线程 / 多进程的用法,可以使用极简模式配合 xtquant 库使用

QMT 下单失败

  1. 检查是否是在模型交易界面,实盘模式运行的策略。模拟模式只显示策略信号,不发出委托。
  2. 如运行到交易函数,未看到策略信号,检查交易函数是否使用了快速下单参数(quickTrade),默认为0,只会在k线结束发出委托,日线及以上周期等于全天不会委托。传1时,非历史bar上执行时(ContextInfo.is_last_bar()为True),只要策略模型中调用到就触发下单交易。传2,无论是否是历史bar,运行到交易函数时立刻发出委托。

如果希望盘中出现信号立即下单,建议传1,这种情况下会有策略信号闪烁的风险,需要自己处理;如果希望K线结束下单(信号不闪烁),建议传0通常情况下不建议传2

提示

具体到场景:

  1. handlebar逐k线下单, 每次k线结束的分笔生效一次, 传0;
  2. 需要在handlebar盘中触发立刻下单, 传1;
  3. 定时器/init/after_init与交易回调函数, 行情回调函数内下单, 传2.
  1. 如看到实盘的策略信号,未找到对应委托,检查客户端左下角消息提示是否有报错,如有,请根据消息提示的描述修改下单参数

行情相关

QMT 行情数据基础概念

QMT行情数据主要分为三种,包括本地数据全推数据订阅数据

  1. 本地数据: 指下载到本地的行情数据加密文件。包括历史数据,适合回测模式使用,对应python接口为get_market_data_ex(subscribe=False) 在新窗口打开
  2. 全推数据: 指客户端启动后, 自动接收,更新的全市场最新数据快照, 包括日线的开高低收,成交量成交额,与五档盘口(在行情界面选择了五档行情时可用五档 具体见行情常规问题3)。支持取全市场品种, 只有最新值,没有历史值,服务器对交易所下发的数据即时转发,打包增量部分发送给下游客户端。可以用get_full_tick一次性取出当前最新值,也可以用subscribe_whole_quote注册回调函数,每次处理增量的部分。 对应python接口为get_full_tick在新窗口打开subscribe_whole_quote在新窗口打开
  3. 订阅:指向行情服务器订阅指定品种行情, 共有四种周期(分笔 1分钟 5分钟 日线),可以订阅当日数据,当天以前的需要用 down_history_data下. 订阅有最大数量限制(例如:假设最大数量限制为300个,则可以单独订阅日线300个,若同时订阅日线和五分钟 则各150个),如需订阅超过定义上限,可以在页面右上角,选购行情vip服务。对应python接口为subscribe_quote在新窗口打开get_market_data_ex(subscribe=True,)在新窗口打开其中,使用get_market_dataget_market_data_ex(subscribe=True,)时客户端会自动订阅传入的品种,不需要额外调用subscibe_quote,但这种方式订阅的品种没有订阅号,无法手动反订阅,只能通过停止策略释放可订阅数。
警告

如果超出订阅数量限制,则返回的行情数据会使用前值填充,出现重复值,非正确行情数据。

QMT 行情调用函数对比说明

  • down_history_data 下载指定区间的行情数据到本地,存放在硬盘上。效果和界面,点击行情数据下载一致。 开始时间不填时,为增量下载(以本地数据最后一天为开始时间), 填写的话按填写值下载。
  • get_local_data 取本地数据函数,盘中不会更新,速度快,回测可以用这个函数取。
  • get_full_tick 取客户端缓存中的最新全推数据。全推数据不包括历史,不用订阅,没有品种数量限制,盘中50ms更新一次,速度快。
  • subscribe_quote 向服务器订阅股票行情 盘中实时更新 初次订阅耗时长,最大订阅品种数受限. 订阅超过一定数量的品种k线行情不会更新.可订阅四种基本周期(分笔 一分钟 五分钟 日线)行情(如果有 Level-2 行情权限 也可以订 Level-2 的), 同一品种订阅了不同周期累加计数(如订阅浦发银行 1分钟 5分钟 日线行情 算订阅3次). 复数策略订阅同一品种计数不会累加. Level-2 的订阅也会受限,但是和 Level 1 的互不影响。
  • unsubscribe_quote 按订阅号反订阅行情, 释放可订阅数.
  • get_market_data_ex 取订阅/本地数据接口。用subscribe_quoteinit函数中先订阅后subscribe参数为True时,取本地数据和订阅的最新行情。subscribe参数传False时,可以用来取本地数据,不会订阅。 如股票池超过一定数量,可用 down_history_data + get_local_data + get_full_tick 拼接历史和最新数据替代get_market_data_ex
注意

gmd系列函数在init中运行时,只能读取到本地数据,不会取到最新行情数据,因子,不建议在init中调用使用gmd系列函数

警告

不再推荐使用!

set_universe, get_history_data, get_market_data 是早期订阅股票池, 取订阅的行情数据接口. 因为set_universe订阅的品种没有订阅号 无法在策略中反订阅, 只能通过停止策略释放订阅数。

全推接口和订阅接口的分笔行情没有5档行情,只有最新价

问题描述

get_full_tick, subscribe_while_quote函数中获取分笔行情没有5档行情,只有最新价。

解决办法

修改行情源对应的全推行情级别,见下图

image102
image102

或者

image101
image101

行情中心和交易中心到底有啥区别?

行情中心控制单支订阅,例如subscribe_quote

交易中心影响全推数据,例如get_full_tick,subscribe_whole_quote

passorder使用对手价下单报错/有误

问题描述

passorder参数prType填写14(对手价下单)时,委托价格有误,或信息提示对手价无效,无法下单!

解决办法

修改行情源对应的全推行情级别,见下图

或者

为什么在handlebar中获取期货tick时,tick是3S一个而非0.5s一个?

这是由于handlebar函数是逐K线驱动在新窗口打开的,在实时行情中,handlebar会随着主图标的tick的更新被调用

在这个问题场景中,主图的标的通常被设置为股票,而股票的tick通常是3s一个,这就导致handlebar函数3s才被调用一次

解决方法

  1. 使用定时器(run_time)在新窗口打开进行计算
  2. 使用订阅推送(subscribe)在新窗口打开,在回调函数中进行计算
  3. 如果需要在handlebar中进行期货策略编写,建议将主图设置为期货品种,来保证handlebar调用频率

为什么在非交易时间段handlebar也会被调用

handlebar受行情数据推送驱动,在非交易时段,行情服务会做一系列准备工作,其中可能伴随着服务重启,在重启后为了保证数据齐全,客户端会重新订阅数据,这时服务会推送最新的数据,客户端会把推送的最新数据更新至缓存,并向上层策略推送更新,也就是触发handlebar执行

这个合并数据的驱动执行只会在最新一根bar而不会在历史范围,策略可以根据需要处理这次推送或直接根据交易时间跳过这个驱动,例如判断time小于09:15则直接return

关于证券状态openint值的详细说明

沪市

时间段 状态 编码
9:15 - 9:25 盘前集合竞价 12
9:25 - 14:57 盘中连续竞价 13
14:57 - 15:00 盘后集合竞价 18
15:00 收盘状态 15
15:05 - 15:30 盘后定价 22
15:30 盘后定价结束 23
上一状态后 收盘状态 15

深市

时间段 状态 编码
9:15 - 9:25 盘前集合竞价 12
9:25 - 9:30 休市 14
9:30 - 11:30 盘中连续竞价 13
11:30 - 13:00 休市 14
13:00 - 14:57 盘中连续竞价 13
14:57 - 15:00 盘后集合竞价 18
15:00 发收盘状态 15
15:05 - 15:30 盘后定价 22
15:30 盘后定价结束 23
上一状态后 收盘状态 15

静态数据问题

报错:[系统]ERROR:******.**获取合约乘数和最小变动价位失败,跳过

点击右下角【行情】按钮,选择【智能下载】,数据选项下拉框勾选【过期合约列表】点击该面板右下角【开始】,待过期合约数据补充完毕后,即可正常获取过期合约数据。

软件运行日志相关

如何找到软件运行日志

Log文件通常在安装目录下的.\userdata\log文件夹中,在 .\userdata\log 文件夹中,你可能会看到一个或者多个 log 文件,通常以 '.log' 作为扩展名。这些文件将包含软件运行时的详细情况。

投研:{安装目录}\userdata\log

说明

XtClient_20210922.log - 客户端常规日志

XtClient_datasource_20210922.log - 行情数据日志

XtClient_Formula_20210922.log - 策略运行日志

XtClient_FormulaOutput.log - 策略输出日志

QMT:{安装目录}\userdata\log

说明

XtClient_20210922.log - 客户端常规日志

XtClient_Formula_20210922.log - 策略运行日志

XtClient_FormulaOutput.log - 策略输出日志

XtClient_PerformanceFile_20210922.log - 客户端流程节点日志

极简模式:{安装目录}\userdata_mini\log

说明

XtMiniQuote_20210917.log - 行情策略模块日志

XtMiniQmt_20210917.log - 客户端常规日志

XtMiniQmt_perform_20210917.log - 客户端流程节点日志

PTrade 快速开始

PTrade 是由券商提供的托管式 Python 策略平台。不同券商的入口、权限和界面可能不同,但策略通常按照“新建策略 → 编写代码 → 设置回测 → 检查结果 → 新建交易”的顺序使用。

第一次使用流程

  1. 从券商提供的入口进入 PTrade。
  2. 新建股票等对应业务类型的策略。
  3. 保留或编写 initialize(context)handle_data(context, data)
  4. 设置回测开始时间、结束时间、资金、基准和频率。
  5. 保存策略并开始回测。
  6. 查看收益曲线、评价指标、委托、成交、持仓和日志。
  7. 通过回测与模拟检查后,再决定是否新建交易任务。

最小策略结构

def initialize(context):
    log.info('INIT_OK')

def handle_data(context, data):
    log.info('HANDLE_DATA_OK')

成功标准

  • 初始化日志只在启动时出现一次。
  • handle_data 按所选日线或分钟频率触发。
  • 回测区间、基准、资金和频率与设置一致。
  • 日志没有未处理异常。

PTrade 客户端、权限与环境准备

PTrade 通常由券商提供,QuantX 不把某一家券商的开通条件写成平台通用规则。获取入口、支持业务、行情权限和交易权限应以实际服务机构为准。

开始前确认

  • 已获得券商提供的 PTrade 登录入口。
  • 能进入策略、回测和交易模块。
  • 已确认股票、两融、基金或期货等目标业务类型是否支持。
  • 已确认研究、回测、模拟和实盘所用账号环境。
  • 了解目标环境的 Python 版本和第三方库白名单。

权限不足的表现

权限或数据能力不足时,可能表现为模块不可见、接口返回空数据、Level2 或 Tick 数据不可用、交易任务无法创建。出现这些情况应先核对平台权限,再排查代码。

券商差异

运行时间、可用 API、行情等级、业务类型和柜台限制可能由券商配置。本文只描述本地官方 PTrade API 文档能够确认的通用能力。

PTrade 界面操作与第一次回测

新建策略

在策略模块点击新增,选择业务类型并填写策略名称。创建完成后,可以基于默认模板编写策略。

PTrade 新建策略入口与策略信息设置界面
新建策略:选择业务类型并设置策略名称。

设置回测

回测前至少设置:开始时间、结束时间、初始资金、回测基准和运行频率。日线回测通常每天触发一次,分钟回测按分钟 K 线触发。

PTrade 回测时间、资金、基准和频率设置界面
回测前核对时间范围、资金、基准与频率。

开始回测

  1. 保存策略。
  2. 核对业务类型和频率。
  3. 点击回测。
  4. 观察日志是否进入 initializehandle_data
  5. 查看评价指标、收益曲线、委托、成交与持仓。

结果验收

正收益不能单独证明策略正确。还应确认基准、费用、成交限制、运行频率、交易数量、实际持仓和无交易原因。

新建交易任务

回测与模拟验证完成后,可在交易模块新增任务,选择已经保存的策略并设置任务名称。创建前应再次确认账号、业务类型、交易权限和策略中的真实委托开关。

PTrade 新建交易任务并选择策略方案的界面
新增交易任务时选择已验证的策略方案。

交易运行后,先在任务列表核对总资产、可用资金与运行状态,再进入详情查看评价指标、交易明细、持仓明细和日志。

PTrade 交易任务状态、总资产和可用资金界面
交易任务列表用于确认资金与运行状态。
PTrade 交易详情中的评价指标、交易、持仓与日志界面
交易详情用于核对指标、成交、持仓与日志。

PTrade 策略生命周期与运行时间

PTrade 以事件驱动方式运行策略。initializehandle_data 是最基础的必选函数,盘前与盘后函数按需定义。

initialize

策略启动时执行一次,用于设置股票池、参数、基准、费用和全局状态。

before_trading_start

每个交易日盘前执行。为兼容不同券商环境,建议写成 before_trading_start(context, data=None)

handle_data

盘中按策略频率触发。日线和分钟频率的实际时间以券商配置及回测环境为准。

after_trading_end

盘后执行,适合汇总日志和保存状态。建议定义为 after_trading_end(context, data=None)

调用顺序

启动 → initialize → 每日盘前 → handle_data → 每日盘后

回调职责对照

回调 典型用途 不适合放入的工作
initialize 初始化参数、股票池、基准和状态 每日重复执行的行情判断
before_trading_start 盘前更新股票池、重置日内标记 假设盘中实时行情已经就绪
handle_data 按策略频率读取数据、计算信号和执行风控 无条件重复注册定时任务
after_trading_end 汇总当日订单、成交、持仓和日志 依赖下一交易日数据的判断

验证实际顺序

在每个回调中输出日期、时间和回调名,至少跨两个交易日运行。若某个回调没有出现,应先检查策略频率、回测区间和函数签名,再检查业务逻辑。

PTrade 策略生命周期、行情驱动、定时任务及回报事件关系图
PTrade 生命周期、行情驱动、定时任务与委托成交事件关系。

PTrade 代码约定、状态与持久化

全局状态

需要跨回调使用的状态通常放在全局对象 g 中,并在 initialize 里显式初始化。读写名称必须完全一致。

重启与持久化

模拟盘或实盘任务重启后,内存变量可能丢失。目标环境支持持久化时,应只保存可序列化对象,并验证恢复顺序。券商升级或环境重启时,框架可能先执行 initialize,再用持久化值覆盖同名状态。

异常处理

捕获异常时必须记录 API、证券、日期和错误信息。不要使用宽泛的 except Exception: continue 静默清空股票池或跳过全部交易。

平台边界

PTrade 使用 initialize(context)handle_data(context, data)order* 系列函数,不应混入其他策略平台的生命周期或下单接口。

PTrade 行情与证券数据

PTrade 常用历史行情接口包括 get_historyget_price。证券、指数成分、行业和基本面数据应使用 PTrade 官方接口及目标券商实际返回结构。

使用前检查

  • 明确研究、回测或交易环境。
  • 明确证券代码尾缀和市场格式。
  • 检查返回对象的列名、索引名和行数。
  • 多证券数据先记录实际形状,再编写因子计算。

常用接口

需求 首选接口 先确认什么
获取连续历史 K 线 get_history 频率、字段、条数和复权方式
按时间范围读取行情 get_price 起止时间、频率和返回结构
获取当前行情快照 get_snapshot 目标环境是否支持实时快照
获取指数成分股 get_index_stocks 指数代码与查询日期
查询财务数据 get_fundamentals 查询对象、字段和日期口径

新手应先用一个证券、一个字段和很短的时间范围验证返回值,再扩展到多证券。这样能先看清索引、列名和数据方向,避免把“结构理解错误”误判成策略逻辑错误。

最小验证方法

def handle_data(context, data):
    bars = get_history(5, '1d', 'close', security_list=['000001.XSHE'])
    log.info('type=%s shape=%s columns=%s' % (
        type(bars).__name__,
        getattr(bars, 'shape', None),
        list(getattr(bars, 'columns', []))
    ))

这段代码的目标不是产生信号,而是确认接口能调用、证券代码有效、频率受支持,并记录真实返回结构。

回测限制

不要默认在回测中使用实时快照接口。目标环境若不支持 get_snapshot,应改用历史行情或当前 Bar 数据,并记录功能降级。

空数据排查

依次检查证券代码、日期范围、频率、权限、停牌或上市时间、字段名称和返回结构。不得把空数据直接解释成“没有交易机会”。

完整行情函数

完整的行情、交易日、证券信息和历史数据函数统一收录在行情与历史数据函数目录。每个函数详情页包含调用签名、参数、返回值、示例和适用环境。

PTrade 策略设置、定时任务与频率

运行频率

PTrade 回测支持日线和分钟级别;交易环境还可能支持 Tick 级别。日线 handle_data 每个交易日运行一次,分钟级别按每根分钟 K 线结束触发。

run_daily

run_daily 用于安排自定义函数在指定交易时间执行。不要用它再次注册 before_trading_startafter_trading_end,这两个生命周期函数由框架自动调用。

run_interval

run_interval 属于交易环境能力,用于按间隔执行任务。不能因为 API 存在就假设回测支持。

选择方式

需求 推荐入口 适用说明
每根 Bar 计算一次 handle_data 与策略日线或分钟频率同步
每个交易日固定时点 run_daily 在初始化阶段注册一次
交易任务按间隔执行 run_interval 先核对目标交易环境支持情况
实时 Tick 处理 tick_data 依赖对应行情和交易环境

不要在 handle_data 内重复调用 run_dailyrun_interval 注册同一个任务,否则可能随 Bar 数量不断增加重复调度。

频率验收

日志应输出实际日期、时间和频率。策略含 09:40、14:55 等严格时点规则时,应使用能够表达该时点的分钟或交易环境,不应静默压缩成日线逻辑。

PTrade 交易、账户与持仓

PTrade 股票交易常用函数包括 orderorder_targetorder_valueorder_target_value。回测中的订单是模拟撮合,交易任务中的订单可能发送到柜台。

下单前检查

  • 交易开关是否明确开启。
  • 当前运行环境是否允许委托。
  • 证券代码和业务类型是否匹配。
  • 可用资金、持仓和可卖数量是否足够。
  • 是否存在同证券、同方向的重复委托。

常用下单函数

目标 首选函数 数量含义
买卖指定数量 order 本次增减的证券数量
调整到目标数量 order_target 调整后的目标持仓数量
按金额买卖 order_value 本次增减的资金金额
调整到目标市值 order_target_value 调整后的目标持仓市值
撤销未完成委托 cancel_order 传入订单标识或订单对象

数量型、金额型、目标型接口的语义不同。调用目标型接口前,应读取当前持仓;调用后应再次读取实际持仓,不能把“已调用函数”当作“已经成交”。

查询委托与成交

要查看的状态 接口
当前未完成委托 get_open_orders
委托记录 get_orders
成交记录 get_trades
当前持仓 get_positions

订单可能经历提交、受理、部分成交、全部成交、撤单或拒绝等状态。策略的去重和风控应以订单状态、成交回报和实际持仓共同判断。

目标仓位订单

调用 order_targetorder_target_value 后,应重新读取实际持仓并比较目标差额。返回订单编号或没有未完成订单,不等于目标仓位一定达到。

默认安全规则

可复用模板应默认关闭真实委托。只有明确确认账号、运行模式、风控和停止方案后,才允许打开交易开关。

完整交易函数

更多普通交易、ETF、两融、期货及专业业务接口见交易、委托与订单函数目录两融、期货与专业交易目录

PTrade 委托、成交与状态管理

订单调用、委托受理、部分成交、全部成交和撤单是不同状态。策略不能在调用下单函数后立即把目标视为已成交。

可用能力

PTrade 提供订单查询、成交查询以及可选的 on_order_responseon_trade_response 主推事件。具体可用性以目标券商环境为准。

状态管理原则

  • 为每次计划记录日期、证券、方向和目标。
  • 下单后保存订单标识,不重复提交同一动作。
  • 根据成交或刷新后的实际持仓更新状态。
  • 部分成交时记录目标、实际和剩余数量。
  • 超时、拒单和未知状态必须进入人工可见日志。

回测注意

最大成交比例和最小交易单位可能造成部分成交或零数量订单。必须用实际持仓验收,而不是只统计下单调用次数。

PTrade 完整示例与学习顺序

推荐顺序

  1. 最小生命周期示例:只输出 initializehandle_data 日志。
  2. 单证券行情示例:读取历史价格并打印返回结构。
  3. 信号示例:计算指标,同时记录无信号原因。
  4. 回测订单示例:使用受保护的订单函数验证委托路径。
  5. 目标仓位示例:下单后重新读取持仓并核对差额。

示例验收

每个示例都应说明运行环境、频率、证券、数据要求、是否可能产生订单以及成功日志。真实交易版本必须默认关闭订单开关。

平台边界

PTrade 示例只能使用 PTrade 生命周期和 API,不要混入其他策略平台的生命周期、行情或下单接口,也不要复制其他平台的基本面查询写法。

PTrade ETF、两融、期货与业务类型

PTrade 可支持股票、基金、融资融券和期货等业务,但回测与交易环境支持范围并不完全相同,且受券商权限影响。

使用前必须确认

  • 新建策略时选择的业务类型。
  • 账号是否开通对应业务与交易权限。
  • 委托数量单位是股、份还是手。
  • 最小交易单位、最小价差和保证金规则。
  • 所用 API 是否支持研究、回测或交易环境。

不可混用

股票普通委托、两融开平仓和期货开平仓具有不同语义。不能仅替换证券代码就把一种业务的策略迁移到另一种业务。

验收建议

先在目标业务类型的回测或仿真环境中,用最小数量验证代码、订单方向、单位、费用和状态回报,再考虑扩大范围。

PTrade 对象、枚举与 API 索引

生命周期

initializebefore_trading_starthandle_dataafter_trading_endon_order_responseon_trade_response

行情与证券

get_historyget_price、交易日、证券信息、指数成分、行业、状态和基本面相关接口。

交易与账户

orderorder_targetorder_valueorder_target_value、撤单、订单、成交、持仓和账户相关接口。

定时与运行

run_daily、交易环境的 run_interval,以及运行频率和业务类型查询。

每个函数页都应单独记录签名、参数、返回结构、可用环境、权限、最小示例、常见错误、来源与核验时间。不能仅凭函数名称推断与其他平台相同。

对象与工具

如果已经知道函数名称,优先使用页面顶部搜索框直接搜索;如果只知道任务,例如“获取历史行情”或“按目标市值下单”,先进入对应分类,再从常用函数开始。

PTrade 常见问题、权限与版本

策略没有日志

确认策略已保存并启动,包含 initializehandle_data,回测区间存在交易日,实际频率与预期一致。日志格式应先完成字符串插值再传给 log.info

行情返回为空

检查证券尾缀、日期、频率、权限和接口可用环境。多证券结果先记录列名、索引名和行数,避免把长表误当成宽表。

有信号但没有委托

记录每个风控条件、交易开关、资金、持仓、最小交易单位和下单返回值。不要把静默返回当作没有信号。

委托后没有达到目标仓位

检查最大成交比例、可用资金、最小手数、涨跌停、停牌和部分成交。下单后重新读取持仓,输出目标、实际和差额。

回测可用、交易不可用

核对实时行情、交易权限、账号、柜台状态和仅交易环境可用的 API。券商版本差异必须在目标环境中预检。

NameError 或函数不存在

先确认当前页面属于 PTrade,且函数名称、大小写和调用环境与详情页一致。不要把 QMT、PTrade 或其他平台的生命周期、行情、下单函数混在同一策略中。

定时任务重复执行

检查是否在 handle_data 中反复注册 run_dailyrun_interval。定时任务通常应在 initialize 中注册一次,并在日志中输出注册时间和实际触发时间。

排查信息最小集合

提交问题时至少保留:平台和券商环境、研究/回测/交易模式、策略频率、完整函数签名、证券代码、发生时间、完整错误文本、关键输入以及接口实际返回类型。只提供一句“没有交易”不足以定位问题。