请选择 进入手机版 | 继续访问电脑版
楼主: tkfy920
5258 11

[交易策略] 【Python量化】如何利用欧奈尔的RPS寻找强势股? [推广有奖]

  • 8关注
  • 38粉丝

Python金融量化

讲师

49%

还不是VIP/贵宾

-

威望
0
论坛币
466 个
通用积分
22.2061
学术水平
27 点
热心指数
25 点
信用等级
19 点
经验
64933 点
帖子
473
精华
0
在线时间
513 小时
注册时间
2008-3-28
最后登录
2024-3-15

tkfy920 在职认证  学生认证  发表于 2019-3-20 20:29:19 |显示全部楼层 |坛友微信交流群
相似文件 换一批

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
真正的领军股,它们往往是在接近或位于新的股价高点之上时才开始大规模涨势的,而不是在接近新的低点或是从高点巨量跌落之后才转跌为升的。——威廉·欧奈尔《笑傲股市》

1引言
股票市场经常流传着一句话:“强者恒强”。最近两个多月A股市场交投火热,大部分股票出现了巨幅反弹甚至创出2015年以来的新高,尤其是以东方通信为代表的妖股,120日收益率翻了五倍。强者恒强背后的逻辑可以用大家熟知的“马太效应”和“二八法则”来解释。马太效应来自圣经《新约·马太福音》中的一则寓言: “凡有的,还要加给他叫他多余;没有的,连他所有的也要夺过来。”二八法则是意大利经济学家帕累托1897年提出来的,揭示了20%的人占有80%社会财富的一种不平等。同样道理,市场总是朝着阻力最小的路径走,而主力运作个股也需要沿着阻力最小的路径去操作。所以市场20%的股票涨势往往超过80%的股票,80%的资金总是追逐20%的股票。因此,看上去价格高、风险大的股票,反而能够再创新高;而看上去价格低、风险小的股票,则通常继续走低。这也是“强者愈强,弱者愈弱”的表现。那么如何选出“强势股”呢?本文将为大家介绍威廉·欧奈尔的RPS选股方法,重点是如何使用Python实现RPS指标的计算、排序和可视化,筛选出市场的强势股,寻找下一波行情的大黑马。


截至2019年3月19日,创业板指数30日收益率接近40%



2欧奈尔的RPS指标
威廉·欧奈尔是美国股市的传奇人物,驰骋股票市场数十年长盛不衰,并自创了一套投资体系,通过《笑傲股市》一书为广大散户带来了投资希望。电子书可在公众号Python金融量化后台回复“笑傲江湖”免费下载。

RPS英文全称Relative Price Strength Rating,即股价相对强度,该指标是欧奈尔CANSLIM选股法则中的趋势分析,具有很强的实战指导意义。RPS指标是指在一段时间内,个股涨幅在全部股票涨幅排名中的位次值。
比如A股共有3500只股票,若某只股票的120日涨幅在所有股票中排名第350位,则该股票的RPS值为:(1-350/3500)*100=90。

RPS的值代表该股的120日涨幅超过其他90%的股票的涨幅。通过该指标可以反映个股股价走势在同期市场中的表现相对强弱。RPS的值介于0-100之间,在过去的一年中,所有股票的涨幅排行中,前1%的股票的RPS值为99至100,前2%的股票的RPS值为98至99,以此类推。RPS时间周期可以自己根据需要进行调整,常用的有60日(3个月)、120日(半年)和250日(一年)等。


3使用Python计算RPS
RPS的计算公式很简单,难的是对RPS指标的具体应用,需要大量的实战经验积累和严格的操作纪律。下面给出从数据获取、数据处理、指标计算和可视化的Python核心代码。

#先引入后面可能用到的library
import pandas as pd  
import tushare as ts
import matplotlib.pyplot as plt
%matplotlib inline   

#正常显示画图时出现的中文和负号
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False

#使用之前先输入token,可以从个人主页上复制出来,
#每次调用数据需要先运行该命令
token='输入你在tushare获得的token'
ts.set_token(token)
pro=ts.pro_api()


数据来源于tushare,首先使用stock_basic获取当前交易日的所有股票代码。截至2019年3月19日,一共有3594只股票。

df = pro.stock_basic(exchange='', list_status='L',
    fields='ts_code,symbol,name,area,industry,list_date')
