//@version=6
strategy(
     title="CNPS14 IMPULSE-PB",
     shorttitle="CNPS14 IMPULSE-PB",
     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
)


// ╔══════════════════════════════════════════════════════════════╗
// ║                  CNPS14 IMPULSE-PB                          ║
// ║              IMPULSE -> FIRST PULLBACK                     ║
// ╠══════════════════════════════════════════════════════════════╣
// ║ Execution Chart : M1                                       ║
// ║ Context         : M5                                       ║
// ║ Position Size   : 3 Contracts                              ║
// ║ Commission      : VND 10,000 / Contract                    ║
// ║                                                             ║
// ║ FIXED RISK                                                  ║
// ║ Stop Loss       : 5 Points                                 ║
// ║ Take Profit     : 15 Points                                ║
// ║ Nominal RR      : 1:3                                      ║
// ║                                                             ║
// ║ LONG                                                        ║
// ║ Bullish M5 Impulse                                         ║
// ║ -> Wait First Pullback 38.2% - 61.8%                       ║
// ║ -> Cancel if Retracement > 65%                             ║
// ║ -> M1 Close > Previous M1 High                             ║
// ║ -> LONG                                                     ║
// ║                                                             ║
// ║ SHORT                                                       ║
// ║ Bearish M5 Impulse                                         ║
// ║ -> Wait First Pullback 38.2% - 61.8%                       ║
// ║ -> Cancel if Retracement > 65%                             ║
// ║ -> M1 Close < Previous M1 Low                              ║
// ║ -> SHORT                                                    ║
// ╚══════════════════════════════════════════════════════════════╝


// ============================================================================
// SECTION 1: FIXED RISK PARAMETERS
// ============================================================================

float FIXED_SL_POINTS = 5.0
float FIXED_TP_POINTS = 15.0


// ============================================================================
// SECTION 2: INPUTS
// ============================================================================


// ── M5 Impulse ──────────────────────────────────────────────────────────────

impulseBars = input.int(
     3,
     title="M5 Impulse Bars",
     minval=2,
     maxval=6,
     group="M5 Impulse"
)

m5ATRLength = input.int(
     14,
     title="M5 ATR Length",
     minval=2,
     group="M5 Impulse"
)

impulseATRMultiplier = input.float(
     1.30,
     title="Minimum Impulse / M5 ATR",
     minval=0.5,
     step=0.05,
     group="M5 Impulse"
)

minimumDirectionalBars = input.int(
     2,
     title="Minimum Directional M5 Bars",
     minval=1,
     maxval=6,
     group="M5 Impulse"
)

minimumClosePosition = input.float(
     0.70,
     title="Minimum Close Position In Impulse",
     minval=0.50,
     maxval=0.95,
     step=0.05,
     group="M5 Impulse"
)

minimumImpulsePoints = input.float(
     5.0,
     title="Minimum Impulse Width (Points)",
     minval=0.1,
     step=0.5,
     group="M5 Impulse"
)


// ── First Pullback ──────────────────────────────────────────────────────────

pullbackStartPercent = input.float(
     38.2,
     title="Pullback Zone Start (%)",
     minval=10.0,
     maxval=60.0,
     step=0.1,
     group="First Pullback"
)

pullbackEndPercent = input.float(
     61.8,
     title="Pullback Zone End (%)",
     minval=20.0,
     maxval=80.0,
     step=0.1,
     group="First Pullback"
)

maximumRetracementPercent = input.float(
     65.0,
     title="Maximum Retracement Before Invalidation (%)",
     minval=30.0,
     maxval=95.0,
     step=0.5,
     group="First Pullback"
)

setupExpiryBars = input.int(
     30,
     title="Setup Expiration (M1 Bars)",
     minval=5,
     maxval=120,
     group="First Pullback"
)


// ── M1 Confirmation ─────────────────────────────────────────────────────────

requireDirectionalEntryCandle = input.bool(
     true,
     title="Require Directional Entry Candle?",
     group="M1 Confirmation"
)

