博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用talib实现基于emv的简易量化投资策略
阅读量:4209 次
发布时间:2019-05-26

本文共 10731 字,大约阅读时间需要 35 分钟。

前两天看到一篇论文《基于EMV指标的量化交易策略在我国A股市场的研究》,想想看我们学习talib中居然没有这个指标,至少目前还没碰见。作者通过EMV指标实现了年化20%的收益。对于一个本着学习目的的我来说,学一学EMV指标确实挺好。想想看要是自己也能开发这样一套系统的话,想想都觉得美滋滋。但毕竟咋不是专业的,野路子就要咋不断的动手了,希望黄天不负有心人吧!

1.EMV到底是什么?

简易波动指标(EMV),是为数不多的考虑价量关系的技术指标。它是根据成交量和人气的变化,构成一个完整的股价系统循环。该指标指示投资者在人气聚集且成交热络的时候买进股票,并且在成交量逐渐展现无力时,卖出股票。具体来说,当股价下跌时,由于买方萎靡退缩,致使成交量逐渐的减少,EMV数值也因而尾随下降,直到股价下跌至某一个合理支撑区,捡便宜货的买单促使成交量再度活跃,EMV 数值于是作相对反应向上攀升。所以EMV 指标的上升下降意味着市场的强弱变化,可以以此作为择时的判断依据。

2.EMV的计算公式

EM=((high[i]+low[i])/2-(high[i-1]+low[i-1])/2)*(high[i]-low[i])/volum[i]#EMV表示EM的n日平均值EMV=talib.SMA(EM,n)  #MAEMV表示m日的EMV的均值MAEMV=talib.SMA(EMV,m)

3.使用python实现上述公式并作图

def TEMV(data,fasttimeperiod,lasttimeperiod):    temp=data    temp['sub']=2    emFront=talib.DIV(talib.ADD(temp['high'],temp['low']),temp['sub'])    emFrontSub=talib.DIV(talib.ADD(temp['high'].shift(1),temp['low'].shift(1)),temp['sub'])    emEnd=talib.DIV(talib.SUB(temp['high'],temp['low']),temp['volume'])    em= talib.SUB(emFront,emFrontSub)*emEnd    EMV=talib.SMA(em,fasttimeperiod)    MAEMV=talib.SMA(EMV,lasttimeperiod)    return EMV,MAEMV

小结:通过上述简易的Demo,我们发现emv指标确实能够捕捉到一些信号。至少会比我盲听别人的观点强的多。作为一个专业搞软件的同学,我觉得咋就搭建一个系统然后做一个EMV策略。因为咋也没做过投资,那就按一般的常识做。当emv和maemv指数均大于0,并且emv指数上穿maemv我们就买入,当emv下穿maven咋就卖出。并设定投资金额是5000元人名币,每次笔交易的服务费是0.2%

策略运行结果如下:

分析一下:emv的周期我设置的是5,maemv的周期设置的是10,当emv和maemv指数均大于0,并且emv指数上穿maemv我们就买入,当emv下穿maven咋就卖出。每次买入信号来的时候买100股,每次卖出信号来的时候全部卖出。总之在年末我的账面资金是:

这里贴一下耗了一下午的策略。算是学了python吧

