적응형 이동 평균 교차 변동성 추적 양적 거래 전략

MA交叉 ATR EMA SMA WMA HMA VWMA 趋势过滤 波动率过滤 跟踪止损 双重止盈
생성 날짜: 2025-05-14 10:49:04 마지막으로 수정됨: 2025-05-14 10:49:04
복사: 0 클릭수: 317
avatar of ianzeng123 ianzeng123
2
집중하다
319
수행원

적응형 이동 평균 교차 변동성 추적 양적 거래 전략 적응형 이동 평균 교차 변동성 추적 양적 거래 전략

전략 개요

자기 적응형 평행선 교차율 변동성을 추적하는 양적 거래 전략은 고주파 거래와 단선 운영을 위해 특별히 설계된 체계화 된 전략이다. 이 전략의 핵심은 빠른 이동 평균 (MA) 과 느린 이동 평균의 교차점을 주요 신호 트리거 포인트로 이용하는 동시에 여러 가지 핵심 필터와 정확한 위험 관리 도구를 결합하여 소규모이지만 빠른 가격 변동을 포착한다. 이 전략의 구성성은 매우 높으며 사용자가 다양한 시장의 리듬에 맞는 거래 요구에 맞게 평균 라인 유형 (EMA, SMA, WMA, HMA, VWMA) 과 주기 파라미터를 유연하게 선택할 수 있습니다.

전략 원칙

