Matriks purata bergerak adaptif berbilang dimensi dan strategi perdagangan ketepatan dinamik ATR

MA ATR HMA TEMA DEMA VWMA ZLEMA ALMA KAMA EMA SMA WMA
Tarikh penciptaan: 2025-04-16 15:50:36 Akhirnya diubah suai: 2025-04-16 15:50:36
Salin: 0 Bilangan klik: 412
2
fokus pada
319
Pengikut

Matriks purata bergerak adaptif berbilang dimensi dan strategi perdagangan ketepatan dinamik ATR Matriks purata bergerak adaptif berbilang dimensi dan strategi perdagangan ketepatan dinamik ATR

Gambaran keseluruhan

Strategi perdagangan ketepatan dinamik matriks purata bergerak beradaptasi multidimensi dengan ATR adalah sistem perdagangan kuantitatif canggih yang direka untuk keadaan pasaran yang berubah dengan cepat. Inti strategi ini adalah menggabungkan pelbagai jenis penapis purata bergerak dan ATR (rata-rata gelombang sebenar) untuk membentuk matriks perdagangan yang sangat fleksibel dan beradaptasi. Dengan menangkap tren dan turun naik pasaran dengan tepat, strategi ini dapat mengenal pasti tempat masuk dan tempat keluar dengan kemungkinan tinggi dalam persekitaran perdagangan frekuensi tinggi, sambil melaksanakan langkah-langkah kawalan risiko yang ketat.

Prinsip Strategi

