Hệ thống theo dõi xu hướng thích ứng dựa trên nhiều đường trung bình động được làm mịn của hạt nhân

MA RSI ATR MAs NW 趋势追踪 核平滑 滑动止损
Ngày tạo: 2025-03-28 15:13:28 sửa đổi lần cuối: 2025-03-28 15:13:28
sao chép: 2 Số nhấp chuột: 336
2
tập trung vào
319
Người theo dõi

Hệ thống theo dõi xu hướng thích ứng dựa trên nhiều đường trung bình động được làm mịn của hạt nhân Hệ thống theo dõi xu hướng thích ứng dựa trên nhiều đường trung bình động được làm mịn của hạt nhân

Tổng quan

Hệ thống theo dõi xu hướng tự điều chỉnh dựa trên nhiều đường trung bình phẳng là một chiến lược giao dịch định lượng cao cấp, nó tích hợp năm đường trung bình di chuyển tùy chỉnh, bộ lọc nhiều lớp và cơ chế xác nhận để xác định và tận dụng xu hướng thị trường liên tục. Chiến lược này sử dụng công nghệ phẳng hạt nhân thay vì đường trung bình di chuyển truyền thống, cung cấp hiệu quả phẳng linh hoạt hơn và khả năng tự điều chỉnh, có thể thích ứng với nhiều điều kiện thị trường và khung thời gian.

Các chức năng cốt lõi bao gồm: hiển thị xu hướng thị trường hiện tại bằng cách sử dụng “băng đồng bằng” bao gồm năm đường trung bình di chuyển; giảm tiếng ồn và tín hiệu giả mạo thông qua bộ lọc RSI, bộ lọc cường độ xu hướng và thời gian xác nhận xu hướng; chỉ kích hoạt tín hiệu nhập cảnh khi các điều kiện cụ thể được đáp ứng; và sử dụng nhiều lựa chọn thoát ra (như dừng theo dõi phần trăm, dừng theo dõi ATR, mục tiêu thu lợi nhuận ATR và dừng lỗ cứng) để quản lý rủi ro và bảo vệ lợi nhuận.

Nguyên tắc chiến lược

