VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 4669
声望: 285

发布于vn.py社区公众号【vnpy-community】
 
原文作者:Bili | 发布时间:2021-09-07
 

description

 

前情回顾

 

在前面的文章当中,我们对RSJ指标有了初步的了解,并且在RSJ指标样本内外实验中也取得一个不错的回测结果。接下来,我们将继续根据陶勤英博士的财通证券研究所的研报中所指出的将RSJ指标与其他技术指标组合使用来进行进一步的实验研究观察回测后的效果。

 

测试原理

 

首先,我们根据文章选取了另外三个技术指标,分别是DMI指标、RSI指标和ROC指标分别与RSJ指标进行叠加使用进行回测。所以接下来我们需要了解各个指标的基本原理以及他们的信号逻辑:

 

DMI指标

 

基本原理:DMI指标基本原理是在于寻找股票价格涨跌过程中,股价藉以创新高价或新低价的功能,研判多空力量,进而寻求买卖双方的均衡点及股价在双方互动下波动的循环过程。与大多数技术指标相比DMI指标把每日的高低波动的幅度因素计算在内,从而更加准确的反应行情的走势及更好的预测行情未来的发展变化。

信号逻辑:趋向技术指标 DMI 包括多空指标 PDI、MDI 以及趋向指标 ADX。我们针对 DMI 指标建立相应的择时策略,即若昨日的 ADX 大于前一日的 ADX,则今日在收盘的时候看多;若昨日的 ADX、PDI、MDI 均小于前一日的相对应的指标值,则今日在收盘的时候看空(其中,ADX 值若不在[20,60]之内,则不进行交易)。

 

RSI指标

 

基本原理:RSI的原理简单来说是以数字计算的方法求出买卖双方的力量对比,譬如有100个人面对一-件商品, 如果50个人以上要买,竞相抬价,商品价格必涨。相反,如果50个人以上争着卖出,价格自然下跌。

信号逻辑:对于相对强弱指标 RSI,两种力量的对比决定了个股及大盘所处的状态:强势或弱势。从 RSI 值的变动范围来看:当 20 < RSI <50 时,弱势,卖出,空仓;当 50 < RSI <80 时,强势,买入,持仓。因此,若昨日的 RSI 值在(50,80]内,则今日在收盘的时候看多;若昨日的RSI 值在[20,50)内,则今日在收盘的时候看空。

 

ROC指标

 

基本原理:变动率指标(ROC),是以当日的收盘价和N天前的收盘价比较,通过计算股价某一段时间内收盘价变动的比例,应用价格的移动比较来测量价位动量,达到事先探测股价买卖供需力量的强弱,进而分析股价的趋势及其是否有转势的意愿,属于反趋势指标之一。

信号逻辑:ROC指标测量股价动量,可以用来监视常态性和极端性两种行情,对买卖股票提供强有力的参考。ROC 变大,代表未来市场仍会在短时间内上涨,反之则代表市场可能下跌。因此,若昨日的 ROC 大于前一日的 ROC,则今日在收盘的时候看多;反之,发出看空信号。

 

代码分析

 

接下来,我们将正式进入我们的实验阶段。为了避免文章内容的重复,我们仅以RSJ+DMI为例,为大家进行代码分析:

在本策略当中,我们需要使用到两种K线——5分钟K线和日K线,所以我们还需创建日K线生成器DailyBarGenerator:

class DailyBarGenerator:

    def __init__(self, on_daily_bar: Callable) -> None:
        """日K线合成器"""        
        self.on_daily_bar: Callable = on_daily_bar        
        self.daily_bar: BarData = None        
        self.last_bar: BarData = None

