//@version=6
strategy(
     title="CNPS13 ORB-SMC",
     shorttitle="CNPS13 ORB-SMC",
     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=500,
     max_lines_count=500,
     max_bars_back=5000
)

// ╔══════════════════════════════════════════════════════════════╗
// ║                     CNPS13 ORB-SMC                          ║
// ╠══════════════════════════════════════════════════════════════╣
// ║ Execution Chart: 1 Minute                                   ║
// ║ Context Timeframe: 15 Minutes                               ║
// ║ Position Size: 3 Contracts                                  ║
// ║ Commission: VND 10,000 / Contract                           ║
// ║ Tax: Excluded                                                ║
// ╠══════════════════════════════════════════════════════════════╣
// ║ M15 CONTEXT                                                 ║
// ║ First 15 minutes = Opening Range                            ║
// ║                                                             ║
// ║ M15 Close > OR High                                         ║
// ║ → Long Context                                              ║
// ║                                                             ║
// ║ M15 Close < OR Low                                          ║
// ║ → Short Context                                             ║
// ╠══════════════════════════════════════════════════════════════╣
// ║ M1 CONFIRMATION                                             ║
// ║ CHoCH → Pullback → BOS → Entry                             ║
// ╠══════════════════════════════════════════════════════════════╣
// ║ REVERSAL                                                    ║
// ║ Long → Short:                                               ║
// ║ 1. EXIT_LONG_REVERSE_TO_SHORT                               ║
// ║ 2. ENTRY_SHORT_AFTER_LONG_EXIT                              ║
// ║                                                             ║
// ║ Short → Long:                                               ║
// ║ 1. EXIT_SHORT_REVERSE_TO_LONG                               ║
// ║ 2. ENTRY_LONG_AFTER_SHORT_EXIT                              ║
// ╚══════════════════════════════════════════════════════════════╝


// ════════════════════════════════════════════════════════════════
// SECTION 1: INPUTS
// ════════════════════════════════════════════════════════════════

// ── M15 Context ─────────────────────────────────────────────────
openingRangeMinutes = input.int(
     15,
     title="Opening Range Duration (Minutes)",
     minval=15,
     maxval=120,
     step=15,
     group="M15 Context"
)

breakoutBuffer = input.float(
     0.0,
     title="M15 OR Breakout Buffer (Points)",
     minval=0.0,
     step=0.1,
     group="M15 Context"
)


// ── M1 Structure ────────────────────────────────────────────────
pivotLength = input.int(
     1,
     title="M1 Pivot Length",
     minval=1,
     maxval=10,
     group="M1 Structure"
)

structureBreakMode = input.string(
     "Candle Close",
     title="M1 Structure Break Mode",
     options=[
         "Candle Close",
         "Wick"
     ],
     group="M1 Structure"
)

useEMAFilter = input.bool(
     true,
     title="Use EMA Filter On Entry BOS?",
     group="M1 Structure"
)

emaLength = input.int(
     9,
     title="M1 EMA Length",
     minval=1,
     group="M1 Structure"
)


// ── Stop Loss ───────────────────────────────────────────────────
stopLossMode = input.string(
     "Manual Points",
     title="Stop Loss Mode",
     options=[
         "Manual Points",
         "ATR",
         "Opposite OR"
     ],
     group="Risk Management"
)

manualSLPoints = input.float(
     10.0,
     title="Manual Stop Loss (Points)",
     minval=0.1,
     step=0.1,
     group="Risk Management"
)

atrLength = input.int(
     14,
     title="ATR Length",
     minval=1,
     group="Risk Management"
)

atrStopMultiplier = input.float(
     1.0,
     title="ATR Stop Multiplier",
     minval=0.1,
     step=0.1,
     group="Risk Management"
)

orStopBuffer = input.float(
     0.0,
     title="Opposite OR Stop Buffer (Points)",
     minval=0.0,
     step=0.1,
     group="Risk Management"
)


// ── Take Profit ─────────────────────────────────────────────────
takeProfitMode = input.string(
     "Manual Points",
     title="Take Profit Mode",
     options=[
         "Manual Points",
         "Fixed RR"
     ],
     group="Risk Management"
)

manualTPPoints = input.float(
     15.0,
     title="Manual Take Profit (Points)",
     minval=0.1,
     step=0.1,
     group="Risk Management"
)

takeProfitRR = input.float(
     1.5,
     title="Take Profit R Multiple",
     minval=0.1,
     step=0.1,
     group="Risk Management"
)


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


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

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

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

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


