最近看到一个根据均线偏离度来进行投资的策略,今天在ETF基金定投中测试一下看看有无效果。

一、均线偏离策略

均线偏离策略是通过短期收盘价偏离长期均线的程度来设定不同的定投比例。

均线偏离程度是用偏离百分比来衡量,均线偏离百分比是指当前收盘价与长期均价差值占长期均价的百分比。长期均价为N日移动平均收盘价价格,N可以去不同的时间长度。

策略的思路是:根据收盘价偏离长期均线的程度不同,设置不同的定投投比例。

为了对比不同的偏离程度对定投的影响,采用如下两种方式:

(1)在偏离程度为负时将比例设的较大,负向偏离越远定投比例越大;在偏离程度为正时将定投比例设的较小,正向偏离越远定投比例越小。

(2)将正负偏离程度相同的定投比例设为一致。

定投比例设置如下表所示:

均线偏离度

<=-1.2

-1.2~-0.8

-0.8~-0.5

-0.5~0

0~0.5

0.5~1

1~2

>2

定投比例1

2.0

1.8

1.5

1.2

1.0

0.8

0.5

0

定投比例2

0.3

0.5

0.8

1.0

0.8

0.5

0.3

0

二、结果分析

本次测试直接采用的标的有跟踪大盘指数的沪深300ETF基金510300和跟踪创业板指数的创业板ETF基金159915。延续一致以来的习惯,还是采用傻瓜定投策略,即定时定额购买以上标的并一直持有至回测结束,定时每月的第一个交易日进行定投。

为了方便对比,这里首先采用5年定投方式,时间从2012年1月1日开始到2016年12月31日结束,采用的费率为0.05%,没有印花税。

代码如下:

