请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  数理科学 帖子:3364705 新帖:26

Boll指标的趋势效应与择时交易

2020来了发表于:5 月 10 日 04:44回复(1)

计算Boll与画图的公用函数

def get_boll(security, start_date=None, end_date=None, time_count=10):
    hs_data=get_price(security,start_date=start_date,end_date=end_date,frequency='daily',fields=None,skip_paused=False,fq='pre')
    stock_data = get_price(securirty, end_date= end_date, frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(hs_data['close']) time_count-1))
    upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=2,nbdevdn=2,matype=0)
    stock_data = pd.DataFrame({'upper': upper, 'middle': middle, 'lower': lower}, index= stock_data.index)
    stock_data = stock_data.dropna()
    stock_data['close'] = hs_data['close']
    return stock_data

def show_boll(stock_data):
    plt.figure(figsize=(20, 5))
    plt.grid()
    plt.plot(stock_data['upper'], '-', color='r')
    plt.plot(stock_data['lower'], '-', color='r')
    plt.plot(stock_data['middle'], '-.', color='b')
    plt.show()

Boll指标研究

布林线指标,即BOLL指标,其英文全称是“Bollinger Bands”,布林线(BOLL)由约翰·布林先生创造,其利用统计原理,一般而言,股价的运动总是围绕某一价值中枢(如均线、成本线等)在一定的范围内变动,布林线指标正是在上述条件的基础上,引进了“股价信道”的概念,其认为股价信道的宽窄随着股价波动幅度的大小而变化,而且股价信道又具有变异性,它会随着股价的变化而自动调整,求出股价的标准差及其信赖区间,从而确定股价的波动范围及未来走势,利用波带显示股价的安全高低价位。

原理:

根据统计学中的标准差原理设计,股价的波动利用标准差方式来表达,配合均线做为中位线,从而变成了偏离情况的写照。

公式:

一、日BOLL指标的计算公式:

  • 中轨线=N日的移动平均线
  • 上轨线=中轨线 两倍的N日标准差
  • 下轨线=中轨线-两倍的N日标准差

二、日BOLL指标的计算过程:

(1)、计算MA

MA=N日内的收盘价之和÷N

(2)、计算标准差MD

MD=平方根N日的(C-MA)的两次方之和除以N

(3)、计算MB、UP、DN线、K倍

MB=(N-1)日的MA
UP=MB K×MD
DN=MB-K×MD

正常使用方法:

  • 当股价穿越上限压力线时,卖点信号;
  • 当股价穿越下限支撑线时,买点信号;

目的:

  • 寻找最优中轨参数:N
  • 寻找最优搭配参数:K

导入需要模块

