JavaScript中怎么实现一个布林轨策略
这期内容当中小编将会给大家带来有关JavaScript中怎么实现一个布林轨策略,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
策略简介
布林带也称为布林通道,英文简称BOLL。它是最常用的技术指标之一,由约翰·包宁杰(John Bollinger)在1980年代发明。理论上,价格总是围绕着价值在一定范围内上下波动,布林带正是根据这个理论基础,又引入了"价格通道"的概念。
其计算方式是利用统计学原理,先计算一段时间价格的"标准差",再由均线加/减2倍的标准差,求出价格的"信赖区间"。其基本的型态是由三条轨道线组成的带状通道(中轨、上轨、下轨)。中轨为价格的平均成本,上轨和下轨分别代表价格的压力线和支撑线。如下图所示:
由于采用了标准差的概念,使得布林通道的宽度会根据近期价格的波动而做出动态调整。波动小,布林通道会变窄;波动大,布林通道会变宽。当BOLL通道由宽变窄,说明价格逐渐向均值回归。当BOLL通道由窄变宽,意味着行情开始发生变化,如果价格上穿上轨,表明买力增强,如果价格下穿下轨,表明卖力增强。
布林带指标计算方法
在所有的技术指标中,布林带的计算方法是最复杂之一,其中引进了统计学中的标准差概念,涉及到中轨线(MB)、上轨线(UP)和下轨线(DN)的计算。其计算方法如下:
中轨 = N时间段的简单移动平均线
上轨 = 中轨 + K × N时间段的标准差
下轨 = 中轨 − K × N时间段的标准差
function main() { // 主函数,程序从这里开始执行 while(true){ // 进入循环 exchange.SetContractType('MA888'); // 设置合约 var records = exchange.GetRecords(); // 获取K线数组 var boll = TA.BOLL(records, 50); // 获取50周期BOLL指标数组 top = boll[0]; // 获取BOLL指标上轨数组 ma = boll[1]; // 获取BOLL指标中轨数组 bottom = boll[2]; // 获取BOLL指标下轨数组 Log(top); // 把BOLL指标上轨数组打印到日志中 Log(ma); // 把BOLL指标中轨数组打印到日志中 Log(bottom); // 把BOLL指标下轨数组打印到日志中 }}
策略逻辑
布林线的使用方法有很多,可以单独使用,也可以和其他指标结合在一起使用。 本节教程我们将采用布林线一种最简单的使用方法。即:当价格自下而上突破上轨,即突破上方压力线时,我们认为多方力量正在走强,一波上涨行情已经形成,买入开仓信号产生;当价格自上而下跌破下轨,即跌破支撑线时,我们认为空方力量正在走强,一波下跌趋势已经形成,卖出开仓信号产生。
如果买入开仓后,价格又重新跌回到了布林线中轨,我们认为多方力量正在走弱,或者空方力量正在加强,卖出平仓信号产生;如果卖出开仓后,价格又重新涨回到布林线中轨,我们认为空方力量正在走弱,或者多方力量正在加强,买入平仓信号产生。
买卖条件
多头开仓:如果无持仓,并且收盘价大于上轨,并且时间非14:45
空头开仓:如果无持仓,并且收盘价小于下轨,并且时间非14:45
多头平仓:如果持多单,并且收盘价小于中轨,或者时间是14:45
空头平仓:如果持空单,并且收盘价大于中轨,或者时间是14:45
策略代码实现
要想实现策略,首先需要考虑我们需要什么数据?通过什么API去获取?然后如何计算交易逻辑?最后通过哪些方式下单方式去交易?接下来,让我们一步一步来实现吧:
第一步:使用CTA策略框架
所谓的CTA策略框架是由发明者量化官方推出的一套标准框架,使用该框架可以不必考虑开发量化交易策略的琐碎问题,直接把精力放在编程交易逻辑上。比如,如果不使用该框架的话,在下单的时候,需要考虑换月移仓、下单买卖价格、下单不成交时撤单或追单等等问题......
function main() { $.CTA("rb000/rb888", function(st){ //编写策略 })}
上图就是使用发明者量化工具的CTA策略框架。这是一个固定的代码格式,所有的交易逻辑代码从第3行开始编写。在使用中除了需要修改品种代码外(浅黄色),其他地方不用任何修改。
需要注意的是,上图中的品种代码是"rb000/rb888"它代表的意思是信号的数据使用的是"rb000",交易数据使用的是"rb888",并且自动换月移仓。当然你也可以指定具体的品种代码,比如把品种代码"rb1910",就是信号数据和交易数据都使用"rb1910"。
第二步:获取各种数据
仔细想下,都需要哪些数据呢?从我们的策略交易逻辑中发现:首先需要获取当前的持仓状态,然后比较收盘价与布林带指标上中下轨的相互关系,最后判断行情是不是即将收盘。那么接下来让我们一以获取这些数据吧。
获取K线数据
首先就是获取K线数组和上根K线收盘价,因为有了K线数组,才能计算出布林带指标。用代码写出来是这样的:
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 })}
如以上代码所示:
第4行:获取K线数组,这是一个固定的格式。
第5行:过滤K线的长度,因为我们计算布林带指标用的参数是20,当K线小于20根的时候,是无法计算布林带指标的。所以这里要过滤下K线的长度,如果K线少于20根,就直接返回,继续等待下一根K线。
第6行:从获取的K线数组中,先获取上根K线的对象,再从该对象中获取收盘价。获取一个数组的倒数第二个元素,就是这个数组的长度减2(r[r.length - 2]);K线数组里面的元素都是一个个对象,对象包含了开盘价、最高价、最低价、收盘价、成交量、时间,要获取收盘价就直接在后面加上"."和属性名就可以了(r[r.length - 2].Close)。
获取K线时间数据
因为我们是日内策略,需要在收盘前平掉仓位,所以要判断当前K线是不是临近收盘,如果是临近收盘的K线就平掉仓位,如果不是临近收盘的K线就可以开仓,用代码写出来是这样的:
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 var time = new Date(r[r.length - 1].Time); // 根据当根K线时间戳,创建一个时间对象 var isClose = time.getHours() == 14 && time.getMinutes() == 45; // 判断时间是否14:45 })}
如以上代码所示:
第8行:获取当根K线的时间戳属性,然后创建一个时间对象(new Date(时间戳))。
第9行:根据时间对象,分别计算小时和分钟数,并判断当根K线的时间是不是14:45。
获取持仓数据
持仓信息是量化交易策略中一个很重要的条件,当交易条件成立时,还需要通过持仓状态和持仓数,来判断是否下单。比如:当买入开仓交易条件成立时,如果有持仓,就不必在重复下单了;如果无持仓,就可以下单。用代码写出来是这样的:
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 var time = new Date(r[r.length - 1].Time); // 根据当根K线时间戳,创建一个时间对象 var isClose = time.getHours() == 14 && time.getMinutes() == 45; // 判断时间是否14:45 var mp = st.position.amount; // 获取持仓信息 })}
如以上代码所示:
第11行:获取当前的持仓状态。如果有多单,则值是1;如果有空单,则值是-1;如果无持仓,则值是0。
获取布林带数据
接着就需要计算布林带指标上轨、中轨、下轨的数值了。那就要先获取布林带数组,在从数组中获取上中下轨的数值。在发明者量化工具中,获取布林带数组还很简单,直接调用布林带的API就可以了,难的是获取上中下轨的数值,因为布林带数组是一个二维数组。
二维数组其实很好理解,它就是数组中的数组,那么获取的顺序就是:先获取数组中指定的数组,然后在从指定的数组中获取指定的元素,如以下代码所示:
var arr = [[100, 200, 300], [10, 20, 30], [1, 2, 3]]; // 这是一个二维数组var test = arr[0]; // 先获取这个二维数组里面的第一个数组,并把结果设置给testvar demo1 = test[0]; // 再从test数组中,获取第一个数值demo1; // 结果是:100var demo2 = arr[0][0] // 我们也可以这样写demo2; // 结果同样为100
如以下代码中,第13行~19行就是用代码获取布林带上轨、中轨、下轨的数值。其中第13行是直接使用发明者量化工具的API,直接获取布林带数组;第14行~16行是先分别获取二维数组中的上轨数组、中轨数组、下轨数组;第17行~19行是分别从上轨数组、中轨数组、下轨数组中获取上根K线的布林带上轨、中轨、下轨数值。
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 var time = new Date(r[r.length - 1].Time); // 根据当根K线时间戳,创建一个时间对象 var isClose = time.getHours() == 14 && time.getMinutes() == 45; // 判断时间是否14:45 var mp = st.position.amount; // 获取持仓信息 var boll = TA.BOLL(r, 20, 2); // 计算布林带指标 var upLine = boll[0]; //获取上轨数组 var midLine = boll[1]; //获取中轨数组 var downLine = boll[2]; //获取下轨数组 var upPrice = upLine[upLine.length - 2]; //获取上根K线的上轨数组 var midPrice = midLine[midLine.length - 2]; //获取上根K线的中轨数组 var downPrice = downLine[downLine.length -2]; //获取上根K线的下轨数组 })}
第三步:下单交易
有了以上数据,就可以编写交易逻辑以及下单交易的代码了。格式也非常简单,最常用到的是"if语句",用文字可以描述为:如果条件1和条件2成立,下单;如果条件3或条件4成立,下单。如以下代码所示:
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 var time = new Date(r[r.length - 1].Time); // 根据当根K线时间戳,创建一个时间对象 var isClose = time.getHours() == 14 && time.getMinutes() == 45; // 判断时间是否14:45 var mp = st.position.amount; // 获取持仓信息 var boll = TA.BOLL(r, 20, 2); // 计算布林带指标 var upLine = boll[0]; //获取上轨数组 var midLine = boll[1]; //获取中轨数组 var downLine = boll[2]; //获取下轨数组 var upPrice = upLine[upLine.length - 2]; //获取上根K线的上轨数组 var midPrice = midLine[midLine.length - 2]; //获取上根K线的中轨数组 var downPrice = downLine[downLine.length -2]; //获取上根K线的下轨数组 if (mp == 1 && (close < midPrice || isClose)) return -1; //如果持多单,并且收盘价小于中轨,或者时间是14:45,平多 if (mp == -1 && (close > midPrice || isClose)) return 1; //如果持空单,并且收盘价大于中轨,或者时间是14:45,平空 if (mp == 0 && close > upPrice && !isClose) return 1; //如果无持仓,并且收盘价大于上轨,并且时间是14:45,开多 if (mp == 0 && close < downPrice && !isClose) return -1; //如果无持仓,并且收盘价小于下轨,并且时间是14:45,开空 })}
以上代码中,第21行~24行就是交易逻辑以及下单交易的代码。从上往下分别是:平多、平空、开多、开空。
以开多单(第23行)为例,这是一个"if语句",在该语句中如果只执行一行代码,花括号"{}"是可以省略的。该语句翻译成文字是:如果当前持仓是0,并且收盘价大于上轨,并且K线时间不是14:45,就"return 1"
细心的你可能会发现,这几行有"return 1"和"return -1",这是一个固定的格式,意思就是:如果是买入的就写"return 1";如果是卖出的就写"return -1"。开多和平空都是买入,所以写"return 1";开空和平多都是卖出,所以写"return -1"。
完整的策略代码
至此一个完整的策略代码就写完了,如果把交易框架、交易数据、交易逻辑、下单买卖等分开来写是不是很简单呢,以下就是这个策略的整个代码:
function main(){ $.CTA("rb000/rb888", function(st){ var r = st.records; // 获取K线数组 if (r.length < 20) return; // 过滤K线长度 var close = r[r.length - 2].close; // 获取上根K线收盘价 var time = new Date(r[r.length - 1].Time); // 根据当根K线时间戳,创建一个时间对象 var isClose = time.getHours() == 14 && time.getMinutes() == 45; // 判断时间是否14:45 var mp = st.position.amount; // 获取持仓信息 var boll = TA.BOLL(r, 20, 2); // 计算布林带指标 var upLine = boll[0]; //获取上轨数组 var midLine = boll[1]; //获取中轨数组 var downLine = boll[2]; //获取下轨数组 var upPrice = upLine[upLine.length - 2]; //获取上根K线的上轨数组 var midPrice = midLine[midLine.length - 2]; //获取上根K线的中轨数组 var downPrice = downLine[downLine.length -2]; //获取上根K线的下轨数组 if (mp == 1 && (close < midPrice || isClose)) return -1; //如果持多单,并且收盘价小于中轨,或者时间是14:45,平多 if (mp == -1 && (close > midPrice || isClose)) return 1; //如果持空单,并且收盘价大于中轨,或者时间是14:45,平空 if (mp == 0 && close > upPrice && !isClose) return 1; //如果无持仓,并且收盘价大于上轨,并且时间是14:45,开多 if (mp == 0 && close < downPrice && !isClose) return -1; //如果无持仓,并且收盘价小于下轨,并且时间是14:45,开空 })}
有两个地方需要注意:
1、尽量(但不是必须)把策略逻辑写成当根K线条件成立,下根K线发单,或者上根K线条件成立,当根K线发单,这样回测的结果与实盘的结果相差不大。不这样写也可以,但是要注意策略逻辑是否正确。
2、一般而言,把平仓的逻辑写在开仓逻辑的前面,这样做的目的是,尽量让策略逻辑符合你的预期。比如:如果策略逻辑刚好赶上反手的时候,反手的规则是,先平仓再开新仓。而不是先开新仓,再平仓。如果我们直接把平仓逻辑写到开仓逻辑前面,就不会出现这种问题。
上述就是小编为大家分享的JavaScript中怎么实现一个布林轨策略了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注行业资讯频道。