//@version=6
strategy(
     title="CNPS21 AUTOMATE-ST V2",
     shorttitle="CNPS21 AUTOMATE-ST V2",
     overlay=true,
     initial_capital=100000000,
     default_qty_type=strategy.fixed,
     default_qty_value=3,
     pyramiding=0,
     margin_long=0,
     margin_short=0,
     slippage=3,
     commission_type=strategy.commission.cash_per_contract,
     commission_value=10000,
     fill_orders_on_standard_ohlc=true,
     process_orders_on_close=true,
     calc_on_order_fills=true,
     max_labels_count=300,
     max_lines_count=300,
     max_bars_back=5000
)


// ============================================================================
// CNPS21 AUTOMATE-ST V2
//
// SOURCE-STYLE SIGNAL ENGINES
// - EMA XO/XU
// - TURTLE
// - SFP
//
// DEFAULT:
// - Turtle only
// - No automatic reversal
// - Maximum 4 trades / day
// - Hard Stop: 5 points
// - A4.0-style VWATR mechanical trailing exit
//
// CURRENT CHART TIMEFRAME
// 3 CONTRACTS
// ============================================================================


// ============================================================================
// SECTION 1: SIGNAL ENGINE
// ============================================================================

signalEngine = input.string(
     "Turtle",
     title="Signal Engine",
     options=[
         "Turtle",
         "EMA XO/XU",
         "SFP",
         "Combined Priority"
     ],
     group="Signal Engine"
)


// ============================================================================
// SECTION 2: TRADE CONTROL
// ============================================================================

tradeDirection = input.string(
     "Both",
     title="Trade Direction",
     options=[
         "Long",
         "Short",
         "Both"
     ],
     group="Trade Control"
)

bool allowLong = (
     tradeDirection == "Long" or
     tradeDirection == "Both"
)

bool allowShort = (
     tradeDirection == "Short" or
     tradeDirection == "Both"
)

allowReversal = input.bool(
     false,
     title="Reverse On Opposite Signal?",
     group="Trade Control"
)

maximumTradesPerDay = input.int(
     4,
     title="Maximum Trades Per Day",
     minval=1,
     maxval=20,
     group="Trade Control"
)

cooldownBars = input.int(
     2,
     title="Cooldown Bars After Entry",
     minval=0,
     maxval=100,
     group="Trade Control"
)


// ============================================================================
// SECTION 3: EMA XO/XU
// ============================================================================

maPair = input.string(
     "9/26",
     title="EMA Pair",
     options=[
         "5/13",
         "9/26",
         "12/25",
         "26/128"
     ],
     group="EMA XO/XU"
)


// ============================================================================
// SECTION 4: EXIT MODE
// ============================================================================

exitMode = input.string(
     "VWATR Trailing",
     title="Exit Mode",
     options=[
         "VWATR Trailing",
         "Fixed Points"
     ],
     group="Risk Management"
)


// ============================================================================
// SECTION 5: HARD RISK
// ============================================================================

hardStopPoints = input.float(
     5.0,
     title="Hard Stop Loss (Points)",
     minval=0.5,
     step=0.5,
     group="Risk Management"
)

fixedTakeProfitPoints = input.float(
     15.0,
     title="Fixed Take Profit (Points)",
     minval=0.5,
     step=0.5,
     group="Risk Management"
)


// ============================================================================
// SECTION 6: OPTIONAL TP FOR TRAILING MODE
// ============================================================================

useTakeProfitWithTrailing = input.bool(
     false,
     title="Use Take Profit With VWATR Trailing?",
     group="Risk Management"
)

trailingTakeProfitPoints = input.float(
     15.0,
     title="Trailing Mode Take Profit (Points)",
     minval=0.5,
     step=0.5,
     group="Risk Management"
)


// ============================================================================
// SECTION 7: SOURCE-STYLE A4.0 VWATR
// ============================================================================

linRegLength = input.int(
     10,
     title="Linear Regression Length",
     minval=2,
     group="VWATR Trailing"
)

longATRLength = input.int(
     14,
     title="Long VWATR Length",
     minval=2,
     group="VWATR Trailing"
)

shortATRLength = input.int(
     26,
     title="Short VWATR Length",
     minval=2,
     group="VWATR Trailing"
)

longATRMultiplier = input.float(
     4.0,
     title="Long VWATR Multiplier",
     minval=0.1,
     step=0.1,
     group="VWATR Trailing"
)

shortATRMultiplier = input.float(
     2.0,
     title="Short VWATR Multiplier",
     minval=0.1,
     step=0.1,
     group="VWATR Trailing"
)

minimumBarsBeforeTrailingExit = input.int(
     5,
     title="Minimum Bars Before Mechanical Exit",
     minval=0,
     maxval=50,
     group="VWATR Trailing"
)


// ============================================================================
// SECTION 8: BREAK EVEN
// ============================================================================

useBreakEven = input.bool(
     false,
     title="Use Break Even?",
     group="Break Even"
)

breakEvenTriggerPoints = input.float(
     7.5,
     title="Break Even Trigger",
     minval=0.5,
     step=0.5,
     group="Break Even"
)