接下来构造update_bar函数用于更新K线到容器中,缓存K线本身的OHLCV数据:

 def update_bar(self, bar: BarData) -> None:        
     """更新分钟K线"""        
     if not self.daily_bar:            
         dt = bar.datetime.replace(                
             hour=0,                
             minute=0,                
             second=0,                
             microsecond=0
        )

        self.daily_bar = BarData(
            symbol=bar.symbol,
            exchange=bar.exchange,
            datetime=dt,
            gateway_name=bar.gateway_name,
            open_price=bar.open_price,
            high_price=bar.high_price,
            low_price=bar.low_price
        )        
    # Otherwise, update high/low price into window bar        
    else:            
        self.daily_bar.high_price = max(
            self.daily_bar.high_price,
            bar.high_price
        )            
        self.daily_bar.low_price = min(
            self.daily_bar.low_price,
            bar.low_price
        )

        # Update close price/volume/turnover into window bar   
        self.daily_bar.close_price = bar.close_price      
        self.daily_bar.volume += bar.volume  
        self.daily_bar.open_interest = bar.open_interest

        # Check if window bar completed       
        if (    
            self.last_bar       
            and self.last_bar.datetime.date() != bar.datetime.date()        
        ):            
            self.on_daily_bar(self.daily_bar)       
            self.daily_bar = None

        # Cache last bar object      
        self.last_bar = bar

交易信号执行:

5分钟K线用于计算RSJ指标,我们需要先使用BarGenerator将1分钟K线合成为5分钟K线,日K线用于计算DMI指标:

def __init__(self, cta_engine, strategy_name, vt_symbol, setting):  
    """"""        
    super().__init__(cta_engine, strategy_name, vt_symbol, setting)

    self.bg = BarGenerator(self.on_bar, 5, self.on_5min_bar)    
    self.am = NewArrayManager()

    self.daily_bg = DailyBarGenerator(self.on_daily_bar)   
    self.daily_am = NewArrayManager()

计算技术指标:

分别将RSJ、ADX、PDI以及MDI指标计算出来:

    # 计算技术指标        
    self.rsj_value = self.am.rsj(self.rsj_window)

    adx_array = self.daily_am.adx(self.dmi_window, array=True)   
    pdi_array = self.daily_am.plus_di(self.dmi_window, array=True)      
    mdi_array = self.daily_am.minus_di(self.dmi_window, array=True)

    adx_value = adx_array[-1]

判断交易信号:

当 RSJ 和 DMI指标同时发出看多信号,则在当日收盘的时候发出看多信号;若两个指标同时发出看空信号,则在当日收盘的时候发出看空信号;否则,不发出任何信号。

    # 判断交易信号      
    target_pos = 0

    if bar.datetime.time() == time(14, 50):  
        # 满足开仓交易的ADX要求           
        if 20 <= adx_value <= 60:   
            # 做多条件               
            if (                   
                self.rsj_value < 0 
                and adx_array[-1] > adx_array[-2]         
            ):                 
                target_pos = 1           
            # 做空条件           
            elif (             
                self.rsj_value > 0   
                and adx_array[-1] < adx_array[-2]     
                and pdi_array[-1] < pdi_array[-2] 
                and mdi_array[-1] < mdi_array[-2] 
            ):                   
                target_pos = -1

交易逻辑:

基于目标仓位和实际仓位,决定如何交易:

            trade_volume = target_pos - self.pos
            if trade_volume > 0:    
                 if self.pos >= 0:      
                     self.buy(bar.close_price + 5, trade_volume)    
                 else:     
                    self.cover(bar.close_price + 5, trade_volume)           
             elif trade_volume < 0: 
                if self.pos <= 0:   
                    self.short(bar.close_price - 5, abs(trade_volume))     
                else:       
                    self.sell(bar.close_price - 5, abs(trade_volume))

tips:

由于策略中涉及到多个技术指标,代码变得较为复杂。所以在这时将计算技术指标、判断交易信号和交易逻辑三个部分分开来写,会让我们的代码变得更加清晰从而增加代码的可读性。

 

回测结果

 

我们用 2017 年 7 月 23 日-2020 年 7 月 22 日的数据,对该日内指标进行回测。指标当日发出信号后,分别于当日收盘分别对上证 50、沪深 300、中证 500指数进行操作。

实验一:RSJ + DMI

其中 DMI 组合指标时间参数为14。

  • 本地代码:IF888.CFFEX、IH888.CFFEX、IC888.CFFEX
  • K线周期:1分钟
  • 开始日期:2017-7-23
  • 结束日期:2020-7-22
  • 手续费率:0.00003
  • 交易滑点:0.4
  • 合约乘数:300
  • 价格跳动:0.2
  • 回测资金:100W

description

资金曲线的形状和财通研报中的结果基本一致 ,可以认为比较正确的复现了策略逻辑:

description

