Ptrade/QMT 可转债转股操作 python代码

李魔佛 发表了文章 • 0 个评论 • 2018 次浏览 • 2023-06-19 18:14 • 来自相关话题

如果想进行折价套利(裸套),需要对持有的转债进行转股操作。
 
而这个转股操作是要在交易时间,也就是盘中时间下一个债转股的命令,然后盘后交易所会更会你盘中下的转股指令,将对应的可转债转为对应的股票,这是,持仓里面的可转债会消失,变成该可转债对应的正股。
 
(当然这是在全部转股的前提下的情况,也有可能有部分人转债只转一部分,这样持仓里面还仍然会有部分可转债没有被转为股票)
 
那么在Ptrade和QMT里面,如何调用API接口进行可转债转股呢?
 
Ptrade:
def initialize(context):
g.security = "600570.SS"
set_universe(g.security)

def before_trading_start(context, data):
g.count = 0

def handle_data(context, data):
if g.count == 0:
# 对持仓内的贝斯进行转股操作
debt_to_stock_order("123075.SZ", -1000)
g.count += 1
# 查看委托状态
log.info(get_orders())
g.count += 1
 主要是上面的函数, 
debt_to_stock_order 传入可转债代码和转股的数量,注意数量用加一个负号。
 
 
QMT可转债转股操作
#coding:gbk
c = True
account = '11111111' # 个人账户
def init(ContextInfo):
pass

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

if c:
passorder(80,1101,account,s,5,0,-100,'1',2,'tzbz',ContextInfo)
c=False

 passorder 里面的 80是 普通账户可转债转股
 
更多Ptrade,qmt知识,可以关注公众号

 
  查看全部
如果想进行折价套利(裸套),需要对持有的转债进行转股操作。
 
而这个转股操作是要在交易时间,也就是盘中时间下一个债转股的命令,然后盘后交易所会更会你盘中下的转股指令,将对应的可转债转为对应的股票,这是,持仓里面的可转债会消失,变成该可转债对应的正股。
 
(当然这是在全部转股的前提下的情况,也有可能有部分人转债只转一部分,这样持仓里面还仍然会有部分可转债没有被转为股票)
 
那么在Ptrade和QMT里面,如何调用API接口进行可转债转股呢?
 
Ptrade:
def initialize(context):
g.security = "600570.SS"
set_universe(g.security)

def before_trading_start(context, data):
g.count = 0

def handle_data(context, data):
if g.count == 0:
# 对持仓内的贝斯进行转股操作
debt_to_stock_order("123075.SZ", -1000)
g.count += 1
# 查看委托状态
log.info(get_orders())
g.count += 1

 主要是上面的函数, 
debt_to_stock_order 传入可转债代码和转股的数量,注意数量用加一个负号。
 
 
QMT可转债转股操作
#coding:gbk
c = True
account = '11111111' # 个人账户
def init(ContextInfo):
pass

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

if c:
passorder(80,1101,account,s,5,0,-100,'1',2,'tzbz',ContextInfo)
c=False

 passorder 里面的 80是 普通账户可转债转股
 
更多Ptrade,qmt知识,可以关注公众号

 
 

宁稳可转债全表数据 - 历史数据更新至2023年06-18日

可转债李魔佛 发表了文章 • 0 个评论 • 1498 次浏览 • 2023-06-19 11:16 • 来自相关话题

包含全字段:
转债代码  转债名称  满足  发行日期  股票代码  股票名称  行业  子行业  转债价格  本息  涨跌  日内套利  股价  正股涨跌  剩余本息  转股价格  转股溢价率  转股价值  距离转股日  剩余年限  回售年限  剩余余额  成交额(百万)  转债换手率 余额/市值  余额/股本  股票市值(亿)  P/B 税前收益率  税后收益率  税前回售收益  税后回售收益 回售价值 纯债价值 弹性 信用 折现率 老式双低 老式排名 新式双低 新式排名 热门度





点击查看大图





点击查看大图
 
数据会定期更新,目前更新到本文发文日期,2023-06-18
  查看全部
包含全字段:
转债代码  转债名称  满足  发行日期  股票代码  股票名称  行业  子行业  转债价格  本息  涨跌  日内套利  股价  正股涨跌  剩余本息  转股价格  转股溢价率  转股价值  距离转股日  剩余年限  回售年限  剩余余额  成交额(百万)  转债换手率 余额/市值  余额/股本  股票市值(亿)  P/B 税前收益率  税后收益率  税前回售收益  税后回售收益 回售价值 纯债价值 弹性 信用 折现率 老式双低 老式排名 新式双低 新式排名 热门度

20230619002.jpg

点击查看大图

20230619001-v2.jpg

点击查看大图
 
数据会定期更新,目前更新到本文发文日期,2023-06-18
 

国盛Ptrade又可以重新开了,需要的小伙伴抓紧开啦

Ptrade李魔佛 发表了文章 • 0 个评论 • 1666 次浏览 • 2023-06-14 11:34 • 来自相关话题

作为目前为止,唯一一个可以和外部通讯的Ptrade券商,之前因为账户号码耗尽的原因,暂停了开通Ptrade的业务。
而目前又可以重新开启这个量化业务了。
 
如果不太懂的小伙伴,笔者这里可以稍加详细解释。
这里的外网,指的外部网络,相对券商部署的服务器内网而言的,并不是指墙外的网络哈,这里小伙伴们注意一下哈。
 
 在大部分券商里,Ptrade是封闭环境下运行的,Ptrade是在券商的内部服务器上执行,所以它无法把数据传出外部的服务器,同样也不能访问外面服务器的数据。比如我想获取同花顺的热门概念,由于Ptrade无法访问外部网络,如果内置的Ptrade数据没有提供,就没有办法了。或者用Ptrade想要搞点可转债溢价率,规模的数据,如果没办法联通外网,实际你的策略就无法下手,因为基础数据已经缺乏了。
 
好在国盛的Ptrade支持外网联通,可以用爬虫的方式,读取mysql的方式,读取MQ队列的方式的等等获取外部数据,弥补内置数据的不足。
 
具体可以看这个文章:
http://30daydo.com/article/44453
 
比如下面代码是在ptrade里面访问百度的:
 
import requests

def initialize(context):
# 初始化策略
g.security = "600570.SS"
set_universe(g.security)


def handle_data(context, data):

url='http://www.baidu.com'
headers={'User-Agent':'Google'}
try:
r=requests.get(url,headers=headers)
r.encoding='utf8'
print(r.text)
except Exception as e:
print('error')
print(e)

 
可以看到能够使用requests这个库正常获取数据的,当然requests库是ptrade本身就有的,不需要你再pip安装,当然ptrade也无法pip安装第三方库。
 
ptrade支持的内置库名单:
http://www.30daydo.com/article/44458
 
APScheduler (3.3.1)
arch (3.2)
bcolz (1.2.1)
beautifulsoup4 (4.6.0)
bleach (1.5.0)
boto (2.43.0)
Bottleneck (1.0.0)
bz2file (0.98)
cachetools (3.1.0)
click (4.0)
contextlib2 (0.4.0)
crypto (1.4.1)
cvxopt (1.1.8)
cx-Oracle (8.0.1)
cycler (0.10.0)
cyordereddict (0.2.2)
Cython (0.22.1)
decorator (4.0.10)
entrypoints (0.2.2)
fastcache (1.0.2)
gensim (0.13.3)
h5py (2.6.0)
hmmlearn (0.2.0)
hs-udata (0.3.6)
html5lib (0.9999999)
ipykernel (4.5.0)
ipython (5.1.0)
ipython-genutils (0.1.0)
ipywidgets (5.2.2)
jieba (0.38)
Jinja2 (2.8)
jsonpickle (1.0)
jsonschema (2.5.1)
jupyter (1.0.0)
jupyter-client (4.4.0)
jupyter-console (5.0.0)
jupyter-core (4.2.0)
jupyter-kernel-gateway (1.1.1)
Keras (2.3.1)
Keras-Applications (1.0.8)
Keras-Preprocessing (1.1.0)
line-profiler (2.1.2)
Logbook (1.4.3)
lxml (4.5.0)
Markdown (2.2.0)
MarkupSafe (0.23)
matplotlib (1.5.3)
mistune (0.7.3)
Naked (0.1.31)
nbconvert (4.2.0)
nbformat (4.1.0)
networkx (1.9.1)
nose (1.3.6)
notebook (4.2.3)
numexpr (2.6.1)
numpy (1.11.2)
pandas (0.23.4)
patsy (0.4.0)
pexpect (4.2.1)
pickleshare (0.7.4)
pip (9.0.1)
pkgconfig (1.0.0)
prompt-toolkit (1.0.8)
protobuf (3.3.0)
ptvsd (2.2.0)
ptyprocess (0.5.1)
PyBrain (0.3)
pycrypto (2.6.1)
Pygments (2.1.3)
PyMySQL (0.9.3)
pyparsing (2.1.10)
python-dateutil (2.7.5)
pytz (2015.4)
PyWavelets (0.4.0)
PyYAML (5.3.1)
pyzmq (16.1.0.dev0)
qtconsole (4.2.1)
requests (2.7.0)
retrying (1.3.3)
scikit-learn (0.18)
scipy (0.18.0)
seaborn (0.7.1)
setuptools (28.7.1)
setuptools-scm (3.1.0)
shellescape (3.4.1)
simplegeneric (0.8.1)
simplejson (3.17.0)
six (1.10.0)
sklearn (0.0)
smart-open (1.3.5)
SQLAlchemy (1.0.8)
statsmodels (0.10.2)
TA-Lib (0.4.10)
tables (3.3.0)
tabulate (0.7.5)
tensorflow (1.3.0rc1)
tensorflow-tensorboard (0.1.2)
terminado (0.6)
Theano (0.8.2)
toolz (0.7.4)
tornado (4.4.2)
traitlets (4.3.1)
tushare (1.2.48)
tzlocal (1.3)
wcwidth (0.1.7)
Werkzeug (0.12.2)
wheel (0.29.0)
widgetsnbextension (1.2.6)
xcsc-tushare (1.0.0)
xgboost (0.6a2)
xlrd (1.1.0)
xlwt (1.3.0)
zipline (0.8.3)
You are using pip version 9.0.1, however version 22.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
需要开户可以关注微信公众号
费率优惠多多(万一免五)

后台回复:ptrade开通
 
 
  查看全部
作为目前为止,唯一一个可以和外部通讯的Ptrade券商,之前因为账户号码耗尽的原因,暂停了开通Ptrade的业务。
而目前又可以重新开启这个量化业务了。
 
如果不太懂的小伙伴,笔者这里可以稍加详细解释。
这里的外网,指的外部网络,相对券商部署的服务器内网而言的,并不是指墙外的网络哈,这里小伙伴们注意一下哈。
 
 在大部分券商里,Ptrade是封闭环境下运行的,Ptrade是在券商的内部服务器上执行,所以它无法把数据传出外部的服务器,同样也不能访问外面服务器的数据。比如我想获取同花顺的热门概念,由于Ptrade无法访问外部网络,如果内置的Ptrade数据没有提供,就没有办法了。或者用Ptrade想要搞点可转债溢价率,规模的数据,如果没办法联通外网,实际你的策略就无法下手,因为基础数据已经缺乏了。
 
好在国盛的Ptrade支持外网联通,可以用爬虫的方式,读取mysql的方式,读取MQ队列的方式的等等获取外部数据,弥补内置数据的不足。
 
具体可以看这个文章:
http://30daydo.com/article/44453
 
比如下面代码是在ptrade里面访问百度的:
 
import requests

def initialize(context):
# 初始化策略
g.security = "600570.SS"
set_universe(g.security)


def handle_data(context, data):

url='http://www.baidu.com'
headers={'User-Agent':'Google'}
try:
r=requests.get(url,headers=headers)
r.encoding='utf8'
print(r.text)
except Exception as e:
print('error')
print(e)


 
可以看到能够使用requests这个库正常获取数据的,当然requests库是ptrade本身就有的,不需要你再pip安装,当然ptrade也无法pip安装第三方库。
 
ptrade支持的内置库名单:
http://www.30daydo.com/article/44458
 
APScheduler (3.3.1)
arch (3.2)
bcolz (1.2.1)
beautifulsoup4 (4.6.0)
bleach (1.5.0)
boto (2.43.0)
Bottleneck (1.0.0)
bz2file (0.98)
cachetools (3.1.0)
click (4.0)
contextlib2 (0.4.0)
crypto (1.4.1)
cvxopt (1.1.8)
cx-Oracle (8.0.1)
cycler (0.10.0)
cyordereddict (0.2.2)
Cython (0.22.1)
decorator (4.0.10)
entrypoints (0.2.2)
fastcache (1.0.2)
gensim (0.13.3)
h5py (2.6.0)
hmmlearn (0.2.0)
hs-udata (0.3.6)
html5lib (0.9999999)
ipykernel (4.5.0)
ipython (5.1.0)
ipython-genutils (0.1.0)
ipywidgets (5.2.2)
jieba (0.38)
Jinja2 (2.8)
jsonpickle (1.0)
jsonschema (2.5.1)
jupyter (1.0.0)
jupyter-client (4.4.0)
jupyter-console (5.0.0)
jupyter-core (4.2.0)
jupyter-kernel-gateway (1.1.1)
Keras (2.3.1)
Keras-Applications (1.0.8)
Keras-Preprocessing (1.1.0)
line-profiler (2.1.2)
Logbook (1.4.3)
lxml (4.5.0)
Markdown (2.2.0)
MarkupSafe (0.23)
matplotlib (1.5.3)
mistune (0.7.3)
Naked (0.1.31)
nbconvert (4.2.0)
nbformat (4.1.0)
networkx (1.9.1)
nose (1.3.6)
notebook (4.2.3)
numexpr (2.6.1)
numpy (1.11.2)
pandas (0.23.4)
patsy (0.4.0)
pexpect (4.2.1)
pickleshare (0.7.4)
pip (9.0.1)
pkgconfig (1.0.0)
prompt-toolkit (1.0.8)
protobuf (3.3.0)
ptvsd (2.2.0)
ptyprocess (0.5.1)
PyBrain (0.3)
pycrypto (2.6.1)
Pygments (2.1.3)
PyMySQL (0.9.3)
pyparsing (2.1.10)
python-dateutil (2.7.5)
pytz (2015.4)
PyWavelets (0.4.0)
PyYAML (5.3.1)
pyzmq (16.1.0.dev0)
qtconsole (4.2.1)
requests (2.7.0)
retrying (1.3.3)
scikit-learn (0.18)
scipy (0.18.0)
seaborn (0.7.1)
setuptools (28.7.1)
setuptools-scm (3.1.0)
shellescape (3.4.1)
simplegeneric (0.8.1)
simplejson (3.17.0)
six (1.10.0)
sklearn (0.0)
smart-open (1.3.5)
SQLAlchemy (1.0.8)
statsmodels (0.10.2)
TA-Lib (0.4.10)
tables (3.3.0)
tabulate (0.7.5)
tensorflow (1.3.0rc1)
tensorflow-tensorboard (0.1.2)
terminado (0.6)
Theano (0.8.2)
toolz (0.7.4)
tornado (4.4.2)
traitlets (4.3.1)
tushare (1.2.48)
tzlocal (1.3)
wcwidth (0.1.7)
Werkzeug (0.12.2)
wheel (0.29.0)
widgetsnbextension (1.2.6)
xcsc-tushare (1.0.0)
xgboost (0.6a2)
xlrd (1.1.0)
xlwt (1.3.0)
zipline (0.8.3)
You are using pip version 9.0.1, however version 22.1.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

需要开户可以关注微信公众号
费率优惠多多(万一免五)

后台回复:ptrade开通
 
 
 

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

