QMT获取不到行情,一般是什么原因?或者获取行情有中断的情况

8-9成原因是 因为你选择的行情服务器掉线了

20231120204016.png

 
或者你获取的5档tick行情,但是你的行情菜单那里,选择的是 最新价,这样你也是无法获取到 5档tick数据的。

20240929102328.png

 
然后还有一个问题,如果你用get_market_data 或者get_market_data_ex 这个函数,获取的股票数量很多(比如全市场的股票),那么第一次的启动数据会非常的慢,并且你的内存消耗非常大,整个QMT像死机了一样。
 
如何解决? 下回分解
 
继续阅读 »
8-9成原因是 因为你选择的行情服务器掉线了

20231120204016.png

 
或者你获取的5档tick行情,但是你的行情菜单那里,选择的是 最新价,这样你也是无法获取到 5档tick数据的。

20240929102328.png

 
然后还有一个问题,如果你用get_market_data 或者get_market_data_ex 这个函数,获取的股票数量很多(比如全市场的股票),那么第一次的启动数据会非常的慢,并且你的内存消耗非常大,整个QMT像死机了一样。
 
如何解决? 下回分解
 
收起阅读 »

QMT的handlebar设置成一分钟周期的时候,运行是3秒一次的

QMT
平时很少用handlebar驱动。
 
刚好有个策略是一分钟周期运行的,所以就用了handle驱动。

20240913113955.png

 
 
结果发现,经常查询重复买入。
 
调试后发现,原来这个handlebar是3m触发一次的。
 
如果要一分钟运行一次,还是用
ContextInfo.run_time("execution", INTERVAL_STRING, running_time)
 
INTERVAL_STRING 用1分钟表示。
 
示例代码:
一分钟打印当前时间:
 
# -*-coding:gbk-*-
# 作者公众号:可转债量化分析
import datetime
import json
import redis

####### 以下为固定配置,请勿随意修改 ##########
# 注意:程序需要在9:30前启动

START_TIME = '09:30' # 启动时间,可以修改为开盘任意时间9:30-14:57
STOCK_ACCOUNT = '' # 股票账户


INTERVAL_SECOND = 60 # 交易间隔
INTERVAL_STRING = "{}nSecond".format(INTERVAL_SECOND)

def today_date():
return datetime.datetime.now().strftime('%Y%m%d')


def init(ContextInfo):
now = datetime.datetime.now()
print('策略初始化 {}'.format(now))
now = datetime.datetime.now()
running_time = '{} {}'.format(today_date(), START_TIME)
print('策略初始化 {} , 程序启动时间 {}'.format(now, START_TIME))
ContextInfo.run_time("execution", INTERVAL_STRING, running_time)



def handlebar(ContextInfo):
pass

def execution(ContextInfo):
if not ContextInfo.is_last_bar():
return
now = datetime.datetime.now()
print(now)


公众号:
继续阅读 »
平时很少用handlebar驱动。
 
刚好有个策略是一分钟周期运行的,所以就用了handle驱动。

20240913113955.png

 
 
结果发现,经常查询重复买入。
 
调试后发现,原来这个handlebar是3m触发一次的。
 
如果要一分钟运行一次,还是用
ContextInfo.run_time("execution", INTERVAL_STRING, running_time)
 
INTERVAL_STRING 用1分钟表示。
 
示例代码:
一分钟打印当前时间:
 
# -*-coding:gbk-*-
# 作者公众号:可转债量化分析
import datetime
import json
import redis

####### 以下为固定配置,请勿随意修改 ##########
# 注意:程序需要在9:30前启动

START_TIME = '09:30' # 启动时间,可以修改为开盘任意时间9:30-14:57
STOCK_ACCOUNT = '' # 股票账户


INTERVAL_SECOND = 60 # 交易间隔
INTERVAL_STRING = "{}nSecond".format(INTERVAL_SECOND)

def today_date():
return datetime.datetime.now().strftime('%Y%m%d')


def init(ContextInfo):
now = datetime.datetime.now()
print('策略初始化 {}'.format(now))
now = datetime.datetime.now()
running_time = '{} {}'.format(today_date(), START_TIME)
print('策略初始化 {} , 程序启动时间 {}'.format(now, START_TIME))
ContextInfo.run_time("execution", INTERVAL_STRING, running_time)



def handlebar(ContextInfo):
pass

def execution(ContextInfo):
if not ContextInfo.is_last_bar():
return
now = datetime.datetime.now()
print(now)


公众号:
收起阅读 »

QMT/iQuant居然禁止redis获取股票行情数据,如何破解

QMT禁止redis获取股票行情数据,如何破解

因为QMT没有转债的规模,而国信iquant本身又把requests 库给封禁了,它无法通过requests 获取任何外部数据,比如访问东财,tushare都会提示访问超时。(后面发现它修改了requests的源码)

于是发现iquant的redis是内置库,不需要pip安装,所以第一时间就想到使用redis获取转债数据。

简单测试了一下,redis是可以获取数据的。比如随便丢一个字符到redis,然后QMT可以获取到这个字符数据

于是就把原来的策略里,使用requests 调用API的部分,改成redis。

可是运行后发现报错:


微信图片_20240910103921.jpg


2024-09-10 10:05:19,851 [INFO] [0x00000e24] [msg service] msg: 0C:\iquant\python\新建策略文件.py_SH00030021

DataError:Sensitive Data Detected, Forbidden!

报错信息说的很明显,敏感信息检测到,禁止!

居然对redis的数据进行检验,很明显这部分是QMT对redis的源码进行了修改。

于是根据报错的提示,找到 目录:

D:\tool\gjzq_qmt_simulation\bin.x64\Lib\site-packages\redis,下面的client.py

找到对应的行:


微信图片_20240910103929.png



的确有一个check_response 的函数用于检测 redis的内容,看正则表达式和变量命名(search_stock),类似股票代码的数据传输被阻止了,检测到之后直接raise Error,程序会停止的。

解决办法,也很简单,直接把这一段 代码删除就好了。

然后需要重启你的QMT,不然修改的代码不会生效。

然后重新运行的你的策略,发现一起正常了。
 
需要开通QMT和代写量化策略,可以关注公众号:
继续阅读 »
QMT禁止redis获取股票行情数据,如何破解

因为QMT没有转债的规模,而国信iquant本身又把requests 库给封禁了,它无法通过requests 获取任何外部数据,比如访问东财,tushare都会提示访问超时。(后面发现它修改了requests的源码)

于是发现iquant的redis是内置库,不需要pip安装,所以第一时间就想到使用redis获取转债数据。

简单测试了一下,redis是可以获取数据的。比如随便丢一个字符到redis,然后QMT可以获取到这个字符数据

于是就把原来的策略里,使用requests 调用API的部分,改成redis。

可是运行后发现报错:


微信图片_20240910103921.jpg


2024-09-10 10:05:19,851 [INFO] [0x00000e24] [msg service] msg: 0C:\iquant\python\新建策略文件.py_SH00030021

DataError:Sensitive Data Detected, Forbidden!

报错信息说的很明显,敏感信息检测到,禁止!

居然对redis的数据进行检验,很明显这部分是QMT对redis的源码进行了修改。

于是根据报错的提示,找到 目录:

D:\tool\gjzq_qmt_simulation\bin.x64\Lib\site-packages\redis,下面的client.py

找到对应的行:


微信图片_20240910103929.png



的确有一个check_response 的函数用于检测 redis的内容,看正则表达式和变量命名(search_stock),类似股票代码的数据传输被阻止了,检测到之后直接raise Error,程序会停止的。

解决办法,也很简单,直接把这一段 代码删除就好了。

然后需要重启你的QMT,不然修改的代码不会生效。

然后重新运行的你的策略,发现一起正常了。
 
需要开通QMT和代写量化策略,可以关注公众号:
收起阅读 »

国信iquant requests 爬虫 获取数据 还有使用 tushare,akshare 无法连接,提示超时

经过验证,比如把下面的代码放入到国信的iquant里运行
#encoding:gbk


import requests

def get_baidu():

url = 'https://www.baidu.com'
req = requests.get(url,headers={'User-Agent':'Mozilla/5.0'})
print(req.text)

def init(ContextInfo):
get_baidu()

def handlebar(ContextInfo):
pass

会报错,同时访问baidu.com 超时:

微信图片_20240828141957.png

 
明显是国信的iquant内部设置了proxy,导致request出去的时候走了proxy。
 
所以连baidu都访问不了。
 
而tushare,akshare底层是周的爬虫 (requests), 所以对于iquant,底层走http requests的库,或者获取数据的手段是失效了的。
 
不过也有其他的手段可以实现获取外部数据。
 
笔者亲测了redis可以访问外部的redis数据库,为啥用redis,因为iquant没有内置pymysql,需要自己安装,客户也不懂怎么安装,(到iquant的安装文件路径下的python 包路径下,运行 pip install pymysq)
 
而iquant内置了redis 的库,所以可以直接import redis
 
redis测试代码:
def base_usage():
print('start')
r = RedisCls()
data = {'name': 'zhangsan', 'age': 18}
key = 'test_key'
r.push(key, json.dumps(data))
print('push')
print(r.delete('key')) # reutrn 1 if delete success, else return 0
start_time = time.time()
ret_data = r.pop(key)
end_time = time.time()
print('cost time: ', end_time - start_time)
print(ret_data)



base_usage()

上面的代码是正常运行,不报错,就说明正常的了。
PS: 
r = RedisCls() 只是封装了
r = redis.Redis 连接的ip和端口,密码 而已。
 
按照网上的redis连接教程使用就好了。
 

 
继续阅读 »
经过验证,比如把下面的代码放入到国信的iquant里运行
#encoding:gbk


import requests

def get_baidu():

url = 'https://www.baidu.com'
req = requests.get(url,headers={'User-Agent':'Mozilla/5.0'})
print(req.text)

def init(ContextInfo):
get_baidu()

def handlebar(ContextInfo):
pass

会报错,同时访问baidu.com 超时:

微信图片_20240828141957.png

 
明显是国信的iquant内部设置了proxy,导致request出去的时候走了proxy。
 
所以连baidu都访问不了。
 
而tushare,akshare底层是周的爬虫 (requests), 所以对于iquant,底层走http requests的库,或者获取数据的手段是失效了的。
 
不过也有其他的手段可以实现获取外部数据。
 
笔者亲测了redis可以访问外部的redis数据库,为啥用redis,因为iquant没有内置pymysql,需要自己安装,客户也不懂怎么安装,(到iquant的安装文件路径下的python 包路径下,运行 pip install pymysq)
 
而iquant内置了redis 的库,所以可以直接import redis
 
redis测试代码:
def base_usage():
print('start')
r = RedisCls()
data = {'name': 'zhangsan', 'age': 18}
key = 'test_key'
r.push(key, json.dumps(data))
print('push')
print(r.delete('key')) # reutrn 1 if delete success, else return 0
start_time = time.time()
ret_data = r.pop(key)
end_time = time.time()
print('cost time: ', end_time - start_time)
print(ret_data)



base_usage()

上面的代码是正常运行,不报错,就说明正常的了。
PS: 
r = RedisCls() 只是封装了
r = redis.Redis 连接的ip和端口,密码 而已。
 
按照网上的redis连接教程使用就好了。
 

  收起阅读 »

QMT如何获取持仓成本 盈亏比例

QMT
比如多次买入一个股票,每次买入不同的数量,如果中间又有分红除权,虽然可以通过自己写一个计算函数记录,但是会非常复杂。
 
那么QMT有没有内置的可以获取持仓成本的函数呢?
 
 position 持仓对象 里面有一个字段:
 
m_dOpenPrice: 持仓成本
 
可以用来获取当前的持仓成本:
 
具体代码如下:
 
# encoding:gbk

ACCOUNT = 'xxxxxxx' # 填入你的QMT账户ID, 如果没有,可以联系我开通 QMT权限


def init(ContextInfo):
# hs300成分股中sh和sz市场各自流通市值最大的前3只股票
pass


def handlebar(ContextInfo):
# 计算当前主图的cci
position_info = get_trade_detail_data(ACCOUNT, 'stock', 'position')
for i in position_info:
print('股票', i.m_strInstrumentID, '持仓数',
i.m_nVolume, '持有成本', round(i.m_dOpenPrice, 2),
'持仓盈亏', round(i.m_dPositionProfit, 2),
'持仓盈亏比例', round(i.m_dProfitRate*100, 2)
)


 得到的输出结果:
 

20240825081954.png

 
扫码免费开通QMT:

 
继续阅读 »
比如多次买入一个股票,每次买入不同的数量,如果中间又有分红除权,虽然可以通过自己写一个计算函数记录,但是会非常复杂。
 
那么QMT有没有内置的可以获取持仓成本的函数呢?
 
 position 持仓对象 里面有一个字段:
 
m_dOpenPrice: 持仓成本
 
