【手把手教你】使用qstock实现量化策略选股

6bfdd1b527ed142114d44a60f265de54.gif

qstock简介

qstock由“Python金融量化”公众号开发,试图打造成个人量化投研分析开源库,目前包括数据获取(data)、可视化(plot)、选股(stock)和量化回测(backtest)四个模块。其中数据模块(data)数据来源于东方财富网、同花顺、新浪财经等网上公开数据。qstock致力于为用户提供更加简洁和规整化的金融市场数据接口。可视化模块基于plotly.express和pyecharts包,为用户提供基于web的交互图形简单操作接口;选股模块提供了同花顺的技术选股和公众号策略选股,包括RPS、MM趋势、财务指标、资金流模型等,回测模块为大家提供向量化(基于pandas)和基于事件驱动的基本框架和模型。

qstock目前在pypi官网上发布,开源第一版本为1.1.0,目前更新至1.3.3。读者第一次安装,可以直接在cmd上输入“pip install qstock ”进行安装,如已安装旧版本,需要通过’pip install –upgrade qstock’进行更新。

GitHub地址:https://github.com/tkfy920/qstock。

目前部分策略选股和策略回测功能仅供知识星球会员使用,会员可在知识星球置顶帖子上上获取qstock-vip-1.3.3.tar.gz (强化版)安装包,将安装包放在工作路径下输入’pip install qstock-vip-1.3.3.tar.gz’进行离线安装。

更新后的最新版本qstock 1.3.3,所有接口函数(包括可视化plot、选股stock)均可通过qstock调用,即先导入import qstock as qs,然后使用qs.xxx,xxx为对应接口函数,如qs.kline(df)画K线图,qs.get_data(‘代码’)获取数据。

1a540c5f66631c17282c71a91cc67487.gif

a2befe8268cd9f615915cec70a9f4439.gif

数据模块

#导入qstock包
import qstock as qs

获取代码/名称函数接口:get_code(market='沪深A股')

获取某市场交易标的代码和名称。

market表示行情名称或列表,默认沪深A股;'沪深京A':沪深京A股市场; '沪深A':沪深A股市场;'沪A':沪市A股市场;'深A':深市A股市场;北A :北证A股市场;'可转债':沪深可转债市场; '期货':期货市场;'创业板':创业板市场行情;'美股':美股市场;'港股':港股市场;'中概股':中国概念股市场;'新股':沪深新股市场; '科创板':科创板市场;'沪股通' 沪股通市场;'深股通':深股通市场;'行业板块':行业板块市场;'概念板块':概念板块市场;'沪深指数':沪深系列指数市场;'上证指数':上证系列指数市场; '深证指数':深证系列指数市场;'ETF' ETF基金市场;'LOF' LOF 基金市场

25878fc3b21adfbc28afe340772103f2.gif

codes=qs.get_code()
#查看前几行代码
codes[:5]
['300392', '300123', '300288', '301132', '300890']
names=qs.get_name()
#查看前几行代码
names[:5]
['*ST腾信', '亚光科技', '朗玛信息', '满坤科技', '翔丰华']
#获取沪深A股市场名称代码字典
name_code=qs.get_name_code()
#获取ETF基金市场名称代码字典
name_code=qs.get_name_code(market='ETF')

指数数据接口 获取多个指数行情面板数据

get_index_data(code_list, start='19000101', end=None, freq='d')
获取多个指数收盘价数据(截面数据)

get_index_price(code_list,start='19000101', end=None, freq='d')

code_list:指数代码(多个指数代码的list),其他参数与个股get_data类似

5368fd48486d8510b514c1adda3138da.gif

#获取沪深指数代码
index_code=qs.get_code('沪深指数')
#获取前两个指数数据
#qs.get_index_data(index_code[:2])
#获取前10个指数价格数据
df=qs.get_index_price(index_code[:10])
df.tail()

32188f187f87d986fc070754360f6d65.png

data=df.pct_change()['2020':].apply(lambda s:(1+s).cumprod())
qs.line(data)

b44c886193b801d9b82a75595f61b9f6.jpeg

关于qstock的数据、可视化、选股等详细教程请参阅以下推文:

【qstock开源了】数据篇之行情交易数据

【qstock数据篇】行业概念板块与资金流

【qstock量化】数据篇之股票基本面数据

【qstock量化】数据篇之宏观指标和财经新闻文本

【qstock量化】动态交互数据可视化

【qstock量化】技术形态与概念热点选股池

18adaa7491ef19e3546253dce9408e0b.gif

量化选股

选股涉及两个方面,一是公司分析,包括财务状况、发展潜力和成长性等,这方面是俗称的基本面分析,可以参考的资料已经汗牛充栋;二是股票分析(包括股价技术形态分析)。

股票分析主要回答三个问题:  

(1)如何判断一只股票有投资价值?  

(2)如何从股票池中选出符合自己认为有价值的股票?  

(3)选出合适的股票后如何构建投资组合并动态调整?  