import akshare as ak
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import pandas as pd
from math import sqrt, pow
import numpy as np
import numpy_financial as npf# 计算扣款比例
# def get_rate(data):  # 比例1
#     if data > 2:
#         return 0.0
#     elif data > 1:
#         return 0.5
#     elif data > 0.5:
#         return 0.8
#     elif data > 0:
#         return 1.0
#     elif data > -0.5:
#         return 1.2
#     elif data > -0.8:
#         return 1.5
#     elif data > -1.2:
#         return 1.8
#     else:
#         return 2.0def get_rate(data):  #比例2if data > 2:return 0.0elif data > 1:return 0.3elif data > 0.5:return 0.5elif data > 0:return 0.8elif data > -0.5:return 1.0elif data > -0.8:return 0.8elif data > -1.2:return 0.5else:return 0.3# 计算定投策略并得到买卖信号和仓位
def period_invest(stock_data, type='M', n=500):stock_data.index = pd.to_datetime(stock_data.date)stock_data = stock_data.sort_index()# 每月第一个交易日定投buy_month = stock_data.resample(type, kind='period').first()#print(buy_month)# 根据均线偏离程度计算定投比例# stock_data['short'] = stock_data.close.rolling(5).mean()stock_data['short'] = stock_data['close'].shift(1)stock_data['long'] = stock_data.close.rolling(n).mean()# NAN值如何处理?填1??stock_data['price_div'] = stock_data['short']/stock_data['long']-1stock_data['price_div'].fillna(3, inplace=True)# stock_data = stock_data.reset_index(drop=True)stock_data['rate'] = stock_data['price_div'].apply(lambda x: get_rate(x))# 定投购买指数基金stock_data['poschg'] = 0stock_data['OP_SIG'] = 0stock_data['invest'] = 0old_invest = 0#stock_data.index = range(len(stock_data))buy_month.index = range(len(buy_month))i = 0# comm_rate = 3 / 10000  # 费率# amount = 1000  # 定投金额global comm_rateglobal amountwhile i < len(buy_month):date = buy_month.loc[i, 'date']stock_data.loc[stock_data['date'] == date, 'OP_SIG'] = 1i += 1i = 0stock_data.index = range(len(stock_data))while i < len(stock_data):if stock_data.loc[i, 'OP_SIG'] == 1:price = stock_data.loc[i, 'open']rate = 1  # stock_data.loc[i, 'rate']# print(date, price, rate, amount * rate * (1 - comm_rate) / price)stock_data.loc[i, 'poschg'] = amount * rate * (1 - comm_rate) / price  # 定投日增加固定金额old_invest += amount * rateif abs(rate) < 0.1:stock_data.loc[i, 'OP_SIG'] = 0# print('%f,%f,%f' % (rate, amount, old_invest))stock_data.loc[i, 'invest'] = old_invest  # 累计投入金额i += 1stock_data['position'] = stock_data['poschg'].cumsum()  # 累计申购份额# stock_data['invest'] = amount * stock_data['rate'] * stock_data['OP_SIG'].cumsum()  # 累计投入金额stock_data['current'] = stock_data['close'] * stock_data['position']  # 累计现值stock_data['capital'] = stock_data['current'] / stock_data['invest']  # 累计净值stock_data['capital_rtn'] = stock_data['capital'].pct_change()  # 日涨跌幅stock_data['capital'].fillna(1, inplace=True)# 处理第一行数据为NAN问题stock_data.index = range(len(stock_data))stock_data.loc[0, 'change'] = stock_data.loc[0, 'close'] / stock_data.loc[0, 'open'] - 1stock_data.loc[0, 'capital_rtn'] = stock_data.loc[0, 'capital'] - 1return stock_data, buy_month# 计算最大回撤
def max_drawdown(date_list, capital_list):df = pd.DataFrame({'date': date_list, 'capital': capital_list})df['max2here'] = df['capital'].expanding().max()  # 计算当日之前的账户最大价值df['dd2here'] = df['capital'] / df['max2here'] - 1  # 计算当日的回撤# 计算最大回撤和结束时间temp = df.sort_values(by='dd2here').iloc[0][['date', 'dd2here']]max_dd = temp['dd2here']end_date = temp['date']# 计算开始时间df = df[df['date'] <= end_date]start_date = df.sort_values(by='capital', ascending=False).iloc[0]['date']# df.to_excel("dropdown.xlsx", sheet_name='capital', index=False)# print('最大回撤为:%f,开始日期:%s,结束日期:%s' % (max_dd, start_date, end_date))return max_dd, start_date, end_date# ====读取基金数据
code = '510300'
code = '159915'
df_small = pd.read_csv(code+'.csv', encoding='gbk')
# 使用copy()避免SettingWithCopyWarning
data = df_small[['交易日期', '开盘价', '最高价', '最低价', '收盘价', '成交量']].copy()
# 列名改为英文方便下面操作
data.rename(columns={'交易日期': 'date', '开盘价': 'open', '最高价': 'high', '最低价': 'low','收盘价': 'close', '成交量': 'volume'}, inplace=True)
data.index = pd.to_datetime(data.date)
data.index = data.index.strftime('%Y%m%d')
data = data.sort_index()
data['change'] = data['close'].pct_change(periods=1)  # 计算涨跌幅=change
# ====设置回测参数
amount = 1000  # 定投金额
trade_day = 244  # 每年平均交易日天数
s_date = '20120101'  # 回测开始日期
e_date = '20161231'  # 回测结束日期
# slippage_rate = 0.1 / 1000  # 滑点率
comm_rate = 5 / 10000  # 交易费率
# ====根据策略,计算仓位,资金曲线等
# 计算买卖信号
start_date=pd.to_datetime(s_date)
end_date=pd.to_datetime(e_date)
cond1 = data['date'] >= start_date.strftime('%Y-%m-%d')  # 从指定时间开始
cond2 = data['date'] <= end_date.strftime('%Y-%m-%d')  # 到指定时间结束
print("回测区间:%s-%s" % (s_date, e_date))
df = data[cond1 & cond2]
(df, buy_month) = period_invest(df, 'M', 250)# df['capital1'] = (df['capital_rtn'] + 1).cumprod()  # 计算累积收益率
df['stock'] = (df['change'] + 1).cumprod()  # 计算累积收益率---???算的什么???
df.to_excel("ETF定投策略-"+code+".xlsx", sheet_name='回测结果')
# ====根据策略结果,计算评价指标
# 计算股票和策略年收益
dft = df[['date', 'change', 'capital_rtn']].copy()
dft['date'] = pd.to_datetime(dft['date'])  # 将str类型改为时间戳格式
# 计算每一年股票、资金曲线的收益
year_rtn = dft.set_index('date')[['change', 'capital_rtn']].resample('A').apply(lambda x: (x + 1.0).prod() - 1.0)
year_rtn.dropna(inplace=True)
date_list = list(df['date'])
capital_list = list(df['capital'])
index_list = list(df['stock'])
dft = pd.DataFrame({'date': date_list, 'capital': capital_list, 'close': index_list})
dft.sort_values(by='date', inplace=True)
dft.reset_index(drop=True, inplace=True)
rng = pd.period_range(dft['date'].iloc[0], dft['date'].iloc[-1], freq='D')  # 创建时间范围,用于计算回测天数
capital_cum = dft['capital'].iloc[-1] / dft['capital'].iloc[0]
stock_cum = dft['close'].iloc[-1] / dft['close'].iloc[0]
# capital_annual = (dft['capital'].iloc[-1] / dft['capital'].iloc[0]) ** (trade_day / len(rng)) - 1
stock_annual = (dft['close'].iloc[-1] / dft['close'].iloc[0]) ** (trade_day / len(rng)) - 1
# invest_num = len(buy_month)
df['invest_chg'] = df['invest']-df['invest'].shift(1)
df['invest_chg'].fillna(amount, inplace=True)
pll = df.loc[df['OP_SIG'] == 1, 'invest_chg']
pll = -pll
invest_num = len(df[df['OP_SIG'] == 1])
fund = df['invest'].iloc[-1]
pl = [-1000] * (invest_num + 1)  # 建立irr计算用list
pl[:len(pll)] = pll[:len(pll)]
pl[invest_num] = df['current'].iloc[-1]  # 资金现值
month_capital = npf.irr(pl)  # 计算月收益
capital_annual = pow((1 + month_capital), 12)-1  # 计算年化收益
capital_drawdown = max_drawdown(date_list, capital_list)
stock_drawdown = max_drawdown(date_list, index_list)print('定投次数:%d  投入资金:%d  账户现值:%d' % (invest_num, fund, df['current'].iloc[-1]))
print('策略累积收益:%f  基金累积收益:%f' % (capital_cum, stock_cum))
print('策略年化收益:%.2f%%  基金年化收益:%.2f%%' % (round(100*capital_annual, 2), round(100*stock_annual, 2)))
print('策略最大回撤:%f,开始日期:%s,结束日期:%s' % capital_drawdown)
print('股票最大回撤:%f,开始日期:%s,结束日期:%s' % stock_drawdown)plt.gca().xaxis.set_major_locator(ticker.MultipleLocator(100))  # 设置x轴密度
plt.xticks(rotation=45)  # 旋转45度显示
plt.plot(df['date'], df['stock'], label=code+'收益')
plt.plot(df['date'], df['capital'], label='ETF定投收益')
plt.plot(df['date'], df['close'], label='收盘价')
plt.scatter(buy_month['date'], buy_month['close'], c='r', label='买点')
plt.ylabel("y轴", fontproperties="SimSun")
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.title("ETF定投策略回测(%s-%s)" % (s_date, e_date))
plt.legend(loc='best')
plt.savefig(code + '_' + '定投回测结果' + '.png')
plt.show()