QMT李魔佛 发表了文章 • 0 个评论 • 4231 次浏览 • 2023-05-29 00:37 • 来自相关话题

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





 
量化新人用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李魔佛 发表了文章 • 0 个评论 • 1797 次浏览 • 2023-05-24 15:31 • 来自相关话题

.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秒获取一次 城市转债 的分笔/逐笔数据。
 
然后在实盘重运行得到下面的结果:





 
(点击放大)
 
可以拿到分笔委托的价格,委卖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李魔佛 发表了文章 • 0 个评论 • 1760 次浏览 • 2023-05-18 15:43 • 来自相关话题

又得吐槽一次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常见的坑和问题,也可以提问:





 
 
这里简单介绍一下几个常用的字段:
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李魔佛 发表了文章 • 0 个评论 • 1763 次浏览 • 2023-05-11 14:10 • 来自相关话题

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





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





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





 
看到没?
上面的日志就是记录当时的策略输出。
 
国信证券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

用户问的比较多的关于ptrade基础问题

Ptrade李魔佛 发表了文章 • 0 个评论 • 2083 次浏览 • 2023-05-04 01:19 • 来自相关话题

一些星友(星球好友)问的比较多的问题: 
 
1. 国金的Ptrade 实盘交易客户端是无法进行回测的,在任何时间段;
而模拟客户端可以,可以找自己的经理申请一个Ptrade模拟客户端账户; 
 
2. 国盛的Ptrade实盘交易客户端仅在交易时间无法回测,但非交易时间可以回测;
主要是因为实盘回测和交易在同一个服务器,回测占用过多资源会影响实盘交易;模拟客户端没有这个问题;

任何时间段均可以回测; (之前某个券商的ptrade实盘服务器,因为某个用户开了40多个回测策略,一直在后台运行,而且是关于运算密集型的,导致实盘交易的程序也崩溃了)
 
3. 国金Ptrade无法回测星球上面的可转债实盘代码,实盘代码是基于当前的实时数据,用来进行回测没有意义,因为获取不到可转债的历史数据(溢价率,规模等),只有历史的价格数据; 
 
4. 国金Ptrade无法使用星球上的可转债代码进行实盘,因为无法访问外网,无法访问我部署的接口数据; 而国盛的Ptrade可以;如果国金Ptrade需要实盘交易可转债,需要手工上传一些基础数据,Ptrade提供上传功能,具体操作可查找星球相关文章; 
 
5. 在共享的Ptrade模拟试用账户上,不要保留个人代码记录,跑完后记得删除,否则其他共有同一个账户的人可以进去修改复制你的策略和代码;如果是单独的个人模拟账户,则没有这个问题。
  查看全部
一些星友(星球好友)问的比较多的问题: 
 
1. 国金的Ptrade 实盘交易客户端是无法进行回测的,在任何时间段;
而模拟客户端可以,可以找自己的经理申请一个Ptrade模拟客户端账户; 
 
2. 国盛的Ptrade实盘交易客户端仅在交易时间无法回测,但非交易时间可以回测;
主要是因为实盘回测和交易在同一个服务器,回测占用过多资源会影响实盘交易;模拟客户端没有这个问题;

任何时间段均可以回测; (之前某个券商的ptrade实盘服务器,因为某个用户开了40多个回测策略,一直在后台运行,而且是关于运算密集型的,导致实盘交易的程序也崩溃了)
 
3. 国金Ptrade无法回测星球上面的可转债实盘代码,实盘代码是基于当前的实时数据,用来进行回测没有意义,因为获取不到可转债的历史数据(溢价率,规模等),只有历史的价格数据; 
 
4. 国金Ptrade无法使用星球上的可转债代码进行实盘,因为无法访问外网,无法访问我部署的接口数据; 而国盛的Ptrade可以;如果国金Ptrade需要实盘交易可转债,需要手工上传一些基础数据,Ptrade提供上传功能,具体操作可查找星球相关文章; 
 
5. 在共享的Ptrade模拟试用账户上,不要保留个人代码记录,跑完后记得删除,否则其他共有同一个账户的人可以进去修改复制你的策略和代码;如果是单独的个人模拟账户,则没有这个问题。
 

如何下载Ptrade上的数据?

Ptrade李魔佛 发表了文章 • 0 个评论 • 1751 次浏览 • 2023-04-29 02:40 • 来自相关话题

很多菜鸟会觉得不能下载或者上传数据到Ptrade的。

部分券商的Ptrade可以连通外网,只需要部署一个mysql服务器,或者rabbitMQ,就可以快捷的接受数据了。为啥是这两个,而不是mongodb?

因为ptrade内置的pip装好的库就有pymysql和pyzmq,可以配置下就可以直接开箱使用。如果需要开通有外网功能的Ptrade券商,可以关注公众号:可转债量化分析,后台留言:ptrade外网,即可咨询开通。


1. 首先,我们把数据保存到ptrade的服务端,保存方法多样,比如csv,excel,sql文件等,比如df.to_csv, df.to_excel等等。这里要注意一下,保存的路径。需要指定,/home/fly/notebookimport pickle
from collections import defaultdict
NOTEBOOK_PATH = '/home/fly/notebook/'
'''
持仓N日后卖出,仓龄变量每日pickle进行保存,重启策略后可以保证逻辑连贯
'''
def initialize(context):
#尝试启动pickle文件
try:
with open(NOTEBOOK_PATH+'hold_days.pkl','rb') as f:
g.hold_days = pickle.load(f)

2. 文件保存了之后,接着就可以下载了。

   数据在研究的页面那里。







然后点击某个文件,

如果是非纯文本文件,比如excel文件,会显示:Error! not UTF-8 encoded

Saving disable

See console for more details
不用理会,直接点击左上角的文件,下载,选择本地的路径,然后文件就可以下载下来了。 查看全部
很多菜鸟会觉得不能下载或者上传数据到Ptrade的。

部分券商的Ptrade可以连通外网,只需要部署一个mysql服务器,或者rabbitMQ,就可以快捷的接受数据了。为啥是这两个,而不是mongodb?

因为ptrade内置的pip装好的库就有pymysql和pyzmq,可以配置下就可以直接开箱使用。如果需要开通有外网功能的Ptrade券商,可以关注公众号:可转债量化分析,后台留言:ptrade外网,即可咨询开通。


1. 首先,我们把数据保存到ptrade的服务端,保存方法多样,比如csv,excel,sql文件等,比如df.to_csv, df.to_excel等等。这里要注意一下,保存的路径。需要指定,/home/fly/notebook
import pickle
from collections import defaultdict
NOTEBOOK_PATH = '/home/fly/notebook/'
'''
持仓N日后卖出,仓龄变量每日pickle进行保存,重启策略后可以保证逻辑连贯
'''
def initialize(context):
#尝试启动pickle文件
try:
with open(NOTEBOOK_PATH+'hold_days.pkl','rb') as f:
g.hold_days = pickle.load(f)


2. 文件保存了之后,接着就可以下载了。

   数据在研究的页面那里。


20230429001.jpg


然后点击某个文件,

如果是非纯文本文件,比如excel文件,会显示:
Error! not UTF-8 encoded

Saving disable

See console for more details

不用理会,直接点击左上角的文件,下载,选择本地的路径,然后文件就可以下载下来了。

20230429002.jpg

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

QMT李魔佛 发表了文章 • 0 个评论 • 2210 次浏览 • 2023-04-25 12:22 • 来自相关话题

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





 
如果要修改字体大小,可以修改: 
 
  <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"/>
 






 
如果需要修改背景色:
同理:
        <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李魔佛 发表了文章 • 0 个评论 • 2079 次浏览 • 2023-04-23 00:33 • 来自相关话题