minimumEntryBodyRatio = input.float(
     0.30,
     title="Minimum Entry Candle Body / Range",
     minval=0.0,
     maxval=1.0,
     step=0.05,
     group="M1 Confirmation"
)


// ── 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(
     false,
     title="Disable SL / TP Alerts?",
     group="Alert Control"
)


// ── Display ──────────────────────────────────────────────────────────────────

showImpulseLevels = input.bool(
     true,
     title="Show Active Impulse High / Low?",
     group="Display"
)

showPullbackZone = input.bool(
     true,
     title="Show Pullback Zone?",
     group="Display"
)

showInvalidationLevel = input.bool(
     true,
     title="Show 65% Invalidation Level?",
     group="Display"
)

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

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

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


// ============================================================================
// SECTION 3: SESSION / EXECUTION
// ============================================================================

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

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 and
     barstate.isconfirmed
)

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

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


// ============================================================================
// SECTION 4: M5 IMPULSE ENGINE
// ============================================================================

f_m5_impulse(
     int barsCount,
     int atrLen,
     float atrMultiplier,
     int requiredDirectionalBars,
     float closePositionThreshold,
     float minImpulseWidth,
     int startMinute,
     int endMinute
) =>

    float atrValue = ta.atr(
         atrLen
    )

    float impulseHighValue = ta.highest(
         high,
         barsCount
    )

    float impulseLowValue = ta.lowest(
         low,
         barsCount
    )

    float impulseWidthValue = (
         impulseHighValue -
         impulseLowValue
    )

    float firstOpen = (
         open[barsCount - 1]
    )

    float bullishDisplacement = (
         close -
         firstOpen
    )

    float bearishDisplacement = (
         firstOpen -
         close
    )

    float closePosition = (
         impulseWidthValue > 0
         ? (
             close -
             impulseLowValue
         ) / impulseWidthValue
         : 0.5
    )

    int bullishBars = 0
    int bearishBars = 0

    for i = 0 to barsCount - 1

        if close[i] > open[i]
            bullishBars += 1

        if close[i] < open[i]
            bearishBars += 1


    int oldestTime = (
         time[barsCount - 1]
    )

    int oldestMinute = (
         hour(oldestTime) * 60 +
         minute(oldestTime)
    )

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

    bool sameDateWindow = (
         year(oldestTime) == year(time) and
         month(oldestTime) == month(time) and
         dayofmonth(oldestTime) == dayofmonth(time)
    )

    bool contiguousWindow = (
         time -
         oldestTime ==
         (
             barsCount -
             1
         ) *
         300000
    )

    bool validSessionWindow = (
         oldestMinute >= startMinute and
         newestCloseMinute <= endMinute
    )

    bool validBase = (
         sameDateWindow and
         contiguousWindow and
         validSessionWindow and
         not na(atrValue) and
         atrValue > 0 and
         impulseWidthValue >= minImpulseWidth
    )

    bool bullishImpulse = (
         validBase and
         bullishDisplacement >= atrValue * atrMultiplier and
         bullishBars >= requiredDirectionalBars and
         closePosition >= closePositionThreshold
    )

    bool bearishImpulse = (
         validBase and
         bearishDisplacement >= atrValue * atrMultiplier and
         bearishBars >= requiredDirectionalBars and
         closePosition <= (
             1.0 -
             closePositionThreshold
         )
    )

    [
         bullishImpulse,
         bearishImpulse,
         impulseHighValue,
         impulseLowValue,
         time,
         time_close
    ]


// ============================================================================
// SECTION 5: REQUEST M5 CONTEXT
// ============================================================================

[
     m5BullImpulseRaw,
     m5BearImpulseRaw,
     m5ImpulseHighRaw,
     m5ImpulseLowRaw,
     m5ImpulseTimeRaw,
     m5ImpulseCloseTimeRaw
] = request.security(
     syminfo.tickerid,
     "5",
     f_m5_impulse(
         impulseBars,
         m5ATRLength,
         impulseATRMultiplier,
         minimumDirectionalBars,
         minimumClosePosition,
         minimumImpulsePoints,
         sessionStartTotal,
         sessionEndTotal
     ),
     gaps=barmerge.gaps_off,
     lookahead=barmerge.lookahead_off
)