"""导入常用模块"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime
import talib
from jqdata import *
from jqlib.technical_analysis import *
from environment import * # 导入大树工作室开发的回测模块

沪深300价量展示Boll

import seaborn as sns
sns.set(font='serif')
securirty = '000300.XSHG'
Boll_data = []
HS_data = []
trade_date = get_trade_days(start_date= '2018-9-01', end_date= '2019-03-01')
time_count=20
HS_data = get_price(security='000300.XSHG', 
                  start_date='2018-9-01', 
                  end_date='2019-03-01', 
                  frequency='daily', 
                  fields=None, 
                  skip_paused=False, 
                  fq='pre')

stock_data = get_price(securirty, end_date= '2019-03-01' , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_data['close']) time_count-1))
upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=2,nbdevdn=2,matype=0)
stock_data = pd.DataFrame({'upper': upper, 'middle': middle, 'lower': lower}, index= stock_data.index)
stock_data = stock_data.dropna()
stock_data['close'] = HS_data['close']

plt.figure(figsize=(20, 5))
plt.grid()
plt.plot(stock_data['close'], '-', color='g')
plt.plot(stock_data['upper'], '-', color='r')
plt.plot(stock_data['lower'], '-', color='r')
plt.plot(stock_data['middle'], '-.', color='b')
plt.title('沪深300指数与Boll通道图')
plt.legend(['指数价格', 'Boll上轨', 'Boll中轨', 'Boll下轨'], loc=2)
plt.show()

output_6_0.png

上图展示沪深300指数与其Boll通道表现,图例的通道以及价格走势,明显可知,这是一种类价值回归,也与波动性有一定挂钩。对期货不陌生的投资者应该最为了解,因为在CTA部分策略中,最常使用这类的指标。综上所述,我们本次内容,就深入了解Boll指标,做进行布林带探索的[稀饭?哥伦布魏]!

Boll指标择时效应研究

Boll指标用法可谓五花八门,因为三线合一,不同的搭配有不同的口味,而且三线又可各自组合,使得使用起来更加多变。仔细思考,向上突破下轨,向上突破上轨,站于中轨,二次站于中轨等等,只要不脱轨,就很不错了。

本次研究的脉络为:

  • 择时交易择优参-常规择优
  • 择时交易择优参-轨道分化择优
  • 择时交易择优参-轨道综合

择时交易择优参

[稀饭?哥伦布魏]以简单方式带大家分享Boll。择时交易,方式非常容易理解,就是对Boll参数进行筛选,筛选的参数有三类,中轨均线参数,上下轨标准差倍数。

常规择优

展示常规情况下的中轨配置以及上下轨标准差2倍数,本次的稀饭会比较多清汤,但是会加点肉,因为最近猪瘟还是蛮严重的,所以严选最差猪肉!

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
    代码展示:
"""初始化以下内容"""
context = Context() # 账户对象
order = Order(context) # 下单对象
trade = Trade(context, order) # 回测对旬
context.start_date = '2010-01-01'
context.end_date = '2018-12-31'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'

"""策略主体"""
def handle(context, order):
    stock = context.universe[0]
    time_count = 20
    n = 2
    m = 2
    HS_da = get_price(security=stock, 
                      end_date= context.current_dt,
                      frequency= 'daily', 
                      fields= None, 
                      skip_paused= False, 
                      fq='pre',
                      count= 50)
    stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
    upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
    if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
        if stock in context.position.keys():
            return
        order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
    elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
        if stock not in context.position.keys():
            return
        order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])

"""执行策略"""
trade.trade(handle)

从正常角度看,整个数据表现得不是很理想,猪肉的质量有点差,猪毛(回撤:0.4754)占面积略大,而且猪肉可食用部位(策略收益:-0.4332)也比较少。咱们还是用多参数来下锅吧。

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
  • Boll参数:[5, 10, 15, 20, 25, 30, 35, 40]
    代码展示:
trade_list = []
Boll_list = [10, 15, 20, 25, 30, 35, 40, 45, 50]
for _Boll in Boll_list:
    # 策略结构
    context = Context()
    order = Order(context)
    trade = Trade(context, order)
    context.start_date = '2010-01-01'
    context.end_date = '2018-12-31'
    context.universe = ['000300.XSHG']
    context.base = '000300.XSHG'

    """策略主体"""
    def handle(context, order):
        stock = context.universe[0]
        time_count = _Boll
        n = 2
        m = 2
        HS_da = get_price(security=stock, 
                          end_date= context.current_dt,
                          frequency= 'daily', 
                          fields= None, 
                          skip_paused= False, 
                          fq='pre',
                          count= 50)
        stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
        upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
        if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
            if stock in context.position.keys():
                return
            order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
        elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
            if stock not in context.position.keys():
                return
            order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])
    trade.trade(handle, False)
    trade_list.append(trade)
# 展示
Trade.show_ratio_compare('Boll', Boll_list, trade_list, 3, 3)


虽然是猪肉,但是还是有好位置的,现在数据表出参数10,整个参数中唯一一个整收益的,还是蛮吃惊的,怎么会出现这样情况呢?因为Boll是类于波动率,进出场都和波动息息相关,只有波动和股价恰到好处,才是最合适的刷单或是价差空间,可谓一物降一物的感觉。

轨道分化择优

中轨参数已经得到相对于其他数据比较优秀的参数,接着就是上下轨的设置,烤猪肉要木叉子,基本两根为主,能够固定方向,把控肉质。吃个稀饭,还烤肉,也是不容易啊。

轨道分化择优-上轨

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
  • Boll参数:[5, 10, 15, 20, 25, 30, 35, 40]
  • n参数:[0.5, 1, 1.5, 2]
    代码展示:
_list = []
trade_list = []
Boll_list = [10, 15, 20, 25, 30, 35, 40, 45, 50]
Boll_list_n = [0.5, 1, 1.5, 2]
for _Boll in Boll_list:
    for n_Boll in Boll_list_n:
        # 策略结构
        context = Context()
        order = Order(context)
        trade = Trade(context, order)
        context.start_date = '2010-01-01'
        context.end_date = '2018-12-31'
        context.universe = ['000300.XSHG']
        context.base = '000300.XSHG'
        _list.append(str(_Boll) ',' str(n_Boll))

        """策略主体"""
        def handle(context, order):
            stock = context.universe[0]
            time_count = _Boll
            n = n_Boll
            m = 2
            HS_da = get_price(security=stock, 
                              end_date= context.current_dt,
                              frequency= 'daily', 
                              fields= None, 
                              skip_paused= False, 
                              fq='pre',
                              count= 50)
            stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
            upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
            if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
                if stock in context.position.keys():
                    return
                order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
            elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
                if stock not in context.position.keys():
                    return
                order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])
        trade.trade(handle, False)
        trade_list.append(trade)
# 展示
Trade.show_all_ratio('Boll', Boll_list, trade_list)


数据表给予的信息蛮有非巧合性的,最优的Boll参数依旧为10。最优上轨标准差倍数为0.5,该参数的各项数据对比的排名基本为首位,但是回撤问题一直围绕着,得思考思考,就要考虑下轨问题。不过还是让[稀饭?哥伦布魏]有点尴尬而不失礼节的买了该配置的叉子。

轨道分化择优-下轨

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
  • Boll参数:[5, 10, 15, 20, 25, 30, 35, 40]
  • m参数:[0.5, 1, 1.5, 2]
    代码展示:
_list = []
trade_list = []
Boll_list = [10, 15, 20, 25, 30, 35, 40, 45, 50]
Boll_list_m = [0.5, 1, 1.5, 2]
for _Boll in Boll_list:
    for m_Boll in Boll_list_m:
        # 策略结构
        context = Context()
        order = Order(context)
        trade = Trade(context, order)
        context.start_date = '2010-01-01'
        context.end_date = '2018-12-31'
        context.universe = ['000300.XSHG']
        context.base = '000300.XSHG'
        _list.append(str(_Boll) ',' str(m_Boll))

        """策略主体"""
        def handle(context, order):
            stock = context.universe[0]
            time_count = _Boll
            n = 2
            m = m_Boll
            HS_da = get_price(security=stock, 
                              end_date= context.current_dt,
                              frequency= 'daily', 
                              fields= None, 
                              skip_paused= False, 
                              fq='pre',
                              count= 50)
            stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
            upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
            if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
                if stock in context.position.keys():
                    return
                order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
            elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
                if stock not in context.position.keys():
                    return
                order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])
        trade.trade(handle, False)
        trade_list.append(trade)
# 展示
Trade.show_all_ratio('Boll', Boll_list, trade_list)


[稀饭?哥伦布魏]尴尬一笑,依旧是如此的场景,单一参数,策略正收益,最优下轨参数为2,差评地方为回撤貌似加大许多。

轨道综合

上节内容,应该明白发生什么事情,猪肉还是要好好买好好烤。这节内容,会比较严肃介绍。因为是风险厌恶择优的分析,以个人的风险厌恶程度来分析,做比较。

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
  • Boll参数:[5, 10, 15, 20, 25, 30, 35, 40]
  • n参数:[0.5, 1, 1.5, 2]
  • m参数:[0.5, 1, 1.5, 2]
    代码展示:
_list = []
trade_list = []
Boll_list = [10, 15, 20, 25, 30, 35, 40, 45, 50]
Boll_list_n = [0.5, 1, 1.5, 2]
Boll_list_m = [0.5, 1, 1.5, 2]
for _Boll in Boll_list:
    for m_Boll in Boll_list_m:
        for n_Boll in Boll_list_n:
            # 策略结构
            context = Context()
            order = Order(context)
            trade = Trade(context, order)
            context.start_date = '2010-01-01'
            context.end_date = '2018-12-31'
            context.universe = ['000300.XSHG']
            context.base = '000300.XSHG'
            _list.append(str(_Boll) ',' str([n_Boll,m_Boll]))

            """策略主体"""
            def handle(context, order):
                stock = context.universe[0]
                time_count = _Boll
                n = n_Boll
                m = m_Boll
                HS_da = get_price(security=stock, 
                                  end_date= context.current_dt,
                                  frequency= 'daily', 
                                  fields= None, 
                                  skip_paused= False, 
                                  fq='pre',
                                  count= 50)
                stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
                upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
                if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
                    if stock in context.position.keys():
                        return
                    order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
                elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
                    if stock not in context.position.keys():
                        return
                    order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])
            trade.trade(handle, False)
            trade_list.append(trade)
# 展示
Trade.show_all_ratio('Boll', Boll_list, trade_list)

image.png

排头数据列表给予的信息比较明确,最优Boll参数为10,最优上轨标准差倍数为0.5,最优下轨标准差倍数为[0.5, 2],为何上轨标准差倍数是单个,而最优下轨标准差倍数是两个。从看收益来解释,正常的投资,是想保稳定收益,出场可以说是最简单也是最难的,因为心态和欲望控制、风险厌恶程度,因此上轨选择最稳定,而且小空间上轨等于中轨,有点价值回归的味道。下轨为何会两个,这就关系到风险程度以及市场情绪变化、质变,下轨0.5与2是四倍的关系,从回撤角度,2的回撤几乎快是0.5的一倍,胜率提高了0.1,但是收益下降了一倍多,这就是进场风险选择的关键,总所周知,对于股价,每个人都希望走得稳定,但是却不能如愿,一旦股价走向极端,恰恰是引起质变效果,市场的情绪变化导致我们的心理变化,一波冲击波的情绪量瞬间扩大动能,然而使股价回归的另一波动能却不一定能使得股价回归,因为承接力以及大盘环境因素、股价自身情况。Boll的运用,可以从多方面去切入,既然是中位线与价格的标准差,可以尝试使用标准差为重心去思考,如何使得中位线与偏离程度能更合适搭配我们的策略,配合量能去做搭配。总的一句话:波动之间最稳定的是平稳,而且不能急躁,慢工出细活。

总结

Boll是以波动率和价值回归为基础,数据告诉我们,谨慎是最安全的,以敏感的Boll参数10配合稳定小空间上下轨标准差倍数参数0.5,实际运用中,参数0.5的运用可能受限,但是可以在更小的周期里面运用。
市场的变化,是情绪得变化,多重变化,会引起质变,极端市场的行情,在Boll中是一种机会,但是也是一种风险,因为股票的性质会市场对待的情绪改变了。

下面展示本次研究效果最好的参数

  • 回测标的:沪深300指数。
  • 回测时间:2010年01月01日到2018年12月31日。
  • 初始资金:100000元。
  • 不考虑对冲成本,尽量投入全部资金。
    代码展示:
"""初始化以下内容"""
context = Context() # 账户对象
order = Order(context) # 下单对象
trade = Trade(context, order) # 回测对旬
context.start_date = '2010-01-01'
context.end_date = '2018-12-31'
context.universe = ['000300.XSHG']
context.base = '000300.XSHG'

"""策略主体"""
def handle(context, order):
    stock = context.universe[0]
    time_count = 10
    n = 0.5
    m = 0.5
    HS_da = get_price(security=stock, 
                      end_date= context.current_dt,
                      frequency= 'daily', 
                      fields= None, 
                      skip_paused= False, 
                      fq='pre',
                      count= 50)
    stock_data = get_price(stock, end_date= context.current_dt , frequency= 'daily', fields= 'close', skip_paused= True, fq= 'pre', count= (len(HS_da['close']) time_count-1))
    upper, middle, lower = talib.BBANDS(stock_data['close'].values, timeperiod=time_count,nbdevup=n,nbdevdn=m,matype=0)
    if lower[-2] > HS_da['close'][-2] and lower[-1] < HS_da['close'][-1]:
        if stock in context.position.keys():
            return
        order.buy(stock, HS_da['close'][-1], context.cash // HS_da['close'][-1])
    elif lower[-1] > HS_da['close'][-1] or upper[-1] < HS_da['close'][-1]:
        if stock not in context.position.keys():
            return
        order.sell(stock, HS_da['close'][-1], context.position[stock]['count'])

"""执行策略"""
trade.trade(handle)

!

全部回复

0/140

量化课程

    移动端课程