breakEvenOffsetPoints = input.float(
     0.5,
     title="Break Even Offset",
     minval=0.0,
     step=0.5,
     group="Break Even"
)


// ============================================================================
// SECTION 9: SESSION
// ============================================================================

strategyTimezone = input.string(
     "Asia/Ho_Chi_Minh",
     title="Strategy Timezone",
     group="Session"
)

sessionStartHour = input.int(
     9,
     title="Entry Start Hour",
     minval=0,
     maxval=23,
     group="Session"
)

sessionStartMinute = input.int(
     0,
     title="Entry Start Minute",
     minval=0,
     maxval=59,
     group="Session"
)

lastEntryHour = input.int(
     14,
     title="Last Entry Hour",
     minval=0,
     maxval=23,
     group="Session"
)

lastEntryMinute = input.int(
     30,
     title="Last Entry Minute",
     minval=0,
     maxval=59,
     group="Session"
)

sessionEndHour = input.int(
     14,
     title="Force Close Hour",
     minval=0,
     maxval=23,
     group="Session"
)

sessionEndMinute = input.int(
     45,
     title="Force Close Minute",
     minval=0,
     maxval=59,
     group="Session"
)


// ============================================================================
// SECTION 10: ALERTS
// ============================================================================

disableSLTPAlerts = input.bool(
     false,
     title="Disable SL / TP Alerts?",
     group="Alerts"
)


// ============================================================================
// SECTION 11: DISPLAY
// ============================================================================

showSelectedEMA = input.bool(
     false,
     title="Show Selected EMA Pair?",
     group="Display"
)

showTrailingStop = input.bool(
     true,
     title="Show VWATR Trailing Stop?",
     group="Display"
)

showActiveSLTP = input.bool(
     true,
     title="Show Active Hard SL / TP?",
     group="Display"
)

showSignalMarkers = input.bool(
     false,
     title="Show Signal Markers?",
     group="Display"
)

showDiagnostics = input.bool(
     false,
     title="Show Diagnostics?",
     group="Display"
)


// ============================================================================
// SECTION 12: TIME
// ============================================================================

int currentMinute = (
     hour(time, strategyTimezone) * 60 +
     minute(time, strategyTimezone)
)

int currentCloseMinute = (
     hour(time_close, strategyTimezone) * 60 +
     minute(time_close, strategyTimezone)
)

int sessionStartTotal = (
     sessionStartHour * 60 +
     sessionStartMinute
)

int lastEntryTotal = (
     lastEntryHour * 60 +
     lastEntryMinute
)

int sessionEndTotal = (
     sessionEndHour * 60 +
     sessionEndMinute
)

bool entrySession = (
     currentMinute >= sessionStartTotal and
     currentMinute <= lastEntryTotal
)


// ============================================================================
// SECTION 13: DAILY COUNTER
// ============================================================================

int dayKey = (
     year(time, strategyTimezone) * 10000 +
     month(time, strategyTimezone) * 100 +
     dayofmonth(time, strategyTimezone)
)

bool newTradingDay = (
     bar_index == 0 or
     dayKey != dayKey[1]
)

var int tradesToday = 0

if newTradingDay
    tradesToday := 0


// ============================================================================
// SECTION 14: SFP FUNCTION
// ============================================================================

