Sistema de rastreamento de tendências adaptável baseado em médias móveis múltiplas suavizadas pelo kernel

MA RSI ATR MAs NW 趋势追踪 核平滑 滑动止损
Data de criação: 2025-03-28 15:13:28 última modificação: 2025-03-28 15:13:28
cópia: 2 Cliques: 336
2
focar em
319
Seguidores

Sistema de rastreamento de tendências adaptável baseado em médias móveis múltiplas suavizadas pelo kernel Sistema de rastreamento de tendências adaptável baseado em médias móveis múltiplas suavizadas pelo kernel

Visão geral

Este sistema de rastreamento de tendências adaptativo baseado em múltiplos médios de nivelamento nuclear é uma estratégia de negociação de alta qualidade que integra cinco médias móveis personalizadas, filtros em várias camadas e mecanismos de confirmação para identificar e aproveitar as tendências de mercado contínuas. A estratégia usa a tecnologia de nivelamento nuclear em vez das médias móveis tradicionais, oferecendo um efeito de nivelamento mais flexível e capacidade de adaptação, capaz de se adaptar a várias condições de mercado e prazos de tempo.

As funções principais incluem: a visualização da tendência atual do mercado usando uma “banda de linha uniforme” composta por cinco médias móveis; a redução de ruído e falsos sinais por meio de filtros RSI, filtros de intensidade de tendência e período de confirmação de tendência; o disparo de sinais de entrada somente quando determinadas condições são atendidas; e a administração de riscos e proteção de lucros com várias opções de saída (como parada de percentual de perda, parada de perda de ATR, objetivo de ganho de ATR e parada de perda de dureza).

Princípio da estratégia

A lógica central da estratégia gira em torno dos seguintes componentes-chave:

  1. Média móvel de deslizamento nuclearA estratégia usa a técnica de suavização de núcleos para substituir a média móvel padrão, oferecendo um efeito de suavização mais flexível e adaptável do que a MA tradicional. Suporta três tipos de núcleos:

    • Núcleo Beta: a opção mais poderosa, permitindo a passagemalphaebetaOs parâmetros são controlados de forma independente, com um atraso positivo e negativo, permitindo que a MA reaja de forma diferente aos aumentos e baixas dos preços.
    • Ghosn: Criar uma gravidade em forma de sino.bandwidthOs parâmetros controlam a largura da curva de sino.
    • Núcleo Epanechnikov: semelhante ao núcleo de Gauss, mas de forma ligeiramente diferente, também usadobandwidthParâmetros
  2. Faixa de equilíbrioOs cinco MA formam uma “banda de linha média” no gráfico, cuja disposição e posição relativa fornece uma indicação visual da intensidade e direção da tendência.

  3. Testes cruzados: estratégia de monitoramento de cruzamentos entre MAs contínuos na faixa de equilíbrio, o usuário pode especificar o número de cruzamentos necessários para gerar um sinal potencial.

  4. Filtro RSIAjuda a evitar a entrada em caso de sobre-extensão do mercado. Quando a entrada é múltipla, o RSI deve estar abaixo do nível de supervenda; Quando a entrada é vazia, deve estar acima do nível de supercompra.

  5. Filtros de intensidade de tendênciaO RSI usa uma média móvel para medir a intensidade da tendência, garantindo a negociação na direção de uma tendência forte e estabelecida.

  6. Confirmação da tendênciaPara reduzir ainda mais os falsos sinais, os requisitos de entrada (MA cruzado, RSI e intensidade da tendência) devem satisfazer um número especificado de linhas K consecutivamente antes de o negócio ser realmente acionado.

  7. Sair da lógicaA estratégia de priorizar a saída na seguinte ordem: Hard Stop Loss, Tracking Stop Loss (porcentagem ou baseado no ATR) e Profit (baseado no ATR). Isso garante que as perdas sejam minimizadas e os lucros sejam protegidos.

Vantagens estratégicas

  1. Alturas personalizadas de suavização do núcleoO uso de núcleos suaves (especialmente núcleos beta) fornece níveis de controle de resposta à MA, que não são utilizáveis na MA padrão. Isso permite uma abordagem mais adaptativa e minuciosa para o rastreamento de tendências.

  2. Combinação de Força e Confirmação de TendênciasA combinação de um filtro de força de tendência (RSI com MA) e um período de confirmação de tendência fornece um poderoso mecanismo de filtragem que vai além de uma simples leitura de MA cruzado ou RSI. Isso ajuda a filtrar tendências fracas e oscilações.

  3. Opções de desativação de prioridade múltiplaA lógica de saída da estratégia é muito complexa, oferecendo uma combinação de stop loss fixo e dinâmico, bem como níveis de ganho. A prioridade é garantir que a saída mais conservadora (stop loss de dureza) seja a primeira a ser acionada, seguida de um stop loss de rastreamento e, finalmente, um objetivo de ganho.

  4. Agrupamento de todas as entradasTodos os inputs foram classificados em grupos de aspectos específicos da estratégia de controle, permitindo que o usuário localize e ajuste rapidamente os inputs.

  5. Controle de direção de transaçãoA estratégia permite ativar ou desativar independentemente a operação multihead e a operação no-head, ao contrário de muitas estratégias.

  6. Sistema de tendências globaisO indicador combina vários aspectos necessários para a negociação: sinal de entrada, cálculo de stop-loss, cálculo de ganhos.