// Generate only one M1 pulse when a new M5 impulse appears.

bool bullImpulsePulse = (
     isM1Chart and
     m5BullImpulseRaw and
     not m5BullImpulseRaw[1]
)

bool bearImpulsePulse = (
     isM1Chart and
     m5BearImpulseRaw and
     not m5BearImpulseRaw[1]
)

bool ambiguousImpulse = (
     bullImpulsePulse and
     bearImpulsePulse
)


// ============================================================================
// SECTION 6: SETUP STATE
// ============================================================================
//
// setupDirection:
//  1 = Waiting for LONG pullback.
// -1 = Waiting for SHORT pullback.
//  0 = No active setup.
// ============================================================================

var int setupDirection = 0

var float activeImpulseHigh = na
var float activeImpulseLow = na
var float activeImpulseWidth = na

var float pullbackZoneUpper = na
var float pullbackZoneLower = na

var float setupInvalidationLevel = na

var int setupStartBar = na

var bool pullbackTouched = false


// ============================================================================
// SECTION 7: SESSION RESET
// ============================================================================

if newSession

    setupDirection := 0

    activeImpulseHigh := na
    activeImpulseLow := na
    activeImpulseWidth := na

    pullbackZoneUpper := na
    pullbackZoneLower := na

    setupInvalidationLevel := na

    setupStartBar := na

    pullbackTouched := false


// ============================================================================
// SECTION 8: ARM LONG SETUP
// ============================================================================

if (
     bullImpulsePulse and
     not ambiguousImpulse and
     allowLong and
     inSession and
     strategy.position_size == 0
)

    float width = (
         m5ImpulseHighRaw -
         m5ImpulseLowRaw
    )

    if width > 0

        setupDirection := 1

        activeImpulseHigh := m5ImpulseHighRaw
        activeImpulseLow := m5ImpulseLowRaw
        activeImpulseWidth := width

        pullbackZoneUpper := (
             activeImpulseHigh -
             activeImpulseWidth *
             (
                 pullbackStartPercent /
                 100.0
             )
        )

        pullbackZoneLower := (
             activeImpulseHigh -
             activeImpulseWidth *
             (
                 pullbackEndPercent /
                 100.0
             )
        )

        setupInvalidationLevel := (
             activeImpulseHigh -
             activeImpulseWidth *
             (
                 maximumRetracementPercent /
                 100.0
             )
        )

        setupStartBar := bar_index
        pullbackTouched := false


// ============================================================================
// SECTION 9: ARM SHORT SETUP
// ============================================================================

if (
     bearImpulsePulse and
     not ambiguousImpulse and
     allowShort and
     inSession and
     strategy.position_size == 0
)

    float width = (
         m5ImpulseHighRaw -
         m5ImpulseLowRaw
    )

    if width > 0

        setupDirection := -1

        activeImpulseHigh := m5ImpulseHighRaw
        activeImpulseLow := m5ImpulseLowRaw
        activeImpulseWidth := width

        pullbackZoneLower := (
             activeImpulseLow +
             activeImpulseWidth *
             (
                 pullbackStartPercent /
                 100.0
             )
        )

        pullbackZoneUpper := (
             activeImpulseLow +
             activeImpulseWidth *
             (
                 pullbackEndPercent /
                 100.0
             )
        )

        setupInvalidationLevel := (
             activeImpulseLow +
             activeImpulseWidth *
             (
                 maximumRetracementPercent /
                 100.0
             )
        )

        setupStartBar := bar_index
        pullbackTouched := false


// ============================================================================
// SECTION 10: SETUP EXPIRATION
// ============================================================================

bool setupExpired = (
     setupDirection != 0 and
     not na(setupStartBar) and
     bar_index -
     setupStartBar >
     setupExpiryBars
)

if setupExpired

    setupDirection := 0
    pullbackTouched := false


// ============================================================================
// SECTION 11: SETUP INVALIDATION
// ============================================================================

