Estrategia de trading cuantitativo con seguimiento de volatilidad de cruce de medias móviles adaptativas

MA交叉 ATR EMA SMA WMA HMA VWMA 趋势过滤 波动率过滤 跟踪止损 双重止盈
Fecha de creación: 2025-05-14 10:49:04 Última modificación: 2025-05-14 10:49:04
Copiar: 0 Número de Visitas: 317
2
Seguir
319
Seguidores

Estrategia de trading cuantitativo con seguimiento de volatilidad de cruce de medias móviles adaptativas Estrategia de trading cuantitativo con seguimiento de volatilidad de cruce de medias móviles adaptativas

Descripción general de la estrategia

La estrategia de comercio cuantitativo de seguimiento de la tasa de fluctuación de la media de la media es una estrategia sistematizada diseñada específicamente para operaciones de alta frecuencia y operaciones de línea corta. El núcleo de la estrategia utiliza la media de movimiento rápido (MA) y la intersección de la media de movimiento lento como el principal punto de activación de la señal, mientras que combina varios filtros clave y herramientas precisas de gestión de riesgo para capturar las fluctuaciones de precios pequeñas pero rápidas. La estrategia es altamente configurable, lo que permite a los usuarios elegir con flexibilidad los tipos de línea media (EMA, SMA, WMA, HMA, VWMA) y sus parámetros de ciclo para adaptarse a las necesidades de comercio de diferentes ritmos del mercado.

Principio de estrategia

La lógica central de esta estrategia se divide en las siguientes partes clave:

  1. Señales de entrada: principalmente a través del cruce / cruce de la línea media rápida con la línea media lenta como condición de entrada. El usuario puede configurar flexiblemente el tipo de línea media (EMA, SMA, WMA, HMA, VWMA) y la longitud del ciclo para ajustar la sensibilidad de la señal para adaptarse a diferentes condiciones del mercado.

  2. Filtración de tendenciasEstrategia: Utilice selectivamente las medias móviles a largo plazo como filtros de tendencias grandes, asegurando que las operaciones se realicen solo en la dirección de la tendencia grande y evitando operaciones de línea contraria en mercados con una fuerte dirección.

  3. Confirme el filtro

    • Filtrador de fluctuaciones ATRDiseñado para la suspensión de la entrada en mercados extremadamente planos o “muertos”, donde la volatilidad es inferior a los mínimos dinámicos (basado en el ATR promedio), que ayuda a prevenir la oscilación en condiciones sin tendencia y de baja energía.
    • Filtrador de cantidad de entrega: Evita la entrada basada en picos de baja liquidez o acciones de precios insignificantes, al exigir una participación mínima en el mercado (comparación del volumen de transacciones con sus medias móviles) para validar las señales de entrada.
  4. El paquete de gestión de riesgos

    • Cancelación de la tasa de fluctuación inicialEl stop inicial basado en el ATR proporciona un punto de partida objetivo para la definición del riesgo de cada operación, adaptado a la volatilidad reciente.
    • ATR paralizó el seguimientoEs fundamental para un mercado dinámico que el seguimiento de las líneas de stop loss se ajuste a un movimiento favorable de los precios, con el objetivo de proteger los beneficios de las operaciones de corto plazo exitosas, mientras que se reducen las pérdidas con relativa rapidez cuando el movimiento se invierte.
    • Pérdida de ganancias y pérdidas de equilibrio (opcional)Cuando se alcanza el TP1 o el precio se mueve a una distancia ATR específica, el stop loss se puede mover automáticamente al precio de entrada (con un amortiguador) para el riesgo de transacciones rápidas, moderadas y que han demostrado un éxito inicial.
    • Niveles de doble gananciaSe establecen dos objetivos de ganancias: TP1 y TP2. TP1 está diseñado para obtener ganancias rápidas (por ejemplo, 50%), mientras que TP2 busca más espacio para las posiciones restantes.
  5. Administración de posicionesLa adopción de un número fijo de posiciones de tamaño, que permite un control preciso de la escala de las posiciones de cada transacción, es fundamental para la generación de órdenes de API y aplicaciones de riesgo consistentes en entornos de alta frecuencia.

Ventajas estratégicas

A través de un análisis profundo del código, la estrategia tiene las siguientes ventajas evidentes:

  1. Alta configurabilidadEl usuario puede ajustar con flexibilidad varios parámetros, incluyendo el tipo y el ciclo de la línea media, la configuración del filtro y los parámetros de gestión de riesgo, para que la estrategia se adapte a diversos entornos de mercado y estilos de negociación.

  2. Mecanismo de filtración de varias capas: Combinación de tendencias, volatilidad y filtros de volumen de transacción para reducir efectivamente las señales erróneas y el ruido del mercado, y mejorar la calidad de las transacciones.

  3. Una buena gestión de riesgosLa estrategia incluye múltiples mecanismos de detención de pérdidas (inicial, seguimiento, compensación de pérdidas) y objetivos de doble ganancia, lo que permite un control de riesgo y protección de ganancias.

  4. Diseño amigable con las APIUna lógica de entrada y salida clara y clara genera señales inequívocas que facilitan la integración con sistemas de negociación externos y la ejecución de órdenes casi instantáneas.

  5. Control de posición de precisión: El tamaño de las posiciones de cantidad fija simplifica la carga útil de los puntos finales de la API y hace que la ejecución automática sea más confiable.

  6. Altamente adaptableA través de la adaptación de parámetros, la estrategia puede cambiar de un modelo de comercio de líneas cortas de alta frecuencia a un modelo de seguimiento de tendencias más prolongado, adaptado a diferentes condiciones de mercado y preferencias comerciales individuales.