上一篇文章(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取实时行情代码如下:








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差不多级别了。











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








取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/

公众号:

【100行python代码实现可转债日内网格-成交驱动】 自定义买卖步长

Ptrade李魔佛 发表了文章 • 0 个评论 • 1990 次浏览 • 2023-04-19 13:27 • 来自相关话题

基于ptrade的可转债日内网格实盘,基于成交驱动,成交后马上挂入下一轮的网格委托。
 
 ## 2023-04-19 更新: 部分成交的需要等待全部成交才触发下一轮挂单

简单的可转债日内网格策略,自定义买卖步长,基准价格,买入与卖出数量,保留底仓张数

开始同时挂买入和卖出委托,如果买入成交后,撤掉委卖(如果是卖出先成交,则撤掉委买),继续挂入下一个步长的委买与委卖,不断循环。


把注释和空格去了100行不到。

代码仅供参考学习具体用法:

用于实盘亏损盈亏自负

后续如果有需要再贴个升级版:多标的网格

或者,额,qmt版本。。。

部分代码截图:




 
 
实盘交易日志:点击查看大图





 






完整代码请参见知识星球.
知识无价,请尊重知识。
  查看全部
基于ptrade的可转债日内网格实盘,基于成交驱动,成交后马上挂入下一轮的网格委托。
 
 ## 2023-04-19 更新: 部分成交的需要等待全部成交才触发下一轮挂单

简单的可转债日内网格策略,自定义买卖步长,基准价格,买入与卖出数量,保留底仓张数

开始同时挂买入和卖出委托,如果买入成交后,撤掉委卖(如果是卖出先成交,则撤掉委买),继续挂入下一个步长的委买与委卖,不断循环。


把注释和空格去了100行不到。

代码仅供参考学习具体用法:

用于实盘亏损盈亏自负

后续如果有需要再贴个升级版:多标的网格

或者,额,qmt版本。。。

部分代码截图:
20230419001.jpg

 
 
实盘交易日志:点击查看大图

20230419003.jpg

 

20230419004.jpg


完整代码请参见知识星球.
知识无价,请尊重知识。
 

QMT vs Ptrade 速度对比 (一) 历史行情获取速度

QMT李魔佛 发表了文章 • 0 个评论 • 2669 次浏览 • 2023-04-11 16:45 • 来自相关话题

众所周知(狗头),QMT是在你本地电脑运行的,包括行情获取,计算指标,选股选债,下单都在你的本地电脑执行。行情数据通过网络去券商服务器或者迅投(QMT)服务器获取,拿到数据在你的本地电脑处理,比如计算涨速,量比,然后再使用下单接口把下单指令通过网络提交到券商柜台,券商柜台接到QMT的委托指令后,再提交给交易所。

Ptrade(恒生电子)则是在券商部署的服务器上执行,你下载的Ptrade在你的本地电脑,只是负责写代码,把代码部署到券商服务器,然后在券商服务其执行你的策略,当然你的代码在券商服务器运行时是被加密的。行情获取,计算指标,下单委托都在券商机房内部执行,属于云策略的类型,策略部署好了,就不需要开着本地电脑观察它的状态。

对比环境均为同一个券商下的QMT和Ptrade,均为生产环境的实盘版本。(PS:温馨提示,平时少用模拟版本,bug多,交易不准,还浪费时间。我平时调试都直接在实盘上调试的,要对自己的策略有信心哈,至少回测过了的嘛O(∩_∩)O~~)

历史行情数据获取

目标:获取2022年到昨天的沪深300所有股票的日线收盘价数据。

QMT

获取行情数据 使用这个函数:ContextInfo.get_market_data()用法: ContextInfo.get_market_data(fields, stock_code = , start_time = '',
end_time = '', skip_paused = True, period = 'follow',
dividend_type = 'follow', count = -1)
 open -- 开盘价(str:numpy.float64);
high -- 最高价(str:numpy.float64);
low --最低价(str:numpy.float64);
close -- 收盘价(str:numpy.float64);
volume -- 交易量(str:numpy.float64);
money -- 交易金额(str:numpy.float64);
price -- 最新价(str:numpy.float64);
preclose -- 昨收盘价(str:numpy.float64)(仅日线返回);
high_limit -- 涨停价(str:numpy.float64)(仅日线返回);
low_limit -- 跌停价(str:numpy.float64)(仅日线返回);
unlimited -- 判断查询日是否无涨跌停限制(1:该日无涨跌停限制;0:该日有涨跌停限制)(str:numpy.float64)(仅日线返回);
 
在fields里面指定只获取close价格即可。

QMT测试代码如下:(需要的也可以后台留言回复获取)

[vscode里面的代码,需要复制到qmt里面执行]

把代码复制到QMT里面,然后切换到模型交易,在中间切换到实盘模式,就会运行上面代码。

注意,这里需要第一次运行上面的代码来计算时间,因为QMT会有个cache缓存机制,它会把曾经跑过的历史数据自动下载下来,保存到你的电脑硬盘里,从而加快QMT后续的读取速度,同样的数据没有必要每次再去网络上拉。

大部分情况下网络IO都会是任何一个量化交易系通最大的性能瓶颈。

运行得到下面的结果:







上面运行时间是22秒。不要惊讶哦,首次获取历史行情数据都是挺慢的。如果你的电脑网速够快,或者但在阿里云,腾讯云之类的云服务上跑,获取历史行情速度会有所提高。

在你运行了上面的代码之后,QMT会在某个时刻,在后台把数据下载到本地QMT安装目录下。








文件按照股票代码作为文件名存储。当然里面不是txt格式,而是QMT做了相应的封装的。上面按照修改日期排序,4月11日多了很多新的DAT数据文件,显然是刚刚生成的。

QMT在获取历史行情数据后,会有个触发器,在后台一次性保存大量的文件,所以QMT会在某一个瞬间,界面会出现卡顿,甚至无响应,而看任务管理器会看到内存飙升甚至爆满100%,有些新人菜鸟就认为QMT太占内存,太垃圾的结论,这也是片面的。实际上在数据完备的情况下,QMT需要的内存4GB就够的了。如果你经常会有扫描全市场股票代码历史数据的话,内存还是尽量选大一点的。如果无法避免内存突然飙升,可以每次把获取行情的股票代码列表减少,细分多几批获取,用时间换空间。

当然 QMT也提供了一个下载历史数据的一个菜单入口,用于在图形界面下手动下载历史行情,从而加速历史行情读取速度。








等数据下载完成后,

第二次跑上面的同一个代码,运行时间明显快了。








但用时还是要7.9秒,反复测试几次,获取时间依然是在6-8秒之间波动。 因为程序读取历史行情数据的一个个独立的文件,所以这里硬盘的性能因素对获取行情影响还是很大的。

笔者感觉7.9秒这个速度还是很慢的,换了台性能好一点的的windows机子,下载了历史数据后再跑了一次:







但用时依然在6秒左右。

所以个人是不推荐大家在tick策略里面,在盘中去获取历史数据的,这个动作应该在盘前就应该完成,把数据保存到内存列表或者dataframe变量中,盘中用的时候去取就可以了。 当然低频策略就无所谓啦。

Ptrade

操作上ptrade相对而言更加简洁,容易上手。

它的API设计和它对应的API文档更加规范,可读性更好。

直接把代码复制到量化->策略,新建策略,然后在交易里面添加策略,直接启动策略。代码设置定时运行,在启动策略后的一分钟后运行。








同样获取沪深300的日线数据,2022年1月到2023年4月10日。
get_price - 获取历史数据 get_price(security, start_date=None, end_date=None, frequency='1d', fields=None, fq=None, count=None)
运行 







上面的结果显示,Ptrade获取同样的历史数据耗时只有700毫秒,0.7秒左右。测试多几次,获取时间基本每次都比较平稳,在0.6-0.8秒之间。(下面打印的306不是沪深300的个数,而是获取到的日期的天数,它返回的结构虽然都是panel,但和QMT的轴有点不同)。

结论

总的来说,获取历史行情数据的速度,Ptrade是秒杀了QMT的,不在一个量级上的。

本来想继续对比实时行情,下单延时对比等等,但开盘时间有限,写了一下时间就不够用了。所以把教程拆分为多个系列,下一篇再对比QMT和PTrade的实时行情数据,下单回调等等啦。


如果想要自己测试文中的数据,可以获取代码,公众号 后台回复: 历史行情数据代码

参考API接口文档:

Ptrade: http://ptradeapi.com/

QMT: http://qmt.ptradeapi.com/
 
公众号: 查看全部
众所周知(狗头),QMT是在你本地电脑运行的,包括行情获取,计算指标,选股选债,下单都在你的本地电脑执行。行情数据通过网络去券商服务器或者迅投(QMT)服务器获取,拿到数据在你的本地电脑处理,比如计算涨速,量比,然后再使用下单接口把下单指令通过网络提交到券商柜台,券商柜台接到QMT的委托指令后,再提交给交易所。

Ptrade(恒生电子)则是在券商部署的服务器上执行,你下载的Ptrade在你的本地电脑,只是负责写代码,把代码部署到券商服务器,然后在券商服务其执行你的策略,当然你的代码在券商服务器运行时是被加密的。行情获取,计算指标,下单委托都在券商机房内部执行,属于云策略的类型,策略部署好了,就不需要开着本地电脑观察它的状态。

对比环境均为同一个券商下的QMT和Ptrade,均为生产环境的实盘版本。(PS:温馨提示,平时少用模拟版本,bug多,交易不准,还浪费时间。我平时调试都直接在实盘上调试的,要对自己的策略有信心哈,至少回测过了的嘛O(∩_∩)O~~)

历史行情数据获取

目标:获取2022年到昨天的沪深300所有股票的日线收盘价数据。

QMT

获取行情数据 使用这个函数:ContextInfo.get_market_data()
用法: ContextInfo.get_market_data(fields, stock_code = , start_time = '', 
end_time = '', skip_paused = True, period = 'follow',
dividend_type = 'follow', count = -1)

 
open -- 开盘价(str:numpy.float64);
high -- 最高价(str:numpy.float64);
low --最低价(str:numpy.float64);
close -- 收盘价(str:numpy.float64);
volume -- 交易量(str:numpy.float64);
money -- 交易金额(str:numpy.float64);
price -- 最新价(str:numpy.float64);
preclose -- 昨收盘价(str:numpy.float64)(仅日线返回);
high_limit -- 涨停价(str:numpy.float64)(仅日线返回);
low_limit -- 跌停价(str:numpy.float64)(仅日线返回);
unlimited -- 判断查询日是否无涨跌停限制(1:该日无涨跌停限制;0:该日有涨跌停限制)(str:numpy.float64)(仅日线返回);

 
在fields里面指定只获取close价格即可。

QMT测试代码如下:(需要的也可以后台留言回复获取)

[vscode里面的代码,需要复制到qmt里面执行]

把代码复制到QMT里面,然后切换到模型交易,在中间切换到实盘模式,就会运行上面代码。

注意,这里需要第一次运行上面的代码来计算时间,因为QMT会有个cache缓存机制,它会把曾经跑过的历史数据自动下载下来,保存到你的电脑硬盘里,从而加快QMT后续的读取速度,同样的数据没有必要每次再去网络上拉。

大部分情况下网络IO都会是任何一个量化交易系通最大的性能瓶颈。

运行得到下面的结果:


20230411015.jpg


上面运行时间是22秒。不要惊讶哦,首次获取历史行情数据都是挺慢的。如果你的电脑网速够快,或者但在阿里云,腾讯云之类的云服务上跑,获取历史行情速度会有所提高。

在你运行了上面的代码之后,QMT会在某个时刻,在后台把数据下载到本地QMT安装目录下。


20230411014.jpg



文件按照股票代码作为文件名存储。当然里面不是txt格式,而是QMT做了相应的封装的。上面按照修改日期排序,4月11日多了很多新的DAT数据文件,显然是刚刚生成的。

QMT在获取历史行情数据后,会有个触发器,在后台一次性保存大量的文件,所以QMT会在某一个瞬间,界面会出现卡顿,甚至无响应,而看任务管理器会看到内存飙升甚至爆满100%,有些新人菜鸟就认为QMT太占内存,太垃圾的结论,这也是片面的。实际上在数据完备的情况下,QMT需要的内存4GB就够的了。如果你经常会有扫描全市场股票代码历史数据的话,内存还是尽量选大一点的。如果无法避免内存突然飙升,可以每次把获取行情的股票代码列表减少,细分多几批获取,用时间换空间。

当然 QMT也提供了一个下载历史数据的一个菜单入口,用于在图形界面下手动下载历史行情,从而加速历史行情读取速度。


20230411017.jpg



等数据下载完成后,

第二次跑上面的同一个代码,运行时间明显快了。


20230411018.jpg



但用时还是要7.9秒,反复测试几次,获取时间依然是在6-8秒之间波动。 因为程序读取历史行情数据的一个个独立的文件,所以这里硬盘的性能因素对获取行情影响还是很大的。

笔者感觉7.9秒这个速度还是很慢的,换了台性能好一点的的windows机子,下载了历史数据后再跑了一次:


20230411019.jpg


但用时依然在6秒左右。

所以个人是不推荐大家在tick策略里面,在盘中去获取历史数据的,这个动作应该在盘前就应该完成,把数据保存到内存列表或者dataframe变量中,盘中用的时候去取就可以了。 当然低频策略就无所谓啦。

Ptrade

操作上ptrade相对而言更加简洁,容易上手。

它的API设计和它对应的API文档更加规范,可读性更好。

直接把代码复制到量化->策略,新建策略,然后在交易里面添加策略,直接启动策略。代码设置定时运行,在启动策略后的一分钟后运行。


20230411016.jpg



同样获取沪深300的日线数据,2022年1月到2023年4月10日。
get_price - 获取历史数据 get_price(security, start_date=None, end_date=None, frequency='1d', fields=None, fq=None, count=None)
运行 

20230411013.jpg



上面的结果显示,Ptrade获取同样的历史数据耗时只有700毫秒,0.7秒左右。测试多几次,获取时间基本每次都比较平稳,在0.6-0.8秒之间。(下面打印的306不是沪深300的个数,而是获取到的日期的天数,它返回的结构虽然都是panel,但和QMT的轴有点不同)。

结论

总的来说,获取历史行情数据的速度,Ptrade是秒杀了QMT的,不在一个量级上的。

本来想继续对比实时行情,下单延时对比等等,但开盘时间有限,写了一下时间就不够用了。所以把教程拆分为多个系列,下一篇再对比QMT和PTrade的实时行情数据,下单回调等等啦。


如果想要自己测试文中的数据,可以获取代码,公众号 后台回复: 历史行情数据代码

参考API接口文档:

Ptrade: http://ptradeapi.com/

QMT: http://qmt.ptradeapi.com/
 
公众号:

Ptrade QMT实盘策略记录 - 不定期更新

李魔佛 发表了文章 • 0 个评论 • 2294 次浏览 • 2023-04-03 15:27 • 来自相关话题

简单记录当前使用Ptrade和QMT编写策略的情况。(只记录大体的意思,不透露具体策略细节,除非是那种烂大街的策略,什么macd,均线,双低,小市值等等)
写出来的是已经实现且实盘稳定运行的;
涨停板;依赖ptrade的高速行情自动配合手动;两融账户的股票日内做T,持有底仓;股票小市值轮动+多因子可转债多因子(有N个版本+不同的排除因子 组合)可转债日内高频股票趋势动量ETF轮动套利脉冲卖出扫描
 
 
纯粹自己做的记录,便于自己平时复盘。






有兴趣的朋友可以关注公众号交流。 查看全部
简单记录当前使用Ptrade和QMT编写策略的情况。(只记录大体的意思,不透露具体策略细节,除非是那种烂大街的策略,什么macd,均线,双低,小市值等等)
写出来的是已经实现且实盘稳定运行的;
  1. 涨停板;依赖ptrade的高速行情自动配合手动;
  2. 两融账户的股票日内做T,持有底仓;
  3. 股票小市值轮动+多因子
  4. 可转债多因子(有N个版本+不同的排除因子 组合)
  5. 可转债日内高频
  6. 股票趋势动量
  7. ETF轮动套利
  8. 脉冲卖出扫描

 
 
纯粹自己做的记录,便于自己平时复盘。

20230403001.jpg


有兴趣的朋友可以关注公众号交流。

ptrade担保品买卖,融资买入,融券卖出,卖券还款,买券还券 下单后回调函数里面的结构

Ptrade李魔佛 发表了文章 • 0 个评论 • 1420 次浏览 • 2023-03-31 21:44 • 来自相关话题

【ptrade的稳定性,获取行情速度,实盘交易,回测速度无意不秒杀QMT的。
而对于不能安装第三方库的原因,不少菜鸟转而选择了QMT。有点可惜了ptrade。ptrade其实也可以联通外部数据。
ptrade软件设计层面和体验是企业级的,而QMT就呵呵哒,0售后技术支持,软件bug层出不穷。里面的某个别的工程师(袁姓)素质也是底下,我星球上的代码他也抄过去,抄过去后呢 放到他自己付费星球,而且还不止一篇。】
而ptrade相对而言,恒生电子的工程师服务就很到位,发送日志给他们,会在一天内分析结果告知你哪些出现问题了。
 
题外话说多了。
 
ptrade支持两融账户的量化操作。
如:担保品买卖,融资买入,融券卖出,卖券还款,买券还券margin_trade - 担保品买卖

margincash_open - 融资买入

margincash_close - 卖券还款

margincash_direct_refund - 直接还款

marginsec_open - 融券卖出

marginsec_close - 买券还券




它们之间的参数都比较相近:

margin_xxxx(security, amount, limit_price=None)

security:股票代码(str);

amount:交易数量,输入正数(int);

limit_price:买卖限价(float);
 
而用它们进行买卖操作后,在on_trade_response回调函数里面的机构提如下:
 
担保品买入:2023-03-31 14:41:02 - INFO - 生成订单,订单号:cd25d27f39854721aac99db13c9e9b73股票代码:601328.SS 数量:信用买入1000
2023-03-31 14:41:02 - INFO - {'error_info': '', 'stock_code': '601328.SS', 'order_id': 'cd25d27f39854721aac99db13c9e9b73', 'status': '2', 'price': 5.1, 'entrust_type': '9', 'amount': 1000, 'business_amount': 0.0, 'entrust_prop': '0', 'entrust_no': '1', 'order_time': '2023-03-31 14:35:53.776'}
2023-03-31 14:41:02 - INFO - {'business_amount': 1000, 'order_id': 'cd25d27f39854721aac99db13c9e9b73', 'stock_code': '601328.SS', 'entrust_bs': '1', 'entrust_no': '1', 'status': '8', 'business_balance': 5100.0, 'business_price': 5.1, 'business_id': '2', 'business_time': '2023-03-31 14:39:17'} 
 
 
  
 融资买入:2023-03-31 14:52:00 - INFO - 生成订单,订单号:01b7851d37014709bde3ec6ebe9e89c3股票代码:601328.SS 数量:融资买入100
2023-03-31 14:52:00 - INFO - {'price': 5.1, 'entrust_prop': '0', 'status': '2', 'entrust_type': '6', 'stock_code': '601328.SS', 'business_amount': 0.0, 'entrust_no': '3', 'order_time': '2023-03-31 14:46:51.620', 'error_info': '', 'amount': 100, 'order_id': '01b7851d37014709bde3ec6ebe9e89c3'}
2023-03-31 14:52:00 - INFO - {'business_id': '4', 'business_balance': 509.99999999999994, 'business_price': 5.1, 'order_id': '01b7851d37014709bde3ec6ebe9e89c3', 'business_time': '2023-03-31 14:50:14', 'status': '8', 'entrust_bs': '1', 'business_amount': 100, 'entrust_no': '3', 'stock_code': '601328.SS'} 
 
卖券还款2023-03-31 14:58:20 - INFO - start
2023-03-31 14:59:00 - INFO - 生成订单,订单号:20cef28ec52c4d41b09c80fc49167497股票代码:600269.SS 数量:卖券还款-200
2023-03-31 14:59:00 - INFO - {'business_amount': 0.0, 'amount': -200, 'stock_code': '600269.SS', 'error_info': '', 'order_time': '2023-03-31 14:53:51.375', 'price': 3.38, 'entrust_type': '6', 'status': '2', 'order_id': '20cef28ec52c4d41b09c80fc49167497', 'entrust_prop': '0', 'entrust_no': '5'}
2023-03-31 14:59:00 - INFO - {'status': '8', 'business_time': '2023-03-31 14:57:14', 'stock_code': '600269.SS', 'entrust_bs': '2', 'business_id': '6', 'business_balance': -676.0, 'business_amount': -200, 'order_id': '20cef28ec52c4d41b09c80fc49167497', 'business_price': 3.38, 'entrust_no': '5'}
返回的结构体和那个普通账户交易的回调函数基本一致的。
 
  查看全部

【ptrade的稳定性,获取行情速度,实盘交易,回测速度无意不秒杀QMT的。
而对于不能安装第三方库的原因,不少菜鸟转而选择了QMT。有点可惜了ptrade。ptrade其实也可以联通外部数据。
ptrade软件设计层面和体验是企业级的,而QMT就呵呵哒,0售后技术支持,软件bug层出不穷。里面的某个别的工程师(袁姓)素质也是底下,我星球上的代码他也抄过去,抄过去后呢 放到他自己付费星球,而且还不止一篇。】
而ptrade相对而言,恒生电子的工程师服务就很到位,发送日志给他们,会在一天内分析结果告知你哪些出现问题了。
 
题外话说多了。
 
ptrade支持两融账户的量化操作。
如:担保品买卖,融资买入,融券卖出,卖券还款,买券还券
margin_trade - 担保品买卖

margincash_open - 融资买入

margincash_close - 卖券还款

margincash_direct_refund - 直接还款

marginsec_open - 融券卖出

marginsec_close - 买券还券




它们之间的参数都比较相近:

margin_xxxx(security, amount, limit_price=None)

security:股票代码(str);

amount:交易数量,输入正数(int);

limit_price:买卖限价(float);
 
而用它们进行买卖操作后,在on_trade_response回调函数里面的机构提如下:
 
担保品买入:
2023-03-31 14:41:02 - INFO - 生成订单,订单号:cd25d27f39854721aac99db13c9e9b73股票代码:601328.SS 数量:信用买入1000
2023-03-31 14:41:02 - INFO - {'error_info': '', 'stock_code': '601328.SS', 'order_id': 'cd25d27f39854721aac99db13c9e9b73', 'status': '2', 'price': 5.1, 'entrust_type': '9', 'amount': 1000, 'business_amount': 0.0, 'entrust_prop': '0', 'entrust_no': '1', 'order_time': '2023-03-31 14:35:53.776'}
2023-03-31 14:41:02 - INFO - {'business_amount': 1000, 'order_id': 'cd25d27f39854721aac99db13c9e9b73', 'stock_code': '601328.SS', 'entrust_bs': '1', 'entrust_no': '1', 'status': '8', 'business_balance': 5100.0, 'business_price': 5.1, 'business_id': '2', 'business_time': '2023-03-31 14:39:17'}
 
 
 
  
 融资买入:
2023-03-31 14:52:00 - INFO - 生成订单,订单号:01b7851d37014709bde3ec6ebe9e89c3股票代码:601328.SS 数量:融资买入100
2023-03-31 14:52:00 - INFO - {'price': 5.1, 'entrust_prop': '0', 'status': '2', 'entrust_type': '6', 'stock_code': '601328.SS', 'business_amount': 0.0, 'entrust_no': '3', 'order_time': '2023-03-31 14:46:51.620', 'error_info': '', 'amount': 100, 'order_id': '01b7851d37014709bde3ec6ebe9e89c3'}
2023-03-31 14:52:00 - INFO - {'business_id': '4', 'business_balance': 509.99999999999994, 'business_price': 5.1, 'order_id': '01b7851d37014709bde3ec6ebe9e89c3', 'business_time': '2023-03-31 14:50:14', 'status': '8', 'entrust_bs': '1', 'business_amount': 100, 'entrust_no': '3', 'stock_code': '601328.SS'}
 
 
卖券还款
2023-03-31 14:58:20 - INFO - start
2023-03-31 14:59:00 - INFO - 生成订单,订单号:20cef28ec52c4d41b09c80fc49167497股票代码:600269.SS 数量:卖券还款-200
2023-03-31 14:59:00 - INFO - {'business_amount': 0.0, 'amount': -200, 'stock_code': '600269.SS', 'error_info': '', 'order_time': '2023-03-31 14:53:51.375', 'price': 3.38, 'entrust_type': '6', 'status': '2', 'order_id': '20cef28ec52c4d41b09c80fc49167497', 'entrust_prop': '0', 'entrust_no': '5'}
2023-03-31 14:59:00 - INFO - {'status': '8', 'business_time': '2023-03-31 14:57:14', 'stock_code': '600269.SS', 'entrust_bs': '2', 'business_id': '6', 'business_balance': -676.0, 'business_amount': -200, 'order_id': '20cef28ec52c4d41b09c80fc49167497', 'business_price': 3.38, 'entrust_no': '5'}

返回的结构体和那个普通账户交易的回调函数基本一致的。
 
 

Ptrade融资融券双均线 代码 讲解

Ptrade李魔佛 发表了文章 • 0 个评论 • 1704 次浏览 • 2023-03-31 02:08 • 来自相关话题

因为一些融资融券的函数只能在交易模块使用,所以如果需要模拟的话,可以使用模拟端进行交易。
 
def initialize(context):
# 初始化策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = "600300.SS"
set_universe(g.security)

def before_trading_start(context, data):
# 买入标识
g.order_buy_flag = False
# 卖出标识
g.order_sell_flag = False

#当五日均线高于十日均线时买入,当五日均线低于十日均线时卖出
def handle_data(context, data):
# 得到十日历史价格
df = get_history(10, "1d", "close", g.security, fq=None, include=False)
# 得到五日均线价格
ma5 = round(df["close"][-5:].mean(), 3)
# 得到十日均线价格
ma10 = round(df["close"][-10:].mean(), 3)
# 取得昨天收盘价
price = data[g.security]["close"]
# 如果五日均线大于十日均线
if ma5 > ma10:
if not g.order_buy_flag:
# 获取最大可融资数量
amount = get_margincash_open_amount(g.security).get(g.security)
# 进行融资买入操作
margincash_open(g.security, amount)
# 记录这次操作
log.info("Buying %s Amount %s" % (g.security, amount))
# 当日已融资买入
g.order_buy_flag = True

# 如果五日均线小于十日均线,并且目前有头寸
elif ma5 < ma10 and get_position(g.security).amount > 0:
if not g.order_sell_flag:
# 获取标的卖券还款最大可卖数量
amount = get_margincash_close_amount(g.security).get(g.security)
# 进行卖券还款操作
margincash_close(g.security, -amount)
# 记录这次操作
log.info("Selling %s Amount %s" % (g.security, amount))
# 当日已卖券还款
g.order_sell_flag = True  查看全部
因为一些融资融券的函数只能在交易模块使用,所以如果需要模拟的话,可以使用模拟端进行交易。
 
def initialize(context):
# 初始化策略
# 设置我们要操作的股票池, 这里我们只操作一支股票
g.security = "600300.SS"
set_universe(g.security)

def before_trading_start(context, data):
# 买入标识
g.order_buy_flag = False
# 卖出标识
g.order_sell_flag = False

#当五日均线高于十日均线时买入,当五日均线低于十日均线时卖出
def handle_data(context, data):
# 得到十日历史价格
df = get_history(10, "1d", "close", g.security, fq=None, include=False)
# 得到五日均线价格
ma5 = round(df["close"][-5:].mean(), 3)
# 得到十日均线价格
ma10 = round(df["close"][-10:].mean(), 3)
# 取得昨天收盘价
price = data[g.security]["close"]
# 如果五日均线大于十日均线
if ma5 > ma10:
if not g.order_buy_flag:
# 获取最大可融资数量
amount = get_margincash_open_amount(g.security).get(g.security)
# 进行融资买入操作
margincash_open(g.security, amount)
# 记录这次操作
log.info("Buying %s Amount %s" % (g.security, amount))
# 当日已融资买入
g.order_buy_flag = True

# 如果五日均线小于十日均线,并且目前有头寸
elif ma5 < ma10 and get_position(g.security).amount > 0:
if not g.order_sell_flag:
# 获取标的卖券还款最大可卖数量
amount = get_margincash_close_amount(g.security).get(g.security)
# 进行卖券还款操作
margincash_close(g.security, -amount)
# 记录这次操作
log.info("Selling %s Amount %s" % (g.security, amount))
# 当日已卖券还款
g.order_sell_flag = True
 

Ptrade担保品买入卖出

Ptrade李魔佛 发表了文章 • 0 个评论 • 1452 次浏览 • 2023-03-31 01:31 • 来自相关话题

担保品卖出指的是融资融券交易当中,用自有资金进行买卖的行为

 
实际上是买卖股票,但在信用账户上,用只有资金买卖股票。
 
ptrade支持两融操作。
 
比如下面的示例代告诉我们,担保品买入股票的3个不同参数的效果:def initialize(context):
g.security = '600570.SS'
set_universe(g.security)

def handle_data(context, data):
# 以系统最新价委托
margin_trade(g.security, 100)
# 以72块价格下一个限价单
margin_trade(g.security, 100, limit_price=72)
# 以最优五档即时成交剩余撤销委托
margin_trade(g.security, 200, market_type=4) security:股票代码(str);

amount:交易数量,正数表示买入,负数表示卖出(int);

limit_price:买卖限价(float);

market_type:市价委托类型,上证非科创板股票支持参数1、4,上证科创板股票支持参数0、1、2、4,深证股票支持参数0、2、3、4、5(int);

0:对手方最优价格;
1:最优五档即时成交剩余转限价;
2:本方最优价格;
3:即时成交剩余撤销;
4:最优五档即时成交剩余撤销;
5:全额成交或撤单; 查看全部


担保品卖出指的是融资融券交易当中,用自有资金进行买卖的行为


 
实际上是买卖股票,但在信用账户上,用只有资金买卖股票。
 
ptrade支持两融操作。
 
比如下面的示例代告诉我们,担保品买入股票的3个不同参数的效果:
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)