// ── Alert Control ───────────────────────────────────────────────
disableSLTPAlerts = input.bool(
     true,
     title="Disable SL / TP Alerts?",
     group="Alert Control"
)


// ── Display ─────────────────────────────────────────────────────
showOpeningRange = input.bool(
     true,
     title="Show M15 Opening Range?",
     group="Display"
)

showEMA = input.bool(
     true,
     title="Show M1 EMA9?",
     group="Display"
)

showContextMarkers = input.bool(
     true,
     title="Show M15 Context Markers?",
     group="Display"
)

showConfirmationStructure = input.bool(
     true,
     title="Show Confirmation CHoCH / BOS?",
     group="Display"
)

showAllStructure = input.bool(
     false,
     title="Show All M1 Structure Events?",
     group="Display"
)

showEntryMarkers = input.bool(
     true,
     title="Show Entry Markers?",
     group="Display"
)

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


// ════════════════════════════════════════════════════════════════
// SECTION 2: BASIC
// ════════════════════════════════════════════════════════════════

bool isM1Chart = (
     timeframe.in_seconds(timeframe.period) == 60
)

bool useBodyBreak = (
     structureBreakMode == "Candle Close"
)

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

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

int sessionStartTotal = (
     sessionStartHour * 60 +
     sessionStartMinute
)

int sessionEndTotal = (
     sessionEndHour * 60 +
     sessionEndMinute
)

int currentOpenTotal = (
     hour(time) * 60 +
     minute(time)
)

int currentCloseTotal = (
     hour(time_close) * 60 +
     minute(time_close)
)

bool inSession = (
     currentOpenTotal >= sessionStartTotal and
     currentOpenTotal < sessionEndTotal
)

bool previousInSession = (
     bar_index > 0
     ? inSession[1]
     : false
)

bool dayChanged = (
     bar_index > 0 and
     (
         year(time) != year(time[1]) or
         month(time) != month(time[1]) or
         dayofmonth(time) != dayofmonth(time[1])
     )
)

bool newSession = (
     isM1Chart and
     inSession and
     (
         barstate.isfirst or
         dayChanged or
         not previousInSession
     )
)

bool finalSessionBar = (
     isM1Chart and
     inSession and
     currentCloseTotal >= sessionEndTotal
)

bool allowEntry = (
     isM1Chart and
     inSession and
     currentCloseTotal < sessionEndTotal
)


// ════════════════════════════════════════════════════════════════
// SECTION 3: M15 OPENING RANGE FUNCTION
// ════════════════════════════════════════════════════════════════
//
// Function executes inside request.security("15").
//
// Therefore:
//
// Context calculations use TRUE 15-minute bars.
//
// Execution and confirmation remain on M1.
// ════════════════════════════════════════════════════════════════

f_m15_context(
     int startTotal,
     int endTotal,
     int rangeMinutes,
     float buffer
) =>

    int currentMinutes = (
         hour(time) * 60 +
         minute(time)
    )

    bool contextInSession = (
         currentMinutes >= startTotal and
         currentMinutes < endTotal
    )

    bool previousContextInSession = (
         bar_index > 0
         ? contextInSession[1]
         : false
    )

    bool contextDayChanged = (
         bar_index > 0 and
         (
             year(time) != year(time[1]) or
             month(time) != month(time[1]) or
             dayofmonth(time) != dayofmonth(time[1])
         )
    )

    bool contextNewSession = (
         contextInSession and
         (
             barstate.isfirst or
             contextDayChanged or
             not previousContextInSession
         )
    )

    int rangeEndTotal = (
         startTotal +
         rangeMinutes
    )

    bool rangeActive = (
         contextInSession and
         currentMinutes >= startTotal and
         currentMinutes < rangeEndTotal
    )

    bool rangeComplete = (
         contextInSession and
         currentMinutes >= rangeEndTotal
    )

    var float orHigh = na
    var float orLow = na

    if contextNewSession
        orHigh := na
        orLow := na

    if rangeActive

        orHigh := (
             na(orHigh)
             ? high
             : math.max(
                 orHigh,
                 high
             )
        )

        orLow := (
             na(orLow)
             ? low
             : math.min(
                 orLow,
                 low
             )
        )

    float longLevel = (
         not na(orHigh)
         ? orHigh + buffer
         : na
    )

    float shortLevel = (
         not na(orLow)
         ? orLow - buffer
         : na
    )

    bool longBreak = (
         rangeComplete and
         not na(longLevel) and
         close > longLevel and
         close[1] <= longLevel
    )

    bool shortBreak = (
         rangeComplete and
         not na(shortLevel) and
         close < shortLevel and
         close[1] >= shortLevel
    )

    [
         orHigh,
         orLow,
         longBreak,
         shortBreak,
         rangeComplete
    ]


