Tendencia siguiendo una estrategia basada en la media móvil

El autor:¿ Qué pasa?, Fecha: 2024-01-24 14:24:36
Las etiquetas:

img

Resumen general

Es una estrategia de seguimiento de tendencia simple basada en el promedio móvil. Juzga la dirección y duración de la tendencia actual comparando la relación de tamaño entre los promedios móviles de diferentes ciclos. Se hace largo cuando el promedio móvil de ciclo corto cruza por encima del ciclo largo, y se hace corto cuando sucede lo contrario. Al mismo tiempo, se establecen puntos de stop loss y take profit para controlar los riesgos.

Estrategia lógica

La estrategia utiliza 4 promedios móviles con diferentes ciclos: líneas de 5 días, 10 días, 15 días y 25 días. Se llaman MA1, MA2, MA3 y MA4. Entre ellos, MA1 es el más corto y MA4 es el más largo.

Cuando MA1>MA2>MA3>MA4, indica una tendencia al alza y va largo.

Las condiciones de posición abierta tanto para el largo como para el corto deben satisfacer el filtro de stop loss ATR al mismo tiempo, es decir, el valor de ATR debe ser mayor que la SMA de 40 días de ATR. Esto evita generar señales erróneas cuando la fluctuación del precio es demasiado pequeña.

Análisis de ventajas

La estrategia tiene las siguientes ventajas:

  1. La lógica es simple y fácil de implementar.
  2. El uso de múltiples promedios móviles para determinar la dirección de la tendencia es confiable.
  3. La configuración de puntos de stop loss y take profit puede controlar eficazmente la pérdida máxima por operación.
  4. El filtro de stop loss ATR evita señales erróneas cuando la fluctuación del precio es pequeña.

Análisis de riesgos

La estrategia también presenta los siguientes riesgos:

  1. Es fácil generar señales erróneas en un mercado en gran parte con choque.
  2. La configuración incorrecta de los parámetros (ciclo de media móvil, etc.) puede conducir a un mal rendimiento de la estrategia.
  3. No tiene en cuenta el impacto de los datos fundamentales y las noticias importantes en los precios.

Para reducir estos riesgos, los parámetros se pueden optimizar adecuadamente o se pueden agregar condiciones de filtro adicionales para mejorar la estabilidad de la estrategia.

Direcciones de optimización

Las direcciones de optimización de la estrategia incluyen:

  1. Prueba diferentes combinaciones de parámetros de ciclo de media móvil para encontrar los parámetros óptimos.
  2. Añadir otros filtros de indicadores técnicos como MACD y KDJ para juzgar la fiabilidad de las señales.
  3. Añadir un filtro de volumen de operaciones, sólo operar cuando el volumen de operaciones se expande.
  4. Parámetros de ajuste fino basados en las diferencias entre variedades.
  5. Agregue algoritmos de aprendizaje automático para juzgar las señales.

Conclusión

En general, esta es una estrategia de seguimiento de tendencias relativamente simple. Juzga la dirección de la tendencia a través de promedios móviles y establece un stop loss y take profit razonables para controlar los niveles de riesgo. Todavía hay mucho espacio para la optimización, como ajustar parámetros, agregar filtros, etc. para mejorar aún más la estabilidad y la rentabilidad de la estrategia.


