使用 Elasticsearch 构建布林带趋势指标
在公式中:
p: 价格
SMA : 使用简单模型的移动平均值
short : 短周期滑动窗口
long : 长周期滑动窗口
abs : 绝对值函数
BBUshort : 短周期布林带上轨道线
BBLshort : 短周期布林带下轨道线
BBUlong : 长周期布林带上轨道线
BBLlong : 长周期布林带下轨道线
在本文中,我们将使用股票型公募基金作为样本,并专注于Elasticsearch作为分析的计算工具。 以下示例随机选用工银前沿医疗股票C基金,其代码为010685.OF。 数据选自Tushare大数据开放社区,时间范围为2020 年 12 月 01 日至 2021 年 4 月 30 日之间。 假设有一个填充了数据的 Elasticsearch 索引,其使用的数据映射与上一篇论文相同(使用Elasticsearch计算布林带宽度指标)。以下步骤说明操作流程,同时演示REST API请求主体的代码:
- 通过搜索操作收集所有相关文档:
使用带有必要条件(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"}}
]
}
},
- 提取每日的复权单位净值:
使用名为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"}
},
- 提取存储桶的日期
由于增加了一个月的数据,而后续操作要计算布林带宽度的平均值,因此需要存储桶的日期作为筛选的限制条件。我们可以使用名为DateStr的最小值聚合间接取得日期,Elasticsearch的日期用新纪元时间(Epoch Time) 表示,并且以毫秒为单位,时区为UTC。
"DateStr": {
"min": { "field": "end_date"}
},
- 计算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"}
},
- 计算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"}
},
- 计算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"
}
},
- 计算布林带趋势指标
使用名为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"
}
},
- 确定BBTrend值是在上升趋势还是下降趋势内
使用名为BBTrendDiff的导数(derivative)聚合,并配合参数buckets_path指定BBTrend聚合的值来确定它与前一个时间戳的值,是增量还是减量。
"BBTrendDiff" :{
"derivative": {
"buckets_path": "BBTrend"
}
},
- 确定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)"
}
},
- 输出前过滤掉额外的文档
使用名为 SBBW 的“bucket_selector”聚合,并配合参数“buckets_path”为“DateStr”,“script”语句中指定存储桶的选择条件。 选择标准是日期在 2021 年 2 月 1 日及之后的存储桶(以毫秒为单位指定纪元时间 1612137600000)。
"SBBW": {
"bucket_selector": {
"buckets_path": {"DateStr":"DateStr"},
"script": "params.DateStr >= 1612137600000L"
}
}
}
},
"size": 0
}
- 收集结果后,我们可以绘制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 新书之一。
本文来自博客园,作者:王博分享,转载请注明原文链接:https://www.cnblogs.com/dbsrhouse/p/14976524.html