import talibimport matplotlib.pyplot as pltfrom matplotlib.pylab import date2numimport matplotlib.ticker as ticker  # 用于日期刻度定制import baostock as bsimport pandas as pdimport datetimefrom matplotlib import colors as mcolors  # 用于颜色转换成渲染时顶点需要的颜色格式from matplotlib.collections import LineCollection, PolyCollection  # 用于绘制直线集合和多边形集合from matplotlib.widgets import Cursor  # 处理鼠标totalRmb=10000handTotal=0buysell=[]myRmb=[]def date_to_num(dates):    num_time = []    for date in dates:        date_time = datetime.datetime.strptime(date,'%Y-%m-%d')        num_date = date2num(date_time)        num_time.append(num_date)    return num_time# 绘制蜡烛图def format_date(x, pos=None):    # 日期格式化函数,根据天数索引取出日期值    return '' if x < 0 or x > len(date_tickers) - 1 else date_tickers[int(x)]#EMV技术计算def TEMV(data,fasttimeperiod,lasttimeperiod):    temp=data    temp['sub']=2    emFront=talib.DIV(talib.ADD(temp['high'],temp['low']),temp['sub'])    emFrontSub=talib.DIV(talib.ADD(temp['high'].shift(1),temp['low'].shift(1)),temp['sub'])    emEnd=talib.DIV(talib.SUB(temp['high'],temp['low']),temp['volume'])    em= talib.SUB(emFront,emFrontSub)*emEnd    EMV=talib.SMA(em,fasttimeperiod)    MAEMV=talib.SMA(EMV,lasttimeperiod)    SubEmv=talib.SUB(EMV,MAEMV)    return EMV,MAEMV,SubEmv#策略def BuySallForEmv(Emv,MaEmv):    BuyIndex=[]    SallIndex=[]    temp=pd.DataFrame({ 'emv' :Emv, 'maemv' :MaEmv})    for index, row in temp.iterrows():        if row['emv'] is None:            continue        if row['emv'] > 0 and row['maemv']>0 and row['emv']>row['maemv']:            BuyIndex.append(index)        elif row['emv']>=0 and row['maemv']>=0 and row['emv']
0: totalRmb=totalRmb-currentRmb handTotal=handTotal+1 buysell.append(index-start) myRmb.append(totalRmb+handTotal*100*price) print("总金额:" + str(totalRmb) + " 总手数" + str(handTotal)+" 账户总金额:"+str(totalRmb+handTotal*100*price)) else: print("资金不足")#卖股票def Dosell(index,price): global buysell, myRmb global totalRmb, handTotal if handTotal>0: currentRmb=handTotal*100*price*0.998 totalRmb=totalRmb+currentRmb buysell.append(index-start) myRmb.append(totalRmb) handTotal=0 print("总金额:"+str(totalRmb)+" 总手数"+str(handTotal)+" 账户总金额:"+str(totalRmb)) else: print("不用再往出卖了")#历史回测def calculateHistory(doBuy,doSell): bySort=doBuy.index bySell=doSell.index doBuy['could']=1 doBuy['sort']=bySort doSell['could']=-1 doSell['sort']=bySell temp=pd.concat([doBuy,doSell]) wang=temp.sort_values(by="sort", ascending=True) for index, row in wang.iterrows(): print(str(index)+" "+str(row['could'])+" "+str(row['sort'])+" "+str(row['low'])) if row['could']==1: Dobuy(index,float(row['close'])) elif row['could']==-1: price=float(row['close']) Dosell(index,price)lg = bs.login()rs = bs.query_history_k_data_plus("sh.600567", "date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST", start_date='1999-07-01', end_date='2020-10-24', frequency="d", adjustflag="3")#### 打印结果集 ####data_list = []while (rs.error_code == '0') & rs.next(): data_list.append(rs.get_row_data())result = pd.DataFrame(data_list, columns=rs.fields)window=360start=len(result)-window#二维数组result=result.loc[:,['date','open','high','low','close','volume'] ]result=result[-window:]date_tickers=result.date.valuesresult.date = range(0, len(result)) # 日期改变成序号matix = result.values # 转换成绘制蜡烛图需要的数据格式(date, open, close, high, low, volume)xdates = matix[:,0] # X轴数据(这里用的天数索引)#总投资金额为5000元,买入信号出现时每次买一手。如果有卖出信号则全部卖出t3Price = talib.T3(result['close'], timeperiod=10, vfactor=0)Adxprice = talib.ADX(result['high'],result['low'],result['close'], timeperiod=5)Adxrprice = talib.ADXR(result['high'],result['low'],result['close'], timeperiod=5)emv,maemv,subemv=TEMV(result,5,10)buy,sell=BuySallForEmv(emv,maemv)realBuy=result.index.isin(buy)doBuy=result[realBuy]realSell=result.index.isin(sell)doSell=result[realSell]upperband, middleband, lowerband = talib.BBANDS(result['close'], timeperiod=5, nbdevup=2, nbdevdn=2, matype=0)# 设置外观效果plt.rc('font', family='Microsoft YaHei') # 用中文字体,防止中文显示不出来plt.rc('figure', fc='k') # 绘图对象背景图plt.rc('text', c='#800000') # 文本颜色plt.rc('axes', axisbelow=True, xmargin=0, fc='k', ec='#800000', lw=1.5, labelcolor='#800000', unicode_minus=False) # 坐标轴属性(置底,左边无空隙,背景色,边框色,线宽,文本颜色,中文负号修正)plt.rc('xtick', c='#d43221') # x轴刻度文字颜色plt.rc('ytick', c='#d43221') # y轴刻度文字颜色plt.rc('grid', c='#800000', alpha=0.9, ls=':', lw=0.8) # 网格属性(颜色,透明值,线条样式,线宽)plt.rc('lines', lw=0.8) # 全局线宽# 创建绘图对象和4个坐标轴fig = plt.figure(figsize=(16, 8))left, width = 0.05, 0.9ax1 = fig.add_axes([left, 0.6, width, 0.4]) # left, bottom, width, heightax2 = fig.add_axes([left, 0.5, width, 0.15], sharex=ax1) # 共享ax1轴ax3 = fig.add_axes([left, 0.35, width, 0.15], sharex=ax1) # 共享ax1轴ax4 = fig.add_axes([left, 0.2, width, 0.15], sharex=ax1) # 共享ax1轴ax5 = fig.add_axes([left, 0.05, width, 0.15], sharex=ax1) # 共享ax1轴plt.setp(ax1.get_xticklabels(), visible=False) # 使x轴刻度文本不可见,因为共享,不需要显示plt.setp(ax2.get_xticklabels(), visible=False) # 使x轴刻度文本不可见,因为共享,不需要显示plt.setp(ax3.get_xticklabels(), visible=False) # 使x轴刻度文本不可见,因为共享,不需要显示ax1.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) # 设置自定义x轴格式化日期函数ax1.xaxis.set_major_locator(ticker.MultipleLocator(max(int(len(result) / 15), 5))) # 横向最多排15个左右的日期,最少5个,防止日期太拥挤# # 下面这一段代码,替换了上面注释的这个函数,因为上面的这个函数达不到同花顺的效果opens, closes, highs, lows = matix[:, 1], matix[:, 4], matix[:, 2], matix[:, 3] # 取出ochl值avg_dist_between_points = (xdates[-1] - xdates[0]) / float(len(xdates)) # 计算每个日期之间的距离delta = avg_dist_between_points / 4.0 # 用于K线实体(矩形)的偏移坐标计算barVerts = [((date - delta, open), (date - delta, close), (date + delta, close), (date + delta, open)) for date, open, close in zip(xdates, opens, closes)] # 生成K线实体(矩形)的4个顶点坐标rangeSegLow = [((date, low), (date, min(open, close))) for date, low, open, close in zip(xdates, lows, opens, closes)] # 生成下影线顶点列表rangeSegHigh = [((date, high), (date, max(open, close))) for date, high, open, close in zip(xdates, highs, opens, closes)] # 生成上影线顶点列表rangeSegments = rangeSegLow + rangeSegHigh # 上下影线顶点列表print(rangeSegments)cmap = { True: mcolors.to_rgba('#000000', 1.0), False: mcolors.to_rgba('#54fcfc', 1.0) } # K线实体(矩形)中间的背景色(True是上涨颜色,False是下跌颜色)inner_colors = [cmap[opn < cls] for opn, cls in zip(opens, closes)] # K线实体(矩形)中间的背景色列表cmap = {True: mcolors.to_rgba('#ff3232', 1.0), False: mcolors.to_rgba('#54fcfc', 1.0)} # K线实体(矩形)边框线颜色(上下影线和后面的成交量颜色也共用)updown_colors = [cmap[opn < cls] for opn, cls in zip(opens, closes)] # K线实体(矩形)边框线颜色(上下影线和后面的成交量颜色也共用)列表#ax1.add_collection(LineCollection(rangeSegments, colors=updown_colors, linewidths=0.5,antialiaseds=False))# 生成上下影线的顶点数据(颜色,线宽,反锯齿,反锯齿关闭好像没效果)ax1.add_collection(PolyCollection(barVerts, facecolors=inner_colors, edgecolors=updown_colors, antialiaseds=False,linewidths=0.5))# 生成多边形(矩形)顶点数据(背景填充色,边框色,反锯齿,线宽)# 绘制均线mav_colors = ['#ffffff', '#d4ff07', '#ff80ff', '#00e600', '#02e2f4', '#ffffb9', '#2a6848'] # 均线循环颜色mav_period = [5, 10, 20, 30, 60, 120, 180] # 定义要绘制的均线周期,可增减# mav_period = [5] # 定义要绘制的均线周期,可增减n = len(result)for i in range(len(mav_period)): if n >= mav_period[i]: mav_vals = result['close'].rolling(mav_period[i]).mean().values ax1.plot(xdates, mav_vals, c=mav_colors[i % len(mav_colors)], label='MA' + str(mav_period[i]))for index, row in doBuy.iterrows(): ax1.scatter(index-start, float(row['close']), color="Y", marker="*")for index, row in doSell.iterrows(): ax1.scatter(index-start, float(row['close']), color="b", marker="^")calculateHistory(doBuy,doSell)ax1.plot(xdates,t3Price,label='t3price')ax1.set_title('sz.002918') # 标题ax1.grid(True) # 画网格ax1.legend(loc='upper left') # 图例放置于右上角ax1.xaxis_date() # 好像要不要效果一样?barVerts = [((date - delta, 0), (date - delta, vol), (date + delta, vol), (date + delta, 0)) for date, vol in zip(xdates, matix[:, 5])]# 生成K线实体(矩形)的4个顶点坐标ax2.add_collection(PolyCollection(barVerts, facecolors=inner_colors, edgecolors=updown_colors, antialiaseds=False,linewidths=0.5))# 生成多边形(矩形)顶点数据(背景填充色,边框色,反锯齿,线宽)if n >= 5: # 5日均线,作法类似前面的均线 vol5 = result['volume'].rolling(5).mean().values ax2.plot(xdates, vol5, c='y', label='VOL5')if n >= 10: # 10日均线,作法类似前面的均线 vol10 = result['volume'].rolling(10).mean().values ax2.plot(xdates, vol10, c='w', label='VOL10')ax2.yaxis.set_ticks_position('right') # y轴显示在右边ax2.legend(loc='upper left') # 图例放置于右上角ax2.grid(True) # 画网格ax3.plot(xdates, Adxprice, c='w', label='Adxprice')ax3.plot(xdates, Adxrprice, c='b', label='Adxrprice')ax3.legend(loc='upper left') # 图例放置于右上角ax3.grid(True) # 画网格ax4.plot(xdates,emv,c='r',label='EMV')ax4.plot(xdates,maemv,c='g',label='MAEMV')ax4.axhline(0, ls='-', c='w', lw=0.5) # 水平线ax4.legend(loc='upper left') # 图例放置于右上角ax4.grid(True) # 画网格ax5.axhline(10000, ls='-', c='w', lw=0.5) # 水平线ax5.plot(buysell, myRmb, c='g', label='割韭菜')ax5.legend(loc='upper left') # 图例放置于右上角ax5.grid(True) # 画网格cursor = Cursor(ax1, useblit=True, color='w', linewidth=0.5, linestyle='--')cursor1 = Cursor(ax3, useblit=True, color='w', linewidth=0.5, linestyle='--')cursor2 = Cursor(ax4, useblit=True, color='w', linewidth=0.5, linestyle='--')# 登出系统bs.logout()plt.show()‍

转载地址:http://olkmi.baihongyu.com/

你可能感兴趣的文章
ZooKeeper分布式锁
查看>>
3126 Prime Path
查看>>
app自动化测试---ADBInterface驱动安装失败问题:
查看>>
RobotFramework+Eclipse安装步骤
查看>>
测试的分类
查看>>
photoshop cc2019快捷键
查看>>
pycharm2019版本去掉下划线的方法
查看>>
SQL中EXISTS的用法
查看>>
10丨案例:在JMeter中如何设置参数化数据?
查看>>
11丨性能脚本:用案例和图示帮你理解HTTP协议
查看>>
12丨性能场景:做参数化之前,我们需要考虑什么?
查看>>
九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
查看>>
九度OJ 1092:Fibonacci (递归)
查看>>
九度OJ 1093:WERTYU (翻译)
查看>>
九度OJ 1094:String Matching(字符串匹配) (计数)
查看>>
九度OJ 1095:2的幂次方 (递归)
查看>>
九度OJ 1471-1480(10/10)
查看>>
九度OJ 1481-1490(7/10)
查看>>
九度OJ 1491-1500(5/10)
查看>>
九度OJ 1501-1510(10/10)
查看>>