// ════════════════════════════════════════════════════════════════
// SECTION 4: M15 CONTEXT
// ════════════════════════════════════════════════════════════════

[
     m15ORHigh,
     m15ORLow,
     m15LongBreakRaw,
     m15ShortBreakRaw,
     m15ORComplete
] = request.security(
     syminfo.tickerid,
     "15",
     f_m15_context(
         sessionStartTotal,
         sessionEndTotal,
         openingRangeMinutes,
         breakoutBuffer
     ),
     gaps=barmerge.gaps_off,
     lookahead=barmerge.lookahead_off
)


// Convert repeated HTF state into one M1 pulse.
bool m15LongContextPulse = (
     isM1Chart and
     m15LongBreakRaw and
     not m15LongBreakRaw[1]
)

bool m15ShortContextPulse = (
     isM1Chart and
     m15ShortBreakRaw and
     not m15ShortBreakRaw[1]
)


// ════════════════════════════════════════════════════════════════
// SECTION 5: M1 INDICATORS
// ════════════════════════════════════════════════════════════════

float pivotHigh = ta.pivothigh(
     high,
     pivotLength,
     pivotLength
)

float pivotLow = ta.pivotlow(
     low,
     pivotLength,
     pivotLength
)

int pivotHighBar = (
     bar_index -
     pivotLength
)

int pivotLowBar = (
     bar_index -
     pivotLength
)

int pivotHighTime = (
     time[pivotLength]
)

int pivotLowTime = (
     time[pivotLength]
)

float ema9 = ta.ema(
     close,
     emaLength
)

float atrValue = ta.atr(
     atrLength
)


// ════════════════════════════════════════════════════════════════
// SECTION 6: CONTINUOUS M1 STRUCTURE ENGINE
// ════════════════════════════════════════════════════════════════
//
// structureDirection:
//
// 0 = Unknown
// 1 = Bearish
// 2 = Bullish
//
// HIGH BREAK:
//
// Bullish structure
// → Bull BOS.
//
// Bearish / Unknown structure
// → Bull CHoCH.
//
// LOW BREAK:
//
// Bearish structure
// → Bear BOS.
//
// Bullish / Unknown structure
// → Bear CHoCH.
// ════════════════════════════════════════════════════════════════

var int structureDirection = 0

var float structureHigh = na
var int structureHighBar = na
var int structureHighTime = na

var float structureLow = na
var int structureLowBar = na
var int structureLowTime = na

var int brokenHighPivotBar = na
var int brokenLowPivotBar = na

bool bullCHoCH = false
bool bullBOS = false

bool bearCHoCH = false
bool bearBOS = false


if newSession

    structureDirection := 0

    structureHigh := na
    structureHighBar := na
    structureHighTime := na

    structureLow := na
    structureLowBar := na
    structureLowTime := na

    brokenHighPivotBar := na
    brokenLowPivotBar := na


// ── Latest Confirmed Swing High ─────────────────────────────────
if not na(pivotHigh)

    structureHigh := pivotHigh
    structureHighBar := pivotHighBar
    structureHighTime := pivotHighTime


// ── Latest Confirmed Swing Low ──────────────────────────────────
if not na(pivotLow)

    structureLow := pivotLow
    structureLowBar := pivotLowBar
    structureLowTime := pivotLowTime


// ════════════════════════════════════════════════════════════════
// SECTION 7: BREAK PRICES
// ════════════════════════════════════════════════════════════════

float bullishBreakPrice = (
     useBodyBreak
     ? close
     : high
)

float bearishBreakPrice = (
     useBodyBreak
     ? close
     : low
)


// ════════════════════════════════════════════════════════════════
// SECTION 8: STRUCTURE BREAK DETECTION
// ════════════════════════════════════════════════════════════════

bool validHighStructure = (
     inSession and
     not na(structureHigh) and
     not na(structureHighBar) and
     structureHighBar < bar_index
)

bool validLowStructure = (
     inSession and
     not na(structureLow) and
     not na(structureLowBar) and
     structureLowBar < bar_index
)

bool highBreak = (
     validHighStructure and
     (
         na(brokenHighPivotBar) or
         structureHighBar != brokenHighPivotBar
     ) and
     bullishBreakPrice > structureHigh
)

bool lowBreak = (
     validLowStructure and
     (
         na(brokenLowPivotBar) or
         structureLowBar != brokenLowPivotBar
     ) and
     bearishBreakPrice < structureLow
)

