La estrategia bidireccional de inversión de promedios móviles es una estrategia comercial cuantitativa basada en la teoría de la inversión de la media de precios.
La idea central de esta estrategia es la reversión de la media de precios, que sugiere que los precios tienden a fluctuar alrededor de un valor promedio, y tienen una mayor probabilidad de revertir cuando se desvían demasiado del promedio.
Desde la perspectiva lógica del código, hay dos promedios móviles de entrada - largo y corto - que consisten en promedios móviles rápidos y lentos respectivamente. La desviación entre ellos y el precio determina el tamaño de la posición. Además, el promedio móvil de salida es un promedio móvil separado que indica cuándo cerrar las posiciones. Cuando los precios tocan esta línea, las posiciones existentes se aplanarán.
Las principales ventajas de la estrategia de reversión de la media móvil bidireccional incluyen:
Esta estrategia funciona bien con instrumentos de baja volatilidad que tienen fluctuaciones de precios relativamente pequeñas, especialmente cuando entran en ciclos de rango. Puede capturar eficazmente las oportunidades de las reversiones temporales de precios. Mientras tanto, las medidas de control de riesgos son bastante integrales, limitando las pérdidas dentro de rangos razonables incluso si los precios no se recuperan.
También hay algunos riesgos asociados con esta estrategia:
Algunas formas de mitigar los riesgos anteriores incluyen:
También hay un amplio margen para optimizar aún más esta estrategia:
La estrategia bidireccional de inversión de promedio móvil tiene como objetivo obtener ganancias de las reversiones de precios después de desviaciones significativas de sus niveles de promedio móvil. Con las medidas adecuadas de control de riesgos, puede lograr ganancias consistentes a través de la puesta a punto de parámetros. Si bien los riesgos como perseguir tendencias y volatilidad excesiva todavía existen, pueden abordarse mejorando la lógica de entrada, reduciendo los tamaños de las posiciones y más.
/*backtest start: 2023-12-15 00:00:00 end: 2024-01-14 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ //@version=5 strategy(title = "hamster-bot MRS 2", overlay = true, default_qty_type = strategy.percent_of_equity, initial_capital = 100, default_qty_value = 30, pyramiding = 1, commission_value = 0.1, backtest_fill_limits_assumption = 1) info_options = "Options" on_close = input(false, title = "Entry on close", inline=info_options, group=info_options) OFFS = input.int(0, minval = 0, maxval = 1, title = "| Offset View", inline=info_options, group=info_options) trade_offset = input.int(0, minval = 0, maxval = 1, title = "Trade", inline=info_options, group=info_options) use_kalman_filter = input.bool(false, title="Use Kalman filter", group=info_options) //MA Opening info_opening = "MA Opening Long" maopeningtyp_l = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening, group=info_opening) maopeningsrc_l = input.source(ohlc4, title = "", inline=info_opening, group=info_opening) maopeninglen_l = input.int(3, minval = 1, title = "", inline=info_opening, group=info_opening) long1on = input(true, title = "", inline = "long1") long1shift = input.float(0.96, step = 0.005, title = "Long", inline = "long1") long1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "long1") info_opening_s = "MA Opening Short" maopeningtyp_s = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening_s, group=info_opening_s) maopeningsrc_s = input.source(ohlc4, title = "", inline=info_opening_s, group=info_opening_s) maopeninglen_s = input.int(3, minval = 1, title = "", inline=info_opening_s, group=info_opening_s) short1on = input(true, title = "", inline = "short1") short1shift = input.float(1.04, step = 0.005, title = "short", inline = "short1") short1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "short1") //MA Closing info_closing = "MA Closing" maclosingtyp = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_closing, group=info_closing) maclosingsrc = input.source(ohlc4, title = "", inline=info_closing, group=info_closing) maclosinglen = input.int(3, minval = 1, maxval = 200, title = "", inline=info_closing, group=info_closing) maclosingmul = input.float(1, step = 0.005, title = "mul", inline=info_closing, group=info_closing) startTime = input(timestamp("01 Jan 2010 00:00 +0000"), "Start date", inline = "period") finalTime = input(timestamp("31 Dec 2030 23:59 +0000"), "Final date", inline = "period") HMA(_src, _length) => ta.wma(2 * ta.wma(_src, _length / 2) - ta.wma(_src, _length), math.round(math.sqrt(_length))) EHMA(_src, _length) => ta.ema(2 * ta.ema(_src, _length / 2) - ta.ema(_src, _length), math.round(math.sqrt(_length))) THMA(_src, _length) => ta.wma(ta.wma(_src,_length / 3) * 3 - ta.wma(_src, _length / 2) - ta.wma(_src, _length), _length) tema(sec, length)=> tema1= ta.ema(sec, length) tema2= ta.ema(tema1, length) tema3= ta.ema(tema2, length) tema_r = 3*tema1-3*tema2+tema3 donchian(len) => math.avg(ta.lowest(len), ta.highest(len)) ATR_func(_src, _len)=> atrLow = low - ta.atr(_len) trailAtrLow = atrLow trailAtrLow := na(trailAtrLow[1]) ? trailAtrLow : atrLow >= trailAtrLow[1] ? atrLow : trailAtrLow[1] supportHit = _src <= trailAtrLow trailAtrLow := supportHit ? atrLow : trailAtrLow trailAtrLow f_dema(src, len)=> EMA1 = ta.ema(src, len) EMA2 = ta.ema(EMA1, len) DEMA = (2*EMA1)-EMA2 f_zlema(src, period) => lag = math.round((period - 1) / 2) ema_data = src + (src - src[lag]) zl= ta.ema(ema_data, period) f_kalman_filter(src) => float value1= na float value2 = na value1 := 0.2 * (src - src[1]) + 0.8 * nz(value1[1]) value2 := 0.1 * (ta.tr) + 0.8 * nz(value2[1]) lambda = math.abs(value1 / value2) alpha = (-math.pow(lambda, 2) + math.sqrt(math.pow(lambda, 4) + 16 * math.pow(lambda, 2)))/8 value3 = float(na) value3 := alpha * src + (1 - alpha) * nz(value3[1]) //SWITCH ma_func(modeSwitch, src, len, use_k_f=true) => modeSwitch == "SMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.sma(src, len)) : ta.sma(src, len) : modeSwitch == "RMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.rma(src, len)) : ta.rma(src, len) : modeSwitch == "EMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.ema(src, len)) : ta.ema(src, len) : modeSwitch == "TEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(tema(src, len)) : tema(src, len): modeSwitch == "DEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_dema(src, len)) : f_dema(src, len): modeSwitch == "ZLEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_zlema(src, len)) : f_zlema(src, len): modeSwitch == "WMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.wma(src, len)) : ta.wma(src, len): modeSwitch == "VWMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.vwma(src, len)) : ta.vwma(src, len): modeSwitch == "Hma" ? use_kalman_filter and use_k_f ? f_kalman_filter(HMA(src, len)) : HMA(src, len): modeSwitch == "Ehma" ? use_kalman_filter and use_k_f ? f_kalman_filter(EHMA(src, len)) : EHMA(src, len): modeSwitch == "Thma" ? use_kalman_filter and use_k_f ? f_kalman_filter(THMA(src, len/2)) : THMA(src, len/2): modeSwitch == "ATR" ? use_kalman_filter and use_k_f ? f_kalman_filter(ATR_func(src, len)): ATR_func(src, len) : modeSwitch == "L" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.lowest(len)): ta.lowest(len) : modeSwitch == "H" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.highest(len)): ta.highest(len) : modeSwitch == "DMA" ? donchian(len) : na //Var sum = 0.0 maopening_l = 0.0 maopening_s = 0.0 maclosing = 0.0 pos = strategy.position_size p = 0.0 p := pos == 0 ? (strategy.equity / 100) / close : p[1] truetime = true loss = 0.0 maxloss = 0.0 equity = 0.0 //MA Opening maopening_l := ma_func(maopeningtyp_l, maopeningsrc_l, maopeninglen_l) maopening_s := ma_func(maopeningtyp_s, maopeningsrc_s, maopeninglen_s) //MA Closing maclosing := ma_func(maclosingtyp, maclosingsrc, maclosinglen) * maclosingmul long1 = long1on == false ? 0 : long1shift == 0 ? 0 : long1lot == 0 ? 0 : maopening_l == 0 ? 0 : maopening_l * long1shift short1 = short1on == false ? 0 : short1shift == 0 ? 0 : short1lot == 0 ? 0 : maopening_s == 0 ? 0 : maopening_s * short1shift //Colors long1col = long1 == 0 ? na : color.green short1col = short1 == 0 ? na : color.red //Lines // plot(maopening_l, offset = OFFS, color = color.new(color.green, 50)) // plot(maopening_s, offset = OFFS, color = color.new(color.red, 50)) plot(maclosing, offset = OFFS, color = color.fuchsia) long1line = long1 == 0 ? close : long1 short1line = short1 == 0 ? close : short1 plot(long1line, offset = OFFS, color = long1col) plot(short1line, offset = OFFS, color = short1col) //Lots lotlong1 = p * long1lot lotshort1 = p * short1lot //Entry if truetime //Long sum := 0 strategy.entry("L", strategy.long, lotlong1, limit = on_close ? na : long1, when = long1 > 0 and pos <= sum and (on_close ? close <= long1[trade_offset] : true)) sum := lotlong1 //Short sum := 0 pos := -1 * pos strategy.entry("S", strategy.short, lotshort1, limit = on_close ? na : short1, when = short1 > 0 and pos <= sum and (on_close ? close >= short1[trade_offset] : true)) sum := lotshort1 strategy.exit("Exit", na, limit = maclosing) if time > finalTime strategy.close_all()