1.不同定投比例及定投年限的影响

对于创业板ETF和沪深300ETF,在长期均价参数N分别等于500、250和180天的回测结果如下:

从表中可以看出,定投比例1和比例2对于收益结果的影响非常小。长期均价参数N的取值对于收益结果的影响较大,取值较大时年化收益较小。主要原因是跟定投实际发生的次数有关,定投次数过少时,长期均价波动加大,会导致整体收益会显著下降。策略对于5年定投最大回撤的影响较小。

另外,长期均线参数N的取值对沪深300ETF和创业板ETF的收益影响不同。对于沪深300ETF,N取250时可以获得最好收益;而对于创业板ETF,N取180时可以获得最好收益。

对于创业板ETF和沪深300ETF,在长期均价参数N分别等于500、250和180天的回测结果如下:

从表中可以看出,定投比例1和比例2对于收益结果的影响同样非常小。长期均价参数N的取值对于收益结果的影响也不大。主要原因应该是在定投次数达到一定界限后,长期均价波动对收益的影响会减弱。同样,策略对于10年定投最大回撤的影响较小。

另外,长期均线参数N的取值对沪深300ETF和创业板ETF的收益影响不同。对于沪深300ETF,N取250时可以获得最好收益;而对于创业板ETF,N取180时可以获得最好收益,N的取值继续降低,收益还会增加,但幅度很小。。

