Mehrdimensionale adaptive gleitende Durchschnittsmatrix und ATR-Strategie für dynamische Präzisionshandel

MA ATR HMA TEMA DEMA VWMA ZLEMA ALMA KAMA EMA SMA WMA
Erstellungsdatum: 2025-04-16 15:50:36 zuletzt geändert: 2025-04-16 15:50:36
Kopie: 0 Klicks: 412
2
konzentrieren Sie sich auf
319
Anhänger

Mehrdimensionale adaptive gleitende Durchschnittsmatrix und ATR-Strategie für dynamische Präzisionshandel Mehrdimensionale adaptive gleitende Durchschnittsmatrix und ATR-Strategie für dynamische Präzisionshandel

Überblick

Die Multidimensionelle Adaptive Moving Average Matrix mit ATR Dynamic Precision Trading Strategy ist ein hochwertiges Quantifizierungs-Trading-System, das für schnell wechselnde Marktbedingungen entwickelt wurde. Im Mittelpunkt der Strategie steht die Kombination verschiedener Arten von Moving Averages mit ATR (Average True Range) -Filtern, um eine hochflexible und adaptive Handelsmatrix zu bilden. Durch die genaue Erfassung von Markttrends und -Volatilitäten ist die Strategie in der Lage, Ein- und Ausgänge mit hoher Wahrscheinlichkeit in Hochfrequenz-Trading-Umgebungen zu identifizieren und gleichzeitig strenge Risikokontrollmaßnahmen zu ergreifen.

Strategieprinzip

Die Kernprinzipien der Strategie basieren auf der Zusammenarbeit mehrerer wichtiger Komponenten:

  1. Hochrangige Moving Average MatrixDie Strategie implementiert bis zu 11 verschiedene Arten von Moving Averages, darunter SMA, EMA, SMMA, HMA, TEMA, WMA, VWMA, ZLEMA, ALMA, KAMA und DEMA. Jeder Moving Average hat seine eigene Berechnungsmethode und Reaktionsmerkmale, die flexibel nach Marktbedingungen ausgewählt werden können. Das System verwendet zwei Moving Averages (schnell und langsam) als Haupttrendindikatoren, deren Kreuzung und relative Position zur Erzeugung von Basishandelssignalen verwendet werden.

  2. ATR-basierte RisikomanagementStrategie: Die ATR-Indikatoren werden verwendet, um die Marktvolatilität zu messen und auf verschiedene Arten anzuwenden:

    • Beurteilung der Volatilität: Das Verhältnis von ATR zum Schlusskurs wird als Auswahlkriterium für die Volatilitätsmarge verwendet
    • Eintrittsfilter: Sicherstellen, dass die Preise ausreichend weit von den langsamen Moving Averages entfernt sein müssen (berechnet als Multiplikator des ATR), um eintritt zu erhalten
    • Dynamische Risikokontrolle: ATR-basierte Einstellung von festen Stop-Losses, Zielgewinnen und Verfolgung von Stop-Losses, um das Risikomanagement an die aktuelle Marktvolatilität anzupassen
  3. Mehrfache Zeitrahmen-TrendfilterStrategie: Signalsicherheit durch Abfrage von Moving Average-Trends in höheren Zeitrahmen (z. B. 15 Minuten) erhöhen und sicherstellen, dass die Handelsrichtung mit den größeren Markttrends übereinstimmt.

  4. Verifizierung der Transaktionsmenge und des ZeitfenstersDie Transaktionsqualität wird weiter verbessert, wenn nur die Mindesttransaktionsvolumen-Anforderungen erfüllt werden, wenn ein Transaktionsbruch auftritt und innerhalb eines vordefinierten Transaktionszeitfensters.

  5. Logik der Signalgenerierung

    • Mehrköpfige Konditionen: Preise, die höher sind als der schnelle und der langsame bewegliche Durchschnitt, der schnelle bewegliche Durchschnitt ist höher als der langsame bewegliche Durchschnitt, und die ATR-Filter, die Transaktionsmenge und die Zeitfensterbedingungen sind erfüllt
    • Leerköpfe: Gegenüberstellungen im Gegenteil
  6. Zusammengesetzte AusstiegslogikDie Strategie nutzt eine dreistufige Ausstiegsmechanik: Fixed Stop (multipliziert mit ATR), Target Profit (multipliziert mit ATR) und Tracking Stop (dynamisch angepasst nach ATR), um einen umfassenden Risikobeschutz für jeden Handel zu bieten.

