
Este sistema de seguimiento de tendencias adaptativo basado en la media múltiple de la nivelación nuclear es una estrategia de negociación cuantitativa avanzada que integra cinco promedios móviles personalizados, filtros de múltiples capas y mecanismos de confirmación para identificar y aprovechar las tendencias continuas del mercado. La estrategia utiliza la tecnología de la nivelación nuclear en lugar de las promedios móviles tradicionales, lo que ofrece un efecto de nivelación más flexible y una capacidad de adaptación que se adapta a una variedad de condiciones de mercado y marcos de tiempo.
Las funciones centrales incluyen: la visualización de las tendencias actuales del mercado con el uso de una “banda de línea media” compuesta por cinco medias móviles; la reducción de ruido y falsas señales a través de filtros RSI, filtros de intensidad de tendencia y confirmación de tendencia; la activación de señales de entrada solo cuando se cumplen ciertas condiciones; y la adopción de múltiples opciones de salida (como el porcentaje de seguimiento de stop loss, el seguimiento de stop loss ATR, el objetivo de ganancia ATR y el stop loss de dureza) para administrar el riesgo y proteger los beneficios.
La lógica central de la estrategia se desarrolla en torno a los siguientes componentes clave:
La media móvil del núcleoLa estrategia utiliza la tecnología de la suavización nuclear en lugar de la media móvil estándar, ofreciendo una suavización más flexible y adaptable que la MA tradicional. Soporta tres tipos de núcleos:
alphaybetaLos parámetros se controlan independientemente en el retraso positivo y negativo, lo que hace que la MA reaccione de manera diferente a la subida y bajada de los precios.bandwidthEl parámetro controla la anchura de la curva de la campana.bandwidthParámetrosCinturón de la línea mediaLos cinco MA forman una “banda de mediano” en el gráfico, cuya disposición y posición relativa proporcionan una indicación visual de la intensidad y dirección de la tendencia.
Pruebas cruzadas: Estrategia de monitoreo de cruces entre MA continuos en la banda homogénea, el usuario puede especificar el número de cruces necesarios para generar una señal potencial.
El filtro RSI: ayuda a evitar la entrada en el mercado de exceso de extensión. En el caso de entrada múltiple, el RSI debe estar por debajo del nivel de sobreventa; en el caso de entrada en blanco, debe estar por encima del nivel de sobreventa.
Filtros de intensidad de tendenciaUtiliza el RSI de una media móvil para medir la intensidad de una tendencia y asegúrese de operar en la dirección de una tendencia fuerte y establecida.
Confirmación de la tendencia: Para reducir aún más las señales falsas, se requiere que los requisitos de entrada (cruzadas MA, RSI y intensidad de la tendencia) se cumplan en un número determinado de líneas K en serie antes de activar una operación.
Salir de la lógicaLas estrategias priorizan la salida en el siguiente orden: Hard Stop Loss, Tracking Stop Loss (porcentaje o basado en el ATR) y Profit (basado en el ATR). Esto asegura que las pérdidas se minimicen y las ganancias se protejan.
Alturas de nivelación personalizadasEl uso de núcleos suaves (especialmente núcleos beta) proporciona un nivel de control de la sensibilidad a la MA, que no está disponible en la MA estándar. Esto permite un enfoque más adaptativo y refinado del seguimiento de tendencias.
Combinando la fuerza de la tendencia y la confirmaciónLa combinación del filtro de la fuerza de la tendencia (RSI con MA) y el período de confirmación de la tendencia ofrece un poderoso mecanismo de filtración que va más allá de las lecturas simples de MA cruzado o RSI. Esto ayuda a filtrar las tendencias débiles y las situaciones de oscilación.
Opciones de exclusión de múltiples prioridades: La lógica de salida de la estrategia es muy compleja, ofreciendo una combinación de paradas fijas y dinámicas y niveles de ganancias. La prioridad es asegurar que la salida más conservadora (parada de dureza) sea la primera en ser activada, seguida por el seguimiento de las paradas y finalmente el objetivo de ganancias.
Grupos de entrada completos: Todos los insumos están clasificados en grupos de aspectos específicos de la estrategia de control, lo que permite al usuario ubicar y ajustar fácilmente los insumos.
Control de la dirección de la transacciónA diferencia de muchas otras estrategias, esta permite activar o desactivar de forma independiente las operaciones con más y con menos titulares.
Sistema de tendencias en todas las direccionesEl indicador combina los aspectos necesarios para el comercio: señales de entrada, cálculo de stop loss y cálculo de ganancias.
Desafíos de optimización de parámetrosDebido a que la estrategia tiene una gran cantidad de parámetros, existe el riesgo de sobreajuste. Ajustar los parámetros con demasiada precisión puede hacer que la estrategia funcione bien en la retroalimentación, pero falle en el comercio real. Se recomienda una sólida verificación cruzada y pruebas fuera de la muestra para asegurar que la configuración de los parámetros sea universal.
Retrasos en la respuesta a los cambios de tendencia: Aunque la estrategia está diseñada para identificar tendencias continuas, puede no reaccionar con suficiente rapidez en el caso de una reversión brusca del mercado, lo que lleva a una retirada parcial. Se puede equilibrar la sensibilidad a los cambios de tendencia y la capacidad de filtrar el ruido mediante el ajuste de la longitud de la MA y los parámetros centrales.
MA cruza falsas señales: Incluso con múltiples capas de filtración, es posible que se produzcan falsas señales en mercados convulsivos. Se recomienda usar esta estrategia en mercados de tendencia identificados, o aumentar el período de confirmación de tendencia para reducir las falsas señales.
El deterioro se desencadena demasiado pronto.En un mercado de gran volatilidad, los paros pueden ser desencadenados prematuramente, lo que lleva a la pérdida de las reajustes de precios posteriores y la reanudación de la tendencia. Los paros basados en el ATR pueden considerarse y ajustarse adecuadamente para adaptarse a la volatilidad del mercado.
Riesgo de complejidadLa complejidad de las estrategias puede dificultar la detección de fallos y la supervisión en tiempo real. Se recomienda comenzar con una configuración simple y agregar funciones complejas gradualmente, asegurando una comprensión completa del papel de cada componente.
Adaptabilidad del marco de tiempo: La política actual puede optimizarse aún más para que pueda ajustar automáticamente los parámetros en función de diferentes marcos de tiempo. Por ejemplo, se puede agregar la función de ajuste automático de parámetros en función de los marcos de tiempo, lo que permite que la política funcione de manera efectiva en los gráficos de línea diaria, horaria o minuto.
Detección del entorno del mercadoAumentar el mecanismo de detección automática del entorno de mercado (trend, intervalo o alta volatilidad) y ajustar los parámetros de negociación de acuerdo con los resultados detectados. Por ejemplo, aumentar la intensidad de filtración en el mercado intervalo o ajustar el objetivo de ganancias, relajar las condiciones de filtración en el mercado de tendencia.
El RSI está a la baja.El diseño de los umbrales de sobrecompra y sobreventa del RSI es dinámico en lugar de estático, y se ajusta automáticamente según la volatilidad del mercado reciente. Esto puede mejorar la adaptabilidad de la estrategia en diferentes condiciones de mercado.
Indicadores de fluctuación cuantitativa integradosIntegración de la estrategia con indicadores de volatilidad (como el ancho de banda de Bollinger) para ajustar los objetivos de stop loss y profit en un entorno de alta volatilidad y reducir el riesgo de ser desviado de una tendencia efectiva.
Confirmación del marco temporal múltiple: agregar una confirmación de tendencia en un marco de tiempo más alto para asegurar que la dirección de la operación coincida con una tendencia más grande. Por ejemplo, solo se realiza una operación cuando la tendencia de la línea diaria coincide con la tendencia de la línea horaria.
Monitoreo de rendimiento y adaptaciónSistema de monitoreo en tiempo real del rendimiento de la estrategia, seguimiento de indicadores como el índice de ganancias, pérdidas y ganancias y el máximo retiro, ajuste automático de parámetros o suspensión de operaciones cuando los indicadores de rendimiento bajan por debajo del umbral predeterminado.
Aprendizaje automático: Explorar la integración de algoritmos de aprendizaje automático en el proceso de optimización de parámetros, lo que permite que las estrategias aprendan la combinación de parámetros óptima de los datos históricos y mejoren constantemente a medida que se acumulan nuevos datos.
El sistema de seguimiento de tendencias adaptativo basado en el plano nuclear de múltiples medias es una herramienta de seguimiento de tendencias poderosa y flexible, que combina la claridad visual de la banda de medias móviles con la capacidad de filtrado y gestión de riesgos avanzados de plano nuclear, RSI, intensidad de la tendencia y varias opciones de salida. Está diseñado para los comerciantes que desean tener herramientas personalizadas y potentes para identificar y negociar tendencias continuas en el mercado.
La mayor ventaja de esta estrategia reside en su alta personalización y adaptabilidad, lo que le permite adaptarse a una variedad de condiciones de mercado. A través de la tecnología de suavización nuclear, ofrece un control más refinado que el promedio móvil tradicional, mientras que los mecanismos de filtración y confirmación en múltiples capas ayudan a reducir las señales falsas. Al mismo tiempo, el sistema de gestión de riesgos integrado ofrece una variedad de estrategias de salida que aseguran la minimización de pérdidas y la protección de las ganancias.
Sin embargo, los usuarios deben estar atentos a los desafíos de la optimización de los parámetros, evitar el exceso de ajuste y ajustar las estrategias en función de las condiciones específicas del mercado. Se recomienda realizar una adecuada retroalimentación y pruebas de avance para garantizar que las estrategias funcionen de manera sólida en una variedad de condiciones de mercado.
/*backtest
start: 2024-03-28 00:00:00
end: 2025-03-27 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/
//@version=5
strategy("B4100 - NW Trend Ribbon Strategy", overlay=true, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, commission_value = 0.02)
// === Optimized Functions ===
f_calculate_beta_kernel(length, alpha, beta) =>
kernel = array.new_float(length, 0)
sum = 0.0
for i = 0 to length - 1
x = i / (length - 1)
w = math.pow(x, alpha - 1) * math.pow(1 - x, beta - 1)
array.set(kernel, i, w)
sum += w
for i = 0 to length - 1
array.set(kernel, i, array.get(kernel, i) / sum)
kernel
f_calculate_gaussian_kernel(length, bandwidth) =>
kernel = array.new_float(length, 0)
sum = 0.0
for i = 0 to length - 1
x = i / (length - 1)
w = math.exp(-0.5 * math.pow((x - 0.5) / bandwidth, 2))
array.set(kernel, i, w)
sum += w
for i = 0 to length - 1
array.set(kernel, i, array.get(kernel, i) / sum)
kernel
f_calculate_epanechnikov_kernel(length, bandwidth) =>
kernel = array.new_float(length, 0)
sum = 0.0
for i = 0 to length - 1
x = i / (length - 1)
w = math.max(0.0, 1 - math.pow((x - 0.5) / bandwidth, 2))
array.set(kernel, i, w)
sum += w
for i = 0 to length - 1
array.set(kernel, i, array.get(kernel, i) / sum)
kernel
f_apply_kernel_ma(src, kernel, length) =>
sum = 0.0
for i = 0 to length - 1
sum += src[i] * array.get(kernel, i)
sum
f_trend_strength(ma, length) =>
ts = ta.rsi(ma, length) / 100
ts
// === Inputs ===
src = input.source(close, title="Price Source", tooltip="Select the price data used for calculations. 'Close' is the most common, but you can also use 'Open', 'High', 'Low', 'HL2' (typical price), etc.")
// MA Parameters
maGroup = "Moving Average Settings"
maCrossoverGroup = "Moving Average Crossover Settings"
rsiFilterGroup = "RSI Filter Settings"
trendStrengthGroup = "Trend Strength Filter Settings"
trendConfirmGroup = "Trend Confirmation Settings"
trailingStopGroup = "Trailing Stop Settings"
atrTrailingStopGroup = "ATR Trailing Stop Settings"
atrTakeProfitGroup = "ATR Take Profit Settings"
hardStopGroup = "Hard Stop Loss Settings"
tradeDirectionGroup = "Trade Direction Control"
length1 = input.int(20, title="MA1 Length", minval=1, tooltip="Number of bars used to calculate the first Moving Average.", group=maGroup)
kernelType1 = input.string(title="MA1 Kernel Type", defval="Beta", options=["Beta", "Gaussian", "Epanechnikov"], tooltip="Select the type of smoothing kernel for MA1. 'Beta' allows for lag adjustment. 'Gaussian' and 'Epanechnikov' use a bandwidth.", group=maGroup)
alpha1 = input.float(3.0, title="MA1 Beta Kernel +Lag", minval=1, maxval=10, tooltip="For Beta kernel only: Higher values increase *positive* lag (MA reacts *slower* to price increases).", group=maGroup)
beta1 = input.float(3.0, title="MA1 Beta Kernel -Lag", minval=1, maxval=10, tooltip="For Beta kernel only: Higher values increase *negative* lag (MA reacts *slower* to price decreases).", group=maGroup)
bandwidth1 = input.float(0.3, title="MA1 Bandwidth", minval=0.1, maxval=10.0, tooltip="For Gaussian/Epanechnikov kernels: Smaller values create a *tighter* fit to the price (more sensitive). Larger values create a *smoother*, less sensitive MA.", group=maGroup)
length2 = input.int(100, title="MA2 Length", minval=1, tooltip="Number of bars for the second Moving Average.", group=maGroup)
kernelType2 = input.string(title="MA2 Kernel Type", defval="Gaussian", options=["Beta", "Gaussian", "Epanechnikov"], tooltip="Kernel type for MA2 (see MA1 Kernel Type for details).", group=maGroup)
alpha2 = input.float(3.0, title="MA2 Beta Kernel +Lag", minval=1, maxval=10, tooltip="Beta kernel positive lag for MA2 (see MA1 Beta Kernel +Lag for details).", group=maGroup)
beta2 = input.float(3.0, title="MA2 Beta Kernel -Lag", minval=1, maxval=10, tooltip="Beta kernel negative lag for MA2 (see MA1 Beta Kernel -Lag for details).", group=maGroup)
bandwidth2 = input.float(0.3, title="MA2 Bandwidth", minval=0.1, maxval=10.0, tooltip="Bandwidth for MA2 (see MA1 Bandwidth for details).", group=maGroup)
length3 = input.int(150, title="MA3 Length", minval=1, tooltip="Number of bars for the third Moving Average.", group=maGroup)
kernelType3 = input.string(title="MA3 Kernel Type", defval="Epanechnikov", options=["Beta", "Gaussian", "Epanechnikov"], tooltip="Kernel type for MA3.", group=maGroup)
alpha3 = input.float(3.0, title="MA3 Beta Kernel +Lag", minval=1, maxval=10, tooltip="Beta kernel positive lag for MA3.", group=maGroup)
beta3 = input.float(3.0, title="MA3 Beta Kernel -Lag", minval=1, maxval=10, tooltip="Beta kernel negative lag for MA3.", group=maGroup)
bandwidth3 = input.float(0.3, title="MA3 Bandwidth", minval=0.1, maxval=10.0, tooltip="Bandwidth for MA3.", group=maGroup)
length4 = input.int(200, title="MA4 Length", minval=1, tooltip="Number of bars for the fourth Moving Average.", group=maGroup)
kernelType4 = input.string(title="MA4 Kernel Type", defval="Beta", options=["Beta", "Gaussian", "Epanechnikov"], tooltip="Kernel type for MA4.", group=maGroup)
alpha4 = input.float(3.0, title="MA4 Beta Kernel +Lag", minval=1, maxval=10, tooltip="Beta kernel positive lag for MA4.", group=maGroup)
beta4 = input.float(3.0, title="MA4 Beta Kernel -Lag", minval=1, maxval=10, tooltip="Beta kernel negative lag for MA4.", group=maGroup)
bandwidth4 = input.float(0.3, title="MA4 Bandwidth", minval=0.1, maxval=10.0, tooltip="Bandwidth for MA4.", group=maGroup)
length5 = input.int(250, title="MA5 Length", minval=1, tooltip="Number of bars for the fifth Moving Average.", group=maGroup)
kernelType5 = input.string(title="MA5 Kernel Type", defval="Gaussian", options=["Beta", "Gaussian", "Epanechnikov"], tooltip="Kernel type for MA5.", group=maGroup)
alpha5 = input.float(3.0, title="MA5 Beta Kernel +Lag", minval=1, maxval=10, tooltip="Beta kernel positive lag for MA5.", group=maGroup)
beta5 = input.float(3.0, title="MA5 Beta Kernel -Lag", minval=1, maxval=10, tooltip="Beta kernel negative lag for MA5.", group=maGroup)
bandwidth5 = input.float(0.3, title="MA5 Bandwidth", minval=0.1, maxval=10.0, tooltip="Bandwidth for MA5.", group=maGroup)
// Entry Logic
maCrossoversRequired = input.int(3, title="MA Crossovers Required", minval=1, maxval=5, tooltip="How many moving averages must cross each other to generate a potential trade signal. A higher number means a stronger (but potentially later) signal.", group=maCrossoverGroup)
useRsiFilter = input.bool(true, title="Use RSI Filter", tooltip="If enabled, the RSI must also be in overbought/oversold territory for a signal to be valid.", group=rsiFilterGroup)
rsiLength = input.int(7, title="RSI Length", minval=2, tooltip="Number of bars used to calculate the RSI.", group=rsiFilterGroup)
rsiOverbought = input.int(60, title="RSI Overbought", minval=50, maxval=100, tooltip="RSI level considered overbought (for short entries).", group=rsiFilterGroup)
rsiOversold = input.int(40, title="RSI Oversold", minval=0, maxval=50, tooltip="RSI level considered oversold (for long entries).", group=rsiFilterGroup)
// Trend Strength Filter
useTrendStrengthFilter = input.bool(true, title="Use Trend Strength Filter", tooltip="If enabled, the trend strength (measured by the RSI of a selected MA) must be above/below a threshold.", group=trendStrengthGroup)
trendStrengthLength = input.int(7, title="Trend Strength Length", minval=1, tooltip="Number of bars for the trend strength calculation (RSI of the selected MA).", group=trendStrengthGroup)
trendStrengthMa = input.int(1, title="Trend Strength MA", minval=1, maxval=5, tooltip="Which moving average (1-5) to use for calculating trend strength. 1 = MA1, 2 = MA2, etc.", group=trendStrengthGroup)
minTrendStrength = input.float(0.5, title="Min Trend Strength (Longs)", minval=0.0, maxval=1.0, step=0.01, tooltip="Minimum trend strength (0.0 - 1.0) required for long entries. 0.5 means the selected MA's RSI must be above 50.", group=trendStrengthGroup)
maxTrendStrength = input.float(0.5, title="Max Trend Strength (Shorts)", minval=0.0, maxval=1.0, step=0.01, tooltip="Maximum trend strength (0.0 - 1.0) required for short entries. 0.5 means the selected MA's RSI must be below 50.", group=trendStrengthGroup)
// Trend Confirmation
trendConfirmationPeriod = input.int(4, title="Trend Confirmation Period", minval=1, tooltip="Number of consecutive bars the entry conditions must be met before a trade is taken. This helps filter out false signals.", group=trendConfirmGroup)
// Exit Logic
useTrailingStop = input.bool(true, title="Use Percentage Trailing Stop", tooltip="Enable a percentage-based trailing stop loss.", group=trailingStopGroup)
trailingStopActivationPercent = input.float(2.0, title="Activation (%)", minval=0.1, step=0.1, tooltip="Percentage above/below the entry price at which the trailing stop activates.", group=trailingStopGroup) / 100
trailingStopOffsetPercent = input.float(1.0, title="Offset (%)", minval=0.1, step=0.1, tooltip="Percentage offset from the highest/lowest price reached since entry. This determines how tightly the stop trails the price.", group=trailingStopGroup) / 100
useAtrTrailingStop = input.bool(true, title="Use ATR Trailing Stop", tooltip="Enable a trailing stop based on the Average True Range (ATR).", group=atrTrailingStopGroup)
atrTrailingStopLength = input.int(1, title="ATR Length", minval=1, tooltip="Number of bars used to calculate the ATR.", group=atrTrailingStopGroup)
atrTrailingStopMult = input.float(200.0, title="ATR Multiplier", minval=0.1, tooltip="Multiplier for the ATR value. A larger multiplier creates a wider stop.", group=atrTrailingStopGroup)
useAtrTakeProfit = input.bool(false, title="Use ATR Take Profit", tooltip="Enable a take profit level based on the Average True Range (ATR).", group=atrTakeProfitGroup)
atrTakeProfitLength = input.int(14, title="ATR Length", minval=1, tooltip="Number of bars used to calculate the ATR for take profit.", group=atrTakeProfitGroup)
atrTakeProfitMultiplier = input.float(3.0, title="ATR Multiplier", minval=0.1, tooltip="Multiplier for the ATR value. A larger multiplier sets a further take profit target.", group=atrTakeProfitGroup)
useHardStopLoss = input.bool(false, title="Use Hard Stop Loss", tooltip="Enable a fixed stop loss.", group=hardStopGroup)
hardStopLossPercent = input.float(0.0, title="Hard Stop Loss (%)", minval=0.0, step=0.1, tooltip="Percentage below (long) or above (short) the entry price for the hard stop loss.", group=hardStopGroup) / 100
useAtrHardStopLoss = input.bool(false, title="Use ATR Hard Stop Loss", tooltip="Use ATR to calculate hard stop loss", group=hardStopGroup)
atrHardStopLossLength = input.int(14, title="ATR Hard Stop Loss Length", minval=1, tooltip="Length of the ATR for the hard stop loss", group=hardStopGroup)
atrHardStopLossMult = input.float(1.5, title="ATR Hard Stop Loss Multiplier", minval=0.1, tooltip="Multiplier of ATR for the hard stop loss", group=hardStopGroup)
// *** Trade Direction Control ***
enableLongs = input.bool(true, title="Enable Long Trades", group=tradeDirectionGroup)
enableShorts = input.bool(true, title="Enable Short Trades", group=tradeDirectionGroup)
// === Pre-calculate kernels (do this only once) ===
var kernel1 = array.new_float(length1, 0.0)
var kernel2 = array.new_float(length2, 0.0)
var kernel3 = array.new_float(length3, 0.0)
var kernel4 = array.new_float(length4, 0.0)
var kernel5 = array.new_float(length5, 0.0)
if barstate.isfirst
if kernelType1 == "Beta"
kernel1 := f_calculate_beta_kernel(length1, alpha1, beta1)
else if kernelType1 == "Gaussian"
kernel1 := f_calculate_gaussian_kernel(length1, bandwidth1)
else // Epanechnikov
kernel1 := f_calculate_epanechnikov_kernel(length1, bandwidth1)
if kernelType2 == "Beta"
kernel2 := f_calculate_beta_kernel(length2, alpha2, beta2)
else if kernelType2 == "Gaussian"
kernel2 := f_calculate_gaussian_kernel(length2, bandwidth2)
else // Epanechnikov
kernel2 := f_calculate_epanechnikov_kernel(length2, bandwidth2)
if kernelType3 == "Beta"
kernel3 := f_calculate_beta_kernel(length3, alpha3, beta3)
else if kernelType3 == "Gaussian"
kernel3 := f_calculate_gaussian_kernel(length3, bandwidth3)
else // Epanechnikov
kernel3 := f_calculate_epanechnikov_kernel(length3, bandwidth3)
if kernelType4 == "Beta"
kernel4 := f_calculate_beta_kernel(length4, alpha4, beta4)
else if kernelType4 == "Gaussian"
kernel4 := f_calculate_gaussian_kernel(length4, bandwidth4)
else // Epanechnikov
kernel4 := f_calculate_epanechnikov_kernel(length4, bandwidth4)
if kernelType5 == "Beta"
kernel5 := f_calculate_beta_kernel(length5, alpha5, beta5)
else if kernelType5 == "Gaussian"
kernel5 := f_calculate_gaussian_kernel(length5, bandwidth5)
else // Epanechnikov
kernel5 := f_calculate_epanechnikov_kernel(length5, bandwidth5)
// === Apply pre-calculated kernels to data ===
nw_ma1 = f_apply_kernel_ma(src, kernel1, length1)
nw_ma2 = f_apply_kernel_ma(src, kernel2, length2)
nw_ma3 = f_apply_kernel_ma(src, kernel3, length3)
nw_ma4 = f_apply_kernel_ma(src, kernel4, length4)
nw_ma5 = f_apply_kernel_ma(src, kernel5, length5)
// MA Array for easier iteration
ma_array = array.new_float(5)
array.set(ma_array, 0, nw_ma1)
array.set(ma_array, 1, nw_ma2)
array.set(ma_array, 2, nw_ma3)
array.set(ma_array, 3, nw_ma4)
array.set(ma_array, 4, nw_ma5)
// Calculate ATR values *unconditionally*
atrTrailingValue = ta.atr(atrTrailingStopLength)
atrTakeProfitValue = ta.atr(atrTakeProfitLength)
atrHardStopLossValue = ta.atr(atrHardStopLossLength)
// Calculate Trend Strength *unconditionally* (and only once)
trendStrengthValue = useTrendStrengthFilter ? f_trend_strength(array.get(ma_array, trendStrengthMa - 1), trendStrengthLength) : 0.0
// === Entry Logic ===
// MA Crossovers
longMaCrossovers = 0
shortMaCrossovers = 0
for i = 0 to 3
if array.get(ma_array, i) > array.get(ma_array, i + 1)
longMaCrossovers := longMaCrossovers + 1
if array.get(ma_array, i) < array.get(ma_array, i + 1)
shortMaCrossovers := shortMaCrossovers + 1
longCrossoverCondition = longMaCrossovers >= maCrossoversRequired
shortCrossoverCondition = shortMaCrossovers >= maCrossoversRequired
// RSI Filter
rsiValue = ta.rsi(src, rsiLength)
longRsiCondition = not useRsiFilter or (rsiValue < rsiOversold)
shortRsiCondition = not useRsiFilter or (rsiValue > rsiOverbought)
// Trend Strength Filter - Simplified Logic
longTrendStrengthCondition = not useTrendStrengthFilter or trendStrengthValue >= minTrendStrength
shortTrendStrengthCondition = not useTrendStrengthFilter or trendStrengthValue <= maxTrendStrength
// --- Trend Confirmation Logic ---
var int long_confirm_count = 0
var int short_confirm_count = 0
var bool confirmedLong = false
var bool confirmedShort = false
// Update confirmation counters
if longCrossoverCondition and longRsiCondition and longTrendStrengthCondition
long_confirm_count := long_confirm_count + 1
short_confirm_count := 0 // Reset opposite counter
else
long_confirm_count := 0
if shortCrossoverCondition and shortRsiCondition and shortTrendStrengthCondition
short_confirm_count := short_confirm_count + 1
long_confirm_count := 0 // Reset opposite counter
else
short_confirm_count := 0
// Check for confirmed trend
confirmedLong := long_confirm_count >= trendConfirmationPeriod
confirmedShort := short_confirm_count >= trendConfirmationPeriod
// Combined Entry Conditions (using confirmed trend)
longCondition = confirmedLong and enableLongs // Added trade direction check
shortCondition = confirmedShort and enableShorts // Added trade direction check
// === Exit Logic ===
var float longTrail = na
var float shortTrail = na
var float longTakeProfitPrice = na
var float shortTakeProfitPrice = na
var float longHardStopLossPrice = na
var float shortHardStopLossPrice = na
// Hard Stop Loss and Take Profit calculation on entry
if longCondition or shortCondition
// Calculate Hard Stop Loss
if useHardStopLoss
if useAtrHardStopLoss
longHardStopLossPrice := close - (atrHardStopLossValue * atrHardStopLossMult)
shortHardStopLossPrice := close + (atrHardStopLossValue * atrHardStopLossMult)
else
longHardStopLossPrice := close * (1 - hardStopLossPercent)
shortHardStopLossPrice := close * (1 + hardStopLossPercent)
else
longHardStopLossPrice := na
shortHardStopLossPrice := na
// Calculate Take Profit
if useAtrTakeProfit
longTakeProfitPrice := close + (atrTakeProfitValue * atrTakeProfitMultiplier)
shortTakeProfitPrice := close - (atrTakeProfitValue * atrTakeProfitMultiplier)
else
longTakeProfitPrice := na
shortTakeProfitPrice := na
// Trailing Stop Logic - updated for each bar
if strategy.position_size > 0
// Calculate trailing stop
float tempTrail = na
if useTrailingStop
if close > strategy.position_avg_price * (1 + trailingStopActivationPercent)
tempTrail := close * (1 - trailingStopOffsetPercent)
if na(longTrail) or tempTrail > longTrail
longTrail := tempTrail
if useAtrTrailingStop
float atrTrail = close - (atrTrailingValue * atrTrailingStopMult)
if na(longTrail) or atrTrail > longTrail
longTrail := atrTrail
if strategy.position_size < 0
// Calculate trailing stop
float tempTrail = na
if useTrailingStop
if close < strategy.position_avg_price * (1 - trailingStopActivationPercent)
tempTrail := close * (1 + trailingStopOffsetPercent)
if na(shortTrail) or tempTrail < shortTrail
shortTrail := tempTrail
if useAtrTrailingStop
float atrTrail = close + (atrTrailingValue * atrTrailingStopMult)
if na(shortTrail) or atrTrail < shortTrail
shortTrail := atrTrail
// === Strategy Execution ===
if longCondition
strategy.entry("Long", strategy.long)
longTrail := na // Reset on new entry
shortTrail := na // Reset on new entry
if shortCondition
strategy.entry("Short", strategy.short)
shortTrail := na // Reset on new entry
longTrail := na // Reset on new entry
// Unified exit logic with proper ordering
if strategy.position_size > 0
// Define effective stop level (combining hard stop and trailing stop)
float effectiveStopLevel = na
if not na(longHardStopLossPrice) and useHardStopLoss
effectiveStopLevel := longHardStopLossPrice
if not na(longTrail) and (useTrailingStop or useAtrTrailingStop)
if na(effectiveStopLevel) or longTrail > effectiveStopLevel
effectiveStopLevel := longTrail
// Combined exit strategy with proper parameters
strategy.exit("Long Exit", "Long",
limit = useAtrTakeProfit ? longTakeProfitPrice : na,
stop = effectiveStopLevel)
if strategy.position_size < 0
// Define effective stop level (combining hard stop and trailing stop)
float effectiveStopLevel = na
if not na(shortHardStopLossPrice) and useHardStopLoss
effectiveStopLevel := shortHardStopLossPrice
if not na(shortTrail) and (useTrailingStop or useAtrTrailingStop)
if na(effectiveStopLevel) or shortTrail < effectiveStopLevel
effectiveStopLevel := shortTrail
// Combined exit strategy with proper parameters
strategy.exit("Short Exit", "Short",
limit = useAtrTakeProfit ? shortTakeProfitPrice : na,
stop = effectiveStopLevel)
// === Plotting ===
plotColorMa1 = nw_ma1 > nw_ma1[1] ? color.rgb(100, 250, 120) : color.rgb(255, 100, 120)
plotColorMa2 = nw_ma2 > nw_ma2[1] ? color.rgb(100, 250, 120) : color.rgb(255, 100, 120)
plotColorMa3 = nw_ma3 > nw_ma3[1] ? color.rgb(100, 250, 120) : color.rgb(255, 100, 120)
plotColorMa4 = nw_ma4 > nw_ma4[1] ? color.rgb(100, 250, 120) : color.rgb(255, 100, 120)
plotColorMa5 = nw_ma5 > nw_ma5[1] ? color.rgb(100, 250, 120) : color.rgb(255, 100, 120)
plot(nw_ma1, title="NW MA 1", color=plotColorMa1, linewidth=2)
plot(nw_ma2, title="NW MA 2", color=plotColorMa2, linewidth=2)
plot(nw_ma3, title="NW MA 3", color=plotColorMa3, linewidth=2)
plot(nw_ma4, title="NW MA 4", color=plotColorMa4, linewidth=2)
plot(nw_ma5, title="NW MA 5", color=plotColorMa5, linewidth=2)