使用Elasticsearch计算布林带宽度指标

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

布林带宽度(Bollinger Band Width)是美国股市分析家约翰·布林于2010年发明,用于测量布林带(Bollinger Bands于1980年发明)上下轨道线之间的相对距离。它随带宽变窄而减小,而随着带宽放宽而增加。因为布林带基于标准差,所以带宽的波动幅度可以反映波动性,并且可视为波动率指标。布林带由三条不同的线组成,包括简单移动平均线及正负距离两个标准差的上下轨道线。可为日常股票交易决策提供参考依据,是金融市场常用的技术指标之一。

要計算布林带宽度,第一步要先計算布林带,计算方法如下:

在这里插入图片描述

在公式中:

  • p = 价格

  • window = 移动平均线涉及的滑动窗口(通常为20或26)

  • SMA = 使用简单模型的移动平均值

  • SD = 標準差

  • n = 数字(通常为2,即2倍標準差)

  • BBU =布林带上轨道线

  • BBL = 布林带下轨道线

  • BBW = 布林带宽

    一般来说,布林带指标常用于股票市场,在本文中,我们尝试将其用于股票型公募基金,以复权单位净值代替价格。 并且使用Elasticsearch作为分析的计算工具。以下示例使用基金名称工银高端制造股票基金,代码为000793.OF,日期从2021年01月01日到2021年04月30日的数据。假設我们的 Elasticsearch 服务器有一个索引,包括三个字段,基金代码(ts_code)、复权单位净值(adj_nav)和公告截止日期(end_date)。数据映射如下:

"mappings": {
	"dynamic": "false",
	"properties": {
    	"ts_code": { "type": "keyword" },
        "adj_nav": { "type": "double" },
        "end_date": { "type": "date",  "format": "yyyyMMdd" }
    }
}

以下步骤说明操作流程,同时演示REST API请求主体的代码:

  1. 通过搜索操作收集所有相关文档:
    使用带有必要条件(must)子句的布林查询(bool query)来收集基金代码为000793.OF,和公告截止日期从2020年12月01日到2021年04月30日的文档。 由于需要计算移动平均值,因此多增加了前一个月的数据(从2020年12月01日到2020年12月31日)。
{
	"query":{
		"bool":{
			"must": [
				{"range":{"end_date":{"gte":"20201201", "lte":"20210430"}}},
		    	{"term": {"ts_code":"000793.OF"}}
			]
		}
	},
  1. 提取每日的复权单位净值:
    使用名为BBI的日期直方图(date_histogram)存储桶聚合,并配合参数field(字段)为end_date和interval(间隔)为 1d(1天),提取每日的复权单位净值(adj_nav)。由于子聚合使用管道(pipeline)聚合而无法直接采用文档字段,所以额外使用平均值(avg)聚合获取每日的复权单位净值,聚合名称为Daily。(Elasticsearch中的数据提取自Tushare大数据开放社区,若当天没有公布的值,其值的计算方法是从其前后公布的值推算而来。)
	"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. 计算每日的简单移动平均值:
    使用名为SMA的移动函数(moving_fn)聚合,并配合参数window为26和参数buckets_path(存储桶路径)为Daily来计算adj_nav的26天简单移动平均值。SMA使用未加权平均函数(MovingFunctions.unweightedAvg)来计算。
	            "SMA": {
	            	"moving_fn" : {"script":"MovingFunctions.unweightedAvg(values)", "window":26, "buckets_path":"Daily"}
	            },
  1. 计算每日SMA的标准差:
    使用名为SD的移动函数(moving_fn)聚合,并配合参数window为26和参数buckets_path为Daily的值来计算SMA的26天简单移动平均值的标准差。SD使用标准差函数(MovingFunctions.stdDev)来计算。
	            "SD": {
	            	"moving_fn": {"script":"MovingFunctions.stdDev(values, MovingFunctions.unweightedAvg(values))", "window":26, "buckets_path":"Daily"}
	            },
  1. 计算布林带上下限:
    使用名为BBU和BBL的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用SMA聚合的值、SD聚合的值和2个标准差的值来计算布林带上下限的值。
	            "BBU": {
	                "bucket_script": {
	                    "buckets_path": {
	                        "SMA": "SMA",
	                        "SD": "SD"
	                    },
	                    "script": "params.SMA + 2 * params.SD"
	                }
	            },
	            "BBL": {
	                "bucket_script": {
	                    "buckets_path": {
	                        "SMA": "SMA",
	                        "SD": "SD"
	                    },
	                    "script": "params.SMA - 2 * params.SD"
	                }
	            },
  1. 计算布林带宽度
    使用名为BBW的存储桶脚本(bucket_script)聚合,并配合参数buckets_path指定使用BBU聚合的值、BBL聚合的值和SMA聚合的值来计算布林带宽度指标。
	            "BBW": {
	                "bucket_script": {
	                    "buckets_path": {
	                        "BBU": "BBU",
	                        "BBL": "BBL",
	                        "SMA": "SMA"
	                    },
	                    "script": "(params.BBU - params.BBL) / params.SMA"
	                }
	            },
  1. 收集结果后,我们可以绘制布林带(BBU、BBL和SMA) 如图1所示及布林带宽度(BBW)如图2所示。
    图1 布林带(BBU、BBL和SMA)
    在这里插入图片描述

在特定情况下,布林带宽度指标可用于识别交易信号,例如使用布林带挤压指标(Bollinger Band Squeeze)来辨认该标的是否进入盘整状态,但本文不会涉及和讨论它。在本文的开头曾经提到布林带宽度可被视为波动率指标,在这里,我们尝试使用布林带宽度覆盖的区域面积来表示该基金在该段期间内的波动程度。而区域的面积可以使用带宽的平均值替代,平均值越大表示该标的在该段期间内波动性越大。操作流程延续步骤7(计算布林带宽度),在使用桶平均值(avg_bucket)聚合前一个阶段结果之前,使用名为SBBW的桶选择器(bucket_selector)聚合过滤掉额外一个月的文档(日期从2020年12月01日到2020年12月31日的数据)。过滤条件为储桶日期等于或大于2020年01月01日以毫秒为单位的新纪元时间(1609459200000) ,时区为UTC。下面显示代码片段:

            "SBBW": {
	          "bucket_selector": {
                    "buckets_path": {"DateStr":"DateStr"},
                    "script": "params.DateStr >= 1609459200000L"
                }
            }
        }
    },

