# DMA指标事件策略复现

By [不确定性守恒](https://paragraph.com/@uniswapv6) · 2022-06-10

---

[https://bbs.quantclass.cn/thread/12369](https://bbs.quantclass.cn/thread/12369)

一、指标说明
------

![](https://storage.googleapis.com/papyrus_images/195bf158ff7ff120a9c1bd549e6dd3864a78d428f4575f1ef2a3bf05546cc9e2.png)

二、策略代码
======

#### 2.1、指标计算

    def calculate(df, parameters, **kwargs):
        """
        计算单个币种的因子
        这边坚决不能进行去重或者删除空值等删除某行的操作
        :param df:  需要计算的币种数据
        :param parameters:  参数
        :param kwargs:    额外的参数
        :return:
        """
        N1,N2=parameters
        DMA=df['close'].rolling(window=N1).mean()-df['close'].rolling(window=N2).mean()
        df['{}_{}'.format(factor_name, parameters)]=DMA
        df['{}MA_{}'.format(factor_name,parameters)]=DMA.rolling(window=N1).mean()
        return df
    

#### 2.2、遍历代码

    def batch_parameters():
        """
        生成遍历的参数
        :return:
        """
    
        listp = [2, 3, 5, 9, 14, 23, 36, 57, 93]
        while len(listp)<20:
            _par=int(listp[-1]/0.8)
            listp.append(_par)
        parameters_list = []
        for short in listp:
            for long in listp:
                if short < long:
                    parameters_list.append([short, long])
        return parameters_list
    

#### 2.3、事件定义

当DMA值上穿其移动平均线时买入

    def event_strategy(df, params, **kwargs):
        """
        计算事件
        :param df: 数据
        :param params:
        :return:
        """
        event_name = '{}_{}'.format(strategy_name,params)  # 策略名称
        #-----long-------------
        #条件1，DMA上穿其均线，买入
        con1=df['DMA_{}'.format(params)]>df['DMAMA_{}'.format(params)]
    
        #条件2，上一周期，DMA在均线下
        #短线对应SMI
        df['DMA_shift_{}'.format(params)] = df.groupby('symbol')['DMA_{}'.format(params)].shift()
        #长线对应SMIMA
        df['DMAMA_shift_{}'.format(params)] = df.groupby('symbol')['DMAMA_{}'.format(params)].shift()
        con2=df['DMA_shift_{}'.format(params)] < df['DMAMA_shift_{}'.format(params)]
        df.loc[con1 & con2, event_name] = 1
    
        return df
    

三、回测结果（收益回撤比Top3）
=================

#### 3.1、TOP1资金曲线

![](https://storage.googleapis.com/papyrus_images/e6f022f99dde84d7270839bb00bd842d3054d93f0ef26150556690773c3134e5.png)

![](https://storage.googleapis.com/papyrus_images/fdea6b5c8a7ad542227901b4a2697c333fddbb8ec469f2e9babc38fa7d915c97.png)

#### 3.2、收益回撤比事件频率

![](https://storage.googleapis.com/papyrus_images/44bef6de310a6c510ed9df63526ac8790d4f8400dea66bbdee5bbf8e8585aba9.png)

![](https://storage.googleapis.com/papyrus_images/fdea6b5c8a7ad542227901b4a2697c333fddbb8ec469f2e9babc38fa7d915c97.png)

#### 3.3、回测评价

![](https://storage.googleapis.com/papyrus_images/612f131ab8c9db5332d2f44bbb79fa71e2bfbce518b5f98252b211ec78718f69.png)

#### 3.4、最优结果每年表现

![](https://storage.googleapis.com/papyrus_images/ec4c23206077859f8ca78a63476940499fbc72a93e2b58fa8442df50ded7f5fd.png)

#### 3.5、TOP1盈利最多三笔交易

![](https://storage.googleapis.com/papyrus_images/ffba46e6e8baafa963720646e01d2d9dddc37ef277ffcc68d038d7462132b2d0.png)

#### 3.6、TOP1亏损最多三笔交易

![](https://storage.googleapis.com/papyrus_images/b8ee635926aa1cc28edf2666543d6aafe897786fb1a7138b5a30fd1e64b5b399.png)

四、遍历结果（收益回撤比前十）
---------------

![](https://storage.googleapis.com/papyrus_images/bdc438a3617f315e6eed1dd56df15d6f3f8b91665527c46e6fb0f03b5786d1c2.png)

五、附件内容
======

#### 1、指标计算代码

    import pandas as pd
    factor_name = 'DMA'
    
    
    def special_data(candle_df, symbol, agg_dict, **kwargs):
        """
        导入额外的数据
        :param candle_df:   基础数据
        :param symbol:  币种名
        :param agg_dict:   转换周期的字典
        :return:
        """
    
        return candle_df, agg_dict
    
    
    def batch_parameters():
        """
        生成遍历的参数
        :return:
        """
    
        listp = [2, 3, 5, 8, 13, 21, 34, 55, 89]
        while len(listp)<20:
            _par=int(listp[-1]/0.8)
            listp.append(_par)
        parameters_list = []
        for short in listp:
            for long in listp:
                if short < long:
                    parameters_list.append([short, long])
        return parameters_list
    
    
    
    
    
    def calculate(df, parameters, **kwargs):
        """
        计算单个币种的因子
        这边坚决不能进行去重或者删除空值等删除某行的操作
        :param df:  需要计算的币种数据
        :param parameters:  参数
        :param kwargs:    额外的参数
        :return:
        """
        N1,N2=parameters
        DMA=df['close'].rolling(window=N1).mean()-df['close'].rolling(window=N2).mean()
        df['{}_{}'.format(factor_name, parameters)]=DMA
        df['{}MA_{}'.format(factor_name,parameters)]=DMA.rolling(window=N1).mean()
        return df
    
    
    def cross_section_calculate(df, parameters, **kwargs):
        """
        计算截面因子的函数
        :param df:  所有币种的数据
        :param parameters:  参数
        :param kwargs:    额外的参数
        :return:
        """
        df['{}_{}_排名' .format (factor_name, parameters)] = df.groupby('candle_begin_time')['{}_{}'.format(factor_name,parameters)].rank(ascending=False, method='first')
        return df
    

#### 2、事件生成代码

    # 事件需要的因子
    factors = ['DMA']
    # 事件的名称名
    strategy_name = 'DMA&event'  # 名称和程序文件名相同，不能含有_
    
    
    
    def batch_parameters():
        """
        生成遍历的参数
        :return:
        """
    
        listp = [2, 3, 5, 8, 13, 21, 34, 55, 89]
        while len(listp)<20:
            _par = int(listp[-1]/0.8)
            listp.append(_par)
        parameters_list = []
        for short in listp:
            for long in listp:
                if short < long:
                    parameters_list.append([short, long])
        return parameters_list
    
    
    
    def event_strategy(df, params, **kwargs):
        """
        计算事件
        :param df: 数据
        :param params:
        :return:
        """
        event_name = '{}_{}'.format(strategy_name,params)  # 策略名称
        #-----long-------------
        #条件1，DMA上穿其均线，买入
        con1=df['DMA_{}'.format(params)]>df['DMAMA_{}'.format(params)]
    
        #条件2，上一周期，DMA在均线下
        #短线对应SMI
        df['DMA_shift_{}'.format(params)] = df.groupby('symbol')['DMA_{}'.format(params)].shift()
        #长线对应SMIMA
        df['DMAMA_shift_{}'.format(params)] = df.groupby('symbol')['DMAMA_{}'.format(params)].shift()
        con2=df['DMA_shift_{}'.format(params)] < df['DMAMA_shift_{}'.format(params)]
        df.loc[con1 & con2, event_name] = 1
    
        return df
    

#### 3、遍历回测结果

[https://bbs.quantclass.cn/thread/12369](https://bbs.quantclass.cn/thread/12369)

[https://bbs.quantclass.cn/thread/12369](https://bbs.quantclass.cn/thread/12369)

---

*Originally published on [不确定性守恒](https://paragraph.com/@uniswapv6/dma)*
