
Sistem pengesanan trend yang beradaptasi yang berasaskan pelbagai rata-rata penyelarasan teras adalah strategi perdagangan kuantitatif yang canggih yang menggabungkan lima rata-rata bergerak tersuai, penapis berlapis, dan mekanisme pengesahan untuk mengenal pasti dan memanfaatkan trend pasaran yang berterusan. Strategi ini menggunakan teknologi penyelarasan teras dan bukan rata-rata bergerak tradisional, memberikan kesan penyelarasan yang lebih fleksibel dan kebolehan menyesuaikan diri dengan pelbagai keadaan pasaran dan jangka masa.
Fungsi teras termasuk: menggambarkan trend pasaran semasa menggunakan visual “band rata-rata” yang terdiri daripada lima rata-rata bergerak; mengurangkan bunyi dan isyarat palsu melalui penapis RSI, penapis kekuatan trend dan tempoh pengesahan trend; mencetuskan isyarat masuk hanya apabila syarat tertentu dipenuhi; dan menggunakan pelbagai pilihan keluar (seperti peratusan tracking stop loss, ATR tracking stop loss, ATR profit target dan stop loss keras) untuk menguruskan risiko dan melindungi keuntungan.
Strategi ini berpusat pada komponen-komponen utama:
Rata-rata bergerak rata-rataStrategi: Menggunakan teknik penyejukan teras sebagai pengganti purata bergerak standard, memberikan kesan penyejukan yang lebih fleksibel dan menyesuaikan diri daripada MA tradisional. Ia menyokong tiga jenis teras:
alphadanbetaParameter kawalan bebas positif-negatif yang menyebabkan MA bertindak balas secara berbeza terhadap kenaikan dan penurunan harga.bandwidthParameter yang mengawal lebar bel.bandwidthParameterGaris rata: Lima MA membentuk “band rata-rata” pada carta, susunan dan kedudukan relatifnya memberikan petunjuk visual mengenai kekuatan dan arah trend.
Pemeriksaan silangStrategi memantau persilangan antara MA berturut-turut dalam jalur rata, pengguna boleh menentukan jumlah persilangan yang diperlukan untuk menghasilkan isyarat berpotensi.
Penapis RSI: membantu mengelakkan masuk dalam keadaan pasaran yang terlalu panjang. Apabila masuk dengan banyak mata, RSI mestilah di bawah tahap jual beli; apabila masuk dengan kepala kosong, mestilah di atas tahap beli beli.
Penapis kekuatan trend: Menggunakan RSI pada purata bergerak untuk mengukur kekuatan trend, memastikan perdagangan di arah trend yang kuat dan mapan.
Penegasan trendUntuk mengurangkan lebih banyak isyarat palsu, syarat kemasukan (MA crossover, RSI, dan kekuatan trend) mesti dipenuhi secara berturut-turut dengan jumlah garis K yang ditetapkan sebelum perdagangan sebenarnya dicetuskan.
Keluar dari logikStrategi memberi keutamaan kepada penarikan diri mengikut urutan berikut: hentikan kerugian keras, hentikan kerugian yang dikesan (peratusan atau berdasarkan ATR) dan keuntungan (berdasarkan ATR). Ini memastikan kerugian diminimumkan dan melindungi keuntungan.
Ketinggian yang boleh disesuaikan keratanPenggunaan kerangka yang halus (terutamanya kerangka beta) memberikan tahap kawalan terhadap tindak balas MA, yang tidak boleh digunakan dalam MA standard. Ia membolehkan pendekatan yang lebih serasi dan halus untuk mengesan trend.
Gabungan antara kekuatan dan pengesahan trendFilter kekuatan trend (RSI menggunakan MA) dan gabungan tempoh pengesahan trend menyediakan mekanisme penapisan yang kuat, melampaui bacaan simpulan MA atau RSI. Ini membantu menapis trend lemah dan pergerakan goyah.
Pilihan keluar pelbagai keutamaan: Logik keluar dari strategi sangat rumit, menawarkan gabungan stop loss tetap dan dinamik serta tahap keuntungan. Keutamaan memastikan keluar paling konservatif (hardness stop loss) yang pertama dicetuskan, diikuti oleh tracking stop loss, dan akhirnya keuntungan.
Pengelompokan input keseluruhan: Semua input dikelaskan ke dalam kumpulan untuk aspek tertentu dalam strategi kawalan, pengguna dapat dengan mudah dan cepat mencari dan menyesuaikan input.
Kawalan arah perdaganganBerbeza dengan banyak strategi, strategi ini membolehkan anda secara bebas mengaktifkan atau menonaktifkan perdagangan multihead dan kosong.
Sistem Trend KeseluruhanIndeks ini menggabungkan pelbagai aspek yang diperlukan untuk berdagang: isyarat masuk, pengiraan stop loss, pengiraan keuntungan.
Cabaran pengoptimuman parameterOleh kerana strategi mempunyai banyak parameter, ia mungkin menghadapi risiko overfitting. Menyesuaikan parameter yang terlalu halus boleh menyebabkan strategi berfungsi dengan baik dalam pengujian semula, tetapi tidak berfungsi dalam perdagangan sebenar.
Tanggapan lambat terhadap perubahan trendWalaupun strategi ini bertujuan untuk mengenal pasti trend yang berterusan, ia mungkin tidak bertindak balas dengan cepat apabila pasaran berbalik secara mendadak, yang menyebabkan penarikan balik sebahagiannya. Sensitiviti terhadap perubahan trend dan kebolehan menyaring kebisingan boleh diseimbangkan dengan menyesuaikan panjang MA dan parameter teras.
MA silang isyarat palsuWalaupun terdapat pelbagai lapisan penapisan, isyarat palsu masih boleh dihasilkan dalam pasaran yang bergolak. Ia disyorkan untuk menggunakan strategi ini dalam pasaran trend yang ditetapkan, atau meningkatkan tempoh pengesahan trend untuk mengurangkan isyarat palsu.
Hentikan Kerosakan Terlalu Awal: Dalam pasaran yang bergelombang besar, hentian mungkin dicetuskan terlalu awal, menyebabkan penurunan harga dan pemulihan trend yang tidak diikuti. Hentian berdasarkan ATR boleh dipertimbangkan dan disesuaikan dengan keadaan pasaran yang bergelombang.
Kompleksiti risikoKompleksiti strategi boleh membuat pemecahan masalah dan pemantauan masa nyata menjadi sukar. Adalah disyorkan untuk memulakan dengan konfigurasi mudah, menambah fungsi yang rumit secara beransur-ansur, memastikan peranan setiap komponen difahami sepenuhnya.
Kerangka masa yang sesuaiStrategi semasa boleh dioptimumkan lebih jauh untuk menyesuaikan parameter secara automatik mengikut bingkai masa yang berbeza. Sebagai contoh, fungsi penyesuaian parameter automatik berdasarkan bingkai masa boleh ditambahkan, menjadikan strategi berfungsi dengan baik pada grafik garis hari, garis jam atau garis minit.
Pemeriksaan persekitaran pasaran: Menambah mekanisme pengesanan automatik keadaan pasaran ((trend, interval atau turun naik yang tinggi) dan menyesuaikan parameter perdagangan berdasarkan hasil pengesanan. Sebagai contoh, meningkatkan intensiti penapisan di pasaran interval atau menyesuaikan sasaran keuntungan, melonggarkan syarat penapisan di pasaran trend.
Dinamika RSIRSI direka bentuk untuk bergerak, bukan statik, dan menyesuaikan diri secara automatik dengan turun naik pasaran baru-baru ini. Ini dapat meningkatkan kemampuan strategi untuk menyesuaikan diri dengan keadaan pasaran yang berbeza.
Indeks Fluktuasi Kuantitatif Bersepadu: Mengintegrasikan strategi dengan penunjuk kadar turun naik (seperti Bollinger Bandwidth) untuk menyesuaikan sasaran hentian dan keuntungan dalam persekitaran yang bergelombang tinggi, mengurangkan risiko untuk terikat dengan trend yang berkesan.
Pengesahan pelbagai kerangka masa: Tambah pengesahan trend pada bingkai masa yang lebih tinggi untuk memastikan arah perdagangan selaras dengan trend yang lebih besar. Sebagai contoh, hanya berdagang apabila trend garis hari selaras dengan arah trend garis jam.
Pemantauan dan penyesuaian prestasiSistem pemantauan masa nyata untuk prestasi strategi, mengesan petunjuk seperti kadar kemenangan, kadar kerugian dan pengeluaran maksimum, menyesuaikan parameter secara automatik atau menangguhkan perdagangan apabila petunjuk prestasi jatuh di bawah paras paras yang ditetapkan.
Pembelajaran MesinPenyelidikan: Mengintegrasikan algoritma pembelajaran mesin ke dalam proses pengoptimuman parameter, membolehkan strategi mempelajari kombinasi parameter terbaik dari data sejarah dan terus bertambah baik dengan pengumpulan data baru.
Sistem pengesanan trend adaptif yang berasaskan Core Smooth Multiple Meanline adalah alat pengesanan trend yang kuat dan fleksibel yang menggabungkan kejernihan visual dari jalur purata bergerak dengan kebolehan penapisan dan pengurusan risiko yang lebih tinggi untuk Core Smooth, RSI, kekuatan trend dan pelbagai pilihan keluar. Ia direka khas untuk peniaga yang ingin mempunyai alat yang boleh disesuaikan dan kuat untuk mengenal pasti dan berdagang trend pasaran yang berterusan.
Kelebihan terbesar strategi ini adalah kepelbagaian dan kebolehpasaran yang tinggi, yang membolehkannya menyesuaikan diri dengan pelbagai keadaan pasaran. Melalui teknologi penyelarasan teras, ia dapat memberikan kawalan yang lebih halus daripada rata-rata bergerak tradisional, sementara mekanisme penapisan dan pengesahan berlapis membantu mengurangkan isyarat palsu.
Walau bagaimanapun, pengguna harus memberi perhatian kepada cabaran pengoptimuman parameter, mengelakkan kecocokan berlebihan, dan menyesuaikan strategi mengikut keadaan pasaran tertentu. Percubaan balasan dan pengujian ke hadapan yang mencukupi disarankan untuk memastikan strategi berfungsi dengan baik dalam pelbagai keadaan pasaran. Dengan penilaian dan pengoptimuman secara berkala, strategi ini berpotensi menjadi aset berharga dalam kotak alat pedagang trend yang berjaya.
/*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)