bool longSetupInvalidated = (
     setupDirection == 1 and
     not na(setupInvalidationLevel) and
     low < setupInvalidationLevel
)

bool shortSetupInvalidated = (
     setupDirection == -1 and
     not na(setupInvalidationLevel) and
     high > setupInvalidationLevel
)

if (
     longSetupInvalidated or
     shortSetupInvalidated
)

    setupDirection := 0
    pullbackTouched := false


// ============================================================================
// SECTION 12: FIRST PULLBACK DETECTION
// ============================================================================


// Bullish impulse:
// Wait for price to retrace into the Fibonacci pullback zone.

bool longZoneTouch = (
     allowEntry and
     setupDirection == 1 and
     low <= pullbackZoneUpper and
     high >= pullbackZoneLower
)

if longZoneTouch

    pullbackTouched := true


// Bearish impulse:
// Wait for price to retrace upward into the Fibonacci pullback zone.

bool shortZoneTouch = (
     allowEntry and
     setupDirection == -1 and
     high >= pullbackZoneLower and
     low <= pullbackZoneUpper
)

if shortZoneTouch

    pullbackTouched := true


// ============================================================================
// SECTION 13: M1 ENTRY CANDLE QUALITY
// ============================================================================

float currentCandleRange = (
     high -
     low
)

float currentBody = (
     math.abs(
         close -
         open
     )
)

float currentBodyRatio = (
     currentCandleRange > 0
     ? currentBody /
       currentCandleRange
     : 0.0
)

bool entryBodyOK = (
     currentBodyRatio >=
     minimumEntryBodyRatio
)


// ============================================================================
// SECTION 14: FAST CONTINUATION CONFIRMATION
// ============================================================================
//
// LONG:
// Pullback touched.
// Current M1 closes above previous M1 high.
//
// SHORT:
// Pullback touched.
// Current M1 closes below previous M1 low.
// ============================================================================

bool rawLongSignal = (
     allowEntry and
     setupDirection == 1 and
     pullbackTouched and
     close > high[1] and
     entryBodyOK and
     (
         not requireDirectionalEntryCandle or
         close > open
     )
)

bool rawShortSignal = (
     allowEntry and
     setupDirection == -1 and
     pullbackTouched and
     close < low[1] and
     entryBodyOK and
     (
         not requireDirectionalEntryCandle or
         close < open
     )
)

bool ambiguousEntrySignal = (
     rawLongSignal and
     rawShortSignal
)

bool longSignal = (
     rawLongSignal and
     not ambiguousEntrySignal and
     strategy.position_size == 0
)

bool shortSignal = (
     rawShortSignal and
     not ambiguousEntrySignal and
     strategy.position_size == 0
)


// ============================================================================
// SECTION 15: ENTRY ORDERS
// ============================================================================

if longSignal

    // Consume setup immediately after entry.
    setupDirection := 0
    pullbackTouched := false

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


if shortSignal

    // Consume setup immediately after entry.
    setupDirection := 0
    pullbackTouched := false

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


// ============================================================================
// SECTION 16: FIXED LONG SL / TP
// ============================================================================

var float activeLongSL = na
var float activeLongTP = na

var float activeShortSL = na
var float activeShortTP = na


if strategy.position_size > 0

    float entryPrice = (
         strategy.position_avg_price
    )

    activeLongSL := (
         entryPrice -
         FIXED_SL_POINTS
    )

    activeLongTP := (
         entryPrice +
         FIXED_TP_POINTS
    )

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


// ============================================================================
// SECTION 17: FIXED SHORT SL / TP
// ============================================================================

if strategy.position_size < 0

    float entryPrice = (
         strategy.position_avg_price
    )

    activeShortSL := (
         entryPrice +
         FIXED_SL_POINTS
    )

    activeShortTP := (
         entryPrice -
         FIXED_TP_POINTS
    )

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


// ============================================================================
// SECTION 18: POSITION CLEANUP
// ============================================================================

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

if positionJustClosed

    activeLongSL := na
    activeLongTP := na

    activeShortSL := na
    activeShortTP := na


// ============================================================================
// SECTION 19: SESSION END
// ============================================================================

