使用 Elasticsearch 构建布林带趋势指标

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

如果您阅读我之前所写的“使用 Elasticsearch 计算布林带宽度”一文,可能还想使用 Elasticsearch来构建布林带趋势指标 (BBTrend)。 BBTrend 是 John Bollinger开发的一个相对较新的指标。 这指标既能反映标的股票的走势,又能体现强度和方向两个方面,为交易者提供了有价值的参考。 当 BBTrend 读数高于零时,它可以表示市场看涨,反之亦然。其值高于或低于零的程度决定了趋势背后的强度或动量。 BBTrend 涉及两个布林带,短周期和长周期。 一般来说短周期为 20,而长周期为50。 要了解如何使用Elasticsearch计算布林带(BB),可以参考前文。BBTrend 的计算公式如下:

在这里插入图片描述
在公式中:
p: 价格
SMA : 使用简单模型的移动平均值
short : 短周期滑动窗口
long : 长周期滑动窗口
abs : 绝对值函数
BBUshort : 短周期布林带上轨道线
BBLshort : 短周期布林带下轨道线
BBUlong : 长周期布林带上轨道线
BBLlong : 长周期布林带下轨道线

在本文中,我们将使用股票型公募基金作为样本,并专注于Elasticsearch作为分析的计算工具。 以下示例随机选用工银前沿医疗股票C基金,其代码为010685.OF。 数据选自Tushare大数据开放社区,时间范围为2020 年 12 月 01 日至 2021 年 4 月 30 日之间。 假设有一个填充了数据的 Elasticsearch 索引,其使用的数据映射与上一篇论文相同(使用Elasticsearch计算布林带宽度指标)。以下步骤说明操作流程,同时演示REST API请求主体的代码:

  1. 通过搜索操作收集所有相关文档:
    使用带有必要条件(must)子句的布林查询(bool query)来收集基金代码为010685.OF,和公告截止日期从2021年02月01日到2021年04月30日的文档。 由于需要计算50天的移动平均值,此多增加了约两个月的数据(从2020年12月01日到2020年1月31日)。
{
	"query": {
		"bool": {
			"must": [
				{"range": {"end_date": {"gte": "20201201", "lte": "20210430"}}},
		    	{"term": {"ts_code": "010685.OF"}}
			]
		}
	},
  1. 提取每日的复权单位净值:
    使用名为BBI的日期直方图(date_histogram)存储桶聚合,并配合参数field(字段)为end_date和interval(间隔)为 1d(1天),提取每日的复权单位净值(adj_nav)。由于子聚合使用管道(pipeline)聚合而无法直接采用文档字段,所以额外使用平均值(avg)聚合获取每日的复权单位净值,聚合名称为Daily。(若当天基金没有公布的值,其值的计算方法是从其前后公布的值推算而来。)
    "aggs": {
        "BBI": {
            "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. 计算26 天和 50 天的简单移动平均值:
    由于周末等非交易日的数据已被插值,因此使用26天作为短周期。使用名为SMA26的移动函数(moving_fn)聚合,并配合参数window为26和参数buckets_path(存储桶路径)为Daily来计算adj_nav的26天简单移动平均值。SMA26使用未加权平均函数(MovingFunctions.unweightedAvg)来计算。SMA50的移动函数聚合可以相同的方式完成。
                "SMA26": {
                    "moving_fn": {"script": "MovingFunctions.unweightedAvg(values)", "window": 26, "buckets_path": "Daily"}
                },
                "SMA50": {
                    "moving_fn" : {"script": "MovingFunctions.unweightedAvg(values)", "window": 50, "buckets_path": "Daily"}
                },
  1. 计算26 天和 50 天的标准差:
    使用名为SD26的移动函数(moving_fn)聚合,并配合参数window为26和参数buckets_path为Daily的值来计算adj_nav的26天的标准差。SD26使用标准差函数(MovingFunctions.stdDev)来计算。SD50的移动函数聚合可以相同的方式完成。
                "SD26": {
                    "moving_fn": {"script":"MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))", "window":26, "buckets_path":"Daily"}
                },
                "SD50": {
                    "moving_fn": {"script":"MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))", "window":50, "buckets_path":"Daily"}
                },
  1. 计算26 天和 50 天的布林带上下轨道线:
    使用名为BBU26和BBL26的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用SMA26聚合的值和SD26聚合的值。并使用2个标准差的值来计算布林带上下轨道线的值。
                "BBL26": {
                    "bucket_script": {
                        "buckets_path": {
                            "SMA": "SMA26",
                            "SD": "SD26"
                        },
                        "script": "params.SMA - 2 * params.SD"
                    }
                },
                "BBU26": {
                    "bucket_script": {
                        "buckets_path": {
                            "SMA": "SMA26",
                            "SD": "SD26"
                        },
                        "script": "params.SMA + 2 * params.SD"
                    }
                },
                "BBL50": {
                    "bucket_script": {
                        "buckets_path": {
                            "SMA": "SMA50",
                            "SD": "SD50"
                        },
                        "script": "params.SMA - 2 * params.SD"
                    }
                },
                "BBU50": {
                    "bucket_script": {
                        "buckets_path": {
                            "SMA": "SMA50",
                            "SD": "SD50"
                        },
                        "script": "params.SMA + 2 * params.SD"
                    }
                },
  1. 计算布林带趋势指标
    使用名为BBTrend的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用BBU26、BBL26、SMA26、BBU50和BBL50聚合的值,并根据前述方程来计算布林带趋势指标。
               "BBTrend": {
                    "bucket_script": {
                        "buckets_path": {
                            "BBU20": "BBU20",
                            "BBL20": "BBL20",
                            "SMA20": "SMA20",
                            "BBU50": "BBU50",
                            "BBL50": "BBL50"
                        },
                        "script": "(Math.abs(params.BBL20 - params.BBL50)  - Math.abs(params.BBU20 - params.BBU50) ) / params.SMA20"
                    }
                },
  1. 确定BBTrend值是在上升趋势还是下降趋势内
    使用名为BBTrendDiff的导数(derivative)聚合,并配合参数buckets_path指定BBTrend聚合的值来确定它与前一个时间戳的值,是增量还是减量。
                "BBTrendDiff" :{
                    "derivative": {
                        "buckets_path": "BBTrend" 
                     }
                },
  1. 确定BBTrend值的类型
    使用名为BBTrendType的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用BBTrend和BBTrendDiff聚合的值,对 BTrend 值的类型进行分类。
    ➤ 如果是减量并且 BBTrend < 0,则为类型1
    ➤ 如果BBTrendDiff是增量并且 BBTrend < 0,则为类型 2
    ➤ 如果BBTrendDiff是增量并且 BBTrend > 0,则为类型 3
    ➤ 如果BBTrendDiff是减量并且 BBTrend > 0,则为类型 4
    ➤ 其他情况为类型 0
                "BBTrendType": {
                    "bucket_script": {
                        "buckets_path": {
                            "BBTrend": "BBTrend",
                            "BBTrendDiff": "BBTrendDiff"
                        },
                        "script": "(params.BBTrend > 0) ? (params.BBTrendDiff > 0 ? 3 : 4) : ((params.BBTrend < 0) ? (params.BBTrendDiff > 0 ? 2 : 1): 0)"
                    }
                },
  1. 输出前过滤掉额外的文档
    使用名为 SBBW 的“bucket_selector”聚合,并配合参数“buckets_path”为“DateStr”,“script”语句中指定存储桶的选择条件。 选择标准是日期在 2021 年 2 月 1 日及之后的存储桶(以毫秒为单位指定纪元时间 1612137600000)。
                "SBBW": {
   		             "bucket_selector": {
                            "buckets_path": {"DateStr":"DateStr"},
                            "script": "params.DateStr >= 1612137600000L"
                    }
                }
            }
        },
    "size": 0
}
  1. 收集结果后,我们可以绘制20天和50天的布林带(BBU20、BBL20、SMA20、BBU20和BBL20) 如下图所示。

在这里插入图片描述
12. 使用条形图绘制BBTrend,如下图 所示。类型 0 到类型 4使用的条形颜色分别为白色、红色、橙色、水蓝色和蓝色。

在这里插入图片描述
根据BBTrend的定义,很容易从图1中描绘出图2的形状。基本上,当BBL20和BBL50之间的距离大于BBU20和BBU50之间的距离时,BBTrend值为正。 差异越大,趋势背后的驱动力就越大。 图1的前期和后期,20 天的布林带偏向于 50 天的布林带上半部分,因此,图 2 中相对应的 BBTrend是正值并且数值大。图1的中期20 天的布林带偏向于 50 天的布林带下半部分,因此,图 2 中相对应的 BBTrend是负值并且数值大。 。然而,当我们结合图 1 中的复权单位净值并试图解释它是在上升趋势还是下降趋势时,似乎并不那么容易理解和直接相对应。 关于本文中所使用的 Elasticsearch 实例,它显示无缝且易于理解。 读者可以进一步参考Gitee上的开源项目(使用Elasticsearch构建布林带趋势指标)。

备注:
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-06 13:42  王博分享  阅读(203)  评论(0编辑  收藏  举报