def handle_data(context, data):
# 以系统最新价委托
margin_trade(g.security, 100)
# 以72块价格下一个限价单
margin_trade(g.security, 100, limit_price=72)
# 以最优五档即时成交剩余撤销委托
margin_trade(g.security, 200, market_type=4)
 
security:股票代码(str);

amount:交易数量,正数表示买入,负数表示卖出(int);

limit_price:买卖限价(float);

market_type:市价委托类型,上证非科创板股票支持参数1、4,上证科创板股票支持参数0、1、2、4,深证股票支持参数0、2、3、4、5(int);

0:对手方最优价格;
1:最优五档即时成交剩余转限价;
2:本方最优价格;
3:即时成交剩余撤销;
4:最优五档即时成交剩余撤销;
5:全额成交或撤单;

国信如何运行miniQMT

QMT李魔佛 发表了文章 • 0 个评论 • 2749 次浏览 • 2023-03-30 02:31 • 来自相关话题

国信的QMT名字叫iQuant, 它也有属于自己的miniQMT。
不过它需要额外申请。就看你的经理愿不愿意帮你去申请了。
毕竟申请这个没有资金要求,纯粹看经理的心情了。申请需要打印纸质电子版文件并签字,拍照发给营业部审核。
 
而且开通了miniQMT后,只能拉取数据,无法进行交易,因为个人是没有交易权限的,只有机构才可以申请miniQMT的交易权限。
 这也是经理不愿意帮你开通的原因,他们有可能会说国信目前不支持miniQMT这样的胡话来推搪打发你。如果需要申请开通,可以联系文末二维码开通国信iquant和miniQMT,这位经理比较热心肠,只要申请,就可以帮你开通miniQMT权限。
 
如何打开国信的miniQMT?
 
国信的miniQMT并不是和iQuant绑定的,笔者怀疑是因为iQuant定制化过多,甚至把miniQMT给阉割了。以至于为了补回miniQMT,他们还得特意要下载一个QMT的客户端(其实这个就是其他券商的QMT客户端),然后使用这个客户端和xtquant通讯。
 
 
输入个人的账户和密码后,登录极速版,对,国信的极速版即使miniQMT了。勾选极简模式。 国信的miniQMT支持自动登录,这个比国金的要好。国金的由于没有自动登录,每天还得自己手动的登录一次。(笔者之前也提供了几个版本的自动登录脚本,需要的可以到星球获取)





 





 
 
行情源这里要注意,如果你选择的获取最新价,那么在获取行情数据的返回值里面,只有最新价格,没有5档委托价格。( 国信iquant并没有这个选择菜单,估计是深度定制了,删除了)。
 
由于没有交易权限,账户里面没有显示个人的持仓信息,直接是空白一片





然后把xtquant的文件夹复制到本地的python site-package目录下。用以下下载数据的代码测试一下:
 import pandas as pd
import datetime


def get_tick(code, start_time, end_time, period='tick'):
from xtquant import xtdata

xtdata.download_history_data(code, period=period, start_time=start_time, end_time=end_time)
data = xtdata.get_local_data(field_list=, stock_code=, period=period, count=10)
result_list = data df = pd.DataFrame(result_list)

df['time_str'] = df['time'].apply(lambda x: datetime.datetime.fromtimestamp(x / 1000.0))
return df


def process_timestamp(df, filename):
df = df.set_index('time_str')
result = df.resample('3S').first().ffill()
# result = result[(result.index >= '2022-07-20 09:30') & (result.index <= '2022-07-20 15:00')]
result = result.reset_index()
result.to_csv(filename + '.csv')


def dump_single_code_tick():
# 导出单个转债的tick数据
code='128022'
start_date = '20210113'
end_date = '20210130'

post_fix = 'SZ' if code.startswith('12') else 'SH'
code = '{}.{}'.format(code,post_fix)
filename = '{}'.format(code)
df = get_tick(code, start_date, end_date)
process_timestamp(df, filename)

dump_single_code_tick()保存上述代码为app.py
运行python app.py
 
稍等片刻,数据导出到当前路径,名字为:

128022.sz 
 
打开看一下,数据在csv里面的了。
 
可关注下面关注号; 如需要开通国信,可以后台回复:开通国信证券
 

  查看全部
国信的QMT名字叫iQuant, 它也有属于自己的miniQMT。
不过它需要额外申请。就看你的经理愿不愿意帮你去申请了。
毕竟申请这个没有资金要求,纯粹看经理的心情了。申请需要打印纸质电子版文件并签字,拍照发给营业部审核。
 
而且开通了miniQMT后,只能拉取数据,无法进行交易,因为个人是没有交易权限的,只有机构才可以申请miniQMT的交易权限。
 这也是经理不愿意帮你开通的原因,他们有可能会说国信目前不支持miniQMT这样的胡话来推搪打发你。如果需要申请开通,可以联系文末二维码开通国信iquant和miniQMT,这位经理比较热心肠,只要申请,就可以帮你开通miniQMT权限。
 
如何打开国信的miniQMT?
 
国信的miniQMT并不是和iQuant绑定的,笔者怀疑是因为iQuant定制化过多,甚至把miniQMT给阉割了。以至于为了补回miniQMT,他们还得特意要下载一个QMT的客户端(其实这个就是其他券商的QMT客户端),然后使用这个客户端和xtquant通讯。
 
 
输入个人的账户和密码后,登录极速版,对,国信的极速版即使miniQMT了。勾选极简模式。 国信的miniQMT支持自动登录,这个比国金的要好。国金的由于没有自动登录,每天还得自己手动的登录一次。(笔者之前也提供了几个版本的自动登录脚本,需要的可以到星球获取)

20230330002.jpg

 

20230330001.jpg

 
 
行情源这里要注意,如果你选择的获取最新价,那么在获取行情数据的返回值里面,只有最新价格,没有5档委托价格。( 国信iquant并没有这个选择菜单,估计是深度定制了,删除了)。
 
由于没有交易权限,账户里面没有显示个人的持仓信息,直接是空白一片

20230330003.jpg

然后把xtquant的文件夹复制到本地的python site-package目录下。用以下下载数据的代码测试一下:
 
import pandas as pd
import datetime


def get_tick(code, start_time, end_time, period='tick'):
from xtquant import xtdata

xtdata.download_history_data(code, period=period, start_time=start_time, end_time=end_time)
data = xtdata.get_local_data(field_list=, stock_code=
, period=period, count=10)
result_list = data
    df = pd.DataFrame(result_list)

df['time_str'] = df['time'].apply(lambda x: datetime.datetime.fromtimestamp(x / 1000.0))
return df


def process_timestamp(df, filename):
df = df.set_index('time_str')
result = df.resample('3S').first().ffill()
# result = result[(result.index >= '2022-07-20 09:30') & (result.index <= '2022-07-20 15:00')]
result = result.reset_index()
result.to_csv(filename + '.csv')


def dump_single_code_tick():
# 导出单个转债的tick数据
code='128022'
start_date = '20210113'
end_date = '20210130'

post_fix = 'SZ' if code.startswith('12') else 'SH'
code = '{}.{}'.format(code,post_fix)
filename = '{}'.format(code)
df = get_tick(code, start_date, end_date)
process_timestamp(df, filename)

dump_single_code_tick()
保存上述代码为app.py
运行python app.py
 
稍等片刻,数据导出到当前路径,名字为:

128022.sz 
 
打开看一下,数据在csv里面的了。
 
可关注下面关注号; 如需要开通国信,可以后台回复:开通国信证券
 

 

ptrade QMT 动态止盈卖出 python代码实现

Ptrade李魔佛 发表了文章 • 0 个评论 • 1466 次浏览 • 2023-03-13 23:53 • 来自相关话题

帮你轻松实现自动止盈。
比如设置20%,那么会每天盘中扫描,可以精确到3S 一格,如果你的持仓股的收益率大于20%,它将会帮你自动卖出。
 
占坑 待续 》》》
帮你轻松实现自动止盈。
比如设置20%,那么会每天盘中扫描,可以精确到3S 一格,如果你的持仓股的收益率大于20%,它将会帮你自动卖出。
 
占坑 待续 》》》

ptrade qmt的模拟账户能不用尽量不用,无尽的bug让你浪费时间 怀疑人生

Ptrade李魔佛 发表了文章 • 0 个评论 • 2372 次浏览 • 2023-03-02 15:57 • 来自相关话题

个人平时基本很少用模拟账户。但有时候又没有办法。实盘账户在跑,仓位无法挪腾出来测试(最近折腾的打板策略)
所以临时登录了模拟账户。 里面也挺悲剧的,初始化的500w资金,之前测试的时候随意买入的转债,很多都强赎了。而ptrade里面依然还在,导致大部分是亏损99%以上, 账上只剩可怜的88w,虚拟基金。
 
今天用ptrade获取A股市场所有的股票代码,居然调试了半小时,代码如下
def initialize(context):
# 初始化策略
g.security = "600570.SS"
set_universe(g.security)

def handle_data(context, data):
stock=get_Ashares()
log.info(stock)
输出的stock是[],没有任何数据。