if finalSessionBar

    setupDirection := 0
    pullbackTouched := false

    if strategy.position_size != 0

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


// ============================================================================
// SECTION 20: IMPULSE DISPLAY
// ============================================================================

plot(
     showImpulseLevels and
     setupDirection != 0
     ? activeImpulseHigh
     : na,
     title="Impulse High",
     color=color.green,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     showImpulseLevels and
     setupDirection != 0
     ? activeImpulseLow
     : na,
     title="Impulse Low",
     color=color.red,
     linewidth=2,
     style=plot.style_linebr
)


// ============================================================================
// SECTION 21: PULLBACK ZONE DISPLAY
// ============================================================================

plot(
     showPullbackZone and
     setupDirection != 0
     ? pullbackZoneUpper
     : na,
     title="Pullback Zone Upper",
     color=color.orange,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     showPullbackZone and
     setupDirection != 0
     ? pullbackZoneLower
     : na,
     title="Pullback Zone Lower",
     color=color.orange,
     linewidth=2,
     style=plot.style_linebr
)

plot(
     showInvalidationLevel and
     setupDirection != 0
     ? setupInvalidationLevel
     : na,
     title="Maximum Retracement",
     color=color.red,
     linewidth=1,
     style=plot.style_linebr
)


// ============================================================================
// SECTION 22: OPTIONAL SIGNAL MARKERS
// ============================================================================
//
// These are setup signals only.
// TradingView Strategy order markers remain the authoritative fills.
// ============================================================================

plotshape(
     showSignalMarkers and
     longSignal,
     title="Long Signal",
     style=shape.triangleup,
     location=location.belowbar,
     size=size.small,
     color=color.lime,
     text="L",
     textcolor=color.white
)

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


// ============================================================================
// SECTION 23: ACTIVE SL / TP DISPLAY
// ============================================================================

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

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

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

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


// ============================================================================
// SECTION 24: DIAGNOSTICS
// ============================================================================

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

if showDiagnostics and barstate.islast

    string setupText = (
         setupDirection == 1
         ? "WAIT LONG"
         : (
             setupDirection == -1
             ? "WAIT SHORT"
             : "NONE"
         )
    )

    table.cell(
         diagnostics,
         0,
         0,
         "CNPS14 IMPULSE-PB",
         text_color=color.white,
         bgcolor=color.black
    )

    table.cell(
         diagnostics,
         1,
         0,
         isM1Chart
         ? "M1 OK"
         : "USE M1",
         text_color=color.white,
         bgcolor=color.black
    )

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

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

    table.cell(
         diagnostics,
         0,
         2,
         "Impulse High"
    )

    table.cell(
         diagnostics,
         1,
         2,
         str.tostring(
             activeImpulseHigh
         )
    )

    table.cell(
         diagnostics,
         0,
         3,
         "Impulse Low"
    )

    table.cell(
         diagnostics,
         1,
         3,
         str.tostring(
             activeImpulseLow
         )
    )

    table.cell(
         diagnostics,
         0,
         4,
         "PB Upper"
    )

    table.cell(
         diagnostics,
         1,
         4,
         str.tostring(
             pullbackZoneUpper
         )
    )

    table.cell(
         diagnostics,
         0,
         5,
         "PB Lower"
    )

    table.cell(
         diagnostics,
         1,
         5,
         str.tostring(
             pullbackZoneLower
         )
    )

    table.cell(
         diagnostics,
         0,
         6,
         "PB Touched"
    )

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

    table.cell(
         diagnostics,
         0,
         7,
         "Fixed SL"
    )

    table.cell(
         diagnostics,
         1,
         7,
         "5 pts"
    )

    table.cell(
         diagnostics,
         0,
         8,
         "Fixed TP"
    )

    table.cell(
         diagnostics,
         1,
         8,
         "15 pts"
    )

    table.cell(
         diagnostics,
         0,
         9,
         "Closed Trades"
    )

    table.cell(
         diagnostics,
         1,
         9,
         str.tostring(
             strategy.closedtrades
         )
    )