print(len(df))
#输出结果:3594


考虑到A股新股上市交易的情况,上市后前一段时间往往会一字涨停,然后出现下跌调整。为了剔除新股次新股的影响,这里选择2017年1月1日前上市的股票作为分析样本,共得到3024只股票。

#排除掉新股次新股,这里是只考虑2017年1月1日以前上市的股票
df=df[df['list_date'].apply(int).values<20170101]
len(df)
#输出结果:3024

#获取当前所有非新股次新股代码和名称
codes=df.ts_code.values
names=df.name.values
#构建一个字典方便调用
code_name=dict(zip(names,codes))

#使用tushare获取上述股票周价格数据并转换为周收益率
#设定默认起始日期为2018年1月5日,结束日期为2019年3月19日
#日期可以根据需要自己改动
def get_data(code,start='20180101', end='20190319'):
    df=pro.daily(ts_code=code, start_date=start, end_date=end,fields='trade_date,close')
    #将交易日期设置为索引值
    df.index=pd.to_datetime(df.trade_date)
    df=df.sort_index()
    #计算收益率
    return df.close


通过定义的函数获取上述3024只股票自2018年1月5日以来的所有日交易数据,并计算每只股票120日滚动收益率。

#构建一个空的dataframe用来装数据
data=pd.DataFrame()
for name,code in code_name.items():
    data[name]=get_data(code)

#data.to_csv('daily_data.csv',encoding='gbk')
#data=pd.read_csv('stock_data.csv',encoding='gbk',index_col='trade_date')
#data.index=(pd.to_datetime(data.index)).strftime('%Y%m%d')

#计算收益率
def cal_ret(df,w=5):
    '''w:周5;月20;半年:120; 一年250
    '''
    df=df/df.shift(w)-1
    return df.iloc[w:,:].fillna(0)

经过这一轮的大幅上涨,截至2019年3月19日,上述3024只股票中,有49只股票120日收益率超过100%,占比1.68%;收益率在20%-100%之间的股票有1280只,占比达到43.99%;仍有360只股票120日收益率为负数。

ret120=cal_ret(data,w=120)

#计算RPS
def get_RPS(ser):
    df=pd.DataFrame(ser.sort_values(ascending=False))
    df['n']=range(1,len(df)+1)
    df['rps']=(1-df['n']/len(df))*100
    return df
#计算每个交易日所有股票滚动w日的RPS
def all_RPS(data):
    dates=(data.index).strftime('%Y%m%d')
    RPS={}
    for i in range(len(data)):
        RPS[dates]=pd.DataFrame(get_RPS(data.iloc).values,columns=['收益率','排名','RPS'],index=get_RPS(data.iloc).index)  
    return RPS  

rps120=all_RPS(ret120)

#获取所有股票在某个期间的RPS值
def all_data(rps,ret):
    df=pd.DataFrame(np.NaN,columns=ret.columns,index=ret.index)
    for date in ret.index:
        date=date.strftime('%Y%m%d')
        d=rps[date]
        for c in d.index:
            df.loc[date,c]=d.loc[c,'RPS']
    return df

#构建一个以前面收益率为基础的空表
df_new=pd.DataFrame(np.NaN,columns=ret120.columns,index=ret120.index)


计算所有股票在每一个交易日的向前120日滚动RPS值。对股票价格走势和RPS进行可视化。

for date in df_new.index:
    date=date.strftime('%Y%m%d')
    d=rps120[date]
    for c in d.index:
        df_new.loc[date,c]=d.loc[c,'RPS']

def plot_rps(stock):
    plt.subplot(211)
    data[stock][120:].plot(figsize=(16,16),color='r')
    plt.title(stock+'股价走势',fontsize=15)
    plt.yticks(fontsize=12)
    plt.xticks([])
    ax = plt.gca()  
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    plt.subplot(212)
    df_new[stock].plot(figsize=(16,8),color='b')
    plt.title(stock+'RPS相对强度',fontsize=15)
    my_ticks = pd.date_range('2018-06-9','2019-3-31',freq='m')
    plt.xticks(my_ticks,fontsize=12)
    plt.yticks(fontsize=12)
    ax = plt.gca()  
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')
    plt.show()

