RSI BB 还是RSI & BB? 很简单,让我们用 Elasticsearch 来实现吧!

转贴作者原创于CSDN相关文章

**相对强弱指数** (Relative Strength Index) 是 J. Walles Widler Jr. 于 1978 年开发,到现在也经常使用的一项技术分析指标,主要用于判断股票或商品的超买或超卖情况。 与 MACD 一样,相对强弱指数(RSI) 是一个趋势跟踪动量指标。RSI与MACD 不同之处在于它衡量的是收益和损失的移动平均线,而不是价格变化的移动平均线。 当近期收益增加时 RSI 值增加,当近期损失增加时 RSI 值减少。

在之前所写《当 MACD 与布林带在 Elasticsearch中结合时, …》一文中,MACD 和布林带(BB) 是紧耦合在一起。 计算MACD BB 的BB是基于MACD 值而不是每日价格。然而,在WEB 上同时出现RSI和BB的相关文章,大多数是基于价格来构建BB。根据发布在Investopedia的《How Do I Create a Trading Strategy with Bollinger Bands and the RSI? 》一文中,作者建议使用 RSI 的结论作为补充证据,以确认从布林带总结出价格提高或降低趋势。当价格到达布林带上限 (BBU)且RSI读数为 70+ 时,可以确认超买信号增强。当价格到达布林带下限 (BBL) 且 RSI 低于 30- 时,可以确认超卖信号增强。在本文中,我们将按照 MACD BB 方法检验 RSI BB,看看对趋势的确认是否有帮助。本文将使用 Elasticsearch 来实现,处理过程显示了无缝集成并且易于理解。推荐读者阅读我之前所写的文章,可快速对BB和使用Elasticsearch的实现细节有一个基本的了解。

前面说过,RSI的计算涉及近期平均收益(gain)和近期平均亏损(loss)两种数据,周期一般为14。 当天的收益定义为当前价格大于前一个价格时的差额,否则收益为0。同理,当天的亏损定义为当前价格小于前一个价格时的差额绝对值,否则损失为 0。 对于滑动窗口(window) 为n,最近平均收益可以简单移动平均收益(SMAgain,n) 表示。最近平均损失可以简单移动平均损失(SMAloss,n) 表示。然而简单移动平均函数(SMA)默认只使用过去数据,但是RSI 需要包括当前数据。 因此将 SMA 向右移动 1 个数据,并表示为 SMAgain,n,1 和 SMAloss,n,1。 因此,RSI 的方程可以改写如下:
在这里插入图片描述
在《使用Elasticsearch计算布林带宽度指标》一文中, BB基于SMA和每日价格(Daily)的标准差 (SD) 以构建BBU 和BBL。 BB 的中线是 SMA。 滑动窗口window为20或26,标准差n的个数在通常情况下为1或2。
在这里插入图片描述
如果使用与MACD BB相同的概念,RSI BB 将定义如下:
在这里插入图片描述
本文尝试将 RSI & BB 和 RSI BB 应用Tushare大数据开放社区提供的股票型公募基金,并专注于将 Elasticsearch 作为分析工具。 下面的例子随机选择了"工银研究精选股票" (代码为000803.OF)。 数据选自提供的 2021年01月01日到2021年04月30日之间的时间范围。RSI的窗口是14,SMA的窗口是20,标准差的个数是2。

在下面的两个图表中,首先RSI与每日的复权单位净值(Daily)一起绘制,RSI大于 70 并与前一个时间戳中的RSI值相比是一个增量,使用水蓝色点。如果 RSI大于 70但为减量,则为蓝色点。RSI小于30并与前一个时间戳中的RSI值相比是一个减量,则为红色点。如果RSI小于30但为减量,则为橙色点。 对于其他情况,则为灰色点。RSI图表与之后显示的 MACD图表相比,RSI 似乎是一个更好的净值趋势跟踪指标,当然这可能只是个案。而且还观察到RSI能够紧紧跟随Daily的急速上升趋势,能够给予确认的帮助。