detectSFP(int leftBars, int rightBars) =>

    bool swingHighFound = not na(
         ta.pivothigh(
             high,
             leftBars,
             rightBars
         )
    )

    bool swingLowFound = not na(
         ta.pivotlow(
             low,
             leftBars,
             rightBars
         )
    )

    float localSwingHigh = ta.valuewhen(
         swingHighFound,
         high[rightBars],
         0
    )

    float localSwingLow = ta.valuewhen(
         swingLowFound,
         low[rightBars],
         0
    )

    bool lowerLowStructure = (
         low <
         ta.lowest(
             low,
             rightBars
         )[1]
    )

    bool higherHighStructure = (
         high >
         ta.highest(
             high,
             rightBars
         )[1]
    )

    bool bullishSFPCandle = (
         not na(localSwingLow) and
         low <
         localSwingLow and
         open >
         localSwingLow and
         close >
         localSwingLow and
         lowerLowStructure
    )

    bool bearishSFPCandle = (
         not na(localSwingHigh) and
         high >
         localSwingHigh and
         open <
         localSwingHigh and
         close <
         localSwingHigh and
         higherHighStructure
    )

    float bullishLow = ta.valuewhen(
         bullishSFPCandle,
         low,
         0
    )

    float bearishHigh = ta.valuewhen(
         bearishSFPCandle,
         high,
         0
    )

    float bullishNullRaw = na

    if (
         not na(bullishLow) and
         close <
         bullishLow
    )
        bullishNullRaw := 1.0

    else if (
         not na(bullishLow) and
         bullishLow >
         ta.lowest(
             close,
             2
         )[1]
    )
        bullishNullRaw := 1.0

    else if bullishSFPCandle
        bullishNullRaw := 0.0


    float bearishNullRaw = na

    if (
         not na(bearishHigh) and
         close >
         bearishHigh
    )
        bearishNullRaw := 1.0

    else if (
         not na(bearishHigh) and
         bearishHigh <
         ta.highest(
             close,
             2
         )[1]
    )
        bearishNullRaw := 1.0

    else if bearishSFPCandle
        bearishNullRaw := 0.0


    float bullishNull = fixnan(
         bullishNullRaw
    )

    float bearishNull = fixnan(
         bearishNullRaw
    )

    float directionRaw = na

    if bullishSFPCandle
        directionRaw := 1.0

    else if bearishSFPCandle
        directionRaw := -1.0

    float direction = fixnan(
         directionRaw
    )

    bool bullishValid = (
         direction ==
         1.0 and
         bullishNull !=
         1.0
    )

    bool bearishValid = (
         direction ==
         -1.0 and
         bearishNull !=
         1.0
    )

    float latestBullHigh = ta.valuewhen(
         bullishSFPCandle,
         high,
         0
    )

    float latestBearLow = ta.valuewhen(
         bearishSFPCandle,
         low,
         0
    )

    int bullishAge = ta.barssince(
         bullishSFPCandle
    )

    int bearishAge = ta.barssince(
         bearishSFPCandle
    )

    bool bullishRecent = (
         not na(bullishAge) and
         bullishAge <=
         5
    )

    bool bearishRecent = (
         not na(bearishAge) and
         bearishAge <=
         5
    )

    bool bullishConfirmed = (
         not bearishSFPCandle and
         bullishRecent and
         bullishValid and
         not na(latestBullHigh) and
         close >
         latestBullHigh and
         close >=
         1.0005 *
         high[1]
    )

    bool bearishConfirmed = (
         not bullishSFPCandle and
         bearishRecent and
         bearishValid and
         not na(latestBearLow) and
         close <
         latestBearLow and
         close <=
         0.9995 *
         low[1]
    )

    float confirmedRaw = na

    if bullishConfirmed
        confirmedRaw := 1.0

    else if bearishConfirmed
        confirmedRaw := -1.0

    else if (
         bullishSFPCandle or
         bearishSFPCandle
    )
        confirmedRaw := 0.0

    float confirmedState = fixnan(
         confirmedRaw
    )

    bool finalBull = (
         confirmedState[1] !=
         1.0 and
         bullishConfirmed
    )

    bool finalBear = (
         confirmedState[1] !=
         -1.0 and
         bearishConfirmed
    )

    [
         finalBull,
         finalBear,
         bullishSFPCandle,
         bearishSFPCandle
    ]


// ============================================================================
// SECTION 15: VOLUME
// ============================================================================

float averageVolume = ta.sma(
     volume,
     13
)

bool volumeSpike = (
     volume >
     volume[1] and
     volume >
     averageVolume
)

bool strongVolumeSpike = (
     volume >
     1.618 *
     averageVolume
)


// ============================================================================
// SECTION 16: MARKET SWINGS
// ============================================================================

bool swingHigh = not na(
     ta.pivothigh(
         high,
         5,
         5
     )
)

bool swingLow = not na(
     ta.pivotlow(
         low,
         5,
         5
     )
)

float swingHighPrice = ta.valuewhen(
     swingHigh,
     high[5],
     0
)

float swingLowPrice = ta.valuewhen(
     swingLow,
     low[5],
     0
)


// ============================================================================
// SECTION 17: CANDLE ANALYSIS
// ============================================================================

bool bullishCandle = (
     close >
     open
)

bool bearishCandle = (
     close <
     open
)

bool closeUp = (
     close >
     close[1]
)

bool closeDown = (
     close <
     close[1]
)

float candleRange = (
     high -
     low
)

float bodyHigh = math.max(
     close,
     open
)

float bodyLow = math.min(
     close,
     open
)

float bodySize = (
     bodyHigh -
     bodyLow
)

float upperWick = (
     high -
     bodyHigh
)

float lowerWick = (
     bodyLow -
     low
)

bool fullMomentum = (
     candleRange >
     0 and
     bodySize >=
     candleRange *
     0.666
)

bool bearishWideWick = (
     candleRange >
     0 and
     upperWick >
     0.382 *
     candleRange
)

bool bullishWideWick = (
     candleRange >
     0 and
     lowerWick >
     0.382 *
     candleRange
)

bool bearishWickTrap = (
     candleRange >
     0 and
     upperWick >
     0.55 *
     candleRange
)

bool bullishWickTrap = (
     candleRange >
     0 and
     lowerWick >
     0.55 *
     candleRange
)

bool bullishWick2 = (
     candleRange >
     0 and
     lowerWick >
     0.25 *
     candleRange and
     upperWick <
     0.10 *
     candleRange
)

bool bearishWick2 = (
     candleRange >
     0 and
     upperWick >
     0.25 *
     candleRange and
     lowerWick <
     0.10 *
     candleRange
)

bool bullishWick3 = (
     candleRange >
     0 and
     lowerWick >
     0.275 *
     candleRange and
     upperWick <
     0.10 *
     candleRange
)

bool bearishWick3 = (
     candleRange >
     0 and
     upperWick >
     0.275 *
     candleRange and
     lowerWick <
     0.10 *
     candleRange
)

bool bullishCandleQuality = (
     (
         fullMomentum and
         bullishCandle
     ) or
     bullishWick2 or
     bullishWick3 or
     bullishWickTrap or
     (
         candleRange >
         0 and
         lowerWick >
         0.50 *
         candleRange
     )
)