Riesgo estratégico

A pesar de la buena concepción de la estrategia, existen algunos riesgos y desafíos potenciales:

  1. Riesgos de la optimización de parámetrosDado que la estrategia contiene muchos parámetros configurables, la optimización excesiva puede conducir a un buen resultado de la retroalimentación pero un mal desempeño en la realidad (sobreajuste), y los inversores deben evitar este riesgo mediante la verificación de datos fuera de la muestra o mediante pruebas de avance.

  2. Efectos en el costo de las transaccionesEl comercio de alta frecuencia significa que un gran número de operaciones, comisiones acumuladas y puntos de deslizamiento pueden afectar significativamente la rentabilidad neta, y es necesario calcular estos costos con precisión en la configuración y la retroalimentación antes de usarlos.

  3. Fluctuaciones en la calidad de la señal: La fiabilidad de la señal de cruce de línea medida puede variar en diferentes condiciones de mercado, especialmente en mercados de oscilación horizontal o de alta volatilidad.

  4. Dependencia tecnológicaComo una estrategia API-ready, su eficacia depende en parte de la velocidad de ejecución y la estabilidad tecnológica, ya que los retrasos o fallas en el sistema pueden causar oportunidades perdidas o desviaciones de ejecución.

  5. Limitación de la cantidad de fondosLa cantidad fija de posiciones puede no ser adecuada para el tamaño de todas las cuentas, las cuentas pequeñas pueden estar expuestas a un riesgo excesivo, y las cuentas grandes pueden no aprovechar plenamente los fondos.

Dirección de optimización de la estrategia

En función del diseño de la estrategia y los riesgos potenciales, las siguientes son algunas posibles direcciones de optimización:

  1. Parámetros de adaptaciónDiseño de parámetros clave (como el multiplicador ATR y el ciclo de la línea media) que se ajusten automáticamente en función de las condiciones del mercado, mejorando la adaptabilidad de la estrategia en diferentes fases del mercado.

  2. Mejora de los filtros inteligentesLa integración de indicadores adicionales de estado del mercado (como la estructura del mercado, la identificación de patrones de fluctuación o la relevancia de los activos relacionados) mejora aún más la precisión del filtro.

  3. Gestión de posiciones dinámicasEl número de posiciones fijas se sustituye por el número de posiciones dinámicas calculadas en función del tamaño de la cuenta, la volatilidad actual y el rendimiento de la estrategia reciente para una gestión de fondos más inteligente.

  4. Confirmación del marco temporal múltiple: Verificar las señales en diferentes marcos de tiempo, asegurarse de que la dirección de las transacciones coincida con la estructura del mercado más grande, y reducir las transacciones innecesarias.

  5. Integración del aprendizaje automático: Utiliza algoritmos de aprendizaje automático para analizar el rendimiento histórico de las señales, predecir la probabilidad de éxito de las señales futuras y priorizar la ejecución de operaciones de alta eficiencia.

  6. Gestión de las sesiones de negociación: Agregar filtros de tiempo de negociación, evitar los períodos de baja liquidez o alta volatilidad y centrarse en las ventanas de negociación de mayor eficiencia en el mercado.

  7. Filtrado por relevancia: Para las transacciones de múltiples activos, agregue análisis de correlación con los mercados relevantes y evite la exposición excesiva a factores de riesgo específicos.

Resumir

La estrategia de comercio de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de fluctuación de la tasa de flu

Para los operadores de alta frecuencia, la estrategia ofrece una lógica clara de entrada y salida, así como la capacidad de integración sin problemas con plataformas de ejecución externas, lo cual es fundamental para tomar decisiones rápidamente en un mercado cambiante. Sin embargo, cuando se utiliza esta estrategia, se debe prestar especial atención al riesgo de acumulación de costos de transacción y de optimización excesiva, para garantizar la solidez y rentabilidad de la estrategia en operaciones reales.

En última instancia, la estrategia representa un enfoque equilibrado que aprovecha la fuerza de los indicadores técnicos y las herramientas de gestión de riesgos, mientras se mantiene la suficiente flexibilidad para adaptarse a las condiciones cambiantes del mercado. A través de un cuidadoso ajuste de parámetros y una mejora continua de la supervisión, la estrategia puede ser una parte valiosa de la cartera de operaciones cuantitativas.

Código Fuente de la Estrategia
/*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")