カーネル平滑化複数移動平均に基づく適応型トレンド追跡システム

MA RSI ATR MAs NW 趋势追踪 核平滑 滑动止损
作成日: 2025-03-28 15:13:28 最終変更日: 2025-03-28 15:13:28
コピー: 2 クリック数: 336
2
フォロー
319
フォロワー

カーネル平滑化複数移動平均に基づく適応型トレンド追跡システム カーネル平滑化複数移動平均に基づく適応型トレンド追跡システム

概要

核平準多重平均線に基づく自己適応トレンドトラッキングシステムは,五つのカスタム移動平均線,多層のフィルターと確認機構を統合した高度な量化取引戦略である.この戦略は,継続的な市場トレンドを認識し,利用するために使用される.従来の移動平均線ではなく,核平準技術の採用により,より柔軟な平準効果と自己適応性が提供され,さまざまな市場条件と時間枠に対応できます.

核心機能には,5つの移動平均を構成する”均線帯”のビジュアル化により,現在の市場トレンドを表す;RSIフィルター,トレンド強度フィルター,トレンド確認期を通じて,ノイズと偽信号を減らす;特定の条件が満たされた場合にのみ入場シグナルをトリガーする;そして,リスク管理と利益保護のために,複数の退出オプション (パーセントトラッキングストップ,ATRトラッキングストップ,ATR利益目標と硬性ストップなど) を採用する.

戦略原則

