在Elasticsearch中回测阿隆(Aroon)指標交叉交易策略
我们已经讨论过如何在Elasticsearch 中回测“ RSI 交叉策略”和 随机(Stochastic)交叉策略,在本文中,我们将实现阿隆(Aroon)交叉策略,并将其性能与上述两种策略进行比较。 可以揭示新趋势的阿隆指标是Tushar Chande于1995年开发的,与上述两个指标相比较新。
与 RSI 和随机指标类似,阿隆指标也是一个振荡器(Oscillator)。 它的值在 0 到 100 之间。但是,它的值并不直接取决于价格。 相反,它的计算基于最近的最高价和最近的最低价得出的距离。 阿隆指标将高低价格的波动转化为一种数据,即两个归一化距离的差值。 AroonUp 定义为自 n 个周期内与最高价格的距离。 AroonDown 定义为自 n 个周期中与最低价格的距离。 该公式可以重写如下,其中 MMaxPn+1,1 和 MMinPn+1,1 分别是自 n+1 个移动窗口中与最高价格和最低价格的周期数。 对应Elasticsearch的移动函数,需要右移1个数据来包含当前数据。 通常,周期 n 使用 25 个周期,亦即滑动窗口为26。
阿隆振荡器定义为这两个归一化距离的相差。
阿隆交叉策略可以定义为当 AroonOS 从负值变为零或正值时(亦即AroonUp 从AroonDown下方越过到达上方)发出买入信号,因为它预示市场看涨。 当 AroonOS 从正值变为零或负值时(亦即AroonUp 从AroonDown 上方越过到达下方),发出卖出信号,因为它预示市场看跌。 对于其他值,耐心等待信号产生。
使用图表来观察值的变化要容易得多。 在本文中,我们尝试将回应用于Tushare大数据开放社区提供的股票型公募基金,并专注于将 Elasticsearch 作为分析工具。 下面的例子随机选择了"工银研究精选股票" (代码为000803.OF) ,并另外抽取10只股票型基金运行,结果将在最后的段落汇总和展示。数据选自2021年01月15日到2021年05月31日之间的时间范围。在下图中,AroonUp 线和 AroonDown 线与每日收盘价一起绘制。 在每日价格曲线中,有卖出信号的价格标为红色,有买入信号的价格标为蓝色。
下图同时绘制了每日收盘价和阿隆振荡器。
在这里,我们展示了一个简单的阿隆交叉策略,并使用 Elasticsearch 来展示实现细节。
- 假设限制一次购买和持有 1 股,则在所持有的股份被出售之前不会发生任何交易。
- 当 AroonUp 穿过 AroonDown 时买入 1 股。
- 当 AroonDown 低于 AroonUp 时卖出 1 股。
- 在测试期结束时,持有的股票以当前价格兑现。
根据Aroon交易策略,有3个蓝点和3个红点。 第一个卖出信号无法实现,因为没有持股。 对于其他信号可以兑现。 因此,允许 3 次买入和 2 次卖出交易。 一项观察表明,该策略可能会以某种方式选择以高价买入,然后以低价卖出。 就像文章Aroon Oscillator 中的结论一样,该指标将在波动的市场条件下可能提供错误的交易信号。让我们描述一下使用 Elasticsearch 的实现。 假设有一个填充有数据的 Elasticsearch 索引,其使用的数据映射与上一篇论文中描述的相同。 以下步骤演示了 REST API 请求正文的代码。
通过搜索操作收集所有相关文档
使用带有必要条件(must)子句的布林查询(bool query)来收集基金代码为000803.OF,和公告截止日期从2021年01月15日到2021年05月31日的文档。 由于需要计算滑动窗口为26的移动函数,因此增加了一个半月的数据(从2020年12月01日到2021年01月15日)。
{"query": {"bool": {"must": [{"range": {"end_date": {"gte": "20201201", "lte": "20210531"}}},{"term": {"ts_code": "000803.OF"}}]}},
提取每日的复权单位净值
使用名为Backtest_Aroon日期直方图(date_histogram)存储桶聚合,并配合参数field(字段)为end_date和interval(间隔)为 1d(1天)。由于没有内插数据,为了过滤非交易日(空桶),使用名为 SDaily 的“bucket_selector”聚合来选择文档计数(_count)大于 0 的桶。
"aggs": {"Backtest_Aroon": {"date_histogram": {"field": "end_date","interval": "1d","format": "yyyyMMdd"},"aggs": {"SDaily": {"bucket_selector": {"buckets_path": {"count":"_count"},"script": "params.count > 0"}},
提取每日的复权单位净值和单位净值
由于子聚合使用管道(pipeline)聚合而无法直接采用文档字段,所以额外使用平均值(avg)聚合获取每日的复权单位净值(adj_nav),聚合名称为Daily。由于买入价格和利润百分比使用单位价格(unit_nav)计算,故此同样建立聚合名称为Daily_unit_nav。
"Daily": {"avg": {"field": "adj_nav"}},"Daily_unit_nav": {"avg": {"field": "unit_nav”}},
提取存储桶的日期
由于增加了数据,而后续操作需要过滤掉额外的文档,因此以存储桶的日期作为筛选限制条件。我们可以使用名为DateStr的最小值聚合间接取得日期,Elasticsearch的日期用新纪元时间(Epoch Time) 表示,并且以毫秒为单位,时区为UTC。
"DateStr": {"min": {"field": "end_date"}},
计算收盘价的简单移动最大值和最小值
使用两个"moving_fn"聚合,命名为 MMaxP 和 MMinP,参数 window 为 26 (25 个周期),参数"buckets_path"为 Daily。 参数"shift"设置为 1 以包括最近的数据。MMaxP 使用脚本在移动窗口中循环查找当前交易日与窗口中每日收盘价最高的那一天之间的距离。 MMinP 可以用同样的方式完成。
"MMaxP": {"moving_fn": {"script": "int i = 0; float max=0f; int maxIndex=0; for (float daily : values){if (daily >= max){maxIndex=i; max=daily;} i++;} return values.length - 1 - maxIndex;", "buckets_path": "Daily", "window": 26, "shift": 1}}, "MMinP": {"moving_fn": {"script": "int i = 0; float min=10000f; int minIndex=0; for (float daily : values){if (daily <= min){minIndex=i; min=daily;} i++;} return values.length - 1 - minIndex;", "buckets_path": "Daily", "window": 26, "shift": 1}},
计算 AroonUp、AroonDown 和 AroonOscillator
使用三个“bucket_script”聚合,命名为 AroonUp、AroonDown 和 AroonOS。 ArronUp 使用参数“buckets_path”作为 MMaxP 并根据之前描述的公式编写脚本。 AroonDown 可以用同样的方式完成。 AroonOS 是 AroonUp 减去 AroonDown 的值。
"AroonUp": {"bucket_script": {"buckets_path": {"MMaxP": "MMaxP"}, "script": "100 * (25.0 - params.MMaxP)/25"}}, "AroonDown": {"bucket_script": {"buckets_path": {"MMinP": "MMinP"}, "script": "100 * (25.0 - params.MMinP)/25"}},"AroonOS": {"bucket_script": {"buckets_path": {"AroonUp": "AroonUp", "AroonDown": "AroonDown"}, "script": "params.AroonUp - params.AroonDown"}},
识别Aroon Oscillator的交叉类型
(a) 确定交叉类型需要前一交易日的数据。 使用“moving_fn”聚合,命名为PRE_AroonOS,参数“buckets_path”指定AroonOS值,参数window设置为1。移动函数使用MovingFunctions.sum()存储之前的数据。
"PRE_AroonOS": {"moving_fn": {"script": "MovingFunctions.sum(values)", "buckets_path": "AroonOS", "window": 1}},
(b) 要确定 AroonUp 线是否在 AroonDown 线下方或上方交叉,请检查以下聚合 AroonOS_Type 标准。 如果是卖出信号,则将 AroonOS_Type 设置为 1。如果是买入信号,则将其设置为 -1。 否则,将其设置为 0。
- 在交易日AroonUp 从AroonDown下方越过到达上方
params.AroonOS == 0 和 params.PRE_AroonOS < 0
- 在交易日AroonUp 从AroonDown上方越过到达下方
params.AroonOS == 0 和 params.PRE_AroonOS > 0
- 在两个交易日之间,AroonUp 从AroonDown上方越过到达下方
params.PRE_AroonOS > 0 && params.AroonOS < 0
- 在两个交易日之间,AroonUp 从AroonDown上方越过到达下方
params.PRE_AroonOS < 0 && params.AroonOS > 0
"AroonOS_Type": {"bucket_script": {"buckets_path": {"AroonOS":"AroonOS", "PRE_AroonOS":"PRE_AroonOS"}, "script": "(params.AroonOS == 0) ? ( params.PRE_AroonOS < 0 ? -1 : 1) : ((params.PRE_AroonOS > 0 && params.AroonOS < 0 ) ? 1 : (params.PRE_AroonOS < 0 && params.AroonOS > 0) ? -1 : 0)"}},
过滤有效数据
使用名为 S_Date 的"bucket_selector"聚合,并配合参数"buckets_path"为"DateStr”,“script"语句中指定存储桶的选择条件。 选择标准是日期在 2021 年 1月 15日及之后的存储桶(以毫秒为单位指定纪元时间 1610668800000)。由于涉及当前收盘价,买入或卖出交易将顺延至下一个交易日。因此,所有的结果都会在python程序中上报和处理,根据策略买入或卖出交易。
"S_Date": {"bucket_selector": {"buckets_path": {"DateStr": "DateStr"}, "script": "params.DateStr >= 1610668800000L"}}}}},"from": 0, "size": 0
}
收集结果后,可以绘制如前图所示。
执行结果会发出买入或卖出信号; 然而,这些信号仅满足前述交易策略的第二种和第三种情况。 对于第一种和第四种情况,需要使用 Python 编程语言来编写程序。主程序包括四个部分。
- 读取两个命令行参数。 一个用于选定的代码,另一个用于包含使用 JSON 格式在 Elasticsearch REST API 请求正文中编写的交易策略的文件名称。
- 从 Elasticsearch 服务器获取数据。
- 解析响应数据并优化买入和卖出信号。
- 报告回测统计数据(为简单起见,利润并未扣除交易费用)。
主函数如下所示:
def main(argv):type = 'AroonOS_Type'inputfile, symbol = get_opt(argv)resp = get_data(inputfile, symbol)transactions = parse_data(resp, type)report(transactions, type)
在本文中,仅展示了买卖信号细化的代码段。 读者可以进一步参考Gitee上的开源项目Backtest_Aroon。 为确保每次只买入及只持有一股,并且在卖出持有的股票之前不发生交易,我们使用布尔变量"hold"来确保交易满足以下条件。
- 当hold为 False 时,买入信号(值等于 -1)被接受
- 当hold为True时,卖出信号(值等于1)被接受
函数parse_data()如下所示。 最后,交易数组transaction只包含有效信号。然而,这些信号将在report中按照交易策略处理买入或卖出。利润是使用复权单位净值差额计算。而买入价格和利润百分比则使用单位价格(unit_nav)计算。
def parse_data(resp, type):result = json.loads(resp)aggregations = result['aggregations']if aggregations and 'Backtest_Aroon' in aggregations:Backtest_Aroons = aggregations['Backtest_Aroon']transactions = []hold = Falseif Backtest_Aroons and 'buckets' in Backtest_Aroons:for bucket in Backtest_Aroons['buckets']:transaction = {}transaction['date'] = bucket['key_as_string']transaction['Daily'] = bucket['Daily']['value']# honor buy signal if there is no share holdif bucket[type]['value'] == -1:transaction['original'] = 'buy'if not hold:transaction['buy_or_sell'] = 'buy'else:transaction['buy_or_sell'] = 'hold'hold = True# honor sell signal if there is a share holdelif bucket[type]['value'] == 1:transaction['original'] = 'sell'if hold:transaction['buy_or_sell'] = 'sell'else:transaction['buy_or_sell'] = 'hold'hold = False# for other situations, just hold the actionelse:transaction['original'] = 'hold'transaction['buy_or_sell'] = 'hold'transactions.append(transaction)return transactions
这python程序提供交易策略的统计信息,包括整个买卖交易的"赢"和"输"。以下是对000803.OF运行阿隆交易策略后的结果。
购买次数: 1
卖出次数: 0
得胜次数: 1
亏损次数: 0
总利润: 0.27
平均购买价格: 3.11
利润百分率: 8.76%
从2021年01月15日到2021年05月31日,11只股票型基金运行简单型阿隆交易策略的结果汇总和展示如下表。结果表明,这个交易策略不一定可以获利。大多数交易者的建议不要根据单一指标进行交易。
下表汇总了所有11只股票型基金的买入、卖出、盈利、亏损次数和总盈利情况。 该表还显示了每种交易策略最大利润的基金。 与其他两种策略相比,相对强弱指数交叉交易策略比较卓越。 但是,阿隆指标也可以在某只基金带来不错的利润。
备注:
- 感谢Tushare大数据开放社区提供相关数据及Gitee开源社区提供存储开源项目。
- 本文基于公开发布技术和研究观点,并不构成任何投资建议,读者在使用时须自行承担责任。
- 文中可能还存在疏漏和错误之处,恳请广大读者批评和指正。
- 作者的中文著作Elasticsearch 数据分析与实战应用(ISBN 978-7-113-27886-1号)将于2021 年 8月出版。
- 作者的英文著作Advanced Elasticsearch 7.0(ISBN 978-1-789-95775-4号)被bookauthority评为 2021 年最值得阅读的 4 本 Elasticsearch 新书之一。
在Elasticsearch中回测阿隆(Aroon)指標交叉交易策略相关推荐
- 在Elasticsearch中回测隨機(Stochastic)指標交叉交易策略
之前的文章"在Elasticsearch 中回测 RSI 交叉策略",介紹在Elasticsearch中如何回測 相对强弱指数(RSI)指标交叉交易策略.在本文中,我们将实施随机( ...
- 在Elasticsearch中回测超级趋势线(Supertrend)交叉交易策略
我们已经讨论了好几个单一指标交易策略,其中简单的相对强弱指数(RSI)交易策略取得的利润最高. 在本文中,我们将使用 Elasticsearch 实现超级趋势线(Supertrend)交叉交易策略,并 ...
- matlab配对交易回测,精品案例 | 经典投资策略之配对交易策略
原标题:精品案例 | 经典投资策略之配对交易策略 人不恋爱枉少年,在"全城热恋"的氛围下,股市也来凑热闹,配对交易策略油然而生.所谓"男女搭配,干活不累",成双 ...
- backtrader量化回测,基础篇,附MACD交易回测代码
backtrader由德国工程师开发,拥有股票的回测,检测交易策略,支持期货实时交易,对于股票交易还在完善,我尝试了pylagotrade,vn.py,发现backtrader功能强大,交易策略全面, ...
- python量化回测结果分析53课_#滑动平均策略——python回测结果 (中山大学岭南学院量化投资协会)...
策略如下: 回测区间为2016年10月10日至2017年10月13日,选择沪深300进行回测. 记录所有当天5日滑动平均价格高于20日滑动平均价格的股票 将总资金额的一半n/2用于买入股票,每一支股票 ...
- matlab中Cci,【每日一策】MATLAB量化交易策略之 CCI择时
策略名称:CCI择时策略说明: 1.CCI 为正值时,视为多头市场:为负值时,视为空头市场: 2.常态行情时,CCI 波动于±100 的间:强势行情,CCI 会超出±100 : 3.CCI>10 ...
- 移动平均函数对 RSI 交叉策略回测结果的显着影响
之前的文章"在 Elasticsearch 中回测 RSI 交叉策略",我们介绍了如何使用 Elasticsearch 实现相对强弱指数 (RSI) 指标以获得回测结果. 文章中相 ...
- vnpy怎么创建策略并回测_【手把手教你】入门量化回测最强神器backtrader(一)
1 引言 目前基于Python的量化回测框架有很多,开源框架有zipline.vnpy.pyalgotrader和backtrader等,而量化平台有Quantopian(国外).聚宽.万矿.优矿.米 ...
- backtrader程序介绍-策略回测用法
backtrader的策略回测初尝 前言 backtrader作为能够在自己的python环境运行的回测程序之一,不得不说很好用.今天进行了初步的学习,稍微进行分享. 一.回测基础步骤 应用backt ...
最新文章
- python中文名字叫什么-什么是Python
- git reset改写提交
- 【网络安全】某安全网关前端JS分析
- 编写高性能 .NET 代码 第一章:工具介绍 -- Performance Counters(性能计数器)
- 【转】Qt串口通信专题教程
- 3、Fiddler 如何捕获Firefox的会话
- CString char BSTR 转换
- 关于maven各种报错
- win7下linux 双系统安装教程,【系统安装】双系统——Win7下安装linux系统详细步骤...
- 海康isapi协议原理学习(Intelligent Security API 智能安全API)
- nginx配置反向代理和负载均衡完结篇
- 关于Filename too long解决方法
- 1-计算机是如何工作的?
- 2022-06-30 Android app WakeLock息屏状态下唤醒屏幕并且解锁demo
- CSS代码常用代码以及前端图片代码
- PHP(2):PHP读取MS Sql Server 2014数据库数据
- 李嘉诚传给年青人的人生忠告
- ctfshow信息收集web1~10
- 勤哲 mysql 2005_勤哲Excel服务器-学习与下载园地
- gerrit服务器搭建和gitlab自动同步(一)