bool ambiguousStructureBreak = (
     highBreak and
     lowBreak
)


// ════════════════════════════════════════════════════════════════
// SECTION 9: CLASSIFY BULL BREAK
// ════════════════════════════════════════════════════════════════

if (
     highBreak and
     not ambiguousStructureBreak
)

    if structureDirection == 2
        bullBOS := true
    else
        bullCHoCH := true

    structureDirection := 2
    brokenHighPivotBar := structureHighBar


// ════════════════════════════════════════════════════════════════
// SECTION 10: CLASSIFY BEAR BREAK
// ════════════════════════════════════════════════════════════════

if (
     lowBreak and
     not ambiguousStructureBreak
)

    if structureDirection == 1
        bearBOS := true
    else
        bearCHoCH := true

    structureDirection := 1
    brokenLowPivotBar := structureLowBar


// ════════════════════════════════════════════════════════════════
// SECTION 11: RANGE HELPERS
// ════════════════════════════════════════════════════════════════

f_highest_between(
     int startBar,
     int endBar
) =>

    float resultPrice = na
    int resultTime = na

    if (
         not na(startBar) and
         not na(endBar) and
         endBar >= startBar
    )

        for i = 0 to 1000

            if bar_index >= i

                int candidateBar = (
                     bar_index -
                     i
                )

                if (
                     candidateBar >= startBar and
                     candidateBar <= endBar
                )

                    if (
                         na(resultPrice) or
                         high[i] > resultPrice
                    )

                        resultPrice := high[i]
                        resultTime := time[i]

    [
         resultPrice,
         resultTime
    ]


f_lowest_between(
     int startBar,
     int endBar
) =>

    float resultPrice = na
    int resultTime = na

    if (
         not na(startBar) and
         not na(endBar) and
         endBar >= startBar
    )

        for i = 0 to 1000

            if bar_index >= i

                int candidateBar = (
                     bar_index -
                     i
                )

                if (
                     candidateBar >= startBar and
                     candidateBar <= endBar
                )

                    if (
                         na(resultPrice) or
                         low[i] < resultPrice
                    )

                        resultPrice := low[i]
                        resultTime := time[i]

    [
         resultPrice,
         resultTime
    ]


// ════════════════════════════════════════════════════════════════
// SECTION 12: DRAW STRUCTURE
// ════════════════════════════════════════════════════════════════

var array<line> structureLines = array.new_line()
var array<label> structureLabels = array.new_label()


f_draw_structure(
     int startTime,
     int endTime,
     float level,
     string textValue,
     color structureColor
) =>

    if (
         not na(startTime) and
         not na(endTime) and
         not na(level)
    )

        line newLine = line.new(
             x1=startTime,
             y1=level,
             x2=endTime,
             y2=level,
             xloc=xloc.bar_time,
             extend=extend.none,
             color=structureColor,
             width=1
        )

        int middleTime = (
             startTime +
             int(
                 (
                     endTime -
                     startTime
                 ) /
                 2
             )
        )

        label newLabel = label.new(
             x=middleTime,
             y=level,
             xloc=xloc.bar_time,
             text=textValue,
             style=label.style_none,
             textcolor=structureColor,
             size=size.tiny
        )

        array.push(
             structureLines,
             newLine
        )

        array.push(
             structureLabels,
             newLabel
        )

        if array.size(structureLines) > 120

            line oldLine = array.shift(
                 structureLines
            )

            label oldLabel = array.shift(
                 structureLabels
            )

            if not na(oldLine)
                line.delete(oldLine)

            if not na(oldLabel)
                label.delete(oldLabel)

    0


// ════════════════════════════════════════════════════════════════
// SECTION 13: OPTIONAL ALL-STRUCTURE DISPLAY
// ════════════════════════════════════════════════════════════════

if showAllStructure

    if bullCHoCH

        f_draw_structure(
             structureHighTime,
             time_close,
             structureHigh,
             "Bull CHoCH",
             color.lime
        )

    if bullBOS

        f_draw_structure(
             structureHighTime,
             time_close,
             structureHigh,
             "Bull BOS",
             color.green
        )

    if bearCHoCH

        f_draw_structure(
             structureLowTime,
             time_close,
             structureLow,
             "Bear CHoCH",
             color.red
        )

    if bearBOS

        f_draw_structure(
             structureLowTime,
             time_close,
             structureLow,
             "Bear BOS",
             color.maroon
        )