实验二:RSJ + RSI

其中 RSI 指标的时间参数为 6。

  • 本地代码:IF888.CFFEX、IH888.CFFEX、IC888.CFFEX

  • K线周期:1分钟

  • 开始日期:2017-7-23

  • 结束日期:2020-7-22

  • 手续费率:0.00003

  • 交易滑点:0.4

  • 合约乘数:300

  • 价格跳动:0.2

  • 回测资金:100W

description

资金曲线的形状和财通研报中的结果基本一致 ,可以认为比较正确的复现了策略逻辑:

description

实验三:RSJ + ROC

其中 ROC 指标参数为 12。

  • 本地代码:IF888.CFFEX、IH888.CFFEX、IC888.CFFEX

  • K线周期:1分钟

  • 开始日期:2017-7-23

  • 结束日期:2020-7-22

  • 手续费率:0.00003

  • 交易滑点:0.4

  • 合约乘数:300

  • 价格跳动:0.2

  • 回测资金:100W

description

资金曲线的形状和财通研报中的结果基本一致 ,可以认为比较正确的复现了策略逻辑:

description

结论:

RSJ指标分别与DMI、RSI和ROC指标组合使用的回测效果整体上资金曲线都是呈上扬趋势,但是对于部分品种来说资金曲线不太稳键,还有较大的改进提升空间。

 

代码获取

 

本文中提到的三个策略代码较长,就不在这里贴出了。请关注本公众号(vnpy-community)后,回复内容【RSJ】获取源代码下载链接。
 

Member
avatar
加入于:
帖子: 15
声望: 1

公众号获取到rsj_tool.py 和rsj_dmi_strategy.py两个文件,放入C:\Users\ccc\strategies里,打开CTA回测触发如下异常,请问该如何让rsj_dmi_strategy正常运行?

description

现在的版本是
description

11:48:19 初始化CTA回测引擎
11:48:19 策略文件strategies.rsj_dmi_strategy加载失败,触发异常:
Traceback (most recent call last):
File "C:\vnstudio\lib\site-packages\vnpy_ctabacktester\engine.py", line 107, in load_strategy_class_from_module
module = importlib.import_module(module_name)
File "C:\vnstudio\lib\importlib__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "C:\Users\ccc\strategies\rsj_dmi_strategy.py", line 15, in <module>
from rsj_tool import NewArrayManager, DailyBarGenerator
ModuleNotFoundError: No module named 'rsj_tool'

11:48:19 策略文件加载完成
11:48:19 RQData数据接口初始化成功

Administrator
avatar
加入于:
帖子: 4501
声望: 321

请将rsj_tool所在目录,添加到系统环境变量PYTHONPATH中

Member
avatar
加入于:
帖子: 15
声望: 1

问题已解决,谢谢

Member
avatar
加入于:
帖子: 18
声望: 0

我用的同花顺的数据,回测了2017-2021年...与楼主的回测结果基本吻合,只是最后一个策略出入较大...
而且,2020-2021年的回测结果不理想,收益曲线不再保持前面的上升角度了...
1 、RsjDmiStrategy:

description

2 、RsjRsiStrategy:

description

3 、RsjRocStrategy:

description

结论:
初步判断,RSJ+技术指标也无法穿越牛熊...
靠ALPHA盈利的策略想要多、空、横通杀...唯有靠预测(具有一定成功率的预测系统)来过滤交易信号...

Member
avatar
加入于:
帖子: 101
声望: 9

在公众号获取所有代码,里面都有。

Member
avatar
加入于:
帖子: 1
声望: 0

RSJ,求代码

Member
avatar
加入于:
帖子: 4669
声望: 285

1楼有介绍关注公众号(vnpy-community)后,回复内容【RSJ】获取源代码下载链接

Member
avatar
加入于:
帖子: 11
声望: 0

关注了公众号,也没链接。

Member
avatar
加入于:
帖子: 4669
声望: 285

有像8楼说的那样回复内容【RSJ】吗?

Member
avatar
加入于:
帖子: 58
声望: 0

这里日K线合成,对于有夜盘的品种,夜盘的数据合到当天的K线了去了。夜盘应该是次交易日的数据

Member
avatar
加入于:
帖子: 12
声望: 0

码一下,回头来看

© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】