RSI指标策略
策略介绍
RSI(相对强弱指标),是通过一段时期内的平均收盘上涨和下跌数,计算价格上涨所产生的波动占整个波动的百分比,来分析市场买卖盘的意向和实力。
计算公式(以日为单位举例)
RSI的计算很简单,公式如下:
RSI(N) = A / (A + B) * 100
其中,N为计算RSI的回看窗口,A为N日内收盘涨幅之和,B为N日内收盘跌幅之和的绝对值。
使用方法
从RSI的公式我们可以看出,RSI一定是一个介于0和100之间的数。RSI值越大,说明近一段时间内价格上涨所产生的波动占整个波动的比例越大。当RSI超过70时,我们认为涨幅过于强劲,接下来很有可能会反转下跌,所以定义70以上的区域为超买区,应当卖出。反之,我们定义30以下的区域为超卖区,应当买入。注意,这里的30和70的阈值设定,并不是绝对的。根据不同标的,不同行情,以及不同投资者的风险偏好,可以适当调整。
优点
RSI指标能够较为直观且有效的显示出一段时期内买卖双方的力量对比,帮助投资者较好的认清市场动态,掌握买卖时机,被多数投资者喜爱,尤其是短线操作中尤为给力,是最常用的技术指标之一。
缺点
由于RSI是一个比率指标,在趋势分析中会比较弱,尤其是遇到单边行情时,出现的指标钝化现象会让投资者过早卖出或者买入。而且RSI指标只考虑收盘价,完全忽略日内的波动,在大幅震荡的行情会丢失很多有效信息。短期RSI信号频繁但可靠性差,而长期RSI的买卖信号反应迟缓,容易错过良机。
RSI指标可以和一些趋势指标一起使用,如MACD,KDJ等,来弥补自身的缺陷。有兴趣的同学可以深入研究下。
回测
- 参数设置
时间段 | 2015-01-01至2016-10-10 |
---|---|
回测频率(context.frequency) | 1d |
超卖线 | 20 |
超买线 | 80 |
回看时间窗口 | 21(天) |
这里使用的超买超卖线为80/20,比上文中提到的70/30更极端,更不容易触发。这里的考虑主要是数字货币市场十分不稳定,暴涨暴跌都很容易发生,如果超买超卖线设置的太宽松,会产生很多干扰信号。而回看时间窗口的设定,也应当视市场情况而定。时间窗口短时,RSI指标更为敏感,但快速震荡次数较多,可靠性差;而时间窗口长时,RSI指标更为准确可靠,但敏感性不够,反应迟缓,容易错过买卖良机。
- 回测结果:
在15年这一整年的回测中,策略收益明显好于基准,波动以及回撤也都相对较小。但是,我们应注意到,我们的策略在10月下旬的一波快速上涨中,早早的产生了超买信号,提前下车,错过了这段牛市。这正是上文中我们提到的RSI指标的缺点,在单边行情中容易过早的产生买入/卖出的信号。
总结
RSI指标利用一段时期内上涨和下跌的比例,来反映市场的景气程度,并对未来做出预测。但同时,RSI指标也有很多缺点,尤其在大牛市和大熊市这种单边行情中尤为明显。所以,在使用RSI时,应当结合其他指标一起使用。
代码
# !/usr/bin/env python # -*- coding: utf-8 -*- # 策略代码总共分为三大部分,1)PARAMS变量 2)initialize函数 3)handle_data函数 # 请根据指示阅读。或者直接点击运行回测按钮,进行测试,查看策略效果。 # 策略名称:RSI指标策略 # 策略详细介绍:https://wequant.io/study/strategy.rsi.html # 关键词:相对强弱、逆市指标。 # 方法: # 1)通过特定周期内涨幅和跌幅的对比,来确定多头和空头的强弱; # 2)设置超买超卖线线,制定买入卖出计划 import numpy as np import talib # 阅读1,首次阅读可跳过: # PARAMS用于设定程序参数,回测的起始时间、结束时间、滑点误差、初始资金和持仓。 # 可以仿照格式修改,基本都能运行。如果想了解详情请参考新手学堂的API文档。 PARAMS = { "start_time": "2017-06-01 00:00:00", "end_time": "2017-08-01 00:00:00", "slippage": 0.003, # 此处"slippage"包含佣金(千二)+交易滑点(千一) "account_initial": {"huobi_cny_cash": 100000, "huobi_cny_btc": 0}, } # 阅读2,遇到不明白的变量可以跳过,需要的时候回来查阅: # initialize函数是两大核心函数之一(另一个是handle_data),用于初始化策略变量。 # 策略变量包含:必填变量,以及非必填(用户自己方便使用)的变量 def initialize(context): # 设置回测频率, 可选:"1m", "5m", "15m", "30m", "60m", "4h", "1d", "1w" context.frequency = "4h" # 设置回测基准, 比特币:"huobi_cny_btc", 莱特币:"huobi_cny_ltc", 以太坊:"huobi_cny_eth" context.benchmark = "huobi_cny_btc" # 设置回测标的, 比特币:"huobi_cny_btc", 莱特币:"huobi_cny_ltc", 以太坊:"huobi_cny_eth" context.security = "huobi_cny_btc" # 设置使用talib计算rsi的参数 # 买入线 context.user_data.lower_rsi = 20 # 卖出线 context.user_data.upper_rsi = 80 # 获取历史数据的长度 context.user_data.rsi_window = 21 # 至此initialize函数定义完毕。 # 阅读3,策略核心逻辑: # handle_data函数定义了策略的执行逻辑,按照frequency生成的bar依次读取并执行策略逻辑,直至程序结束。 # handle_data和bar的详细说明,请参考新手学堂的解释文档。 def handle_data(context): # 获取历史数据, 取后rsi_window根bar hist = context.data.get_price(context.security, count=context.user_data.rsi_window+1, frequency=context.frequency) if len(hist.index) < context.user_data.rsi_window+1: context.log.warn("bar的数量不足, 等待下一根bar...") return # 历史收盘价 prices = np.array(hist["close"]) # 初始化买入/卖出信号 long_signal_triggered = False short_signal_triggered = False # 计算RSI值 rsi = talib.RSI(prices, context.user_data.rsi_window)[-1] # 产生买入/卖出信号 if rsi < context.user_data.lower_rsi: long_signal_triggered = True elif rsi > context.user_data.upper_rsi: short_signal_triggered = True context.log.info("当前 RSI = %s" % rsi) # 有卖出信号,且持有仓位,则市价单全仓卖出 if short_signal_triggered: context.log.info("RSI值超过了超买线,产生卖出信号") if context.account.huobi_cny_btc >= HUOBI_CNY_BTC_MIN_ORDER_QUANTITY: context.log.info("正在卖出 %s" % context.security) context.log.info("卖出数量为 %s" % context.account.huobi_cny_btc) context.order.sell(context.security, quantity=str(context.account.huobi_cny_btc)) else: context.log.info("仓位不足,无法卖出") # 有买入信号,且持有现金,则市价单全仓买入 elif long_signal_triggered: context.log.info("RSI值超过了超卖线,产生买入信号") if context.account.huobi_cny_cash >= HUOBI_CNY_BTC_MIN_ORDER_CASH_AMOUNT: context.log.info("正在买入 %s" % context.security) context.log.info("下单金额为 %s 元" % context.account.huobi_cny_cash) context.order.buy(context.security, cash_amount=str(context.account.huobi_cny_cash)) else: context.log.info("现金不足,无法下单") else: context.log.info("无交易信号,进入下一根bar")
回测