bool bearishCandleQuality = (
     (
         fullMomentum and
         bearishCandle
     ) or
     bearishWick2 or
     bearishWick3 or
     bearishWickTrap or
     (
         candleRange >
         0 and
         upperWick >
         0.50 *
         candleRange
     )
)


// ============================================================================
// SECTION 18: EMAS
// ============================================================================

float ema5 = ta.ema(
     close,
     5
)

float ema9 = ta.ema(
     close,
     9
)

float ema12 = ta.ema(
     close,
     12
)

float ema13 = ta.ema(
     close,
     13
)

float ema25 = ta.ema(
     close,
     25
)

float ema26 = ta.ema(
     close,
     26
)

float ema50 = ta.ema(
     close,
     50
)

float ema128 = ta.ema(
     close,
     128
)

float ema200 = ta.ema(
     close,
     200
)

bool xo513 = ta.crossover(
     ema5,
     ema13
)

bool xu513 = ta.crossunder(
     ema5,
     ema13
)

bool xo926 = ta.crossover(
     ema9,
     ema26
)

bool xu926 = ta.crossunder(
     ema9,
     ema26
)

bool xo1225 = ta.crossover(
     ema12,
     ema25
)

bool xu1225 = ta.crossunder(
     ema12,
     ema25
)

bool xo26128 = ta.crossover(
     ema26,
     ema128
)

bool xu26128 = ta.crossunder(
     ema26,
     ema128
)

int trend1225 = -1

if ema12 > ema25
    trend1225 := 1


// ============================================================================
// SECTION 19: SELECTED MA CROSS
// ============================================================================

bool selectedXO = false
bool selectedXU = false

if maPair == "5/13"

    selectedXO := xo513
    selectedXU := xu513

else if maPair == "9/26"

    selectedXO := xo926
    selectedXU := xu926

else if maPair == "12/25"

    selectedXO := xo1225
    selectedXU := xu1225

else

    selectedXO := xo26128
    selectedXU := xu26128


// ============================================================================
// SECTION 20: TURTLE
// ============================================================================

float turtleHigh13 = ta.highest(
     high,
     13
)[1]

float turtleHigh26 = ta.highest(
     high,
     26
)[1]

float turtleLow13 = ta.lowest(
     low,
     13
)[1]

float turtleLow26 = ta.lowest(
     low,
     26
)[1]

bool turtleLong9 = (
     close >
     ta.highest(
         high,
         9
     )[1] and
     closeUp
)

bool turtleShort9 = (
     close <
     ta.lowest(
         low,
         9
     )[1] and
     closeDown
)

bool turtleLong13 = (
     ta.crossover(
         close,
         turtleHigh13
     ) and
     closeUp
)

bool turtleLong26 = (
     ta.crossover(
         close,
         turtleHigh26
     ) and
     closeUp
)

bool turtleShort13 = (
     ta.crossunder(
         close,
         turtleLow13
     ) and
     closeDown
)

bool turtleShort26 = (
     ta.crossunder(
         close,
         turtleLow26
     ) and
     closeDown
)

float turtleStateRaw = na

if turtleLong26
    turtleStateRaw := 2.0

else if turtleShort26
    turtleStateRaw := -2.0

else if turtleLong13
    turtleStateRaw := 1.0

else if turtleShort13
    turtleStateRaw := -1.0

float turtleState = fixnan(
     turtleStateRaw
)


// ============================================================================
// SECTION 21: SFP
// ============================================================================

[
     sfpLong52,
     sfpShort52,
     sfpBull52,
     sfpBear52
] = detectSFP(
     5,
     2
)

[
     sfpLong55,
     sfpShort55,
     sfpBull55,
     sfpBear55
] = detectSFP(
     5,
     5
)

[
     sfpLong133,
     sfpShort133,
     sfpBull133,
     sfpBear133
] = detectSFP(
     13,
     3
)


// ============================================================================
// SECTION 22: VOLATILITY BREAKOUT
// ============================================================================

float atr5 = ta.atr(
     5
)

bool volatilityBreakShort = (
     open -
     1.5 *
     atr5 >
     low
)


// ============================================================================
// SECTION 23: NULLIFICATION
// ============================================================================

bool nullLong = (
     not (
         sfpBear55 or
         sfpBear133 or
         bearishWideWick
     )
)

bool nullShort = (
     not (
         sfpBull55 or
         sfpBull133 or
         bullishWideWick
     )
)


// ============================================================================
// SECTION 24: EMA SIGNALS
// ============================================================================

bool emaLongSignal = (
     (
         selectedXO or
         xo26128
     ) and
     volumeSpike and
     not na(
         swingHighPrice
     ) and
     close >
     swingHighPrice and
     nullLong
)

int barsSinceVolatilityShort = ta.barssince(
     volatilityBreakShort
)

bool recentVolatilityShort = (
     not na(
         barsSinceVolatilityShort
     ) and
     barsSinceVolatilityShort <=
     3
)

bool emaShortSignal = (
     recentVolatilityShort and
     selectedXU and
     volumeSpike and
     nullShort
)