可以用来获取当前的持仓成本:
 
具体代码如下:
 
# encoding:gbk

ACCOUNT = 'xxxxxxx' # 填入你的QMT账户ID, 如果没有,可以联系我开通 QMT权限


def init(ContextInfo):
# hs300成分股中sh和sz市场各自流通市值最大的前3只股票
pass


def handlebar(ContextInfo):
# 计算当前主图的cci
position_info = get_trade_detail_data(ACCOUNT, 'stock', 'position')
for i in position_info:
print('股票', i.m_strInstrumentID, '持仓数',
i.m_nVolume, '持有成本', round(i.m_dOpenPrice, 2),
'持仓盈亏', round(i.m_dPositionProfit, 2),
'持仓盈亏比例', round(i.m_dProfitRate*100, 2)
)


 得到的输出结果:
 

20240825081954.png

 
扫码免费开通QMT:

  收起阅读 »

QMT获取持仓信息报错:AttributeError: 'NoneType' object has no attribute 'request_id'

QMT
这个是新手经常遇到的问题。读取持仓信息的时候报错:
代码如下:
 
 
原因就是不能init之前去读取
# encoding:gbk
'''
实盘可以执行
固定数量
'''
import datetime


ACCOUNT = ''


def init(ContextInfo):
ContextInfo.set_account(ACCOUNT)


def get_position_infos():
# 信用账户可用资金
position_infos = get_trade_detail_data(ACCOUNT, 'stock', 'position')


pos_dict={}
for pos in position_infos:
code = pos.m_strInstrumentID
if pos.m_nVolume > 0:
pos_dict[code] = pos.m_nVolume
return pos_dict

datax = get_position_infos() # 这里error

def handlebar(ContextInfo):
if ContextInfo.is_last_bar():
current = datetime.datetime.now().strftime('%H:%M:%S.%f')
print(datax)


datax = get_position_infos()  #这里error
这个函数再最开始的时候就被定义了。没有经过initial初始话函数,很多数据没有获取,从而导致的报错。
 欢迎关注交流

 
继续阅读 »
这个是新手经常遇到的问题。读取持仓信息的时候报错:
代码如下:
 
 
原因就是不能init之前去读取
# encoding:gbk
'''
实盘可以执行
固定数量
'''
import datetime


ACCOUNT = ''


def init(ContextInfo):
ContextInfo.set_account(ACCOUNT)


def get_position_infos():
# 信用账户可用资金
position_infos = get_trade_detail_data(ACCOUNT, 'stock', 'position')


pos_dict={}
for pos in position_infos:
code = pos.m_strInstrumentID
if pos.m_nVolume > 0:
pos_dict[code] = pos.m_nVolume
return pos_dict

datax = get_position_infos() # 这里error

def handlebar(ContextInfo):
if ContextInfo.is_last_bar():
current = datetime.datetime.now().strftime('%H:%M:%S.%f')
print(datax)


datax = get_position_infos()  #这里error
这个函数再最开始的时候就被定义了。没有经过initial初始话函数,很多数据没有获取,从而导致的报错。
 欢迎关注交流

  收起阅读 »

QMT股票两融对冲建仓实盘

QMT
为了避免速度过快造成价格波动,提供速度,数量,延时控制。

20240529111758.png

 
成交了多少量,就融券多少量。达到指标即可停止。
 
代写量化程序,可以关注公众号,后台联系。 价格比QMT官网低的多了。实战性选手,选过N多QMT,ptrade实盘代码。
 
继续阅读 »
为了避免速度过快造成价格波动,提供速度,数量,延时控制。

20240529111758.png

 
成交了多少量,就融券多少量。达到指标即可停止。
 
代写量化程序,可以关注公众号,后台联系。 价格比QMT官网低的多了。实战性选手,选过N多QMT,ptrade实盘代码。
 
收起阅读 »

迅投官网的实例代码好多问题,惨不忍睹

QMT

20240512165205.png

以前喜欢用C替代ContextInfo,现在改过去了,又有部分改的不完整。
 
还有更多的缩进的问题。
 

20240512165415.png

 
pep8的规范早已经不用tab来做缩进,而是用4个空格。
 
之前的文章里面也提到了,可以在qmt的配置文件里面改的。不过在UI上是不提供修改的地方。
http://www.30daydo.com/article/44602
 
继续阅读 »

20240512165205.png

以前喜欢用C替代ContextInfo,现在改过去了,又有部分改的不完整。
 
还有更多的缩进的问题。
 

20240512165415.png

 
pep8的规范早已经不用tab来做缩进,而是用4个空格。
 
之前的文章里面也提到了,可以在qmt的配置文件里面改的。不过在UI上是不提供修改的地方。
http://www.30daydo.com/article/44602
  收起阅读 »

QMT里定时任务运行时间操作定时任务的间隔,会怎么样?

QMT
代码很简单,就是在run_time这个定期运行的任务里面,定期1秒执行一次任务
 

20240506101947.png



当时任务运行时间超过1秒钟,比如上面的代码里面用time.sleep(3) 模拟这个超时,等待3秒。

在tick 实盘模式下运行,输出什么的?

答案如下:


20240506101516.png



每次的start和end之间间隔了3秒钟,然后下一次的start和上一次start的间隔也是在3秒钟,也就是当然时刻的定时任务没有执行完成,下一个时刻的定时任务不会被执行。

那么有人会要求,不想要被运行时间长的任务阻碍了当前的任务,要怎么操作呢? 最简单的方式,加一个多线程就好了。

稍微改动一下上面的代码:

20240506101043.png



把要执行的任务,写成一个函数,然后使用threading.Thread去执行这个函数, t.star() 就是启动任务。


20240506101030.png



执行结果如上图,每次的start 间隔只有1秒,当时end是要等待3秒之后才打印出来。但end的输出不会阻塞当前的start输出,start稳定地1秒间隔输出一次,end也在当前start的3秒之后打印出来。
 
 
继续阅读 »
代码很简单,就是在run_time这个定期运行的任务里面,定期1秒执行一次任务
 

20240506101947.png



当时任务运行时间超过1秒钟,比如上面的代码里面用time.sleep(3) 模拟这个超时,等待3秒。

在tick 实盘模式下运行,输出什么的?

答案如下:


20240506101516.png



每次的start和end之间间隔了3秒钟,然后下一次的start和上一次start的间隔也是在3秒钟,也就是当然时刻的定时任务没有执行完成,下一个时刻的定时任务不会被执行。

那么有人会要求,不想要被运行时间长的任务阻碍了当前的任务,要怎么操作呢? 最简单的方式,加一个多线程就好了。

稍微改动一下上面的代码:

20240506101043.png



把要执行的任务,写成一个函数,然后使用threading.Thread去执行这个函数, t.star() 就是启动任务。


20240506101030.png



执行结果如上图,每次的start 间隔只有1秒,当时end是要等待3秒之后才打印出来。但end的输出不会阻塞当前的start输出,start稳定地1秒间隔输出一次,end也在当前start的3秒之后打印出来。
 
  收起阅读 »

使用量化程序获取ETF的成分股与实时净值

QMT
代码只有几行:
# coding:gbk
def init(C):
pass

def handlebar(C):
iopv = get_etf_iopv("159928.SZ")
print(f'基金净值为{iopv}')
info = get_etf_info('513520.SH')
print(f'基金申购信息: {info}')

得到的数据如下:

20240411122042.png

 
需要开通低门槛量化QMT的朋友,可以扫码关注公众号开通:
继续阅读 »
代码只有几行:
# coding:gbk
def init(C):
pass

def handlebar(C):
iopv = get_etf_iopv("159928.SZ")
print(f'基金净值为{iopv}')
info = get_etf_info('513520.SH')
print(f'基金申购信息: {info}')

得到的数据如下:

20240411122042.png

 
需要开通低门槛量化QMT的朋友,可以扫码关注公众号开通:
收起阅读 »

QMT回测会跳过当前的周六日和节假日吗

QMT
使用的handle_bar进行回测,它是会自动跳过周六日和节假日的。
比如回测日期选择 2024年3月28日到2024年4月2日。
其中3月30日和31日是周六日。
下面回测的数据是不执行这两天的数据。从3月30日 15:00的数据,下一个bar就是4月1日09:30了
20240409130951.png

需要低门槛开通量化QMT,Ptrade,可以扫码联系。
开通后可加入技术交流群。
继续阅读 »
使用的handle_bar进行回测,它是会自动跳过周六日和节假日的。
比如回测日期选择 2024年3月28日到2024年4月2日。
其中3月30日和31日是周六日。
下面回测的数据是不执行这两天的数据。从3月30日 15:00的数据,下一个bar就是4月1日09:30了
20240409130951.png

需要低门槛开通量化QMT,Ptrade,可以扫码联系。
开通后可加入技术交流群。
收起阅读 »

qmt下载完数据之后,记得重启一次qmt,不然get_market_data_ex依然还是获取不到数据的

QMT
最近群里问这个问题的人比较多。
 
qmt下载完数据之后,get_market_data_ex依然还是获取不到数据。
 
其实主要数据没有刷新。
 
只需要你手动关闭QMT,再打开一次就好了。
 

20240401133759.png

 
反正呢,这些问题,QMT也不会告诉你,要靠自己摸索了。
 
欢迎收藏网站哦!
继续阅读 »
最近群里问这个问题的人比较多。
 
qmt下载完数据之后,get_market_data_ex依然还是获取不到数据。
 
其实主要数据没有刷新。
 
只需要你手动关闭QMT,再打开一次就好了。
 

20240401133759.png

 
反正呢,这些问题,QMT也不会告诉你,要靠自己摸索了。
 
欢迎收藏网站哦! 收起阅读 »

QMT每次自动升级,都会把改过的配置文件给覆盖掉

QMT
太业余。
感觉设计模式有问题。
 
本来我配置了缩进用的4个空格,(这是pep8的标准好吧)
而qmt默认是用tab做缩进。
 
导致从vs code或者pycharm上的代码迁移迁移过来qmt的编辑器,你按tab键,是制表符,而不是4个空格。
 
运行或者回测就会报错。

20240331004.png

 
每次升级都把我的配置给改了。
 
难道不覆盖config文件不行吗? 每次类似全量升级,一点点bug fix都在全量升级
 
继续阅读 »
太业余。
感觉设计模式有问题。
 
本来我配置了缩进用的4个空格,(这是pep8的标准好吧)
而qmt默认是用tab做缩进。
 
导致从vs code或者pycharm上的代码迁移迁移过来qmt的编辑器,你按tab键,是制表符,而不是4个空格。
 
运行或者回测就会报错。

20240331004.png

 
每次升级都把我的配置给改了。
 
难道不覆盖config文件不行吗? 每次类似全量升级,一点点bug fix都在全量升级
  收起阅读 »

不同券商的数据质量简单对比:国金QMT vs 国信QMT(iquant)

同一段代码,先在国信上跑回测,先获取可转债的1分钟的分笔数据,发现一些时间段里的成交额居然是0. (数据已经先下载好了)

点击打开大图
20240331002.png


上面的amount字段(成交额),返回的是0。

看了一下对应的转债,没有停牌,是有正常数据交易的。

然后用国金的QMT记性交叉验证。同样的代码
点击打开大图
20240331001.png

 
国金的是正常的。只是成交量的小数浮点位是不是有点多了? 可能用的numy的默认9位,没有做处理而已。

【在写这个文章的时候发现国信的qmt的volume成交量是有数据的,那么其实可以用价格x成交量=成交额,间接获取成交额,大坑】

点击打开大图
20240331003.png

 
附测试源码:
 
# coding:gbk
# 公众号:可转债量化分析
DEBUG = True
import time
def get_datetime(ContextInfo):
# 获取当前时间
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
if DEBUG:
print('当前日期 ', date)
return date

def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2024-03-27 10:00:00'
ContextInfo.end = '2024-03-29 10:00:00'
#
#ContextInfo.end = '2023-01-05'
#ContextInfo.start = '2023-01-16'
print('init')

def handlebar(ContextInfo):
# 回测的时候不需要
#if not ContextInfo.is_last_bar():
# print('return')
# return
get_datetime(ContextInfo)
print('handlebar')
data = ContextInfo.get_market_data(['quoter'], stock_code = ['123167.SZ'], skip_paused = True, period = 'tick', dividend_type = 'front')

#data = ContextInfo.get_market_data(['close'], stock_code = ['113567.SH'], skip_paused = True, period = '1d', dividend_type = 'front')
#print(type(data))
print(data)

def stop(ContextInfo):
print( 'strategy is stop !')

继续阅读 »
同一段代码,先在国信上跑回测,先获取可转债的1分钟的分笔数据,发现一些时间段里的成交额居然是0. (数据已经先下载好了)

点击打开大图
20240331002.png


上面的amount字段(成交额),返回的是0。

看了一下对应的转债,没有停牌,是有正常数据交易的。