Strategische Vorteile

Eine Analyse des Codes der Strategie zeigt folgende deutliche Vorteile:

  1. Besondere AnpassungsfähigkeitDie Strategie kann an unterschiedliche Marktbedingungen angepasst werden, indem verschiedene Arten von Moving Averages (von HMA bis KAMA usw.) geschaltet werden können. Diese Flexibilität ermöglicht es dem Händler, den besten Indikator für die aktuelle Marktumgebung zu wählen, ohne die gesamte Strategie neu zu schreiben.

  2. Dynamische RisikomanagementDie ATR-basierte Risikokontrolle gewährleistet, dass die Stop-Loss- und Gewinnziele automatisch an die Volatilität des Marktes angepasst werden. Diese Methode bietet besseren Schutz in den stark volatilen Märkten und ermöglicht gleichzeitig die Erfassung von mehr Gewinnen in den Trendmärkten.

  3. Mehrfach-SignalfilterungDurch die Kombination von Moving Average Crossover, Trading Volume Analysis, Volatilitätsmargin und Multi-Time-Frame-Trend-Filterung reduziert die Strategie effektiv Fehlsignale und verbessert die Handelsqualität. Besonders die Trend-Filterung der 15-Minuten-Zeit-Frame reduziert die Wahrscheinlichkeit von Abwehrtrades erheblich.

  4. Genaue EintrittsbedingungenDie Strategie beruht nicht nur auf der Kreuzung der technischen Indikatoren, sondern erfordert auch eine ausreichende ATR-Distanz zwischen den Preisen und den langsamen gleitenden Durchschnitten, was dazu beiträgt, häufige Transaktionen in Quermärkten zu vermeiden und die Verluste durch falsche Durchbrüche zu reduzieren.

  5. Transparente LeistungsüberwachungDie integrierte Dashboard bietet eine Echtzeit-Anzeige der wichtigsten Leistungsindikatoren, einschließlich des aktuellen Gewinns/Verlusts, der Aktienbeteiligung, des ATR (Abbildungswert und Prozentsatz) und der Differenz zwischen den Moving Averages, so dass der Händler die Strategie jederzeit beurteilen kann.

Strategisches Risiko

Obwohl die Strategie so gut konzipiert ist, gibt es folgende potenzielle Risiken:

  1. ParameteroptimierungsfallenDie Strategie enthält eine große Anzahl von Parametern (beispielsweise Moving Average-Typen und -Perioden, ATR-Perioden und Multiplikatoren). Überoptimierung kann zu Kurvenpassung führen, wodurch die Strategie im Live-Trading schlecht funktioniert. Die Lösung besteht darin, robuste Tests über Märkte und Zeiträume durchzuführen, um übermäßige Parameteranpassungen zu vermeiden.

  2. Das Risiko einer schnellen UmkehrungTrotz der Verwendung von ATR-Dynamischen Stop-Losses können die Preise bei einem plötzlichen Marktumkehr (z. B. nach einer wichtigen Pressemitteilung) springen, bevor der Stop-Loss ausgelöst wird, was zu einem höheren als erwarteten Verlust führt. Es wird empfohlen, zusätzliche Nacht-Risiko-Kontrollen durchzuführen oder den Handel vor einem hoch-volatilen Ereignis auszusetzen.

  3. Signalverzögerung: Alle Moving Averages sind von Natur aus rückläufig. Selbst niedrig verzögerte Varianten wie HMA oder ZLEMA können einen idealen Einstiegspunkt in schnellen Märkten verpassen. Es kann in Betracht gezogen werden, die vorhandenen Signalsysteme durch die Kombination von Dynamik- oder Preisverhaltensindikatoren zu ergänzen.

  4. Abhängigkeit von UmsatzDie Strategie signalisiert einen Anstieg des Umsatzes, der jedoch in bestimmten Märkten oder Zeiten irreführend sein kann. Der Umsatzfilter sollte bei Bedarf angepasst oder in bestimmten Marktbedingungen in Betracht gezogen werden, diese Funktion zu deaktivieren.

  5. ZeitfensterbeschränkungEs wird empfohlen, die Handelszeiten an die aktivsten Zeiten in einem bestimmten Markt anzupassen.

