请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  数理科学 帖子:3365785 新帖:17

DMA指标的趋势与择时效应

英雄就是我发表于:5 月 9 日 19:18回复(1)
"""导入常用模块"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
from jqdata import *
from environment import * # 导入大树工作室开发的回测模块
from jqlib.technical_analysis 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分析方法如下:

  1. DMA线向上交叉AMA线,买进;DMA线向下交叉AMA线,卖出。
  2. 当DMA和AMA均>0(即在图形上表示为它们处于零线以上)并向上移动时,一般表示为股市处于多头行情中,为买入信号,可以买入或持股;当DMA和AMA均<0(即在图形上表示为它们处于零线以下)并向下移动时,一般表示为股市处于空头行情中,为卖出信号,可以卖出股票或观望。
  3. 当DMA和AMA均<0时,经过一段时间的下跌后,如果两者同时从低位向上移动时,为买进信号;当DMA和AMA均>0,在经过一段时间的上涨后,如果两者同时从高位向下移动时,为卖出信号。
  4. DMA指标与股价产生背离时的交叉信号,可信度较高。
  5. 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,效果并不理想。也许,与其他指标结合使用,效果会更好。

这里只研究单一指标的择时效果,超出范围的不去涉猎,有兴趣的朋友,可以息行研究一下。

全部回复

0/140

量化课程

    移动端课程