В процессе загрузки ресурсов... загрузка...

Стратегия прорыва полосы Боллинджера

Автор:Чао Чжан, Дата: 2023-11-13 11:26:50
Тэги:

img

Обзор

Эта стратегия использует динамические верхние и нижние диапазоны полос Боллинджера, чтобы идти длинным, когда цена превышает верхнюю полосу, и закрыть позицию, когда цена падает ниже нижней полосы.

Логика стратегии

Стратегия опирается в основном на индикатор Bollinger Bands для выявления прорывов.

  1. Средняя линия: скользящая средняя за n периодов
  2. Верхняя полоса: средняя линия + стандартное отклонение k * n периодов
  3. Нижняя полоса: средняя линия - стандартное отклонение k * n периодов

Когда цена поднимается выше верхней полосы, рынок считается перекупленным, и длинная позиция может быть инициирована.

Стратегия позволяет настраивать параметры полос Боллинджера: скользящий средний период n и мультипликатор стандартного отклонения k. По умолчанию значения составляют 20 периодов для скользящего среднего и 2 для мультипликатора стандартного отклонения.

Стратегия проверяет, если цена закрытия превышает верхний диапазон после каждого торгового дня. Если это произойдет, длинный сигнал запускается на следующий день открытия. Как только длинный, стратегия отслеживает, если цена превышает нижний диапазон в режиме реального времени и закрывает позицию, если это произойдет.

Стратегия также включает в себя фильтр скользящей средней, который генерирует сигналы покупки только тогда, когда цена выше скользящей средней линии.

Существует два варианта стоп-лосса: фиксированный процент стоп-лосса или отставание от нижней полосы.

Преимущества стратегии

  • Использовать полосы Боллинджера для оценки уровня перекупленности/перепроданности
  • Фильтр скользящей средней избегает торговли против тренда
  • Параметры настраиваемых полос Боллинджера подходят для различных периодов
  • Выбор между двумя методами стоп-лосса
  • Обратное тестирование позволяет оптимизировать параметры и проверять их вне выборки

Риски стратегии

  • Боллингерские полосы не могут полностью определить перекупленность/перепроданность
  • Перемещающийся средний фильтр может пропустить более быстрые прорывы
  • Фиксированный стоп-лосс может быть слишком консервативным, последующий стоп может быть слишком агрессивным
  • Параметры необходимо оптимизировать для различных продуктов и временных рамок
  • Невозможно ограничить размер потерь, необходимо рассмотреть управление деньгами

Руководство по оптимизации

  • Испытать различные комбинации параметров скользящей средней
  • Попробуйте другие параметры полос Боллинджера
  • Сравните фиксированный процент стоп-лосса с нижней полосой прибыли.
  • Добавить модуль управления деньгами к лимиту по убыткам в торговле
  • Включить другие индикаторы для подтверждения сигнала Bollinger Bands

Заключение

Стратегия определяет условия перекупки/перепродажи с использованием динамических полос Боллинджера, ссылается на фильтры скользящих средних и использует остановки для защиты капитала. По сравнению с традиционными фиксированными уровнями прорывов, она лучше адаптируется к колебаниям рынка. С дальнейшей оптимизацией параметров и контролем рисков стратегия может достичь более высокой стабильности и доходности. В целом, используя динамический характер полос Боллинджера, стратегия захватывает сильные стороны стратегий прорыва и стоит живой торговли и долгосрочной оптимизации.