// ════════════════════════════════════════════════════════════════
// SECTION 14: CONTEXT / CONFIRMATION STATE
// ════════════════════════════════════════════════════════════════
//
// contextDirection:
//
//  1 = Long Context
// -1 = Short Context
//  0 = None
//
// confirmationPhase:
//
// 1 = Wait CHoCH
// 2 = Wait Pullback
// 3 = Wait BOS
// ════════════════════════════════════════════════════════════════

var int contextDirection = 0
var int confirmationPhase = 0

var int contextStartBar = na

var int confirmChochBar = na
var float confirmChochLevel = na
var int confirmChochTime = na

var float pullbackPrice = na
var int pullbackBar = na
var int pullbackTime = na

var float confirmBosLevel = na
var int confirmBosTime = na

bool longEntrySignal = false
bool shortEntrySignal = false


// ════════════════════════════════════════════════════════════════
// SECTION 15: NEW M15 LONG CONTEXT
// ════════════════════════════════════════════════════════════════

if (
     m15LongContextPulse and
     allowLong and
     allowEntry
)

    contextDirection := 1
    confirmationPhase := 1

    contextStartBar := bar_index

    confirmChochBar := na
    confirmChochLevel := na
    confirmChochTime := na

    pullbackPrice := na
    pullbackBar := na
    pullbackTime := na

    confirmBosLevel := na
    confirmBosTime := na


// ════════════════════════════════════════════════════════════════
// SECTION 16: NEW M15 SHORT CONTEXT
// ════════════════════════════════════════════════════════════════

if (
     m15ShortContextPulse and
     allowShort and
     allowEntry
)

    contextDirection := -1
    confirmationPhase := 1

    contextStartBar := bar_index

    confirmChochBar := na
    confirmChochLevel := na
    confirmChochTime := na

    pullbackPrice := na
    pullbackBar := na
    pullbackTime := na

    confirmBosLevel := na
    confirmBosTime := na


// ════════════════════════════════════════════════════════════════
// SECTION 17: M1 CHoCH CONFIRMATION
// ════════════════════════════════════════════════════════════════

// ── Long Context → Bull CHoCH ───────────────────────────────────
if (
     contextDirection == 1 and
     confirmationPhase == 1 and
     bullCHoCH and
     not na(contextStartBar) and
     bar_index >= contextStartBar
)

    confirmChochBar := bar_index

    confirmChochLevel := structureHigh
    confirmChochTime := structureHighTime

    confirmationPhase := 2

    if showConfirmationStructure

        f_draw_structure(
             confirmChochTime,
             time_close,
             confirmChochLevel,
             "CHoCH",
             color.orange
        )


// ── Short Context → Bear CHoCH ──────────────────────────────────
if (
     contextDirection == -1 and
     confirmationPhase == 1 and
     bearCHoCH and
     not na(contextStartBar) and
     bar_index >= contextStartBar
)

    confirmChochBar := bar_index

    confirmChochLevel := structureLow
    confirmChochTime := structureLowTime

    confirmationPhase := 2

    if showConfirmationStructure

        f_draw_structure(
             confirmChochTime,
             time_close,
             confirmChochLevel,
             "CHoCH",
             color.orange
        )


// ════════════════════════════════════════════════════════════════
// SECTION 18: INVALIDATE FAILED REVERSAL
// ════════════════════════════════════════════════════════════════
//
// Long Context:
//
// Bull CHoCH occurs,
// but M1 structure produces Bear CHoCH before entry.
//
// → Keep M15 context.
// → Reset confirmation.
// → Wait for another Bull CHoCH.
//
// Short inverse.
// ════════════════════════════════════════════════════════════════

if (
     contextDirection == 1 and
     confirmationPhase >= 2 and
     bearCHoCH
)

    confirmationPhase := 1

    confirmChochBar := na
    confirmChochLevel := na
    confirmChochTime := na

    pullbackPrice := na
    pullbackBar := na
    pullbackTime := na

    confirmBosLevel := na
    confirmBosTime := na


if (
     contextDirection == -1 and
     confirmationPhase >= 2 and
     bullCHoCH
)

    confirmationPhase := 1

    confirmChochBar := na
    confirmChochLevel := na
    confirmChochTime := na

    pullbackPrice := na
    pullbackBar := na
    pullbackTime := na

    confirmBosLevel := na
    confirmBosTime := na


// ════════════════════════════════════════════════════════════════
// SECTION 19: LONG PULLBACK
// ════════════════════════════════════════════════════════════════