上面的xxxxx is expired , close all positions by system. 是因为模拟账户上退市转债还依然挂在上面,清仓也清不掉。每次跑就循环一分钟输出。。
 
换了个券商的模拟账户,问题依然在,只好倒腾实盘账户。然后问题就解决了。
这个问题,在qmt上就更加严重了。 下次在星球上或者群里慢慢吐槽吧
 
  查看全部
个人平时基本很少用模拟账户。但有时候又没有办法。实盘账户在跑,仓位无法挪腾出来测试(最近折腾的打板策略)
所以临时登录了模拟账户。 里面也挺悲剧的,初始化的500w资金,之前测试的时候随意买入的转债,很多都强赎了。而ptrade里面依然还在,导致大部分是亏损99%以上, 账上只剩可怜的88w,虚拟基金。
 
今天用ptrade获取A股市场所有的股票代码,居然调试了半小时,代码如下
def initialize(context):
# 初始化策略
g.security = "600570.SS"
set_universe(g.security)

def handle_data(context, data):
stock=get_Ashares()
log.info(stock)

输出的stock是[],没有任何数据。

20230302012.jpg

上面的xxxxx is expired , close all positions by system. 是因为模拟账户上退市转债还依然挂在上面,清仓也清不掉。每次跑就循环一分钟输出。。
 
换了个券商的模拟账户,问题依然在,只好倒腾实盘账户。然后问题就解决了。
这个问题,在qmt上就更加严重了。 下次在星球上或者群里慢慢吐槽吧
 
 

qmt position对象里面有哪些属性?

QMT李魔佛 发表了文章 • 0 个评论 • 1583 次浏览 • 2023-02-27 22:12 • 来自相关话题

查看属性的代码:
  obj_list = get_trade_detail_data(ACCOUNT,'stock','position')
for obj in obj_list:
print(obj.m_strInstrumentID,obj.m_strInstrumentName,'----')
# 查看有哪些属性字段
print('='*10)
for item in dir(obj):
if not item.startswith('__'):
print(item)

print('='*10)
得到的position的内置属性有下面的:m_bIsToday
m_dAvgOpenPrice
m_dCloseAmount
m_dCloseProfit
m_dFloatProfit
m_dInstrumentValue
m_dLastPrice
m_dLastSettlementPrice
m_dMargin
m_dMarketValue
m_dOpenCost
m_dOpenPrice
m_dPositionCost
m_dPositionProfit
m_dProfitRate
m_dRealUsedMargin
m_dRedemptionVolume
m_dReferenceRate
m_dRoyalty
m_dSettlementPrice
m_dSingleCost
m_dStaticHoldMargin
m_dStockLastPrice
m_dStructFundVol
m_dTotalCost
m_eFutureTradeType
m_eSideFlag
m_nCanUseVolume
m_nCidIncrease
m_nCidIsDelist
m_nCidRateOfCurrentLine
m_nCidRateOfTotalValue
m_nCloseVolume
m_nCoveredVolume
m_nDirection
m_nEnableExerciseVolume
m_nFrozenVolume
m_nHedgeFlag
m_nLegId
m_nOnRoadVolume
m_nOptCombUsedVolume
m_nPREnableVolume
m_nVolume
m_nYesterdayVolume
m_strAccountID
m_strAccountKey
m_strComTradeID
m_strExchangeID
m_strExchangeName
m_strExpireDate
m_strInstrumentID
m_strInstrumentName
m_strOpenDate
m_strProductID
m_strProductName
m_strStockHolder
m_strTradeID
m_strTradingDay
m_xtTag
虽然有上面的属性,但是实际上很可能是空的,并没有值。






  查看全部
查看属性的代码:
 
    obj_list = get_trade_detail_data(ACCOUNT,'stock','position')
for obj in obj_list:
print(obj.m_strInstrumentID,obj.m_strInstrumentName,'----')
# 查看有哪些属性字段
print('='*10)
for item in dir(obj):
if not item.startswith('__'):
print(item)

print('='*10)

得到的position的内置属性有下面的:
m_bIsToday
m_dAvgOpenPrice
m_dCloseAmount
m_dCloseProfit
m_dFloatProfit
m_dInstrumentValue
m_dLastPrice
m_dLastSettlementPrice
m_dMargin
m_dMarketValue
m_dOpenCost
m_dOpenPrice
m_dPositionCost
m_dPositionProfit
m_dProfitRate
m_dRealUsedMargin
m_dRedemptionVolume
m_dReferenceRate
m_dRoyalty
m_dSettlementPrice
m_dSingleCost
m_dStaticHoldMargin
m_dStockLastPrice
m_dStructFundVol
m_dTotalCost
m_eFutureTradeType
m_eSideFlag
m_nCanUseVolume
m_nCidIncrease
m_nCidIsDelist
m_nCidRateOfCurrentLine
m_nCidRateOfTotalValue
m_nCloseVolume
m_nCoveredVolume
m_nDirection
m_nEnableExerciseVolume
m_nFrozenVolume
m_nHedgeFlag
m_nLegId
m_nOnRoadVolume
m_nOptCombUsedVolume
m_nPREnableVolume
m_nVolume
m_nYesterdayVolume
m_strAccountID
m_strAccountKey
m_strComTradeID
m_strExchangeID
m_strExchangeName
m_strExpireDate
m_strInstrumentID
m_strInstrumentName
m_strOpenDate
m_strProductID
m_strProductName
m_strStockHolder
m_strTradeID
m_strTradingDay
m_xtTag

虽然有上面的属性,但是实际上很可能是空的,并没有值。

20230227004.jpg


 

qmt 可转债 双低(阈值)轮动 实盘代码

QMT李魔佛 发表了文章 • 0 个评论 • 2359 次浏览 • 2023-02-26 15:18 • 来自相关话题

之前在星球埋的坑,答应群友写个qmt的双低可转债的轮动实盘代码。
用已有的ptrade的代码,然后部分获取行情和交易接口按照qmt的接口文档(http://qmt.ptradeapi.com )重写,就给了一版。(对,很早以前就有一版ptrade的转债双低的了)
 
无论是qmt还是ptrade,都只是一个工具,用熟悉了,都无所哪个好哪个不好。





 





 





 
 
完整代码在个人星球。
 
觉得之前星球太便宜了,不仅给了代码,还部署了接口免费使用,通过接口获取可转债的实时数据,强赎天数,规模,溢价率,评级等等一系列数据。 而且随着时间的推移,里面积累的数据,代码也越来越多,感觉这样对前面进去并不断续费的星友有点公平,尽管以后他们续费都直接打折扣。所以还是按照一些大v运营的意见,逐年涨价策略。
越往后的朋友,因为前面积累的内容越多,因此价格也随之增长。
 
当然有能力可以自己写接口,部署,实盘,获取三方数据的大v,就没必要加了。
  查看全部
之前在星球埋的坑,答应群友写个qmt的双低可转债的轮动实盘代码。
用已有的ptrade的代码,然后部分获取行情和交易接口按照qmt的接口文档(http://qmt.ptradeapi.com )重写,就给了一版。(对,很早以前就有一版ptrade的转债双低的了)
 
无论是qmt还是ptrade,都只是一个工具,用熟悉了,都无所哪个好哪个不好。

20230217003.jpg

 

20230226011.jpg

 

20230226012.jpg

 
 
完整代码在个人星球。
 
觉得之前星球太便宜了,不仅给了代码,还部署了接口免费使用,通过接口获取可转债的实时数据,强赎天数,规模,溢价率,评级等等一系列数据。 而且随着时间的推移,里面积累的数据,代码也越来越多,感觉这样对前面进去并不断续费的星友有点公平,尽管以后他们续费都直接打折扣。所以还是按照一些大v运营的意见,逐年涨价策略。
越往后的朋友,因为前面积累的内容越多,因此价格也随之增长。
 
当然有能力可以自己写接口,部署,实盘,获取三方数据的大v,就没必要加了。
 

qmt软件里面的快速计算是在什么模式下使用的?

QMT李魔佛 发表了文章 • 0 个评论 • 1508 次浏览 • 2023-02-25 13:35 • 来自相关话题

QMT 平台模型是根据行情驱动,逐 K 线运行的。
 
即点击运行模型时,模型是从第 0 根 K 线开始运行到最后一根 K 线(如想加快模型运行速度,可以策略编辑器 - 基本信息中设置快速计算,限制计算范围,只计算最新的指定数量的 K 线范围),每根 K 线调用一次 Python 模型中的 handlebar(ContextInfo) 函数。
 
也就是你点击“运行”按钮的时候,如果你的快速计算默认设置的是0,
 
handlebar里面的k线是从2005年1月1日运行的,即使你在代码里面设置了运行时间:
def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2023-02-20 10:00:00'
ContextInfo.end = '2023-02-23 10:00:00'或者在回测参数里面设置的时间:






都是不管用的。
 
需要在代码里添加一句:
if not ContextInfo.is_last_bar():
return 
 
或者 把快速计算的值设置为1, 就只会以最新的k线计算。也就是只会执行1次handlebar。





 
不得不说,qmt的说明文档很让人困惑的。笔者也多次吐槽了。
如果没有编程的朋友,不建议自己折腾了。不少编程大咖都惊呼这软件和文档入门太难,文档太扯淡。
如果需要qmt策略代码 和实盘代码 代写,可以在公众号后台留言:qmt代写
 
 
  查看全部
QMT 平台模型是根据行情驱动,逐 K 线运行的。
 
即点击运行模型时,模型是从第 0 根 K 线开始运行到最后一根 K 线(如想加快模型运行速度,可以策略编辑器 - 基本信息中设置快速计算,限制计算范围,只计算最新的指定数量的 K 线范围),每根 K 线调用一次 Python 模型中的 handlebar(ContextInfo) 函数。
 
也就是你点击“运行”按钮的时候,如果你的快速计算默认设置的是0,
 
handlebar里面的k线是从2005年1月1日运行的,即使你在代码里面设置了运行时间:
def init(ContextInfo):
print("==============start==========")
ContextInfo.start = '2023-02-20 10:00:00'
ContextInfo.end = '2023-02-23 10:00:00'
或者在回测参数里面设置的时间:

20230225001.jpg


都是不管用的。
 
需要在代码里添加一句:
    if not ContextInfo.is_last_bar():
return
 
 
或者 把快速计算的值设置为1, 就只会以最新的k线计算。也就是只会执行1次handlebar。

20230225002.jpg

 
不得不说,qmt的说明文档很让人困惑的。笔者也多次吐槽了。
如果没有编程的朋友,不建议自己折腾了。不少编程大咖都惊呼这软件和文档入门太难,文档太扯淡。
如果需要qmt策略代码 和实盘代码 代写,可以在公众号后台留言:qmt代写
 
 
 

qmt隔夜文件单(python代码实现)实盘代码

QMT李魔佛 发表了文章 • 0 个评论 • 2028 次浏览 • 2023-02-24 14:17 • 来自相关话题

 代码基于iquant平台编写。可以拿去参考参考。# encoding:gbk
import logging
import pandas as pd
from datetime import datetime, timedelta, time
from decimal import InvalidOperation
from decimal import Decimal as D
from READFILE import read_file

logging.basicConfig(level=logging.INFO)
# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 规避 account_callback 的 Racing Condition
RUN_TIME_DELAY = 10

# global FILEPATH, DIR, PRICE, VOL, START_TIME, account
SH_pattern = r'^[1-9]\d{5}\.(sh|SH)$'
SZ_pattern = r'^(?!39)\d{6}\.(sz|SZ)$'
SH_prefix = ['5', '6', '9', '11']
SZ_prefix = ['0', '2', '30', '12', '159']
COLNAMES = ['direction', 'vol', 'price', 'start_time']


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)

ContextInfo.can_order = False
ContextInfo.all_order_done = False

if not load_file_order(ContextInfo):
load_sys_order(ContextInfo)

# load_file_order(ContextInfo)
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
(datetime.now() + timedelta(seconds=RUN_TIME_DELAY)).strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True


def handlebar(ContextInfo):
return


def load_file_order(ContextInfo):
def _price_vol_filtering(row):
if not isinstance(row.start_time, time):
logging.warning('读取{0}指令时间失败: {1}'.format(row.name, row.start_time))
return None
if row.direction not in ['买', '卖']:
logging.warning('读取{0}买卖方向失败: {1}'.format(row.name, row.direction))
return None
try:
# parse start_time
curr_start_time = datetime.now().strftime('%Y-%m-%d ') + row.start_time.strftime('%H:%M:%S')
curr_start_time = datetime.strptime(curr_start_time, '%Y-%m-%d %H:%M:%S')
# parse direction
curr_direction = 23 if row.direction == '买' else 24
# parse price and vol
price = D(row.price)
vol = int(row.vol)
return pd.Series([curr_direction, vol, price, curr_start_time])
except InvalidOperation:
logging.warning("读取 {0} 指令价格失败: {1}".format(row.name, row.price))
return None
except ValueError:
logging.warning('读取 {0} 下单总量失败: {1}'.format(row.name, row.vol))
return None

def _name_parser(asset_name):
# 目前默认用户输入.SH 或.SZ时标的名称正确
if '.SH' in asset_name or '.SZ' in asset_name:
# todo: SH/SZ_pattern regex check here?
return asset_name
else:
raise ValueError('{0} 标的代码不合法'.format(asset_name))

try:
tmp_df = read_file(FILEPATH, names=COLNAMES, index_col=0)
except:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None

tmp_df.index = tmp_df.index.to_series().astype(str)
tmp_df.index = tmp_df.index.str.strip()
tmp_df.index = tmp_df.index.str.upper()
tmp_df.index = tmp_df.index.to_series().apply(_name_parser).dropna()
tmp_df = tmp_df.apply(_price_vol_filtering, axis=1, broadcast=True).dropna()
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return False

tmp_df.set_axis(COLNAMES, axis='columns', inplace=True)
# 挂单成功Flag
tmp_df['finished'] = [False] * tmp_df.shape[0]
ContextInfo.order_df = tmp_df
ContextInfo.set_universe(ContextInfo.order_df.index.tolist())
return True


def load_sys_order(ContextInfo):
try:
asset_name = ContextInfo.stockcode + '.' + ContextInfo.market
ContextInfo.set_universe([asset_name])
direction = 23 if DIR == '买入' else 24
start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
price = D(PRICE)
vol = int(VOL)
except BaseException:
raise ValueError("读取策略面板交易配置失败。请尝试修正挂单配置文件或者策略面板参数。")

price = float(price)
ContextInfo.order_df = pd.DataFrame(data=[direction, vol, price, start_time], index=COLNAMES,
columns=[asset_name]).T
ContextInfo.order_df['finished'] = False
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.all_order_done:
return
for curr_asset in ContextInfo.get_universe():
if not ContextInfo.order_df.loc[curr_asset].finished \
and datetime.now() > ContextInfo.order_df.loc[curr_asset].start_time:
curr_order = ContextInfo.order_df.loc[curr_asset]
direction = int(curr_order.direction)
txt_direction = '买入' if direction == 23 else '卖出'
price = float(D(curr_order.price))
vol = int(curr_order.vol)
order_remark = '隔日文件挂单: 以 {0} {1} {2}'.format(price, txt_direction, curr_asset)
passorder(direction, 1101, ContextInfo.accID, curr_asset, 11, price, vol, order_remark, 1, order_remark,
ContextInfo)
ContextInfo.order_df.loc[curr_asset, 'finished'] = True

ContextInfo.all_order_done = all(ContextInfo.order_df['finished'].tolist())


def order_callback(ContextInfo, orderInfo):
curr_asset = orderInfo.m_strInstrumentID + '.' + orderInfo.m_strExchangeID
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus
if '隔日文件挂单' in curr_remark and curr_status == 57:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:报单废单 (柜台返回失败),原因:{1} 尝试重报'.format(curr_asset, orderInfo.m_strCancelInfo))
elif '隔日文件挂单' in curr_remark and curr_status == 50:
logging.info('{0} 隔日文件挂单:报单成功'.format(curr_asset))
return


def orderError_callback(ContextInfo, orderArgs, errMsg):
curr_asset = orderArgs.orderCode
if '隔日文件挂单' in orderArgs.strategyName:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:账号下单异常 (COS/iQuant校验失败), 错误消息:{1} 尝试重报'.format(curr_asset, errMsg))
return






 把上述代码复制到iquant里面,然后部署到策略运行,运行策略,切换为实盘 查看全部
20230224003.jpg

 代码基于iquant平台编写。可以拿去参考参考。
# encoding:gbk
import logging
import pandas as pd
from datetime import datetime, timedelta, time
from decimal import InvalidOperation
from decimal import Decimal as D
from READFILE import read_file

logging.basicConfig(level=logging.INFO)
# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 规避 account_callback 的 Racing Condition
RUN_TIME_DELAY = 10

# global FILEPATH, DIR, PRICE, VOL, START_TIME, account
SH_pattern = r'^[1-9]\d{5}\.(sh|SH)$'
SZ_pattern = r'^(?!39)\d{6}\.(sz|SZ)$'
SH_prefix = ['5', '6', '9', '11']
SZ_prefix = ['0', '2', '30', '12', '159']
COLNAMES = ['direction', 'vol', 'price', 'start_time']


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)