// ============================================================================
// SECTION 25: TURTLE SIGNALS
// ============================================================================

bool turtleLongSignal = (
     turtleLong9 and
     trend1225 >=
     0 and
     bullishCandleQuality and
     strongVolumeSpike
)

int barsSinceVolatilityVolumeShort = ta.barssince(
     volatilityBreakShort and
     strongVolumeSpike
)

bool recentVolatilityVolumeShort = (
     not na(
         barsSinceVolatilityVolumeShort
     ) and
     barsSinceVolatilityVolumeShort <=
     3
)

bool turtleShortSignal = (
     recentVolatilityVolumeShort and
     turtleShort9 and
     turtleState[1] >
     0 and
     bearishCandleQuality and
     nullShort
)


// ============================================================================
// SECTION 26: SFP SIGNALS
// ============================================================================

bool sfpLongSignal = (
     (
         (
             sfpLong55 and
             fullMomentum
         ) or
         (
             sfpLong52 and
             bullishCandleQuality and
             strongVolumeSpike
         )
     ) and
     nullLong
)

bool sfpShortSignal = (
     (
         (
             sfpShort55 and
             fullMomentum
         ) or
         (
             sfpShort133 and
             bearishCandleQuality
         )
     ) and
     nullShort
)


// ============================================================================
// SECTION 27: SELECT SIGNAL ENGINE
// ============================================================================

bool rawLongSignal = false
bool rawShortSignal = false

if signalEngine == "Turtle"

    rawLongSignal := turtleLongSignal
    rawShortSignal := turtleShortSignal

else if signalEngine == "EMA XO/XU"

    rawLongSignal := emaLongSignal
    rawShortSignal := emaShortSignal

else if signalEngine == "SFP"

    rawLongSignal := sfpLongSignal
    rawShortSignal := sfpShortSignal

else

    if emaLongSignal
        rawLongSignal := true

    else if emaShortSignal
        rawShortSignal := true

    else if turtleLongSignal
        rawLongSignal := true

    else if turtleShortSignal
        rawShortSignal := true

    else if sfpLongSignal
        rawLongSignal := true

    else if sfpShortSignal
        rawShortSignal := true


// ============================================================================
// SECTION 28: A4.0 VWATR
// ============================================================================

float trueRange = ta.tr(
     true
)

float longVolumeAverage = ta.sma(
     volume,
     longATRLength
)

float shortVolumeAverage = ta.sma(
     volume,
     shortATRLength
)

float longVolumeWeight = 1.0

if (
     not na(longVolumeAverage) and
     longVolumeAverage >
     0
)
    longVolumeWeight := (
         volume /
         longVolumeAverage
    )

float shortVolumeWeight = 1.0

if (
     not na(shortVolumeAverage) and
     shortVolumeAverage >
     0
)
    shortVolumeWeight := (
         volume /
         shortVolumeAverage
    )

float weightedTRLong = (
     trueRange *
     longVolumeWeight
)

float weightedTRShort = (
     trueRange *
     shortVolumeWeight
)

float vwatrLong = ta.sma(
     weightedTRLong,
     longATRLength
)

float vwatrShort = ta.sma(
     weightedTRShort,
     shortATRLength
)

float linearRegression = ta.linreg(
     close,
     linRegLength,
     1
)


// ============================================================================
// SECTION 29: EFFICIENCY RATIO
// ============================================================================

float absoluteChange = math.abs(
     close -
     close[1]
)

float changeSum = (
     ta.sma(
         absoluteChange,
         shortATRLength
     ) *
     shortATRLength
)

float directionalMove = math.abs(
     close -
     close[shortATRLength]
)

float efficiencyRatio = 0.5

if (
     not na(changeSum) and
     changeSum >
     0 and
     not na(directionalMove)
)
    efficiencyRatio := (
         directionalMove /
         changeSum
    )

float regimeScale = (
     0.8 +
     efficiencyRatio *
     0.4
)


// ============================================================================
// SECTION 30: RAW TRAILING LEVELS
// ============================================================================

float rawLongTrail = (
     linearRegression -
     longATRMultiplier *
     regimeScale *
     vwatrLong
)

float rawShortTrail = (
     linearRegression +
     shortATRMultiplier *
     regimeScale *
     vwatrShort
)


// ============================================================================
// SECTION 31: POSITION STATE
// ============================================================================

bool flat = (
     strategy.position_size ==
     0
)

bool inLong = (
     strategy.position_size >
     0
)

bool inShort = (
     strategy.position_size <
     0
)

bool newLongPosition = (
     inLong and
     strategy.position_size[1] <=
     0
)

bool newShortPosition = (
     inShort and
     strategy.position_size[1] >=
     0
)

bool positionJustClosed = (
     flat and
     strategy.position_size[1] !=
     0
)


// ============================================================================
// SECTION 32: ENTRY CONTROLS
// ============================================================================

var int lastEntryBar = na

bool cooldownOK = (
     na(
         lastEntryBar
     ) or
     bar_index -
     lastEntryBar >
     cooldownBars
)

bool tradeLimitOK = (
     tradesToday <
     maximumTradesPerDay
)

bool longPositionOK = (
     flat or
     (
         inShort and
         allowReversal
     )
)