if (
     contextDirection == 1 and
     confirmationPhase == 2 and
     not na(pivotLow) and
     not na(confirmChochBar)
)

    bool validLongPullback = (
         pivotLowBar > confirmChochBar
    )

    if validLongPullback

        int impulseEndBar = (
             pivotLowBar -
             1
        )

        [
             calculatedBos,
             calculatedBosTime
        ] = f_highest_between(
             confirmChochBar,
             impulseEndBar
        )

        if not na(calculatedBos)

            pullbackPrice := pivotLow
            pullbackBar := pivotLowBar
            pullbackTime := pivotLowTime

            confirmBosLevel := calculatedBos
            confirmBosTime := calculatedBosTime

            confirmationPhase := 3


// ════════════════════════════════════════════════════════════════
// SECTION 20: SHORT PULLBACK
// ════════════════════════════════════════════════════════════════

if (
     contextDirection == -1 and
     confirmationPhase == 2 and
     not na(pivotHigh) and
     not na(confirmChochBar)
)

    bool validShortPullback = (
         pivotHighBar > confirmChochBar
    )

    if validShortPullback

        int impulseEndBar = (
             pivotHighBar -
             1
        )

        [
             calculatedBos,
             calculatedBosTime
        ] = f_lowest_between(
             confirmChochBar,
             impulseEndBar
        )

        if not na(calculatedBos)

            pullbackPrice := pivotHigh
            pullbackBar := pivotHighBar
            pullbackTime := pivotHighTime

            confirmBosLevel := calculatedBos
            confirmBosTime := calculatedBosTime

            confirmationPhase := 3


// ════════════════════════════════════════════════════════════════
// SECTION 21: LONG BOS CONFIRMATION
// ════════════════════════════════════════════════════════════════

if (
     contextDirection == 1 and
     confirmationPhase == 3 and
     not na(confirmBosLevel) and
     not na(pullbackBar)
)

    bool longBosBreak = (
         bar_index > pullbackBar and
         bullishBreakPrice > confirmBosLevel
    )

    bool longEMAOK = (
         not useEMAFilter or
         close > ema9
    )

    if (
         longBosBreak and
         longEMAOK and
         allowEntry
    )

        longEntrySignal := true

        if showConfirmationStructure

            f_draw_structure(
                 confirmBosTime,
                 time_close,
                 confirmBosLevel,
                 "BOS",
                 color.lime
            )

        contextDirection := 0
        confirmationPhase := 0


// ════════════════════════════════════════════════════════════════
// SECTION 22: SHORT BOS CONFIRMATION
// ════════════════════════════════════════════════════════════════

if (
     contextDirection == -1 and
     confirmationPhase == 3 and
     not na(confirmBosLevel) and
     not na(pullbackBar)
)

    bool shortBosBreak = (
         bar_index > pullbackBar and
         bearishBreakPrice < confirmBosLevel
    )

    bool shortEMAOK = (
         not useEMAFilter or
         close < ema9
    )

    if (
         shortBosBreak and
         shortEMAOK and
         allowEntry
    )

        shortEntrySignal := true

        if showConfirmationStructure

            f_draw_structure(
                 confirmBosTime,
                 time_close,
                 confirmBosLevel,
                 "BOS",
                 color.red
            )

        contextDirection := 0
        confirmationPhase := 0


// ════════════════════════════════════════════════════════════════
// SECTION 23: CANDIDATE STOP LOSS
// ════════════════════════════════════════════════════════════════

float candidateLongSL = (
     stopLossMode == "Manual Points"
     ? (
         close -
         manualSLPoints
     )
     : (
         stopLossMode == "ATR"
         ? (
             close -
             atrValue *
             atrStopMultiplier
         )
         : (
             m15ORLow -
             orStopBuffer
         )
     )
)

float candidateShortSL = (
     stopLossMode == "Manual Points"
     ? (
         close +
         manualSLPoints
     )
     : (
         stopLossMode == "ATR"
         ? (
             close +
             atrValue *
             atrStopMultiplier
         )
         : (
             m15ORHigh +
             orStopBuffer
         )
     )
)


// ════════════════════════════════════════════════════════════════
// SECTION 24: CANDIDATE TAKE PROFIT
// ════════════════════════════════════════════════════════════════

float candidateLongRisk = (
     close -
     candidateLongSL
)

float candidateShortRisk = (
     candidateShortSL -
     close
)

float candidateLongTP = (
     takeProfitMode == "Manual Points"
     ? (
         close +
         manualTPPoints
     )
     : (
         close +
         candidateLongRisk *
         takeProfitRR
     )
)

float candidateShortTP = (
     takeProfitMode == "Manual Points"
     ? (
         close -
         manualTPPoints
     )
     : (
         close -
         candidateShortRisk *
         takeProfitRR
     )
)