Risco estratégico

  1. Desafios de optimização de parâmetrosUma estratégia com um grande número de parâmetros pode correr o risco de overfitting. Ajustar os parâmetros com muita precisão pode fazer com que a estratégia se comporte bem no feedback, mas falhe na negociação real. Recomenda-se uma robusta verificação cruzada e testes fora de amostra para garantir a universalidade dos parâmetros.

  2. Mudança de tendência, atraso na resposta: Embora a estratégia seja destinada a identificar tendências contínuas, pode não reagir com rapidez suficiente em caso de uma reversão acentuada do mercado, resultando em uma retirada parcial. A sensibilidade às mudanças de tendência e a capacidade de filtragem de ruído podem ser equilibradas ajustando o comprimento do MA e os parâmetros principais.

  3. MA cruzado falsoMesmo com filtragem em várias camadas, pode haver falsos sinais em mercados de turbulência. Recomenda-se usar esta estratégia em mercados de tendência identificados, ou aumentar o período de confirmação de tendência para reduzir os falsos sinais.

  4. Determinação de acidentes prematuros: Em mercados de grande volatilidade, o stop loss pode ser desencadeado prematuramente, resultando em perdas de subsequentes reajustes de preços e retomadas de tendências. O stop loss baseado no ATR pode ser considerado e adequadamente ajustado para se adaptar à volatilidade do mercado.

  5. Risco de complexidadeA complexidade das estratégias pode dificultar a detecção de falhas e o monitoramento em tempo real. Recomenda-se começar com uma configuração simples e adicionar funções complexas gradualmente, garantindo a plena compreensão do papel de cada componente.

Direção de otimização da estratégia

  1. Adaptabilidade do quadro de tempoA estratégia atual pode ser ainda mais otimizada, permitindo que ela ajuste automaticamente os parâmetros de acordo com diferentes prazos. Por exemplo, pode ser adicionado um recurso de ajuste automático de parâmetros baseado em prazos, permitindo que a estratégia funcione efetivamente em gráficos de linha do dia, linha da hora ou linha do minuto.

  2. Avaliação do cenário de mercadoAumentar o mecanismo de detecção automática do ambiente de mercado (trend, intervalo ou alta volatilidade) e ajustar os parâmetros de negociação de acordo com os resultados detectados. Por exemplo, aumentar a intensidade de filtragem em mercados intermédios ou ajustar os objetivos de lucro, relaxar as condições de filtragem em mercados de tendência.

  3. Dinâmico RSIO RSI foi concebido para ser dinâmico e não estático, ajustando-se automaticamente à volatilidade recente do mercado. Isso pode melhorar a adaptabilidade da estratégia em diferentes condições de mercado.

  4. Indicador de flutuação quantitativa integradoIntegração de estratégias com indicadores de volatilidade (como a banda de Bollinger) para ajustar os objetivos de stop loss e gain em ambientes de alta volatilidade, reduzindo o risco de ser excluído de uma tendência efetiva.

  5. Confirmação do Multi-Tempos: Adicionar a confirmação de tendências de um quadro de tempo mais alto para garantir que a direção da negociação esteja de acordo com a tendência maior. Por exemplo, só é possível negociar quando a tendência da linha do dia coincide com a tendência da linha da hora.

  6. Monitoramento de desempenho e adaptaçãoO sistema de monitoramento em tempo real do desempenho da estratégia, acompanhando indicadores como taxa de vitória, taxa de ganho e perda e retração máxima, ajusta automaticamente os parâmetros ou suspende a negociação quando os indicadores de desempenho caem abaixo do limiar predefinido.

  7. Aprendizagem de máquinaExplorar a integração de algoritmos de aprendizagem de máquina no processo de otimização de parâmetros, permitindo que as estratégias aprendam o melhor conjunto de parâmetros de dados históricos e melhorem continuamente com a acumulação de novos dados.

Resumir

O sistema de rastreamento de tendências adaptativo baseado em uma linha de média múltipla de nivelação de núcleo é uma ferramenta de rastreamento de tendências poderosa e flexível, que combina a clareza visual da banda de médias móveis com a capacidade de filtragem e gerenciamento de risco avançadas de nivelação de núcleo, RSI, intensidade da tendência e várias opções de saída. Ele foi projetado para comerciantes que desejam ter ferramentas personalizáveis e poderosas para identificar e negociar tendências de mercado contínuas.

A maior vantagem da estratégia reside na sua alta customizabilidade e adaptabilidade, permitindo-lhe adaptar-se a uma variedade de condições de mercado. Através da tecnologia de suavização nuclear, ela pode oferecer um controle mais fino do que a média móvel tradicional, enquanto os mecanismos de filtragem e confirmação em camadas múltiplas ajudam a reduzir os falsos sinais.

No entanto, os usuários devem estar atentos aos desafios de otimização de parâmetros, evitar o overfitting e ajustar a estratégia de acordo com o ambiente de mercado específico. Recomenda-se um bom teste de retrospectiva e prospectiva para garantir que a estratégia funcione de forma robusta em várias condições de mercado. Com avaliação e otimização regulares, a estratégia tem o potencial de ser um valioso ativo na caixa de ferramentas do trader de tendências bem sucedido.

Código-fonte da estratégia
/*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)