bool shortPositionOK = (
     flat or
     (
         inLong and
         allowReversal
     )
)

bool commonEntryApproval = (
     entrySession and
     currentCloseMinute <
     sessionEndTotal and
     cooldownOK and
     tradeLimitOK and
     barstate.isconfirmed
)

bool finalLongSignal = (
     commonEntryApproval and
     allowLong and
     rawLongSignal and
     longPositionOK
)

bool finalShortSignal = (
     commonEntryApproval and
     allowShort and
     rawShortSignal and
     shortPositionOK
)


// ============================================================================
// SECTION 33: AMBIGUOUS SIGNAL
// ============================================================================

bool ambiguousSignal = (
     finalLongSignal and
     finalShortSignal
)

finalLongSignal := (
     finalLongSignal and
     not ambiguousSignal
)

finalShortSignal := (
     finalShortSignal and
     not ambiguousSignal
)


// ============================================================================
// SECTION 34: ENTRIES
// ============================================================================

if finalLongSignal

    strategy.entry(
         "Long",
         strategy.long,
         qty=3,
         comment="CNPS21 Long",
         alert_message="ENTRY_LONG_CNPS21_V2"
    )

    lastEntryBar := (
         bar_index
    )

    tradesToday += 1


if finalShortSignal

    strategy.entry(
         "Short",
         strategy.short,
         qty=3,
         comment="CNPS21 Short",
         alert_message="ENTRY_SHORT_CNPS21_V2"
    )

    lastEntryBar := (
         bar_index
    )

    tradesToday += 1


// ============================================================================
// SECTION 35: ACTIVE TRADE STATE
// ============================================================================

var float activeEntryPrice = na

var float activeHardSL = na
var float activeTP = na

var float activeLongTrail = na
var float activeShortTrail = na

var int activeEntryBar = na

var bool breakEvenActivated = false


// ============================================================================
// SECTION 36: INITIALIZE LONG
// ============================================================================

if newLongPosition

    activeEntryPrice := (
         strategy.position_avg_price
    )

    activeHardSL := (
         activeEntryPrice -
         hardStopPoints
    )

    activeTP := na

    if exitMode == "Fixed Points"

        activeTP := (
             activeEntryPrice +
             fixedTakeProfitPoints
        )

    else if useTakeProfitWithTrailing

        activeTP := (
             activeEntryPrice +
             trailingTakeProfitPoints
        )


    activeLongTrail := (
         rawLongTrail
    )

    activeShortTrail := na

    activeEntryBar := (
         bar_index
    )

    breakEvenActivated := false


// ============================================================================
// SECTION 37: INITIALIZE SHORT
// ============================================================================

if newShortPosition

    activeEntryPrice := (
         strategy.position_avg_price
    )

    activeHardSL := (
         activeEntryPrice +
         hardStopPoints
    )

    activeTP := na

    if exitMode == "Fixed Points"

        activeTP := (
             activeEntryPrice -
             fixedTakeProfitPoints
        )

    else if useTakeProfitWithTrailing

        activeTP := (
             activeEntryPrice -
             trailingTakeProfitPoints
        )


    activeShortTrail := (
         rawShortTrail
    )

    activeLongTrail := na

    activeEntryBar := (
         bar_index
    )

    breakEvenActivated := false


// ============================================================================
// SECTION 38: RATCHET LONG TRAIL
// ============================================================================

if (
     inLong and
     exitMode ==
     "VWATR Trailing" and
     not na(
         rawLongTrail
     )
)

    if na(activeLongTrail)

        activeLongTrail := (
             rawLongTrail
        )

    else

        activeLongTrail := math.max(
             activeLongTrail,
             rawLongTrail
        )


// ============================================================================
// SECTION 39: RATCHET SHORT TRAIL
// ============================================================================

if (
     inShort and
     exitMode ==
     "VWATR Trailing" and
     not na(
         rawShortTrail
     )
)

    if na(activeShortTrail)

        activeShortTrail := (
             rawShortTrail
        )

    else

        activeShortTrail := math.min(
             activeShortTrail,
             rawShortTrail
        )


// ============================================================================
// SECTION 40: BARS IN TRADE
// ============================================================================

int barsInTrade = 0

if (
     not na(
         activeEntryBar
     ) and
     not flat
)
    barsInTrade := (
         bar_index -
         activeEntryBar
    )


// ============================================================================
// SECTION 41: BREAK EVEN LONG
// ============================================================================

if (
     inLong and
     useBreakEven and
     not breakEvenActivated and
     not na(
         activeEntryPrice
     )
)

    float longBETrigger = (
         activeEntryPrice +
         breakEvenTriggerPoints
    )

    if high >= longBETrigger

        float newStop = (
             activeEntryPrice +
             breakEvenOffsetPoints
        )

        if newStop > activeHardSL

            activeHardSL := (
                 newStop
            )

        breakEvenActivated := true


// ============================================================================
// SECTION 42: BREAK EVEN SHORT
// ============================================================================

