本文延续“手把手教你使用Python的TA-Lib”系列,以资金流量指标(MFI)为例,使用Python编写简单的回测框架,着重介绍动量指标(Momentum Indicators)及其运用。前面推文【手把手教你】股市技术分析利器之TA-Lib(一)主要探讨了重叠指标的相关原理与Python实现,【手把手教你】股市技术分析利器之TA-Lib(二) 着重介绍TA-Lib中强大的数学运算、数学变换、统计函数、价格变换、周期指标和波动率指标函数及其应用实例。【手把手教你】量价关系分析与Python实现,则主要介绍了交易量指标(Volume Indicators)及其运用。TA-Lib的安装与使用见之前推文。
0 2动量指标概述 动量指标,英文全称为 Momentum Indicators,是一种利用动力学原理,研究股价在波动过程中趋势与反转现象的技术指标。动量指标建立在价格与供求关系的基础上,认为股价的涨跌幅随着时间的推移逐渐变小,股价变化的速度和能量慢慢减缓后,行情可能发生反转。常见的动量指标包括ADX、CMO、MACD、RSI、KDJ、动量指数(MOM)和威廉指标等。TA-Lib 库里的动量指标类函数如下表所示。函数名 |
英文全称 |
中文名称 |
Python实现 |
ADX |
Average Directional Movement Index |
平均趋向指数 |
ta.ADX(high, low, close, timeperiod=14) |
ADXR |
Average Directional Movement Index Rating |
平均趋向指数评估 |
ta.ADXR(high, low, close, timeperiod=14) |
APO |
Absolute Price Oscillator |
价格摆动指标 |
ta.APO(close, fastperiod=12, slowperiod=26, matype=0) |
AROON |
Aroon |
阿隆指标 |
down, up =ta.AROON(high, low, timeperiod=14) |
AROONOSC |
Aroon Oscillator |
阿隆振荡 |
ta.AROONOSC(high, low, timeperiod=14) |
BOP |
Balance Of Power |
均势指标 |
ta.BOP(open, high, low, close) |
CCI |
Commodity Channel Index |
商品通道指数或顺势指标 |
ta.CCI(high, low, close, timeperiod=14) |
CMO |
Chande Momentum Oscillator |
钱德动量摆动指标 |
ta.CMO(close, timeperiod=14) |
DX |
Directional Movement Index |
DMI指标或动向指标 |
ta.DX(high, low, close, timeperiod=14) |
MACD |
Moving Average Convergence Divergence |
平滑异同移动平均线 |
macd, macdsignal, macdhist = MACD(close, fastperiod=12, slowperiod=26, signalperiod=9) |
MACDEXT |
MACD with controllable MA type |
可选择MA类型的MACD指标 |
macd, macdsignal, macdhist = ta.MACDEXT(close, fastperiod=12, fastmatype=0, slowperiod=26, slowmatype=0, signalperiod=9, signalmatype=0) |
MACDFIX |
Moving Average Convergence/ Divergence Fix 12/26 |
MACD12/26 |
macd, macdsignal, macdhist = ta.MACDFIX(close, signalperiod=9) |
MFI |
Money Flow Index |
资金流量指标 |
ta.MFI(high, low, close, volume, timeperiod=14) |
MINUS_DI |
Minus Directional Indicator |
负向指标 |
ta.MINUS_DI(high, low, close, timeperiod=14) |
MINUS_DM |
Minus Directional Movement |
负向移动指标 |
ta.MINUS_DM(high, low, timeperiod=14) |
MOM |
Momentum |
动量 |
ta.MOM(close, timeperiod=10) |
PLUS_DI |
Plus Directional Indicator |
正向指标 |
ta.PLUS_DI(high, low, close, timeperiod=14) |
PLUS_DM |
Plus Directional Movement |
正向移动指标 |
ta.PLUS_DM(high, low, timeperiod=14) |
PPO |
Percentage Price Oscillator |
价格百分比摆动指标 |
ta.PPO(close, fastperiod=12, slowperiod=26, matype=0) |
ROC |
Rate of change |
变动率指标 |
ta.ROC(close, timeperiod=10) |
ROCP |
Rate of change Percentage |
变动率百分比 |
ta.ROCP(close, timeperiod=10) |
ROCR |
Rate of change ratio |
价格比值 |
ta.ROCR(close, timeperiod=10) |
ROCR100 |
Rate of change ratio 100 scale |
价格比值*100 |
ta.ROCR100(close, timeperiod=10) |
RSI |
Relative Strength Index |
相对强弱指数 |
ta.RSI(close, timeperiod=14) |
STOCH |
Stochastic |
随机指标,俗称KD |
ta.STOCH(high, low, close, fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0) |
STOCHF |
Stochastic Fast |
随机指标快速线 |
ta.STOCHF(high, low, close, fastk_period=5, fastd_period=3, fastd_matype=0) |
STOCHRSI |
Stochastic Relative Strength Index |
随机相对强弱指标 |
ta.STOCHRSI(close, timeperiod=14, fastk_period=5, fastd_period=3, fastd_matype=0) |
TRIX |
1-day Rate-Of-Change (ROC) of a Triple Smooth EMA |
三重光滑EMA的日变化率 |
ta.TRIX(close, timeperiod=30) |
ULTOSC |
Ultimate Oscillator |
终极波动 指标 |
ta.ULTOSC(high, low, close, timeperiod1=7, timeperiod2=14, timeperiod3=28) |
WILLR |
Williams' %R |
威廉指标 |
Ta.WILLR(high, low, close, timeperiod=14) |
典型价格(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,而产生背离现象时,视为买进信号。
0 4 MFI 指标 Python 应用实例下面结合MFI 指标的超买超卖法则,以上证指数为标的,使用 Python 对其进行历史回测,主要利用了pandas、numpy、talib和matplotlib进行数据处理和可视化。
#先引入后面可能用到的包(package)import pandas as pd import numpy as npimport 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时,买入信号设置为1for i in range(15,len(df)):if df['mfi'][i]>20 and df['mfi'][i-1]<20:
df.loc[df.index[i],'收盘信号']=1if 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)
0 5结语
本文以MFI指标为例,简要介绍了动量指标的原理及其Python量化运用实例,由于篇幅有限,只给出了部分核心代码,完整代码可通过加入知识星球获取。
在指标运用中,不少交易者会产生困惑,有时指标严重超买,股价却继续上涨,或指标严重超卖,股价仍未止跌企稳。其实这是混淆了技术指标与股价的关系,指标并不能决定股价涨跌,股价才决定指标的大小,股价是因,指标是果,由因可推出果,但由果来导出因可能不准确。既然那样,技术指标还有什么用呢?
其实技术分析就如温度计,能够测量当前温度,却不能预测也不能决定未来温度。换句话说,技术指标虽不能预测未来走势,但可以衡量当前市场交投情况,用于确认趋势。也就是说技术指标可以作为辅助参考作用,当股价趋势继续上涨或下跌时,指标也将继续超买或超卖,而当股价一旦发生转势,指标随后也会发生转势买卖信号,为仓位管理和择时提供技术上的参考。