QTYX系统简介
股票量化交易系统QTYX是一个即可以用于学习,也可以用于实战炒股分析的系统。
分享QTYX系统目的是提供给大家一个搭建量化系统的模版,最终帮助大家搭建属于自己的系统。因此我们提供源码,可以根据自己的风格二次开发。
关于QTYX的使用攻略可以查看链接:QTYX使用攻略
QTYX一直迭代更新,当前版本V2.9.9。后续升级版本会同步更新文档内容。
功能概述
QTYX内置了一款“六边形”量化交易框架(集成了“策略&回测&仓位&风控&下单&标注BS”为一体)。
这套框架包含如下模块:
实时扫描交易品种分钟数据
根据择时策略产生交易信号
可视化标注策略BS交易点
根据止盈止损值产生交易信号
通过仓位管理分配下单数量
连接QMT接口自动下单
打通回测框架,实盘前可以回测择时策略,评估策略的效果
支持股票和ETF
可添加自己的择时策略到框架中
为什么要支持ETF?ETF兼具股票和指数基金的特色,既能获得股票一样的超额收益,也具备指数稳定的特点。买ETF相当于购买了一篮子股票,能分散投资并降低投资风险。另外,ETF还能买到海外市场的指数,有些ETF还能够T+0交易,非常灵活!
本篇攻略我们分享下这套框架的使用方法,以及如何在框架中添加自己的策略。
如何使用
我们点击“策略导航—>实盘监测—>股票池监控/ETF池T+0”。
选择“ETF池T+0”是启用ETF框架,选择“股票池监控”是启用股票池框架。
然后会出现一个操作对话框,如下所示:
接下来,我们介绍下界面上的功能。这里的功能同时适用于ETF和股票框架。
开始日期&结束日期:根据时间范围返回对应的ETF/股票分钟数据。实盘时结束时间保持最新日期。
股票周期:支持1分钟、5分钟、15分钟、30分钟、60分钟级别扫描ETF/股票择时信号
发送邮件使能:ETF/股票出现买卖信号后邮件通知,记得json文件填写邮箱信息。如何填写邮箱信息,下文有具体介绍。
止盈止损使能:ETF/股票触发止盈止损条件时自动卖出,记得json文件填写参数
自动交易使能:ETF/股票出现买卖信号后直接下单,记得json文件填写参数
“设置买入滑点”:在当前价格的基础上增加滑点,避免市场波动而出现买不进的情况。设置为0时,现价直接买入。
“设置买入股数”:可以选择按总资金比例分配买入和按股数买入,记得json文件填写参数
“设置卖出滑点”:在当前价格的基础上增加滑点,避免市场波动而出现卖不出的情况。设置为0时,现价直接卖出。
“设置卖出股数”:实盘时卖出该股的股数,目前出现信号全部卖出。
“择时策略”:选择当前运行的策略,目前预置了“MACD金叉死叉”、“布林带突破”等4个策略
点击“开始扫描”后,程序就开始监测ETF/股票池中是否有出现交易信号了。结束时需要先点击“停止扫描”,然后再退出。
可以从对话框中看到,159509、513300监测到卖出信号,但是在账户中未持有,未触发自动卖出。
当触发止损信号时,如果159509、513300这些ETF在账户中持有,QTYX自动卖出。
当出现止盈止损交易信号时,系统会链接上QMT客户端(提前登录QMT客户端,并且在configfiles/trade_para.json文件中填写下单参数),自动卖出ETF。
建议提前在QTYX“交易”界面中测试下QMT下单是否成功!
一顿卖出后,QTYX监测到账户中已经清仓了这些ETF!159509、513300这些ETF未在账户中持有,不会监测止盈止损信号。
参数配置
关于QMT自动下单相关的配置,主要是客户端安装路径和账号。打开configfiles/trade_para.json文件手动更改。配置完成后,可以在“交易”界面上测试下单接口是否配置成功。
我们把miniQMT的驱动移植到了QTYX/TradeDrv目录下,这样就可以和QMT客户端进行互动。整体的实现原理在miniqmt_if.py文件中,大家可以参看一下。
ETF/股票池,已经搬运至ConfigFiles/trade_para.json文件中,请按格式填写,“percent”的值表示买入资金占总资金的比例,“amount”的值表示买入的股数。
关于ETF/股票止盈止损参数。止盈止损是交易领域中是不可或缺的风险管理方法,有助于限制损失、锁定利润。我们在ConfigFiles/trade_para.json文件中按格式填写,此处我们填写止盈是4%,止损是3%,大家可以根据自己的风险偏好填写。
关于策略,我们在StrategyGath\SignalGath.py文件中预置了多个策略,大家可以在这个文件中使用Python语言添加和修改。后续我们也会不断往这个接口中添加和优化策略,比如指数通行红绿灯策略等等。
策略的关键参数,我们在ConfigFiles/trade_para.json文件中按格式填写,比如“MACD金叉死叉”的周期和“布林带突破”的上下轨倍数等。
如何回测
我们点击“回测参数”标签页,填入ETF代码(注意格式xxxxxx.SH/SZ),选择策略,然后点击“开始回测”。
接下来填写回测参数,比如回测日期、数据周期、初始资金、滑点、手续费等等。
填写完成后,点击“确认”就会出现可视化回测结果。
点击“交易日志”可以查看具体的交易明细。
回测的策略与实盘框架同源,是在StrategyGath\SignalGath.py文件中预置的策略。
标记策略BS点
在“量化”主页面中,我们看到左边有“策略导航”树形列表,“衍生指标”中列出了目前添加的择时策略。
衍生指标可以把择时策略的交易信号在K线图上标注出来,这样一来,同一个策略可以分别在实盘交易框架、回测评估框架、信号图形化框架中使用!
比如点击“布林带突破”策略作为演示,然后会跳出对话框,选择股票数据的参数,比如起始日期、周期、复权选项等等。
点击确认后,会出现图形化界面,界面上会标注出股票数据中全部的买卖信号,比如突破上轨/跌破下轨,出现的日期等,效果图如下所示,
可以清楚看到,每当股价跌破下轨时分仓买入,突破上轨时分仓卖出,这个套利思路非常稳!
比如点击“均线交叉”策略作为演示,如下所示:
关于策略,我们在StrategyGath\SignalGath.py文件中预置了多个策略,大家可以在这个文件中使用Python语言添加和修改。后续我们也会不断往这个接口中添加和优化策略,比如指数通行红绿灯策略等等。
策略的关键参数,我们在ConfigFiles/trade_para.json文件中按格式填写,比如“MACD金叉死叉”的周期和“布林带突破”的上下轨倍数等。
刚才提到同一个策略是可以分别用在实盘交易框架、回测评估框架、信号图形化框架中使用!
比如回测的效果图:
比如实盘交易的效果图:
远程报告配置
实盘时发现该股已经符合止盈止损交易条件时,会远程发送信息提醒。(要记得在ConfigFiles/sys_para.json中填写邮箱信息,在微信上开启QQ邮箱提醒功能,效果如同微信提醒)
如何填写邮箱信息:
发送邮件和核心是SMTP(Simple Mail Transfer Protocol)协议,它是一组用于由源地址到目的地址的邮件传输规则。
Python真的是什么都能做,它对SMTP进行了简单的封装,只需用到两个模块,就可以轻松实现发送纯文本邮件、HTML邮件以及带附件的邮件。
哪两个模块呢?Python内置的email模块负责构建邮件,另一个smtplib模块负责发送邮件。
常规的流程,先把涉及到的模块全部导入进来,如下所示:
首先用MIMEText()构造一个最简单的纯文本邮件,其中第一个参数是邮件正文,第二个参数是内容的类型,比如'plain'表示纯文本邮件,'html'表示HTML邮件。
创建的邮件对象中,要添加From、To和Subject这些属性,否则就不是一封完整的邮件,比如会出现邮件没有主题,发件人的名称为匿名,明明收到了邮件却提示不在收件人中这些情况。
典型的例程如下所示:
再来说说负责发送邮件的smtplib模块,这个模块主要是用smtplib.SMTP()类去连接SMTP服务器,然后发送邮件。
例程中我们会用到几个常用的方法,比如set_debuglevel(1)打印和SMTP服务器交互的所有信息。login()登录SMTP服务器,sendmail()方法发邮件。
典型例程如下所示:
这里的password是个比较容易混淆的地方。不是邮箱登陆的密码,而是授权码。
第三方客户端登录QQ邮箱时是需要授权码的,包括其他邮箱也都一样,比如126、163邮箱等等。授权码可以认为是一个专用密码,适用于登录以下服务:POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务。
如何设置呢?以QQ邮箱为例,我们在QQ邮件的帮助中心找到了方法。
在个人邮箱页面进入[设置] -> [帐户] 页面找到入口,然后把POP3/IMAP/SMTP这几个服务开启。
开启的时候有验证密保环节,需要发送短信,接着就获取到授权码,在第三方客户端的密码栏里面输入这16位授权码进行验证即可。
这样一来邮件就发送成功了!
添加自定义策略
我们在StrategyGath\SignalGath.py文件中预置了多个策略。如果有新的策略可以在这个文件中使用Python语言添加和修改。
我们在ConfigFiles/trade_para.json文件中按格式填写策略参数,比如“MACD金叉死叉”的周期和“布林带突破”的上下轨倍数等。
我们以"MACD金叉死叉"为例进行讲解。
完整的策略逻辑代码如下所示:
@ind.route_types(u"MACD金叉死叉")
def macd_corss_detect(stock_dat, **kwargs):
# 检测当前是否有交叉信号
fast_period, slow_period, signal_period, run_mode = int(kwargs["快速移动平均线周期"]), int(kwargs["慢速移动平均线周期"]), int(kwargs["信号线周期"]), kwargs["模式"]
dif, dea, hist = talib.MACD(stock_dat['Close'], fastperiod=fast_period, slowperiod=slow_period, signalperiod=signal_period)
stock_dat["list_diff"] = np.sign(dif - dea)
# 金叉为1 死叉为-1 中间为0
stock_dat["Signal"] = np.sign(stock_dat["list_diff"] - stock_dat["list_diff"].shift(1))
if run_mode == "实盘":
curtime = stock_dat.index[-1].strftime("%Y-%m-%d %H:%M:%S")
if stock_dat.loc[stock_dat.index[-1], "Signal"] < 0:
cont = f"当前时间 {curtime} 出现死叉!!!建议:卖出!\n"
elif stock_dat.loc[stock_dat.index[-1], "Signal"] > 0:
cont = f"当前时间 {curtime} 出现金叉!!!建议:买入!\n"
else:
cont = f"无金叉/死叉"
return cont+"\n"
else:
stock_dat['Signal'] = stock_dat.Signal.shift(1) # 当天出信号则第二天买入
stock_dat['Signal'].fillna(method='ffill', inplace=True) # 与前面元素值保持一致
stock_dat['Signal'].fillna(value=0, inplace=True) # 序列最前面几个NaN值用0填充
return stock_dat
完整的策略参数设置如下所示:
"策略参数": { "MACD金叉死叉": {
"快速移动平均线周期": 12,
"慢速移动平均线周期": 26,
"信号线周期": 9
}
}
策略逻辑中的名称要和配置文件中保持一致。
把配置文件中策略的参数导入到策略逻辑中,名称要保持一致。
编写策略买卖信号。stock_dat["Signal"]字段存储交易信号,1是买入,-1是卖出,0是保持。
# 检测当前是否有交叉信号
fast_period, slow_period, signal_period, run_mode = int(kwargs["快速移动平均线周期"]), int(kwargs["慢速移动平均线周期"]), int(kwargs["信号线周期"]), kwargs["模式"]
dif, dea, hist = talib.MACD(stock_dat['Close'], fastperiod=fast_period, slowperiod=slow_period, signalperiod=signal_period)
stock_dat["list_diff"] = np.sign(dif - dea)
# 金叉为1 死叉为-1 中间为0
stock_dat["Signal"] = np.sign(stock_dat["list_diff"] - stock_dat["list_diff"].shift(1))
stock_dat是一个dataframe格式数据,我们打印出来如下所示:
Open Close High Low 涨跌幅 涨跌额 Volume 成交额 振幅 换手率 list_diff Signal
date
2024-11-27 09:45:00 1.08 1.08 1.10 1.08 -0.37 -4.00e-03 2315 2.51e+05 1.47 0.15 NaN NaN
2024-11-27 10:00:00 1.08 1.08 1.08 1.08 -0.09 -1.00e-03 7549 8.18e+05 0.18 0.48 NaN NaN
2024-11-27 10:15:00 1.08 1.08 1.08 1.08 -0.28 -3.00e-03 1594 1.72e+05 0.55 0.10 NaN NaN
2024-11-27 10:30:00 1.08 1.08 1.08 1.08 0.28 3.00e-03 120 1.30e+04 0.37 0.01 NaN NaN
2024-11-27 10:45:00 1.08 1.08 1.08 1.08 0.18 2.00e-03 220 2.39e+04 0.18 0.01 NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ...
2025-01-10 11:00:00 1.06 1.06 1.06 1.06 -0.19 -2.00e-03 69 7.33e+03 0.19 0.00 -1.0 0.0
2025-01-10 11:15:00 1.06 1.06 1.06 1.06 0.09 1.00e-03 23100 2.45e+06 0.09 1.47 -1.0 0.0
2025-01-10 11:30:00 1.06 1.07 1.07 1.06 0.38 4.00e-03 14010 1.49e+06 0.38 0.89 -1.0 0.0
2025-01-10 13:15:00 1.07 1.06 1.07 1.06 -0.28 -3.00e-03 8112 8.63e+05 0.28 0.52 -1.0 0.0
2025-01-10 13:30:00 1.06 1.06 1.06 1.06 0.00 0.00e+00 0 0.00e+00 0.00 0.00 1.0 1.0
[506 rows x 12 columns]
如果是实盘模式的话,有交易信号时,cont 中要包含字符串“买入”或者“卖出”关键字。
if run_mode == "实盘":
curtime = stock_dat.index[-1].strftime("%Y-%m-%d %H:%M:%S")
if stock_dat.loc[stock_dat.index[-1], "Signal"] < 0:
cont = f"当前时间 {curtime} 出现死叉!!!建议:卖出!\n"
elif stock_dat.loc[stock_dat.index[-1], "Signal"] > 0:
cont = f"当前时间 {curtime} 出现金叉!!!建议:买入!\n"
else:
cont = f"无金叉/死叉"
return cont+"\n"
回测时返回的是dataframe格式的序列。
stock_dat['Signal'] = stock_dat.Signal.shift(1) # 当天出信号则第二天买入
stock_dat['Signal'].fillna(method='ffill', inplace=True) # 与前面元素值保持一致
stock_dat['Signal'].fillna(value=0, inplace=True) # 序列最前面几个NaN值用0填充
return stock_dat
下单接口
本套量化框架中涉及的自动交易接口是QMT。关于如何使用QMT,可以查看以下这篇使用攻略!
如何QMT开户可以看这篇介绍:量化交易自动下单方案—对接QMT已出炉
说明
想要加入知识星球《玩转股票量化交易》的小伙伴记得先微信call我获取福利!
知识星球介绍点击:知识星球《玩转股票量化交易》精华内容概览