La idea principal de esta estrategia es identificar la dirección de la tendencia en un marco de tiempo más grande y encontrar puntos de ruptura para entrar en un marco de tiempo más pequeño.
Esta estrategia se basa principalmente en tres indicadores para el juicio.
Primero, calcule un ciclo más largo (como el diario) promedio móvil simple de X días. Permita comprar solo cuando el precio esté por encima de este promedio móvil. Esto se puede usar para determinar la dirección general de la tendencia y evitar períodos oscilantes de negociación.
En segundo lugar, calcular el precio más alto Swing High en un ciclo más corto (como 5 días). Cuando el precio rompe este precio más alto, se activa una señal de compra.
Tercero, establecer una línea de stop loss. Después de ingresar a la posición, la línea de stop loss se bloquea al precio más bajo un cierto período de lbStop lejos del punto más bajo reciente. Al mismo tiempo, establece una línea de promedio móvil (como la EMA de 10 días en el diario) como mecanismo de salida. Salga de la posición cuando el precio esté por debajo de esta línea de promedio móvil.
La estrategia también establece el valor ATR para evitar comprar puntos sobreextensibles.
El juicio de la interacción de los tres indicadores anteriores constituye la lógica central de esta estrategia.
Como estrategia de seguimiento de fuga, tiene las siguientes ventajas:
Utilice dos marcos de tiempo para evitar quedar atrapado en falsas rupturas en los mercados oscilantes.
Este tipo de ruptura tiene cierta inercia y es fácil de formar seguimiento. El parámetro de período de retroceso lb también se puede ajustar para encontrar rupturas realmente efectivas.
El método de stop loss es relativamente estricto, rastreando el punto más bajo reciente con una cierta distancia de amortiguador para evitar ser raspado.
Utilice la media móvil como mecanismo de salida para obtener ganancias de forma flexible de acuerdo con las condiciones del mercado.
El indicador ATR evita el riesgo de sobreapalancamiento.
Se pueden establecer diferentes combinaciones de parámetros para pruebas, con un gran espacio de optimización.
La estrategia también tiene algunos riesgos:
Cuando el precio oscila hacia arriba y hacia abajo alrededor de la línea media móvil, es fácil cambiar de ida y vuelta entre las posiciones de entrada y salida.
Cuando el punto de ruptura está cerca de la línea de la media móvil, existe un riesgo de retroceso relativamente grande.
Cuando no hay una tendencia obvia en el mercado, el tiempo de retención puede ser demasiado largo, lo que conlleva un riesgo temporal.
El parámetro ATR debe establecerse razonablemente. Si ATR es demasiado pequeño, el efecto de filtrado es débil. Si es demasiado grande, las oportunidades de entrada disminuirán.
Los parámetros excesivamente grandes pueden perder algunas oportunidades, mientras que los parámetros demasiado pequeños pueden identificar fallas.
Mitigación del riesgo:
La estrategia también puede optimizarse en las siguientes dimensiones:
Prueba diferentes combinaciones de parámetros de media móvil para encontrar los parámetros óptimos.
Pruebe diferentes ajustes de parámetros ATR para equilibrar las oportunidades de entrada y el control de riesgos.
Optimizar el parámetro de período de búsqueda para identificar breakouts más eficientes.
Trate de construir un stop loss dinámico basado en la volatilidad y la reducción para controlar el riesgo.
Incorporar otros factores como el volumen de operaciones para determinar la eficacia de las rupturas.
Desarrollar/
Intenta el aprendizaje automático para entrenar parámetros para parámetros óptimos
En general, esta es una estrategia típica de seguimiento de ruptura. A juzgar por los marcos de tiempo duales, el uso de Swing High para identificar el momento de entrada, y el uso de la línea de stop loss y los mecanismos de salida de seguro de doble promedio móvil forman un sistema lógico completo. Las características de riesgo y retorno de esta estrategia son claras, adecuadas para los inversores de seguimiento a mediano y largo plazo. Aunque hay ciertos riesgos, pueden reducirse optimizando parámetros y reglas. La estrategia tiene mucho margen de mejora.
/*backtest start: 2023-01-24 00:00:00 end: 2024-01-30 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/ // © millerrh // The intent of this strategy is to buy breakouts with a tight stop on smaller timeframes in the direction of the longer term trend. // Then use a trailing stop of a close below either the 10 MA or 20 MA (user choice) on that larger timeframe as the position // moves in your favor (i.e. whenever position price rises above the MA). // Option of using daily ATR as a measure of finding contracting ranges and ensuring a decent risk/reward. // (If the difference between the breakout point and your stop level is below a certain % of ATR, it could possibly find those consolidating periods.) //@version=4 strategy("Qullamaggie Breakout", overlay=true, initial_capital=10000, currency='USD', default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1) // === BACKTEST RANGE === Start = input(defval = timestamp("01 Jan 2019 06:00 +0000"), title = "Backtest Start Date", type = input.time) Finish = input(defval = timestamp("01 Jan 2100 00:00 +0000"), title = "Backtest End Date", type = input.time) // Inputs lb = input(defval = 3, title = "Lookback Period for Swing High", minval = 1, tooltip = "Lookback period for defining the breakout level.") lbStop = input(defval = 3, title = "Lookback Bars for Stop Level", minval = 1, tooltip = "Initial stop placement is the lowest low this many bars back. Allows for tighter stop placement than referencing swing lows.") htf = input(defval="D", title="Timeframe of Moving Averages", type=input.resolution, tooltip = "Allows you to set a different time frame for the moving averages. The default behavior is to identify good tightening setups on a larger timeframe (like daily) and enter the trade on a breakout occuring on a smaller timeframe, using the moving averages of the larger timeframe to trail your stop.") maType = input(defval="SMA", options=["EMA", "SMA"], title = "Moving Average Type") ma1Length = input(defval = 10, title = "1st Moving Average Length", minval = 1) ma2Length = input(defval = 20, title = "2nd Moving Average Length", minval = 1) ma3Length = input(defval = 50, title = "3rd Moving Average Length", minval = 1) useMaFilter = input(title = "Use 3rd Moving Average for Filtering?", type = input.bool, defval = true, tooltip = "Signals will be ignored when price is under this slowest moving average. The intent is to keep you out of bear periods and only buying when price is showing strength or trading with the longer term trend.") trailMaInput = input(defval="2nd Moving Average", options=["1st Moving Average", "2nd Moving Average"], title = "Trailing Stop") // MA Calculations ma(maType, src, length) => maType == "EMA" ? ema(src, length) : sma(src, length) //Ternary Operator (if maType equals EMA, then do ema calc, else do sma calc) ma1 = security(syminfo.tickerid, htf, ma(maType, close, ma1Length)) ma2 = security(syminfo.tickerid, htf, ma(maType, close, ma2Length)) ma3 = security(syminfo.tickerid, htf, ma(maType, close, ma3Length)) plot(ma1, color=color.purple, style=plot.style_line, title="MA1", linewidth=2, transp = 60) plot(ma2, color=color.yellow, style=plot.style_line, title="MA2", linewidth=2, transp = 60) plot(ma3, color=color.white, style=plot.style_line, title="MA3", linewidth=2, transp = 60) // === USE ATR FOR FILTERING === // The idea here is that you want to buy in a consolodating range for best risk/reward. So here you can compare the current distance between // support/resistance vs.the ATR and make sure you aren't buying at a point that is too extended from normal. useAtrFilter = input(title = "Use ATR for Filtering?", type = input.bool, defval = false, tooltip = "Signals will be ignored if the distance between support and resistance is larger than a user-defined percentage of Daily ATR. This allows the user to ensure they are not buying something that is too extended and instead focus on names that are consolidating more.") atrPerc = input(defval = 100, title = "% of Daily ATR Value", minval = 1) atrValue = security(syminfo.tickerid, "D", atr(14))*atrPerc*.01 // === PLOT SWING HIGH/LOW AND MOST RECENT LOW TO USE AS STOP LOSS EXIT POINT === // Change these values to adjust the look back and look forward periods for your swing high/low calculations pvtLenL = lb pvtLenR = lb // Get High and Low Pivot Points pvthi_ = pivothigh(high, pvtLenL, pvtLenR) pvtlo_ = pivotlow(low, pvtLenL, pvtLenR) // Force Pivot completion before plotting. Shunt = 1 //Wait for close before printing pivot? 1 for true 0 for flase maxLvlLen = 0 //Maximum Extension Length pvthi = pvthi_[Shunt] pvtlo = pvtlo_[Shunt] // Count How many candles for current Pivot Level, If new reset. counthi = barssince(not na(pvthi)) countlo = barssince(not na(pvtlo)) pvthis = fixnan(pvthi) pvtlos = fixnan(pvtlo) hipc = change(pvthis) != 0 ? na : color.maroon lopc = change(pvtlos) != 0 ? na : color.green // Display Pivot lines plot((maxLvlLen == 0 or counthi < maxLvlLen) ? pvthis : na, color=hipc, transp=0, linewidth=1, offset=-pvtLenR-Shunt, title="Top Levels") // plot((maxLvlLen == 0 or countlo < maxLvlLen) ? pvtlos : na, color=lopc, transp=0, linewidth=1, offset=-pvtLenR-Shunt, title="Bottom Levels") plot((maxLvlLen == 0 or counthi < maxLvlLen) ? pvthis : na, color=hipc, transp=0, linewidth=1, offset=0, title="Top Levels 2") // plot((maxLvlLen == 0 or countlo < maxLvlLen) ? pvtlos : na, color=lopc, transp=0, linewidth=1, offset=0, title="Bottom Levels 2") // BUY CONDITIONS stopLevelCalc = valuewhen(pvtlo_, low[pvtLenR], 0) //Stop Level at Swing Low buyLevel = valuewhen(pvthi_, high[pvtLenR], 0) //Buy level at Swing High plot(buyLevel, style=plot.style_line, color=color.blue, title = "Current Breakout Level", show_last=1, linewidth=1, transp=50, trackprice=true) // Conditions for entry and exit stopLevel = float(na) // Define stop level here as "na" so that I can reference it in the inPosition // variable and the ATR calculation before the stopLevel is actually defined. buyConditions = (useMaFilter ? buyLevel > ma3 : true) and (useAtrFilter ? (buyLevel - stopLevel[1]) < atrValue : true) // buySignal = high > buyLevel and buyConditions buySignal = crossover(high, buyLevel) and buyConditions trailMa = trailMaInput == "1st Moving Average" ? ma1 : ma2 sellSignal = crossunder(close, trailMa) // sellSignal = security(syminfo.tickerid, htf, close < trailMa) and security(syminfo.tickerid, htf, close[1] < trailMa) // STOP AND PRICE LEVELS inPosition = bool(na) inPosition := buySignal[1] ? true : sellSignal[1] ? false : low <= stopLevel[1] ? false : inPosition[1] lowDefine = lowest(low, lbStop) stopLevel := inPosition ? stopLevel[1] : lowDefine // plot(stopLevel) buyPrice = buyLevel buyPrice := inPosition ? buyPrice[1] : buyLevel plot(stopLevel, style=plot.style_line, color=color.orange, title = "Current Stop Level", show_last=1, linewidth=1, transp=50, trackprice=true) plot(inPosition ? stopLevel : na, style=plot.style_circles, color=color.orange, title = "Historical Stop Levels", transp=50, trackprice=false) // plot(buyPrice, style=plot.style_line, color=color.blue, linewidth=1, transp=50, trackprice=true) // (STRATEGY ONLY) Comment out for Study strategy.entry("Long", strategy.long, stop = buyLevel, when = buyConditions) strategy.exit("Exit Long", from_entry = "Long", stop=stopLevel[1]) if (low[1] > trailMa) strategy.close("Long", when = sellSignal) // if (low[1] > trailMa) // strategy.exit("Exit Long", from_entry = "Long", stop=trailMa) //to get this to work right, I need to reference highest highs instead of swing highs //because it can have me buy right back in after selling if the stop level is above the last registered swing high point.