然后用国金的QMT记性交叉验证。同样的代码
点击打开大图
20240331001.png

 
国金的是正常的。只是成交量的小数浮点位是不是有点多了? 可能用的numy的默认9位,没有做处理而已。

【在写这个文章的时候发现国信的qmt的volume成交量是有数据的,那么其实可以用价格x成交量=成交额,间接获取成交额,大坑】

点击打开大图
20240331003.png

 
附测试源码:
 
# coding:gbk
# 公众号:可转债量化分析
DEBUG = True
import time
def get_datetime(ContextInfo):
# 获取当前时间
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
if DEBUG:
print('当前日期 ', date)
return date

def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2024-03-27 10:00:00'
ContextInfo.end = '2024-03-29 10:00:00'
#
#ContextInfo.end = '2023-01-05'
#ContextInfo.start = '2023-01-16'
print('init')

def handlebar(ContextInfo):
# 回测的时候不需要
#if not ContextInfo.is_last_bar():
# print('return')
# return
get_datetime(ContextInfo)
print('handlebar')
data = ContextInfo.get_market_data(['quoter'], stock_code = ['123167.SZ'], skip_paused = True, period = 'tick', dividend_type = 'front')

#data = ContextInfo.get_market_data(['close'], stock_code = ['113567.SH'], skip_paused = True, period = '1d', dividend_type = 'front')
#print(type(data))
print(data)

def stop(ContextInfo):
print( 'strategy is stop !')

收起阅读 »

miniQMT安装包路径 | 下载地址

QMT
安装好QMT之后,在QMT的设置里面选择安装python。
 
等待几分钟,python文件下载好了之后。
 
找到qmt的安装目录,
 
进去这里面
 
\bin.x64\Lib\site-packages\xtquant
 
把这个目录复制到你的python路径的site-package 下面, 就可以在你的python环境下运行miniQMT了。
 
当然首先还是要启动你的QMT客户端,勾选极速模式。 (不开的话连不到券商服务器,这以为这无法再linux上单独跑,wine额外另说)
 
比如下面的获取行情的示例代码,还有直接下单代码
 
# 用前须知

## xtdata提供和MiniQmt的交互接口,本质是和MiniQmt建立连接,由MiniQmt处理行情数据请求,再把结果回传返回到python层。使用的行情服务器以及能获取到的行情数据和MiniQmt是一致的,要检查数据或者切换连接时直接操作MiniQmt即可。

## 对于数据获取接口,使用时需要先确保MiniQmt已有所需要的数据,如果不足可以通过补充数据接口补充,再调用数据获取接口获取。

## 对于订阅接口,直接设置数据回调,数据到来时会由回调返回。订阅接收到的数据一般会保存下来,同种数据不需要再单独补充。

# 代码讲解

# 从本地python导入xtquant库,如果出现报错则说明安装失败
from xtquant import xtdata
import time

# 设定一个标的列表
code_list = ["000001.SZ"]
# 设定获取数据的周期
period = "1d"

# 下载标的行情数据
if 1:
## 为了方便用户进行数据管理,xtquant的大部分历史数据都是以压缩形式存储在本地的
## 比如行情数据,需要通过download_history_data下载,财务数据需要通过
## 所以在取历史数据之前,我们需要调用数据下载接口,将数据下载到本地
for i in code_list:
xtdata.download_history_data(i,period=period,incrementally=True) # 增量下载行情数据(开高低收,等等)到本地

xtdata.download_financial_data(code_list) # 下载财务数据到本地
xtdata.download_sector_data() # 下载板块数据到本地
# 更多数据的下载方式可以通过数据字典查询

# 读取本地历史行情数据
history_data = xtdata.get_market_data_ex(,code_list,period=period,count=-1)
print(history_data)
print("=" * 20)

# 如果需要盘中的实时行情,需要向服务器进行订阅后才能获取
# 订阅后,get_market_data函数于get_market_data_ex函数将会自动拼接本地历史行情与服务器实时行情

# 向服务器订阅数据
for i in code_list:
xtdata.subscribe_quote(i,period=period,count=-1) # 设置count = -1来取到当天所有实时行情

# 等待订阅完成
time.sleep(1)

# 获取订阅后的行情
kline_data = xtdata.get_market_data_ex(,code_list,period=period)
print(kline_data)

# 获取订阅后的行情,并以固定间隔进行刷新,预期会循环打印10次
for i in range(10):
# 这边做演示,就用for来循环了,实际使用中可以用while True
kline_data = xtdata.get_market_data_ex(,code_list,period=period)
print(kline_data)
time.sleep(3) # 三秒后再次获取行情

# 如果不想用固定间隔触发,可以以用订阅后的回调来执行
# 这种模式下当订阅的callback回调函数将会异步的执行,每当订阅的标的tick发生变化更新,callback回调函数就会被调用一次
# 本地已有的数据不会触发callback

# 定义的回测函数
## 回调函数中,data是本次触发回调的数据,只有一条
def f(data):
# print(data)

code_list = list(data.keys()) # 获取到本次触发的标的代码

kline_in_callabck = xtdata.get_market_data_ex(,code_list,period = period) # 在回调中获取klines数据
print(kline_in_callabck)

for i in code_list:
xtdata.subscribe_quote(i,period=period,count=-1,callback=f) # 订阅时设定回调函数

# 使用回调时,必须要同时使用xtdata.run()来阻塞程序,否则程序运行到最后一行就直接结束退出了。
xtdata.run()





 
异步下单
#coding:utf-8
import time, datetime, traceback, sys
from xtquant import xtdata
from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
from xtquant.xttype import StockAccount
from xtquant import xtconstant

#定义一个类 创建类的实例 作为状态的容器
class _a():
pass
A = _a()
A.bought_list =
A.hsa = xtdata.get_stock_list_in_sector('沪深A股')

def interact():
"""执行后进入repl模式"""
import code
code.InteractiveConsole(locals=globals()).interact()
xtdata.download_sector_data()

def f(data):
now = datetime.datetime.now()
for stock in data:
if stock not in A.hsa:
continue
cuurent_price = data[stock]['lastPrice']
pre_price = data[stock]['lastClose']
ratio = cuurent_price / pre_price - 1 if pre_price > 0 else 0
if ratio > 0.09 and stock not in A.bought_list:
print(f"{now} 最新价 买入 {stock} 200股")
async_seq = xt_trader.order_stock_async(acc, stock, xtconstant.STOCK_BUY, 200, xtconstant.LATEST_PRICE, -1, 'strategy_name', stock)
A.bought_list.append(stock)

class MyXtQuantTraderCallback(XtQuantTraderCallback):
def on_disconnected(self):
"""
连接断开
:return:
"""
print(datetime.datetime.now(),'连接断开回调')

def on_stock_order(self, order):
"""
委托回报推送
:param order: XtOrder对象
:return:
"""
print(datetime.datetime.now(), '委托回调', order.order_remark)


def on_stock_trade(self, trade):
"""
成交变动推送
:param trade: XtTrade对象
:return:
"""
print(datetime.datetime.now(), '成交回调', trade.order_remark)


def on_order_error(self, order_error):
"""
委托失败推送
:param order_error:XtOrderError 对象
:return:
"""
# print("on order_error callback")
# print(order_error.order_id, order_error.error_id, order_error.error_msg)
print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")

def on_cancel_error(self, cancel_error):
"""
撤单失败推送
:param cancel_error: XtCancelError 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)

def on_order_stock_async_response(self, response):
"""
异步下单回报推送
:param response: XtOrderResponse 对象
:return:
"""
print(f"异步委托回调 {response.order_remark}")

def on_cancel_order_stock_async_response(self, response):
"""
:param response: XtCancelOrderResponse 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)

def on_account_status(self, status):
"""
:param response: XtAccountStatus 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)


if __name__ == '__main__':
print("start")
#指定客户端所在路径
path = r'D:\qmt\sp3\迅投极速交易终端 睿智融科版\userdata_mini'
# 生成session id 整数类型 同时运行的策略不能重复
session_id = int(time.time())
xt_trader = XtQuantTrader(path, session_id)
# 开启主动请求接口的专用线程 开启后在on_stock_xxx回调函数里调用XtQuantTrader.query_xxx函数不会卡住回调线程,但是查询和推送的数据在时序上会变得不确定
# 详见: http://docs.thinktrader.net/vip/pages/ee0e9b/#开启主动请求接口的专用线程
# xt_trader.set_relaxed_response_order_enabled(True)

# 创建资金账号为 800068 的证券账号对象
acc = StockAccount('800068', 'STOCK')
# 创建交易回调类对象,并声明接收回调
callback = MyXtQuantTraderCallback()
xt_trader.register_callback(callback)
# 启动交易线程
xt_trader.start()
# 建立交易连接,返回0表示连接成功
connect_result = xt_trader.connect()
print('建立交易连接,返回0表示连接成功', connect_result)
# 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
subscribe_result = xt_trader.subscribe(acc)
print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)

#这一行是注册全推回调函数 包括下单判断 安全起见处于注释状态 确认理解效果后再放开
# xtdata.subscribe_whole_quote(["SH", "SZ"], callback=f)
# 阻塞主线程退出
xt_trader.run_forever()
# 如果使用vscode pycharm等本地编辑器 可以进入交互模式 方便调试 (把上一行的run_forever注释掉 否则不会执行到这里)
interact()


需要开通miniQMT(低门槛,低费率)的朋友,
可以扫码联系:或者添加 技术公众号:

 
公众号:
 

 
 
继续阅读 »
安装好QMT之后,在QMT的设置里面选择安装python。
 
等待几分钟,python文件下载好了之后。
 
找到qmt的安装目录,
 
进去这里面
 
\bin.x64\Lib\site-packages\xtquant
 
把这个目录复制到你的python路径的site-package 下面, 就可以在你的python环境下运行miniQMT了。
 
当然首先还是要启动你的QMT客户端,勾选极速模式。 (不开的话连不到券商服务器,这以为这无法再linux上单独跑,wine额外另说)
 
比如下面的获取行情的示例代码,还有直接下单代码
 
# 用前须知

## xtdata提供和MiniQmt的交互接口,本质是和MiniQmt建立连接,由MiniQmt处理行情数据请求,再把结果回传返回到python层。使用的行情服务器以及能获取到的行情数据和MiniQmt是一致的,要检查数据或者切换连接时直接操作MiniQmt即可。

## 对于数据获取接口,使用时需要先确保MiniQmt已有所需要的数据,如果不足可以通过补充数据接口补充,再调用数据获取接口获取。

## 对于订阅接口,直接设置数据回调,数据到来时会由回调返回。订阅接收到的数据一般会保存下来,同种数据不需要再单独补充。

# 代码讲解

# 从本地python导入xtquant库,如果出现报错则说明安装失败
from xtquant import xtdata
import time

# 设定一个标的列表
code_list = ["000001.SZ"]
# 设定获取数据的周期
period = "1d"

# 下载标的行情数据
if 1:
## 为了方便用户进行数据管理,xtquant的大部分历史数据都是以压缩形式存储在本地的
## 比如行情数据,需要通过download_history_data下载,财务数据需要通过
## 所以在取历史数据之前,我们需要调用数据下载接口,将数据下载到本地
for i in code_list:
xtdata.download_history_data(i,period=period,incrementally=True) # 增量下载行情数据(开高低收,等等)到本地

xtdata.download_financial_data(code_list) # 下载财务数据到本地
xtdata.download_sector_data() # 下载板块数据到本地
# 更多数据的下载方式可以通过数据字典查询

# 读取本地历史行情数据
history_data = xtdata.get_market_data_ex(,code_list,period=period,count=-1)
print(history_data)
print("=" * 20)

# 如果需要盘中的实时行情,需要向服务器进行订阅后才能获取
# 订阅后,get_market_data函数于get_market_data_ex函数将会自动拼接本地历史行情与服务器实时行情

# 向服务器订阅数据
for i in code_list:
xtdata.subscribe_quote(i,period=period,count=-1) # 设置count = -1来取到当天所有实时行情

# 等待订阅完成
time.sleep(1)

# 获取订阅后的行情
kline_data = xtdata.get_market_data_ex(,code_list,period=period)
print(kline_data)

# 获取订阅后的行情,并以固定间隔进行刷新,预期会循环打印10次
for i in range(10):
# 这边做演示,就用for来循环了,实际使用中可以用while True
kline_data = xtdata.get_market_data_ex(,code_list,period=period)
print(kline_data)
time.sleep(3) # 三秒后再次获取行情

# 如果不想用固定间隔触发,可以以用订阅后的回调来执行
# 这种模式下当订阅的callback回调函数将会异步的执行,每当订阅的标的tick发生变化更新,callback回调函数就会被调用一次
# 本地已有的数据不会触发callback

# 定义的回测函数
## 回调函数中,data是本次触发回调的数据,只有一条
def f(data):
# print(data)

code_list = list(data.keys()) # 获取到本次触发的标的代码

kline_in_callabck = xtdata.get_market_data_ex(,code_list,period = period) # 在回调中获取klines数据
print(kline_in_callabck)

for i in code_list:
xtdata.subscribe_quote(i,period=period,count=-1,callback=f) # 订阅时设定回调函数

# 使用回调时,必须要同时使用xtdata.run()来阻塞程序,否则程序运行到最后一行就直接结束退出了。
xtdata.run()





 
异步下单
#coding:utf-8
import time, datetime, traceback, sys
from xtquant import xtdata
from xtquant.xttrader import XtQuantTrader, XtQuantTraderCallback
from xtquant.xttype import StockAccount
from xtquant import xtconstant

#定义一个类 创建类的实例 作为状态的容器
class _a():
pass
A = _a()
A.bought_list =
A.hsa = xtdata.get_stock_list_in_sector('沪深A股')

def interact():
"""执行后进入repl模式"""
import code
code.InteractiveConsole(locals=globals()).interact()
xtdata.download_sector_data()

def f(data):
now = datetime.datetime.now()
for stock in data:
if stock not in A.hsa:
continue
cuurent_price = data[stock]['lastPrice']
pre_price = data[stock]['lastClose']
ratio = cuurent_price / pre_price - 1 if pre_price > 0 else 0
if ratio > 0.09 and stock not in A.bought_list:
print(f"{now} 最新价 买入 {stock} 200股")
async_seq = xt_trader.order_stock_async(acc, stock, xtconstant.STOCK_BUY, 200, xtconstant.LATEST_PRICE, -1, 'strategy_name', stock)
A.bought_list.append(stock)

class MyXtQuantTraderCallback(XtQuantTraderCallback):
def on_disconnected(self):
"""
连接断开
:return:
"""
print(datetime.datetime.now(),'连接断开回调')

def on_stock_order(self, order):
"""
委托回报推送
:param order: XtOrder对象
:return:
"""
print(datetime.datetime.now(), '委托回调', order.order_remark)


def on_stock_trade(self, trade):
"""
成交变动推送
:param trade: XtTrade对象
:return:
"""
print(datetime.datetime.now(), '成交回调', trade.order_remark)


def on_order_error(self, order_error):
"""
委托失败推送
:param order_error:XtOrderError 对象
:return:
"""
# print("on order_error callback")
# print(order_error.order_id, order_error.error_id, order_error.error_msg)
print(f"委托报错回调 {order_error.order_remark} {order_error.error_msg}")

def on_cancel_error(self, cancel_error):
"""
撤单失败推送
:param cancel_error: XtCancelError 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)