/*backtest
start: 2023-01-17 00:00:00
end: 2024-01-23 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/
// © fpemehd
// @version=5

// # ========================================================================= #
// #                   |   STRATEGY  |
// # ========================================================================= #

strategy(title = 'MA Simple Strategy with SL & TP & ATR Filters',
      shorttitle = 'MA Strategy',
      overlay = true,
      pyramiding = 0,
      default_qty_type = strategy.percent_of_equity,
      default_qty_value = 100,
      commission_type  = strategy.commission.percent,
      commission_value = 0.1,
      initial_capital = 100000,
      max_lines_count = 150,
      max_labels_count = 300)

// # ========================================================================= #
// #                          Inputs
// # ========================================================================= #

// 1. Time
i_start = input (defval = timestamp("20 Jan 1990 00:00 +0900"), title = "Start Date", tooltip = "Choose Backtest Start Date", inline = "Start Date", group = "Time" ) 
i_end = input (defval = timestamp("20 Dec 2030 00:00 +0900"), title = "End Date", tooltip = "Choose Backtest End Date", inline = "End Date", group = "Time" ) 
c_timeCond = true

// 2. Inputs for direction: Long? Short? Both? 
i_longEnabled = input.bool(defval = true , title = "Long?", tooltip = "Enable Long Position Trade?", inline = "Long / Short", group = "Long / Short" )
i_shortEnabled = input.bool(defval = true , title = "Short?", tooltip = "Enable Short Position Trade?", inline = "Long / Short", group = "Long / Short" )

// 3. Use Filters? What Filters?
i_ATRFilterOn = input.bool(defval = true , title = "ATR Filter On?", tooltip = "ATR Filter On?", inline = "ATR Filter", group =  "Filters") 
i_ATRSMALen = input.int(defval = 40 , title = "SMA Length for ATR SMA", minval = 1 , maxval = 100000 , step = 1 , tooltip = "ATR should be bigger than this", inline = "ATR Filter", group = "Filters") 

// 3. Shared inputs for Long and Short
//// 3-1. Inputs for Stop Loss Type: normal? or trailing? 
//// If trailing, always trailing or trailing after take profit order executed?
i_useSLTP = input.bool(defval =  true, title = "Enable SL & TP?", tooltip = "", inline = "Enable SL & TP & SL Type", group = "Shared Inputs") 
i_tslEnabled = input.bool(defval = false , title = "Enable Trailing SL?", tooltip = "Enable Stop Loss & Take Profit? \n\Enable Trailing SL?", inline = "Enable SL & TP & SL Type", group = "Shared Inputs") 
// i_tslAfterTP = input.bool(defval = true , title = "Enable Trailing SL after TP?", tooltip = "Enable Trailing SL after TP?", inline = "Trailing SL Execution", group = "Shared Inputs") 
i_slType = input.string(defval = "ATR", title = "Stop Loss Type", options = ["Percent", "ATR"], tooltip = "Stop Loss based on %? ATR?", inline = "Stop Loss Type", group = "Shared Inputs") 
i_slATRLen = input.int(defval = 14, title = "ATR Length", minval = 1 , maxval = 200 , step = 1, inline = "Stop Loss ATR", group = "Shared Inputs")  
i_tpType = input.string(defval = "R:R", title = "Take Profit Type", options = ["Percent", "ATR", "R:R"], tooltip = "Take Profit based on %? ATR? R-R ratio?", inline = "Take Profit Type", group = "Shared Inputs") 

//// 3-2. Inputs for Quantity
i_tpQuantityPerc = input.float(defval = 50, title = 'Take Profit Quantity %', minval = 0.0, maxval = 100, step = 1.0, tooltip = '% of position when tp target is met.', group = 'Shared Inputs')

// 4. Inputs for Long Stop Loss & Long Take Profit

i_slPercentLong = input.float(defval = 3, title = "SL Percent", tooltip = "", inline = "Percent > Long Stop Loss / Take Profit Percent", group = "Long Stop Loss / Take Profit") 
i_tpPercentLong = input.float(defval = 3, title = "TP Percent", tooltip = "Long Stop Loss && Take Profit Percent?", inline = "Percent > Long Stop Loss / Take Profit Percent", group = "Long Stop Loss / Take Profit") 
i_slATRMultLong = input.float(defval = 3, title = "SL ATR Multiplier", minval = 1 , maxval = 200 , step = 0.1, tooltip = "", inline = "Long Stop Loss / Take Profit ATR", group = "Long Stop Loss / Take Profit") 
i_tpATRMultLong = input.float(defval = 3, title = "TP ATR Multiplier", minval = 1 , maxval = 200 , step = 0.1, tooltip = "ATR > Long Stop Loss && Take Profit ATR Multiplier? \n\Stop Loss = i_slATRMultLong * ATR (i_slATRLen) \n\Take Profit = i_tpATRMultLong * ATR (i_tpATRLen)", inline = "Long Stop Loss / Take Profit ATR", group = "Long Stop Loss / Take Profit") 
i_tpRRratioLong = input.float(defval = 1.8, title = "R:R Ratio", minval = 0.1 , maxval = 200 , step = 0.1, tooltip = "R:R Ratio > Risk Reward Ratio? It will automatically set Take Profit % based on Stop Loss", inline = "R:R Ratio", group = "Long Stop Loss / Take Profit") 

// 5. Inputs for Short Stop Loss & Short Take Profit
i_slPercentShort = input.float(defval = 3, title = "SL Percent", tooltip = "", inline = "Percent > Short Stop Loss / Take Profit Percent", group = "Short Stop Loss / Take Profit") 
i_tpPercentShort = input.float(defval = 3, title = "TP Percent", tooltip = "Short Stop Loss && Take Profit Percent?", inline = "Percent > Short Stop Loss / Take Profit Percent", group = "Short Stop Loss / Take Profit") 
i_slATRMultShort = input.float(defval = 3, title = "SL ATR Multiplier", minval = 1 , maxval = 200 , step = 0.1, tooltip = "", inline = "ATR > Short Stop Loss / Take Profit ATR", group = "Short Stop Loss / Take Profit") 
i_tpATRMultShort = input.float(defval = 3, title = "TP ATR Multiplier", minval = 1 , maxval = 200 , step = 0.1, tooltip = "ATR > Short Stop Loss && Take Profit ATR Multiplier? \n\Stop Loss = i_slATRMultShort * ATR (i_slATRLen) \n\Take Profit = i_tpATRMultShort * ATR (i_tpATRLen)", inline = "ATR > Short Stop Loss / Take Profit ATR", group = "Short Stop Loss / Take Profit") 
i_tpRRratioShort = input.float(defval = 1.8, title = "R:R Ratio", minval = 0.1 , maxval = 200 , step = 0.1, tooltip = "R:R Ratio > Risk Reward Ratio? It will automatically set Take Profit % based on Stop Loss", inline = "R:R Ratio", group = "Short Stop Loss / Take Profit") 

// 6. Inputs for logic
i_MAType = input.string(defval = "RMA", title = "MA Type", options = ["SMA", "EMA", "WMA", "HMA", "RMA", "VWMA", "SWMA", "ALMA", "VWAP"], tooltip = "Choose MA Type", inline = "MA Type", group = 'Strategy') 
i_MA1Len = input.int(defval = 5, title = 'MA 1 Length', minval = 1, inline = 'MA Length', group = 'Strategy')
i_MA2Len = input.int(defval = 10, title = 'MA 2 Length', minval = 1, inline = 'MA Length', group = 'Strategy')
i_MA3Len = input.int(defval = 15, title = 'MA 3 Length', minval = 1, inline = 'MA Length', group = 'Strategy')
i_MA4Len = input.int(defval = 25, title = 'MA 4 Length', minval = 1, inline = 'MA Length', group = 'Strategy')
i_ALMAOffset = input.float(defval = 0.7 , title = "ALMA Offset Value", tooltip = "The Value of ALMA offset", inline = "ALMA Input", group = 'Strategy')
i_ALMASigma = input.float(defval = 7 , title = "ALMA Sigma Value", tooltip = "The Value of ALMA sigma", inline = "ALMA Input", group = 'Strategy')

// # ========================================================================= #
// #                          Entry, Close Logic
// # ========================================================================= #

bool i_ATRFilter = ta.atr(length = i_slATRLen) >= ta.sma(source = ta.atr(length = i_slATRLen), length = i_ATRSMALen) ? true : false

// calculate Technical Indicators for the Logic

getMAValue (source, length, almaOffset, almaSigma) => 
    switch i_MAType 
        'SMA' => ta.sma(source = source, length = length) 
        'EMA' => ta.ema(source = source, length = length) 
        'WMA' => ta.wma(source = source, length = length) 
        'HMA' => ta.hma(source = source, length = length) 
        'RMA' => ta.rma(source = source, length = length) 
        'SWMA' => ta.swma(source = source) 
        'ALMA' => ta.alma(series = source, length = length, offset = almaOffset, sigma = almaSigma) 
        'VWMA' => ta.vwma(source = source, length = length) 
        'VWAP' => ta.vwap(source = source)
        => na 

float c_MA1 = getMAValue(close, i_MA1Len, i_ALMAOffset, i_ALMASigma)
float c_MA2 = getMAValue(close, i_MA2Len, i_ALMAOffset, i_ALMASigma)
float c_MA3 = getMAValue(close, i_MA3Len, i_ALMAOffset, i_ALMASigma)
float c_MA4 = getMAValue(close, i_MA4Len, i_ALMAOffset, i_ALMASigma)

// Logic: 정배열 될 떄 들어가
var ma1Color = color.new(color.red, 0)
plot(series = c_MA1, title = 'SMA 1', color = ma1Color, linewidth = 1, style = plot.style_line)
var ma2Color = color.new(color.orange, 0)
plot(series = c_MA2, title = 'SMA 2', color = ma2Color, linewidth = 1, style = plot.style_line)
var ma3Color = color.new(color.yellow, 0)
plot(series = c_MA3, title = 'SMA 3', color = ma3Color, linewidth = 1, style = plot.style_line)
var ma4Color = color.new(color.green, 0)
plot(series = c_MA4, title = 'SMA 4', color = ma4Color, linewidth = 1, style = plot.style_line)

bool openLongCond = (c_MA1 >= c_MA2 and c_MA2 >= c_MA3 and c_MA3 >= c_MA4) 
bool openShortCond = (c_MA1 <= c_MA2 and c_MA2 <= c_MA3 and c_MA3 <= c_MA4)

bool openLong = i_longEnabled and openLongCond and (not i_ATRFilterOn or i_ATRFilter)
bool openShort = i_shortEnabled and openShortCond and (not i_ATRFilterOn or i_ATRFilter)

openLongCondColor = openLongCond ? color.new(color = color.blue, transp = 80) : na
bgcolor(color = openLongCondColor)
ATRFilterColor = i_ATRFilter ? color.new(color = color.orange, transp = 80) : na 
bgcolor(color = ATRFilterColor)

bool enterLong = openLong and not (strategy.opentrades.size(strategy.opentrades-1) > 0)
bool enterShort = openShort and not (strategy.opentrades.size(strategy.opentrades-1) < 0)

bool closeLong = i_longEnabled and (c_MA1[1] >= c_MA2[1] and c_MA2[1] >= c_MA3[1] and c_MA3[1] >= c_MA4[1]) and not (c_MA1 >= c_MA2 and c_MA2 >= c_MA3 and c_MA3 >= c_MA4) 
bool closeShort = i_shortEnabled and (c_MA1[1] <= c_MA2[1] and c_MA2[1] <= c_MA3[1] and c_MA3[1] <= c_MA4[1]) and not (c_MA1 <= c_MA2 and c_MA2 <= c_MA3 and c_MA3 <= c_MA4)

// # ========================================================================= #
// #                          Position, Status Conrtol
// # ========================================================================= #

// longisActive: New Long || Already Long && not closeLong, short is the same
bool longIsActive = enterLong or strategy.opentrades.size(strategy.opentrades - 1) > 0 and not closeLong
bool shortIsActive = enterShort or strategy.opentrades.size(strategy.opentrades - 1) < 0 and not closeShort

// before longTPExecution: no trailing SL && after longTPExecution: trailing SL starts
// longTPExecution qunatity should be less than 100% 
bool longTPExecuted = false
bool shortTPExecuted = false

// # ========================================================================= #
// #                          Long Stop Loss Logic
// # ========================================================================= #
float openAtr = ta.valuewhen(enterLong or enterShort, ta.atr(i_slATRLen), 0)

f_getLongSL (source) => 
    switch i_slType
        'Percent' => source * (1 - (i_slPercentLong/100))
        'ATR' => source - i_slATRMultLong * openAtr
        => na

var float c_longSLPrice = na
c_longSLPrice := if (longIsActive)
    if (enterLong)
        f_getLongSL(close)
    else
        c_stopPrice = f_getLongSL(i_tslEnabled ? high : strategy.opentrades.entry_price(trade_num = strategy.opentrades - 1))
        math.max(c_stopPrice, nz(c_longSLPrice[1]))
else
    na

// # ========================================================================= #
// #                          Short Stop Loss Logic
// # ========================================================================= #
f_getShortSL (source) => 
    switch i_slType
        'Percent' => source * (1 + (i_slPercentShort)/100)
        'ATR' => source + i_slATRMultShort * openAtr
        => na

var float c_shortSLPrice = na
c_shortSLPrice := if (shortIsActive)
    if (enterShort)
        f_getShortSL (close)
    else
        c_stopPrice = f_getShortSL(i_tslEnabled ? low : strategy.opentrades.entry_price(strategy.opentrades - 1))
        math.min(c_stopPrice, nz(c_shortSLPrice[1], 999999.9))
else
    na

// # ========================================================================= #
// #                          Long Take Profit Logic
// # ========================================================================= #

f_getLongTP () => 
    switch i_tpType
        'Percent' => close * (1 + (i_tpPercentLong/100))
        'ATR' => close + i_tpATRMultLong * openAtr
        'R:R' => close + i_tpRRratioLong * (close - f_getLongSL(close))
        => na

var float c_longTPPrice = na
c_longTPPrice := if (longIsActive and not longTPExecuted)
    if (enterLong)
        f_getLongTP()
    else 
        nz(c_longTPPrice[1], f_getLongTP())
else
    na

longTPExecuted := strategy.opentrades.size(strategy.opentrades - 1) > 0 and (longTPExecuted[1] or strategy.opentrades.size(strategy.opentrades - 1) < strategy.opentrades.size(strategy.opentrades - 1)[1] or strategy.opentrades.size(strategy.opentrades - 1)[1] == 0 and high >= c_longTPPrice)

// # ========================================================================= #
// #                          Short Take Profit Logic
// # ========================================================================= #

f_getShortTP () => 
    switch i_tpType
        'Percent' => close * (1 - (i_tpPercentShort/100))
        'ATR' => close - i_tpATRMultShort * openAtr
        'R:R' => close - i_tpRRratioShort * (close - f_getLongSL(close))
        => na

var float c_shortTPPrice = na
c_shortTPPrice := if (shortIsActive and not shortTPExecuted)
    if (enterShort)
        f_getShortTP()
    else
        nz(c_shortTPPrice[1], f_getShortTP())
else
    na

shortTPExecuted := strategy.opentrades.size(strategy.opentrades - 1) < 0 and (shortTPExecuted[1] or strategy.opentrades.size(strategy.opentrades - 1) > strategy.opentrades.size(strategy.opentrades - 1)[1] or strategy.opentrades.size(strategy.opentrades - 1)[1] == 0 and low <= c_shortTPPrice)

// # ========================================================================= #
// #                          Make Orders
// # ========================================================================= #

if (c_timeCond)
    if (enterLong)
        strategy.entry(id = "Long Entry", direction = strategy.long , comment = 'Long(' + syminfo.ticker + '): Started', alert_message = 'Long(' + syminfo.ticker + '): Started')

    if (enterShort)
        strategy.entry(id = "Short Entry", direction = strategy.short , comment = 'Short(' + syminfo.ticker + '): Started', alert_message = 'Short(' + syminfo.ticker + '): Started')

    if (closeLong)
        strategy.close(id = 'Long Entry', comment = 'Close Long', alert_message = 'Long: Closed at market price')

    if (closeShort)
        strategy.close(id = 'Short Entry', comment = 'Close Short', alert_message = 'Short: Closed at market price')

    if (longIsActive and i_useSLTP)
        strategy.exit(id = 'Long Take Profit / Stop Loss', from_entry = 'Long Entry', qty_percent = i_tpQuantityPerc, limit = c_longTPPrice, stop = c_longSLPrice, alert_message = 'Long(' + syminfo.ticker + '): Take Profit or Stop Loss executed')
        strategy.exit(id = 'Long Stop Loss', from_entry = 'Long Entry', stop = c_longSLPrice, alert_message = 'Long(' + syminfo.ticker + '): Stop Loss executed')
    
    if (shortIsActive and i_useSLTP)
        strategy.exit(id = 'Short Take Profit / Stop Loss', from_entry = 'Short Entry', qty_percent = i_tpQuantityPerc, limit = c_shortTPPrice, stop = c_shortSLPrice, alert_message = 'Short(' + syminfo.ticker + '): Take Profit or Stop Loss executed')
        strategy.exit(id = 'Short Stop Loss', from_entry = 'Short Entry', stop = c_shortSLPrice, alert_message = 'Short(' + syminfo.ticker + '): Stop Loss executed')

// # ========================================================================= #
// #                          Plot
// # ========================================================================= #

var posColor = color.new(color.white, 0)
plot(series = strategy.opentrades.entry_price(strategy.opentrades - 1), title = 'Position', color = posColor, linewidth = 1, style = plot.style_linebr)

var stopLossColor = color.new(color.maroon, 0)
plot(series = c_longSLPrice, title = 'Long Stop Loss', color = stopLossColor, linewidth = 1, style = plot.style_linebr, offset = 1)
plot(series = c_shortSLPrice, title = 'Short Stop Loss', color = stopLossColor, linewidth = 1, style = plot.style_linebr, offset = 1)

longTPExecutedColor = longTPExecuted ? color.new(color = color.green, transp = 80) : na 
//bgcolor(color = longTPExecutedColor) 
shortTPExecutedColor = shortTPExecuted ? color.new(color = color.red, transp = 80) : na 
//bgcolor(color = shortTPExecutedColor) 
// isPositionOpenedColor = strategy.opentrades.size(strategy.opentrades-1) != 0 ? color.new(color = color.yellow, transp = 90) : na 
// bgcolor(color = isPositionOpenedColor) 

var takeProfitColor = color.new(color.teal, 0)
plot(series = c_longTPPrice, title = 'Long Take Profit', color = takeProfitColor, linewidth = 1, style = plot.style_linebr, offset = 1)
plot(series = c_shortTPPrice, title = 'Short Take Profit', color = takeProfitColor, linewidth = 1, style = plot.style_linebr, offset = 1)

Más.