/*backtest
start: 2022-11-06 00:00:00
end: 2023-11-12 00:00:00
period: 1d
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=5

// Revision:        1
// Author:          @millerrh
// Strategy:  
//      Entry: Buy when price breaks out of upper Bollinger Band
//      Exit: Trail a stop with the lower Bollinger Band 
// Conditions/Variables:
//    1. Can add a filter to only take setups that are above a user-defined moving average on current timeframe and/or longer timeframe (helps avoid trading counter trend) 
//    2. Manually configure which dates to back test
//    3. User-Configurable Bollinger Band Settings
//    4. Optionally use a tighter initial stop level.  Once Bollinger Band catches up, trail with lower Bollinger Band to give more breathing room.

// strategy('Donchian Breakout', overlay=true, initial_capital=100000, currency='USD', default_qty_type=strategy.percent_of_equity, calc_on_every_tick = true,
//   default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1)

strategy('Bollinger Breakout', overlay=true, initial_capital=100000, currency='USD', default_qty_type=strategy.percent_of_equity,
  default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.0, calc_on_order_fills=true)

// === BACKTEST RANGE ===
Start = input(defval = timestamp("01 Jan 2019 06:00 +0000"), title = "Backtest Start Date", group = "backtest window")
Finish = input(defval = timestamp("01 Jan 2100 00:00 +0000"), title = "Backtest End Date", group = "backtest window")

// == INPUTS ==
// Bollinger Band Inputs
bbLength = input.int(20, minval=1, group = "Bollinger Band Settings", title="Bollinger Band Length",
  tooltip = "Bollinger Band moving average length.")
bbMultTop = input.float(2.0, minval=0.001, maxval=50, title="Standard Deviation (Top)")
bbMultBot = input.float(2.0, minval=0.001, maxval=50, title="Standard Deviation (Bottom)")

useTightStop = input.bool(title='Use Fixed Percentage for Initial Stop?', defval=false, group = "order entry",
  tooltip = "'Keep your losers small and let winners run' is the saying.  This will allow you to use a tight initial stop
  until the lower Bollinger Band catches up.")
percStop = input.int(title="Stop", defval=8, group = "order entry", inline = "perc")
trigInput = input.string(title='Execute Trades On...', defval='Wick', options=['Wick', 'Close'], group = "order entry",
  tooltip = "Useful for comparing standing stop orders at the Bollinger Band boundary (executing on the wick) vs. waiting for candle closes prior to taking action")

// Moving Average Filtering Inputs
useMaFilter = input.bool(title='Use Moving Average for Filtering (Current Timeframe)?', defval=false, group = "moving average filtering",
  tooltip = "Signals will be ignored when price is under this moving average.  The intent is to keep you out of bear periods and only buying when 
             price is showing strength.")
maType = input.string(defval='SMA', options=['EMA', 'SMA'], title='MA Type For Filtering', group = "moving average filtering")
maLength = input.int(defval=50, title="Moving Average:    Length", minval=1, group = "moving average filtering", inline = "1ma")
ma1Color = input.color(color.new(color.green, 50), title = " Color", group = "moving average filtering", inline = "1ma")
useMaFilter2 = input.bool(title='Use Moving Average for Filtering (High Timeframe)?', defval=false, group = "moving average filtering")
tfSet = input.timeframe(defval="D", title="Timeframe of Moving Average", group = "moving average filtering",
  tooltip = "Allows you to set a different time frame for a moving average filter.  Trades will be ignored when price is under this moving average.
  The idea is to keep your eye on the larger moves in the market and stay on the right side of the longer term trends and help you be pickier about 
  the stocks you trade.")
ma2Type = input.string(defval='SMA', options=['EMA', 'SMA'], title='MA Type For Filtering', group = "moving average filtering")
ma2Length = input.int(defval=50, title="Moving Average:    Length", minval=1, group = "moving average filtering", inline = "2ma")
ma2Color = input.color(color.new(color.white, 50), title = " Color", group = "moving average filtering", inline = "2ma")


// === THE BOLLINGER BAND ===
// Logic
bbBasis = ta.sma(close, bbLength)
bbUpper = bbBasis + bbMultTop * ta.stdev(close, bbLength)
bbLower = bbBasis - bbMultBot * ta.stdev(close, bbLength)

// Plotting
plot(bbBasis, "Basis", color=color.new(color.white, 50))
p1 = plot(bbUpper, color=color.new(color.blue, 50), linewidth=1, title='Upper Bollinger Band')
p2 = plot(bbLower, color=color.new(color.blue, 50), linewidth=1, title='Lower Bollinger Band')
fill(p1, p2, title = "Background", color=color.rgb(33, 150, 243, 95))

// == FILTERING LOGIC ==
// Declare function to be able to swap out EMA/SMA
ma(maType, src, length) =>
    maType == 'EMA' ? ta.ema(src, length) : ta.sma(src, length)  //Ternary Operator (if maType equals EMA, then do ema calc, else do sma calc)
maFilter = ma(maType, close, maLength)
maFilter2 = request.security(syminfo.tickerid, tfSet, ma(ma2Type, close, ma2Length))

// Plotting
plot(useMaFilter ? maFilter : na, title='Trend Filter MA - CTF', color=ma1Color, linewidth=2, style=plot.style_line)
plot(useMaFilter2 ? maFilter2 : na, title='Trend Filter MA - HTF', color=ma2Color, linewidth=2, style=plot.style_line)


// == ENTRY AND EXIT CRITERIA ==
// Trigger stop based on candle close or High/Low (i.e. Wick)
trigResistance = trigInput == 'Close' ? close : trigInput == 'Wick' ? high : na
trigSupport = trigInput == 'Close' ? close : trigInput == 'Wick' ? low : na
buySignal = trigResistance >= bbUpper 

buyConditions = (useMaFilter ? bbUpper > maFilter : true) and
  (useMaFilter2 ? bbUpper > maFilter2 : true) 
  
// == STOP AND PRICE LEVELS ==
// Configure initial stop level
inPosition = strategy.position_size > 0
stopLevel = strategy.position_avg_price - (strategy.position_avg_price * percStop/100)
posStop = stopLevel > bbLower ? stopLevel : bbLower


// Check if using stop vs. not
stop = useTightStop ? posStop : bbLower
plot(inPosition ? stop : na, style=plot.style_linebr, color=color.new(color.red, 40), linewidth = 1, title = "Stop Levels", trackprice=false)

sellSignal = trigSupport <= stop

// == STRATEGY ENTRIES & EXITS ==
// This string of code enters and exits at the candle close
if trigInput == 'Close'
    strategy.entry('Long', strategy.long, when=buyConditions and buySignal)
    strategy.close('Long', when=sellSignal)

// This string of code enters and exits at the wick (i.e. with pre-set stops)
if trigInput == 'Wick'
    strategy.entry('Long', strategy.long, stop=bbUpper, when=buyConditions)
    strategy.exit('Exit Long', from_entry='Long', stop=stop)
strategy.cancel('Long',when= not(buyConditions)) // Resets stop level once buyConditions aren't true anymore



Больше