이 전략의 핵심 논리는 다음과 같은 몇 가지 핵심 부분으로 나뉘어져 있습니다.

  1. 출입 신호: 주로 빠른 평균선과 느린 평균선의 교차/횡단으로 입시 조건으로 트리거한다. 사용자는 평균선 유형 (EMA, SMA, WMA, HMA, VWMA) 과 주기의 길이를 조정하여 신호의 민감도를 조정하여 다른 시장 상황에 맞게 조정할 수 있다.

  2. 트렌드 필터전략: 전략은 선택적으로 장기 이동 평균선을 큰 트렌드 필터로 사용하여 큰 트렌드 방향으로만 거래되도록하고, 강한 방향의 시장에서 역동적인 짧은 선을 거래하는 것을 피합니다.

  3. 필터 확인

    • ATR 변동율 필터: 극도로 평평한 또는 “죽은” 시장에 일시적으로 입문하기 위해 설계된, 이러한 시장의 변동률은 동적 하위값 이하이다 ((평균 ATR을 기반으로), 추세없는, 낮은 에너지 조건에서 흔들림을 방지하는 데 도움이 된다.
    • 수량 필터: 최저 시장 참여를 요구하여 입시 신호를 검증하기 위해 (거래량과 이동 평균의 비교) 그리고 낮은 유동성 피크 또는 중요하지 않은 가격 행동에 기반한 입시를 피하기 위해.
  4. 위험 관리 패키지

    • 초기 변동률 정지ATR 기반의 초기 손실은 거래 당 위험 정의에 객관적인 출발점을 제공하며, 최근 변동성에 적합합니다.
    • ATR 추적 손실동적인 시장에 중요한 것은, 스톱 라인을 추적하는 것이 유리한 가격 움직임에 따라 조정되어 성공적인 단선 거래의 이익을 보호하고, 흐름이 역전될 때 손실을 비교적 신속하게 줄이는 것입니다.
    • 이윤 손실 균형 중지 (선택): TP1을 달성하거나 가격이 특정 ATR 거리를 이동하면 자동으로 입시 가격으로 스톱로스를 이동할 수 있습니다.
    • 이중 이익 수준: TP1와 TP2 두 가지 수익 목표가 설정되어 있습니다. TP1은 빠른 부분 수익 (예: 50%) 을 위해 설계되었으며, TP2는 나머지 포지션에 더 많은 돈을 벌기 위해 노력하고 있습니다.
  5. 포지션 관리: 고정된 수의 포지션 크기를 채택하여 각 거래의 포지션 크기를 정확하게 제어하는 것은 고주파 환경에서 일관된 위험 응용 프로그램과 API 명령 생성에 중요합니다.

전략적 이점

코드에 대한 심층적인 분석을 통해, 이 전략은 다음과 같은 명백한 장점을 가지고 있습니다:

  1. 고도의 구성성: 사용자는 다양한 변수들을 조정할 수 있습니다. 평균선 유형과 주기, 필터 설정, 위험 관리 변수 등이 포함됩니다. 전략은 다양한 시장 환경과 거래 스타일에 맞게 조정할 수 있습니다.

  2. 다단계 필터링트렌드, 변동, 거래량 필터를 결합하여 잘못된 신호와 시장 소음을 효과적으로 줄이고 거래 품질을 향상시킵니다.

  3. 좋은 위험 관리전략 내장 다중 손해 중지 장치 (초기, 추적, 손해 균형) 과 이중 수익 목표, 정교한 위험 제어 및 이익 보호를 실현한다.

  4. API 친화적 디자인명확하고 명확한 입출장 논리가 명확한 신호를 생성하여 외부 거래 시스템과 통합하여 거의 즉각적인 주문 실행을 가능하게합니다.

  5. 정밀 위치 제어: 고정된 수의 포지션 크기는 API 엔드 포인트의 유효 부하를 간소화하여 자동화 실행을 더 안정적으로 수행한다.

  6. 매우 적응력이 좋다변수 조정으로, 전략은 높은 주파수 짧은 라인 거래 모드에서 더 장기적인 트렌드 추적 모드로 전환할 수 있으며, 다양한 시장 조건과 개인 거래 선호도에 적합합니다.

전략적 위험

이 전략은 훌륭하게 설계되었지만 몇 가지 잠재적 위험과 도전이 있습니다.

  1. 매개변수 최적화 위험전략에는 많은 구성 가능한 매개 변수가 포함되어 있기 때문에, 과도한 최적화는 재검토 결과가 좋지만 실제 성능이 좋지 않은 결과를 초래할 수 있습니다. 투자자는 샘플 외의 데이터에서 검증하거나 전향 테스트를 통해이 위험을 피해야합니다.

  2. 거래 비용의 영향높은 주파수 거래는 많은 거래, 누적 된 수수료 및 슬라이드 포인트가 순 수익성에 크게 영향을 미칠 수 있음을 의미하며, 사용 전에 설정 및 재검토에서 이러한 비용을 정확하게 계산하는 것이 중요합니다.

  3. 신호 질의 변동: 다른 시장 조건에 따라 평행선 교차 신호의 신뢰도는 달라질 수 있으며, 특히 수평선 흔들림이나 높은 변동성이 있는 시장에서 달라질 수 있다.

  4. 기술 의존성: API 준비 전략으로서, 그것의 유효성은 실행 속도와 기술 안정성에 부분적으로 달려 있으며, 시스템 지연 또는 장애는 기회를 잃거나 실행 편향을 초래할 수 있다.

  5. 자금 규모 제한: 고정된 포지션 규모는 모든 계정 규모에 적합하지 않을 수 있으며, 소규모 계정은 과도한 위험에 처할 수 있으며, 큰 계정은 자금을 충분히 활용하지 못할 수 있습니다.

전략 최적화 방향

전략적 설계와 잠재적인 위험에 따라 몇 가지 최적화 방향은 다음과 같습니다.

  1. 적응 변수: 핵심 매개 변수 (ATR 곱하기 및 평균 주기와 같은) 를 시장 조건에 따라 자동으로 조정하도록 설계하여 다양한 시장 단계에서 전략의 적응성을 향상시킵니다.

  2. 지능형 필터링: 추가적인 시장 상태 지표 (시장 구조, 변동 패턴 식별 또는 관련 자산의 연관성) 를 통합하여 필터의 정확성을 더욱 향상시킵니다.

  3. 동적 위치 관리: 계정 규모, 현재 변동성 및 최근 전략적 성과에 기반한 동적 포지션을 계산하여 고정된 포지션 수를 대체하여 더 지능적인 자금 관리를 구현한다.

  4. 다중 시간 프레임 확인다른 시간 프레임에서 신호를 검증하여 거래 방향이 더 큰 시장 구조와 일치하는지 확인하고 불필요한 거래를 줄입니다.

  5. 기계학습 통합: 기계 학습 알고리즘을 사용하여 역사적 신호 성능을 분석하고, 미래의 신호의 성공 가능성을 예측하고, 높은 성공률 거래를 우선적으로 수행한다.

  6. 트레이딩 세션 관리거래 시간 필터를 추가하여 낮은 유동성 또는 높은 변동성을 피하고 시장에서 가장 효율적인 거래 창에 집중하십시오.

  7. 연관성 필터다자산 거래에 대해 관련 시장의 연관성 분석을 추가하고 특정 위험 요소에 과도한 노출을 피하십시오.

요약하다

적응형 평평선 교차 변동률 추적 수량 거래 전략은 평평선 교차로 트리거 신호를 통해 여러 가지 핵심 필터와 정밀한 위험 관리 도구를 결합하여 소규모이지만 빠른 가격 변동을 포착하기 위해 고도로 설계된 기능이있는 고주파 거래 시스템입니다. 이 전략의 강점은 매우 구성 가능하고 완벽한 위험 관리 프레임 워크로 인해 거래자가 개인 위험 용인성과 시장 조건에 따라 거래 매개 변수를 정밀하게 조정할 수 있습니다.

이 전략은 명확한 입출력 논리와 외부 실행 플랫폼과의 원활한 통합을 제공하며, 이는 급변하는 시장에서 신속한 의사결정을 수행하는 데 중요합니다. 그러나 이 전략을 사용할 때 거래 비용의 누적 및 과도한 최적화의 위험에 대한 특별한 주의를 기울여야 하며, 실제 거래에서 전략의 건전성과 수익성을 유지하도록해야합니다.

궁극적으로, 이 전략은 기술 지표와 위험 관리 도구의 힘을 활용하면서 변화하는 시장 조건에 적응할 수 있는 충분한 유연성을 유지하면서 균형 잡힌 접근법을 나타냅니다. 신중한 매개 변수 조정과 지속적인 모니터링 개선으로 이 전략은 양적 거래 포트폴리오의 가치있는 구성 요소가 될 수 있습니다.

전략 소스 코드
/*backtest
start: 2024-05-14 00:00:00
end: 2025-05-12 08:00:00
period: 2d
basePeriod: 2d
exchanges: [{"eid":"Futures_Binance","currency":"DOGE_USDT"}]
*/

//@version=5
// © ArrowTrade x:ArrowTrade

// --- STRATEGY DEFINITION ---
strategy(
     title="Arrow's Flexible MA Cross Strategy [API Ready]", // Added branding
     shorttitle="ArrowFlex",                  // Added branding
     overlay=true,
     initial_capital=1000, // Example capital, user should adjust
     commission_type=strategy.commission.percent,
     commission_value=0.036, // Example commission, user MUST adjust to their broker/exchange
     slippage=2,             // Example slippage (in ticks), user should adjust based on asset/broker
     process_orders_on_close=true, // Calculates/executes on bar close. Set to false for intrabar (use with caution & specific logic)
     pyramiding=0,           // No pyramiding allowed (one entry per direction)
     default_qty_type=strategy.fixed // Defaulting to fixed quantity
     // Removed default_qty_value from here
     )

// ================================================================================
//  Strategy Description (for TradingView Public Library & Users)
// ================================================================================
// © ArrowTrade
//
// A configurable Moving Average Crossover strategy designed for flexibility and
// API integration.
//
// Features:
// - MA Crossover Entries: Uses configurable Fast/Slow MA crossovers for signals.
// - Trend Filter: Optional longer-term MA filter to trade only with the trend.
// - Volatility Filter: Optional ATR filter to avoid low-volatility periods.
// - Volume Filter: Optional Volume filter to confirm entries with sufficient volume.
// - Stop Loss Options:
//     - Initial Volatility Stop (ATR-based)
//     - ATR Trailing Stop
//     - Break-Even Stop (activated by TP1 hit or ATR distance)
// - Take Profit Options:
//     - Two independent TP levels (percentage-based).
//     - Configurable partial close percentage at TP1.
// - Position Sizing: Fixed quantity per trade (adjustable).
//
// Intended Use:
// While configurable for various styles (scalping to trend-following by adjusting
// parameters), this strategy is built with API automation in mind. The clear
// entry and exit logic facilitates integration with external execution platforms
// via webhooks or other methods. Parameters can be tightened (shorter MAs,
// tighter stops/TPs, specific filters) for higher-frequency signals suitable
// for scalping.
//
// Disclaimer:
// Backtesting results are hypothetical and do not guarantee future performance.
// Market conditions change constantly. Always perform your own due diligence,
// forward testing, and rigorous risk management before trading live with any
// strategy. Ensure you adjust inputs like commission, slippage, and position
// size to accurately reflect your specific broker/exchange and risk profile.
// ================================================================================


// === INPUTS (Grouped and Ordered by Importance/Function) ===

// --- 1. Core Signal & Trend Filter ---
grp_signal = "1. Core Signal & Trend Filter"
signalSource   = input.source(high, title="Signal Source", group=grp_signal, tooltip="Price source for calculating the signal MAs (e.g., close, hl2, ohlc4). 'hlc3' or 'ohlc4' can provide smoother signals.")
signalMaType   = input.string("EMA", title="Signal MA Type", options=["EMA", "SMA", "WMA", "HMA", "VWMA"], group=grp_signal, tooltip="Type of Moving Average used for the fast/slow signal lines (EMA reacts faster, SMA smoother, HMA reduces lag).")
signalFastLen  = input.int(12, title="Fast MA Period", minval=2, maxval=100, step=1, group=grp_signal, tooltip="Period for the shorter-term signal MA. Shorter periods lead to more frequent signals (potentially more noise/scalping).")
signalSlowLen  = input.int(25, title="Slow MA Period", minval=3, maxval=200, step=1, group=grp_signal, tooltip="Period for the longer-term signal MA. Must be greater than Fast MA Period. Defines the crossover signal.")
useTrendFilter = input.bool(true, title="Enable Trend Filter", group=grp_signal, tooltip="If enabled, entry signals are only taken in the direction of the longer-term trend defined by the Trend MA.")
trendMaType    = input.string("EMA", title="Trend MA Type", options=["EMA", "SMA", "WMA", "HMA", "VWMA"], group=grp_signal, tooltip="Type of Moving Average used for the trend filter.")
trendMaLen     = input.int(100, title="Trend MA Period", minval=50, maxval=500, step=10, group=grp_signal, tooltip="Period for the Trend MA. Significantly longer than signal MAs typically. Higher values filter more aggressively.")
trendMaSource  = input.source(hl2, title="Trend MA Source", group=grp_signal, tooltip="Price source for the Trend MA calculation.")

// --- 2. Risk Management: Stop Loss ---
grp_stop = "2. Risk Management: Stop Loss"
useVolatilityStop    = input.bool(true, title="Enable Initial Volatility Stop", group=grp_stop, tooltip="Sets the initial stop loss based on Average True Range (ATR) at the time of entry.")
volStopAtrPeriod     = input.int(7, title="   Initial Stop ATR Period", minval=1, maxval=50, step=1, group=grp_stop, tooltip="ATR lookback period for calculating the initial stop distance.")
volStopAtrMultiplier = input.float(5, title="   Initial Stop ATR Multiplier", minval=0.5, maxval=10, step=0.1, group=grp_stop, tooltip="Multiplier for the ATR value to determine stop distance (Stop = Entry +/- ATR * Multiplier). Lower values = tighter initial stop.")
useTrailingStop      = input.bool(true, title="Enable ATR Trailing Stop", group=grp_stop, tooltip="If enabled, the stop loss will trail behind price based on current ATR, potentially locking in profits. Can override the initial/BE stop if it moves favorably.")
trailAtrPeriod       = input.int(15, title="   Trailing ATR Period", minval=1, maxval=50, step=1, group=grp_stop, tooltip="ATR lookback period for calculating the trailing distance.")
trailAtrMultiplier   = input.float(4.0, title="   Trailing ATR Multiplier", minval=0.5, maxval=10, step=0.1, group=grp_stop, tooltip="Multiplier for the current ATR to determine trailing distance. Lower values trail tighter.")
useBreakEvenStop     = input.bool(false, title="Enable Break-Even Stop", group=grp_stop, tooltip="If enabled, moves the stop loss to entry price (plus a small profit buffer) once a certain condition is met.")
beActivationChoice   = input.string("TP1 Reached", title="   BE Activation Condition", options=["TP1 Reached", "ATR Distance Moved"], group=grp_stop, tooltip="When should the Break-Even Stop activate? When TP1 is hit, or when price moves a certain ATR distance from entry?")
beActivationAtrMult  = input.float(1.5, title="   BE Activation ATR Multiplier", minval=0.1, maxval=5, step=0.1, group=grp_stop, tooltip="Used only if 'ATR Distance Moved' is selected. BE activates if price moves (Entry +/- ATR * Multiplier). Uses 'Initial Stop ATR Period'.")
beProfitTicks        = input.int(2, title="   BE Profit Buffer (Ticks)", minval=0, maxval=50, step=1, group=grp_stop, tooltip="Moves the stop to Entry Price +/- this many ticks (e.g., to cover commissions). Set to 0 for exact entry price.")

// --- 3. Risk Management: Take Profit ---
grp_tp = "3. Risk Management: Take Profit (TP)"
useTp1        = input.bool(true, title="Enable TP1", group=grp_tp, tooltip="Enable the first Take Profit level.")
tp1Pct        = input.float(1.5, title="   TP1 Target (%)", minval=0.1, maxval=20, step=0.1, group=grp_tp, tooltip="First TP target as a percentage distance from the entry price. Should be less than TP2 %.")
tp1QtyPercent = input.int(50, title="   TP1 Close Quantity (%)", minval=1, maxval=100, step=5, group=grp_tp, tooltip="Percentage of the original position size to close when TP1 is hit.")
useTp2        = input.bool(true, title="Enable TP2", group=grp_tp, tooltip="Enable the second (final) Take Profit level.")
tp2Pct        = input.float(3.0, title="   TP2 Target (%)", minval=0.2, maxval=30, step=0.1, group=grp_tp, tooltip="Second TP target as a percentage distance from the entry price. Closes the remaining position.")

// --- 4. Additional Filters ---
grp_filters = "4. Additional Filters"
useAtrFilter        = input.bool(true, title="Enable ATR Volatility Filter", group=grp_filters, tooltip="If enabled, avoids entries during periods of very low volatility (ATR below a moving average of ATR). Helps filter choppy/sideways markets.")
atrFilterPeriod     = input.int(14, title="   ATR Filter Period", minval=1, maxval=50, step=1, group=grp_filters, tooltip="Lookback period for calculating the current ATR and its average for the filter.")
atrFilterMultiplier = input.float(0.5, title="   ATR Filter Threshold Multiplier", minval=0.1, maxval=5, step=0.1, group=grp_filters, tooltip="Entry requires current ATR to be >= (Average ATR * Multiplier). Lower values filter more aggressively.")
useVolumeFilter     = input.bool(true, title="Enable Volume Filter", group=grp_filters, tooltip="If enabled, requires the volume of the entry bar to be above a moving average of volume. Acts as confirmation.")
volumeLookback      = input.int(30, title="   Volume MA Period", minval=2, maxval=100, step=1, group=grp_filters, tooltip="Lookback period for calculating the average volume.")
volumeMultiplier    = input.float(1.0, title="   Min Volume Ratio (vs Avg)", minval=0.1, maxval=5, step=0.1, group=grp_filters, tooltip="Entry requires current volume to be >= (Average Volume * Multiplier). Values >= 1 require above-average volume.")

// --- 5. Position Sizing ---
grp_size = "5. Position Sizing"
// Define the quantity input with its own default value
qtyValue = input.float(0.01, title="Position Size (Fixed Qty)", minval=0.0001, step=0.0001, group=grp_size, tooltip="Fixed quantity (contracts/shares/lots) per trade. Adjust based on your account size, risk tolerance, and the asset being traded. Can be overridden by API.")


// === FUNCTIONS ===
f_ma(maType, src, len) =>
    float result = na
    if maType == "SMA"
        result := ta.sma(src, len)
    else if maType == "EMA"
        result := ta.ema(src, len)
    else if maType == "WMA"
        result := ta.wma(src, len)
    else if maType == "HMA"
        result := ta.hma(src, len)
    else if maType == "VWMA"
        result := ta.vwma(src, len)
    result

// === CORE CALCULATIONS ===

// Parameter Sanity Check
if signalSlowLen <= signalFastLen and barstate.islast
    runtime.error("Signal Slow MA Period must be greater than Fast MA Period!")

// 1. Moving Averages
float fastMA = f_ma(signalMaType, signalSource, signalFastLen)
float slowMA = f_ma(signalMaType, signalSource, signalSlowLen)
float trendMA = useTrendFilter ? f_ma(trendMaType, trendMaSource, trendMaLen) : na

// 2. ATR Values
float atrValueStop = ta.atr(volStopAtrPeriod)
float atrValueTrail = ta.atr(trailAtrPeriod)
float atrValueFilter = ta.atr(atrFilterPeriod)
float atrValueBE = ta.atr(volStopAtrPeriod)

// 3. Filter Conditions
bool trendFilterOK_L = not useTrendFilter or (not na(trendMA) and signalSource > trendMA)
bool trendFilterOK_S = not useTrendFilter or (not na(trendMA) and signalSource < trendMA)
float avgAtrFilter = ta.sma(atrValueFilter, atrFilterPeriod)
bool volatilityFilterOK = not useAtrFilter or (not na(atrValueFilter) and not na(avgAtrFilter) and atrValueFilter >= avgAtrFilter * atrFilterMultiplier)
float avgVolume = ta.sma(volume, volumeLookback)
bool volumeFilterOK = not useVolumeFilter or (not na(volume) and not na(avgVolume) and volume >= avgVolume * volumeMultiplier)
bool finalFilterOK_L = trendFilterOK_L and volatilityFilterOK and volumeFilterOK
bool finalFilterOK_S = trendFilterOK_S and volatilityFilterOK and volumeFilterOK

// 4. Entry Signals
bool longCross = not na(fastMA) and not na(slowMA) and ta.crossover(fastMA, slowMA)
bool shortCross = not na(fastMA) and not na(slowMA) and ta.crossunder(fastMA, slowMA)
bool longEntrySignal = longCross and finalFilterOK_L
bool shortEntrySignal = shortCross and finalFilterOK_S

// === STRATEGY EXECUTION LOGIC ===

// --- State Variables (persisted between bars) ---
var float entryPriceVar = na
var float initialStopPrice = na
var float currentStopPrice = na
var float trailStopLevel = na
var bool isBEActive = false
var bool tp1Reached = false
var float qtyToCloseTp1_Var = na

// --- Position Status ---
bool inLong = strategy.position_size > 0
bool inShort = strategy.position_size < 0
bool inTrade = strategy.position_size != 0

// --- Reset State Variables on Trade Exit ---
if not inTrade and inTrade[1]
    entryPriceVar := na
    initialStopPrice := na
    currentStopPrice := na
    trailStopLevel := na
    isBEActive := false
    tp1Reached := false
    qtyToCloseTp1_Var := na

// --- Handle New Entries ---
if longEntrySignal and not inTrade
    strategy.entry("Long Entry", strategy.long, qty=qtyValue) // Use qtyValue from input

if shortEntrySignal and not inTrade
    strategy.entry("Short Entry", strategy.short, qty=qtyValue) // Use qtyValue from input


// --- Manage Stops and Take Profits for Open Positions ---
if inTrade
    // Initialize state on the bar immediately AFTER entry
    if na(entryPriceVar)
        entryPriceVar := strategy.position_avg_price
        float positionQty = strategy.position_size

        if not na(positionQty) and tp1QtyPercent > 0 and useTp1
            qtyToCloseTp1_Var := math.abs(positionQty * tp1QtyPercent / 100)
        else
            qtyToCloseTp1_Var := 0.0

        if useVolatilityStop and not na(atrValueStop)
            initialStopPrice := entryPriceVar + (inLong ? -1 : 1) * atrValueStop * volStopAtrMultiplier
            currentStopPrice := initialStopPrice
        else
            initialStopPrice := na
            currentStopPrice := na

        if useTrailingStop and not na(atrValueTrail)
            trailStopLevel := entryPriceVar + (inLong ? -1 : 1) * atrValueTrail * trailAtrMultiplier
        else
            trailStopLevel := na

        isBEActive := false
        tp1Reached := false

    // --- Calculations within the trade (if entry price is set) ---
    if not na(entryPriceVar)

        // 1. Calculate TP Levels for the current bar
        float tp1LevelL = na, float tp2LevelL = na, float tp1LevelS = na, float tp2LevelS = na
        if useTp1
            tp1LevelL := entryPriceVar * (1 + tp1Pct / 100)
            tp1LevelS := entryPriceVar * (1 - tp1Pct / 100)
        if useTp2
            tp2LevelL := entryPriceVar * (1 + tp2Pct / 100)
            tp2LevelS := entryPriceVar * (1 - tp2Pct / 100)

        // 2. Check and Activate Break-Even Stop
        if useBreakEvenStop and not isBEActive and not na(currentStopPrice)
            float beTriggerL = na, float beTriggerS = na
            if beActivationChoice == "TP1 Reached" and useTp1
                if not na(tp1LevelL)
                    beTriggerL := tp1LevelL
                if not na(tp1LevelS)
                    beTriggerS := tp1LevelS
            else if beActivationChoice == "ATR Distance Moved" and not na(atrValueBE)
                beTriggerL := entryPriceVar + atrValueBE * beActivationAtrMult
                beTriggerS := entryPriceVar - atrValueBE * beActivationAtrMult

            float beTargetLevel = entryPriceVar + (inLong ? 1 : -1) * beProfitTicks * syminfo.mintick

            if not na(beTriggerL) and not na(beTargetLevel) and inLong and high >= beTriggerL and beTargetLevel > currentStopPrice
                currentStopPrice := beTargetLevel
                isBEActive := true
            if not na(beTriggerS) and not na(beTargetLevel) and inShort and low <= beTriggerS and beTargetLevel < currentStopPrice
                currentStopPrice := beTargetLevel
                isBEActive := true

        // 3. Update Trailing Stop
        if useTrailingStop and not na(currentStopPrice) and not na(atrValueTrail)
            float newTrailStopL = low - atrValueTrail * trailAtrMultiplier
            float newTrailStopS = high + atrValueTrail * trailAtrMultiplier
            float prevTrail = trailStopLevel[1]
            float calculatedNewTrail = na

            if inLong
                calculatedNewTrail := na(prevTrail) ? newTrailStopL : math.max(prevTrail, newTrailStopL)
                if not na(calculatedNewTrail)
                    trailStopLevel := calculatedNewTrail
                if not na(trailStopLevel) and trailStopLevel > currentStopPrice
                    currentStopPrice := trailStopLevel
            if inShort
                calculatedNewTrail := na(prevTrail) ? newTrailStopS : math.min(prevTrail, newTrailStopS)
                if not na(calculatedNewTrail)
                    trailStopLevel := calculatedNewTrail
                if not na(trailStopLevel) and trailStopLevel < currentStopPrice
                    currentStopPrice := trailStopLevel

        // --- Execute Exits ---

        // 4. Apply Stop Loss Exit
        if not na(currentStopPrice)
            bool isTrailingActiveNow = useTrailingStop and not na(trailStopLevel) and currentStopPrice == trailStopLevel
            string stop_comment = isBEActive ? "BE Stop" : (isTrailingActiveNow ? "Trail Stop" : "Vol Stop")
            if inLong
                strategy.exit("SL Exit L", from_entry="Long Entry", stop=currentStopPrice, comment=stop_comment + " L")
            if inShort
                strategy.exit("SL Exit S", from_entry="Short Entry", stop=currentStopPrice, comment=stop_comment + " S")

        // 5. Apply Take Profit Exits
        // TP1 Exit (Partial Quantity)
        if useTp1 and not tp1Reached and not na(qtyToCloseTp1_Var) and qtyToCloseTp1_Var > 0
            if inLong and not na(tp1LevelL)
                strategy.exit("TP1 Exit L", from_entry="Long Entry", qty=qtyToCloseTp1_Var, limit=tp1LevelL, comment="TP1 Hit L")
                if high >= tp1LevelL
                    tp1Reached := true
            if inShort and not na(tp1LevelS)
                strategy.exit("TP1 Exit S", from_entry="Short Entry", qty=qtyToCloseTp1_Var, limit=tp1LevelS, comment="TP1 Hit S")
                if low <= tp1LevelS
                    tp1Reached := true

        // TP2 Exit (Remaining Quantity)
        if useTp2
            if inLong and not na(tp2LevelL)
                strategy.exit("TP2 Exit L", from_entry="Long Entry", limit=tp2LevelL, comment="TP2 Hit L")
            if inShort and not na(tp2LevelS)
                strategy.exit("TP2 Exit S", from_entry="Short Entry", limit=tp2LevelS, comment="TP2 Hit S")


// === PLOTTING ===

// 1. Moving Averages
plot(fastMA, "Fast MA", color=color.new(color.aqua, 0), linewidth=1)
plot(slowMA, "Slow MA", color=color.new(color.fuchsia, 0), linewidth=1)
plot(useTrendFilter and not na(trendMA) ? trendMA : na, "Trend MA", color=color.new(color.gray, 0), linewidth=2, style=plot.style_cross)

// 2. Active Stop Loss Level
color stopColor = color.new(color.red, 0)
bool isTrailingActivePlot = useTrailingStop and not na(trailStopLevel) and not na(currentStopPrice) and currentStopPrice == trailStopLevel
if isBEActive
    stopColor := color.new(color.orange, 0)
else if isTrailingActivePlot
    stopColor := color.new(color.blue, 0)
plot(inTrade and not na(currentStopPrice) ? currentStopPrice : na, "Active Stop Loss", stopColor, style=plot.style_linebr, linewidth=2)

// 3. Take Profit Levels
float plot_tp1LevelL = na, float plot_tp1LevelS = na, float plot_tp2LevelL = na, float plot_tp2LevelS = na
if not na(entryPriceVar)
    if useTp1
        plot_tp1LevelL := entryPriceVar * (1 + tp1Pct / 100)
        plot_tp1LevelS := entryPriceVar * (1 - tp1Pct / 100)
    if useTp2
        plot_tp2LevelL := entryPriceVar * (1 + tp2Pct / 100)
        plot_tp2LevelS := entryPriceVar * (1 - tp2Pct / 100)
plot(inTrade and useTp1 and not na(inLong ? plot_tp1LevelL : plot_tp1LevelS) ? (inLong ? plot_tp1LevelL : plot_tp1LevelS) : na, "TP1 Level", color=color.new(color.green, 30), style=plot.style_linebr, linewidth=1)
plot(inTrade and useTp2 and not na(inLong ? plot_tp2LevelL : plot_tp2LevelS) ? (inLong ? plot_tp2LevelL : plot_tp2LevelS) : na, "TP2 Level", color=color.new(color.green, 0), style=plot.style_linebr, linewidth=1)

// 4. Entry Signal Markers
plotshape(longEntrySignal, title="Long Entry Signal", location=location.belowbar, color=color.new(color.green, 0), style=shape.triangleup, size=size.small)
plotshape(shortEntrySignal, title="Short Entry Signal", location=location.abovebar, color=color.new(color.red, 0), style=shape.triangledown, size=size.small)

// 5. Background Color Filters
bgcolor(useTrendFilter and not na(trendMA) and inTrade ? (inLong ? color.new(color.blue, 90) : color.new(color.red, 90)) : na, title="Trend Filter Active")
bgcolor(useAtrFilter and not volatilityFilterOK ? color.new(color.gray, 85) : na, title="Low Volatility Filter Active")
bgcolor(useVolumeFilter and not volumeFilterOK ? color.new(color.yellow, 90) : na, title="Low Volume Filter Active")