// ════════════════════════════════════════════════════════════════
// SECTION 25: VALID SIGNAL
// ════════════════════════════════════════════════════════════════

bool validLongSignal = (
     longEntrySignal and
     candidateLongRisk > 0.0 and
     candidateLongSL < close and
     candidateLongTP > close
)

bool validShortSignal = (
     shortEntrySignal and
     candidateShortRisk > 0.0 and
     candidateShortSL > close and
     candidateShortTP < close
)


// ════════════════════════════════════════════════════════════════
// SECTION 26: ACTIVE POSITION STATE
// ════════════════════════════════════════════════════════════════

var float activeLongSL = na
var float activeLongTP = na

var float activeShortSL = na
var float activeShortTP = na


// ════════════════════════════════════════════════════════════════
// SECTION 27: REVERSAL STATE
// ════════════════════════════════════════════════════════════════

var bool pendingReverseLong = false
var bool pendingReverseShort = false

var float pendingLongSL = na
var float pendingLongTP = na

var float pendingShortSL = na
var float pendingShortTP = na


// ════════════════════════════════════════════════════════════════
// SECTION 28: LONG SIGNAL HANDLING
// ════════════════════════════════════════════════════════════════

if validLongSignal

    // ── Flat → Long ─────────────────────────────────────────────
    if strategy.position_size == 0

        activeLongSL := candidateLongSL
        activeLongTP := candidateLongTP

        activeShortSL := na
        activeShortTP := na

        strategy.entry(
             "Long",
             strategy.long,
             alert_message="ENTRY_LONG_M15_CONTEXT_M1_CONFIRM"
        )

    // ── Short → Long ────────────────────────────────────────────
    else if strategy.position_size < 0

        pendingReverseLong := true
        pendingReverseShort := false

        pendingLongSL := candidateLongSL
        pendingLongTP := candidateLongTP

        strategy.close(
             "Short",
             immediately=true,
             comment="Reverse Short To Long",
             alert_message="EXIT_SHORT_REVERSE_TO_LONG"
        )


// ════════════════════════════════════════════════════════════════
// SECTION 29: SHORT SIGNAL HANDLING
// ════════════════════════════════════════════════════════════════

if validShortSignal

    // ── Flat → Short ────────────────────────────────────────────
    if strategy.position_size == 0

        activeShortSL := candidateShortSL
        activeShortTP := candidateShortTP

        activeLongSL := na
        activeLongTP := na

        strategy.entry(
             "Short",
             strategy.short,
             alert_message="ENTRY_SHORT_M15_CONTEXT_M1_CONFIRM"
        )

    // ── Long → Short ────────────────────────────────────────────
    else if strategy.position_size > 0

        pendingReverseShort := true
        pendingReverseLong := false

        pendingShortSL := candidateShortSL
        pendingShortTP := candidateShortTP

        strategy.close(
             "Long",
             immediately=true,
             comment="Reverse Long To Short",
             alert_message="EXIT_LONG_REVERSE_TO_SHORT"
        )


// ════════════════════════════════════════════════════════════════
// SECTION 30: EXECUTE PENDING LONG REVERSAL
// ════════════════════════════════════════════════════════════════

if (
     pendingReverseLong and
     strategy.position_size == 0
)

    activeLongSL := pendingLongSL
    activeLongTP := pendingLongTP

    activeShortSL := na
    activeShortTP := na

    strategy.entry(
         "Long",
         strategy.long,
         alert_message="ENTRY_LONG_AFTER_SHORT_EXIT"
    )

    pendingReverseLong := false

    pendingLongSL := na
    pendingLongTP := na


// ════════════════════════════════════════════════════════════════
// SECTION 31: EXECUTE PENDING SHORT REVERSAL
// ════════════════════════════════════════════════════════════════

if (
     pendingReverseShort and
     strategy.position_size == 0
)

    activeShortSL := pendingShortSL
    activeShortTP := pendingShortTP

    activeLongSL := na
    activeLongTP := na

    strategy.entry(
         "Short",
         strategy.short,
         alert_message="ENTRY_SHORT_AFTER_LONG_EXIT"
    )

    pendingReverseShort := false

    pendingShortSL := na
    pendingShortTP := na


// ════════════════════════════════════════════════════════════════
// SECTION 32: MAINTAIN LONG EXIT
// ════════════════════════════════════════════════════════════════

if (
     strategy.position_size > 0 and
     not na(activeLongSL) and
     not na(activeLongTP)
)

    strategy.exit(
         "Long Exit",
         from_entry="Long",
         stop=activeLongSL,
         limit=activeLongTP,
         disable_alert=disableSLTPAlerts
    )