ContextInfo.can_order = False
ContextInfo.all_order_done = False

if not load_file_order(ContextInfo):
load_sys_order(ContextInfo)

# load_file_order(ContextInfo)
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
(datetime.now() + timedelta(seconds=RUN_TIME_DELAY)).strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True


def handlebar(ContextInfo):
return


def load_file_order(ContextInfo):
def _price_vol_filtering(row):
if not isinstance(row.start_time, time):
logging.warning('读取{0}指令时间失败: {1}'.format(row.name, row.start_time))
return None
if row.direction not in ['买', '卖']:
logging.warning('读取{0}买卖方向失败: {1}'.format(row.name, row.direction))
return None
try:
# parse start_time
curr_start_time = datetime.now().strftime('%Y-%m-%d ') + row.start_time.strftime('%H:%M:%S')
curr_start_time = datetime.strptime(curr_start_time, '%Y-%m-%d %H:%M:%S')
# parse direction
curr_direction = 23 if row.direction == '买' else 24
# parse price and vol
price = D(row.price)
vol = int(row.vol)
return pd.Series([curr_direction, vol, price, curr_start_time])
except InvalidOperation:
logging.warning("读取 {0} 指令价格失败: {1}".format(row.name, row.price))
return None
except ValueError:
logging.warning('读取 {0} 下单总量失败: {1}'.format(row.name, row.vol))
return None

def _name_parser(asset_name):
# 目前默认用户输入.SH 或.SZ时标的名称正确
if '.SH' in asset_name or '.SZ' in asset_name:
# todo: SH/SZ_pattern regex check here?
return asset_name
else:
raise ValueError('{0} 标的代码不合法'.format(asset_name))

try:
tmp_df = read_file(FILEPATH, names=COLNAMES, index_col=0)
except:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return None

tmp_df.index = tmp_df.index.to_series().astype(str)
tmp_df.index = tmp_df.index.str.strip()
tmp_df.index = tmp_df.index.str.upper()
tmp_df.index = tmp_df.index.to_series().apply(_name_parser).dropna()
tmp_df = tmp_df.apply(_price_vol_filtering, axis=1, broadcast=True).dropna()
if tmp_df.empty:
logging.warning('读取挂单配置文件失败或挂单配置文件为空,尝试交易读取配置面板参数')
return False

tmp_df.set_axis(COLNAMES, axis='columns', inplace=True)
# 挂单成功Flag
tmp_df['finished'] = [False] * tmp_df.shape[0]
ContextInfo.order_df = tmp_df
ContextInfo.set_universe(ContextInfo.order_df.index.tolist())
return True


def load_sys_order(ContextInfo):
try:
asset_name = ContextInfo.stockcode + '.' + ContextInfo.market
ContextInfo.set_universe([asset_name])
direction = 23 if DIR == '买入' else 24
start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
price = D(PRICE)
vol = int(VOL)
except BaseException:
raise ValueError("读取策略面板交易配置失败。请尝试修正挂单配置文件或者策略面板参数。")

price = float(price)
ContextInfo.order_df = pd.DataFrame(data=[direction, vol, price, start_time], index=COLNAMES,
columns=[asset_name]).T
ContextInfo.order_df['finished'] = False
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.all_order_done:
return
for curr_asset in ContextInfo.get_universe():
if not ContextInfo.order_df.loc[curr_asset].finished \
and datetime.now() > ContextInfo.order_df.loc[curr_asset].start_time:
curr_order = ContextInfo.order_df.loc[curr_asset]
direction = int(curr_order.direction)
txt_direction = '买入' if direction == 23 else '卖出'
price = float(D(curr_order.price))
vol = int(curr_order.vol)
order_remark = '隔日文件挂单: 以 {0} {1} {2}'.format(price, txt_direction, curr_asset)
passorder(direction, 1101, ContextInfo.accID, curr_asset, 11, price, vol, order_remark, 1, order_remark,
ContextInfo)
ContextInfo.order_df.loc[curr_asset, 'finished'] = True

ContextInfo.all_order_done = all(ContextInfo.order_df['finished'].tolist())


def order_callback(ContextInfo, orderInfo):
curr_asset = orderInfo.m_strInstrumentID + '.' + orderInfo.m_strExchangeID
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus
if '隔日文件挂单' in curr_remark and curr_status == 57:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:报单废单 (柜台返回失败),原因:{1} 尝试重报'.format(curr_asset, orderInfo.m_strCancelInfo))
elif '隔日文件挂单' in curr_remark and curr_status == 50:
logging.info('{0} 隔日文件挂单:报单成功'.format(curr_asset))
return


def orderError_callback(ContextInfo, orderArgs, errMsg):
curr_asset = orderArgs.orderCode
if '隔日文件挂单' in orderArgs.strategyName:
ContextInfo.order_df.loc[curr_asset, 'finished'] = False
ContextInfo.all_order_done = False
logging.error('{0} 隔日文件挂单:账号下单异常 (COS/iQuant校验失败), 错误消息:{1} 尝试重报'.format(curr_asset, errMsg))
return






 把上述代码复制到iquant里面,然后部署到策略运行,运行策略,切换为实盘

qmt的文档写的有点稀烂

QMT李魔佛 发表了文章 • 0 个评论 • 1542 次浏览 • 2023-02-21 12:41 • 来自相关话题

在部署QMT 在线文档的时候,还是忍不住吐槽下它的文档。
 这也是当时不用QMT的一个重要原因。
 
不仅仅是文档,而且还有它的函数接口的涉及。
 
比如最常用的交易函数,passorder综合交易下单 passorder()
用法: passorder(opType, orderType, accountid, orderCode, prType, modelprice, volume[, strategyName, quickTrade, userOrderId], ContextInfo)
里面有11个参数,可选参数有2个。 对于一个常用函数来说,这个参数有点多了。
 
而更为令人费解的,是它参数里面额设定值
比如第一个opType,操作类型。
 
里面有59个数字:期货六键:

0:开多

1:平昨多

2:平今多

3:开空

4:平昨空

5:平今空

期货四键:

6:平多,优先平今

7:平多,优先平昨

8:平空,优先平今

9:平空,优先平昨

期货两键:

10:卖出,如有多仓,优先平仓,优先平今,如有余量,再开空

11:卖出,如有多仓,优先平仓,优先平昨,如有余量,再开空

12:买入,如有空仓,优先平仓,优先平今,如有余量,再开多

13:买入,如有空仓,优先平仓,优先平昨,如有余量,再开多

14:买入,不优先平仓

15:卖出,不优先平仓

股票买卖:

23:股票买入,或沪港通、深港通股票买入

24:股票卖出,或沪港通、深港通股票卖出

融资融券:

27:融资买入

28:融券卖出

29:买券还券

30:直接还券

31:卖券还款

32:直接还款

33:信用账号股票买入

34:信用账号股票卖出

组合交易:

25:组合买入,或沪港通、深港通的组合买入

26:组合卖出,或沪港通、深港通的组合卖出

27:融资买入

28:融券卖出

29:买券还券

31:卖券还款

33:信用账号股票买入

34:信用账号股票卖出

40:期货组合开多

43:期货组合开空

46:期货组合平多,优先平今

47:期货组合平多,优先平昨

48:期货组合平空,优先平今

49:期货组合平空,优先平昨

期权交易:

50:买入开仓

51:卖出平仓

52:卖出开仓

53:买入平仓

54:备兑开仓

55:备兑平仓

56:认购行权

57:认沽行权

58:证券锁定

59:证券解锁
它把期货,股票,期权所有品种压缩到一起,通过参数数字来辨认交易类别。
 
那么我们来看一看一个例子,就拿一个官网的一个例子来说:
 
最简单的例子:passorder(23,1101,account,s,11,14.00,100,2,ContextInfo)
一般人看了上面的代码,里面全部是数字,简直就像灾难一样。 但是我要明白它的交易品种和交易逻辑,
就得对着文档去查,编号23是啥,1101是啥,11,14又是啥。
 
如果我是代码reviewer,底下的员工这种文档,或者写代码的人,提交上这样的代码,绝对100%是要reject这个提交的。
 
然后orderType 更加让人吐血。。
 1101:单股、单账号、普通、股/手方式下单

1102:单股、单账号、普通、金额(元)方式下单(只支持股票)

1113:单股、单账号、总资产、比例 [0 ~ 1] 方式下单

1123:单股、单账号、可用、比例[0 ~ 1]方式下单

1201:单股、账号组(无权重)、普通、股/手方式下单

1202:单股、账号组(无权重)、普通、金额(元)方式下单(只支持股票)

1213:单股、账号组(无权重)、总资产、比例 [0 ~ 1] 方式下单

1223:单股、账号组(无权重)、可用、比例 [0 ~ 1] 方式下单

2101:组合、单账号、普通、按组合股票数量(篮子中股票设定的数量)方式下单 > 对应 volume 的单位为篮子的份

2102:组合、单账号、普通、按组合股票权重(篮子中股票设定的权重)方式下单 > 对应 volume 的单位为元

2103:组合、单账号、普通、按账号可用方式下单 > (底层篮子股票怎么分配?答:按可用资金比例后按篮子中股票权重分配,如用户没填权重则按相等权重分配)只对股票篮子支持

2201:组合、账号组(无权重)、普通、按组合股票数量方式下单

2202:组合、账号组(无权重)、普通、按组合股票权重方式下单



这排列组合,谁能记得住,逼着你去查文档,或者每次复制粘贴旧代码。
 
然后下单 类型,继续来各种枚举:
 -1:无效(实际下单时,需要用交易面板交易函数那设定的选价类型)

0:卖5价

1:卖4价

2:卖3价

3:卖2价

4:卖1价

5:最新价

6:买1价

7:买2价(组合不支持)

8:买3价(组合不支持)

9:买4价(组合不支持)

10:买5价(组合不支持)

11:(指定价)模型价(只对单股情况支持,对组合交易不支持)

12:涨跌停价

13:挂单价

14:对手价

27:市价即成剩撤(仅对股票期权申报有效)

28:市价即全成否则撤(仅对股票期权申报有效)

29:市价剩转限价(仅对股票期权申报有效)

42:最优五档即时成交剩余撤销申报(仅对上交所申报有效)

43:最优五档即时成交剩转限价申报(仅对上交所申报有效)

44:对手方最优价格委托(仅对深交所申报有效)

45:本方最优价格委托(仅对深交所申报有效)

46:即时成交剩余撤销委托(仅对深交所申报有效)

47:最优五档即时成交剩余撤销委托(仅对深交所申报有效)

48:全额成交或撤销委托(仅对深交所申报有效)

49:科创板盘后定价
会不会用常量定义个值给客户调用呢?
 passorder(
ContextInfo.TYPE_STOCK,

ContextInfo.TYPE_BUY,
100,
ContextInfo.LIMIT_PRICE,
ContextInfo)
没有标注类型:
虽然python是若类型的语言,可是qmt底层是c++,有些参数不对,就会导致异常:
比如交易软件:
 
比如下单函数passorder的参数列表:
volume,下单数量(股 / 手 / 元 / %)

passorder(opType, orderType, accountID, orderCode, prType, price, volume, ContextInfo)

根据 orderType 值最后一位确定 volume 的单位:

单股下单时:

1:股 / 手

2:金额(元)

3:比例(%)这个类型如果用了浮点,前面类型用了以股为但是,是会报错的,因为不存在100.11 股这样的非100单位的下单数据。
 
看完不想吐槽了,一群文科生设计的软件。。。





  查看全部
在部署QMT 在线文档的时候,还是忍不住吐槽下它的文档。
 这也是当时不用QMT的一个重要原因。
 
不仅仅是文档,而且还有它的函数接口的涉及。
 
比如最常用的交易函数,passorder
综合交易下单 passorder()
用法: passorder(opType, orderType, accountid, orderCode, prType, modelprice, volume[, strategyName, quickTrade, userOrderId], ContextInfo)

里面有11个参数,可选参数有2个。 对于一个常用函数来说,这个参数有点多了。
 
而更为令人费解的,是它参数里面额设定值
比如第一个opType,操作类型。
 
里面有59个数字:
期货六键:

0:开多

1:平昨多

2:平今多

3:开空

4:平昨空

5:平今空

期货四键:

6:平多,优先平今

7:平多,优先平昨

8:平空,优先平今

9:平空,优先平昨

期货两键:

10:卖出,如有多仓,优先平仓,优先平今,如有余量,再开空

11:卖出,如有多仓,优先平仓,优先平昨,如有余量,再开空

12:买入,如有空仓,优先平仓,优先平今,如有余量,再开多

13:买入,如有空仓,优先平仓,优先平昨,如有余量,再开多

14:买入,不优先平仓

15:卖出,不优先平仓

股票买卖:

23:股票买入,或沪港通、深港通股票买入

24:股票卖出,或沪港通、深港通股票卖出

融资融券:

27:融资买入

28:融券卖出

29:买券还券

30:直接还券

31:卖券还款

32:直接还款

33:信用账号股票买入

34:信用账号股票卖出

组合交易:

25:组合买入,或沪港通、深港通的组合买入

26:组合卖出,或沪港通、深港通的组合卖出

27:融资买入

28:融券卖出

29:买券还券

31:卖券还款

33:信用账号股票买入

34:信用账号股票卖出

40:期货组合开多

43:期货组合开空

46:期货组合平多,优先平今

47:期货组合平多,优先平昨

48:期货组合平空,优先平今

49:期货组合平空,优先平昨

期权交易:

50:买入开仓

51:卖出平仓

52:卖出开仓

53:买入平仓

54:备兑开仓

55:备兑平仓

56:认购行权

57:认沽行权

58:证券锁定

59:证券解锁

它把期货,股票,期权所有品种压缩到一起,通过参数数字来辨认交易类别。
 
那么我们来看一看一个例子,就拿一个官网的一个例子来说:
 
最简单的例子:
passorder(23,1101,account,s,11,14.00,100,2,ContextInfo)

一般人看了上面的代码,里面全部是数字,简直就像灾难一样。 但是我要明白它的交易品种和交易逻辑,
就得对着文档去查,编号23是啥,1101是啥,11,14又是啥。
 
如果我是代码reviewer,底下的员工这种文档,或者写代码的人,提交上这样的代码,绝对100%是要reject这个提交的。
 