查看2018年7月31日-2019年3月19日每月RPS情况。下面仅列出每个月RPS排名前十的股票,里面出现不少熟悉的“妖股”身影。
dates=['20180731','20180831','20180928','20181031','20181130','20181228','20190131','20190228','20190319']
df_rps=pd.DataFrame()
for date in dates:
    df_rps[date]=rps120[date].index[:50]

东方通信是这一波上涨行情中的最大牛股,主要受益于5G题材的持续炒作。从下图可见,2018年11月,其120日RPS首次出现大于90,然后一直处于高位,具有非常明显的强势股特征。华业资本是本次120日收益率中最低的股票,自2018年8月其其RPS一直下跌,然后持续处于低位,股价一直反弹不起来。顺鑫农业的RPS在2018年6月-11月一直处于高位,然后股价出现了较大的回调。可见RPS的实战意义是,在强势股出现第一波上涨后发现它,然后深入挖掘,判断是否会出现第二、三波的再创新高。


plot_rps('东方通信')

plot_rps('华业资本')

plot_rps('顺鑫农业')

4结语
欧奈尔研究了1953年至1993年,500只年度涨幅最大的股票,发现每年涨幅居前的,在他们股价真正大幅度攀升之前,其平均的相对强弱指标RPS为87%。这并不意味着,只要RPS>87%就可以买入该股票呢?其实RPS指标只是对强势股的个一个初步筛选,对于A股而言,RPS大于87%的股票就有400多只,都买进也不太现实,具体运用还需结合个股基本面、题材和整体市场情况分析。RPS实际上是欧奈尔在《笑傲股市》中提出的CANSLIM七步选股法的一个技术分析。各字母含义如下所示:C:最近一季度报表显示的盈利(每股收益)
A:每年度每股盈利的增长幅度
N:新产品,新服务,股价创新高
S:该股流通盘大小,市值以及交易量的情况
L:该股票在行业中的低位,是否为龙头
I:该股票有无有实力的庄家,机构大流通股东
M:大盘走势如何,如何判断大盘走向

RPS可以帮助选出创出新高的股票。牛股一定创新高,但是新高不一定是牛股。所以关键是将RPS结合基本面进一步选择,基本面情况好,销售额和盈利增长很快,且这种增长是由公司推出的新产品或新服务带来的。本文主要分享了欧奈尔RPS指标的原理和Python计算方法,受篇幅所限,文中只给出了核心代码,如需完整代码可通过加入知识星球,向博主索要。文中提及股票不构成任何投资建议,投资有风险,入市需谨慎!


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝


当一个人把爱倾注于心灵的深处,有什么样的高度不能踩在脚下。
tkfy920 在职认证  学生认证  发表于 2019-3-21 09:33:41 |显示全部楼层 |坛友微信交流群
文中只给出了核心代码,如需完整代码可通过加入知识星球,向博主索要。
IMG_3708.JPG

使用道具

tkfy920 在职认证  学生认证  发表于 2019-3-27 11:53:14 |显示全部楼层 |坛友微信交流群
干货分享要顶起

使用道具

tkfy920 在职认证  学生认证  发表于 2019-3-31 09:19:20 |显示全部楼层 |坛友微信交流群
一起学习,共同进步
CuteHand微信.JPG

使用道具

tkfy920 在职认证  学生认证  发表于 2019-7-22 17:41:21 |显示全部楼层 |坛友微信交流群
好资料要顶起来,谢谢dd

使用道具

binn 在职认证  发表于 2019-12-16 10:26:39 |显示全部楼层 |坛友微信交流群
支持原创分享!

使用道具

tkfy920 在职认证  学生认证  发表于 2019-12-26 09:42:16 |显示全部楼层 |坛友微信交流群
binn 发表于 2019-12-16 10:26
支持原创分享!
谢谢谢谢支持!

使用道具

renwl 发表于 2020-1-10 20:11:40 |显示全部楼层 |坛友微信交流群

使用道具

67890 发表于 2020-1-12 00:31:07 |显示全部楼层 |坛友微信交流群
坚决支持分享

使用道具

tkfy920 在职认证  学生认证  发表于 2020-2-22 11:23:08 |显示全部楼层 |坛友微信交流群
强者恒强,资金寻求抵抗力最低的路径走,获取最大收益。

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jr
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-3-29 09:25