適応型ボラティリティマルチインジケータートレンドフォロー取引システム

ATR SMA RSI DCA 烛台模式 趋势跟踪 波动率适应 多时间周期 止损 止盈
作成日: 2025-04-11 13:41:56 最終変更日: 2025-04-11 13:41:56
コピー: 3 クリック数: 378
2
フォロー
319
フォロワー

適応型ボラティリティマルチインジケータートレンドフォロー取引システム 適応型ボラティリティマルチインジケータートレンドフォロー取引システム

概要

自動適応率多指標トレンドトラッキング取引システムは,高度に変動する市場のために設計された量化取引戦略であり,動的に調整された技術指標と高度なリスク管理機構を組み合わせている.この戦略の核心は,ATR (平均リアル波幅) を介して移動平均線パラメータを動的に調整し,市場変動に自主的に適応することを実現し,RSI (超買い超売りフィルター,台形状) を統合し,多時間周期のトレンドを確認し,段階的にポジションを構築する (DCA) などを統合し,包括的な取引フレームワークを形成する.この戦略は,期貨市場などの高度に変動する環境に特に適しており,日内取引と波段取引のための柔軟な操作モデルを提供します.

戦略原則

戦略の核心は以下の主要なモジュールに基づいています.

  1. 自動移動均線システム戦略は,速速と遅速の単純な移動平均線 ((SMA) を使用し,その長さはATRによって動的に調整されます.高い波動環境では,平均線長さは,市場の変化に迅速に反応するために短縮されます.低い波動環境では,平均線長さは,騒音を減らすために長縮されます.長い信号は,速い平均線で遅速の平均線を横切って価格が確認されたときに発生します.短い信号は,その反対です.

  2. RSI 運動量フィルター: RSI (相対的に強い指数) を使って入場信号を検証し,取引方向が市場動態と一致していることを確認する.この機能は,選択的にオンまたはオフにされ,カスタムRSIパラメータ (長さ14 ,超買い60 ,超売り40など) をサポートする.

  3. 崩壊した形状の認識: システムは強い看板または下落の吞食形態を識別し,取引量と範囲の強さを組み合わせて検証する.偽の信号を避けるために,二つの逆の形態が同時に出現すると,システムは取引をスキップする.

  4. 多周期トレンド確認: 選択的に取引信号を15分周期のSMAトレンドに整合させ,確認メカニズムの一層を追加し,取引の質を向上させる.

  5. DCAの仕組みを段階的に構築する: トレンド方向で多くのエントリーを許容し,最大で既定数のエントリーをサポートします (例えば4回),エントリー間隔はATR倍数に基づいて設定されます. このメカニズムは,トレンドが継続する市場で平均コストを最適化するのに役立ちます.

  6. 高級リスク管理

    • 初期ストップ:ATRの設定に基づいて (通常は2〜3.5倍),入場柱により広い固定ストップ倍数 (例えば1.3) を適用する.
    • ストップ・ロスを追跡する:ATRの基礎の偏移と倍数を用いて,利益が増加するにつれて動的に調整する (例えば,利益がATRを超えると倍数は0.5から0.3に低下する).
    • ストップ目標:入場価格±ATRの特定の倍数 (例えば1.2) に設定する.
    • 冷却期間:退出後の一時停止期間 ((0-5分)),過剰取引を防止する.
    • 最低のポジション保持時間:取引が一定数の柱で継続されることを保証する (例えば2-10)).
  7. トランザクション実行論理: システムは移動平均線または台形信号を優先する ((ユーザの選択に応じて),交差量,波動性および時間フィルターを適用する. 入場品質を確保するために交差量ピーク条件も追加した ((交差量>1.2)*10期SMA) でした.

戦略的優位性

  1. 市場の適応力ATRの技術指標のパラメータを動的に調整することで,戦略は異なる市場条件に自動的に適応し,高波動性および低波動性環境の両方で有効性を保ちます.

  2. 信号品質のフィルタリング多層のフィルタリングメカニズム ((RSI,多周期的な傾向,取引量および変動性) が,偽信号を効果的に軽減し,取引品質を向上させる.

  3. フレキシブルな入学制度: ユーザの好みに応じて移動均線または形信号を優先して使用し,DCA機能によってトレンド方向にエントリーポイントを最適化する.

  4. ダイナミックなリスク管理: ストップポイントとストップトラッキングは,市場の波動と取引利益の動向に調整し,資本を保護しながら,トレンドに十分な発展スペースを与えます.

  5. 視覚化とデビューツール戦略: 豊富なグラフの覆い層,リアルタイムのメジャーボード,デビュー表を提供して,ユーザがパラメータを最適化し,取引ロジックを理解できるようにする.

  6. モジュール化デザイン: ユーザが好みに応じて様々な機能をオン・オフすることができる (RSIフィルター,倒産形状認識,多時周期トレンドなど),高度にカスタマイズできる.

  7. 詳細な入場管理取引量ピークフィルターにより,市場活動が顕著なときにのみ入場を保証し,冷却期メカニズムにより過度取引を防ぐ.

戦略リスク

  1. パラメータ感度策略: 複数のパラメータを使用する (例えば,平均線長,ATR周期,RSI値など),これらのパラメータの設定は,パフォーマンスに顕著な影響を与える.不適切なパラメータの組み合わせは,過去データに過度適応を引き起こす可能性があります.

解決方法: 幅広くパラメータ最適化テストを実施するが,過度最適化を避ける. 戦略の安定性を検証するために,ウォークフォワードテストとサンプル外テストを使用する.

  1. 市場転換のリスク市場パターンが急激に変化する際 (例えば,トレンドから振動まで) は,新しい状況に適応する前に,戦略が連続して損失を発生させる可能性があります.

解決方法: 市場状態の識別メカニズムを追加することを検討し,異なる市場環境で異なるパラメータセットを使用する. 一日最大損失または連続的な損失の後に取引を停止するなど,全体的なリスク制限を実施する.

  1. スライドポイントと流動性の問題金融市場における高頻度取引や波動性のある市場では,滑り込みや流動性の低下の危険性がある.

解決方法: リアルなスライドポイントと手数料の見積もりを反測に含め,流動性が低い時期の取引を避ける.

  1. システムの複雑さ複数の層の論理と条件の組み合わせは,戦略の複雑さを増し,理解し,維持することが困難になる.

解決方法: 策略が提供するデビューツールを使用して,各コンポーネントのパフォーマンスを密かに監視する. 優れたコード注釈を維持する. 各コンポーネントのモジュールテストの独立効果を考慮する.

  1. 過剰取引のリスクDCAの仕組みと頻度の高いシグナル生成は,過剰な取引を引き起こし,取引コストを増加させる可能性があります.

*解決方法*適切な冷却期と最小保有時間の設定; 取引コストを厳格に評価し,定期的な入場基準の審査と最適化.

最適化の方向

  1. 機械学習の強化:ベイエス最適化や遺伝的アルゴリズムのような自己適応パラメータ最適化アルゴリズムを導入し,異なる市場環境のために最適なパラメータの組み合わせを自動的に見つけます.これは,手動最適化の必要性を減らし,市場の変化に戦略の適応性を向上させます.

  2. 市場環境の分類市場状態の分類システムを開発し (トレンド,震動,高波動,低波動など) 各状態に最適なパラメータ配置を予め設定する.この方法は,市場が変化する時に戦略行動をより迅速に調整し,適応遅れを減らすことができます.

  3. ポジション管理の強化より複雑なポジション管理アルゴリズムの導入,例えばケリー准則または動力強度に基づくダイナミックポジション調整.これは,資金利用を最適化し,強いシグナル時に露出を増やし,弱いシグナル時にリスクを減らすことができる.

  4. 代替指標の統合: 既存のシステムに補足または代替として,Bollinger Bands,MACDまたはIchimoku Cloud Graphのような他の技術指標の有効性をテストする.異なる指標は特定の市場条件下でより正確な信号を提供することがあります.

  5. 感情データ統合: 潜在的な市場転換を早期に識別するために,VIX変動率指数やオプション市場のデータなどの市場情緒指標を組み込むことを検討してください.これらの外部データソースは,従来の技術指標では捉えられない情報を提供できます.

  6. 多資産関連分析関連性分析を開発し,ある市場のシグナルを使用して,別の関連市場の取引決定を検証または強化する.例えば,商品価格の変化を使用して,関連する株式部門のトレンドを確認する.

  7. 計算効率を最適化する計算効率を高めるため,特に高周波策の計算効率を高めるためにコードを再構成する.これはATR計算,条件評価の順序を最適化し,不要な重複計算を減らすことを含む.

要約する

自動適応率の多指標トレンドトラッキング取引システムは,ダイナミックなパラメータ調整と多層のフィルタリングメカニズムにより,さまざまな市場環境に効果的に対応する包括的で柔軟な量化取引方法を表します. 戦略の核心的な優点は,自己適応性と総合的なリスク管理フレームワークにあります.

この戦略は,いくつかのクラシックな技術分析ツール ((移動平均線,RSI,落形) を統合し,現代的な量的な取引要素 ((自適性パラメータ,多時間周期分析,DCA) を加え,バランスの取れたシステムを形成します. 入場タイミングを精密に制御し,複数の入場戦略を最適化し,ストープレベルを動的に調整することにより,資本を保護しながら,市場トレンドの機会を充分に活用することができます.

しかし,戦略の複雑さは,パラメータの感度とシステム維持の課題ももたらします. 投資家は,この戦略を実行する前に,十分な反省と前向きなテストを行い,市場の変化に応じてパラメータを調整する準備ができていなければなりません.

全体として,この戦略は,経験豊富なトレーダーに適した,特定のニーズとリスクの好みに合わせて,今日の瞬く間に変化する金融市場の中で一貫した取引優位性を求めるための,堅固な量化取引の枠組みを提供します.

ストラテジーソースコード
/*backtest
start: 2024-04-11 00:00:00
end: 2025-04-10 00:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

//@version=6
strategy('Dskyz Adaptive Futures Elite (DAFE) - Updated', 
         overlay=true, 
         default_qty_type=strategy.fixed, 
         initial_capital=1000000, 
         commission_value=0, 
         slippage=1, 
         pyramiding=10)

// === INPUTS ===

// Moving Average Settings
fastLength       = input.int(9, '[MA] Fast MA Length', minval=1)
slowLength       = input.int(19, '[MA] Slow MA Length', minval=1)

// RSI Settings
useRSI           = input.bool(false, '[RSI Settings] Use RSI Filter')
rsiLength        = input.int(14, 'RSI Length', minval=1)
rsiOverbought    = input.int(60, 'RSI Overbought', minval=50, maxval=100)
rsiOversold      = input.int(40, 'RSI Oversold', minval=0, maxval=50)
rsiLookback      = input.int(1, 'RSI Lookback', minval=1)

// Pattern Settings
usePatterns      = input.bool(true, '[Pattern Settings] Use Candlestick Patterns')
patternLookback  = input.int(19, 'Pattern Lookback Bars', minval=1)

// Filter Settings
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)

// DCA Settings
useDCA           = input.bool(false, '[DCA Settings] Use DCA')
maxTotalEntries  = input.int(4, 'Max Total Entries per Direction', minval=1)
dcaMultiplier    = input.float(1.0, 'DCA ATR Multiplier', minval=0.1, step=0.1)

// Signal Settings
signalPriority   = input.string('MA', '[Signal Settings] Signal Priority', options=['Pattern', 'MA'])
minBarsBetweenSignals = input.int(5, 'Min Bars Between Signals', minval=1)
plotMode         = input.string('Potential Signals', 'Plot Mode', options=['Potential Signals', 'Actual Entries'])

// Exit Settings
trailOffset      = input.float(0.5, '[Exit Settings] Trailing Stop Offset ATR Multiplier', minval=0.01, step=0.01)
trailPointsMult  = input.float(0.5, 'Trailing Stop Points ATR Multiplier', minval=0.01, step=0.01)
profitTargetATRMult = input.float(1.2, 'Profit Target ATR Multiplier', minval=0.1, step=0.1)  // Profit target factor
fixedStopMultiplier  = input.float(1.3, 'Fixed Stop Multiplier', minval=0.5, step=0.1)    // Fixed stop multiplier

// General Settings
debugLogging     = input.bool(true, '[General Settings] Enable Debug Logging')
fixedQuantity    = input.int(2, 'Trade Quantity', minval=1)
cooldownMinutes  = input.int(0, 'Cooldown Minutes', minval=0)

// ATR Settings – Use Dynamic ATR or fixed value
useDynamicATR    = input.bool(true, title="Use Dynamic ATR")
userATRPeriod    = input.int(7, title="ATR Period (if not using dynamic)", minval=1)
defaultATR       = timeframe.isminutes and timeframe.multiplier <= 2 ? 5 :
                   timeframe.isminutes and timeframe.multiplier <= 5 ? 7 : 10
atrPeriod        = useDynamicATR ? defaultATR : userATRPeriod

// === TRADE TRACKING VARIABLES ===
var int lastSignalBar   = 0
var int lastSignalType  = 0         // 1 for long, -1 for short
var int entryBarIndex   = 0
var bool inLongTrade    = false
var bool inShortTrade   = false

// DCA Tracking Variables
var int longEntryCount  = 0
var int shortEntryCount = 0
var float longInitialEntryPrice = na
var float shortInitialEntryPrice = na
var float longEntryATR  = na
var float shortEntryATR = na
var float long_stop_price = na
var float short_stop_price = na

// Signal Plotting Variables
var int lastLongPlotBar = 0
var int lastShortPlotBar = 0

// === CALCULATIONS ===

// Volume and Time Filters
volumeOk    = volume >= minVolume
currentHour = hour(time)
timeWindow  = currentHour >= tradingStartHour and currentHour <= tradingEndHour

// Additional Entry Filter: Volume Spike Condition
volumeSpike = volume > 1.2 * ta.sma(volume, 10)

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

// Adaptive MA Lengths
fastLengthAdaptive = math.round(fastLength / (1 + volatility))
slowLengthAdaptive = math.round(slowLength / (1 + volatility))
fastLengthSafe     = math.max(1, not na(atr) ? fastLengthAdaptive : fastLength)
slowLengthSafe     = math.max(1, not na(atr) ? slowLengthAdaptive : slowLength)
fastMA             = ta.sma(close, fastLengthSafe)
slowMA             = ta.sma(close, slowLengthSafe)

// RSI Calculation
rsi               = ta.rsi(close, rsiLength)
rsiCrossover      = ta.crossover(rsi, rsiOversold)
rsiCrossunder     = ta.crossunder(rsi, rsiOverbought)
rsiLongOk         = not useRSI or (rsiCrossover and rsi[rsiLookback] < 70)
rsiShortOk        = not useRSI or (rsiCrossunder and rsi[rsiLookback] > 30)

// 15m Trend Filter
[fastMA15m, slowMA15m] = request.security(syminfo.tickerid, '15', [ta.sma(close, fastLength), ta.sma(close, slowLength)])
trend15m = fastMA15m > slowMA15m ? 1 : fastMA15m < slowMA15m ? -1 : 0

// Candlestick Patterns
isBullishEngulfing() =>
    close[1] < open[1] and close > open and open < close[1] and close > open[1] and (close - open) > (open[1] - close[1]) * 0.8

isBearishEngulfing() =>
    close[1] > open[1] and close < open and open > close[1] and close < open[1] and (open - close) > (close[1] - open[1]) * 0.8

// Pattern Strength Calculation
patternStrength(isBull) =>
    bull = isBull ? 1 : 0
    bear = isBull ? 0 : 1
    volumeStrength = volume > ta.sma(volume, 10) ? 1 : 0
    rangeStrength  = (high - low) > ta.sma(high - low, 10) ? 1 : 0
    strength = bull * (volumeStrength + rangeStrength) - bear * (volumeStrength + rangeStrength)
    strength

bullStrength = patternStrength(true)
bearStrength = patternStrength(false)

// Detect Patterns
bullishEngulfingOccurred = ta.barssince(isBullishEngulfing()) <= patternLookback and bullStrength >= 1
bearishEngulfingOccurred = ta.barssince(isBearishEngulfing()) <= patternLookback and bearStrength <= -1
patternConflict          = bullishEngulfingOccurred and bearishEngulfingOccurred

// MA Conditions with Trend & RSI Filters
maAbove      = close > fastMA and fastMA > slowMA and close > close[1]
maBelow      = close < fastMA and fastMA < slowMA and close < close[1]
trendLongOk  = not useTrendFilter or trend15m >= 0
trendShortOk = not useTrendFilter or trend15m <= 0

// Signal Priority Logic
bullPattern  = usePatterns and bullishEngulfingOccurred
bearPattern  = usePatterns and bearishEngulfingOccurred
bullMA       = maAbove and trendLongOk and rsiLongOk
bearMA       = maBelow and trendShortOk and rsiShortOk

longCondition  = false
shortCondition = false

if signalPriority == 'Pattern'
    longCondition  := bullPattern or (not bearPattern and bullMA)
    shortCondition := bearPattern or (not bullPattern and bearMA)
else
    longCondition  := bullMA or (not bearMA and bullPattern)
    shortCondition := bearMA or (not bullMA and bearPattern)

// Apply Filters and require volume spike for quality entries
longCondition  := longCondition and volumeOk and volumeSpike and timeWindow and volatilityOk and not patternConflict
shortCondition := shortCondition and volumeOk and volumeSpike and timeWindow and volatilityOk and not patternConflict

// Update Trade Status
if strategy.position_size > 0
    inLongTrade := true
    inShortTrade := false
else if strategy.position_size < 0
    inShortTrade := true
    inLongTrade := false
else
    inLongTrade := false
    inShortTrade := false

// Entry Checks
canTrade      = strategy.position_size == 0
validQuantity = fixedQuantity > 0
quantity      = fixedQuantity

// Prevent Multiple Alerts Per Bar
var bool alertSent = false
if barstate.isnew
    alertSent := false

// Cooldown Logic
var float lastExitTime = na
if strategy.position_size == 0 and strategy.position_size[1] != 0
    lastExitTime := time
canEnter = na(lastExitTime) or ((time - lastExitTime) / 60000 >= cooldownMinutes)

// === ENTRY LOGIC ===
if canTrade and validQuantity and not alertSent and canEnter and barstate.isconfirmed
    if longCondition and not shortCondition and (lastSignalBar != bar_index or lastSignalType != 1)
        strategy.entry('Long', strategy.long, qty=quantity)
        longInitialEntryPrice := close
        longEntryATR         := atr
        longEntryCount       := 1
        alert('Enter Long', alert.freq_once_per_bar)
        alertSent            := true
        lastSignalBar        := bar_index
        lastSignalType       := 1
        entryBarIndex        := bar_index

    else if shortCondition and not longCondition and (lastSignalBar != bar_index or lastSignalType != -1)
        strategy.entry('Short', strategy.short, qty=quantity)
        shortInitialEntryPrice := close
        shortEntryATR          := atr
        shortEntryCount        := 1
        alert('Enter Short', alert.freq_once_per_bar)
        alertSent             := true
        lastSignalBar         := bar_index
        lastSignalType        := -1
        entryBarIndex         := bar_index


// === DCA LOGIC (IF ENABLED) ===
if useDCA
    if strategy.position_size > 0 and longEntryCount < maxTotalEntries and bullMA and rsi < 70
        nextDCALevel = longInitialEntryPrice - longEntryCount * longEntryATR * dcaMultiplier
        if close <= nextDCALevel
            strategy.entry('Long DCA ' + str.tostring(longEntryCount), strategy.long, qty=quantity)
            longEntryCount := longEntryCount + 1
    if strategy.position_size < 0 and shortEntryCount < maxTotalEntries and bearMA and rsi > 30
        nextDCALevel = shortInitialEntryPrice + shortEntryATR * shortEntryCount * dcaMultiplier
        if close >= nextDCALevel
            strategy.entry('Short DCA ' + str.tostring(shortEntryCount), strategy.short, qty=quantity)
            shortEntryCount := shortEntryCount + 1

// === RESET DCA VARIABLES ON EXIT ===
if strategy.position_size == 0 and strategy.position_size[1] != 0
    longEntryCount := 0
    shortEntryCount := 0
    longInitialEntryPrice := na
    shortInitialEntryPrice := na
    longEntryATR := na
    shortEntryATR := na

// === FIXED STOP-LOSS CALCULATION (WIDER INITIAL STOP) ===
long_stop_price  := strategy.position_avg_price - atr * fixedStopMultiplier
short_stop_price := strategy.position_avg_price + atr * fixedStopMultiplier

// === ADJUST TRAILING POINTS BASED ON PROFIT ===
profitLong  = strategy.position_size > 0 ? close - strategy.position_avg_price : 0
profitShort = strategy.position_size < 0 ? strategy.position_avg_price - close : 0
trailPointsMultAdjusted       = profitLong > atr ? 0.3 : profitLong > atr * 0.66 ? 0.4 : trailPointsMult      // For long positions
trailPointsMultAdjustedShort  = profitShort > atr ? 0.3 : profitShort > atr * 0.66 ? 0.4 : trailPointsMult   // For short positions
trailPointsLong  = atr * trailPointsMultAdjusted
trailPointsShort = atr * trailPointsMultAdjustedShort

// === EXIT LOGIC ===
// On the entry bar, always use the fixed stop; thereafter, use a combination of fixed stop, trailing stop, and a profit target.
// Profit Target: For longs, exit at avg_entry + atr * profitTargetATRMult; for shorts, exit at avg_entry - atr * profitTargetATRMult.
if strategy.position_size > 0
    if bar_index == entryBarIndex
        if debugLogging
            log.info("Long exit on entry bar: fixed stop applied. Price=" + str.tostring(close))
        strategy.exit('Long Exit', 'Long', stop=long_stop_price)
    else
        if debugLogging
            log.info("Long Trade: profit=" + str.tostring(profitLong) + ", ATR=" + str.tostring(atr))
        strategy.exit('Long Exit', 'Long', 
             stop=long_stop_price, 
             limit = strategy.position_avg_price + atr * profitTargetATRMult,
             trail_points=trailPointsLong, 
             trail_offset=atr * trailOffset)
            
if strategy.position_size < 0
    if bar_index == entryBarIndex
        if debugLogging
            log.info("Short exit on entry bar: fixed stop applied. Price=" + str.tostring(close))
        strategy.exit('Short Exit', 'Short', stop=short_stop_price)
    else
        if debugLogging
            log.info("Short Trade: profit=" + str.tostring(profitShort) + ", ATR=" + str.tostring(atr))
        strategy.exit('Short Exit', 'Short', 
             stop=short_stop_price, 
             limit = strategy.position_avg_price - atr * profitTargetATRMult,
             trail_points=trailPointsShort, 
             trail_offset=atr * trailOffset)

// === FORCE CLOSE ON LAST BAR (OPTIONAL) ===
if barstate.islast
    if strategy.position_size > 0
        strategy.close('Long', comment='Forced Exit')
    if strategy.position_size < 0
        strategy.close('Short', comment='Forced Exit')

// === SIGNAL PLOTTING LOGIC ===
plotLongSignal  = longCondition and canTrade and (bar_index - lastLongPlotBar >= minBarsBetweenSignals or lastLongPlotBar == 0)
plotShortSignal = shortCondition and canTrade and (bar_index - lastShortPlotBar >= minBarsBetweenSignals or lastShortPlotBar == 0)

if plotLongSignal
    lastLongPlotBar := bar_index
if plotShortSignal
    lastShortPlotBar := bar_index

// Define plotting conditions based on plotMode
plotLongShape  = plotMode == 'Potential Signals' ? plotLongSignal : strategy.position_size > 0 and strategy.position_size[1] <= 0
plotShortShape = plotMode == 'Potential Signals' ? plotShortSignal : strategy.position_size < 0 and strategy.position_size[1] >= 0

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

var float longSL  = na
var float shortSL = na
if strategy.position_size > 0
    longSL := math.max(longSL, high - trailPointsLong)
else
    longSL := na
plot(longSL, color=color.green, style=plot.style_stepline, title='Long SL')

if strategy.position_size < 0
    shortSL := math.min(shortSL, low + trailPointsShort)
else
    shortSL := na
plot(shortSL, color=color.red, style=plot.style_stepline, title='Short SL')

bgcolor(timeWindow ? color.new(color.blue, 95) : na, title="Trading Hours Highlight")
if plotLongShape
    label.new(bar_index, low, "Buy", yloc=yloc.belowbar, color=color.green, textcolor=color.white, style=label.style_label_up)
if plotShortShape
    label.new(bar_index, high, "Sell", yloc=yloc.abovebar, color=color.red, textcolor=color.white, style=label.style_label_down)

// === DEBUG TABLE ===
var table debugTable = table.new(position.top_right, 3, 10, bgcolor=color.rgb(0, 0, 0, 80), border_color=color.white, border_width=1)
if barstate.islast
    table.cell(debugTable, 0, 0, 'Signal', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(debugTable, 1, 0, 'Status', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(debugTable, 2, 0, 'Priority', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))

    table.cell(debugTable, 0, 1, 'MA Long', text_color=color.blue)
    table.cell(debugTable, 1, 1, bullMA ? 'Yes' : 'No', text_color=bullMA ? color.green : color.red)
    table.cell(debugTable, 2, 1, signalPriority == 'MA' ? 'High' : 'Low', text_color=color.white)

    table.cell(debugTable, 0, 2, 'MA Short', text_color=color.blue)
    table.cell(debugTable, 1, 2, bearMA ? 'Yes' : 'No', text_color=bearMA ? color.green : color.red)
    table.cell(debugTable, 2, 2, signalPriority == 'MA' ? 'High' : 'Low', text_color=color.white)

    table.cell(debugTable, 0, 3, 'Bull Pattern', text_color=color.blue)
    table.cell(debugTable, 1, 3, bullPattern ? 'Yes' : 'No', text_color=bullPattern ? color.green : color.red)
    table.cell(debugTable, 2, 3, signalPriority == 'Pattern' ? 'High' : 'Low', text_color=color.white)

    table.cell(debugTable, 0, 4, 'Bear Pattern', text_color=color.blue)
    table.cell(debugTable, 1, 4, bearPattern ? 'Yes' : 'No', text_color=bearPattern ? color.green : color.red)
    table.cell(debugTable, 2, 4, signalPriority == 'Pattern' ? 'High' : 'Low', text_color=color.white)

    table.cell(debugTable, 0, 5, 'Filters', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(debugTable, 1, 5, 'Status', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(debugTable, 2, 5, '', text_color=color.white, bgcolor=color.rgb(50, 50, 50))

    table.cell(debugTable, 0, 6, 'Time Window', text_color=color.blue)
    table.cell(debugTable, 1, 6, timeWindow ? 'OK' : 'Closed', text_color=timeWindow ? color.green : color.red)
    table.cell(debugTable, 2, 6, str.tostring(currentHour) + 'h', text_color=color.white)

    table.cell(debugTable, 0, 7, 'Volume', text_color=color.blue)
    table.cell(debugTable, 1, 7, volumeOk ? 'OK' : 'Low', text_color=volumeOk ? color.green : color.red)
    table.cell(debugTable, 2, 7, str.tostring(volume, '#'), text_color=color.white)

    table.cell(debugTable, 0, 8, 'Volatility', text_color=color.blue)
    table.cell(debugTable, 1, 8, volatilityOk ? 'OK' : 'High', text_color=volatilityOk ? color.green : color.red)
    table.cell(debugTable, 2, 8, str.tostring(volatility * 100, '#.##') + '%', text_color=color.white)

    table.cell(debugTable, 0, 9, 'Signals', text_color=color.blue)
    table.cell(debugTable, 1, 9, longCondition and not shortCondition ? 'LONG' : shortCondition and not longCondition ? 'SHORT' : longCondition and shortCondition ? 'CONFLICT' : 'NONE', text_color=longCondition and not shortCondition ? color.green : shortCondition and not longCondition ? color.red : color.yellow)
    table.cell(debugTable, 2, 9, canEnter ? alertSent ? 'Sent' : 'Ready' : 'Cooldown', text_color=canEnter ? alertSent ? color.yellow : color.green : color.gray)

// === PERFORMANCE DASHBOARD ===
var table dashboard = table.new(position.bottom_left, 3, 3, bgcolor=color.rgb(0, 0, 0, 80), border_color=color.white, border_width=1)
if barstate.islast
    table.cell(dashboard, 0, 0, 'Position', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(dashboard, 1, 0, 'P/L', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))
    table.cell(dashboard, 2, 0, 'Statistics', text_color=color.rgb(168, 168, 168), bgcolor=color.rgb(50, 50, 50))

    table.cell(dashboard, 0, 1, strategy.position_size > 0 ? 'Long' : strategy.position_size < 0 ? 'Short' : 'Flat', text_color=strategy.position_size > 0 ? color.green : strategy.position_size < 0 ? color.red : color.blue)
    table.cell(dashboard, 1, 1, str.tostring(strategy.netprofit, '#.##'), text_color=strategy.netprofit >= 0 ? color.green : color.red)
    table.cell(dashboard, 2, 1, 'Win Rate', text_color=color.white)

    table.cell(dashboard, 0, 2, strategy.position_size != 0 ? 'Bars: ' + str.tostring(bar_index - entryBarIndex) : '', text_color=color.white)
    table.cell(dashboard, 1, 2, strategy.position_size != 0 ? 'Cooldown: ' + str.tostring(cooldownMinutes) + 'm' : '', text_color=color.white)
    table.cell(dashboard, 2, 2, strategy.closedtrades > 0 ? str.tostring(strategy.wintrades / strategy.closedtrades * 100, '#.##') + '%' : 'N/A', text_color=color.white)

// === CHART TITLE ===
var table titleTable = table.new(position.bottom_right, 1, 1, bgcolor=color.rgb(0, 0, 0, 80), border_color=color.rgb(0, 50, 137), border_width=1)
table.cell(titleTable, 0, 0, "Dskyz - DAFE Trading Systems", text_color=color.rgb(159, 127, 255, 80), text_size=size.large)