def on_order_stock_async_response(self, response):
"""
异步下单回报推送
:param response: XtOrderResponse 对象
:return:
"""
print(f"异步委托回调 {response.order_remark}")

def on_cancel_order_stock_async_response(self, response):
"""
:param response: XtCancelOrderResponse 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)

def on_account_status(self, status):
"""
:param response: XtAccountStatus 对象
:return:
"""
print(datetime.datetime.now(), sys._getframe().f_code.co_name)


if __name__ == '__main__':
print("start")
#指定客户端所在路径
path = r'D:\qmt\sp3\迅投极速交易终端 睿智融科版\userdata_mini'
# 生成session id 整数类型 同时运行的策略不能重复
session_id = int(time.time())
xt_trader = XtQuantTrader(path, session_id)
# 开启主动请求接口的专用线程 开启后在on_stock_xxx回调函数里调用XtQuantTrader.query_xxx函数不会卡住回调线程,但是查询和推送的数据在时序上会变得不确定
# 详见: http://docs.thinktrader.net/vip/pages/ee0e9b/#开启主动请求接口的专用线程
# xt_trader.set_relaxed_response_order_enabled(True)

# 创建资金账号为 800068 的证券账号对象
acc = StockAccount('800068', 'STOCK')
# 创建交易回调类对象,并声明接收回调
callback = MyXtQuantTraderCallback()
xt_trader.register_callback(callback)
# 启动交易线程
xt_trader.start()
# 建立交易连接,返回0表示连接成功
connect_result = xt_trader.connect()
print('建立交易连接,返回0表示连接成功', connect_result)
# 对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功
subscribe_result = xt_trader.subscribe(acc)
print('对交易回调进行订阅,订阅后可以收到交易主推,返回0表示订阅成功', subscribe_result)

#这一行是注册全推回调函数 包括下单判断 安全起见处于注释状态 确认理解效果后再放开
# xtdata.subscribe_whole_quote(["SH", "SZ"], callback=f)
# 阻塞主线程退出
xt_trader.run_forever()
# 如果使用vscode pycharm等本地编辑器 可以进入交互模式 方便调试 (把上一行的run_forever注释掉 否则不会执行到这里)
interact()


需要开通miniQMT(低门槛,低费率)的朋友,
可以扫码联系:或者添加 技术公众号:

 
公众号:
 

 
  收起阅读 »

QMT获取全市场股票,排除ST退市风险股票

QMT
因为QMT不能获取北交所的股票历史数据,所以需要把获取到的所有股票数据里的  北交所的股票排除掉 。
 
def get_all_market_code(ContextInfo):

all_market_codes = [item for item in ContextInfo.get_stock_list_in_sector('沪深A股') if not item.endswith('BJ')]
return filter_ST_stock(ContextInfo, all_market_codes)


def filter_ST_stock(ContextInfo, code_list):
result =
for code in code_list:
if re.search('(st)|(ST)|(\*st)|(\*ST)|(退)',ContextInfo.get_stock_name(code)):
print('排除 : ',ContextInfo.get_stock_name(code),code)
continue
result.append(code)
return result

global_dict = {}

def init(ContextInfo):
now = time.ctime()
print('策略初始化{}'.format(now))
need_download = 1
global_dict['start_date'] = '20231201'
global_dict['end_date'] = ''
global_dict['code_list'] = get_all_market_code(ContextInfo)

 有问题可以咨询公众号或者知识星球
提供策略代写服务
 
继续阅读 »
因为QMT不能获取北交所的股票历史数据,所以需要把获取到的所有股票数据里的  北交所的股票排除掉 。
 
def get_all_market_code(ContextInfo):

all_market_codes = [item for item in ContextInfo.get_stock_list_in_sector('沪深A股') if not item.endswith('BJ')]
return filter_ST_stock(ContextInfo, all_market_codes)


def filter_ST_stock(ContextInfo, code_list):
result =
for code in code_list:
if re.search('(st)|(ST)|(\*st)|(\*ST)|(退)',ContextInfo.get_stock_name(code)):
print('排除 : ',ContextInfo.get_stock_name(code),code)
continue
result.append(code)
return result

global_dict = {}

def init(ContextInfo):
now = time.ctime()
print('策略初始化{}'.format(now))
need_download = 1
global_dict['start_date'] = '20231201'
global_dict['end_date'] = ''
global_dict['code_list'] = get_all_market_code(ContextInfo)

 有问题可以咨询公众号或者知识星球
提供策略代写服务
 
收起阅读 »

QMT实时获取涨停股,筛选流通盘大于X的股票

QMT
基于官方例子修复了一下bug,比如移除了北交所的股票,因为目前qmt获取不了北交所的股票历史数据。
 
直接上代码:
# coding:gbk
import time


class G():
pass


g = G()


def init(ContextInfo):
g.hsa = [item for item in ContextInfo.get_stock_list_in_sector('沪深A股') if not item.endswith('BJ')]
g.vol_dict = {}
for stock in g.hsa:
g.vol_dict[stock] = ContextInfo.get_last_volume(stock)
ContextInfo.run_time("execution", "1nSecond", "2019-10-14 13:20:00")


def execution(ContextInfo):
t0 = time.time()
full_tick = ContextInfo.get_full_tick(g.hsa)
total_market_value = 0
total_ratio = 0
count = 0
for stock in g.hsa:
if full_tick[stock]['lastClose'] == 0:
continue
ratio = full_tick[stock]['lastPrice'] / full_tick[stock]['lastClose'] - 1
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} {ContextInfo.get_stock_name(stock)}")

market_value = full_tick[stock]['lastPrice'] * g.vol_dict[stock]
total_ratio += ratio * market_value
total_market_value += market_value
count += 1
# print(count)
total_ratio /= total_market_value
total_ratio *= 100
print(f'A股加权涨幅 {round(total_ratio, 2)}% 函数运行耗时{round(time.time() - t0, 5)}秒')


20240207182920.png

 
欢迎关注公众号:
可转债量化分析
继续阅读 »
基于官方例子修复了一下bug,比如移除了北交所的股票,因为目前qmt获取不了北交所的股票历史数据。
 
直接上代码:
# coding:gbk
import time


class G():
pass


g = G()


def init(ContextInfo):
g.hsa = [item for item in ContextInfo.get_stock_list_in_sector('沪深A股') if not item.endswith('BJ')]
g.vol_dict = {}
for stock in g.hsa:
g.vol_dict[stock] = ContextInfo.get_last_volume(stock)
ContextInfo.run_time("execution", "1nSecond", "2019-10-14 13:20:00")


def execution(ContextInfo):
t0 = time.time()
full_tick = ContextInfo.get_full_tick(g.hsa)
total_market_value = 0
total_ratio = 0
count = 0
for stock in g.hsa:
if full_tick[stock]['lastClose'] == 0:
continue
ratio = full_tick[stock]['lastPrice'] / full_tick[stock]['lastClose'] - 1
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} {ContextInfo.get_stock_name(stock)}")

market_value = full_tick[stock]['lastPrice'] * g.vol_dict[stock]
total_ratio += ratio * market_value
total_market_value += market_value
count += 1
# print(count)
total_ratio /= total_market_value
total_ratio *= 100
print(f'A股加权涨幅 {round(total_ratio, 2)}% 函数运行耗时{round(time.time() - t0, 5)}秒')


20240207182920.png

 
欢迎关注公众号:
可转债量化分析
收起阅读 »

迅投QMT投研版 有必要开吗?

QMT
没必要。
处处透出一股割韭菜的味道。
 
到处拉人进群,然后群里问问题,他们会让你私聊,加你,说服你开通投研版。
 
投研版无非多一些数据,你用tushare或者自己爬虫就可以获取,他们非要放到投研版里面,付费使用。
 
价格是一年8,9千,感觉没有一点性价比。
 
qmt,minniqmt有交易功能,有数据获取功能,也可以自己接入外部数据。没必要花那些冤枉钱去按年付费买一个不实用的数据。
真的没有数据,或者没有能力获取,付费找人写个api接口,爬虫数据,也不贵。 可以终身使用。 不好过按年付费???
 
关键那群qmt的人水平也不咋地,看他们的文档就知道,变量用A,B,C,D,人品也不咋地,星球上还抄袭我的星球文章,足以说明水平和人品。

Screenshot_2024_0206_150138.jpg

 
群里问点问题,就让你开个投研版咨询哈。 还不如来我的qmt ptrade技术群的,free且有求必应哈。
 
继续阅读 »
没必要。
处处透出一股割韭菜的味道。
 
到处拉人进群,然后群里问问题,他们会让你私聊,加你,说服你开通投研版。
 
投研版无非多一些数据,你用tushare或者自己爬虫就可以获取,他们非要放到投研版里面,付费使用。
 
价格是一年8,9千,感觉没有一点性价比。
 
qmt,minniqmt有交易功能,有数据获取功能,也可以自己接入外部数据。没必要花那些冤枉钱去按年付费买一个不实用的数据。
真的没有数据,或者没有能力获取,付费找人写个api接口,爬虫数据,也不贵。 可以终身使用。 不好过按年付费???
 
关键那群qmt的人水平也不咋地,看他们的文档就知道,变量用A,B,C,D,人品也不咋地,星球上还抄袭我的星球文章,足以说明水平和人品。

Screenshot_2024_0206_150138.jpg

 
群里问点问题,就让你开个投研版咨询哈。 还不如来我的qmt ptrade技术群的,free且有求必应哈。
  收起阅读 »

qmt获取北交所实时行情数据

QMT
之前没有试过用qmt交易北交所的股票,后面闻了一下券商,他们说是qmt支持北交所股票交易。
 
首先试试获取实时的行情:
我获取的是这个北交所股票的数据:

20240124132926.png


获取北交所行情数据如下:
 
#-*-coding:gbk-*-
import datetime
code = '838402.BJ'
def init(ContextInfo):
now = datetime.datetime.now()
print(now)

def handlebar(ContextInfo):
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
info = ContextInfo.get_full_tick(stock_code=["838402.BJ"])
print(info)

返回下面的数据:

20240124132856.png

 
对了下时间戳,是正确的。
 
然后试了下获取北交所的历史数据行情:
#-*-coding:gbk-*-
import datetime

code = '838402.BJ'
def init(ContextInfo):
now = datetime.datetime.now()
print(now)
download_history_data(code,"1d","20240105","")

def handlebar(ContextInfo):
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
print(date)
hist = ContextInfo.get_market_data_ex(['close'],[code], period = "1d",count = 1)
print(hist)

代码里面我想用 download_history_data(code,"1d","20240105","") 下载历史数据。
在数据目录里面也能够获取到这个股票的历史数据文件。
 
可是在qmt里面却输出的是个空的dataframe。

20240124133450.png


数据目录下面是有数据的。。
20240124133533.png

感觉是qmt里面的功能还没有完善对北交所股票的支持。
 
继续阅读 »
之前没有试过用qmt交易北交所的股票,后面闻了一下券商,他们说是qmt支持北交所股票交易。
 
首先试试获取实时的行情:
我获取的是这个北交所股票的数据:

20240124132926.png


获取北交所行情数据如下:
 
#-*-coding:gbk-*-
import datetime
code = '838402.BJ'
def init(ContextInfo):
now = datetime.datetime.now()
print(now)

def handlebar(ContextInfo):
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
info = ContextInfo.get_full_tick(stock_code=["838402.BJ"])
print(info)

返回下面的数据:

20240124132856.png

 
对了下时间戳,是正确的。
 
然后试了下获取北交所的历史数据行情:
#-*-coding:gbk-*-
import datetime

code = '838402.BJ'
def init(ContextInfo):
now = datetime.datetime.now()
print(now)
download_history_data(code,"1d","20240105","")

def handlebar(ContextInfo):
index = ContextInfo.barpos
realtime = ContextInfo.get_bar_timetag(index)
date = timetag_to_datetime(realtime, "%Y-%m-%d %H:%M:%S")
print(date)
hist = ContextInfo.get_market_data_ex(['close'],[code], period = "1d",count = 1)
print(hist)

代码里面我想用 download_history_data(code,"1d","20240105","") 下载历史数据。
在数据目录里面也能够获取到这个股票的历史数据文件。
 
可是在qmt里面却输出的是个空的dataframe。

20240124133450.png


数据目录下面是有数据的。。
20240124133533.png

感觉是qmt里面的功能还没有完善对北交所股票的支持。
  收起阅读 »

迅投官网的示例代码真的无眼看。。。

QMT
20231110001.jpg

如果拿去做code review,估计会被喷的体无完肤。
 
变量名,类名用A ,B,C 噗, 没有一点含义,做什么鬼
 
class a():
pass
A = a()
而且也不符合python风格。。。python类名推荐的大写字母开头,实例化对象用小写字母。
所以退一万步讲,上面的代码正常点的程序员写也应该是这样的。
 
class A():
pass
a = A()

  
其实正确的应该
class GlobalCls():
pass

g = GlobalCls()

其他地方也是有这个毛病。
把代码喂给GPT,让它来分析一下:
得到如下结果:
文件编码声明: #coding:gbk 是指定源文件的编码格式为GBK。在Python 3中,通常使用UTF-8作为文件编码格式,因此可以将该行删除或更改为#coding:utf-8。

类名和函数名: 根据PEP 8命名约定,类名应该使用大写字母开头的驼峰命名法(例如A改为A)。同样,函数名应该使用小写字母开头的小写命名法(例如init改为init,f改为f)。

类和实例: 在代码中定义了一个空类a,但没有给它任何属性或方法。如果不需要这个类,可以将其删除。

缩进和代码格式: Python非常依赖于正确的缩进,以指示代码块的层次结构。请确保代码的缩进是一致的,并使用适当的缩进级别(通常是4个空格)。

代码注释: 代码中有一些注释,但是大部分是被注释掉的。良好的注释可以增加代码的可读性和可维护性,建议在关键部分添加更多有用的注释。

异常处理: 代码中没有包含任何异常处理机制。在实际应用中,建议对可能引发异常的操作进行适当的异常处理,以提高代码的健壮性。

 
然后里面计算涨停是这样的:
		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)


用昨收价* 1.2和1.1判断当前是否涨跌停。 首先,没有考虑到ST股,部分ST是5%涨停的。 
其次,是直接用的昨收价,如果当天是分红除权日,昨收价没有做除权处理,得到的涨跌幅也是不准的。
 
当然这个文档最大的问题是,很多示例代码运行是直接报错的!!
 

 
继续阅读 »
20231110001.jpg

如果拿去做code review,估计会被喷的体无完肤。
 
变量名,类名用A ,B,C 噗, 没有一点含义,做什么鬼
 
class a():
pass
A = a()
而且也不符合python风格。。。python类名推荐的大写字母开头,实例化对象用小写字母。
所以退一万步讲,上面的代码正常点的程序员写也应该是这样的。
 
class A():
pass
a = A()

  
其实正确的应该
class GlobalCls():
pass

g = GlobalCls()

其他地方也是有这个毛病。
把代码喂给GPT,让它来分析一下:
得到如下结果:
文件编码声明: #coding:gbk 是指定源文件的编码格式为GBK。在Python 3中,通常使用UTF-8作为文件编码格式,因此可以将该行删除或更改为#coding:utf-8。

类名和函数名: 根据PEP 8命名约定,类名应该使用大写字母开头的驼峰命名法(例如A改为A)。同样,函数名应该使用小写字母开头的小写命名法(例如init改为init,f改为f)。

类和实例: 在代码中定义了一个空类a,但没有给它任何属性或方法。如果不需要这个类,可以将其删除。

缩进和代码格式: Python非常依赖于正确的缩进,以指示代码块的层次结构。请确保代码的缩进是一致的,并使用适当的缩进级别(通常是4个空格)。

代码注释: 代码中有一些注释,但是大部分是被注释掉的。良好的注释可以增加代码的可读性和可维护性,建议在关键部分添加更多有用的注释。

异常处理: 代码中没有包含任何异常处理机制。在实际应用中,建议对可能引发异常的操作进行适当的异常处理,以提高代码的健壮性。

 
然后里面计算涨停是这样的:
		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)


用昨收价* 1.2和1.1判断当前是否涨跌停。 首先,没有考虑到ST股,部分ST是5%涨停的。 
其次,是直接用的昨收价,如果当天是分红除权日,昨收价没有做除权处理,得到的涨跌幅也是不准的。
 
当然这个文档最大的问题是,很多示例代码运行是直接报错的!!
 

  收起阅读 »

QMT获取A股全市场股票代码

QMT
QMT可以通过板块获取A股的全市场股票代码.
 
"沪深A股"
 
完整代码:
#-*-coding:gbk-*-
import time
start = False
ACCOUNT = ''

def init(ContextInfo):
now = time.ctime()
print(now)
ContextInfo.run_time("execution","30nSecond","2023-04-14 13:20:00")


def execution(ContextInfo):
data = ContextInfo.get_stock_list_in_sector('沪深A股')
print(len(data))

def handlebar(ContextInfo):
pass

当前共有5047只股票
【2023-10-25 15:18:45.533】  start trading mode
【2023-10-25 15:18:45.533】 Wed Oct 25 15:18:45 2023

【2023-10-25 15:18:45.533】 5074
['000001.SZ', '000002.SZ', '000004.SZ', '000005.SZ', '000006.SZ', '000007.SZ', '000008.SZ', '000009.SZ', '000010.SZ', '000011.SZ', '000012.SZ', '000014.SZ', '000016.SZ', '000017.SZ', '000019.SZ', '000020.SZ', '000021.SZ', '000023.SZ', '000025.SZ', '000026.SZ', '000027.SZ', '000028.SZ', '000029.SZ', '000030.SZ', '000031.SZ', '000032.SZ', '000034.SZ', '000035.SZ', '000036.SZ', '000037.SZ', '000039.SZ', '000040.SZ', '000042.SZ', '000045.SZ', '000046.SZ', '000048.SZ', '000049.SZ', '000050.SZ', '000055.SZ', '000056.SZ', '000058.SZ', '000059.SZ', '000060.SZ', '000061.SZ', '000062.SZ', '000063.SZ', '000065.SZ', '000066.SZ', '000068.SZ', '000069.SZ', '000070.SZ', '000078.SZ', '000088.SZ', '000089.SZ', '000090.SZ', '000096.SZ', '000099.SZ', '000100.SZ', '000151.SZ', '000153.SZ', '000155.SZ', '000156.SZ', '000157.SZ', '000158.SZ', '000159.SZ', '000166.SZ', '000301.SZ', '000333.SZ', '000338.SZ', '000400.SZ', '000401.SZ', '000402.SZ', '000403.SZ', '000404.SZ', '000407.SZ', '000408.SZ', '000409.SZ', '000410.SZ', '000411.SZ', '000413.SZ', '000415.SZ', '000416.SZ', '000417.SZ', '000419.SZ', '000420.SZ', '000421.SZ', '000422.SZ', '000423.SZ', '000425.SZ', '000426.SZ',
省略若干...
 
点击查看大图
20231025152005.png

 
是否遇到QMT或Ptrade的问题, 无从入手? 或者咨询无门 ?
来加入 知识星球 , 获取专业的技术解答, 量化实盘代码, 技术交流群

 
继续阅读 »
QMT可以通过板块获取A股的全市场股票代码.
 
"沪深A股"
 
完整代码:
#-*-coding:gbk-*-
import time
start = False
ACCOUNT = ''

def init(ContextInfo):
now = time.ctime()
print(now)
ContextInfo.run_time("execution","30nSecond","2023-04-14 13:20:00")


def execution(ContextInfo):
data = ContextInfo.get_stock_list_in_sector('沪深A股')
print(len(data))

def handlebar(ContextInfo):
pass

当前共有5047只股票
【2023-10-25 15:18:45.533】  start trading mode
【2023-10-25 15:18:45.533】 Wed Oct 25 15:18:45 2023

【2023-10-25 15:18:45.533】 5074
['000001.SZ', '000002.SZ', '000004.SZ', '000005.SZ', '000006.SZ', '000007.SZ', '000008.SZ', '000009.SZ', '000010.SZ', '000011.SZ', '000012.SZ', '000014.SZ', '000016.SZ', '000017.SZ', '000019.SZ', '000020.SZ', '000021.SZ', '000023.SZ', '000025.SZ', '000026.SZ', '000027.SZ', '000028.SZ', '000029.SZ', '000030.SZ', '000031.SZ', '000032.SZ', '000034.SZ', '000035.SZ', '000036.SZ', '000037.SZ', '000039.SZ', '000040.SZ', '000042.SZ', '000045.SZ', '000046.SZ', '000048.SZ', '000049.SZ', '000050.SZ', '000055.SZ', '000056.SZ', '000058.SZ', '000059.SZ', '000060.SZ', '000061.SZ', '000062.SZ', '000063.SZ', '000065.SZ', '000066.SZ', '000068.SZ', '000069.SZ', '000070.SZ', '000078.SZ', '000088.SZ', '000089.SZ', '000090.SZ', '000096.SZ', '000099.SZ', '000100.SZ', '000151.SZ', '000153.SZ', '000155.SZ', '000156.SZ', '000157.SZ', '000158.SZ', '000159.SZ', '000166.SZ', '000301.SZ', '000333.SZ', '000338.SZ', '000400.SZ', '000401.SZ', '000402.SZ', '000403.SZ', '000404.SZ', '000407.SZ', '000408.SZ', '000409.SZ', '000410.SZ', '000411.SZ', '000413.SZ', '000415.SZ', '000416.SZ', '000417.SZ', '000419.SZ', '000420.SZ', '000421.SZ', '000422.SZ', '000423.SZ', '000425.SZ', '000426.SZ',
省略若干...
 
点击查看大图
20231025152005.png

 
是否遇到QMT或Ptrade的问题, 无从入手? 或者咨询无门 ?
来加入 知识星球 , 获取专业的技术解答, 量化实盘代码, 技术交流群

  收起阅读 »

国金QMT测试版|模拟盘 安装程序 下载

QMT

20230902004.jpg


国金证券QMT测试账号信息: 
登录账号:******* 登录密码:*********

QMT交易测试客户端下载链接 链接:https://download.gjzq.com.cn/temp/organ/gjzqqmt_ceshi.rar
 

 
 
在线接口文档:
https://qmt.ptradeapi.com
 
需要开通QMT的视频的朋友可以扫码咨询开通,目前国金开通门槛是入金2W就可以了。费率万一,可半年后免五。
开户后可提供技术相关解答。
 
继续阅读 »

20230902004.jpg


国金证券QMT测试账号信息: 
登录账号:******* 登录密码:*********

QMT交易测试客户端下载链接 链接:https://download.gjzq.com.cn/temp/organ/gjzqqmt_ceshi.rar
 

 
 
在线接口文档:
https://qmt.ptradeapi.com
 
需要开通QMT的视频的朋友可以扫码咨询开通,目前国金开通门槛是入金2W就可以了。费率万一,可半年后免五。
开户后可提供技术相关解答。
 
收起阅读 »

国金QMT实盘版本下载地址

QMT
官网没有提供下载地址,QMT一般是找经理开户后,然后申请QMT开通权限后,会发送账号和下载链接,还有接口文档,使用手册。
 

 
QMT实盘版下载地址:
https://download.gjzq.com.cn/gjty/organ/gjzqqmt.rar​
 
 
安装路径最好不要有中文,和空格。
 
实盘版里面可以切换模拟和实盘。
 

Screenshot_2023_0822_215654.png

 
在线接口文档:
https://qmt.ptradeapi.com
 
需要开通QMT的朋友可以扫码咨询开通,目前国金开通门槛是入金2W就可以了。
开户后可提供技术相关解答。
 

 
 附一个国金Ptrade的下载地址:
Ptrade实盘版下载地址:
https://download.gjzq.com.cn/gjty/organ/gjzqptd.rar
 
继续阅读 »
官网没有提供下载地址,QMT一般是找经理开户后,然后申请QMT开通权限后,会发送账号和下载链接,还有接口文档,使用手册。
 

 
QMT实盘版下载地址:
https://download.gjzq.com.cn/gjty/organ/gjzqqmt.rar​
 
 
安装路径最好不要有中文,和空格。
 
实盘版里面可以切换模拟和实盘。
 

Screenshot_2023_0822_215654.png

 
在线接口文档:
https://qmt.ptradeapi.com
 
需要开通QMT的朋友可以扫码咨询开通,目前国金开通门槛是入金2W就可以了。
开户后可提供技术相关解答。
 

 
 附一个国金Ptrade的下载地址:
Ptrade实盘版下载地址:
https://download.gjzq.com.cn/gjty/organ/gjzqptd.rar
  收起阅读 »

哪些券商有miniqmt? 门槛如何

miniqmt可以不在QMT的框架下编写代码,灵活性要高于QMT。
它属于一个精简版的QMT,把回测功能,UI界面操作功能去除。
 
你可以把miniqmt导入到你的项目里面,直接操作下单。
 
from xtquant import xtdata
data = xtdata.get_market_data(field_list=['time', 'open', 'close', 'high', 'low', 'volume', 'amount'], stock_list=['603000.SH'], period='1d', start_time='20230101')
print(data)
上面代码 可以直接在你的pycharm里面运行, 提前把 xtquant 这个包复制到系统路径,site-packages,或者自己加到环境变量。
 
 
MiniQMT支持新版本的Python
最新已经支持python3.6-3.11
更新方式:主QMT-设置-交易设置-模型设置里更新Python库
 
目前支持miniQTM的券商有哪些?
 
其实miniqmt是附属在QMT上的,正常有QMT的,默认就可以使用miniqmt,除非券商作妖,阉割了。
 
国金,国盛支持miniqmt,开通QMT后 miniqmt就是直接可以使用的。
 

国金国盛.jpg

 
而国信的miniqmt默认被阉割了,需要额外去申请。(可能还有些经理不敬业的,会和你说不支持miniqmt,曾经遇到过),不过国信的miniqmt开通后,个人只能拉取行情数据,是没有下单权限,下单券商是需要机构才可以申请。
 
国金的QMT,miniqmt的开通门槛会低一些,有入金2W就可以开通的营业部; 也有入金50W开通的营业部。 需要的盆友可以扫码咨询开通。
 
国盛的QMT,目前门槛比较高,需要资产100W才能开通。本身之前门槛还只是入金30W就可以的了,后面他们不断地提高门槛,提到50W,后面提高到100W,不过最近几天,营业部的经理和我说目前我这边开通只需要50W即可。
 
 所以平时有优惠费率的时候就不要犹犹豫豫,把账户和权限开了再说,因为好事不常有,过了这个桥就没有这个店。
 
 
需要开户的盆友可以扫码咨询

 
继续阅读 »
miniqmt可以不在QMT的框架下编写代码,灵活性要高于QMT。
它属于一个精简版的QMT,把回测功能,UI界面操作功能去除。
 
你可以把miniqmt导入到你的项目里面,直接操作下单。
 
from xtquant import xtdata
data = xtdata.get_market_data(field_list=['time', 'open', 'close', 'high', 'low', 'volume', 'amount'], stock_list=['603000.SH'], period='1d', start_time='20230101')
print(data)
上面代码 可以直接在你的pycharm里面运行, 提前把 xtquant 这个包复制到系统路径,site-packages,或者自己加到环境变量。
 
 
MiniQMT支持新版本的Python
最新已经支持python3.6-3.11
更新方式:主QMT-设置-交易设置-模型设置里更新Python库
 
目前支持miniQTM的券商有哪些?
 
其实miniqmt是附属在QMT上的,正常有QMT的,默认就可以使用miniqmt,除非券商作妖,阉割了。
 
国金,国盛支持miniqmt,开通QMT后 miniqmt就是直接可以使用的。
 

国金国盛.jpg

 
而国信的miniqmt默认被阉割了,需要额外去申请。(可能还有些经理不敬业的,会和你说不支持miniqmt,曾经遇到过),不过国信的miniqmt开通后,个人只能拉取行情数据,是没有下单权限,下单券商是需要机构才可以申请。
 
国金的QMT,miniqmt的开通门槛会低一些,有入金2W就可以开通的营业部; 也有入金50W开通的营业部。 需要的盆友可以扫码咨询开通。
 
国盛的QMT,目前门槛比较高,需要资产100W才能开通。本身之前门槛还只是入金30W就可以的了,后面他们不断地提高门槛,提到50W,后面提高到100W,不过最近几天,营业部的经理和我说目前我这边开通只需要50W即可。
 
 所以平时有优惠费率的时候就不要犹犹豫豫,把账户和权限开了再说,因为好事不常有,过了这个桥就没有这个店。
 
 
需要开户的盆友可以扫码咨询

  收起阅读 »

国金证券QMT量化新人培训教程

QMT
最近国金证券邀请了QMT技术人员对内部用户进行了新人培训,并提供视频回放。
视频已经整理放到B站:
https://space.bilibili.com/73827743/channel/seriesdetail?sid=3326385&ctype=0
 
视频目录:
 

20230529001.jpg

 
量化新人用QMT+chat GPT快速上手量化策略(一)QMT基础介绍

量化新人用QMT+chat GPT快速上手量化策略(二)QMT均线盘后选股

量化新人用QMT+chat GPT快速上手量化策略(三)一个基本的回测策略代码

量化新人用QMT+chat GPT快速上手量化策略(四) QMT运行一个策略的整体流程

量化新人用QMT+chat GPT快速上手量化策略(五) 获取股票数据

量化新人用QMT+chat GPT快速上手量化策略(六) tablib计算指标

量化新人用QMT+chat GPT快速上手量化策略(七) 下单代码编写
 
欢迎观看并提出疑问。
 
公众号:可转债量化分析
继续阅读 »
最近国金证券邀请了QMT技术人员对内部用户进行了新人培训,并提供视频回放。
视频已经整理放到B站:
https://space.bilibili.com/73827743/channel/seriesdetail?sid=3326385&ctype=0
 
视频目录:
 

20230529001.jpg

 
量化新人用QMT+chat GPT快速上手量化策略(一)QMT基础介绍

量化新人用QMT+chat GPT快速上手量化策略(二)QMT均线盘后选股

量化新人用QMT+chat GPT快速上手量化策略(三)一个基本的回测策略代码

量化新人用QMT+chat GPT快速上手量化策略(四) QMT运行一个策略的整体流程

量化新人用QMT+chat GPT快速上手量化策略(五) 获取股票数据

量化新人用QMT+chat GPT快速上手量化策略(六) tablib计算指标

量化新人用QMT+chat GPT快速上手量化策略(七) 下单代码编写
 
欢迎观看并提出疑问。
 
公众号:可转债量化分析
收起阅读 »

QMT获取实时分笔委托数据用哪个函数?

QMT
.get_market_data 和 get_market_data_ex (第二版)都可以。
 
现在官方更加推荐使用第二版,速度要比第一版的要快,也就是推荐使用  .get_market_data_ex。
 
具体怎么使用呢?
 
def init(ContextInfo):
ContextInfo.run_time('execution', '3nSecond', '2019-10-14 13:20:00',)

def execution(ContextInfo):
if not ContextInfo.is_last_bar():
return
data = ContextInfo.get_market_data_ex(
[], ['123136.SZ'], period='tick'
, start_time='', end_time='', count=1
, dividend_type='follow', fill_data=True
, subscribe=True)
print(data)


def handlebar(ContextInfo):
#计算当前主图的cci
pass
上面代码是每个3秒获取一次 城市转债 的分笔/逐笔数据。
 
然后在实盘重运行得到下面的结果:

20230524152638683.png

 
(点击放大)
 
可以拿到分笔委托的价格,委卖1到5,委托量也可以看到,买和卖的5挡数据。
 
更多QMT的知识分享:
继续阅读 »
.get_market_data 和 get_market_data_ex (第二版)都可以。
 
现在官方更加推荐使用第二版,速度要比第一版的要快,也就是推荐使用  .get_market_data_ex。
 
具体怎么使用呢?
 
def init(ContextInfo):
ContextInfo.run_time('execution', '3nSecond', '2019-10-14 13:20:00',)

def execution(ContextInfo):
if not ContextInfo.is_last_bar():
return
data = ContextInfo.get_market_data_ex(
[], ['123136.SZ'], period='tick'
, start_time='', end_time='', count=1
, dividend_type='follow', fill_data=True
, subscribe=True)
print(data)


def handlebar(ContextInfo):
#计算当前主图的cci
pass
上面代码是每个3秒获取一次 城市转债 的分笔/逐笔数据。
 
然后在实盘重运行得到下面的结果:

20230524152638683.png

 
(点击放大)
 
可以拿到分笔委托的价格,委卖1到5,委托量也可以看到,买和卖的5挡数据。
 
更多QMT的知识分享:
收起阅读 »

QMT委托对象orderInfo的属性以及对应的值

QMT
又得吐槽一次QMT的文档设计与撰写者。纯粹是业余水平+为了完成任务滥竽充数的API接口文档。
 
官网给出了来的oderInfo里面的字段以及简单的介绍(已经简单得不能再简单了,连对应的是什么类型都不写,懒的一笔)
 
m_strAccountID: 资金账号,账号,账号,资金账号

m_strExchangeID: 证券市场

m_strExchangeName: 交易市场

m_strProductID: 品种代码

m_strProductName: 品种名称

m_strInstrumentID: 证券代码

m_strInstrumentName: 证券名称,合约名称

m_strOrderRef: 内部委托号,下单引用等于股票的内部委托号

m_nOrderPriceType: EBrokerPriceType 类型,例如市价单、限价单

m_nDirection: EEntrustBS 类型,操作,多空,期货多空,股票买卖永远是 48,其他的 dir 同理

m_nOffsetFlag: EOffset_Flag_Type类型,买卖/开平,用此字段区分股票买卖,期货开、平仓,期权买卖等

m_nHedgeFlag: EHedge_Flag_Type 类型,投保

m_dLimitPrice: 委托价格,限价单的限价,就是报价

m_nVolumeTotalOriginal: 委托量,最初委托量

m_nOrderSubmitStatus: EEntrustSubmitStatus 类型,报单状态,提交状态,股票中不需要报单状态

m_strOrderSysID: 合同编号,委托号

m_nOrderStatus: EEntrustStatus,委托状态

m_nVolumeTraded: 成交数量,已成交量

m_nVolumeTotal: 委托剩余量,当前总委托量,股票的含义是总委托量减去成交量

m_nErrorID: 状态信息

m_strErrorMsg: 状态信息

m_nTaskId:任务号

m_dFrozenMargin: 冻结金额,冻结保证金

m_dFrozenCommission: 冻结手续费

m_strInsertDate: 委托日期,报单日期

m_strInsertTime: 委托时间

m_dTradedPrice: 成交均价(股票)

m_dCancelAmount: 已撤数量

m_strOptName: 买卖标记,展示委托属性的中文

m_dTradeAmount: 成交金额,成交额,期货 = 均价 * 量 * 合约乘数

m_eEntrustType: EEntrustTypes,委托类别

m_strCancelInfo: 废单原因

m_strUnderCode: 标的证券代码

m_eCoveredFlag: ECoveredFlag,备兑标记 '0' - 非备兑,'1' - 备兑

m_dOrderPriceRMB: 委托价格(人民币),目前用于港股通

m_dTradeAmountRMB: 成交金额(人民币),目前用于港股通

m_dReferenceRate: 汇率,目前用于港股通

m_strCompactNo: 合约编号

m_eCashgroupProp: EXTCompactBrushSource类型,头寸来源

m_dShortOccupedMargin: 预估在途占用保证金,用于期权

m_strXTTrade: 是否是迅投交易

m_strAccountKey: 账号key,唯一区别不同账号的key

m_strRemark:投资备注
但我们可以直接使用枚举的方法,把上面的属性和对应的值列出来。
 
attr EBrokerPriceType value  <class 'EBrokerPriceType'>
attr ECoveredFlag value <class 'ECoveredFlag'>
attr EEntrustBS value <class 'EEntrustBS'>
attr EEntrustStatus value <class 'EEntrustStatus'>
attr EEntrustSubmitStatus value <class 'EEntrustSubmitStatus'>
attr EEntrustTypes value <class 'EEntrustTypes'>
attr EFutureTradeType value <class 'EFutureTradeType'>
attr EHedge_Flag_Type value <class 'EHedge_Flag_Type'>
attr EOffset_Flag_Type value <class 'EOffset_Flag_Type'>
attr ESideFlag value <class 'ESideFlag'>
attr EXTCompactBrushSource value <class 'EXTCompactBrushSource'>
attr EXTCompactStatus value <class 'EXTCompactStatus'>
attr EXTCompactType value <class 'EXTCompactType'>
attr EXTSloTypeQueryMode value <class 'EXTSloTypeQueryMode'>
attr EXTSubjectsStatus value <class 'EXTSubjectsStatus'>
attr __class__ value <class 'COrderDetail'>
attr __delattr__ value <method-wrapper '__delattr__' of COrderDetail object at 0x000000004AD59A60>
attr __dict__ value {}
attr __dir__ value <built-in method __dir__ of COrderDetail object at 0x000000004AD59A60>
attr __doc__ value None
attr __eq__ value <method-wrapper '__eq__' of COrderDetail object at 0x000000004AD59A60>
attr __format__ value <built-in method __format__ of COrderDetail object at 0x000000004AD59A60>
attr __ge__ value <method-wrapper '__ge__' of COrderDetail object at 0x000000004AD59A60>
attr __getattribute__ value <method-wrapper '__getattribute__' of COrderDetail object at 0x000000004AD59A60>
attr __gt__ value <method-wrapper '__gt__' of COrderDetail object at 0x000000004AD59A60>
attr __hash__ value <method-wrapper '__hash__' of COrderDetail object at 0x000000004AD59A60>
attr __init__ value <bound method __init__ of <COrderDetail object at 0x000000004AD59A60>>
attr __init_subclass__ value <built-in method __init_subclass__ of Boost.Python.class object at 0x0000000044C55368>
attr __instance_size__ value 1088
attr __le__ value <method-wrapper '__le__' of COrderDetail object at 0x000000004AD59A60>
attr __lt__ value <method-wrapper '__lt__' of COrderDetail object at 0x000000004AD59A60>
attr __ne__ value <method-wrapper '__ne__' of COrderDetail object at 0x000000004AD59A60>
attr __new__ value <built-in method __new__ of Boost.Python.class object at 0x000007FEDCF525C0>
attr __reduce__ value <bound method <unnamed Boost.Python function> of <COrderDetail object at 0x000000004AD59A60>>
attr __reduce_ex__ value <built-in method __reduce_ex__ of COrderDetail object at 0x000000004AD59A60>
attr __repr__ value <method-wrapper '__repr__' of COrderDetail object at 0x000000004AD59A60>
attr __setattr__ value <method-wrapper '__setattr__' of COrderDetail object at 0x000000004AD59A60>
attr __sizeof__ value <built-in method __sizeof__ of COrderDetail object at 0x000000004AD59A60>
attr __str__ value <method-wrapper '__str__' of COrderDetail object at 0x000000004AD59A60>
attr __subclasshook__ value <built-in method __subclasshook__ of Boost.Python.class object at 0x0000000044C55368>
attr __weakref__ value None
attr j value j
attr m_bEnable value True
attr m_dCancelAmount value 0.0
attr m_dFrozenCommission value 0.15
attr m_dFrozenMargin value 1000.0
attr m_dLimitPrice value 2.3

具体的获取方式,可以到个人的知识星球获取。
星球也会不定时更新一些QMT常见的坑和问题,也可以提问:

20230518001.jpg

 
 
这里简单介绍一下几个常用的字段:
attr m_nOrderStatus value  50
委托状态: 50代表已报, 注意,这里有个坑, 委托状态会返回2次,一次是先显示49,下一次是显示50,状态从待报-变成已报。 
 
 
继续阅读 »
又得吐槽一次QMT的文档设计与撰写者。纯粹是业余水平+为了完成任务滥竽充数的API接口文档。
 
官网给出了来的oderInfo里面的字段以及简单的介绍(已经简单得不能再简单了,连对应的是什么类型都不写,懒的一笔)
 
m_strAccountID: 资金账号,账号,账号,资金账号

m_strExchangeID: 证券市场

m_strExchangeName: 交易市场

m_strProductID: 品种代码

m_strProductName: 品种名称

m_strInstrumentID: 证券代码

m_strInstrumentName: 证券名称,合约名称

m_strOrderRef: 内部委托号,下单引用等于股票的内部委托号

m_nOrderPriceType: EBrokerPriceType 类型,例如市价单、限价单

m_nDirection: EEntrustBS 类型,操作,多空,期货多空,股票买卖永远是 48,其他的 dir 同理

m_nOffsetFlag: EOffset_Flag_Type类型,买卖/开平,用此字段区分股票买卖,期货开、平仓,期权买卖等

m_nHedgeFlag: EHedge_Flag_Type 类型,投保

m_dLimitPrice: 委托价格,限价单的限价,就是报价

m_nVolumeTotalOriginal: 委托量,最初委托量

m_nOrderSubmitStatus: EEntrustSubmitStatus 类型,报单状态,提交状态,股票中不需要报单状态

m_strOrderSysID: 合同编号,委托号

m_nOrderStatus: EEntrustStatus,委托状态

m_nVolumeTraded: 成交数量,已成交量

m_nVolumeTotal: 委托剩余量,当前总委托量,股票的含义是总委托量减去成交量

m_nErrorID: 状态信息

m_strErrorMsg: 状态信息

m_nTaskId:任务号

m_dFrozenMargin: 冻结金额,冻结保证金

m_dFrozenCommission: 冻结手续费

m_strInsertDate: 委托日期,报单日期

m_strInsertTime: 委托时间

m_dTradedPrice: 成交均价(股票)

m_dCancelAmount: 已撤数量

m_strOptName: 买卖标记,展示委托属性的中文

m_dTradeAmount: 成交金额,成交额,期货 = 均价 * 量 * 合约乘数

m_eEntrustType: EEntrustTypes,委托类别

m_strCancelInfo: 废单原因

m_strUnderCode: 标的证券代码

m_eCoveredFlag: ECoveredFlag,备兑标记 '0' - 非备兑,'1' - 备兑

m_dOrderPriceRMB: 委托价格(人民币),目前用于港股通

m_dTradeAmountRMB: 成交金额(人民币),目前用于港股通

m_dReferenceRate: 汇率,目前用于港股通

m_strCompactNo: 合约编号

m_eCashgroupProp: EXTCompactBrushSource类型,头寸来源

m_dShortOccupedMargin: 预估在途占用保证金,用于期权

m_strXTTrade: 是否是迅投交易

m_strAccountKey: 账号key,唯一区别不同账号的key

m_strRemark:投资备注
但我们可以直接使用枚举的方法,把上面的属性和对应的值列出来。
 
attr EBrokerPriceType value  <class 'EBrokerPriceType'>
attr ECoveredFlag value <class 'ECoveredFlag'>
attr EEntrustBS value <class 'EEntrustBS'>
attr EEntrustStatus value <class 'EEntrustStatus'>
attr EEntrustSubmitStatus value <class 'EEntrustSubmitStatus'>
attr EEntrustTypes value <class 'EEntrustTypes'>
attr EFutureTradeType value <class 'EFutureTradeType'>
attr EHedge_Flag_Type value <class 'EHedge_Flag_Type'>
attr EOffset_Flag_Type value <class 'EOffset_Flag_Type'>
attr ESideFlag value <class 'ESideFlag'>
attr EXTCompactBrushSource value <class 'EXTCompactBrushSource'>
attr EXTCompactStatus value <class 'EXTCompactStatus'>
attr EXTCompactType value <class 'EXTCompactType'>
attr EXTSloTypeQueryMode value <class 'EXTSloTypeQueryMode'>
attr EXTSubjectsStatus value <class 'EXTSubjectsStatus'>
attr __class__ value <class 'COrderDetail'>
attr __delattr__ value <method-wrapper '__delattr__' of COrderDetail object at 0x000000004AD59A60>
attr __dict__ value {}
attr __dir__ value <built-in method __dir__ of COrderDetail object at 0x000000004AD59A60>
attr __doc__ value None
attr __eq__ value <method-wrapper '__eq__' of COrderDetail object at 0x000000004AD59A60>
attr __format__ value <built-in method __format__ of COrderDetail object at 0x000000004AD59A60>
attr __ge__ value <method-wrapper '__ge__' of COrderDetail object at 0x000000004AD59A60>
attr __getattribute__ value <method-wrapper '__getattribute__' of COrderDetail object at 0x000000004AD59A60>
attr __gt__ value <method-wrapper '__gt__' of COrderDetail object at 0x000000004AD59A60>
attr __hash__ value <method-wrapper '__hash__' of COrderDetail object at 0x000000004AD59A60>
attr __init__ value <bound method __init__ of <COrderDetail object at 0x000000004AD59A60>>
attr __init_subclass__ value <built-in method __init_subclass__ of Boost.Python.class object at 0x0000000044C55368>
attr __instance_size__ value 1088
attr __le__ value <method-wrapper '__le__' of COrderDetail object at 0x000000004AD59A60>
attr __lt__ value <method-wrapper '__lt__' of COrderDetail object at 0x000000004AD59A60>
attr __ne__ value <method-wrapper '__ne__' of COrderDetail object at 0x000000004AD59A60>
attr __new__ value <built-in method __new__ of Boost.Python.class object at 0x000007FEDCF525C0>
attr __reduce__ value <bound method <unnamed Boost.Python function> of <COrderDetail object at 0x000000004AD59A60>>
attr __reduce_ex__ value <built-in method __reduce_ex__ of COrderDetail object at 0x000000004AD59A60>
attr __repr__ value <method-wrapper '__repr__' of COrderDetail object at 0x000000004AD59A60>
attr __setattr__ value <method-wrapper '__setattr__' of COrderDetail object at 0x000000004AD59A60>
attr __sizeof__ value <built-in method __sizeof__ of COrderDetail object at 0x000000004AD59A60>
attr __str__ value <method-wrapper '__str__' of COrderDetail object at 0x000000004AD59A60>
attr __subclasshook__ value <built-in method __subclasshook__ of Boost.Python.class object at 0x0000000044C55368>
attr __weakref__ value None
attr j value j
attr m_bEnable value True
attr m_dCancelAmount value 0.0
attr m_dFrozenCommission value 0.15
attr m_dFrozenMargin value 1000.0
attr m_dLimitPrice value 2.3

具体的获取方式,可以到个人的知识星球获取。
星球也会不定时更新一些QMT常见的坑和问题,也可以提问:

20230518001.jpg

 
 
这里简单介绍一下几个常用的字段:
attr m_nOrderStatus value  50
委托状态: 50代表已报, 注意,这里有个坑, 委托状态会返回2次,一次是先显示49,下一次是显示50,状态从待报-变成已报。 
 
  收起阅读 »

QMT运行后的历史日志保存在哪个位置?

如果退出了QMT,那么在当前窗口运行的日志就会跟着消失。
 
PS: 知乎上这位是抄袭我的:
https://zhuanlan.zhihu.com/p/650119640
 
我这里有很多QMT的文章,都是没有原创没有加水印的

20230511001.jpg

 
如果想要找回以前的历史日志,可以到下面的路径寻找;
以国信证券的iquant为例:
 
C:\iquant_gx\userdata\log
 
具体以你的券商路径安装名字为准
 

mmexport1683784887096.png

 
个人的日志输出在文件名:
XtClient_FormulaOutput_20230426 (后面的是日期,具体根据你要查找的时间来找)
 

20230511002.jpg

 
看到没?
上面的日志就是记录当时的策略输出。
 
国信证券iQuant, 万一免五 开户,无门槛开通,
需要的可以联系:
可开通miniqmt
继续阅读 »
如果退出了QMT,那么在当前窗口运行的日志就会跟着消失。
 
PS: 知乎上这位是抄袭我的:
https://zhuanlan.zhihu.com/p/650119640
 
我这里有很多QMT的文章,都是没有原创没有加水印的

20230511001.jpg

 
如果想要找回以前的历史日志,可以到下面的路径寻找;
以国信证券的iquant为例:
 
C:\iquant_gx\userdata\log
 
具体以你的券商路径安装名字为准
 

mmexport1683784887096.png

 
个人的日志输出在文件名:
XtClient_FormulaOutput_20230426 (后面的是日期,具体根据你要查找的时间来找)
 

20230511002.jpg

 
看到没?
上面的日志就是记录当时的策略输出。
 
国信证券iQuant, 万一免五 开户,无门槛开通,
需要的可以联系:
可开通miniqmt
收起阅读 »

迅投QMT修改编辑器字体大小,4个空格缩进(默认是TAB),背景颜色

QMT
QMT的默认编辑器是非常难用的。字体,大小,颜色,编码,缩进,一言难尽。
 
而且在菜单里面也找不到设置的地方。
 
其实用户是可以修改这个编辑器的配置的。
 
找到QMT的安装目录,找到config文件夹,里面有个editor.xml 的文件,用记事本或者notepad++等文本编辑器打开。
 

20230425001.jpg

 
如果要修改字体大小,可以修改: 
 
  <font FamilyName="Courier New" IsBold="false" size="16"/>
 
把size设置大一点,字体即可变大。
 
如果要把tab缩进改为空格缩进(主流IDE,pycharm vscode都是4个空格缩进的),可以改成下面的
        <font FamilyName="Courier New" IsBold="false" size="20"/>

        <align TabStop="4" AutoIndent="true" IndentationsUseTabs="false" WrapWord="false"/>
 

20231012200620.png


 
如果需要修改背景色:
同理:
        <color bgcolor="255,255,255"/>
修改这一行,
比如变成黑色背景
        <color bgcolor="0,0,0"/>
 
PS: 上述配置部分券商可以在QMT的IDE上设置,比如字体大小等,而在这个xml里面修改却生效不了
 
改为后记得重启QMT生效
 
公众号后台回复:
qmt配置文件 
可以获取修改为tab缩进的配置文件
 
继续阅读 »
QMT的默认编辑器是非常难用的。字体,大小,颜色,编码,缩进,一言难尽。
 
而且在菜单里面也找不到设置的地方。
 
其实用户是可以修改这个编辑器的配置的。
 
找到QMT的安装目录,找到config文件夹,里面有个editor.xml 的文件,用记事本或者notepad++等文本编辑器打开。
 

20230425001.jpg

 
如果要修改字体大小,可以修改: 
 
  <font FamilyName="Courier New" IsBold="false" size="16"/>
 
把size设置大一点,字体即可变大。
 
如果要把tab缩进改为空格缩进(主流IDE,pycharm vscode都是4个空格缩进的),可以改成下面的
        <font FamilyName="Courier New" IsBold="false" size="20"/>

        <align TabStop="4" AutoIndent="true" IndentationsUseTabs="false" WrapWord="false"/>
 

20231012200620.png


 
如果需要修改背景色:
同理:
        <color bgcolor="255,255,255"/>
修改这一行,
比如变成黑色背景
        <color bgcolor="0,0,0"/>
 
PS: 上述配置部分券商可以在QMT的IDE上设置,比如字体大小等,而在这个xml里面修改却生效不了
 
改为后记得重启QMT生效
 
公众号后台回复:
qmt配置文件 
可以获取修改为tab缩进的配置文件
 
收起阅读 »

QMT vs Ptrade 速度对比 (二)实时行情速度对比


上一篇文章(QMT vs Ptrade 速度对比 (一) 历史行情获取速度)对了了QMT和Ptrade的获取历史行情速度,本篇文章继续对它俩的实时行情速度。

本文以获取市场所有可转债的实时行情为例子,比较二者的速度。



Ptrade获取所有可转债实时行情

目前市场上有480多只可转债,由于Ptrade内置的数据源不足以支撑可转债的大部分策略,所以需要调用外部数据源,因此使用国盛证券的Ptrade进行交易,因为目前只有它可以链接外网,你可以把可转债的数据写入到数据库或者写成自己的接口,传递给Ptrade就可以了。

比如下面的基础数据接口。



【目前星球用户可以提供数据接口免费调用功能,提供实时数据功能,强赎倒数多个API接口】

然后调用端使用python的requests库请求下就有了。下面代码可以在Ptrade里面部署运行,用于获取可转债溢价率,剩余规模等数据。







然后在Ptrade的定时执行函数里面获取实时tick数据,使用get_snapshot,把所有的转债代码传入get_snapshot就可以拿到可转债的行情数据了,行情数据3秒更新一次。





在Ptrade里面的运行情况



红框的地方是几个时间点要关注的。

481:获取的转债个数有481

红色数字1的位置: time used

获取行情数据所用的时间,大概在17毫秒(ms)左右,数据一直比较稳定。返回的数据里面字段除了价格,还有昨收价,委买卖1队列,涨停价,成交量等多个数据,参考上图里面的那个字典格式的数据。 具体可以参考接口文档(http://ptradeapi.com

红色数字2的位置:日志输出时候的时间,也就是程序当前所在时刻,在目前程序在14:42:51,红色数字3的时间,是当前价格的里面的时间,也就tick对应的时间,当前的tick时间是hsTimeStamp: 20230419144251000, 也就是 2023-04-19 14:42:51:000, 所以当前时间程序获取的tick时间是一致的。为什么这里要强调这个呢? 假如当前程序时刻是14:42:51, 而获取的tick timestamp数据是14:42:48,那么说明当前程序拿到的最新tick数据却是在48秒时的数据,也就是数据延时了3秒。所以Ptrade里面的tick数据并没有出现延时滞后。



QMT 实时行情

同样QMT提供的可转债基础也是少的可怜,几乎为零。所以同样调用个人部署的可转债接口数据,如法炮制。PS:通过数据解耦的方式,不同数据可以在不同的量化软件里面使用,省去很多重复编写的代码,即使后面接入掘金,聚宽等平台,你只需要编写下单接口逻辑即可。



QMT取实时行情代码如下:


20230420013.jpg



Bond是一个类,和ptrade里面的一样的,用来获取转债基础数据。

同样在QMT的实盘模式下执行:



网络环境:500M宽带网络,PC:CPU I7 - 内存24GB


stock num : 481 同样获取的是481个转债实时行情数据

红色数字1时间:日志输出的当前时间,获取行情数据前的时间14:43:25

红色数字2时间:日志输出的当前时间,此时为已经获取行情数据后的时间:14:43:34

红色数字3:第一次获取行情数据时间差,达到了9.5秒! 这个数字简直惊呆了。 反复测试几次后,依然如此,使用get_market_data获取实时行情数据,第一次数据到达的时候都要挺久的。

新人刚使用这个函数获取实时行情的时候,往往会以为自己代码出bug,等待很久没数据出来,尤其是获取超过1000个股票代码的行情的时候,等待时候更久,等待时间随着输入的个数增加而增加; 同时QMT占用内存也会稳步增加,如果机子的内存太小,可能还会卡死了。(qmt里面的坑还挺多的)









红色数字6,第二次获取实时行情所用的时间,这一次就快很多了,只用了800毫秒。



随着后续运行,获取实时行情的时间就趋于稳定,从800毫秒慢慢降到150毫秒,最后到13-20毫秒,基本和ptrade差不多级别了。











实时行情延时方面,对比通达信

20230420004-v1.jpg




取110048.SH 这个转债的行情数据作为参考,因为QMT返回字段里面没有带tick的时间戳,所以拿通达信作的分时数据作为的对比,没有用L2,所以框住的位置时间约在14:47:03 ~ 14:47:06

图片上半部分通达信的分时数据,左下角的数据时间是14:47:06,所以数据并没有出现很大的延时。



总结

QMT稳定运行的时候,实时行情基本和Ptrade同一级别水平。但QMT的行情波动性大一些。而在初始启动获取数据时,QMT会非常耗费资源,且等待时间较长,而Ptrade则不存在这种问题。

QMT可以随意获取外部数据,所以对券商没有很高要求;而Ptrade目前只有一家券商(国盛证券)可以自由访问外部数据,如果缺少需要的数据或者指标,将无法实现相应的策略。


参考API接口文档:

Ptrade: http://ptradeapi.com/
QMT: http://qmt.ptradeapi.com/

公众号:
继续阅读 »

上一篇文章(QMT vs Ptrade 速度对比 (一) 历史行情获取速度)对了了QMT和Ptrade的获取历史行情速度,本篇文章继续对它俩的实时行情速度。

本文以获取市场所有可转债的实时行情为例子,比较二者的速度。



Ptrade获取所有可转债实时行情

目前市场上有480多只可转债,由于Ptrade内置的数据源不足以支撑可转债的大部分策略,所以需要调用外部数据源,因此使用国盛证券的Ptrade进行交易,因为目前只有它可以链接外网,你可以把可转债的数据写入到数据库或者写成自己的接口,传递给Ptrade就可以了。

比如下面的基础数据接口。



【目前星球用户可以提供数据接口免费调用功能,提供实时数据功能,强赎倒数多个API接口】

然后调用端使用python的requests库请求下就有了。下面代码可以在Ptrade里面部署运行,用于获取可转债溢价率,剩余规模等数据。







然后在Ptrade的定时执行函数里面获取实时tick数据,使用get_snapshot,把所有的转债代码传入get_snapshot就可以拿到可转债的行情数据了,行情数据3秒更新一次。





在Ptrade里面的运行情况



红框的地方是几个时间点要关注的。

481:获取的转债个数有481

红色数字1的位置: time used

获取行情数据所用的时间,大概在17毫秒(ms)左右,数据一直比较稳定。返回的数据里面字段除了价格,还有昨收价,委买卖1队列,涨停价,成交量等多个数据,参考上图里面的那个字典格式的数据。 具体可以参考接口文档(http://ptradeapi.com

红色数字2的位置:日志输出时候的时间,也就是程序当前所在时刻,在目前程序在14:42:51,红色数字3的时间,是当前价格的里面的时间,也就tick对应的时间,当前的tick时间是hsTimeStamp: 20230419144251000, 也就是 2023-04-19 14:42:51:000, 所以当前时间程序获取的tick时间是一致的。为什么这里要强调这个呢? 假如当前程序时刻是14:42:51, 而获取的tick timestamp数据是14:42:48,那么说明当前程序拿到的最新tick数据却是在48秒时的数据,也就是数据延时了3秒。所以Ptrade里面的tick数据并没有出现延时滞后。



QMT 实时行情

同样QMT提供的可转债基础也是少的可怜,几乎为零。所以同样调用个人部署的可转债接口数据,如法炮制。PS:通过数据解耦的方式,不同数据可以在不同的量化软件里面使用,省去很多重复编写的代码,即使后面接入掘金,聚宽等平台,你只需要编写下单接口逻辑即可。



QMT取实时行情代码如下:


20230420013.jpg



Bond是一个类,和ptrade里面的一样的,用来获取转债基础数据。

同样在QMT的实盘模式下执行:



网络环境:500M宽带网络,PC:CPU I7 - 内存24GB


stock num : 481 同样获取的是481个转债实时行情数据

红色数字1时间:日志输出的当前时间,获取行情数据前的时间14:43:25

红色数字2时间:日志输出的当前时间,此时为已经获取行情数据后的时间:14:43:34

红色数字3:第一次获取行情数据时间差,达到了9.5秒! 这个数字简直惊呆了。 反复测试几次后,依然如此,使用get_market_data获取实时行情数据,第一次数据到达的时候都要挺久的。

新人刚使用这个函数获取实时行情的时候,往往会以为自己代码出bug,等待很久没数据出来,尤其是获取超过1000个股票代码的行情的时候,等待时候更久,等待时间随着输入的个数增加而增加; 同时QMT占用内存也会稳步增加,如果机子的内存太小,可能还会卡死了。(qmt里面的坑还挺多的)









红色数字6,第二次获取实时行情所用的时间,这一次就快很多了,只用了800毫秒。



随着后续运行,获取实时行情的时间就趋于稳定,从800毫秒慢慢降到150毫秒,最后到13-20毫秒,基本和ptrade差不多级别了。











实时行情延时方面,对比通达信

20230420004-v1.jpg




取110048.SH 这个转债的行情数据作为参考,因为QMT返回字段里面没有带tick的时间戳,所以拿通达信作的分时数据作为的对比,没有用L2,所以框住的位置时间约在14:47:03 ~ 14:47:06

图片上半部分通达信的分时数据,左下角的数据时间是14:47:06,所以数据并没有出现很大的延时。



总结

QMT稳定运行的时候,实时行情基本和Ptrade同一级别水平。但QMT的行情波动性大一些。而在初始启动获取数据时,QMT会非常耗费资源,且等待时间较长,而Ptrade则不存在这种问题。

QMT可以随意获取外部数据,所以对券商没有很高要求;而Ptrade目前只有一家券商(国盛证券)可以自由访问外部数据,如果缺少需要的数据或者指标,将无法实现相应的策略。


参考API接口文档:

Ptrade: http://ptradeapi.com/
QMT: http://qmt.ptradeapi.com/

公众号:
收起阅读 »