布林线是一种金融衍生品价格走势图中常用的技术指标,由于其以上下两条线组成的带状区域显示,所以也称为布林带。带状区域的宽度随着价格的变动而变化,当价格幅度增大时,带状区域变宽;当价格幅度减小时,带状区域变窄。布林线在图形上表现为上中下三条线,其中,上下两条线可以分别看成是压力线和支撑线,中间的线是N日的移动均线,通常情况下,价格的走势会在上下两条线之间。
Boll指标的计算如下:
1、计算N日收盘价的移动平均值MA
2、计算N日收盘价的标准差MD
3、计算上轨线UP=MA + K * MD
4、计算下轨线DN=MA - K * MD
通常,N常会选择20,K的选取会选择K=2,也可以根据策略运行的过程中进行调整。
由于下面的vnpy中的策略引入了CCI指标,所以简单对CCI指标进行介绍。CCI指标也称为顺势指标。它是由唐纳德·蓝伯特(Donald Lambert)于20世纪80年代提出的,用于判断当前价格是否超出常态分布范围,同KDJ、RSI一样,也是用于判断超卖超买。但是不同于这些0-100范围限制的指标,CCI的范围是负无穷和正无穷之间,所以CCI对于短期内暴涨暴跌的股票或者期货可以进行更好的衡量与判断,所以很多短期策略都会用到CCI指标。
CCI指标的计算方法是:
1、计算当前的TYP(typical price) = (Low + High + Close) / 3
2、计算N周期的TYP的移动平均值MA
3、计算N周期的TYP的标准差MD
4、CCI = (TYP - MA) / (MD * 0.015)
根据布林通道指标指定的策略有很多,主要还是基于价格与上中下轨道之间的关系制定的。例如,当利多利空消息已经出尽,此时股价幅度开始变小,也就是进入了盘整的情况下,此时通道会变窄,当价格波动超出了狭窄的通道上轨时,会预示着盘整结束后新的向上趋势的开始;当价格波动跌破狭窄的通道下轨时,会预示着盘整结束后新的向下趋势的开始。也有的布林通道策略是根据通道的形态制定的,例如上下轨之间的距离扩大形成的开口型喇叭口形态布林线和上下轨之间距离缩小形成的闭口型喇叭口形态布林线。还有的布林通道策略是通过跟其他指标如RSI、ATR、CCI或者KDJ指标进行结合,使得判断更加精准。
在vnpy中也有实现一个基于布林通道的策略,其思想是上面的第三种,它是通过布林通道结合CCI以及ATR指标制定的。其中CCI指标用来超买超卖,ATR指标用来作为止损止盈,布林通道则作为日内突破的上下轨。
from vnpy.app.cta_strategy import (
CtaTemplate,
StopOrder,
TickData,
BarData,
TradeData,
OrderData,
BarGenerator,
ArrayManager,
)
class BollChannelStrategy(CtaTemplate):
""""""
author = "用Python的交易员"
boll_window = 18
boll_dev = 3.4
cci_window = 10
atr_window = 30
sl_multiplier = 5.2
fixed_size = 1
boll_up = 0
boll_down = 0
cci_value = 0
atr_value = 0
intra_trade_high = 0
intra_trade_low = 0
long_stop = 0
short_stop = 0
parameters = ["boll_window", "boll_dev", "cci_window",
"atr_window", "sl_multiplier", "fixed_size"]
variables = ["boll_up", "boll_down", "cci_value", "atr_value",
"intra_trade_high", "intra_trade_low", "long_stop", "short_stop"]
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super(BollChannelStrategy, self).__init__(
cta_engine, strategy_name, vt_symbol, setting
)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager()
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(10)
def on_start(self):
"""
Callback when strategy is started.
"""
self.write_log("策略启动")
def on_stop(self):
"""
Callback when strategy is stopped.
"""
self.write_log("策略停止")
def on_tick(self, tick: TickData):
"""
Callback of new tick data update.
"""
self.bg.update_tick(tick)
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.bg.update_bar(bar)
def on_15min_bar(self, bar: BarData):
""""""
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
self.boll_up, self.boll_down = am.boll(self.boll_window, self.boll_dev)
self.cci_value = am.cci(self.cci_window)
self.atr_value = am.atr(self.atr_window)
if self.pos == 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = bar.low_price
if self.cci_value > 0:
self.buy(self.boll_up, self.fixed_size, True)
elif self.cci_value < 0:
self.short(self.boll_down, self.fixed_size, True)
elif self.pos > 0:
self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
self.intra_trade_low = bar.low_price
self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier
self.sell(self.long_stop, abs(self.pos), True)
elif self.pos < 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier
self.cover(self.short_stop, abs(self.pos), True)
self.put_event()
def on_order(self, order: OrderData):
"""
Callback of new order data update.
"""
pass
def on_trade(self, trade: TradeData):
"""
Callback of new trade data update.
"""
self.put_event()
def on_stop_order(self, stop_order: StopOrder):
"""
Callback of stop order update.
"""
pass
策略中主要6个超参数和8个变量。
6个超参数的意义是:
1、boll_window:计算布林通道的窗口大小。
2、boll_dev:中轨标准差的倍数。
3、cci_window:计算cci指标的窗口大小。
4、atr_window:计算atr指标的窗口大小。
5、sl_multiplier:止损止盈的乘数。
6、fixed_size:开仓的手数。
8个变量的意义是:
1、boll_up:布林通道的上轨。
2、boll_down:布林通道的下轨。
3、cci_value:cci指标的值。
4、atr_value:atr指标的值。
5、intra_trade_high:日内交易的最高值。
6、intra_trade_low:日内交易的最低值。
7、long_stop:多头止盈止损。
8、short_stop:空头止盈止损。
boll_window = 18
boll_dev = 3.4
cci_window = 10
atr_window = 30
sl_multiplier = 5.2
fixed_size = 1
boll_up = 0
boll_down = 0
cci_value = 0
atr_value = 0
intra_trade_high = 0
intra_trade_low = 0
long_stop = 0
short_stop = 0
parameters = ["boll_window", "boll_dev", "cci_window",
"atr_window", "sl_multiplier", "fixed_size"]
variables = ["boll_up", "boll_down", "cci_value", "atr_value",
"intra_trade_high", "intra_trade_low", "long_stop", "short_stop"]
不同于之前的策略,这次的策略的是基于15min K线级别的,所以在创建BarGenerator对象时需要传递15分钟bar级别的回调函数。策略也是需要10天的数据进行初始化。
def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
""""""
super(BollChannelStrategy, self).__init__(
cta_engine, strategy_name, vt_symbol, setting
)
self.bg = BarGenerator(self.on_bar, 15, self.on_15min_bar)
self.am = ArrayManager()
def on_init(self):
"""
Callback when strategy is inited.
"""
self.write_log("策略初始化")
self.load_bar(10)
由于这个策略是在15-min级别的数据上执行的,所以主要策略逻辑将不是在on_bar()函数里实现,on_bar()函数的作用是继续将推送的1-min数据合成为15-min数据,然后主要策略执行逻辑是在on_15min_bar()函数里实现的。这个策略的思想可以借鉴一下,为以后写其他时间周期级别的策略提供编写代码的思路。
def on_bar(self, bar: BarData):
"""
Callback of new bar data update.
"""
self.bg.update_bar(bar)
一开始同样也是取消上一笔没有成交的订单,然后将bar数据添加到ArrayManager当中。之后通过ArrayMangager对象am中的boll()以及cci()、atr()函数来调用底层的ta-lib接口来计算当前相应窗口下的布林上轨和下轨以及cci和atr指标的值。
def on_15min_bar(self, bar: BarData):
""""""
self.cancel_all()
am = self.am
am.update_bar(bar)
if not am.inited:
return
self.boll_up, self.boll_down = am.boll(self.boll_window, self.boll_dev)
self.cci_value = am.cci(self.cci_window)
self.atr_value = am.atr(self.atr_window)
当持有空仓时,需要记录当前bar的最高价和最低价。如果cci指标的值大于0,则以布林通道的上轨价位开出一手多头停止单;如果cci指标的值小于0,则以布林通道的下轨价位开出一手空头停止单。
if self.pos == 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = bar.low_price
if self.cci_value > 0:
self.buy(self.boll_up, self.fixed_size, True)
elif self.cci_value < 0:
self.short(self.boll_down, self.fixed_size, True)
当持有多头仓位的时候,从之前存储的最高价位和当前bar的最高价位中选取最大的,并且将之前的最低价位设置为当前bar的最低价位。然后通过atr指标和sl_multiplier参数来设置止损止盈的价位,并以这个价位进行平仓卖出;当持有空头仓位的时候,从之前存储的最低价位和当前bar的最低价位中选取最小的,并且将之前的最高价位设置为当前bar的最高价位。然后通过atr指标和sl_multiplier参数来设置止损止盈的价位,并以这个价位进行平仓买入。
elif self.pos > 0:
self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
self.intra_trade_low = bar.low_price
self.long_stop = self.intra_trade_high - self.atr_value * self.sl_multiplier
self.sell(self.long_stop, abs(self.pos), True)
elif self.pos < 0:
self.intra_trade_high = bar.high_price
self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
self.short_stop = self.intra_trade_low + self.atr_value * self.sl_multiplier
self.cover(self.short_stop, abs(self.pos), True)