この戦略の核心的な論理は,以下の重要な要素を中心に展開されています.

  1. 核平滑移動平均戦略: 標準移動平均の代わりに核平準化技術を使用し,従来のMAよりも柔軟で自律的な平準化効果を提供します. 3種類の核をサポートします.

    • ベータ・コア:最も強力なオプションで,alphaそしてbetaパラメータ独立制御の正負の遅滞により,MAは価格上昇と下落に対して異なる速度で反応する.
    • ゲス核: 鐘形加重を創造する.bandwidthパラメータは,鐘形曲線の幅を制御する。
    • エパネチニコフ・コア:ゴス・コアと似ていますが,形状は少し違って,同じ使用法です.bandwidthパラメータ
  2. 均線帯: 5つのMAは,グラフ上の”均等線帯”を形成し,その配列と相対的な位置は,傾向の強さと方向の視覚的な指示を提供します.

  3. クロステスト策略: 均線帯の連続MAの間の交差を監視する.ユーザは潜在信号を生成するために必要な交差数を指定できる.

  4. RSIフィルター: 市場の過伸の状況で入場を避けるのに役立つ. 多頭入場の場合,RSIは超売りレベルより低ければならず,空頭入場の場合,超買いレベルより高ければならない.

  5. トレンド強度フィルター: トレンドの強さを測定するために移動平均のRSIを使用し,強力な,確立されたトレンドの方向で取引することを保証します.

  6. トレンド確認偽信号をさらに減らすために,入場条件 (MA交差,RSI,トレンド強さ) が実際に取引を誘発する前に指定された数のK線を連続的に満たさなければならないことを要求します.

  7. ロジックからの脱出戦略は,次の順序で退出を優先します:ハードルストップ,トラッキングストップ ((パーセントまたはATRベースの) と利益 ((ATRベースの). これは,損失を最小化し,利益を保護することを保証します.

戦略的優位性

  1. 高度調整可能な核平滑: 核の平滑化 (特にベータ核) を使用すると,標準MAでは使用できないMAへの反応性の制御レベルが提供されます.これは,トレンド追跡に対してより自律的で微妙なアプローチを可能にします.

  2. 傾向の強さと確認:トレンド強度フィルター ((MAのRSIを使用する) とトレンド確認期の組み合わせは,単純なMA交差またはRSIの読みを超えた強力なフィルタリング機構を提供します.これは弱いトレンドと振動状態をフィルタリングするのに役立ちます.

  3. 複数の優先度で退出するオプション戦略の退出論理は非常に複雑で,固定および動的なストップと利益のレベルを組み合わせている.優先順位は,最も保守的な退出を確実にする (硬性ストップ) を最初に誘発し,次にストップを追跡し,最後に利益の目標を設定する.

  4. 全体の入力グループ化: すべての入力が制御策の特定の側面のグループに分類され,ユーザは簡単に入力を素早く位置付け,調整することができます.

  5. 取引方向制御この戦略は,多くの戦略とは異なり,多頭と空頭取引を独立に有効または無効にします.

  6. 全面的なトレンドシステムこの指標は,入場シグナル,ストップ・ロスの計算,利益の計算など,取引に必要な複数の側面を組み合わせています.

戦略リスク

  1. パラメータ最適化の課題戦略には多くのパラメータがあるため,過度に適合するリスクがある.パラメータを細かく調整すると,戦略が反測でうまく機能するが,実際の取引では機能しない可能性があります.パラメータの設定が普遍的であることを確認するために,健全なクロス検証とサンプル外テストを行うことをお勧めします.

  2. トレンドの変化への反応の遅延: 策略は継続的なトレンドを識別することを目的としているが,市場が急激に反転すると,反応が迅速に不足し,部分的な撤退を引き起こす可能性がある.MAの長さと核パラメータを調整することによって,トレンドの変化に対する感受性とノイズに対するフィルタリング能力をバランスすることができます.

  3. MA 交差偽信号: 複数のフィルターがあるとしても,揺れ動いている市場では偽信号が生じる可能性があります. この戦略は,特定されたトレンド市場で使用するか,偽信号を減らすためにトレンド確認期間を延長することをお勧めします.

  4. 早期発射による障害:大波動の市場では,ストップが過早に誘発され,その後の価格の調整とトレンドの回復が逃れることがある.ATRに基づくストップを考慮し,市場の波動に適した調整を行うことができます.

  5. 複雑性のリスク: 策略の複雑さは,故障排除とリアルタイム監視を困難にすることがあります. 簡単な構成から始まり,段階的に複雑な機能を追加して,各コンポーネントの役割を十分に理解することを保証することをお勧めします.

戦略最適化の方向性

  1. タイムフレームの適応性: 現在のポリシーをさらに最適化して,異なるタイムフレームに応じてパラメータを自動的に調整できるようにする.例えば,タイムフレームに基づく自動パラメータ調整機能を追加して,日線,時線,または分線グラフで戦略を効果的に動作させることができる.

  2. 市場環境調査: 市場環境の自動検知メカニズムを追加し,検知結果に応じて取引パラメータを調整する.例えば,区間市場でフィルタリングの強さを増やしたり,収益目標を調整したり,トレンド市場でフィルタリング条件を緩和したりする.

  3. RSIの動的下落について: RSIの超買超売の値を静的ではなく動的に設計し,近年の市場変動に応じて自動的に調整する.これは,異なる市場条件下で戦略の適応性を向上させる.

  4. 統合された量的な波動指標戦略と波動率指標 (例えばボリンジャー・バンド) を統合して,高波動性のある環境でストップと利益の目標を調整し,有効なトレンドを出するリスクを軽減します.

  5. 複数時間枠確認: より高い時間枠のトレンド確認を追加し,取引方向がより大きなトレンドと一致することを確認します. 例えば,当日の日線トレンドが時線トレンドの方向と一致するときにのみ取引します.

  6. 性能モニタリングと自己適応: 戦略のパフォーマンスをリアルタイムで監視するシステム,勝利率,勝敗率,最大撤退などの指標を追跡し,パフォーマンス指標がデフォルトの値以下に低下すると,パラメータを自動的に調整するか,取引を一時停止する.

  7. 機械学習の強化: 機械学習アルゴリズムをパラメータ最適化プロセスに統合して,戦略が歴史的なデータから最適なパラメータの組み合わせを学び,新しいデータ蓄積とともに改善できるようにする.

要約する

核平滑多重平均線に基づく自適化トレンド追跡システムは,移動平均線帯の視覚的明晰さと核平滑,RSI,トレンド強度,複数の退出オプションの高度なフィルタリングとリスク管理能力を組み合わせた強力な柔軟なトレンド追跡ツールです.

この戦略の最大の利点は,高度なカスタマイズ性と自己適応性であり,さまざまな市場条件に適応できるようにするものである.核平滑技術によって,従来の移動平均よりもより細かい制御を提供でき,複数のフィルタリングと確認メカニズムが偽信号を減らすのに役立ちます.同時に,統合されたリスク管理システムは,損失を最小限に保ち,利益を保護するために,複数の退出戦略を提供します.

しかし,ユーザーはパラメータの最適化の課題に注意し,過度に適合を避け,特定の市場環境に応じて戦略を調整する必要があります.十分な反省と前向きなテストが,様々な市場条件下で戦略が安定して動作することを保証することを推奨しています.定期的な評価と最適化により,この戦略は成功するトレンドトレーダーのツールボックスに貴重な資産になる可能性があります.

ストラテジーソースコード
/*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)