"""导入常用模块"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from environment import * # 导入大树工作室开发的回测模块
计算DMA与画图的公用函数
"""公用函数"""
def get_dma(security, start_date=None, end_date=None, count=1, n1=10, n2=50, m=10):
price = get_price(security=security,
start_date=start_date,
end_date= end_date,
frequency='daily',
fields=None,
skip_paused=False,
count=count+n2+m,
fq='pre')
ma1 = price['close'].rolling(n1).mean()
ma2 = price['close'].rolling(n2).mean()
DMA = ma1 - ma2
AMA = DMA.rolling(m).mean()
return DMA[-count:].values, AMA[-count:].values
def show_dma(DMA, AMA):
plt.figure(figsize=(16, 3))
plt.plot(DMA)
plt.plot(AMA)
plt.show()
平行线差指标
平行线差(DMA)指标是利用两条不同期间的平均线,来判断当前买卖能量的大小和未来价格趋势。DMA指标是一种中短期指标。
计算公式
- DMA=股价短期平均值—股价长期平均值
- AMA=DMA短期平均值
- 以求10日、50日为基准周期的DMA指标为例,其计算过程具体如下:
- DMA(10)=10日股价平均值—50日股价平均值
- AMA(10)=10日DMA平均值
- 和其他指标的计算一样,由于选用的计算周期的不同,DMA指标也包括日DMA指标、周DMA指标、月DMA指标年DMA指标以及分钟DMA指标等各种类型。经常被用于股市研判的是日DMA指标和周DMA指标。虽然它们的计算时的取值有所不同,但基本的计算方法一样。
常用的DMA分析方法如下:
- DMA线向上交叉AMA线,买进;DMA线向下交叉AMA线,卖出。
- 当DMA和AMA均>0(即在图形上表示为它们处于零线以上)并向上移动时,一般表示为股市处于多头行情中,为买入信号,可以买入或持股;当DMA和AMA均<0(即在图形上表示为它们处于零线以下)并向下移动时,一般表示为股市处于空头行情中,为卖出信号,可以卖出股票或观望。
- 当DMA和AMA均<0时,经过一段时间的下跌后,如果两者同时从低位向上移动时,为买进信号;当DMA和AMA均>0,在经过一段时间的上涨后,如果两者同时从高位向下移动时,为卖出信号。
- DMA指标与股价产生背离时的交叉信号,可信度较高。
- DMA指标亦适于结合形态理论进行分析。
“”6. DMA指标、MACD指标、TRIX指标三者构成一组指标群,互相验证。
展示沪深300一段时期的DMA曲线图
trade_date = get_trade_days(end_date=datetime.datetime.now(), count=100)
DMA, AMA = get_dma('000300.XSHG', end_date=trade_date[-1], count=300)
show_dma(DMA, AMA)
回测条件一
DMA线向上交叉AMA线,买进;DMA线向下交叉AMA线,卖出。
"""初始化以下内容"""
context = Context() # 账户对象
order = Order(context) # 下单对象
trade = Trade(context, order) # 回测对象
context.start_date = '2005-05-01'
context.end_date = '2018-12-31'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'
"""策略主体"""
def handle(context, order):
stock = '000300.XSHG'
DMA, AMA = get_dma(stock, end_date=trade.context.current_dt, count=2)
close = get_price(security=stock,
end_date=context.current_dt,
frequency='daily',
fields=None,
skip_paused=False,
fq='pre',
count=5)['close'][-1]
if DMA[-2] < AMA[-2] and DMA[-1] > AMA[-1]:
if stock in context.position.keys():
return
else:
order.buy(stock, close, context.cash // close)
elif DMA[-2] > AMA[-2] and DMA[-1] < AMA[-1]:
if stock not in context.position.keys():
return
else:
order.sell(stock, close, context.position[stock]['count'])
"""执行策略"""
trade.trade(handle)
2019-02-23 17:49:39.306499,回测完毕,用时0:00:17.551996
上例中的金叉与死叉时间间隔只有一天,这个时间间隔可以是1~10天,因此可将这个时间间隔当作一个可被调节的参数,并回测最优的时间间隔。
date_long = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 这里只测这几个吧
trade_list = []
for long in date_long:
"""初始化以下内容"""
context = Context() # 账户对象
order = Order(context) # 下单对象
trade = Trade(context, order) # 回测对旬
context.start_date = '2005-05-01'
context.end_date = '2018-12-31'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'
"""策略主体"""
def handle(context, order):
stock = '000300.XSHG'
DMA, AMA = get_dma(stock, end_date=trade.context.current_dt, count=long+1)
close = get_price(security=stock,
end_date=context.current_dt,
frequency='daily',
fields=None,
skip_paused=False,
fq='pre',
count=long+1)['close'][-1]
if DMA[-1-long] < AMA[-2] and DMA[-1] > AMA[-1]:
if stock in context.position.keys():
return
else:
order.buy(stock, close, context.cash // close)
elif DMA[-1-long] > AMA[-2] and DMA[-1] < AMA[-1]:
if stock not in context.position.keys():
return
else:
order.sell(stock, close, context.position[stock]['count'])
"""执行策略"""
trade.trade(handle, False)
trade_list.append(trade)
# 展示
Trade.show_ratio_compare('date_long', date_long, trade_list, 3, 3)
Trade.show_result('date_long', date_long, trade_list)
2019-02-23 17:41:16.143275,回测完毕,用时0:00:17.396257
2019-02-23 17:41:33.206154,回测完毕,用时0:00:17.062726
2019-02-23 17:41:50.431428,回测完毕,用时0:00:17.225110
2019-02-23 17:42:07.762340,回测完毕,用时0:00:17.330767
2019-02-23 17:42:24.838906,回测完毕,用时0:00:17.076416
2019-02-23 17:42:42.313726,回测完毕,用时0:00:17.474663
2019-02-23 17:42:59.851819,回测完毕,用时0:00:17.537938
2019-02-23 17:43:16.871338,回测完毕,用时0:00:17.019358
2019-02-23 17:43:34.322078,回测完毕,用时0:00:17.450586
结论:
计算金叉死叉的时间间隔最优秀的是9,也就是10天之前。不过,整体回测效果并不好。看来单独使用这个指标,在金叉死叉的买卖方法上并不好使。
回测条件二
当发生背离时,即价格逐渐走低,而DMA逐渐走高时,买入;当价格逐渐走高,而DMA逐渐走低时,卖出。其中,判断背离需要有一个时间间隔,这里仍旧回测不同时间间隔下的效果。
date_long = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 这里只测这几个吧
trade_list = []
for long in date_long:
"""初始化以下内容"""
context = Context() # 账户对象
order = Order(context) # 下单对象
trade = Trade(context, order) # 回测对旬
context.start_date = '2005-05-01'
context.end_date = '2018-12-31'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'
"""策略主体"""
def handle(context, order):
stock = '000300.XSHG'
DMA, AMA = get_dma(stock, end_date=trade.context.current_dt, count=long+2)
close = get_price(security=stock,
end_date=context.current_dt,
frequency='daily',
fields=None,
skip_paused=False,
fq='pre',
count=long+2)['close']
close1 = close[-1-long]
close2 = close[-1]
DMA1 = DMA[-1-long]
DMA2 = DMA[-1]
# 产生买入的背离信号
if close2 < close1 and DMA2 > DMA1:
if stock in context.position.keys():
return
else:
order.buy(stock, close2, context.cash // close2)
elif close2 > close1 and DMA2 < DMA1:
if stock not in context.position.keys():
return
else:
order.sell(stock, close2, context.position[stock]['count'])
"""执行策略"""
trade.trade(handle, False)
trade_list.append(trade)
# 展示
Trade.show_ratio_compare('date_long', date_long, trade_list, 3, 3)
Trade.show_result('date_long', date_long, trade_list)
2019-02-23 18:34:52.960845,回测完毕,用时0:00:16.602134
2019-02-23 18:35:10.298780,回测完毕,用时0:00:17.337748
2019-02-23 18:35:27.256697,回测完毕,用时0:00:16.957756
2019-02-23 18:35:43.215573,回测完毕,用时0:00:15.958712
2019-02-23 18:36:00.272317,回测完毕,用时0:00:17.056580
2019-02-23 18:36:17.469745,回测完毕,用时0:00:17.197248
2019-02-23 18:36:34.328112,回测完毕,用时0:00:16.858203
2019-02-23 18:36:51.307217,回测完毕,用时0:00:16.978911
2019-02-23 18:37:08.102706,回测完毕,用时0:00:16.795313
结论:
时间间隔为4天的背离计算,得到的回测结果最优,但整体来说,效果并不是很好。看来,单独使用DMA,效果并不理想。也许,与其他指标结合使用,效果会更好。
这里只研究单一指标的择时效果,超出范围的不去涉猎,有兴趣的朋友,可以自行研究一下。
网友评论