if (
     inShort and
     useBreakEven and
     not breakEvenActivated and
     not na(
         activeEntryPrice
     )
)

    float shortBETrigger = (
         activeEntryPrice -
         breakEvenTriggerPoints
    )

    if low <= shortBETrigger

        float newStop = (
             activeEntryPrice -
             breakEvenOffsetPoints
        )

        if newStop < activeHardSL

            activeHardSL := (
                 newStop
            )

        breakEvenActivated := true


// ============================================================================
// SECTION 43: HARD SL / OPTIONAL TP - LONG
// ============================================================================

if (
     inLong and
     not na(
         activeHardSL
     )
)

    strategy.exit(
         "Long Protective Exit",
         from_entry="Long",
         stop=activeHardSL,
         limit=activeTP,
         alert_profit="EXIT_LONG_TP_CNPS21_V2",
         alert_loss="EXIT_LONG_SL_CNPS21_V2",
         disable_alert=disableSLTPAlerts
    )


// ============================================================================
// SECTION 44: HARD SL / OPTIONAL TP - SHORT
// ============================================================================

if (
     inShort and
     not na(
         activeHardSL
     )
)

    strategy.exit(
         "Short Protective Exit",
         from_entry="Short",
         stop=activeHardSL,
         limit=activeTP,
         alert_profit="EXIT_SHORT_TP_CNPS21_V2",
         alert_loss="EXIT_SHORT_SL_CNPS21_V2",
         disable_alert=disableSLTPAlerts
    )


// ============================================================================
// SECTION 45: MECHANICAL LONG TRAIL EXIT
// ============================================================================

bool longMechanicalExit = (
     inLong and
     exitMode ==
     "VWATR Trailing" and
     barsInTrade >=
     minimumBarsBeforeTrailingExit and
     not na(
         activeLongTrail
     ) and
     close <
     activeLongTrail
)

if longMechanicalExit

    strategy.close(
         "Long",
         comment="VWATR Trail Long",
         alert_message="TRAIL_EXIT_LONG_CNPS21_V2"
    )


// ============================================================================
// SECTION 46: MECHANICAL SHORT TRAIL EXIT
// ============================================================================

bool shortMechanicalExit = (
     inShort and
     exitMode ==
     "VWATR Trailing" and
     barsInTrade >=
     minimumBarsBeforeTrailingExit and
     not na(
         activeShortTrail
     ) and
     close >
     activeShortTrail
)

if shortMechanicalExit

    strategy.close(
         "Short",
         comment="VWATR Trail Short",
         alert_message="TRAIL_EXIT_SHORT_CNPS21_V2"
    )


// ============================================================================
// SECTION 47: CLEANUP
// ============================================================================

if positionJustClosed

    activeEntryPrice := na

    activeHardSL := na
    activeTP := na

    activeLongTrail := na
    activeShortTrail := na

    activeEntryBar := na

    breakEvenActivated := false


// ============================================================================
// SECTION 48: SESSION END
// ============================================================================

bool finalSessionBar = (
     currentMinute <
     sessionEndTotal and
     currentCloseMinute >=
     sessionEndTotal
)

if finalSessionBar

    if strategy.position_size != 0

        strategy.close_all(
             immediately=true,
             comment="Session End",
             alert_message="SESSION_END_CNPS21_V2"
        )


// ============================================================================
// SECTION 49: EMA DISPLAY
// ============================================================================

float displayFastEMA = na
float displaySlowEMA = na

if maPair == "5/13"

    displayFastEMA := ema5
    displaySlowEMA := ema13

else if maPair == "9/26"

    displayFastEMA := ema9
    displaySlowEMA := ema26

else if maPair == "12/25"

    displayFastEMA := ema12
    displaySlowEMA := ema25

else

    displayFastEMA := ema26
    displaySlowEMA := ema128


plot(
     showSelectedEMA
     ? displayFastEMA
     : na,
     title="Fast EMA",
     color=color.green,
     linewidth=1
)

plot(
     showSelectedEMA
     ? displaySlowEMA
     : na,
     title="Slow EMA",
     color=color.orange,
     linewidth=1
)


// ============================================================================
// SECTION 50: TRAILING STOP DISPLAY
// ============================================================================

plot(
     showTrailingStop and
     inLong and
     exitMode ==
     "VWATR Trailing"
     ? activeLongTrail
     : na,
     title="Long VWATR Trail",
     color=color.green,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     showTrailingStop and
     inShort and
     exitMode ==
     "VWATR Trailing"
     ? activeShortTrail
     : na,
     title="Short VWATR Trail",
     color=color.red,
     linewidth=2,
     style=plot.style_linebr
)


// ============================================================================
// SECTION 51: HARD SL / TP DISPLAY
// ============================================================================

plot(
     showActiveSLTP and
     inLong
     ? activeHardSL
     : na,
     title="Long Hard SL",
     color=color.red,
     linewidth=1,
     style=plot.style_linebr
)

plot(
     showActiveSLTP and
     inShort
     ? activeHardSL
     : na,
     title="Short Hard SL",
     color=color.red,
     linewidth=1,
     style=plot.style_linebr
)

plot(
     showActiveSLTP and
     not flat
     ? activeTP
     : na,
     title="Active TP",
     color=color.green,
     linewidth=1,
     style=plot.style_linebr
)


// ============================================================================
// SECTION 52: SIGNAL MARKERS
// ============================================================================

