Адаптивная многоиндикаторная система торговли по тренду с волатильностью

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. Опознание формы падения: Система способна распознавать сильные позиционные или bearish поглощение формы, и в сочетании с объемом торговли и диапазона интенсивность для проверки. Чтобы избежать ложных сигналов, система будет пропускать торговлю, когда два противоположных формы одновременно.

  4. Подтверждение многочасовой тенденции: выборочно выравнивать торговые сигналы с трендами SMA на 15-минутных временных циклах, добавлять один уровень подтверждения и повышать качество торгов.

  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 и т. Д.), настройки этих параметров оказывают значительное влияние на производительность, а неправильное сочетание параметров может привести к перенастройке исторических данных.

Решение проблемы: проводить широкий спектр тестов на оптимизацию параметров, но избегать переоптимизации; использовать тестирование на ходу (walk-forward testing) и тестирование вне образца для проверки устойчивости стратегии.

  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)