定投5年和10年的数据对比表明,定投时间增加后,长期均价的波动对收益的影响会减弱,年化收益基本上是小数点的区别了。

2.与无策略傻瓜定投的对比

下表是直接每月定投持续5年和10年的收益情况:

对比发现,均线偏离策略在参数设置不好的情况下,5年定投的收益不如每月直接定投;10年定投的收益跟每月直接定投也相差不大。

三、存在的问题

1.扣款比例的设置对定投结果影响较大。

比如扣款比例设置的过于极端,会导致定投的次数很少,结果最终收益会很差。主要原因是定投其实是通过在时间线上的平均分布来分摊风险,因为你既可能买到高价,也可能买到低价,概率上来说是均等的。如果参与次数过少,就会导致购买价格偏向某一个极端,而且这个是不可控的,如果价格偏高总体收益就很低。所以策略的选择需要考虑平衡,避免走极端。因为你错过了最好的收益,意味着大概率你也避开了最坏的收益。

2.过于复杂的策略存在很多意想不到的问题

比如刚开始预想的是当均线负偏离时多投,在正偏离是少投或者不投,结果发现在市场一直处于上升趋势时,基本没有多少定投的机会,然后收益也非常差。

四、结论

最近一段时间把ETF基金定投的各种方式都分析了一下,总体的感觉是,极端的策略不一定好,策略越极端,越有可能是在某些特定场景下才管用,碰到不合适的场景收益可能会很差。而且策略不是越复杂越好,没准弄了很久的一个策略,得到的结果跟直接定投差不太多,就是瞎折腾☹~~~

-----------------------------------

原创不易,请多支持!