Richtung der Strategieoptimierung

Nach der Analyse des Codes gibt es folgende Optimierungsmöglichkeiten:

  1. Anpassung der AnpassungsparameterEine hochwertige Optimierung besteht darin, dass Parameter automatisch angepasst werden, die sich auf die Marktlage (Trends, Schwankungen, Bandbreite) beziehen. Zum Beispiel kann das ATR-Merkmal automatisch erhöht werden, wenn die Marktlage hoch ist, oder der Moving Average-Typ kann in verschiedenen Marktumgebungen gewechselt werden.

  2. Integration von Modellen für maschinelles LernenDurch die Einführung einer maschinellen Lernschicht, um vorherzusagen, welche Moving Average-Typen unter den aktuellen Marktbedingungen am besten abschneiden könnten, wird automatisch die optimale Kombination von Moving Averages ausgewählt. Dies kann durch die Analyse der relativen Performance verschiedener Indikatoren in historischen Daten erreicht werden.

  3. Trends zur Verbesserung identifizierenDie Trends werden in einer Reihe von Modellen dargestellt, die die Trends mit einer gewissen Schnelligkeit und Intensität bestimmen.

  4. Verstärkte AusstiegsstrategienDerzeitige Ausstiegsstrategien können weiter optimiert werden, indem sie Ausstiegssignale basierend auf der Marktstruktur hinzufügen, wie z. B. Trendlinie-Breakouts, kritische Unterstützungs-/Widerstands-Punkte oder starke Veränderungen der Volatilität. Dies kann helfen, Gewinne vor dem Ende des Trends zu sperren.

  5. Risikobereinigte Positionsgröße: Realisieren Sie dynamische Positionsanpassungen basierend auf der aktuellen Volatilität und den Kontomitteln, anstatt eine feste Anzahl von Geschäften zu verwenden. Zum Beispiel, reduzieren Sie Positionen während hoher Volatilität und erhöhen Sie Positionen moderat während niedriger Volatilität, um die Rendite-Risiko-Relation zu optimieren.

  6. Filterung der relevanten MärkteDie Signalqualität wird durch die Überwachung der relevanten Märkte (z. B. der VIX bei der Handel mit Aktienindizes) oder der Verknüpfung zwischen den Vermögenswerten verbessert. Die Vertrauenswürdigkeit des Handels kann erhöht werden, wenn die relevanten Märkte einheitliche Richtungsschritte zeigen.

Zusammenfassen

Die Multi-Dimension-Adaptive Moving-Average-Matrix und die ATR-Dynamische-Precision-Trading-Strategie stellen eine umfassende und fortschrittliche Methode des Quantifizierens dar. Durch die Kombination der Vorteile mehrerer Moving-Average-Typen mit einer strengen ATR-basierten Risikokontrolle ist die Strategie in der Lage, sich an unterschiedliche Marktbedingungen anzupassen, während sie ein gutes Risikomanagement beibehält. Ihre mehrschichtige Signalfilterung, präzise Einstiegsbedingungen und umfassende Ausstiegslogik schaffen zusammen ein starkes System, das hochwahrscheinliche Handelsmöglichkeiten identifiziert.

Der wahre Wert der Strategie liegt in ihrer Flexibilität und Anpassungsfähigkeit, die es dem Händler erlaubt, sie an bestimmte Märkte und persönliche Risikopräferenzen anzupassen. Durch die empfohlene Optimierungsrichtung, insbesondere durch die Anpassung der Anpassungsparameter und die Integration von Machine Learning, besteht das Potenzial, die Leistung der Strategie weiter zu verbessern.

Diese Strategie bietet einen soliden Rahmen für Händler, die ein technisch starkes und diszipliniertes System in einem hochfrequenten Handelsumfeld einsetzen möchten. Technische Genauigkeit und Risikokontrolle sind unerlässlich. Wichtig ist, dass Händler die Performance der Strategie in ihrem Zielmarkt durch gründliche Rückmeldung und Simulation von Geschäften überprüfen und die erforderlichen Anpassungen an die spezifische Handelsumgebung vornehmen.

Strategiequellcode
/*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)