我认为投资专业的学生只需要两门教授得当的课堂:如何评估一家公司,以及如何考虑市场价格。——巴菲特
01 引言
本文延续“手把手教你使用Python的TA-Lib”系列,以资金流量指标(MFI)为例,使用Python编写简单的回测框架,着重介绍动量指标(Momentum Indicators)及其运用。前面推文【手把手教你】股市技术分析利器之TA-Lib(一)主要探讨了重叠指标的相关原理与Python实现,【手把手教你】股市技术分析利器之TA-Lib(二) 着重介绍TA-Lib中强大的数学运算、数学变换、统计函数、价格变换、周期指标和波动率指标函数及其应用实例。【手把手教你】量价关系分析与Python实现,则主要介绍了交易量指标(Volume Indicators)及其运用。TA-Lib的安装与使用见之前推文。
02 动量指标概述
动量指标,英文全称为 Momentum Indicators,是一种利用动力学原理,研究股价在波动过程中趋势与反转现象的技术指标。动量指标建立在价格与供求关系的基础上,认为股价的涨跌幅随着时间的推移逐渐变小,股价变化的速度和能量慢慢减缓后,行情可能发生反转。常见的动量指标包括ADX、CMO、MACD、RSI、KDJ、动量指数(MOM)和威廉指标等。TA-Lib 库里的动量指标类函数如下表所示。
03 MFI 指标分析框架
下面以大家比较少见的资金流量指标(Money Flow Index, 简称MFI)为例,详细介绍动量类指标的分析框架和应用。MFI指标(Money Flow Index)是1989年3月由JWellesWilder's提出来的,结合考虑了价和量,相当于成交量的RSI指标。一般而言,价涨量增及价跌量缩是一种惯性作用.股价进行波段涨升时,成交量必须伴随上升。
计算方法
典型价格(TP)=当日最高、最低与收盘价均值
资金流量(MF)=TP×N日内成交量
若当日MF>昨日MF,则视为正资金流量(PMF)
若当日MF
MFI=100-[100/(1+PMF/NMF)]
参数N一般设为14日。
应用法则
超买超卖信号:当MFI>80时为超买,在其回头向下跌破80时,为短线卖出时机。
当MFI<20时为超卖,当其回头向上突破20时,为短线买进时机。
当MFI>80,而产生背离现象时,视为卖出信号。
当MFI<20,而产生背离现象时,视为买进信号。
04MFI 指标 Python 应用实例
下面结合MFI 指标的超买超卖法则,以上证指数为标的,使用 Python 对其进行历史回测,主要利用了pandas、numpy、talib和matplotlib进行数据处理和可视化。
#先引入后面可能用到的包(package)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#注意下面的%命令只能在jupyter notebook上运行,否则需要删除或注释掉
%matplotlib inline
#正常显示画图时出现的中文和负号
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False
#引入TA-Lib库
import talib as ta
import tushare as ts
df=ts.get_k_data('sh',start='2000-01-01')
df.index=pd.to_datetime(df.date)
df=df.sort_index()
df['ret']=df.close/df.close.shift(1)-1
df.head()
high,low,close,volume=df.high.values,df.low.values,df.close.values,df.volume.values
df['mfi']=ta.MFI(high, low, close, volume, timeperiod=14)
plt.figure(figsize=(16,14))
plt.subplot(211)
df['close'].plot(color='r')
plt.xlabel('')
plt.title('上证综指走势',fontsize=15)
plt.subplot(212)
df['mfi'].plot()
plt.title('MFI指标',fontsize=15)
plt.xlabel('')
plt.show()
#当前日的MFI<20,而当日的MFI>20时,买入信号设置为1
for i in range(15,len(df)):
if df['mfi'][i]>20 and df['mfi'][i-1]<20:
df.loc[df.index[i],'收盘信号']=1
if df['mfi'][i]<80 and df['mfi'][i-1]>80:
df.loc[df.index[i],'收盘信号']=0
#计算每天的仓位,当天持有上证指数时,仓位为1,当天不持有上证指数时,仓位为0
pd.options.mode.chained_assignment = None
df['当天仓位']=df['收盘信号'].shift(1)
df['当天仓位'].fillna(method='ffill',inplace=True)
from datetime import datetime,timedelta
d=df[df['当天仓位']==1].index[0]-timedelta(days=1)
df_new=df.loc[d:]
df_new['ret'][0]=0
df_new['当天仓位'][0]=0
#当仓位为1时,买入上证指数,当仓位为0时,空仓,计算资金指数
df_new['资金指数']=(df_new.ret*df['当天仓位']+1.0).cumprod()
df_new['指数净值']=(df_new.ret+1.0).cumprod()
df.close.plot(figsize=(16,7))
for i in range(len(df)):
if df['收盘信号'][i]==1:
plt.annotate('买',xy=(df.index[i],df.close[i]),arrowprops=dict(facecolor='r',shrink=0.05))
if df['收盘信号'][i]==0:
plt.annotate('卖',xy=(df.index[i],df.close[i]),arrowprops=dict(facecolor='g',shrink=0.1))
plt.title('上证指数2000-2019年MFI买卖信号',size=15)
plt.xlabel('')
ax=plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.show()
#查看最近两年情况
df1=df.loc['2016-01-01':,]
df1.close.plot(figsize=(16,7))
for i in range(len(df1)):
if df1['收盘信号'][i]==1:
plt.annotate('买',xy=(df1.index[i],df1.close[i]),arrowprops=dict(facecolor='r',shrink=0.05))
if df1['收盘信号'][i]==0:
plt.annotate('卖',xy=(df1.index[i],df1.close[i]),arrowprops=dict(facecolor='g',shrink=0.1))
plt.title('上证指数2016-2019年MFI买卖信号',fontsize=15)
plt.xlabel('')
ax=plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.show()
df1['策略净值']=(df1.ret*df1['当天仓位']+1.0).cumprod()
df1['指数净值']=(df1.ret+1.0).cumprod()
df1['策略收益率']=df1['策略净值']/df1['策略净值'].shift(1)-1
df1['指数收益率']=df1.ret
下面将数据获取、策略计算和历史回测打包成一个strategy函数,对不同参数组合和时间区间进行历史回测,通过下图不难发现,经验总结得出的20/80超卖超买信号效果并不理想,但将超买值改为90后,反而获得了更好的效果。总体而言,MFI指标相对于不择时而言,最大回撤要小很多,即持仓风险小,但是也意味着可能赚不到疯狂上涨的钱。此外,2016年或2017年以来MFI回测效果比较好,特别是将超买值改为90后,而2000、2005或2009以来的回测效果可能还不如大盘,反映了时间周期越长,MFI指标的效果越差,事实上,MFI指标是一个提供中短期买卖信号的技术指标。
strategy('sh','2009-05-12',20,80)
strategy('sh','2009-04-12',20,90)
strategy('sh','2009-04-12',20,95)
strategy('sh','2009-04-12',30,95)
strategy('sh','2009-04-12',15,95)
strategy('sh','2016-01-01',20,90)
strategy('sh','2000-01-01',20,80)
strategy('sh','2000-01-01',20,92)
strategy('sh','2017-04-12',20,80)
strategy('sh','2017-04-12',20,92)
strategy('cyb','2017-04-01',20,80)
05 结语
本文以MFI指标为例,简要介绍了动量指标的原理及其Python量化运用实例,由于篇幅有限,只给出了部分核心代码,完整代码可通过加入知识星球获取。
在指标运用中,不少交易者会产生困惑,有时指标严重超买,股价却继续上涨,或指标严重超卖,股价仍未止跌企稳。其实这是混淆了技术指标与股价的关系,指标并不能决定股价涨跌,股价才决定指标的大小,股价是因,指标是果,由因可推出果,但由果来导出因可能不准确。既然那样,技术指标还有什么用呢?
其实技术分析就如温度计,能够测量当前温度,却不能预测也不能决定未来温度。换句话说,技术指标虽不能预测未来走势,但可以衡量当前市场交投情况,用于确认趋势。也就是说技术指标可以作为辅助参考作用,当股价趋势继续上涨或下跌时,指标也将继续超买或超卖,而当股价一旦发生转势,指标随后也会发生转势买卖信号,为仓位管理和择时提供技术上的参考。
关于Python金融量化
专注于分享Python在金融量化领域的应用。加入知识星球,可以免费获取30多g的量化投资视频资料、公众号文章Python完整源码、量化投资前沿分析框架,与博主直接交流、结识圈内朋友等。