Estrategia de negociación de bandas de porcentaje de Bollinger

El autor:¿ Qué pasa?, Fecha: 2023-12-11 11:14:53
Las etiquetas:

img

Resumen general

Esta estrategia se basa en el indicador Bollinger Bands, combinado con promedios móviles y el indicador técnico ATR, para implementar un sistema de ruptura a corto plazo.

Estrategia lógica

  1. Calcular el canal de bandas de Bollinger y la posición relativa de los precios dentro del canal
  2. Calcular las medias móviles por separado para los precios de apertura, cierre, alto y bajo
  3. Calcular el indicador ATR y establecer líneas de stop loss combinadas con ATR
  4. Juzgar si los precios están cerca de nuevos máximos o nuevos mínimos
  5. Combinar los máximos y mínimos anuales para juzgar las tendencias de los marcos de tiempo más grandes
  6. Generar señales de negociación basadas en cambios en el porcentaje de bandas de Bollinger y nuevos máximos/mínimos

Esta estrategia utiliza el canal de bandas de Bollinger para juzgar la volatilidad del mercado, con el ancho del canal determinado por la desviación estándar. Las señales de compra se generan cuando los precios se rompen por debajo de la banda inferior y las señales de venta cuando los precios se rompen por encima de la banda superior. Los promedios móviles pueden suavizar las fluctuaciones de Bollinger y reducir las fallas de ruptura. El indicador ATR se combina con el stop loss para fijar la escala de stop loss.

Ventajas

  1. Los filtros estrictos de ruptura de bandas de Bollinger ayudan a reducir las señales falsas
  2. Las medias móviles suavizan los precios e identifican las tendencias verdaderas
  3. Indicador ATR que rastrea dinámicamente el stop loss y limita las pérdidas de una sola operación
  4. Los nuevos máximos/bajos y los máximos/bajos anuales hacen que las señales sean más fiables
  5. La combinación eficaz de múltiples indicadores mejora la eficiencia

Riesgos y soluciones

  1. Los parámetros incorrectos de las bandas de Bollinger pueden causar errores excesivos, se deben probar diferentes combinaciones de parámetros para obtener los mejores resultados.
  2. El precio de referencia de cierre puede dar lugar a absorciones que excedan el intervalo de pérdida de parada establecido por ATR, considere utilizar precios altos/bajos más volátiles para el cálculo porcentual
  3. El filtro estricto de Bollinger puede perder algunas oportunidades de tendencia a largo plazo, relajar adecuadamente los filtros y el período de retención
  4. El indicador ATR sigue grandes oscilaciones de precios lentamente, considere medidas de volatilidad de mayor frecuencia como el rango verdadero
  5. Las nuevas rupturas de máximos/bajos son fácilmente perturbadas por el ruido a corto plazo, evaluar la significación estadística y la sostenibilidad de la tendencia

Direcciones de optimización

  1. Prueba de diferentes combinaciones de parámetros para determinar parámetros óptimos de Bollinger y longitudes de media móvil
  2. Emplear combinaciones de modelos que incorporen diferentes parámetros de Bollinger o medias móviles
  3. Prueba de la robustez en diferentes plazos y productos, mejora la adaptabilidad
  4. Incorporar señales de marcos de tiempo más altos como señales diarias de Bollinger o factores estacionales
  5. Evaluación de las oportunidades para ampliar la cobertura de la estrategia y la rentabilidad

Conclusión

Esta estrategia combina efectivamente bandas de porcentaje de Bollinger, promedios móviles, indicador ATR, nuevos máximos / mínimos y máximos / mínimos anuales para construir un sistema de negociación de ruptura a corto plazo relativamente estricto y eficiente. Su ventaja sobresaliente radica en el uso de varias herramientas para reducir el ruido e identificar las verdaderas señales de tendencia. Por supuesto, la estrategia también enfrenta algunas dificultades de ajuste de parámetros y oportunidades perdidas en condiciones estrictas. En general, representa un estilo de negociación único y una estrategia de ruptura de Bollinger de alta eficiencia que justifica una mayor investigación y validación en datos comerciales reales.


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

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HeWhoMustNotBeNamed

//@version=4
strategy("Bollinger %B Candles Strategy", overlay=false, initial_capital = 1000, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, pyramiding = 1, commission_value = 0.01, calc_on_order_fills = true)

BBLength = input(100, minval=1, step=1)
StdDev = 10
useMovingAverage = input(true)
MAType = input(title="Moving Average Type", defval="rma", options=["ema", "sma", "hma", "rma", "vwma", "wma"])
lookbackPeriod = input(22, minval=10, step=10)
colorByPreviousClose = input(true)

AtrMAType = input(title="Moving Average Type", defval="hma", options=["ema", "sma", "hma", "rma", "vwma", "wma"])
AtrLength = input(10)
AtrMult = input(4)
wicks = input(false)

considerYearlyHighLow = input(false)
considerNewLongTermHighLows = input(false)
shortHighLowPeriod = 100
longHighLowPeriod = 200
tradeDirection = input(title="Trade Direction", defval=strategy.direction.all, options=[strategy.direction.all, strategy.direction.long, strategy.direction.short])

backtestYears = input(10, minval=1, step=1)


//////////////////////////////////// Calculate new high low condition //////////////////////////////////////////////////
f_calculateNewHighLows(shortHighLowPeriod, longHighLowPeriod, considerNewLongTermHighLows)=>
    newHigh = highest(shortHighLowPeriod) == highest(longHighLowPeriod) or not considerNewLongTermHighLows
    newLow = lowest(shortHighLowPeriod) == lowest(longHighLowPeriod) or not considerNewLongTermHighLows
    [newHigh,newLow]

