적응형 변동성 다중 지표 추세 추종 거래 시스템

ATR SMA RSI DCA 烛台模式 趋势跟踪 波动率适应 多时间周期 止损 止盈
생성 날짜: 2025-04-11 13:41:56 마지막으로 수정됨: 2025-04-11 13:41:56
복사: 3 클릭수: 378
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

적응형 변동성 다중 지표 추세 추종 거래 시스템 적응형 변동성 다중 지표 추세 추종 거래 시스템

개요

자조적 변동율 다중 지표 트렌드 추적 거래 시스템은 고 변동성 시장에 설계된 정량 거래 전략으로, 동적으로 조정된 기술 지표와 고급 위험 관리 메커니즘을 결합한다. 이 전략의 핵심은 ATR (평균 실제 파동) 을 통해 이동 평균선 파라미터를 동적으로 조정하여 시장 변동에 대한 자조를 구현하는 것과 동시에 RSI 오버 바이 오버 세일 필터, 기판 형식, 다중 시간 주기 트렌드 확인 및 단계적 포지션 구축 (DCA) 등의 기능을 통합하여 포괄적인 거래 프레임워크를 형성한다. 이 전략은 특히 선물 시장과 같은 고 변동 환경에는 적합하며, 일일 거래 및 파동 거래 부문에 유연한 운영 모드를 제공합니다.

전략 원칙

이 전략의 핵심은 다음과 같은 핵심 모듈을 기반으로 합니다.

  1. 적응형 이동평선 시스템전략: 빠른 및 느린 간단한 이동 평균선 ((SMA) 을 사용하며, 그 길이는 ATR에 의해 동적으로 조정된다. 높은 파동 환경에서 평균선 길이는 시장의 변화에 신속하게 반응하기 위해 짧아집니다. 낮은 파동 환경에서 평균선 길이는 소음을 줄이기 위해 길어집니다. 긴 신호는 빠른 평균선에서 느린 평균선을 통과하고 가격을 확인 할 때 발생합니다.

  2. RSI 동력 필터: RSI (대비적으로 강한 지표) 를 통해 진입 신호를 검증하여 거래 방향이 시장 운동과 일치하는지 확인합니다. 이 기능은 선택적으로 켜거나 닫을 수 있으며, 사용자 정의 RSI 파라미터를 지원합니다.

  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 값 등) 이 파라미터들의 설정은 성능에 중대한 영향을 미치며, 부적절한 파라미터 조합은 역사 데이터에 과도하게 적응할 수 있다.

해결 방법: 광범위한 변수 최적화 테스트를 수행하지만 과도한 최적화를 피한다. 전략의 안정성을 검증하기 위해 도보 테스트 (walk-forward testing) 와 샘플 외 테스트를 사용합니다.

  1. 시장 전환의 위험시장 패턴이 급격히 변할 때 (예를 들어, 트렌드에서 변동으로), 전략은 새로운 환경에 적응하기 전에 연속적인 손실을 초래할 수 있다.

해결 방법: 시장 상태를 식별하는 메커니즘을 추가하는 것을 고려하고, 다른 시장 환경에서 다른 파라미터 세트를 사용하십시오. 하루 최대 손실 또는 연속 손실 후 거래 중단과 같은 전체적인 위험 제한을 적용하십시오.

  1. 슬라이드 포인트와 유동성 문제: 고주파 거래와 변동성이 높은 시장은 미끄러짐의 증가와 유동성의 감소의 위험에 직면할 수 있습니다.

해결 방법: 재검토에 실제 슬라이드 포인트와 수수료 추정치를 포함; 유동성이 낮은 시간에 거래를 피; 시장 가격 대신 제한 가격 목록을 사용하는 것을 고려.

  1. 시스템 복잡성여러 계층의 논리와 조건의 조합은 전략의 복잡성을 증가시키고 이해와 유지에 어려움을 줄 수 있습니다.

해결 방법: 정책으로 제공되는 디부팅 도구를 사용하여 각 구성 요소의 성능을 면밀히 모니터링하십시오. 좋은 코드 코멘트를 유지하십시오. 모듈 테스트로 각 구성 요소의 독립적 인 효과를 고려하십시오.

  1. 과도한 거래의 위험DCA 메커니즘과 빈번한 신호 생성으로 인해 과도한 거래가 발생하여 거래 비용이 증가할 수 있습니다.

*해결 방법*적당한 냉각 기간과 최소 보유 기간을 설정하고, 재검토에서 거래 비용을 엄격하게 고려하고, 입시 기준을 정기적으로 검토하고 최적화합니다.

최적화 방향

  1. 기계 학습 강화: 베이스 최적화 또는 유전 알고리즘과 같은 자율적 변수 최적화 알고리즘을 도입하여 서로 다른 시장 환경에 대해 최적의 변수 조합을 자동으로 찾습니다. 이것은 수동 최적화의 필요성을 줄이고 시장 변화에 대한 전략의 적응력을 향상시킵니다.

  2. 시장 환경 분류: 시장 상태 분류 시스템을 개발 (트렌드, 흔들림, 높은 변동, 낮은 변동 등) 하고, 각 상태에 대해 최적의 매개 변수 구성을 미리 설정한다. 이 방법은 시장이 변할 때 전략 행동을 더 빠르게 조정하고, 적응 지연을 줄일 수 있다.

  3. 강화된 포지션 관리: 더 복잡한 포지션 관리 알고리즘을 도입하여, 케일리 규칙이나 동력 강도에 기반한 동적 포지션 조정과 같은 것. 이것은 자금 활용을 최적화하고, 강한 신호가 있을 때 노출을 증가시키고, 약한 신호가 있을 때 위험을 줄일 수 있다.

  4. 대안 지표 통합다른 기술 지표의 유효성을 테스트합니다. 예를 들어 볼린저 대역, MACD 또는 이치모쿠 클라우드 그래프와 같은 기존 시스템을 보완하거나 대체합니다. 특정 시장 조건에서 다른 지표는 더 정확한 신호를 제공 할 수 있습니다.

  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)