选择合适的时间范围后,再进行名为avg_BBW的桶平均值聚合,并配合参数buckets_path指定BBI>BBW来计算布林带宽度平均值,工银高端制造股票基金在该期间内的桶平均值聚合结果为0.13690832010057521。以下演示相关代码:

   	"avg_BBW": {
        "avg_bucket": {
            "buckets_path": "BBI>BBW"
        }
    }
}

假若我们收集了各种类型相关基金在该段期间内的布林带宽度指标的平均值,并且将这些数据文档索引到名为 bbw 的索引。那么我们可以对该索引使用百分位等级(percentiles)聚合计算该值在相关股票基金的百分比排名。索引bbw的数据映射可以设计如下,其中包括六个字段,基金代码(ts_code)、布林带宽度指标的平均值(avg_bbw)、(fund_type)、(invest_type)和开始及结束日期(start_end_date)。以下演示相关的代码:

      "mappings": {
      	"dynamic": "false",
      	"properties": {
        	"ts_code": { "type": "keyword" },
            "management": { "type": "keyword" },
            "avg_bbw": { "type": "float" },
			"fund_type": { "type": "keyword" },
			"invest_type": { "type": "keyword" },
			"start_end_date": {"type": "keyword"}
        }
    }

以下演示基金管理公司为工银瑞信基金所管理的54支股票型基金,在2021年01月01日到2021年04月30日期间内的百分位分布状况与工银高端制造股票基金的百分位等级请求代码:

{
   "query":{
        "bool":{
            "must": [
                {"term": { "management":"工银瑞信基金" }},
                {"term": { "fund_type" : "股票型" }},
                {"term": { "start_end_date" : "20210101_20210430" }}
            ]
        }
    },
    "aggs" : {
        "BBW_Dist" : {
            "percentiles" : {
                "field" : "avg_bbw"
            }
        },
        "Rank" : {
            "percentile_ranks" : {
                "field":"avg_bbw", "values":[ 0.13690832010057521]
            }
        }
    }
}

结果得出的百分比排名约为88%。与同一银行管理的股票基金相比,该基金在此期间的波动性较高。布林带宽度平均值的分布情况如下:

        "BBW_Dist": {
            "values": {
                "1.0": 0.044885078072547914,
                "5.0": 0.04725874215364456,
                "25.0": 0.0701846033334732,
                "50.0": 0.09941961616277695,
                "75.0": 0.11936021596193314,
                "95.0": 0.1485669195652008,
                "99.0": 0.15173230290412903
            }
        },
        "Rank": {
            "values": {
                "0.13690832010057521": 88.1280778188255
            }
        }

对于一组相关标的的基金样本,将布林带宽度平均值的相对百分比,作为局部时间段的相关波动性的参考值是非常有趣的新试验。根据文中使用 的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:46  王博分享  阅读(563)  评论(0编辑  收藏  举报