然后orderType 更加让人吐血。。
 
1101:单股、单账号、普通、股/手方式下单

1102:单股、单账号、普通、金额(元)方式下单(只支持股票)

1113:单股、单账号、总资产、比例 [0 ~ 1] 方式下单

1123:单股、单账号、可用、比例[0 ~ 1]方式下单

1201:单股、账号组(无权重)、普通、股/手方式下单

1202:单股、账号组(无权重)、普通、金额(元)方式下单(只支持股票)

1213:单股、账号组(无权重)、总资产、比例 [0 ~ 1] 方式下单

1223:单股、账号组(无权重)、可用、比例 [0 ~ 1] 方式下单

2101:组合、单账号、普通、按组合股票数量(篮子中股票设定的数量)方式下单 > 对应 volume 的单位为篮子的份

2102:组合、单账号、普通、按组合股票权重(篮子中股票设定的权重)方式下单 > 对应 volume 的单位为元

2103:组合、单账号、普通、按账号可用方式下单 > (底层篮子股票怎么分配?答:按可用资金比例后按篮子中股票权重分配,如用户没填权重则按相等权重分配)只对股票篮子支持

2201:组合、账号组(无权重)、普通、按组合股票数量方式下单

2202:组合、账号组(无权重)、普通、按组合股票权重方式下单



这排列组合,谁能记得住,逼着你去查文档,或者每次复制粘贴旧代码。
 
然后下单 类型,继续来各种枚举:
 
-1:无效(实际下单时,需要用交易面板交易函数那设定的选价类型)

0:卖5价

1:卖4价

2:卖3价

3:卖2价

4:卖1价

5:最新价

6:买1价

7:买2价(组合不支持)

8:买3价(组合不支持)

9:买4价(组合不支持)

10:买5价(组合不支持)

11:(指定价)模型价(只对单股情况支持,对组合交易不支持)

12:涨跌停价

13:挂单价

14:对手价

27:市价即成剩撤(仅对股票期权申报有效)

28:市价即全成否则撤(仅对股票期权申报有效)

29:市价剩转限价(仅对股票期权申报有效)

42:最优五档即时成交剩余撤销申报(仅对上交所申报有效)

43:最优五档即时成交剩转限价申报(仅对上交所申报有效)

44:对手方最优价格委托(仅对深交所申报有效)

45:本方最优价格委托(仅对深交所申报有效)

46:即时成交剩余撤销委托(仅对深交所申报有效)

47:最优五档即时成交剩余撤销委托(仅对深交所申报有效)

48:全额成交或撤销委托(仅对深交所申报有效)

49:科创板盘后定价

会不会用常量定义个值给客户调用呢?
 
passorder(
ContextInfo.TYPE_STOCK,

ContextInfo.TYPE_BUY,
100,
ContextInfo.LIMIT_PRICE,
ContextInfo)

没有标注类型:
虽然python是若类型的语言,可是qmt底层是c++,有些参数不对,就会导致异常:
比如交易软件:
 
比如下单函数passorder的参数列表:
volume,下单数量(股 / 手 / 元 / %)

passorder(opType, orderType, accountID, orderCode, prType, price, volume, ContextInfo)

根据 orderType 值最后一位确定 volume 的单位:

单股下单时:

1:股 / 手

2:金额(元)

3:比例(%)
这个类型如果用了浮点,前面类型用了以股为但是,是会报错的,因为不存在100.11 股这样的非100单位的下单数据。
 
看完不想吐槽了,一群文科生设计的软件。。。

3fc3af7e327ac67c475223f8424004fd.jpg

 

为什么我的QMT安装目录下没有miniqmt的包xtquant

QMT李魔佛 发表了文章 • 0 个评论 • 1462 次浏览 • 2023-02-20 21:00 • 来自相关话题

今天有位群友,qmt新手,说看了我的公众号,想搞miniQMT,结果发现安装了国盛的QMT之后没有发现xtquant的目录。





 



 
他安装的也是实盘正式版本的QMT。
 
那么问题出现在哪里呢?
 
主要问题在于它没有在qmt内部 下载内置的python库。
 





 
经过这个下载过程后。
 
然后就可以看到有site-packages了





 

 
  查看全部
今天有位群友,qmt新手,说看了我的公众号,想搞miniQMT,结果发现安装了国盛的QMT之后没有发现xtquant的目录。

20230220185141623.png

 
20230220012.jpg

 
他安装的也是实盘正式版本的QMT。
 
那么问题出现在哪里呢?
 
主要问题在于它没有在qmt内部 下载内置的python库。
 

mmexport1676896038788.png

 
经过这个下载过程后。
 
然后就可以看到有site-packages了

20230220013.jpg

 

 
 

qmt iquant最新接口文档

QMT李魔佛 发表了文章 • 0 个评论 • 1775 次浏览 • 2023-02-19 15:16 • 来自相关话题

申请了个二级域名,作为QMT iQuant的接口文档。懒得再去搞新的域名了,凑合这用,和ptrade的接口文档拼在一个根域名下面
 
http://qmt.ptradeapi.com





 





 





 
除了官方的接口文档,还加入了一些个人平时编写的写法与回测,实盘代码。 不定期更新。
 
欢迎关注收藏。 查看全部
申请了个二级域名,作为QMT iQuant的接口文档。懒得再去搞新的域名了,凑合这用,和ptrade的接口文档拼在一个根域名下面
 
http://qmt.ptradeapi.com

20230219003.jpg

 

20230219004.jpg

 

20230219005.jpg

 
除了官方的接口文档,还加入了一些个人平时编写的写法与回测,实盘代码。 不定期更新。
 
欢迎关注收藏。

迅投qmt入门教程(一)

QMT李魔佛 发表了文章 • 0 个评论 • 10128 次浏览 • 2023-02-06 19:43 • 来自相关话题

很早想写一个qmt教程的,无奈平时90%时间都用的ptrade。之前想把教程写好了再发出来,不过这样只会越拖越久,为了让自己填这个坑,先把文章发出来,按照平时正常的量化学习的路径,从简单到复杂。 慢慢记录,形成个系列教程。 有疑问的朋友可以到笔者的公众号或者知识星球去提问吧。(见文末)
 
1. 准备:
 
首先得开一个支持qmt的券商,目前市面上支持qmt的券商越来越丰富了。
 
初学者可以开一个门槛第一点的,一般入金1w-2w 不等,就可以申请开通了。 
 
鉴于以学习为目的,真正投入到实盘中的资金不会很大,所以初始阶段也不一定就找万一免五的券商,毕竟目前要给免五,资金门槛比较高,一般要100w甚至以上。
 
笔者推荐国信,国金的qmt, 门槛只要1-2w就足够了,股票费率在万一,可转债万0.4-万0.5。适合初学者,这两家也可以在虚拟机运行,适合苹果mac的用户。 需要的朋友也可以在公众号后台留言: qmt开通





 
2. 假设已经在券商那里开通了qmt功能,接下来就开始进入教学:
 
这里以国信的qmt(iquant)为例:
 
首先要做的就是下载python库。 这个python库指的是qmt的python库,它的版本是3.6.8; 如果你只用qmt内置的python,你就不用自己到网上下载python安装程序,只需要在qmt的设置里面,点一下按钮,就可以安装python库。这里用默认的系统路径就可以了。
 





 
3. 第一个量化程序 hello world
 
新建策略后:
在编辑器里面输入下面的代码:#encoding:gbk

def init(ContextInfo):
print('hello world')

def handlebar(ContextInfo):
#计算当前主图的cci
print("handle bar")
点击回测:
得到输出结果




 
这里介绍2个概念:(3)Handlebar

handlebar 是整个 Python 模型中的核心执行函数。当模型从数据层获取到运行所需要的数据之后,会对数据集上的每一根 bar,调用一次 handlebar 函数,处理当前这根 bar 上的数据。也就是说,用户模型的核心逻辑都是写在该函数中的,如获取数据,设置下单条件等。在 handlebar 中处理完数据后,用户可以通过 paint 方法将需要绘图输出的结果返回给界面。界面会将输出结果如实的展示出来。 (4)ContextInfo

ContextInfo 是整个 Python 框架中的一个核心对象。它包含了各种与 Python 底层框架交互的 API 方法,也是一个全局的上下文环境,可以在 init 以及 handlebar 这两个函数中自由地传递用户创建的各种自定义数据。





文绉绉的,实际写一个策略,必须包含下面两个函数,而且参数也要一致,参数名随意,不过用默认的就好了。你随便改成没有意义的字符,后面自己看代码也是很麻烦。def init(ContextInfo):
pass

def handlebar(ContextInfo):
pass
 
init 和 handlebar 是 Python 模型中最重要的方法,也是唯二由 C++ 直接调用的方法,所有的执行代码都尽量写在这两个方法中或由其中的函数调用。【个人不太喜欢这样】
 
回测时间设置,在右边的菜单栏,有个回测参数,里面设置时间;在菜单“基本信息”里面 ,可以设置回测的时间间隔,可以使用分钟线,日线,小时等等不同周期,不过无法做到tick的回测。最小的只能到分钟。
 
但是如果你有秒的tick数据,自己写个回测框架也是可以做到秒级的tick级别的回测。很早前笔者就在星球上提供了完整的源码和数据,初学者也可以拿着去改,只要后续更新tick数据,就可以不断的回测策略的最新状态。
 
你写的回测实盘python代码,是保存在本地的文件夹的:
C:\iquant_gx\python, 前面的C:\iquant_gx 是你的iquant安装路径。
 
而且底下也有很多的现成的代码:





 
部分代码可以直接用pycharm就可以打开,没有加密的,但也有一些是加密了的。
比如这个自动逆回购是现成的:





对,这里就有,很多人还到处找人写;# encoding:gbk
import logging
from datetime import datetime, timedelta
from decimal import Decimal as D
from decimal import InvalidOperation

logging.basicConfig(level=logging.INFO)

# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 等待account_callback的时长
# RUN_TIME_DELAY = 30

# how is this not defined in package??
MORNING_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '093000', '%Y%m%d%H%M%S')
MORNING_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '113000', '%Y%m%d%H%M%S')
NOON_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '130000', '%Y%m%d%H%M%S')
NOON_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '153000', '%Y%m%d%H%M%S')

# for SH only
TRANS_COST_1D = D('5e-6')
TRANS_COST_LONG = D('1.5e-7')
TRANS_COST_MAX = 100

# ORDER LIMITS
SH_UPPER = 1e7
SH_LOWER = 1e5
SZ_UPPER = 1e8
SZ_LOWER = 1e3

# ASSET NAME DICT
SH_REV_REPO = {'上交所1天': '204001.SH', '上交所2天': '204002.SH', '上交所3天': '204003.SH',
'上交所4天': '204004.SH', '上交所7天': '204007.SH', '上交所14天': '204014.SH',
'上交所28天': '204028.SH', '上交所91天': '204091.SH', '上交所182天': '204182.SH',
}

SZ_REV_REPO = {'深交所3天': '131800.SZ', '深交所7天': '131801.SZ', '深交所14天': '131802.SZ',
'深交所28天': '131803.SZ', '深交所91天': '131805.SZ', '深交所182天': '131806.SZ',
'深交所4天': '131809.SZ', '深交所1天': '131810.SZ', '深交所2天': '131811.SZ',
}


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)
ContextInfo.use_all_cap = False if ALL_CAP == '否' else True

# global trading control, set to False if detected error on user's side
# stop() does not halt strat
ContextInfo.order_control = False

if not ContextInfo.use_all_cap:
try:
ContextInfo.dollar_vol = float(D(DOLLAR_VOL))
except InvalidOperation:
ContextInfo.order_control = True
raise ValueError('读取资金量失败')
else:
if DOLLAR_VOL != '':
logging.warning('已设定使用全部账户资金,忽略所设置资金量')

try:
ContextInfo.start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
ContextInfo.asset_name = SH_REV_REPO[ASSET_NAME]
except KeyError:
ContextInfo.asset_name = SZ_REV_REPO[ASSET_NAME]
except ValueError as error:
if 'unconverted data remains' in str(error):
ContextInfo.order_control = True
raise ValueError('读取挂单时间失败')

if not (MORNING_END > ContextInfo.start_time >= MORNING_START) \
and not (NOON_END > ContextInfo.start_time >= NOON_START):
ContextInfo.order_control = True
raise ValueError('挂单时间不在可交易时间内')

ContextInfo.can_order = False
ContextInfo.order_done = False

if not ContextInfo.order_control:
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
ContextInfo.start_time.strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True
if ContextInfo.use_all_cap:
ContextInfo.dollar_vol = accountInfo.m_dAvailable
else:
if ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('下单额度大于账户可用资金')

# check if order satisfies lower limit for each exchange
if ('SH' in ContextInfo.asset_name and ContextInfo.dollar_vol < SH_LOWER) \
or ('SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol < SZ_LOWER):
ContextInfo.order_control = True
raise ValueError('下单额度低于交易所最低限额')

# checks dollar_vol and rounds the total amount
if 'SH' in ContextInfo.asset_name and ContextInfo.dollar_vol % SH_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SH_LOWER) * SH_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))
elif 'SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol % SZ_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SZ_LOWER) * SZ_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))

'''
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.dollar_vol // SH_UPPER)
remain_order = ContextInfo.dollar_vol - num_batch_order * SH_UPPER
if ContextInfo.asset_name == '204001.SH':
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_1D
else:
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_LONG
if transaction_cost + ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('可用资金不足以垫付交易金额与手续费')
'''

ContextInfo.remain_vol = ContextInfo.dollar_vol


def handlebar(ContextInfo):
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.order_control:
return

if not ContextInfo.order_done:
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.remain_vol // SH_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SH_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SH_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SH_UPPER, order_remark, 1,
order_remark, ContextInfo)
else:
num_batch_order = int(ContextInfo.remain_vol // SZ_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SZ_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SZ_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SZ_UPPER, order_remark, 1,
order_remark, ContextInfo)

order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(remain_order, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, remain_order, order_remark, 1,
order_remark, ContextInfo)

ContextInfo.remain_vol = 0
ContextInfo.order_done = True


def order_callback(ContextInfo, orderInfo):
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus

if '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 57:
ContextInfo.order_done = False
# up the leftover dollar vol by failed amount
# logging.info('reported trade amount:{0}, reported_trade_volume:{1}'.format(orderInfo.m_dTradeAmount, orderInfo.m_nVolumeTotal))
# 单张100元
ContextInfo.remain_vol += orderInfo.m_nVolumeTotal * 100
if '交易时间不合法' in orderInfo.m_strCancelInfo:
ContextInfo.order_control = True
raise ValueError('国债逆回购:未能在交易时间内完成下单,停止报单。余量{0}元未报'.format(ContextInfo.remain_vol))
logging.warning('国债逆回购:报单废单,原因:\"{0}\",尝试重报'.format(orderInfo.m_strCancelInfo))
elif '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 50:
logging.info('国债逆回购:报单{0}元成功'.format(orderInfo.m_nVolumeTotal * 100))
return




待续,不定期更新


 
 
公众号:

星球:

 
 
 
  查看全部
很早想写一个qmt教程的,无奈平时90%时间都用的ptrade。之前想把教程写好了再发出来,不过这样只会越拖越久,为了让自己填这个坑,先把文章发出来,按照平时正常的量化学习的路径,从简单到复杂。 慢慢记录,形成个系列教程。 有疑问的朋友可以到笔者的公众号或者知识星球去提问吧。(见文末)
 
1. 准备:
 
首先得开一个支持qmt的券商,目前市面上支持qmt的券商越来越丰富了。
 
初学者可以开一个门槛第一点的,一般入金1w-2w 不等,就可以申请开通了。 
 