plotshape(
     showSignalMarkers and
     rawLongSignal,
     title="Long Setup",
     style=shape.triangleup,
     location=location.belowbar,
     color=color.green,
     size=size.small,
     text="L",
     textcolor=color.white
)

plotshape(
     showSignalMarkers and
     rawShortSignal,
     title="Short Setup",
     style=shape.triangledown,
     location=location.abovebar,
     color=color.red,
     size=size.small,
     text="S",
     textcolor=color.white
)


// ============================================================================
// SECTION 53: COUNTERS
// ============================================================================

var int emaLongCount = 0
var int emaShortCount = 0

var int turtleLongCount = 0
var int turtleShortCount = 0

var int sfpLongCount = 0
var int sfpShortCount = 0

var int entryLongCount = 0
var int entryShortCount = 0


if emaLongSignal
    emaLongCount += 1

if emaShortSignal
    emaShortCount += 1

if turtleLongSignal
    turtleLongCount += 1

if turtleShortSignal
    turtleShortCount += 1

if sfpLongSignal
    sfpLongCount += 1

if sfpShortSignal
    sfpShortCount += 1

if finalLongSignal
    entryLongCount += 1

if finalShortSignal
    entryShortCount += 1


// ============================================================================
// SECTION 54: DIAGNOSTICS
// ============================================================================

var table diagnostics = table.new(
     position.top_right,
     2,
     16,
     border_width=1
)

if (
     showDiagnostics and
     barstate.islast
)

    string positionText = "FLAT"

    if inLong
        positionText := "LONG"

    if inShort
        positionText := "SHORT"


    table.cell(
         diagnostics,
         0,
         0,
         "CNPS21 V2"
    )

    table.cell(
         diagnostics,
         1,
         0,
         timeframe.period
    )

    table.cell(
         diagnostics,
         0,
         1,
         "Engine"
    )

    table.cell(
         diagnostics,
         1,
         1,
         signalEngine
    )

    table.cell(
         diagnostics,
         0,
         2,
         "EMA L / S"
    )

    table.cell(
         diagnostics,
         1,
         2,
         str.tostring(
             emaLongCount
         ) +
         " / " +
         str.tostring(
             emaShortCount
         )
    )

    table.cell(
         diagnostics,
         0,
         3,
         "Turtle L / S"
    )

    table.cell(
         diagnostics,
         1,
         3,
         str.tostring(
             turtleLongCount
         ) +
         " / " +
         str.tostring(
             turtleShortCount
         )
    )

    table.cell(
         diagnostics,
         0,
         4,
         "SFP L / S"
    )

    table.cell(
         diagnostics,
         1,
         4,
         str.tostring(
             sfpLongCount
         ) +
         " / " +
         str.tostring(
             sfpShortCount
         )
    )

    table.cell(
         diagnostics,
         0,
         5,
         "Entries L / S"
    )

    table.cell(
         diagnostics,
         1,
         5,
         str.tostring(
             entryLongCount
         ) +
         " / " +
         str.tostring(
             entryShortCount
         )
    )

    table.cell(
         diagnostics,
         0,
         6,
         "Volume Spike"
    )

    table.cell(
         diagnostics,
         1,
         6,
         volumeSpike
         ? "YES"
         : "NO"
    )

    table.cell(
         diagnostics,
         0,
         7,
         "Strong Volume"
    )

    table.cell(
         diagnostics,
         1,
         7,
         strongVolumeSpike
         ? "YES"
         : "NO"
    )

    table.cell(
         diagnostics,
         0,
         8,
         "VWATR L"
    )

    table.cell(
         diagnostics,
         1,
         8,
         str.tostring(
             vwatrLong,
             "0.00"
         )
    )

    table.cell(
         diagnostics,
         0,
         9,
         "VWATR S"
    )

    table.cell(
         diagnostics,
         1,
         9,
         str.tostring(
             vwatrShort,
             "0.00"
         )
    )

    table.cell(
         diagnostics,
         0,
         10,
         "Regime Scale"
    )

    table.cell(
         diagnostics,
         1,
         10,
         str.tostring(
             regimeScale,
             "0.00"
         )
    )

    table.cell(
         diagnostics,
         0,
         11,
         "Bars In Trade"
    )

    table.cell(
         diagnostics,
         1,
         11,
         str.tostring(
             barsInTrade
         )
    )

    table.cell(
         diagnostics,
         0,
         12,
         "Trades Today"
    )

    table.cell(
         diagnostics,
         1,
         12,
         str.tostring(
             tradesToday
         ) +
         " / " +
         str.tostring(
             maximumTradesPerDay
         )
    )

    table.cell(
         diagnostics,
         0,
         13,
         "Exit Mode"
    )

    table.cell(
         diagnostics,
         1,
         13,
         exitMode
    )

    table.cell(
         diagnostics,
         0,
         14,
         "Hard Stop"
    )

    table.cell(
         diagnostics,
         1,
         14,
         str.tostring(
             hardStopPoints
         )
    )

    table.cell(
         diagnostics,
         0,
         15,
         "Position"
    )

    table.cell(
         diagnostics,
         1,
         15,
         positionText
    )