欢迎大家订阅《教你用 Python 进阶量化交易》专栏!为了能够提供给大家更轻松的学习过程,笔者在专栏内容之外已陆续推出一些手记来辅助同学们学习本专栏内容,目前推出的扩展篇链接如下:
第一篇《管理概率==理性交易》
第二篇《线性回归拟合股价沉浮》
第三篇《最大回撤评价策略风险》
第四篇《寻找最优化策略参数》
第五篇《标记A股市场涨跌周期》
第六篇《Tushare Pro接口介绍》
第七篇《装饰器计算代码时间》
第八篇《矢量化计算KDJ指标》
第九篇《移植量化交易小工具》
第十篇《统计学预测随机漫步》
第十一篇《TA-Lib库扩展介绍》
第十二篇《股票分笔数据跨周期处理》
第十三篇《TA-Lib库量价指标分析》
第十四篇《ATR在仓位管理的应用》
第十五篇《扒一扒量化回测常见陷阱》
第十六篇《量化回测工具更新版1》
第十七篇《GUI控件在回测工具上的添加》
第十八篇《文本框显示Tushare股票信息》
第十九篇《建立基于TA-Lib的指标库》
第二十篇《爬虫抓取股票论坛帖子》
第二十一篇《欧奈尔RPS指标的计算》
为了将专栏中分散的知识点贯穿起来,笔者在专栏的末尾小节《制作自己的量化交易工具》中分享了早期制作的一个简易版量化交易小工具,希望大家能够通过调试代码的方式掌握相关的知识。
目前在场外篇第9篇中已经移植到了Python3.7x版本上,接下来我们在这个版本的基础上逐步完善这个工具,使专栏的读者不仅能够通过小工具掌握专栏的相关知识点,也能够把工具用到自己的股票量化交易中去。
上一节我们教大家如何计算欧奈尔RPS指标,因为RPS指标指的是一段时间内个股涨幅在全部股票涨幅排名中的位次值,所以我们要计算出全部股票的120日涨跌幅数值,如下所示:
"""
平安银行 万科A 国农科技 ... 继峰股份 方盛制药 读者传媒
trade_date ...
2019-07-03 0.524483 0.220502 NaN ... 0.016753 0.576159 0.147368
2019-07-04 0.507543 0.227669 NaN ... NaN 0.554585 0.151579
2019-07-05 0.427692 0.181308 NaN ... 0.040506 0.495763 0.096192
2019-07-08 0.395277 0.163673 NaN ... -0.008906 0.389344 0.043478
2019-07-09 0.406832 0.166000 NaN ... -0.044529 0.384146 0.029703
2019-07-10 0.364185 0.151599 NaN ... -0.047134 0.338614 0.043651
2019-07-11 0.340594 0.163282 NaN ... -0.034982 0.324803 0.048000
2019-07-12 0.384314 0.171937 NaN ... -0.028894 0.333992 0.029762
2019-07-15 0.384768 0.199041 NaN ... -0.014066 0.355865 0.042510
2019-07-16 0.342773 0.194754 NaN ... -0.007732 0.351085 0.021825
2019-07-17 0.306298 0.185287 0.267123 ... -0.040764 0.339921 0.034137
2019-07-18 0.333659 0.205046 0.244923 ... -0.033376 0.338028 0.011834
2019-07-19 0.341323 0.192158 0.225904 ... -0.011796 0.370297 -0.011583
2019-07-22 0.339458 0.212476 0.138211 ... -0.045514 0.352475 -0.046967
2019-07-23 0.338521 0.181102 0.148126 ... -0.045337 0.406000 -0.027668
2019-07-24 0.341063 0.184117 0.162694 ... -0.029948 0.394790 -0.002004
... ... ... ... ... ... ... ...
2019-12-31 0.210449 0.103945 0.085536 ... 0.037227 0.224189 0.390152
[124 rows x 3003 columns]
"""
因为不同股票因为上市的时间不同,所以120日周期的移动涨跌幅会存在缺失值,我们可以用0去填充,然后把数据存储为CSV文件,这样下次可以从CSV文件中导入,如下所示:
我们看下2019-12-31这一天平安银行120日涨幅为0.210449,我们用可视化方法看下这一天全部股票的涨跌幅排布如何,关键代码和显示效果分别如下所示:
ax.hist(data.iloc[-1,:], bins=50, density=False, color='b')
可以发现在3000只股票中, 120日收益率在[-0.11188698 -0.03826044]区间的股票最多,有657只,在这个区间附近也非常多。分布的数值如下所示:
"""
[ 3. 8. 7. 22. 67. 151. 348. 657. 547. 427. 225. 145. 102. 97.
62. 25. 30. 15. 15. 6. 9. 8. 8. 5. 2. 0. 2. 0.
2. 0. 1. 0. 0. 1. 0. 1. 0. 0. 3. 0. 0. 0.
0. 0. 0. 0. 0. 0. 1. 1.]
[-0.62727273 -0.55364619 -0.48001966 -0.40639312 -0.33276658 -0.25914005
-0.18551351 -0.11188698 -0.03826044 0.03536609 0.10899263 0.18261916
0.2562457 0.32987224 0.40349877 0.47712531 0.55075184 0.62437838
0.69800491 0.77163145 0.84525799 0.91888452 0.99251106 1.06613759
1.13976413 1.21339066 1.2870172 1.36064373 1.43427027 1.50789681
1.58152334 1.65514988 1.72877641 1.80240295 1.87602948 1.94965602
2.02328256 2.09690909 2.17053563 2.24416216 2.3177887 2.39141523
2.46504177 2.5386683 2.61229484 2.68592138 2.75954791 2.83317445
2.90680098 2.98042752 3.05405405]
"""
下一步对全部股票的涨跌幅值进行排序,如下所示:
for index, row in data.iterrows():
df = pd.DataFrame(row.sort_values(ascending=False))
排序完成后我们可以得到每一天的涨幅排名,如下所示:
"""
2019-11-22
中国天楹 0.548611
中国长城 0.515271
深大通 0.502844
深桑达A 0.490971
全新好 0.450980
德赛电池 0.408602
神州数码 0.325490
平安银行 0.257258
... ...
长虹华意 -0.139588
特发信息 -0.140711
兴业矿业 -0.148893
方大集团 -0.152330
"""
然后对每个股票的涨跌幅从1开始逐个编号排序,并且计算出RPS指标,以下是某一天经过排序后涨跌幅排名以及对应的RPS值和股票代码,以DataFrame数据格式存储,此处我们看下截止到2019-12-31这一天涨幅榜前十名和后十名分别是什么股票,如下所示:
有了每天的股票RPS值排名以后,我们就可以把每天排名第一的股票汇集起来,代码和汇集后格式,如下所示:
# 构建一个以时间——收益率/RPS/股票名称的DataFrame空表
df_new = pd.DataFrame(np.NaN, columns = ['pct','name','rps'], index = rps_period_120.keys())
# 按时间汇集每日排名第一的数据
for date in df_new.index:
rps_df = rps_period_120[date]
df_new.loc[date, 'pct'] = rps_df.loc[1, 'pct']
df_new.loc[date, 'name'] = rps_df.loc[1, 'name']
df_new.loc[date, 'rps'] = rps_df.loc[1, 'rps']
"""
pct name rps
20190703 2.925358 金运激光 99.9667
20190704 2.883792 金运激光 99.9667
20190705 2.779621 兴齐眼药 99.9667
20190708 3.089744 兴齐眼药 99.9667
20190709 3.130105 兴齐眼药 99.9667
... ... ... ...
20191120 2.724040 宝鼎科技 99.9667
20191230 2.931699 漫步者 99.9667
20191231 3.054054 漫步者 99.9667
[124 rows x 3 columns]
"""
接下来我们会针对这些数据展开可视化选股分析。查看下2019年7月3日-2019年12月31日每日RPS的情况,这里我们仅列出每日RPS排名前十的股票,关键代码和显示效果分别如下所示:
# 按时间汇集每日排名前十的数据
for date in df_stock.index:
rps_df = rps_period_120[date]
df_stock.loc[date, :] = rps_df.name[0:10]
print(df_stock)
df_stock.to_csv('rps_top10.csv', encoding='gbk')
从中可以看到里面出现不少熟悉的“妖股”身影,比如金运激光、兴齐眼药、宝鼎科技、漫步者……
拿漫步者和金运激光来说,漫步者在A点开始RPS一直处于高位,具有非常明显的强势股特征。金运激光在B点开始一直下跌,然后持续处于低位,股价一直反弹不起来。可见在强势股出现第一波上涨后发现它,然后深入挖掘;当强势股转弱时也可以通过RPS的变化来观察。
另一方面,该指标仍旧需要结合CANSLIM系统的其他指标一起使用,对初步筛选的股票进一步的过滤。 总之,投资需谨慎,入市有风险!!!
接下来我们把2019年12月31日前每日RPS排名前十的股票在专栏自带的GUI小工具上进行显示。
首先还是要在行情资讯栏中添加“RPS排名”这个选项,然后将事件绑定在相应的RadioBox控件上。显示的控件此处采用wxPython中文本框wx.TextCtrl类。关键代码如下所示:
class RPS_Top10Dialog(wx.Dialog): # user-defined
def __init__(self, parent):
wx.Dialog.__init__(self, parent, -1, u"RPS排名前十的股票/2020.1.1", size=(800, 1000),
style=wx.CAPTION | wx.CLOSE_BOX | wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX)
sizer = wx.BoxSizer(wx.VERTICAL)
df_data = pd.read_csv('rps_top10.csv', encoding='gbk', index_col=0, header=0)
print(df_data)
self.BasicInput = wx.TextCtrl(self, -1, "截止2020.1.1-RPS排名前十的股票:\n", size=(700, 900),
style=wx.TE_MULTILINE | wx.TE_READONLY) # 多行|只读
self.BasicInput.AppendText("交易日 " + "TOP1-10 " + "\n")
for index, row in df_data.iterrows():
temp_str = str(index) + " "
for n in range(len(row)):
temp_str += str(row[n]) + " "
self.BasicInput.AppendText(temp_str + "\n")
self.BasicInput.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.BOLD))
okbtn = wx.Button(self, wx.ID_OK, u"确认")
okbtn.SetDefault()
sizer.Add(self.BasicInput, flag=wx.ALIGN_CENTER)
sizer.Add(okbtn, flag=wx.ALIGN_CENTER)
self.SetSizer(sizer)
TextCtrl类的构造函数形式如下 :
wx.TextCtrl(self, parent=None, id=None, value=None, pos=None, size=None, style=0, validator=None, name=None):
解释下其中各个参数的含义:
parent:父窗口部件
id:标识符。使用-1可以自动创建一个唯一的标识
value:显示的内容
pos:一个wx.Point或一个Python元组,它是窗口部件的位置
size:一个wx.Size或一个Python元组,它是窗口部件的尺寸
style:样式标记
validator:赋予text ctrl的内容校验器
name:对象的名字,用于查找的需要
此处style为wx.TE_MULTILINE和wx.TE_READONLY,实际上style为接受样式参数,如下所示:
wx.TE_PASSWORD——文本将回显为星号
wx.TE_READONLY——文本将不可编辑(只读)
wxTE_LEFT——在控件中的文本将左对齐(默认)
wxTE_CENTRE——在控件中的文本将居中对齐
wxTE_RIGHT——在控件中的文本将居右对齐
wx.TE_PROCESS_ENTER——如果使用了该样式,那么当用户在控件内按下回车键时,一个文本输入事件将被触发。否则,按键事件内在的由该文本控件或该对话框管理
wx.TE_NOHIDESEL——文本始终高亮显示,只适用于Windows
wx.TE_PROCESS_TAB——如果指定了这个样式,那么通常的字符事件在Tab键按下时创建(一般意味一个制表符将被插入文本)。否则,tab由对话框来管理,通常是控件间的切换。
多行或丰富文本样式有
wx.HSCROLL——如果文本控件是多行的,并且如果该样式被声明了,那么长的行将不会自动换行,并显示水平滚动条。该选项在GTK+中被忽略。
wx.TE_AUTO_URL——如果丰富文本选项被设置并且平台支持的话,那么当用户的鼠标位于文本中的一个URL上或在该URL上敲击时,这个样式将导致一个事件被生成。
wx.TE_DONTWRAP——wx.HSCROLL的别名。
wx.TE_LINEWRAP——对于太长的行,以字符为界换行。某些操作系统可能会忽略该样式。
wx.TE_MULTILINE——文本控件允许多行。如果未指定该样式,换行字符不应该在控件值中使用。
wx.TE_RICH——用于Windows下,丰富文本控件用作基本的窗口部件。这允许样式文本的使用。
wx.TE_RICH2——用于Windows下,把最新版本的丰富文本控件用作基本的窗口部件。
wx.TE_WORDWRAP——对于太长的行,以单词为界换行。许多操作系统会忽略该样式。
此处显示文本使用了AppendText()方法在尾部添加文本,实际上wx.TextCtrl类还支持很多文本处理的方法,如下所示:
编程下改变文本内容方式有:
GetInsertionPoint():得到插入点的位置,位置是整型的索引值。控件的开始位置是0。
SetInsertionPoint(pos):设置插入点的位置,位置是整型的索引值。控件的开始位置是0。
SetInsertionPointEnd():
GetRange(from, to):返回控件中位置索引范围内的字符串。
SetSelection(from, to):设置选择的文本
GetSelection():以元组的形式返回当前所选择的文本的起始位置的索引值(开始,结束)。
GetStringSelection()得到所选择的字符串。
GetValue():返回控件中所有的字符串
SetValue(value):改变控件中的全部文本。
Remove(from, to):删除指定范围的文本。
Replace(from, to, value):用给定的值替换掉指定范围内的文本。这可以改变文本的长度。
WriteText(text):类似于AppendText(),只是写入的文本被放置在当前的插入点。
Clear():重置控件中的文本为“”。并且生成一个文本更新事件。
EmulateKeyPress(event):产生一个按键事件,插入与事件相关联的控制符,就如同实际的按键发生了。
wx.TextCtrl的一些实用的方法:
GetDefaultStyle()、SetDefaultStyle(style)
GetLineLength(lineNo):返回给定行的长度的整数值。
GetLineText(lineNo):返回给定行的文本。
GetNumberOfLines():返回控件中的行的数量。对于单行,返回1。
IsMultiLine()、IsSingleLine():布尔类型的方法,确定控件的状态。
PositionToXY(pos):指定文本内的一个整数值位置,返回以元组(列,行)形式的索引位置。列和行的索引值均以0作为开始。
SetStyle(start, end,style):立即改变指定范围内文本的样式。
ShowPosition(pos):引起一个多行控件的滚动,以便观察到指定位置的内容。
XYToPosition(x, y):与PositionToXY(pos)相反——指定行和列,返回整数值位置。
显示效果图如下所示:
关于完整代码和整理后的CSV数据文件加入专栏交流群后都可以获取到。更多的量化交易内容欢迎大家订阅专栏阅读!!
共同学习,写下你的评论
评论加载中...
作者其他优质文章