OKEx数字货币量化交易策略系列报告(二)-均线交易策略研究报告
1.移动平均线
在所有的技术指标中,移动平均线的应用最为广泛。因为它的构造方法简便,且成绩易于定量地检验:在技术图表分析中,关于市场趋势的分析在很大程度上是基于分析师的主观判断,因此很难在计算机上进行量化;而移动均线的规则却不随分析师的主观意志而改变,可以简易地编写为计算机程序,然后自动生成买入和卖出信号。
从本质上而言,移动平均线是一种追踪趋势的工具,可以用以识别和显示旧趋势的终结或反转,以及新趋势的萌生。因此,移动平均线从来不会预期市场的走向,而是对市场已经发生的事实做响应。一般而言,根据计算方式的不同,移动平均线被分为简单移动平均(SMA),线性加权移动平均(WMA)和指数加权移动平均(EMA)。其中,线性加权移动平均(WMA)应用在量化上时涉及浮点问题,容易出现漏洞,因此本文着重介绍简单移动平均和指数加权移动平均在量化上的应用。
首先是简单移动平均。所谓简单移动平均其实就是算数平均。根据定义,第k个时间单位的m阶移动平均值(k>m)为:
我们以BTC每日收盘价为例,在python上运行以下程序可以得到其均线图:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pandas.plottingimport register_matplotlib_converters
register_matplotlib_converters()
data = pd.read_csv(rC:Users Desktop量化策略代码数据csvbtc永续30min.csv)
data.index = pd.to_datetime(data.iloc[:,0])
data_value = data.iloc[:,1]
#提取收盘价数据
close = data_value
#建立移动平均函数,获取移动平均值
def ma_function(k): #k为移动平均的滞后期数
#设置时间系列
MA_k = pd.Series(0,index=data.index)
#使用for循环求职
for i in range(k-1,len(close)):
MA_k[i] = sum(close[(i-k+1):(i+1)])/k
return MA_k
#在价格时序图上加入均线图
def picture_1(m,n): #m,n为移动平均滞后阶数,且m
ma_1 = ma_function(m)
ma_2 = ma_function(n)
plt.rcParams[axes.unicode_minus] = False
plt.rcParams[font.sans-serif] = SimHei
plt.plot(close[(n-1):],label=价格,color=k)
plt.plot(ma_1[(n-1):],label=MA_1,color=r)
plt.plot(ma_2[(n-1):],label=MA_2,color=y)
plt.title(BTC移动平均线与价格时序图)
plt.legend() #添加图例
plt.show()
return
另一类是指数加权移动平均,加权移动平均数是一种也别的移动平均,它给后期的价格给以较大的权重,而前期的价格给以较小的权重,并且囊括了金融产品自上市以来的所有历史价格,其计算公式如下:
在python上用代码表示,并做出EMA图如下:
#建立指数加权移动平均函数
def EMA_function(k,exponential=0.2):#k为滞后阶数,权重默认为0.2,可根据实际情况自行修改
ema_k = pd.Series(0,index=close.index)
ema_k[k-1] = np.mean(close[:k])
for i in range(k,len(close)):
ema_k[i] = exponential*close[i]+(1-exponential)*ema_k[i-1]
return ema_k
#在价格时序图上加入指数加权移动均线图
def picture_2(m): #m为移动平均滞后阶数
EMA = EMA_function(m)
plt.rcParams[axes.unicode_minus] = False
plt.rcParams[font.sans-serif] = SimHei
plt.plot(close[(m-1):],label=价格,color=k)
plt.plot(EMA[(m-1):],label=EMA,color=r)
plt.title(BTC移动平均线与价格时序图)
plt.legend() #添加图例
plt.show()
return
2.均线策略的使用
现在我们使用一个简单的双均线策略来构建一个简单的量化系统,这种技术被称为“双线相交法”:
当短期均线从下向上穿过长期均线时,为“黄金交叉”,释放买入信号;
当短期均线从上向下穿过长期均线时,为“死亡交叉”,释放卖出信号。
基于上述原理,我们构造如下交易系统(为方便调用,我们可以把交易系统封装成一个类,里面的各子系统再封装成函数):
#构建均线交易系统
class MA: #使用类封装单条均线系统
def signal_1(self,m,n): #m,n为均线滞后阶数,且m>n
ma_1 = ma_function(m)
ma_2 = ma_function(n)
signal = pd.Series(0,index=close.index)
for i in range(1,len(ma_2.index)):
#黄金交叉
if (ma_1[i]>ma_2[i]) & (ma_1[i-1]<ma_2[i-1]) :
signal[i] = 1
#死亡交叉
elif (ma_1[i]<ma_2[i]) & (ma_1[i-1]>ma_2[i-1]) :
signal[i] = -1
return signal
# 计算收益率
global r
r = close / close.shift(1) - 1
#构建交易系统
#黄金交叉买入
def trade_buy(self, m, n, k): #m,n为均线滞后阶数,且m>n; k 为信号滞后阶数
trade = self.signal_1(m, n).shift(k)
buy = pd.Series(0, index=close.index)
buy[trade == 1] = 1
#计算黄金交叉的收益率
r_buy = (buy*r).dropna()
r_buy_cum = np.cumprod(1+r_buy)-1
return r_buy_cum
#死亡交叉卖出
def trade_sell(self, m, n, k): # m,n为均线滞后阶数,且m>n; k 为信号滞后阶数
trade = self.signal_1(m, n).shift(k)
sell = pd.Series(0, index=close.index)
sell[trade == -1] = -1
# 计算死亡交叉的收益率
r_sell = (sell * r).dropna()
r_sell_cum = np.cumprod(1 + r_sell) - 1
return r_sell_cum
#综合收益率
def trade_all(self,m,n,k1,k2):# m,n为均线滞后阶数,且m>n; k1为买入信号滞后阶数,k2为卖出信号滞后阶数
trade_1 = self.signal_1(m, n).shift(k1)
buy = pd.Series(0, index=close.index)
buy[trade_1 == 1] = 1
trade_2= self.signal_1(m, n).shift(k2)
sell = pd.Series(0, index=close.index)
sell[trade_2 == -1] = -1
all = buy + sell
r_all= (all*r).dropna()
r_all_cum = np.cumprod(1+r_all) - 1
return r_all_cum
#市场同期收益率
def market(self):# m,n为均线滞后阶数,且m>n; k1为买入信号滞后阶数,k2为卖出信号滞后阶数
market_s = pd.Series(1, index=close.index)
r_market = (market_s*r).dropna()
r_m_cum= np.cumprod(1+r_market)-1
return r_m_cum
#作图
def picture_ma_1(self,m,n,k1,k2):# m,n为均线滞后阶数,且m>n; k1为买入信号滞后阶数,k2为卖出信号滞后阶数
a = self.trade_buy(m, n, k1)
b = self.trade_sell(m, n, k2)
c = self.trade_all(m, n, k1, k2)
# 设置字体为SimHei显示中文
plt.rcParams[font.sans-serif] = SimHei
# 解决负坐标问题
plt.rcParams[axes.unicode_minus] = False
plt.plot(a, label=ma_buy,color=r)
plt.plot(b, label=ma_sell, color=y)
plt.plot(c, label=ma_all, color=k)
plt.legend()
plt.show()
return
#作图2
def picture_ma_2(self,m,n,k1,k2):
# 设置字体为SimHei显示中文
plt.rcParams[font.sans-serif] = SimHei
# 解决负坐标问题
plt.rcParams[axes.unicode_minus] = False
c = self.trade_all(m, n, k1, k2)
d = self.market()
plt.plot(c, label=ma_all, color=r)
plt.plot(d, label=market, color=y)
plt.legend()
plt.title(均线策略累计收益率与市场同期累积收益率)
plt.show()
return
下面我们选取BTC季度合约30min收盘价数据,来测试上述均线策略的收益情况:
#导入数据
data = pd.read_csv(rC:UsersDesktop量化策略代码数据csvbtc永续30min_7月.csv)
#调用均线策略类
a = MA()
b = a.trade_buy(5,20,2)
c = a.trade_sell(5,20,1)
d = a.trade_all(5,20,2,1)
e = a.market()
data_ma = pd.DataFrame({buy:b,sell:c,all:d,market:e})
a.picture_ma_1(5,20,2,1)
a.picture_ma_2(5,20,2,1)
print(data_ma)
我们将“黄金交叉”点的买入累积收益、“死亡交叉”点的卖出累积收益和综合累积收益做对比,可以得到如下图所示,“黄金交叉”策略的收益更高一些。
另一方面,为了分析均线策略的实际效果,我们将均线策略的综合累积收益与市场累积收益做对比,结果如下:
从上图可以看出,相比于同期的市场收益情况,均线策略确实能取到一定的效果。
3.注意事项
均线策略多用在市场较为震荡的行情中,如果市场单一上涨或下跌,那么均线策略将发出错误信号。以BTC日收盘价为例,自今年3月以来,BTC一直上涨,累积涨幅目前高达3倍左右,如果使用均线策略,其收益便不如市场收益。
因此均线策略在日度策略中不建议常用,但可以用在15min、30min等高频以及高震荡的环境中。
本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:dacesmiling@qq.com