总体思维:多层次多角度分析  

多角度保证在市场大方向上看对的正确率尽可能增加,多层次可以和多角度相互验证,获取超额收益。通过自上而下的分析框架确定投资方向,选择符合投资方向的最优标的。

量价形态选股

PART 01

#获取沪深全市场A股代码
codes=qs.get_code()
#获取沪深全市场A股2020年以来行情数据后复权价格
all_data=qs.get_data(code_list=codes,start='20200101',fqt=2)

定义选股函数。主要基于价格和成交量的在时间周期上的走势突破,具体参数可根据个人风险偏好和经验修改。

import signal
from tqdm import tqdm
from func_timeout import func_set_timeout
import multitasking
signal.signal(signal.SIGINT, multitasking.killall)
def find_price_vol_stock(data,n=60,rr=0.5):
    up_list=[]
    codes=data['code'].unique()
    pbar = tqdm(total=len(codes))

    @multitasking.task
    @func_set_timeout(5)
    def run(code):
        df=data[data.code==code]
        close=df['close']
        vol=df['volume']
        #价格突破前n日新高
        pn=close[-n:]
        p=close.iloc[-1] #当前价格
        p0=close[-n:-3].min() #前n-3日最低价
        p1=close[-n:-3].max() #前n-3日最高价
        #n日期间价格最大回撤
        md=((pn.cummax()-pn)/pn.cummax()).max()
        #n日期间内价格回测不超过50%
        #欧奈尔设置为12%-15%,最高33%,牛市中可设置40%-50%
        c1=md<rr
        c2=close[-n:-3].idxmax()<close[-n:-3].idxmin()
        #价格突破
        #从低点到当前股价上涨幅度至少在30%以上
        c3=p/p0-1>0.3
        c4=p1<p<p1*(1+rr)
        #近期成交量平均放大两倍以上
        c5=vol[-5:].mean()/vol[-n:-5].mean()>2.0
        c=c1&c2&c3&c4&c5
        if c:
            up_list.append(code)
        else:
            pass
        pbar.update()

    for code in codes:
        try:
            run(code)
        except:
            continue
    multitasking.wait_for_tasks()
    return up_list
stocks=find_price_vol_stock(all_data,n=60,rr=0.5)

选股结果。

stocks
['001318','300755','600458','002669','300848','002059',
 '002561','603000','600506','601698']

K线走势可视化。

qs.HA_kline(qs.get_data(stocks[0]))

05ae9378e81cc5bcbe92078fabf4f5de.jpeg

注意:以下策略选股功能仅供知识星球会员使用,即qstock-vip-1.3.3.tar.gz (强化版)安装包才有下面的选股函数可以调用。

RPS选股

PART 02

RPS(欧奈尔中文书是RS),即股票股价走势横截面(与市场其他个股对比)相对强弱,本质是动量策略。一般建议将RPS价格动量结合公司基本面进行选股。

股价相对强度RPS评级:衡量某一股票在过去n日内(如120、250)内相对股市中其他股票的表现(收益率)。市场上的每一只股票都被指定了1-99范围内的某一数值,99代表相对强度最高,RS值为99,说明该股票在收益率表现方面比其他99%的公司更为优秀。寻找真正的领军股,避免上涨滞后和跟风股。欧奈尔建议选择RPS值80或90以上(二八法则),价格形态合适的股票。一旦大盘下跌彻底结束,最先反弹到价格新高的股票基本上就是要寻找的真正领军股。普通股票的突破行为会持续约13周,而最优秀的股票通常在前3周或前4周就突破出来。注意,根据价格形态选股有失败的可能,一旦股价低于买入价的10%,立即卖出止损。

58d0a004b030081049ea6d5fae373ed0.gif

#获取沪深全市场A股
codes=qs.get_code()
#获取沪深全市场A股2020年以来后复权价格数据
prices=qs.get_price(code_list=codes,start='20200101',fqt=2)

计算rps排序。

rps=qs.RPS(prices)
df_rps=rps.date_rps()
#使用RPS大于90以上选股,可以将股票池从几千只缩小成几百只
#再结合公司基本面进一步选股
len(df_rps[df_rps.rps_120>90])
495
rps.plot_stock_rps('宝明科技')

1b57834f3370e4d3a8c88a767a97fb5c.jpeg

借助RPS相对强弱指标可以选择出中短期强势股

df_rps.sort_values('rps_20',ascending=False)[:10]

#根据5或20日筛选短期强势股
#根据250/120排名可以选择中长期强势股
df_rps.sort_values('rps_250',ascending=False)[:10]

58a37b822370b3a5efb3b01cb74b342e.jpeg

250日RPS大于90股票池

rps_result=df_rps.query('rps_250>90')
print(f'120日RPS大于90个股数量:{len(rps_result)}')
120日RPS大于90个股数量:495

MM趋势选股

PART 03

其中MM趋势参考文章:

https://zhuanlan.zhihu.com/p/165379657。

股票价格高于150天均线和200天均线

150日均线高于200日均线

200日均线上升至少1个月

50日均线高于150日均线和200日均线

股票价格高于50日均线

股票价格比52周低点高30%

股票价格在52周高点的25%以内

相对强弱指数(RS)大于等于70,这里的相对强弱指的是股票与大盘对比,RS = 股票1年收益率 / 基准指数1年收益率。将最后一条去掉,改成结合RPS的相对强弱选股,选择rps_120大于90的个股。

7ab7125b56248fcdba008aea0816c674.gif


MM趋势选股池

mm_trend=prices.apply(qs.MM_trend).T
mm_result=mm_trend.query('满足条件==1')
mm_result

2158525ada6561f16e00c4da8f75f913.jpeg

MM趋势+120日RPS>90

import pandas as pd
mm_rps_result=pd.concat([mm_result,df_rps.query('rps_120>90')],join='inner',axis=1)
mm_rps_result

22f99f1936df7c8e28453163332da8c8.jpeg

mm_rps_result.sort_values('rps_250',ascending=False)[:10]

36efcf814b68acca224e035a753d58ea.jpeg

根据上述价格技术指标筛选后满足条件的个股数量仍较多,这时可以结合公司基本面进一步选股。

资金流选股

PART 04

某段时间内的资金流向反映了股票供求关系,而传统的量价无法区分市场微观结构的流动性和私有信息对股价的影响。资金流向及价格走势可以分为四种基本状况:

价格上升,同时单位时间内资金主动性净流入:这种情况下属于强势,未来价格继续上升概率更大;

股价上升,同时单位时间内资金主动性净流出:这种情况下属于中强势,未来价格继续上升的速度大幅减弱;

股价下跌,同时单位时间内资金主动性净流入:这种情况下属于弱势,未来价格继续下跌概率更大;

股价下跌,同时单位时间内资金主动性净流出:这种情况下属于中弱势,未来价格继续下跌的速度大幅减弱;

资金流向的计算有两种算法:一是如果当前单子的成交价是以对手价或超价成交的,买入成交价 >= 卖一价,代表买家更愿意以较高的价格完成交易,即计入资金主动性流入;二是如果当前成交价格 > 上次成交价格,那么可以理解为,当前的成交量主动推升了价格的上涨,即计入资金主动性流入。

对于强势股而言,最近周期内主力资金累计净流入应为正值

参考资料《量化投资—策略与技术》

12a4feaa08b8f438476f2bcf44eea855.gif

资金流选股池

此处设置时间周期为3、5、10、20、60日,参数可根据市场情况和自身经验不断调整。

qs.stock_money('中国平安',[3,5,10,20,60]).tail()

5067026465d039448b8e690c2a57d216.jpeg

筛选当前日期时间周期内(时间周期默认为[1、3、5、10、20、60]日)

#code_list=qs.moneyflow_stock(mm_rps_result.index)
print(f'最近1、3、5、10、20、60日主力资金累计净流入均大于0个股数量:{len(code_list)}')


MM趋势+RPS+资金流

MM趋势+RPS+资金流选股池

mm_rps_result.loc[(set(mm_rps_result.index)&set(code_list))]
#输出结果为空,表示没有同时满足两种条件的个股

基本财务指标选股

PART 05

获取沪深A股基本财务指标数据。

codes=qs.get_code()
basics_df=qs.stock_basics(code_list=codes)

财务指标条件选股

#净利润大于3千万。避开亏损或净利润较小的个股
c1=basics_df['净利润']>3e7
#流通市值大于100亿元。目前各行业进入头部垄断市场,小市值企业很难逆袭,选择流通市值100亿以上个股
c2=basics_df['流通市值']>1e10
#市盈率
c3=(0<basics_df['市盈率(动)'])&(basics_df['市盈率(动)']<30)
#ROE权益收益率大于20%
c4=basics_df['ROE']>20
#毛利率
c5=basics_df['毛利率']>20
#净利率
c6=basics_df['净利率']>15
#市净率小于10
c7=basics_df['市净率']<10
c=c1&c2&c3&c4&c5&c6&c7
#以净利率排名,查看前十
basics_result=basics_df[c]

选股结果。

basics_result.sort_values('净利率',ascending=False)

dfe572878998768eafe2297e125b8b14.jpeg

1a26e1b4525c62021567c9d29171d5c9.png

关于Python金融量化

a51a38cc34e77d7126f86b3f2b179565.png

专注于分享Python在金融量化领域的应用。加入知识星球,可以免费获取qstock源代码、30多g的量化投资视频资料、量化金融相关PDF资料、公众号文章Python完整源码、与博主直接交流、答疑解惑等。添加个人微信sky2blue2可获取相关优惠。

4182a8e07f3e3c65843897f8208e7cfb.jpeg

猜你喜欢

转载自blog.csdn.net/ndhtou222/article/details/128229551