Prinsip-prinsip utama strategi ini adalah berdasarkan kerja sama antara beberapa komponen utama:

  1. Matriks purata bergerak peringkat tinggiStrategi ini mewujudkan sehingga 11 jenis purata bergerak yang berbeza, termasuk SMA, EMA, SMMA, HMA, TEMA, WMA, VWMA, ZLEMA, ALMA, KAMA, dan DEMA. Setiap purata bergerak mempunyai kaedah pengiraan dan ciri tindak balas yang unik, yang boleh dipilih secara fleksibel mengikut keadaan pasaran. Sistem ini menggunakan dua purata bergerak ((cepat dan perlahan) sebagai penunjuk trend utama, dan persilangan dan kedudukan relatifnya digunakan untuk menghasilkan isyarat perdagangan asas.

  2. Pengurusan risiko berasaskan ATRStrategi: Menggunakan ATR untuk mengukur turun naik pasaran dan menggunakannya dalam pelbagai aspek:

    • Penilaian turun naik: menggunakan nisbah ATR terhadap harga penutupan sebagai penyaringan penurunan turun naik
    • Penapis masuk: memastikan harga mesti berada cukup jauh dari purata bergerak perlahan (dihitung dengan kelipatan ATR) untuk masuk
    • Kawalan risiko dinamik: Tetapkan hentian tetap, keuntungan sasaran dan hentian hentian berdasarkan ATR, menjadikan pengurusan risiko sesuai dengan turun naik pasaran semasa
  3. Penapisan trend pelbagai kerangka masaStrategi: Meningkatkan kebolehpercayaan isyarat dengan menanyakan trend purata bergerak pada jangka masa yang lebih tinggi ((15 minit) dan memastikan arah perdagangan selaras dengan trend pasaran yang lebih besar.

  4. Pengesahan kuantiti dan tetingkap masa: Perdagangan hanya dilaksanakan apabila memenuhi keperluan jumlah transaksi minimum, terdapat penembusan jumlah transaksi dan dalam tetingkap masa perdagangan yang telah ditentukan, meningkatkan lagi kualiti transaksi.

  5. Logik penjanaan isyarat

    • Keadaan berbilang kepala: harga lebih tinggi daripada purata bergerak cepat dan perlahan, purata bergerak cepat lebih tinggi daripada purata bergerak perlahan, sambil memenuhi penapis ATR, syarat kuantiti dan keperluan tingkap masa
    • Keadaan kosong: keadaan yang bertentangan dengan keadaan sebaliknya
  6. Logik keluar komprehensifStrategi menggunakan mekanisme keluar tiga peringkat: berhenti tetap (ganda ATR), keuntungan sasaran (ganda ATR) dan berhenti yang dijejaki (pengesuaian dinamik berdasarkan ATR), memberikan perlindungan risiko yang komprehensif untuk setiap perdagangan.

Kelebihan Strategik

Analisis kod strategi ini dapat meringkaskan kelebihan yang ketara berikut:

  1. Kebolehan beradaptasiDengan pelbagai jenis purata bergerak yang boleh ditukar (dari HMA hingga KAMA, dll.), strategi dapat disesuaikan dengan keadaan pasaran yang berbeza. Fleksibiliti ini membolehkan peniaga memilih indikator terbaik berdasarkan keadaan pasaran semasa tanpa perlu menulis semula keseluruhan strategi.

  2. Pengurusan risiko dinamikMekanisme kawalan risiko berasaskan ATR memastikan sasaran stop-loss dan profit disesuaikan secara automatik dengan turun naik pasaran. Kaedah ini memberikan perlindungan yang lebih baik dalam pasaran yang lebih bergolak dan membolehkan menangkap lebih banyak keuntungan dalam pasaran yang sedang tren.

  3. Penapisan isyarat berlapisStrategi ini berkesan mengurangkan isyarat yang salah dan meningkatkan kualiti perdagangan dengan menggabungkan persilangan purata bergerak, analisis kuantiti dagangan, penurunan turun naik dan penapisan trend pelbagai bingkai masa. Fungsi penapisan trend pada bingkai masa 15 minit, khususnya, mengurangkan kemungkinan perdagangan yang berlawanan.

  4. Syarat kemasukanStrategi ini tidak hanya bergantung kepada penyambungan penunjuk teknikal, tetapi juga memerlukan jarak ATR yang mencukupi antara harga dan purata bergerak perlahan, yang membantu mengelakkan perdagangan yang kerap di pasaran horizontal dan mengurangkan kerugian akibat penembusan palsu.

  5. Pemantauan prestasi yang telusPapan pemuka yang terbina dalam memberikan paparan langsung kepada petunjuk prestasi utama, termasuk keuntungan / kerugian semasa, ekuiti, ATR (nilai mentah dan peratusan) dan jurang antara purata bergerak, yang membolehkan peniaga menilai keadaan strategi setiap masa.

Risiko Strategik

Walaupun strategi ini direka dengan baik, terdapat risiko yang berpotensi:

  1. Perangkap pengoptimuman parameterStrategi mengandungi banyak parameter (seperti jenis dan kitaran purata bergerak, kitaran ATR dan penggandaan, dan lain-lain), pengoptimuman yang berlebihan boleh menyebabkan penyusunan kurva, yang menyebabkan strategi tidak berfungsi dengan baik dalam perdagangan cakera. Penyelesaian adalah untuk melakukan ujian yang mantap di seluruh pasaran dan sepanjang tempoh masa, untuk mengelakkan parameter yang terlalu banyak disesuaikan.

  2. Risiko untuk berbalikWalaupun menggunakan Hentian Dinamis ATR, apabila pasaran berbalik secara tiba-tiba (seperti selepas siaran berita utama), harga mungkin melonjak sebelum Hentian mencetuskan, menyebabkan kerugian melebihi yang dijangkakan. Ia disyorkan untuk melaksanakan kawalan risiko malam tambahan atau menghentikan perdagangan sebelum peristiwa yang bergelombang tinggi.

  3. Isyarat kelewatan: Semua purata bergerak pada dasarnya mempunyai keterlambatan. Walaupun varian dengan kelambatan rendah seperti HMA atau ZLEMA mungkin terlepas titik masuk yang ideal dalam pasaran cepat.

  4. Ketergantungan kuantitiStrategi memberi isyarat apabila jumlah dagangan meningkat, tetapi dalam pasaran atau masa tertentu, jumlah dagangan mungkin mengelirukan. Penapis jumlah dagangan harus disesuaikan jika perlu atau pertimbangkan untuk mematikan ciri ini dalam keadaan pasaran tertentu.

  5. Batasan waktu tetingkap: Tetingkap waktu dagangan yang ditetapkan mungkin terlepas peluang malam atau awal yang penting. Disarankan untuk menyesuaikan waktu dagangan mengikut masa paling aktif di pasaran tertentu.

Arah pengoptimuman strategi

Selepas menganalisis kod, berikut adalah beberapa kemungkinan arah pengoptimuman:

  1. Penyesuaian parameterSatu pengoptimuman yang lebih tinggi adalah untuk mencapai parameter yang menyesuaikan secara automatik berdasarkan keadaan pasaran (trend, turun naik, julat). Sebagai contoh, anda boleh secara automatik meningkatkan ATR pada masa turun naik yang tinggi, atau menukar jenis purata bergerak dalam keadaan pasaran yang berbeza.

  2. Mengintegrasikan model pembelajaran mesinDengan memperkenalkan lapisan pembelajaran mesin untuk meramalkan jenis purata bergerak yang mungkin akan berprestasi terbaik di bawah keadaan pasaran semasa, kombinasi purata bergerak yang paling optimum dipilih secara automatik. Ini boleh dilakukan dengan menganalisis prestasi relatif indikator yang berbeza dalam data sejarah.

  3. Mengenali trend peningkatanSelain daripada penapis trend 15 minit yang sedia ada, algoritma pengenalan trend yang lebih kompleks seperti Indeks Hurst atau Indeks Pergerakan Arahan (DMI) boleh dimasukkan untuk menentukan kekuatan dan kesinambungan trend dengan lebih tepat.

  4. Meningkatkan strategi keluarStrategi keluar semasa boleh dioptimumkan lagi dengan menambah isyarat keluar berdasarkan struktur pasaran, seperti penembusan garisan trend, tahap sokongan / rintangan utama, atau perubahan mendadak dalam turun naik. Ini dapat membantu mengunci keuntungan sebelum berakhirnya trend.

  5. Saiz kedudukan yang disesuaikan dengan risiko: Membuat penyesuaian skala kedudukan dinamik berdasarkan turun naik semasa dan dana akaun, dan bukannya menggunakan jumlah dagangan tetap. Sebagai contoh, mengurangkan kedudukan semasa turun naik tinggi dan meningkatkan kedudukan secara sederhana semasa turun naik rendah untuk mengoptimumkan nisbah pulangan risiko.

  6. Penapisan pasaran berkaitanMeningkatkan kualiti isyarat dengan memantau pasaran yang berkaitan (contohnya VIX semasa perdagangan indeks saham) atau hubungan antara aset. Kepercayaan perdagangan dapat ditingkatkan apabila pasaran yang berkaitan menunjukkan pergerakan arah yang konsisten.

ringkaskan

Matriks bergerak beradaptasi berbilang dimensi dengan strategi perdagangan tepat dinamik ATR mewakili kaedah perdagangan kuantitatif yang komprehensif dan canggih. Dengan menggabungkan kelebihan pelbagai jenis rata-rata bergerak dengan kawalan risiko asas ATR yang ketat, strategi ini dapat menyesuaikan diri dengan keadaan pasaran yang berbeza sambil mengekalkan pengurusan risiko yang baik.

Nilai sebenar strategi ini adalah fleksibiliti dan kebolehpasaran, yang membolehkan peniaga menyesuaikan diri dengan pasaran tertentu dan pilihan risiko peribadi. Prestasi strategi ini berpotensi untuk ditingkatkan lagi melalui arah pengoptimuman yang disyorkan, khususnya dengan penyesuaian parameter yang disesuaikan dan integrasi pembelajaran mesin.

Bagi pedagang yang ingin menggunakan sistem yang berteknologi tinggi dan disiplin dalam persekitaran perdagangan frekuensi tinggi, strategi ini memberikan kerangka yang kuat, menggabungkan ketepatan teknikal dan kawalan risiko, yang kedua-duanya sangat penting. Penting, pedagang harus mengesahkan bagaimana strategi ini berfungsi di pasaran sasaran mereka melalui pengesanan balik yang menyeluruh dan perdagangan simulasi, dan membuat penyesuaian yang diperlukan mengikut keadaan perdagangan tertentu.

Kod sumber strategi
/*backtest
start: 2024-04-16 00:00:00
end: 2025-04-15 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=6
strategy("Dskyz (DAFE) MAtrix with ATR-Powered Precision", 
     overlay=true, 
     default_qty_type=strategy.fixed, 
     initial_capital=1000000, 
     commission_value=0, 
     slippage=1, 
     pyramiding=10)

// ==================================================================
// USER-DEFINED FUNCTIONS
// ==================================================================

// Hull Moving Average (HMA)
hma(src, len) =>
    halfLen = math.round(len * 0.5)
    sqrtLen = math.round(math.sqrt(len))
    wmaf = ta.wma(src, halfLen)
    wmaFull = ta.wma(src, len)
    ta.wma(2 * wmaf - wmaFull, sqrtLen)

// Triple Exponential Moving Average (TEMA)
tema(src, len) =>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    ema3 = ta.ema(ema2, len)
    3 * (ema1 - ema2) + ema3

// Double Exponential Moving Average (DEMA)
dema(src, len) =>
    ema1 = ta.ema(src, len)
    ema2 = ta.ema(ema1, len)
    2 * ema1 - ema2

// VWMA - Volume Weighted Moving Average
vwma(src, len) =>
    ta.vwma(src, len)

// ZLEMA - Zero Lag EMA
zlema(src, len) =>
    lag = math.floor((len - 1) / 2)
    ta.ema(2 * src - src[lag], len)

// ALMA - Arnaud Legoux Moving Average
alma(src, len, offset=0.85, sigma=6) =>
    ta.alma(src, len, offset, sigma)

// Custom Kaufman Adaptive Moving Average (KAMA)
kama(src, len) =>
    fastSC = 2.0 / (2 + 1)
    slowSC = 2.0 / (30 + 1)
    change = math.abs(src - src[len])
    volatility = 0.0
    for i = 0 to len - 1
        volatility += math.abs(src - src[i])
    er = volatility != 0 ? change / volatility : 0.0
    sc = math.pow(er * (fastSC - slowSC) + slowSC, 2)
    var float kama_val = na
    kama_val := na(kama_val) ? ta.sma(src, len) : kama_val + sc * (src - kama_val)
    kama_val

// ==================================================================
// INPUTS
// ==================================================================

fastLength   = input.int(9, "[MA] Fast MA Length", minval=1)
slowLength   = input.int(19, "[MA] Slow MA Length", minval=1)
fastMAType   = input.string("SMA", "Fast MA Type", options=["SMA", "EMA", "SMMA", "HMA", "TEMA", "WMA", "VWMA", "ZLEMA", "ALMA", "KAMA", "DEMA"])
slowMAType   = input.string("SMA", "Slow MA Type", options=["SMA", "EMA", "SMMA", "HMA", "TEMA", "WMA", "VWMA", "ZLEMA", "ALMA", "KAMA", "DEMA"])

atrPeriod           = input.int(14, "ATR Period", minval=1)
atrMultiplier       = input.float(1.5, "ATR Multiplier for Filter", minval=0.1, step=0.1)
useTrendFilter      = input.bool(true, "[Filter Settings] Use 15m Trend Filter")
minVolume           = input.int(10, "Minimum Volume", minval=1)
volatilityThreshold = input.float(1.0, "Volatility Threshold (%)", minval=0.1, step=0.1) / 100
tradingStartHour    = input.int(9, "Trading Start Hour (24h)", minval=0, maxval=23)
tradingEndHour      = input.int(16, "Trading End Hour (24h)", minval=0, maxval=23)
trailOffset         = input.float(0.5, "[Exit Settings] Trailing Stop Offset ATR Multiplier", minval=0.01, step=0.01)
profitTargetATRMult = input.float(1.2, "Profit Target ATR Multiplier", minval=0.1, step=0.1)
fixedStopMultiplier = input.float(1.3, "Fixed Stop Multiplier", minval=0.5, step=0.1)
fixedQuantity       = input.int(2, "Trade Quantity", minval=1)

resetDashboard      = input.bool(false, "Reset Dashboard Stats")

// ==================================================================
// CALCULATIONS
// ==================================================================

volumeOk    = volume >= minVolume
currentHour = hour(time)
timeWindow  = currentHour >= tradingStartHour and currentHour <= tradingEndHour
volumeSpike = volume > 1.2 * ta.sma(volume, 10)

// ATR Calculation
atr          = ta.atr(atrPeriod)
volatility   = nz(atr / close, 0)
volatilityOk = volatility <= volatilityThreshold

// ==================================================================
// MOVING AVERAGES CALCULATIONS
// ==================================================================

var float fastMA = na
var float slowMA = na

// Fast MA Logic
if fastMAType == "SMA"
    fastMA := ta.sma(close, fastLength)
else if fastMAType == "EMA"
    fastMA := ta.ema(close, fastLength)
else if fastMAType == "SMMA"
    fastMA := ta.rma(close, fastLength)
else if fastMAType == "HMA"
    fastMA := hma(close, fastLength)
else if fastMAType == "TEMA"
    fastMA := tema(close, fastLength)
else if fastMAType == "WMA"
    fastMA := ta.wma(close, fastLength)
else if fastMAType == "VWMA"
    fastMA := vwma(close, fastLength)
else if fastMAType == "ZLEMA"
    fastMA := zlema(close, fastLength)
else if fastMAType == "ALMA"
    fastMA := alma(close, fastLength)
else if fastMAType == "KAMA"
    fastMA := kama(close, fastLength)
else if fastMAType == "DEMA"
    fastMA := dema(close, fastLength)

// Slow MA Logic
if slowMAType == "SMA"
    slowMA := ta.sma(close, slowLength)
else if slowMAType == "EMA"
    slowMA := ta.ema(close, slowLength)
else if slowMAType == "SMMA"
    slowMA := ta.rma(close, slowLength)
else if slowMAType == "HMA"
    slowMA := hma(close, slowLength)
else if slowMAType == "TEMA"
    slowMA := tema(close, slowLength)
else if slowMAType == "WMA"
    slowMA := ta.wma(close, slowLength)
else if slowMAType == "VWMA"
    slowMA := vwma(close, slowLength)
else if slowMAType == "ZLEMA"
    slowMA := zlema(close, slowLength)
else if slowMAType == "ALMA"
    slowMA := alma(close, slowLength)
else if slowMAType == "KAMA"
    slowMA := kama(close, slowLength)
else if slowMAType == "DEMA"
    slowMA := dema(close, slowLength)

// ==================================================================
// TREND FILTER & SIGNAL LOGIC
// ==================================================================

// Retrieve 15-minute MAs for trend filtering
[fastMA15m, slowMA15m] = request.security(syminfo.tickerid, "15", [ta.sma(close, fastLength), ta.sma(close, slowLength)])
trend15m    = fastMA15m > slowMA15m ? 1 : fastMA15m < slowMA15m ? -1 : 0
trendLongOk = not useTrendFilter or trend15m >= 0
trendShortOk= not useTrendFilter or trend15m <= 0

// ATR-based Price Filter
atrFilterLong  = close > slowMA + atr * atrMultiplier
atrFilterShort = close < slowMA - atr * atrMultiplier

// Signal Logic: MA alignment + filters
maAbove       = close > fastMA and fastMA > slowMA
maBelow       = close < fastMA and fastMA < slowMA
longCondition = maAbove and trendLongOk and atrFilterLong and volumeOk and volumeSpike and timeWindow and volatilityOk
shortCondition= maBelow and trendShortOk and atrFilterShort and volumeOk and volumeSpike and timeWindow and volatilityOk

// ==================================================================
// ENTRY LOGIC
// ==================================================================

if strategy.position_size == 0 and longCondition
    strategy.entry("Long", strategy.long, qty=fixedQuantity)
if strategy.position_size == 0 and shortCondition
    strategy.entry("Short", strategy.short, qty=fixedQuantity)

// ==================================================================
// EXIT LOGIC
// ==================================================================
if strategy.position_size > 0
    strategy.exit("Long Exit", "Long",
         stop  = strategy.position_avg_price - atr * fixedStopMultiplier,
         limit = strategy.position_avg_price + atr * profitTargetATRMult,
         trail_offset = atr * trailOffset,
         trail_points = atr * trailOffset)
if strategy.position_size < 0
    strategy.exit("Short Exit", "Short",
         stop  = strategy.position_avg_price + atr * fixedStopMultiplier,
         limit = strategy.position_avg_price - atr * profitTargetATRMult,
         trail_offset = atr * trailOffset,
         trail_points = atr * trailOffset)

// ==================================================================
// VISUALS: PLOT MAs
// ==================================================================

plot(fastMA, color=color.blue, linewidth=2, title="Fast MA")
plot(slowMA, color=color.red, linewidth=2, title="Slow MA")

// ==================================================================
// METRICS CALCULATIONS (for Dashboard)
// ==================================================================

// Additional metrics:
atrPct   = close != 0 ? (atr / close) * 100 : na               // ATR as percentage of Close
maGapPct = (slowMA != 0) ? (math.abs(fastMA - slowMA) / slowMA) * 100 : na  // % difference between MAs

// Open PnL Calculation
currentPnL = strategy.position_size != 0 ? (close - strategy.position_avg_price) * strategy.position_size : 0

// Persistent variable for highest equity (for drawdown calculation)
var float highestEquity = strategy.equity
highestEquity := math.max(highestEquity, strategy.equity)
totalDrawdown = strategy.equity - highestEquity

// Reset dashboard metrics if reset toggle is on.
if resetDashboard
    highestEquity := strategy.equity

// ==================================================================
// DASHBOARD: WATERMARK LOGO (Bottom-Right)
// ==================================================================
var table watermarkTable = table.new(position.bottom_right, 1, 1, bgcolor=color.rgb(0, 0, 0, 80), border_color=color.rgb(0, 50, 137), border_width=1)
if barstate.islast
    table.cell(watermarkTable, 0, 0, "⚡ Dskyz - DAFE Trading Systems", text_color=color.rgb(159, 127, 255, 80), text_size=size.large)

// ==================================================================
// DASHBOARD: METRICS TABLE (Bottom-Left)
// ==================================================================
var table dashboard = table.new(position.middle_right, 2, 12, bgcolor=color.new(#000000, 29), border_color=color.rgb(80, 80, 80), border_width=1)
if barstate.islast
    // Row 0 – Dashboard Title (duplicated in both columns to simulate spanning)
    table.cell(dashboard, 0, 0, "⚡(DAFE) Trading Systems", text_color=color.rgb(135, 135, 135), text_size=size.small)
    
    // Row 1 – Position
    table.cell(dashboard, 0, 1, "Position", text_color=color.gray)
    positionText = strategy.position_size > 0 ? "Long" : strategy.position_size < 0 ? "Short" : "Flat"
    table.cell(dashboard, 1, 1, positionText, text_color=strategy.position_size > 0 ? color.green : strategy.position_size < 0 ? color.red : color.blue)
    
    // Row 2 – Current PnL
    table.cell(dashboard, 0, 2, "Current P/L", text_color=color.gray)
    table.cell(dashboard, 1, 2, str.tostring(currentPnL, "#.##"), text_color=(currentPnL > 0 ? color.green : currentPnL < 0 ? color.red : color.gray))
    
    // Row 3 – Equity
    table.cell(dashboard, 0, 3, "Equity", text_color=color.gray)
    table.cell(dashboard, 1, 3, str.tostring(strategy.equity, "#.##"), text_color=color.white)

    // Row 4 – Closed Trades
    table.cell(dashboard, 0, 4, "Closed Trades", text_color=color.gray)
    table.cell(dashboard, 1, 4, str.tostring(strategy.closedtrades), text_color=color.white)

    // Row 5 – Title Step
    table.cell(dashboard, 0, 5, "Metrics", text_color=color.rgb(76, 122, 23))
   
    // Row 6 – Fast MA
    table.cell(dashboard, 0, 6, "Fast MA", text_color=color.gray)
    table.cell(dashboard, 1, 6, str.tostring(fastMA, "#.##"), text_color=color.white)
    
    // Row 7 – Slow MA
    table.cell(dashboard, 0, 7, "Slow MA", text_color=color.gray)
    table.cell(dashboard, 1, 7, str.tostring(slowMA, "#.##"), text_color=color.white)
    
    // Row 8 – ATR (Raw)
    table.cell(dashboard, 0, 8, "ATR", text_color=color.gray)
    table.cell(dashboard, 1, 8, str.tostring(atr, "#.##"), text_color=color.white)
    
    // Row 9 – ATR (%)
    table.cell(dashboard, 0, 9, "ATR (%)", text_color=color.gray)
    table.cell(dashboard, 1, 9, str.tostring(atrPct, "#.##") + "%", text_color=color.white)
    
    // Row 10 – MA Gap (%)
    table.cell(dashboard, 0, 10, "MA Gap (%)", text_color=color.gray)
    table.cell(dashboard, 1, 10, na(maGapPct) ? "N/A" : str.tostring(maGapPct, "#.##") + "%", text_color=color.white)
    
    // Row 11 – Volatility (%)
    table.cell(dashboard, 0, 11, "Volatility (%)", text_color=color.gray)
    table.cell(dashboard, 1, 11, str.tostring(volatility * 100, "#.##") + "%", text_color=color.white)