在这里插入图片描述
在这里插入图片描述
现在,让我们看看 RSI 如何帮助 BB 支持或减少价格趋势的可能性。 下图显示了使用与前相同的时间范围每日复权单位净值(Daily) 的BB。 当RSI读数超过 70时,甚至达到100,但是Daily仍然没有到达BBU,这意味着RSI指标无法帮助确认超买信号,但价格呈现随即急速下降趋势。在类似的情况下,最后两个红点发生在RSI读数从30以下穿越过30时,价格仍然没有到达BBL,也意味着RSI指标无法帮助确认超卖信号,但价格呈现随即急速上升趋势。总之,RSI & BB在这个场景中不能把握这两个很好的买卖点。
在这里插入图片描述
在检验了RSI & BB之后,让我们看看 RSI BB 的表现如何。 下图使用与前相同的时间范围绘制并使用RSI值计算BB。 基本上,上面讨论的两种糟糕情况可以通过RSI BB来解决。在前段当价格呈现急速下降趋势前,RSI读数>70并两次来回穿越过RSI_BBU。在后段当价格呈现急速上升趋势前,RSI读数>30并来回穿越过RSI_BBL。综合上述所得,RSI BB在这个场景中能把握这两个很好的买卖点。读者可以进一步分析个案在什么场景中适合使用。
在这里插入图片描述
以下阐释如何使用Elasticsearch实现RSI BB及RSI &BB。 假设有一个填充有数据的 Elasticsearch 索引,其使用的数据映射与之前发表的文章(使用Elasticsearch计算布林带宽度指标)相同。以下步骤演示了 REST API 请求正文的代码。

  1. 通过搜索操作收集所有相关文档
    使用带有必要条件(must)子句的布林查询(bool query)来收集基金代码为000803.OF,和公告截止日期从2021年01月01日到2021年04月30日的文档。 由于需要计算20天的移动平均值,因此增加了一个月的数据(从2020年12月01日到2020年12月31日)。
{
    "query": {
        "bool": {
		     "must": [
		         {"range": {"end_date": {"gte": "20201201", "lte": "20210430"}}},
		         {"term": {"ts_code": "000803.OF"}}
		     ]
		}
	},
  1. 提取每日的复权单位净值
    使用名为RSI_BB日期直方图(date_histogram)存储桶聚合,并配合参数field(字段)为end_date和interval(间隔)为 1d(1天),提取每日的复权单位净值(adj_nav)。由于子聚合使用管道(pipeline)聚合而无法直接采用文档字段,所以额外使用平均值(avg)聚合获取每日的复权单位净值,聚合名称为Daily。(若当天基金没有公布的值,其值的计算方法是从其前后公布的值推算而来。)
    "aggs": {
        "MACD_Histogram": {
            "date_histogram": {
                "field": "end_date",
                "interval": "1d",
                "format": "yyyyMMdd"
            },
             "aggs": {
                "Daily": {
                    "avg": {"field": "adj_nav"}
                },
  1. 提取存储桶的日期
    由于增加了一个月的数据,而后续操作需要过滤掉额外的文档,因此以存储桶的日期作为筛选限制条件。我们可以使用名为DateStr的最小值聚合间接取得日期,Elasticsearch的日期用新纪元时间(Epoch Time) 表示,并且以毫秒为单位,时区为UTC。
                "DateStr": {
                    "min": {"field": "end_date"}
                },
  1. 计算每日Daily差异
    使用名为Diff的导数(derivative)聚合,并配合参数buckets_path指定Daily聚合的值来确定它与前一个时间戳的值。
                "Diff": {
                    "derivative": {
                        "buckets_path": "Daily" 
                     }
                },
  1. 确定当天Diff聚合的结果是收益还是损失
    使用两个“bucket_script”聚合,命名为 Gain 和 Loss,并配合参数buckets_path指定 Diff 聚合的结果来计算Gain和 Loss的值。 一个是正值而另一个值是零。
               "Gain": {
                   "bucket_script": {
                       "buckets_path": {"Diff": "Diff"},
                       "script": "(params.Diff > 0) ? params.Diff : 0"
                   }
               }, 
               "Loss": {
                   "bucket_script": {
                      "buckets_path": {"Diff": "Diff"}, 
                      "script": "(params.Diff < 0) ? -params.Diff : 0"
                   }
               },
  1. 计算每日总收益和总损失的简单移动平均值
    使用两个“moving_fn”聚合,分别命名为 GainSMA 和 LossSMA,参数window为 14,参数“buckets_path”分别为 Gain 和 Loss的结果。 参数“shift”设置为 1 以包含当天和过去 13 个交易日的数据。SMA 是使用未加权平均函数 (MovingFunctions.unweightedAvg) 来计算。
               "GainSMA": {
                   "moving_fn": {
                       "script": "MovingFunctions.unweightedAvg(values)", 
                           "window": 14, "buckets_path": "Gain", "shift":1
                   }
               },
               "LossSMA": {
                   "moving_fn": {
                       "script": "MovingFunctions.unweightedAvg(values)", "window": 14, "buckets_path": "Loss", "shift":1
                       }
               },
  1. 计算RSI值
    使用名为 RSI 的bucket_script聚合并配合参数buckets_path来指定 GainSMA 和 LossSMA 的结果。 然后根据脚本中的公式计算 RSI 指标。
               "RSI": {
                   "bucket_script": {
                       "buckets_path": {"GainSMA": "GainSMA", "LossSMA": "LossSMA"}, 
                       "script": "100 - 100/(1+params.GainSMA/params.LossSMA)"
                   }
               },
  1. RSI 值差距
    使用名为RSI_Diff的导数(derivative)聚合,并配合参数buckets_path指定RSI聚合的值来确定它与前一个时间戳的RSI值差距。
               "RSI_Diff": {"derivative": {"buckets_path": "RSI"}}, 
  1. 识别 RSI 值的类型
    使用名为RSIType的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用RSI和RSI_Diff聚合的值,对 RSI 值的类型进行分类。
    ◆ 如果RSI <= 30并且RSI_Diff 是减量,则为类型1
    ◆ 如果RSI <= 30并且RSI_Diff是增量,则为类型 2
    ◆ 如果RSI >= 70并且RSI_Diff是增量,则为类型 3
    ◆ 如果RSI >= 70并且RSI_Diff是减量,则为类型 4
    ◆ 其他情况为类型 0
               "RSIType": {
                   "bucket_script": {
                       "buckets_path": {"RSI": "RSI", "RSI_Diff": "RSI_Diff"},
                       "script": "(params.RSI >= 70) ? (params.RSI_Diff > 0 ? 3:4) : (params.RSI <= 30) ? (params.RSI_Diff > 0 ? 2:1):0"
                   }
               },
  1. 计算 RSI_SMA、RSI_SD、RSI_BBU 和 RSI_BBL
    参考《当 MACD 与布林带在 Elasticsearch中结合时, …》一文中MACD BB的实现,使用两个“moving_fn”聚合,命名为RSI_SMA和RSI_SD,计算RSI值的20天简单移动平均线和标准差。 然后根据布林带上下轨道线的定义编写命名为RSI_BBU和RSI_BBL的bucket_script聚合。
              "RSI_SMA": {
                  "moving_fn": {
                      "script": "MovingFunctions.unweightedAvg(values)", 
                          "window": 20, "buckets_path": "RSI"
                  }
              }, 
              "RSI_SD": {
                  "moving_fn": {
                     "script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))", "window": 20, "buckets_path": "RSI"
                  }
              }, 
              "RSI_BBU": {
                  "bucket_script": {
                      "buckets_path": {"SMA": "RSI_SMA", "SD": "RSI_SD"}, 
                      "script": "params.SMA + 2 * params.SD"
                  }
              }, 
              "RSI_BBL": {
                  "bucket_script": {
                      "buckets_path": {"SMA": "RSI_SMA", "SD": "RSI_SD"}, 
                      "script": "params.SMA - 2 * params.SD"
                  }
              },
  1. 计算 SMA、SD、BBU 和 BBL
    使用两个“moving_fn”聚合,命名为SMA和SD,计算Daily值的20天简单移动平均线和标准差。 然后根据布林带上下轨道线的定义编写命名为BBU和BBL的bucket_script聚合。
                "SMA": {
                    "moving_fn": {
                        "script": "MovingFunctions.unweightedAvg(values)", 
"window": 20, "buckets_path": "Daily"
                    }
                }, 
                "SD": {
                    "moving_fn": {
                        "script": "MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))", 
"window": 20, "buckets_path": "Daily"
                    }
                }, 
                "BBU": {
                    "bucket_script": {
                        "buckets_path": {"SMA": "SMA", "SD": "SD"}, 
"script": "params.SMA + 2 * params.SD"
                    }
                }, 
                "RSI_BBL": {
                    "bucket_script": {
                        "buckets_path": {"SMA": "SMA", "SD": "SD"}, 
"script": "params.SMA - 2 * params.SD"
                    }
                },
  1. 输出前过滤掉额外的文档
    使用名为 SRSI_BB 的“bucket_selector”聚合,并配合参数“buckets_path”为“DateStr”,“script”语句中指定存储桶的选择条件。 选择标准是日期在 2021 年 1月 1 日及之后的存储桶(以毫秒为单位指定纪元时间 1609459200000)。
                "SRSI_BB": {
   		            "bucket_selector": {
                        "buckets_path": {"DateStr":"DateStr"},
                        "script": "params.DateStr >= 1609459200000L"
                    }
                }
            }
        }
    },
    "size": 0
}
  1. 收集结果后,可以绘制如前图所示。类型 1 为红色点,类型 2 为橙色点,类型 3为水蓝色点,类型 4 为蓝色点,其他则为灰色点。

读者可以进一步参考Gitee上的开源项目(RSI_BB) 。

备注:
I. 感谢Tushare大数据开放社区提供相关数据及Gitee开源社区提供存储开源项目。
II. 本文基于公开发布技术和研究观点,并不构成任何投资建议,读者在使用时须自行承担责任。
III. 文中可能还存在疏漏和错误之处,恳请广大读者批评和指正。
IV. 作者的中文著作Elasticsearch 数据分析与实战应用(ISBN 978-7-113-27886-1号)将于2021 年 7 月出版。
V. 作者的英文著作Advanced Elasticsearch 7.0(ISBN 978-1-789-95775-4号)被bookauthority评为 2021 年最值得阅读的 4 本 Elasticsearch 新书之一。

posted on 2021-07-12 07:52  王博分享  阅读(218)  评论(0编辑  收藏  举报