在用 python 的 matplotlib 和 numpy 库绘制股票 K 线均线的整合效果 (含从网络接口爬取数据和验证交易策略代码) 一文里, 我讲述了通过爬虫接口得到股票数据并绘制出 K 线均线图形的方式, 在本文里, 将在此基础上再引入成交量效果图, 并结合量价理论, 给出并验证一些交易策略.
1 成交量对量化分析的意义
美国的股市分析家葛兰碧 (Joe Granville) 在他所著的《股票市场指标》一书里提出著名的 "量价理论"."量价理论" 的核心思想是, 任何对股价的分析, 如果离开了对成交量的分析, 都将是无本之木, 无水之源, 因为成交量的增加或萎缩都表现出一定的股价趋势.
成交量是指时间单位内已经成交的股数或总手数. 成交量能反应出股市交易中的供求关系, 其中道理是比较浅显易懂的, 当股票供不应求时, 大家争相购买, 成交量就很大了, 反之当供过于求时, 则说明市场交易冷淡, 成交量必然萎缩.
广义的成交量包括成交股数 (Volumn 或 Vol), 成交金额(AMOUNT, 时间单位内已经成交的总金额数) 和换手率(TUN, 股票每天成交量除以股票的流通总股本所得的比率), 而狭义则是指成交股数. 我们用 yahoo 接口得到的数据里, 有表示成交股数的 Volumn 列, 其中的单位是 "手", 一手为 100 股, 在本部分里, 我们是通过 Volumn 列数据绘制股票的成交量信息.
2 引入成交量
在 K 线和均线整合成交量的效果图里, 出于美观的考虑, 我们对整合的效果提出了如下三点要求.
第一, 绘制上下两个子图, 上图放 K 线和均线, 下图放成交量效果.
第二, 上下两个子图共享 x 轴, 也就是说, 两者 x 轴的刻度标签和间隔应该是一样的.
第三, 通过柱状图来绘制成交量图, 如果当天股票上涨, 成交量图是红色, 下跌则是绿色.
在如下的 drawKMAAndVol.py 案例, 我们将实现增加成交量图的效果.
- #!/usr/bin/env python
- #coding=utf-8
- import pandas as pd
- import matplotlib.pyplot as plt
- from mpl import candlestick_ochl
- from matplotlib import MultipleLocator
- #根据指定代码和时间范围, 获取股票数据
- df = pd.read_csv('D:/stockData/ch7/600895.csv',encoding='gbk')
- #设置大小, 共享 x 坐标轴
- figure,(axPrice, axVol) = plt.subplots(2, sharex=True, figsize=(15,8))
- #调用方法, 绘制 K 线图
- candlestick_ochl(ax = axPrice, opens=df["Open"].values, closes=df["Close"].values, highs=df["High"].values, lows=df["Low"].values,
- width=0.75, colorup='red', colordown='green')
- axPrice.set_title("600895 张江高科 K 线图和均线图")# 设置子图标题
- df['Close'].rolling(Windows=3).plot(ax=axPrice,color="red",label='3 天均线')
- df['Close'].rolling(Windows=5).plot(ax=axPrice,color="blue",label='5 天均线')
- df['Close'].rolling(Windows=10).plot(ax=axPrice,color="green",label='10 天均线')
- axPrice.legend(loc='best') #绘制图例
- axPrice.set_ylabel("价格(单位: 元)")
- axPrice.grid(True) #带网格线
- #如下绘制成交量子图
- #直方图表示成交量, 用 for 循环处理不同的颜色
- for index, row in df.iterrows():
- if(row['Close']>= row['Open']):
- axVol.bar(row['Date'],row['Volume']/1000000,width = 0.5,color='red')
- else:
- axVol.bar(row['Date'],row['Volume']/1000000,width = 0.5,color='green')
- axVol.set_ylabel("成交量(单位: 亿手)")# 设置 y 轴标题
- axVol.set_title("600895 张江高科成交量")# 设置子图的标题
- axVol.set_ylim(0,df['Volume'].max()/100000000*1.2)# 设置 y 轴范围
- xmajorLocator = MultipleLocator(5) #将 x 轴主刻度设置为 5 的倍数
- axVol.xaxis.set_major_locator(xmajorLocator)
- axVol.grid(True) #带网格线
- #旋转 x 轴的展示文字角度
- for xtick in axVol.get_xticklabels():
- xtick.set_rotation(15)
- plt.rcParams['font.sans-serif']=['SimHei']
- plt.show()
从第 8 行到第 20 行, 我们一方面是从 CSV 文件里读取数据, 另一方面在第一个子图里绘制了 K 线和均线图. 这部分的代码和之前很相似, 不过请大家注意两个点.
第一, 在第 10 行里, 不仅设置了绘图区域的大小, 更通过 sharex=True 语句, 设置了 axPrice 和 axVol 这两个子图共享 x 轴.
第二, 第二, 在第 14,18,19 和第 20 行, 由于是在 K 线图和均线图的 axPrice 子图里操作, 所以若干方法的调用主体是 axPrice 对象, 而不是之前的 pyplot.plt 对象.
从第 23 行到第 36 行里, 我们在 axVol 子图里绘制了成交量图的效果. 请大家注意第 23 行到第 27 行的 for 循环, 在其中, 我们通过第 24 行的 if 语句, 比较收盘价和开盘价, 以判断当天股票是涨是跌, 在此基础上, 通过第 25 行或第 27 行的 bar 方法, 设置当日成交量图的填充颜色. 从上述代码能看出, 成交量是在自于 CSV 文件里的 Volume 列.
在绘制成交量图的时候有两个细节请大家注意一下.
第一, 在第 25 行, 第 27 行和第 30 行里, 当我们设置 y 轴的刻度值和范围时, 我们除以了一个相同的数, 这是因为在第 28 行我们设置 y 轴文字时, 指定了 y 轴成交量的单位是 "亿手".
第二, 本次是通过第 35 行和第 36 行的 for 循环, 设置了 "x 轴文字旋转" 的效果, 从代码里我们能看到, 本案例中的旋转角度是 15 度.
上述代码的运行效果如下图所示, 从中大家能看两个 x 轴刻度一致的子图, 且在成交量子图里, 上涨日和下跌日的成交量填充色分别是红色和绿色.
3 成交量与股价的关系
成交量和股价间也存在着八大规律, 通过下图, 我们能感受到这些规律, 其中纵坐标表示价(即股价), 横坐标表示量(即成交量).
我们能看出量价之间的八种关系, 即量增价平, 量增价升, 量平价升, 量缩价升, 量减价平, 量缩价跌, 量平价跌, 量跌价升, 随着上述周期过程, 股价也完成了一个从涨到跌的完整循环, 下面我们来具体解释一下.
1.量增价平: 股价经过持续下跌进入到低位状态, 出现了成交量增加但股价平稳的现象, 此时不同天的成交量高度落差可能比较明显, 这说明该股在底部积聚上涨动力.
2.量增价升: 成交量在低价位区持续上升, 同时伴随着股价上涨趋势, 这说明股价上升得到了成交量的支撑, 后市将继续看好, 这是中短线的买入信号.
3.量平价升: 在股价持续上涨的过程中, 如果多日的成交量保持等量水平, 建议在这一阶段中可以适当增加仓位.
4.量缩价升: 成交量开始减少, 但股价依然在上升, 此时应该视情况继续持股. 但如果还没有买入的投资者就不宜再重仓介入, 因为股价已经有了一定的涨幅, 价位开始接近上限.
5.量减价平: 股价经长期大幅度上涨后, 成交量显著减少, 股价也开始横向调整不再上升, 这是高位预警的信号. 这个阶段里一旦有风吹草动, 比如突然拉出大阳线和大阴线, 建议应出货离场, 做到落袋为安.
6.量缩价跌: 成交量在高位继续减少, 股价也开始进入下降通道, 这是明确的卖出信号. 如果还出现缩量阴跌, 这说明股价底部尚远, 不会轻易止跌.
7.量平价跌: 成交量停止减少, 但股价却出现急速下滑现象, 这说明市场并没有形成一致看空的共识. 股谚有 "多头不死, 跌势不止" 的说法, 出现 "量平价跌" 的情况, 说明主力开始逐渐退出市场, 这个阶段里, 应继续观望或者出货, 别轻易去买入以所谓的 "抢反弹".
8. 量增价跌: 股价经长期大幅下跌之后, 有可能出现成交量增加的情况, 此时的操作原则是建议卖出, 或者空仓观望. 如果低价区成交量有增加, 则说明有资金在此价位区间接盘, 预示后期有望形成底部并出现反弹. 但如果出现量增价跌, 则建议应清仓出局.
在下文里, 我们将通过 Python 语言验证量价理论中的两个规则.
4 验证 "量增价平" 的买点
在如下的 calBuyPointByVol.py 案例中, 我们将验证 "量增价平" 的买点. 在这段代码里我们做了三件事, 第一是通过 yahoo 接口得到了指定股票指定范围内的交易数据, 第二通过 pandas 接口保存得到的数据, 以便日后验证, 第三通过遍历 dataframe 对象, 计算量和价的关系, 从而获得买点日期.
- #!/usr/bin/env python
- #coding=utf-8
- import pandas_datareader
- import pandas as pd
- import numpy as np
- #涨幅是否大于指定比率
- def isMoreThanPer(lessVal,highVal,per):
- if np.abs(highVal-lessVal)/lessVal>per/100:
- return True
- else:
- return False
- #涨幅是否小于指定比率
- def isLessThanPer(lessVal,highVal,per):
- if np.abs(highVal-lessVal)/lessVal<per/100:
- return True
- else:
- return False
- code='600895.ss'
- stock = pandas_datareader.get_data_yahoo(code,'2018-09-01','2018-12-31')
- #删除最后一行, 因为 get_data_yahoo 会多取一天数据
- stock.drop(stock.index[len(stock)-1],inplace=True)
- #保存在本地
- stock.to_csv('D:\\stockData\ch7\\60089520181231.csv')
- #从文件里得到数据
- df = pd.read_csv('D:/stockData/ch7/60089520181231.csv',encoding='gbk')
- cnt=0
- while cnt<=len(df)-1:
- try:
- #规则 1, 连续三天收盘价变动不超过 3%
- if isLessThanPer(df.iloc[cnt]['Close'],df.iloc[cnt+1]['Close'],3) and isLessThanPer(df.iloc[cnt]['close'],df.iloc[cnt+2]['Close'],3) :
- #规则 2, 连续三天成交量涨幅超过 75%
- if isMoreThanPer(df.iloc[cnt]['Volume'],df.iloc[cnt+1]['volume'],75) and isMoreThanPer(df.iloc[cnt]['Volume'],df.iloc[cnt+2]['Volume'],75) :
- print("Buy Point on:" + df.iloc[cnt]['Date'])
- except:
- pass
- cnt=cnt+1
在第 7 行定义的 isMoreThanPer 方法里, 我们比较了高价和低价, 以判断是否超过由参数 per 指定的涨幅. 在第 13 行的 isLessThanPer 方法里, 我们判断了跌幅是否超过 per 指定的范围. 由于这两个功能经常会用到, 所以我们把它们封装成函数.
从第 18 行到第 25 行, 我们完成了获取并保存数据的动作, 并用 df 对象保存了待遍历的股票数据(即张江高科 2018-09-01 到 2018-12-31 的数据).
在第 27 行到第 36 行按日期遍历股票数据时, 我们制定了如下规则, 连续三天股票的收盘价变动范围不超过 5%(即价平)且 3 天成交量的涨幅过 75%(即量增), 把满足条件的日期打印出来. 运行后, 我们能看到 11 月 2 日这个买点.
在之前代码基础上改写下, 把时间范围改成 2018-09-01 到 2018-12-31, 再运行下, 能看到如下图所示的效果.
从中我们能看到验证后的结果: 在 11 月 2 日之后, 股票的涨幅比较明显, 确实是个合适的买点, 从中我们能看出 "量增价平" 的指导意义.
5 验证 "量减价平" 的卖点
在如下 calSellPointByVol.py 案例中, 我们同样是分析张江高科 2018-09-01 到 2018-12-31 的交易数据, 本次我们制定的策略是, 第一, 还是连续三天股票的收盘价变动范围不超过 5%(即价平), 第二, 较第一日相比, 第二日和第三日的成交量下降幅度超过 75%(即量减).
- #!/usr/bin/env python
- #coding=utf-8
- import pandas_datareader
- import pandas as pd
- import numpy as np
- #涨幅是否大于指定比率
- def isMoreThanPer(lessVal,highVal,per):
- if np.abs(highVal-lessVal)/lessVal>per/100:
- return True
- else:
- return False
- #涨幅是否小于指定比率
- def isLessThanPer(lessVal,highVal,per):
- if np.abs(highVal-lessVal)/lessVal<per/100:
- return True
- else:
- return False
- #本次直接从文件里得到数据
- df = pd.read_csv('D:/stockData/ch7/60089520181231.csv',encoding='gbk')
- cnt=0
- while cnt<=len(df)-1:
- try:
- #规则 1, 连续三天收盘价变动不超过 3%
- if isLessThanPer(df.iloc[cnt]['Close'],df.iloc[cnt+1]['Close'],3) and isLessThanPer(df.iloc[cnt]['Close'],df.iloc[cnt+2]['close'],3) :
- #规则 2, 连续三天成交量跌幅超过 75%
- if isMoreThanPer(df.iloc[cnt+1]['Volume'],df.iloc[cnt]['Volume'],75) and isMoreThanPer(df.iloc[cnt+2]['Volume'],df.loc[cnt]['Volume'],75) :
- print("Sell Point on:" + df.iloc[cnt]['Date'])
- except:
- pass
- cnt=cnt+1
上述代码和之前 calBuyPointByVol.py 案例很相似, 只不过我们适当变更了第 26 行判断 "成交量" 的 if 条件. 上述代码运行后, 我们能得到的卖点是 2018-12-05, 从上图里我们能看出, 在这段时间之后的若干交易日里, 张江高科的股价确实有下跌现象.
6 求推荐, 后文预告与版权说明
在本系列的后面文章中, 将陆续通过 python 绘制成交量, KDJ,MACD,RSI,BIAS 和 OBV 等指标, 而且还会用 Python 编写针对这些指标的交易策略, 敬请关注.
本文用了我将近 2 个小时, 如果大家感觉好, 请帮忙推荐下.
关于转载有如下的说明.
1 本文文字和代码均属原创, 可转载, 但谢绝用于商业用户.
来源: https://www.cnblogs.com/JavaArchitect/p/11162005.html