Lập luận cốt lõi của chiến lược này xoay quanh các thành phần quan trọng sau:

  1. Đường trung bình di chuyển phẳngChiến lược: Sử dụng kỹ thuật làm mịn hạt nhân thay cho trung bình di chuyển tiêu chuẩn, cung cấp hiệu ứng làm mịn linh hoạt và thích nghi hơn so với MA truyền thống. Hỗ trợ ba loại hạt nhân:

    • Beta Core: Lựa chọn mạnh nhất, cho phép thông quaalphabetaCác tham số được điều khiển độc lập theo độ trễ dương-lạc, khiến MA phản ứng với giá tăng và giảm khác nhau.
    • Ghosn: Tạo một hình tròn, tạo ra một hình tròn.bandwidthCác tham số điều khiển chiều rộng của đường cong hình chuông.
    • Hạt nhân Epanechnikov: tương tự như hạt nhân Gauss nhưng có hình dạng hơi khác, cũng được sử dụngbandwidthCác tham số.
  2. Dải trung bìnhNăm MA hình thành “băng đường trung bình” trên biểu đồ, sự sắp xếp và vị trí tương đối của chúng cung cấp một chỉ dẫn trực quan về cường độ và hướng của xu hướng.

  3. Xét nghiệm chéoChiến lược giám sát giao nhau giữa các MA liên tiếp trong dải đồng tuyến, người dùng có thể chỉ định số giao nhau cần thiết để tạo ra tín hiệu tiềm năng.

  4. Bộ lọc RSI: giúp tránh nhập cảnh trong trường hợp thị trường mở rộng quá mức. Khi nhập cảnh nhiều đầu, RSI phải thấp hơn mức bán quá mức; khi nhập cảnh trần, phải cao hơn mức mua quá mức.

  5. Bộ lọc cường độ xu hướng: Sử dụng RSI của một số đường trung bình di chuyển để đo cường độ của xu hướng, đảm bảo giao dịch theo hướng của xu hướng mạnh mẽ và đã được thiết lập.

  6. Xu hướng xác nhận: Để giảm thêm tín hiệu giả, yêu cầu các điều kiện nhập cảnh ((MA giao, RSI và cường độ xu hướng) phải đáp ứng một số lượng K-line được chỉ định liên tục trước khi thực sự kích hoạt giao dịch.

  7. Xuất khỏi logicChiến lược: ưu tiên rút ra theo thứ tự sau: Hết lỗ cứng, theo dõi dừng lỗ ((% hoặc dựa trên ATR) và thu lợi nhuận ((dựa trên ATR). Điều này đảm bảo giảm thiểu thiệt hại và bảo vệ lợi nhuận.

Lợi thế chiến lược

  1. Độ cao có thể tùy chỉnh làm mịn lõi: Sử dụng lõi mịn (đặc biệt là lõi Beta) cung cấp mức độ kiểm soát đáp ứng MA, điều này không có trong MA tiêu chuẩn. Điều này cho phép một cách tiếp cận tự động và tinh tế hơn đối với theo dõi xu hướng.

  2. Kết hợp giữa cường độ và xác nhận xu hướngTrình lọc cường độ xu hướng (RSI sử dụng MA) và kết hợp thời gian xác nhận xu hướng cung cấp cơ chế lọc mạnh mẽ, vượt quá chỉ đơn giản là đọc MA chéo hoặc RSI. Điều này giúp lọc xu hướng yếu và biến động.

  3. Lựa chọn thoát nhiều ưu tiên: Lập luận thoát của chiến lược rất phức tạp, cung cấp sự kết hợp giữa mức dừng cố định và động và mức lợi nhuận. Ưu tiên bảo đảm thoát bảo thủ nhất (đứng cứng) được kích hoạt đầu tiên, sau đó là theo dõi dừng và cuối cùng là mục tiêu lợi nhuận.

  4. Phân loại toàn bộ đầu vào: Tất cả các đầu vào được phân loại thành các nhóm về các khía cạnh cụ thể của chiến lược kiểm soát, người dùng có thể dễ dàng định vị và điều chỉnh đầu vào.

  5. Kiểm soát hướng giao dịchKhông giống như nhiều chiến lược khác, chiến lược này cho phép các giao dịch đa đầu và vô đầu được bật hoặc tắt một cách độc lập.

  6. Hệ thống xu hướng toàn diệnChỉ số này kết hợp nhiều khía cạnh cần thiết cho giao dịch: tín hiệu đầu vào, tính toán dừng lỗ, tính toán lợi nhuận.

Rủi ro chiến lược

  1. Thách thức tối ưu hóa tham sốVì chiến lược có rất nhiều tham số, có thể có nguy cơ quá phù hợp. Điều chỉnh tham số quá tinh tế có thể khiến chiến lược hoạt động tốt trong phản hồi, nhưng không hiệu quả trong giao dịch thực tế.

  2. Sự thay đổi xu hướng phản ứng chậm trễ: Mặc dù chiến lược được thiết kế để nhận diện xu hướng liên tục, nó có thể không phản ứng đủ nhanh khi thị trường đảo ngược đột ngột, dẫn đến một phần rút lui. Có thể cân bằng độ nhạy cảm với sự thay đổi xu hướng và khả năng lọc tiếng ồn bằng cách điều chỉnh chiều dài MA và tham số cốt lõi.

  3. MA giao âm giảLưu ý: Ngay cả khi có nhiều lớp lọc, tín hiệu giả vẫn có thể được tạo ra trong thị trường biến động. Lưu ý sử dụng chiến lược này trong thị trường xu hướng được xác định, hoặc tăng thời gian xác nhận xu hướng để giảm tín hiệu giả.

  4. Bắt đầu quá sớm: Trong thị trường biến động lớn, dừng có thể được kích hoạt quá sớm, dẫn đến việc bỏ lỡ sự điều chỉnh giá tiếp theo và phục hồi xu hướng. Bạn có thể xem xét dừng dựa trên ATR và điều chỉnh thích hợp để phù hợp với sự biến động của thị trường.

  5. Rủi ro của sự phức tạpSự phức tạp của các chính sách có thể làm cho việc khắc phục sự cố và giám sát thời gian thực trở nên khó khăn.

Hướng tối ưu hóa chiến lược

  1. Khả năng thích ứng khung thời gianCác chính sách hiện tại có thể được tối ưu hóa hơn nữa để nó có thể tự động điều chỉnh tham số dựa trên các khung thời gian khác nhau. Ví dụ, có thể thêm chức năng điều chỉnh tham số tự động dựa trên khung thời gian để chính sách hoạt động hiệu quả trên biểu đồ đường ngày, đường giờ hoặc đường phút.

  2. Kiểm tra môi trường thị trườngTăng cơ chế tự động phát hiện môi trường thị trường ((trend, interval hoặc biến động cao) và điều chỉnh các tham số giao dịch dựa trên kết quả phát hiện. Ví dụ: tăng cường độ lọc hoặc điều chỉnh mục tiêu lợi nhuận trong thị trường interval, nới lỏng điều kiện lọc trong thị trường xu hướng.

  3. Động lực RSI: Thiết kế RSI với ngưỡng mua bán động thay vì tĩnh, tự động điều chỉnh theo biến động thị trường gần đây. Điều này có thể cải thiện khả năng thích ứng của chiến lược trong các điều kiện thị trường khác nhau.

  4. Chỉ số biến động định lượng tích hợpTích hợp chiến lược với các chỉ số biến động (như Bollinger Bandwidth) để điều chỉnh mục tiêu dừng lỗ và lợi nhuận trong môi trường biến động cao, giảm nguy cơ bị trục xuất bởi xu hướng có hiệu quả.

  5. Xác nhận khung thời gian đa dạng: Thêm xác nhận xu hướng của khung thời gian cao hơn, đảm bảo hướng giao dịch phù hợp với xu hướng lớn hơn. Ví dụ, giao dịch chỉ khi xu hướng đường ngày và đường giờ phù hợp.

  6. Giám sát hiệu suất và thích ứngHệ thống giám sát thực tế về hiệu suất chiến lược, theo dõi các chỉ số như tỷ lệ thắng, tỷ lệ thua lỗ và rút lui tối đa, tự động điều chỉnh tham số hoặc tạm dừng giao dịch khi chỉ số hiệu suất giảm xuống dưới ngưỡng đặt trước.

  7. Tăng cường học máy: Khám phá các thuật toán học máy được tích hợp vào quá trình tối ưu hóa tham số, cho phép các chiến lược học được các tổ hợp tham số tốt nhất từ dữ liệu lịch sử và liên tục cải thiện khi dữ liệu mới tích lũy.

Tóm tắt

Hệ thống theo dõi xu hướng tự điều chỉnh dựa trên các đường trung bình đa phương tiện phẳng lõi là một công cụ theo dõi xu hướng mạnh mẽ và linh hoạt, kết hợp sự rõ ràng trực quan của các đường trung bình di chuyển với các bộ lọc và quản lý rủi ro cao cấp của phẳng lõi, RSI, cường độ xu hướng và nhiều tùy chọn thoát. Nó được thiết kế cho các nhà giao dịch muốn có các công cụ có thể tùy chỉnh và mạnh mẽ để xác định và giao dịch xu hướng thị trường liên tục.

Ưu điểm lớn nhất của chiến lược này là khả năng tùy biến và thích ứng cao, cho phép nó thích ứng với các điều kiện thị trường khác nhau. Thông qua công nghệ làm mịn hạt nhân, nó có thể cung cấp kiểm soát chi tiết hơn so với trung bình di chuyển truyền thống, và các cơ chế lọc và xác nhận nhiều lớp giúp giảm tín hiệu giả.

Tuy nhiên, người sử dụng nên chú ý đến những thách thức của việc tối ưu hóa các tham số, tránh quá phù hợp và điều chỉnh chiến lược theo môi trường thị trường cụ thể. Phản hồi đầy đủ và thử nghiệm về phía trước được khuyến khích để đảm bảo rằng chiến lược có thể hoạt động ổn định trong nhiều điều kiện thị trường khác nhau. Với việc đánh giá và tối ưu hóa thường xuyên, chiến lược này có tiềm năng trở thành một tài sản quý giá trong hộp công cụ của các nhà giao dịch xu hướng thành công.

Mã nguồn chiến lược
/*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)