//////////////////////////////////// Calculate Yearly High Low //////////////////////////////////////////////////
f_getYearlyHighLowCondition(considerYearlyHighLow)=>
    yhigh = security(syminfo.tickerid, '12M', high[1]) 
    ylow = security(syminfo.tickerid, '12M', low[1]) 
    yhighlast = yhigh[365]
    ylowlast = ylow[365]
    yhighllast = yhigh[2 * 365]
    ylowllast = ylow[2 * 365]
    
    yearlyTrendUp = na(yhigh)? true : na(yhighlast)? close > yhigh : na(yhighllast)? close > max(yhigh,yhighlast) : close > max(yhigh, min(yhighlast, yhighllast))
    yearlyHighCondition = (  (na(yhigh) or na(yhighlast) ? true : (yhigh > yhighlast) ) and ( na(yhigh) or na(yhighllast) ? true : (yhigh > yhighllast))) or yearlyTrendUp or not considerYearlyHighLow
    yearlyTrendDown = na(ylow)? true : na(ylowlast)? close < ylow : na(ylowllast)? close < min(ylow,ylowlast) : close < min(ylow, max(ylowlast, ylowllast))
    yearlyLowCondition = (  (na(ylow) or na(ylowlast) ? true : (ylow < ylowlast) ) and ( na(ylow) or na(ylowllast) ? true : (ylow < ylowllast))) or yearlyTrendDown or not considerYearlyHighLow
    
    label_x = time+(60*60*24*1000*1)
    [yearlyHighCondition,yearlyLowCondition]

f_getMovingAverage(source, MAType, length)=>
    ma = sma(source, length)
    if(MAType == "ema")
        ma := ema(source,length)
    if(MAType == "hma")
        ma := hma(source,length)
    if(MAType == "rma")
        ma := rma(source,length)
    if(MAType == "vwma")
        ma := vwma(source,length)
    if(MAType == "wma")
        ma := wma(source,length)
    ma

inDateRange = true
[yearlyHighCondition,yearlyLowCondition] = f_getYearlyHighLowCondition(considerYearlyHighLow)
[newHighS,newLowS] = f_calculateNewHighLows(shortHighLowPeriod, longHighLowPeriod, considerNewLongTermHighLows)
[middleclose, upperclose, lowerclose] = bb(close, BBLength, StdDev)
[middleopen, upperopen, loweropen] = bb(open, BBLength, StdDev)
[middlehigh, upperhigh, lowerhigh] = bb(high, BBLength, StdDev)
[middlelow, upperlow, lowerlow] = bb(low, BBLength, StdDev)

percentBClose = (close - lowerclose)*100/(upperclose-lowerclose)
percentBOpen = (open - loweropen)*100/(upperopen-loweropen)
percentBHigh = (high - lowerhigh)*100/(upperhigh-lowerhigh)
percentBLow = (low - lowerlow)*100/(upperlow-lowerlow)

percentBMAClose = f_getMovingAverage(percentBClose, MAType, lookbackPeriod)
percentBMAOpen = f_getMovingAverage(percentBOpen, MAType, lookbackPeriod)
percentBMAHigh = f_getMovingAverage(percentBHigh, MAType, lookbackPeriod)
percentBMALow = f_getMovingAverage(percentBLow, MAType, lookbackPeriod)

newOpen = useMovingAverage? percentBMAOpen : percentBOpen
newClose = useMovingAverage? percentBMAClose : percentBClose
newHigh = useMovingAverage? percentBMAHigh : percentBHigh
newLow = useMovingAverage? percentBMALow : percentBLow

truerange = max(newHigh, newClose[1]) - min(newLow, newClose[1])

averagetruerange = f_getMovingAverage(truerange, AtrMAType, AtrLength)
atr = averagetruerange * AtrMult

longStop = newClose - atr
longStopPrev = nz(longStop[1], longStop)
longStop := (wicks ? newLow[1] : newClose[1]) > longStopPrev ? max(longStop, longStopPrev) : longStop

shortStop = newClose + atr
shortStopPrev = nz(shortStop[1], shortStop)
shortStop := (wicks ? newHigh[1] : newClose[1]) < shortStopPrev ? min(shortStop, shortStopPrev) : shortStop

dir = 1
dir := nz(dir[1], dir)
dir := dir == -1 and (wicks ? newHigh : newClose) > shortStopPrev ? 1 : dir == 1 and (wicks ? newLow : newClose) < longStopPrev ? -1 : dir

trailingStop = dir == 1? longStop : shortStop

candleColor = colorByPreviousClose ?
                 (newClose[1] < newClose ? color.green : newClose[1] > newClose ? color.red : color.silver) : 
                 (newOpen < newClose ? color.green : newOpen > newClose ? color.red : color.silver)
plotcandle(newOpen, newHigh, newLow, newClose, title='PercentBCandle', color = candleColor, wickcolor=candleColor)
plot(trailingStop, title="TrailingStop", style=plot.style_linebr, linewidth=1, color= dir == 1 ? color.green : color.red)

buyCondition = dir==1 and yearlyHighCondition and newHighS
exitBuyCondition = dir == -1
sellCondition = dir == -1 and yearlyLowCondition and newLowS
exitSellCondition = dir == 1
strategy.risk.allow_entry_in(tradeDirection)

barcolor(buyCondition? color.lime : sellCondition ? color.orange : color.silver)
strategy.entry("Buy", strategy.long, when=buyCondition and inDateRange, oca_name="oca_buy")
strategy.close("Buy", when=exitBuyCondition)

strategy.entry("Sell", strategy.short, when=sellCondition and inDateRange, oca_name="oca_sell")
strategy.close("Sell", when=exitSellCondition)

Más.