鉴于以学习为目的,真正投入到实盘中的资金不会很大,所以初始阶段也不一定就找万一免五的券商,毕竟目前要给免五,资金门槛比较高,一般要100w甚至以上。
 
笔者推荐国信,国金的qmt, 门槛只要1-2w就足够了,股票费率在万一,可转债万0.4-万0.5。适合初学者,这两家也可以在虚拟机运行,适合苹果mac的用户。 需要的朋友也可以在公众号后台留言: qmt开通

20230206005.jpg

 
2. 假设已经在券商那里开通了qmt功能,接下来就开始进入教学:
 
这里以国信的qmt(iquant)为例:
 
首先要做的就是下载python库。 这个python库指的是qmt的python库,它的版本是3.6.8; 如果你只用qmt内置的python,你就不用自己到网上下载python安装程序,只需要在qmt的设置里面,点一下按钮,就可以安装python库。这里用默认的系统路径就可以了。
 

20230206006.jpg

 
3. 第一个量化程序 hello world
 
新建策略后:
在编辑器里面输入下面的代码:
#encoding:gbk

def init(ContextInfo):
print('hello world')

def handlebar(ContextInfo):
#计算当前主图的cci
print("handle bar")

点击回测:
得到输出结果
20230206007.jpg

 
这里介绍2个概念:
(3)Handlebar

handlebar 是整个 Python 模型中的核心执行函数。当模型从数据层获取到运行所需要的数据之后,会对数据集上的每一根 bar,调用一次 handlebar 函数,处理当前这根 bar 上的数据。也就是说,用户模型的核心逻辑都是写在该函数中的,如获取数据,设置下单条件等。在 handlebar 中处理完数据后,用户可以通过 paint 方法将需要绘图输出的结果返回给界面。界面会将输出结果如实的展示出来。
 
(4)ContextInfo

ContextInfo 是整个 Python 框架中的一个核心对象。它包含了各种与 Python 底层框架交互的 API 方法,也是一个全局的上下文环境,可以在 init 以及 handlebar 这两个函数中自由地传递用户创建的各种自定义数据。





文绉绉的,实际写一个策略,必须包含下面两个函数,而且参数也要一致,参数名随意,不过用默认的就好了。你随便改成没有意义的字符,后面自己看代码也是很麻烦。
def init(ContextInfo):
pass

def handlebar(ContextInfo):
pass

 
init 和 handlebar 是 Python 模型中最重要的方法,也是唯二由 C++ 直接调用的方法,所有的执行代码都尽量写在这两个方法中或由其中的函数调用。【个人不太喜欢这样】
 
回测时间设置,在右边的菜单栏,有个回测参数,里面设置时间;在菜单“基本信息”里面 ,可以设置回测的时间间隔,可以使用分钟线,日线,小时等等不同周期,不过无法做到tick的回测。最小的只能到分钟。
 
但是如果你有秒的tick数据,自己写个回测框架也是可以做到秒级的tick级别的回测。很早前笔者就在星球上提供了完整的源码和数据,初学者也可以拿着去改,只要后续更新tick数据,就可以不断的回测策略的最新状态。
 
你写的回测实盘python代码,是保存在本地的文件夹的:
C:\iquant_gx\python, 前面的C:\iquant_gx 是你的iquant安装路径。
 
而且底下也有很多的现成的代码:

20230206008.jpg

 
部分代码可以直接用pycharm就可以打开,没有加密的,但也有一些是加密了的。
比如这个自动逆回购是现成的:

20230206010.jpg

对,这里就有,很多人还到处找人写;
# encoding:gbk
import logging
from datetime import datetime, timedelta
from decimal import Decimal as D
from decimal import InvalidOperation

logging.basicConfig(level=logging.INFO)

# 挂单失败后的等待时长,以秒计
TIMEOUT_ON_FAIL_SEC = 30
# 等待account_callback的时长
# RUN_TIME_DELAY = 30

# how is this not defined in package??
MORNING_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '093000', '%Y%m%d%H%M%S')
MORNING_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '113000', '%Y%m%d%H%M%S')
NOON_START = datetime.strptime(datetime.now().strftime('%Y%m%d') + '130000', '%Y%m%d%H%M%S')
NOON_END = datetime.strptime(datetime.now().strftime('%Y%m%d') + '153000', '%Y%m%d%H%M%S')

# for SH only
TRANS_COST_1D = D('5e-6')
TRANS_COST_LONG = D('1.5e-7')
TRANS_COST_MAX = 100

# ORDER LIMITS
SH_UPPER = 1e7
SH_LOWER = 1e5
SZ_UPPER = 1e8
SZ_LOWER = 1e3

# ASSET NAME DICT
SH_REV_REPO = {'上交所1天': '204001.SH', '上交所2天': '204002.SH', '上交所3天': '204003.SH',
'上交所4天': '204004.SH', '上交所7天': '204007.SH', '上交所14天': '204014.SH',
'上交所28天': '204028.SH', '上交所91天': '204091.SH', '上交所182天': '204182.SH',
}

SZ_REV_REPO = {'深交所3天': '131800.SZ', '深交所7天': '131801.SZ', '深交所14天': '131802.SZ',
'深交所28天': '131803.SZ', '深交所91天': '131805.SZ', '深交所182天': '131806.SZ',
'深交所4天': '131809.SZ', '深交所1天': '131810.SZ', '深交所2天': '131811.SZ',
}


def init(ContextInfo):
ContextInfo.accID = account
ContextInfo.set_account(ContextInfo.accID)
ContextInfo.use_all_cap = False if ALL_CAP == '否' else True

# global trading control, set to False if detected error on user's side
# stop() does not halt strat
ContextInfo.order_control = False

if not ContextInfo.use_all_cap:
try:
ContextInfo.dollar_vol = float(D(DOLLAR_VOL))
except InvalidOperation:
ContextInfo.order_control = True
raise ValueError('读取资金量失败')
else:
if DOLLAR_VOL != '':
logging.warning('已设定使用全部账户资金,忽略所设置资金量')

try:
ContextInfo.start_time = datetime.strptime(datetime.now().strftime('%Y%m%d') + str(START_TIME), '%Y%m%d%H%M%S')
ContextInfo.asset_name = SH_REV_REPO[ASSET_NAME]
except KeyError:
ContextInfo.asset_name = SZ_REV_REPO[ASSET_NAME]
except ValueError as error:
if 'unconverted data remains' in str(error):
ContextInfo.order_control = True
raise ValueError('读取挂单时间失败')

if not (MORNING_END > ContextInfo.start_time >= MORNING_START) \
and not (NOON_END > ContextInfo.start_time >= NOON_START):
ContextInfo.order_control = True
raise ValueError('挂单时间不在可交易时间内')

ContextInfo.can_order = False
ContextInfo.order_done = False

if not ContextInfo.order_control:
ContextInfo.run_time("place_order", "{0}nSecond".format(TIMEOUT_ON_FAIL_SEC),
ContextInfo.start_time.strftime('%Y-%m-%d %H:%M:%S'), 'SH')


def account_callback(ContextInfo, accountInfo):
if not ContextInfo.can_order:
ContextInfo.can_order = True
if ContextInfo.use_all_cap:
ContextInfo.dollar_vol = accountInfo.m_dAvailable
else:
if ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('下单额度大于账户可用资金')

# check if order satisfies lower limit for each exchange
if ('SH' in ContextInfo.asset_name and ContextInfo.dollar_vol < SH_LOWER) \
or ('SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol < SZ_LOWER):
ContextInfo.order_control = True
raise ValueError('下单额度低于交易所最低限额')

# checks dollar_vol and rounds the total amount
if 'SH' in ContextInfo.asset_name and ContextInfo.dollar_vol % SH_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SH_LOWER) * SH_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))
elif 'SZ' in ContextInfo.asset_name and ContextInfo.dollar_vol % SZ_LOWER != 0:
ContextInfo.dollar_vol = (ContextInfo.dollar_vol // SZ_LOWER) * SZ_LOWER
logging.warning('下单额度已规整为:{0}'.format(ContextInfo.dollar_vol))

'''
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.dollar_vol // SH_UPPER)
remain_order = ContextInfo.dollar_vol - num_batch_order * SH_UPPER
if ContextInfo.asset_name == '204001.SH':
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_1D
else:
transaction_cost = TRANS_COST_MAX * num_batch_order + remain_order * TRANS_COST_LONG
if transaction_cost + ContextInfo.dollar_vol > accountInfo.m_dAvailable:
ContextInfo.order_control = True
raise ValueError('可用资金不足以垫付交易金额与手续费')
'''

ContextInfo.remain_vol = ContextInfo.dollar_vol


def handlebar(ContextInfo):
return


def place_order(ContextInfo):
if not ContextInfo.can_order or ContextInfo.order_control:
return

if not ContextInfo.order_done:
if 'SH' in ContextInfo.asset_name:
num_batch_order = int(ContextInfo.remain_vol // SH_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SH_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SH_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SH_UPPER, order_remark, 1,
order_remark, ContextInfo)
else:
num_batch_order = int(ContextInfo.remain_vol // SZ_UPPER)
remain_order = ContextInfo.remain_vol - num_batch_order * SZ_UPPER
for _ in range(num_batch_order):
order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(SZ_UPPER, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, SZ_UPPER, order_remark, 1,
order_remark, ContextInfo)

order_remark = '国债逆回购:尝试报单{0}元 {1}'.format(remain_order, ContextInfo.asset_name)
passorder(24, 1102, ContextInfo.accID, ContextInfo.asset_name, 5, -1, remain_order, order_remark, 1,
order_remark, ContextInfo)

ContextInfo.remain_vol = 0
ContextInfo.order_done = True


def order_callback(ContextInfo, orderInfo):
curr_remark = orderInfo.m_strRemark
curr_status = orderInfo.m_nOrderStatus

if '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 57:
ContextInfo.order_done = False
# up the leftover dollar vol by failed amount
# logging.info('reported trade amount:{0}, reported_trade_volume:{1}'.format(orderInfo.m_dTradeAmount, orderInfo.m_nVolumeTotal))
# 单张100元
ContextInfo.remain_vol += orderInfo.m_nVolumeTotal * 100
if '交易时间不合法' in orderInfo.m_strCancelInfo:
ContextInfo.order_control = True
raise ValueError('国债逆回购:未能在交易时间内完成下单,停止报单。余量{0}元未报'.format(ContextInfo.remain_vol))
logging.warning('国债逆回购:报单废单,原因:\"{0}\",尝试重报'.format(orderInfo.m_strCancelInfo))
elif '国债逆回购' in curr_remark and ContextInfo.asset_name in curr_remark and curr_status == 50:
logging.info('国债逆回购:报单{0}元成功'.format(orderInfo.m_nVolumeTotal * 100))
return




待续,不定期更新


 
 
公众号:

星球:

 
 
 
 

qmt界面的运行和回测按钮功能有什么不同?

QMT李魔佛 发表了文章 • 0 个评论 • 1372 次浏览 • 2023-02-06 19:00 • 来自相关话题

他们二者的区别:
 
在模型编辑器中,有“回测”和“运行”两个按钮,分别代表两种模式,它们之间的区别如下:
(1)回测模式指策略以历史行情为依据,以回测参数中的开始时间、结束时间为回测时间区间进行运
算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表
现。

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

注:如果需要向模拟/实盘柜台发送真实的委托,请将策略加入到“模型交易”中。
盘后运行可能会有抽风现象。

回测的时候日期问题,只能选副图,不知道为何 查看全部

20230206004.jpg

他们二者的区别:
 
在模型编辑器中,有“回测”和“运行”两个按钮,分别代表两种模式,它们之间的区别如下:
(1)回测模式指策略以历史行情为依据,以回测参数中的开始时间、结束时间为回测时间区间进行运
算,投资者可观察该策略在历史行情所获得的年化收益率、夏普比率、最大回撤、信息比率等指标表
现。

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

注:如果需要向模拟/实盘柜台发送真实的委托,请将策略加入到“模型交易”中。
盘后运行可能会有抽风现象。

回测的时候日期问题,只能选副图,不知道为何

Ptrade基本期货策略

Ptrade李魔佛 发表了文章 • 0 个评论 • 1612 次浏览 • 2023-02-04 14:17 • 来自相关话题

ptrade本身支持期货交易,开通账户绑定就可以了。
新建策略的时候选择:期货即可。





 
 
 1. 买入开仓
 
不同期货品种每一跳的价格变动都不一样,limit_price入参的时候要参考对应品种的价格变动规则,如limit_price不做入参则会以交易的行情快照最新价或者回测的分钟最新价进行报单;

根据交易所规则,每天结束时会取消所有未完成交易;
 
 
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#买入开仓
buy_open('IF1712.CCFX', 1)

#买入开仓(限定点数为52220)
buy_open('CU1806.XSGE', 1, limit_price=52220)
2. 卖出平仓
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#卖出平仓
sell_close('IF1712.CCFX', 1)
#卖出平今仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220, close_today=True)
#卖出平仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220)
3. 获取合约信息
get_instruments- 获取合约信息
 
get_instruments(contract)


返回

FutureParams对象,主要返回的字段为:

contract_code -- 合约代码,str类型;
contract_name -- 合约名称,str类型;
exchange -- 交易所:大商所、郑商所、上期所、中金所,str类型;
trade_unit -- 交易单位,int类型;
contract_multiplier -- 合约乘数,float类型;
delivery_date -- 交割日期,str类型;
listing_date -- 上市日期,str类型;
trade_code -- 交易代码,str类型;
margin_rate -- 保证金比例,float类型;

 
代码示例:
def initialize(context):
g.security = ["CU2112.XSGE", "IF2112.CCFX"]
set_universe(g.security)

def before_trading_start(context, data):
# 获取股票池代码合约信息
for security in g.security:
info = get_instruments(security)
log.info(info)

def handle_data(context, data):
pass 查看全部
ptrade本身支持期货交易,开通账户绑定就可以了。
新建策略的时候选择:期货即可。

20230204005.jpg

 
 
 1. 买入开仓
 
不同期货品种每一跳的价格变动都不一样,limit_price入参的时候要参考对应品种的价格变动规则,如limit_price不做入参则会以交易的行情快照最新价或者回测的分钟最新价进行报单;

根据交易所规则,每天结束时会取消所有未完成交易;
 
 
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#买入开仓
buy_open('IF1712.CCFX', 1)

#买入开仓(限定点数为52220)
buy_open('CU1806.XSGE', 1, limit_price=52220)

2. 卖出平仓
def initialize(context):
g.security = ['IF1712.CCFX', 'CU1806.XSGE']
set_universe(g.security)

def handle_data(context, data):
#卖出平仓
sell_close('IF1712.CCFX', 1)
#卖出平今仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220, close_today=True)
#卖出平仓(限定点数为52220)
sell_close ('CU1806.XSGE', 1, limit_price=52220)

3. 获取合约信息
get_instruments- 获取合约信息
 
get_instruments(contract)


返回

FutureParams对象,主要返回的字段为:

contract_code -- 合约代码,str类型;
contract_name -- 合约名称,str类型;
exchange -- 交易所:大商所、郑商所、上期所、中金所,str类型;
trade_unit -- 交易单位,int类型;
contract_multiplier -- 合约乘数,float类型;
delivery_date -- 交割日期,str类型;
listing_date -- 上市日期,str类型;
trade_code -- 交易代码,str类型;
margin_rate -- 保证金比例,float类型;


 
代码示例:
def initialize(context):
g.security = ["CU2112.XSGE", "IF2112.CCFX"]
set_universe(g.security)

def before_trading_start(context, data):
# 获取股票池代码合约信息
for security in g.security:
info = get_instruments(security)
log.info(info)

def handle_data(context, data):
pass