ETF定投的均线偏离策略分析相关推荐

  1. 用 Pandas 分析均线交叉策略收益率

    在这篇文章中,我们会利用上一篇文章中的均线交叉策略回测中获得的结果(<用 Python 基于均线交叉策略进行回测>),并花一些时间更深入地挖掘权益曲线并生成一些关键绩效指标和一些有趣的数据 ...

  2. 数据分析——股票双均线策略分析

    在数据分析中,对于股票双均线策略分析是其中一个应用,这对于短期投资来说是非常有用的(虽然咱们不推荐). 什么是均线? 对于每一个交易日,都可以计算出前N天的移动平均值,然后把这些移动平均值连起来,成为 ...

  3. 周内效应对ETF定投的影响分析

    研究表明,A股市场存在显著的周内效应,且在不同的市场状态下有所差异.大多数指数在周一的平均收益率最高,周四的平均收益率最低.在上涨市场中,周一和周五的收益率显著为正.在下跌市场中,周二和周三表现相对较 ...

  4. 均线交易策略的回测 r_使用r创建交易策略并进行回测

    均线交易策略的回测 r R Programming language is an open-source software developed by statisticians and it is w ...

  5. 1-3移动均线交叉策略2

    第一阶段.一个简单策略入门量化投资 1-3移动均线交叉策略2 上一篇文章1-2 移动均线交叉策略1中我们最后提到: 如果我们从第一天买入股票,一直持有股票,最后一天卖出,获得的收益是每股124.02美 ...

  6. Python量化交易学习笔记(14)——均线交叉策略

    本文使用均线交叉策略,对平安银行自2018年1月1日至2020年2月28日的日线数据进行回测分析. 策略会用到短期移动均线及长期移动均线两个技术指标,在backtrader自定义策略init方法中,添 ...

  7. 高频交易(一)应用于高频交易中的对冲策略分析

    在数字货币市场,每天行情如过山车,让抄币者惊心动魄.能否在不关心行情的情况下实现对冲,在市场套利.那么,今天我们就研究一下在高频交易中的对冲策略.我们可以写一套软体,在我们设定目标的情况下,按照我么既 ...

  8. TokenGazer | HT的投资机会与策略分析

    前言 6月25日,TokenGazer官网发布HT的投资机会与策略分析,基于严谨的数据分析,站在客观的角度,为读者提供最优操作策略.读者想要第一时间掌握市场动态以及查看 TokenGazer 往期项目 ...

  9. 【技术分享】MA21日均线交易策略

    文章目录 1.前言 1.1.相关术语 1.2.MA均线系统设置分类 1.3.斐波那契数列 2.MA21日均线 2.1.MA21日均线 2.2.MA21日均线交易策略 2.3.MA21日均线案例分析 1 ...

  10. 2022-2028年中国海洋电力行业市场深度分析及发展策略分析报告

    [报告类型]产业研究 [报告价格]4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国海洋电力行业市场行业相关概述.中国海洋电 ...

最新文章

  1. 安装配置mysql-proxy
  2. 25个视频神同步,还能给视频声音移花接木,谷歌开源最新自监督算法
  3. 矩阵分析与多元统计II 二次型与二次曲面3 二次型及其标准形的定义
  4. 页面伪静态化 java_UrlRewrite 伪静态化页面
  5. sas数据导入终极汇总-之二
  6. android sendmessage和post的区别,handler中post和send方式区别
  7. Windows下搭建HTK
  8. 小米10鸿蒙版,小米10青春版高清渲染图公布:轻薄得不像5G手机
  9. [Android]对MVC和MVP的总结
  10. 读《About Face 4 交互设计精髓》22
  11. 集成简单的科大讯飞文字转语音
  12. 计算机网络故障是指啥,网络故障管理
  13. 成也史玉柱,败也史玉柱
  14. 表单美化 JS 库 securely
  15. 2021 牛津大学:Recent Advances in Reinforcement Learning in Finance
  16. 30分钟理解关键链--《突破项目的瓶颈--关键链 》读书笔记
  17. 微信小程序获取用户昵称和头像
  18. 2018上半年软件设计师上午试题参考答案
  19. php nslookup,nslookup - 运维猫的个人空间 - OSCHINA - 中文开源技术交流社区
  20. 【香蕉oi】Game(SAM,SG函数,假题)

热门文章

  1. 熵值法、灰色关联分析与层次分析法
  2. 【淘宝商家应用接口】拼多多平台流量解析,如何充分利用平台分配的流量?
  3. 及c语言实现 pdf,词法分析及其C语言实现.PDF
  4. MAC word2015 插入罗马字母
  5. 【Java实验】文件中单词重复字母对的查找
  6. Excel应用技巧之二——常用函数
  7. 乘法鉴相器的matlab仿真,Matlab仿真costas环代码问题。
  8. 解决 SSL握手失败问题
  9. 如何将本地应用制作成docker镜像
  10. 计算机一级用写在简历里面吗,写简历要小心,简历填写最忌讳的是什么,你知道吗?...