// ════════════════════════════════════════════════════════════════
// SECTION 33: MAINTAIN SHORT EXIT
// ════════════════════════════════════════════════════════════════

if (
     strategy.position_size < 0 and
     not na(activeShortSL) and
     not na(activeShortTP)
)

    strategy.exit(
         "Short Exit",
         from_entry="Short",
         stop=activeShortSL,
         limit=activeShortTP,
         disable_alert=disableSLTPAlerts
    )


// ════════════════════════════════════════════════════════════════
// SECTION 34: POSITION CLEANUP
// ════════════════════════════════════════════════════════════════

if (
     strategy.position_size == 0 and
     bar_index > 0 and
     strategy.position_size[1] != 0 and
     not pendingReverseLong and
     not pendingReverseShort
)

    activeLongSL := na
    activeLongTP := na

    activeShortSL := na
    activeShortTP := na


// ════════════════════════════════════════════════════════════════
// SECTION 35: FORCE FLAT AT SESSION END
// ════════════════════════════════════════════════════════════════

if finalSessionBar

    pendingReverseLong := false
    pendingReverseShort := false

    pendingLongSL := na
    pendingLongTP := na

    pendingShortSL := na
    pendingShortTP := na

    contextDirection := 0
    confirmationPhase := 0

    if strategy.position_size != 0

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


// ════════════════════════════════════════════════════════════════
// SECTION 36: M15 OPENING RANGE
// ════════════════════════════════════════════════════════════════

plot(
     (
         showOpeningRange and
         inSession
     )
     ? m15ORHigh
     : na,
     title="M15 OR High",
     color=color.green,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     (
         showOpeningRange and
         inSession
     )
     ? m15ORLow
     : na,
     title="M15 OR Low",
     color=color.red,
     linewidth=2,
     style=plot.style_linebr
)


// ════════════════════════════════════════════════════════════════
// SECTION 37: M1 EMA
// ════════════════════════════════════════════════════════════════

plot(
     showEMA
     ? ema9
     : na,
     title="EMA9 M1",
     color=color.yellow,
     linewidth=1
)


// ════════════════════════════════════════════════════════════════
// SECTION 38: M15 CONTEXT MARKERS
// ════════════════════════════════════════════════════════════════

plotshape(
     (
         showContextMarkers and
         m15LongContextPulse
     ),
     title="M15 Long Context",
     location=location.belowbar,
     style=shape.circle,
     size=size.small,
     color=color.green,
     text="M15 L",
     textcolor=color.white
)

plotshape(
     (
         showContextMarkers and
         m15ShortContextPulse
     ),
     title="M15 Short Context",
     location=location.abovebar,
     style=shape.circle,
     size=size.small,
     color=color.red,
     text="M15 S",
     textcolor=color.white
)


// ════════════════════════════════════════════════════════════════
// SECTION 39: ENTRY MARKERS
// ════════════════════════════════════════════════════════════════

plotshape(
     (
         showEntryMarkers and
         validLongSignal
     ),
     title="Long Confirmed",
     location=location.belowbar,
     style=shape.triangleup,
     size=size.normal,
     color=color.lime,
     text="LONG",
     textcolor=color.white
)

plotshape(
     (
         showEntryMarkers and
         validShortSignal
     ),
     title="Short Confirmed",
     location=location.abovebar,
     style=shape.triangledown,
     size=size.normal,
     color=color.red,
     text="SHORT",
     textcolor=color.white
)


// ════════════════════════════════════════════════════════════════
// SECTION 40: ACTIVE LONG LEVELS
// ════════════════════════════════════════════════════════════════

plot(
     (
         showActiveLevels and
         strategy.position_size > 0
     )
     ? activeLongSL
     : na,
     title="Active Long SL",
     color=color.red,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     (
         showActiveLevels and
         strategy.position_size > 0
     )
     ? activeLongTP
     : na,
     title="Active Long TP",
     color=color.green,
     linewidth=2,
     style=plot.style_linebr
)


// ════════════════════════════════════════════════════════════════
// SECTION 41: ACTIVE SHORT LEVELS
// ════════════════════════════════════════════════════════════════

plot(
     (
         showActiveLevels and
         strategy.position_size < 0
     )
     ? activeShortSL
     : na,
     title="Active Short SL",
     color=color.red,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     (
         showActiveLevels and
         strategy.position_size < 0
     )
     ? activeShortTP
     : na,
     title="Active Short TP",
     color=color.green,
     linewidth=2,
     style=plot.style_linebr
)