RSI BB 还是RSI & BB? 很简单,让我们用 Elasticsearch 来实现吧!
在之前所写《当 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 请求正文的代码。
- 通过搜索操作收集所有相关文档
使用带有必要条件(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"}}
]
}
},
- 提取每日的复权单位净值
使用名为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"}
},
- 提取存储桶的日期
由于增加了一个月的数据,而后续操作需要过滤掉额外的文档,因此以存储桶的日期作为筛选限制条件。我们可以使用名为DateStr的最小值聚合间接取得日期,Elasticsearch的日期用新纪元时间(Epoch Time) 表示,并且以毫秒为单位,时区为UTC。
"DateStr": {
"min": {"field": "end_date"}
},
- 计算每日Daily差异
使用名为Diff的导数(derivative)聚合,并配合参数buckets_path指定Daily聚合的值来确定它与前一个时间戳的值。
"Diff": {
"derivative": {
"buckets_path": "Daily"
}
},
- 确定当天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"
}
},
- 计算每日总收益和总损失的简单移动平均值
使用两个“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
}
},
- 计算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)"
}
},
- RSI 值差距
使用名为RSI_Diff的导数(derivative)聚合,并配合参数buckets_path指定RSI聚合的值来确定它与前一个时间戳的RSI值差距。
"RSI_Diff": {"derivative": {"buckets_path": "RSI"}},
- 识别 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"
}
},
- 计算 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"
}
},
- 计算 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"
}
},
- 输出前过滤掉额外的文档
使用名为 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 为红色点,类型 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 新书之一。
本文来自博客园,作者:王博分享,转载请注明原文链接:https://www.cnblogs.com/dbsrhouse/p/15000440.html