適応型移動平均クロスオーバーボラティリティトラッキング定量取引戦略

MA交叉 ATR EMA SMA WMA HMA VWMA 趋势过滤 波动率过滤 跟踪止损 双重止盈
作成日: 2025-05-14 10:49:04 最終変更日: 2025-05-14 10:49:04
コピー: 0 クリック数: 317
2
フォロー
319
フォロワー

適応型移動平均クロスオーバーボラティリティトラッキング定量取引戦略 適応型移動平均クロスオーバーボラティリティトラッキング定量取引戦略

戦略概要

自動調整均線交差変動率追跡量化取引戦略は,高周波取引と短線操作を専用に設計された体系化された戦略である.この戦略の核心は,高速移動均線 ((MA) と遅い移動均線の交差を主要なシグナルトリガーとして利用し,また,小さな,しかし急速な価格変動を捕捉するために,複数のキーフィルターと正確なリスク管理ツールと組み合わせている.この戦略の構成性は非常に高く,ユーザーは,異なる市場リズムの取引ニーズに適合するために,平均線型 (EMA, SMA, WMA, HMA, VWMA) とその周期パラメータを柔軟に選択することができます.さらに,この戦略はAPIが用意されており,自動取引システムにシグナルを実行し,迅速な実行を実現します.

戦略原則

この戦略の核心的な論理は以下の重要な部分に分かれています.

  1. 入口信号: 主に高速平均線と遅速平均線の交差/横断を入場条件として触発する.ユーザーは,平均線タイプ (EMA,SMA,WMA,HMA,VWMA) と周期長を柔軟に設定して,異なる市場状況に合わせて信号の感度を調整できます.

  2. トレンドフィルター戦略: 長期移動平均線を大きなトレンドのフィルターとして選択的に使用し,大きなトレンドの方向でのみ取引を確実にし,強い方向性のある市場での逆転のショートライン取引を避ける.

  3. フィルターを確認

    • ATR波動率フィルター: 極度に平坦または”静寂”の市場での入場を一時的に停止するために設計され,これらの市場の波動率は動的値より低い ((平均ATRに基づいて),無傾向,低エネルギー条件下での震動を防止するのに役立ちます.
    • 交付量フィルター: 最低の市場参加を要求して (取引量と移動平均の比較) 入場シグナルを検証し,低流動性のピークまたは重要でない価格行動に基づく入場を避ける.
  4. リスク管理パッケージ

    • 初期波動率の停止ATR ベースの初期ストップは,近期変動に対応して,各取引のリスク定義に客観的な出発点を提供します.
    • ATRの追跡停止: ダイナミックな市場にとって重要で,ストップ・ローンを追跡することは,有利な価格の動きに合わせて調整され,成功したショートライン取引の利益を保護し,トレードが逆転したときに比較的迅速に損失を減らすことを目的としています.
    • 利益・損益・均衡・止損 ((選択可能): TP1に達するとか,価格が特定のATR距離を移動すると,ストップ・ロスは自動的に入場価格に移動され,迅速な中性および初期的に成功している取引のリスクに使用されます.
    • 双重利益のレベル:TP1とTP2の2つの利益目標が設定されています.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")