RSI Divergence Entry Engine [trade_w_samet]

tradewsamet · study · 2104 行 · 点赞 4,105 · TradingView 原页

本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。

Pine Script

//@version=6
// RSI Divergence Entry Engine [trade_w_samet]
// Final production version
// Non-repainting confirmed divergence logic with themes, trend filters,
// ATR trade management, historical trade visuals, statistics and alerts.
indicator(
     title="RSI Divergence Entry Engine [trade_w_samet]",
     shorttitle="RSI Divergence Entry Engine [trade_w_samet]",
     format=format.price,
     explicit_plot_zorder=true,
     max_labels_count=500,
     max_boxes_count=500,
     max_lines_count=500,
     max_polylines_count=100
)
 
//==============================================================================
// SIMPLE SETTINGS
//==============================================================================
 
groupTheme = "🎨 Theme"
groupSignal = "🎯 Signal Settings"
groupTrend = "🧭 Trend Filter"
groupTrade = "🛡️ Trade Management"
 
themeMode = input.string(
     defval="Dark Mode",
     title="🎨 Theme Mode",
     options=[
          "Dark Mode",
          "Light Mode",
          "Mobile Theme"
     ],
     tooltip="Dark Mode preserves the current premium appearance. Light Mode uses high-contrast colors for white chart backgrounds. Mobile Theme uses compact labels and a dashboard showing only Win Rate and NET R.",
     group=groupTheme,
     display=display.none
)
 
isLightMode = themeMode == "Light Mode"
isMobileTheme = themeMode == "Mobile Theme"
 
// Only the essential signal controls remain visible.
lbL = input.int(
     defval=47,
     minval=1,
     maxval=50,
     title="🔍 Pivot Lookback",
     tooltip="Higher values find larger RSI swing points. The standard value is 5.",
     group=groupSignal,
     display=display.none
)
 
lbR = input.int(
     defval=1,
     minval=1,
     maxval=10,
     title="✅ Confirmation Bars",
     tooltip="Number of closed candles required to confirm the divergence pivot. Lower values give earlier signals.",
     group=groupSignal,
     display=display.none
)
 
signalLabelSize = input.string(
     defval="Normal",
     title="🏷️ Chart Signal Label Size",
     options=[
          "Tiny",
          "Small",
          "Normal",
          "Large",
          "Huge"
     ],
     tooltip="Changes only the BULLISH and SELL labels on the main price chart. RSI panel labels stay at Normal size.",
     group=groupSignal,
     display=display.none
)
 
signalLabelSizeValue =
     signalLabelSize == "Tiny" ?
     size.tiny :
     signalLabelSize == "Small" ?
     size.small :
     signalLabelSize == "Normal" ?
     size.normal :
     signalLabelSize == "Huge" ?
     size.huge :
     size.large
 
chartSignalLabelSize =
     isMobileTheme ?
     size.small :
     signalLabelSizeValue
 
rsiSignalLabelSize =
     isMobileTheme ?
     size.small :
     size.normal
 
priceLabelSize =
     isMobileTheme ?
     size.tiny :
     size.small
 
exitLabelSize =
     isMobileTheme ?
     size.small :
     size.normal
 
//==============================================================================
// TRADE SETTINGS
//==============================================================================
 
atrLength = input.int(
     defval=14,
     minval=1,
     title="📊 ATR Period",
     tooltip="Measures current market volatility. The standard value is 14.",
     group=groupTrade,
     display=display.none
)
 
atrMultiplier = input.float(
     defval=2.0,
     minval=0.1,
     step=0.1,
     title="🛑 Stop Loss Distance (ATR)",
     tooltip="Example: 2.0 places the stop loss two ATR distances away from entry.",
     group=groupTrade,
     display=display.none
)
 
tp3RewardRisk = input.int(
     defval=6,
     minval=1,
     maxval=7,
     title="🏆 TP3 Target (R)",
     tooltip="Choose the final target from 1R to 7R. TP1 and TP2 are placed automatically at one-third and two-thirds of the TP3 distance.",
     group=groupTrade,
     display=display.none
)
 
//==============================================================================
// TREND FILTER SETTINGS
//==============================================================================
 
trendFilterMode = input.string(
     defval="Off",
     title="🧭 Trend Filter",
     options=[
          "Off",
          "EMA Trend",
          "Supertrend",
          "HTF Trend"
     ],
     tooltip="Off allows every confirmed divergence entry. EMA Trend allows bullish entries above the chart EMA 200 and bearish entries below it. Supertrend uses a fixed 10 ATR period and 3.0 factor. HTF Trend compares the selected higher-timeframe close with its EMA 200.",
     group=groupTrend,
     display=display.none
)
 
trendTimeframe = input.timeframe(
     defval="240",
     title="⏱️ HTF Trend Timeframe",
     tooltip="Higher timeframe used only when HTF Trend is selected. The default value is 4 hours.",
     group=groupTrend,
     display=display.none
)
 
//==============================================================================
// BACKGROUND SETTINGS
// Fixed internally to keep the settings panel simple.
//==============================================================================
 
int len = 14
float src = close
 
int rangeUpper = 60
int rangeLower = 5
 
bool plotBull = true
bool plotHiddenBull = false
bool plotBear = true
bool plotHiddenBear = false
 
bool showChartLabels = true
bool showTradeLevels = true
bool showExitLabels = true
bool showStats = true
 
//==============================================================================
// COLORS
//==============================================================================
 
brandRed = color.rgb(225, 29, 46)
brandBlack = color.rgb(12, 12, 14)
brandWhite = color.rgb(245, 245, 247)
 
bearColor = color.rgb(255, 76, 110)
bullColor = color.rgb(0, 200, 150)
 
themeBackground =
     isLightMode ?
     color.rgb(250, 250, 252) :
     brandBlack
 
themeSurface =
     isLightMode ?
     color.rgb(255, 255, 255) :
     color.rgb(18, 18, 21)
 
themeText =
     isLightMode ?
     color.rgb(15, 15, 18) :
     brandWhite
 
themeMutedText =
     isLightMode ?
     color.rgb(80, 80, 88) :
     color.rgb(196, 196, 204)
 
themeBorder =
     isLightMode ?
     color.new(brandBlack, 72) :
     color.new(brandWhite, 78)
 
themeHeader =
     isLightMode ?
     color.new(brandRed, 4) :
     color.new(brandRed, 18)
 
themeHeaderText =
     isLightMode ?
     brandWhite :
     brandWhite
 
hiddenBullColor = color.new(bullColor, 80)
hiddenBearColor = color.new(bearColor, 80)
 
textColor = themeText
noneColor = color.new(themeText, 100)
 
entryColor =
     isLightMode ?
     brandBlack :
     brandWhite
 
tp1Color = color.new(bullColor, 60)
tp2Color = color.new(bullColor, 30)
tp3Color = bullColor
slColor = bearColor
 
bullZoneColor =
     isLightMode ?
     color.new(bullColor, 88) :
     color.new(bullColor, 84)
 
bearZoneColor =
     isLightMode ?
     color.new(bearColor, 82) :
     color.new(bearColor, 68)
 
bullZoneBorderColor =
     isLightMode ?
     color.new(bullColor, 38) :
     color.new(bullColor, 25)
 
bearZoneBorderColor =
     isLightMode ?
     color.new(bearColor, 72) :
     color.new(bearColor, 88)
 
//==============================================================================
// RSI
//==============================================================================
 
osc = ta.rsi(src, len)
 
plot(
     osc,
     title="RSI",
     linewidth=2,
     color=isLightMode ? color.rgb(25, 90, 210) : color.rgb(41, 98, 255),
     display=display.pane
)
 
bgcolor(
     isLightMode ?
     color.rgb(250, 250, 252) :
     color.rgb(0, 0, 0),
     title="Theme Background"
)
 
hline(
     50,
     title="Middle Line",
     color=isLightMode ? color.rgb(25, 25, 28) : color.white,
     linestyle=hline.style_dotted,
     linewidth=1
)
 
obLevel = hline(
     70,
     title="Overbought",
     color=isLightMode ? color.rgb(210, 30, 55) : bearColor,
     linestyle=hline.style_solid,
     linewidth=1
)
 
osLevel = hline(
     30,
     title="Oversold",
     color=isLightMode ? color.rgb(0, 145, 105) : bullColor,
     linestyle=hline.style_solid,
     linewidth=1
)
 
fill(
     obLevel,
     osLevel,
     title="RSI Range Background",
     color=color.new(
          isLightMode ?
          color.rgb(250, 250, 252) :
          color.rgb(0, 0, 0),
          100
     )
)
 
//==============================================================================
// PIVOT DETECTION
//==============================================================================
 
pivotLowValue = ta.pivotlow(osc, lbL, lbR)
pivotHighValue = ta.pivothigh(osc, lbL, lbR)
 
plFound = not na(pivotLowValue)
phFound = not na(pivotHighValue)
 
_inRange(bool condition) =>
    int barsSince = ta.barssince(condition)
    rangeLower <= barsSince and barsSince <= rangeUpper
 
inRangePl = _inRange(plFound[1])
inRangePh = _inRange(phFound[1])
 
//==============================================================================
// RSI DIVERGENCE BACKGROUND ZONES
// When a valid divergence forms, the RSI area between the two pivot points
// is highlighted with a modern translucent box.
//==============================================================================
 
var array<polyline> rsiDivergenceZones = array.new<polyline>()
int maxRsiZones = 100
 
createRsiZone(
     bool shouldCreate,
     int leftBar,
     int rightBar,
     color zoneBg,
     color zoneBorder
) =>
    if shouldCreate and not na(leftBar) and not na(rightBar) and rightBar > leftBar
        array<chart.point> zonePoints = array.new<chart.point>()
 
        for zoneBar = leftBar to rightBar
            int offset = bar_index - zoneBar
            if offset >= 0
                array.push(
                     zonePoints,
                     chart.point.from_index(
                          zoneBar,
                          osc[offset]
                     )
                )
 
        if array.size(zonePoints) >= 2
            polyline zonePoly = polyline.new(
                 points=zonePoints,
                 curved=false,
                 closed=true,
                 xloc=xloc.bar_index,
                 line_color=zoneBorder,
                 fill_color=zoneBg,
                 line_style=line.style_solid,
                 line_width=2
            )
 
            array.push(
                 rsiDivergenceZones,
                 zonePoly
            )
 
            while array.size(rsiDivergenceZones) > maxRsiZones
                polyline.delete(
                     array.shift(rsiDivergenceZones)
                )
 
 
//==============================================================================
// MAIN-CHART PRICE DIVERGENCE VISUALS
//
// Valid RSI divergences are drawn directly on the main price chart
// using a clean three-layer neon line without additional text.
//==============================================================================
 
var array<line> mainChartDivergenceLines = array.new<line>()
int maxMainChartDivergenceLines = 300
mainChartVisualAtr = ta.atr(atrLength)
 
createMainChartDivergence(
     bool shouldCreate,
     int leftBar,
     float leftPrice,
     int rightBar,
     float rightPrice,
     color divergenceColor
) =>
    if (
         shouldCreate and
         not na(leftBar) and
         not na(rightBar) and
         not na(leftPrice) and
         not na(rightPrice) and
         rightBar > leftBar
    )
        // Neon effect: wide outer glow, medium glow and bright core line.
        line divergenceGlowOuter = line.new(
             x1=leftBar,
             y1=leftPrice,
             x2=rightBar,
             y2=rightPrice,
             xloc=xloc.bar_index,
             extend=extend.none,
             color=color.new(divergenceColor, isLightMode ? 82 : 86),
             style=line.style_solid,
             width=8,
             force_overlay=true
        )
 
        line divergenceGlowInner = line.new(
             x1=leftBar,
             y1=leftPrice,
             x2=rightBar,
             y2=rightPrice,
             xloc=xloc.bar_index,
             extend=extend.none,
             color=color.new(divergenceColor, isLightMode ? 58 : 68),
             style=line.style_solid,
             width=5,
             force_overlay=true
        )
 
        line divergenceCore = line.new(
             x1=leftBar,
             y1=leftPrice,
             x2=rightBar,
             y2=rightPrice,
             xloc=xloc.bar_index,
             extend=extend.none,
             color=divergenceColor,
             style=line.style_solid,
             width=2,
             force_overlay=true
        )
 
        array.push(
             mainChartDivergenceLines,
             divergenceGlowOuter
        )
 
        array.push(
             mainChartDivergenceLines,
             divergenceGlowInner
        )
 
        array.push(
             mainChartDivergenceLines,
             divergenceCore
        )
 
        while array.size(mainChartDivergenceLines) > maxMainChartDivergenceLines
            line.delete(
                 array.shift(mainChartDivergenceLines)
            )
 
//==============================================================================
// REGULAR BULLISH DIVERGENCE
// RSI: Higher Low
// Price: Lower Low
//==============================================================================
 
previousBullOsc = ta.valuewhen(
     plFound,
     osc[lbR],
     1
)
 
previousBullPrice = ta.valuewhen(
     plFound,
     low[lbR],
     1
)
 
previousBullBar = ta.valuewhen(
     plFound,
     bar_index[lbR],
     1
)
 
oscHL =
     not na(previousBullOsc) and
     osc[lbR] > previousBullOsc and
     inRangePl
 
priceLL =
     not na(previousBullPrice) and
     low[lbR] < previousBullPrice
 
bullCondAlert =
     plotBull and
     plFound and
     priceLL and
     oscHL and
     barstate.isconfirmed
 
bullCond = bullCondAlert
 
plot(
     plFound ? osc[lbR] : na,
     offset=-lbR,
     title="Regular Bullish",
     linewidth=2,
     color=bullCond ? bullColor : noneColor,
     display=display.pane
)
 
if bullCond
    label.new(
         x=bar_index - lbR,
         y=osc[lbR],
         text="▲  BULLISH",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=bullColor,
         style=label.style_label_up,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=rsiSignalLabelSize,
         textalign=text.align_center,
         tooltip="Regular Bullish RSI Divergence",
         text_font_family=font.family_default,
         force_overlay=false,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// HIDDEN BULLISH DIVERGENCE
// RSI: Lower Low
// Price: Higher Low
//==============================================================================
 
previousHiddenBullOsc = ta.valuewhen(
     plFound,
     osc[lbR],
     1
)
 
previousHiddenBullPrice = ta.valuewhen(
     plFound,
     low[lbR],
     1
)
 
previousHiddenBullBar = ta.valuewhen(
     plFound,
     bar_index[lbR],
     1
)
 
oscLL =
     not na(previousHiddenBullOsc) and
     osc[lbR] < previousHiddenBullOsc and
     inRangePl
 
priceHL =
     not na(previousHiddenBullPrice) and
     low[lbR] > previousHiddenBullPrice
 
hiddenBullCondAlert =
     plotHiddenBull and
     plFound and
     priceHL and
     oscLL and
     barstate.isconfirmed
 
hiddenBullCond = hiddenBullCondAlert
 
plot(
     plFound ? osc[lbR] : na,
     offset=-lbR,
     title="Hidden Bullish",
     linewidth=2,
     color=hiddenBullCond ? hiddenBullColor : noneColor,
     display=display.pane
)
 
if hiddenBullCond
    label.new(
         x=bar_index - lbR,
         y=osc[lbR],
         text="◆  H-BULLISH",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=color.new(bullColor, 20),
         style=label.style_label_up,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=rsiSignalLabelSize,
         textalign=text.align_center,
         tooltip="Hidden Bullish RSI Divergence",
         text_font_family=font.family_default,
         force_overlay=false,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// REGULAR BEARISH DIVERGENCE
// RSI: Lower High
// Price: Higher High
//==============================================================================
 
previousBearOsc = ta.valuewhen(
     phFound,
     osc[lbR],
     1
)
 
previousBearPrice = ta.valuewhen(
     phFound,
     high[lbR],
     1
)
 
previousBearBar = ta.valuewhen(
     phFound,
     bar_index[lbR],
     1
)
 
oscLH =
     not na(previousBearOsc) and
     osc[lbR] < previousBearOsc and
     inRangePh
 
priceHH =
     not na(previousBearPrice) and
     high[lbR] > previousBearPrice
 
bearCondAlert =
     plotBear and
     phFound and
     priceHH and
     oscLH and
     barstate.isconfirmed
 
bearCond = bearCondAlert
 
plot(
     phFound ? osc[lbR] : na,
     offset=-lbR,
     title="Regular Bearish",
     linewidth=2,
     color=bearCond ? bearColor : noneColor,
     display=display.pane
)
 
if bearCond
    label.new(
         x=bar_index - lbR,
         y=osc[lbR],
         text="▼  SELL",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=bearColor,
         style=label.style_label_down,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=rsiSignalLabelSize,
         textalign=text.align_center,
         tooltip="Regular Bearish RSI Divergence",
         text_font_family=font.family_default,
         force_overlay=false,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// HIDDEN BEARISH DIVERGENCE
// RSI: Higher High
// Price: Lower High
//==============================================================================
 
previousHiddenBearOsc = ta.valuewhen(
     phFound,
     osc[lbR],
     1
)
 
previousHiddenBearPrice = ta.valuewhen(
     phFound,
     high[lbR],
     1
)
 
previousHiddenBearBar = ta.valuewhen(
     phFound,
     bar_index[lbR],
     1
)
 
oscHH =
     not na(previousHiddenBearOsc) and
     osc[lbR] > previousHiddenBearOsc and
     inRangePh
 
priceLH =
     not na(previousHiddenBearPrice) and
     high[lbR] < previousHiddenBearPrice
 
hiddenBearCondAlert =
     plotHiddenBear and
     phFound and
     priceLH and
     oscHH and
     barstate.isconfirmed
 
hiddenBearCond = hiddenBearCondAlert
 
plot(
     phFound ? osc[lbR] : na,
     offset=-lbR,
     title="Hidden Bearish",
     linewidth=2,
     color=hiddenBearCond ? hiddenBearColor : noneColor,
     display=display.pane
)
 
if hiddenBearCond
    label.new(
         x=bar_index - lbR,
         y=osc[lbR],
         text="◆  H-SELL",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=color.new(bearColor, 20),
         style=label.style_label_down,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=rsiSignalLabelSize,
         textalign=text.align_center,
         tooltip="Hidden Bearish RSI Divergence",
         text_font_family=font.family_default,
         force_overlay=false,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// CONSISTENT MAIN-CHART DIVERGENCE CALCULATIONS
// Every function instance is called on every bar for Pine consistency.
//==============================================================================
 
createMainChartDivergence(
     bullCond,
     previousBullBar,
     previousBullPrice,
     bar_index - lbR,
     low[lbR],
     bullColor
)
 
createMainChartDivergence(
     hiddenBullCond,
     previousHiddenBullBar,
     previousHiddenBullPrice,
     bar_index - lbR,
     low[lbR],
     color.new(bullColor, 20)
)
 
createMainChartDivergence(
     bearCond,
     previousBearBar,
     previousBearPrice,
     bar_index - lbR,
     high[lbR],
     bearColor
)
 
createMainChartDivergence(
     hiddenBearCond,
     previousHiddenBearBar,
     previousHiddenBearPrice,
     bar_index - lbR,
     high[lbR],
     color.new(bearColor, 20)
)
 
//==============================================================================
// CONSISTENT DIVERGENCE ZONE CALCULATIONS
// Every function instance is called on every bar. A zone is created only when
// its corresponding divergence condition is true.
//==============================================================================
 
createRsiZone(
     bullCond,
     previousBullBar,
     bar_index - lbR,
     bullZoneColor,
     bullZoneBorderColor
)
 
createRsiZone(
     hiddenBullCond,
     previousHiddenBullBar,
     bar_index - lbR,
     color.new(bullZoneColor, 4),
     bullZoneBorderColor
)
 
createRsiZone(
     bearCond,
     previousBearBar,
     bar_index - lbR,
     bearZoneColor,
     bearZoneBorderColor
)
 
createRsiZone(
     hiddenBearCond,
     previousHiddenBearBar,
     bar_index - lbR,
     color.new(bearZoneColor, 4),
     color.new(bearZoneBorderColor, 4)
)
 
//==============================================================================
// TREND FILTER ENGINE
//
// EMA Trend: Chart close versus EMA 200.
// Supertrend: Fixed ATR 10 and factor 3.0.
// HTF Trend: Confirmed higher-timeframe close versus higher-timeframe EMA 200.
// The filter affects tracked trade entries only. RSI divergence detection and
// RSI-pane divergence visuals remain unchanged.
//==============================================================================
 
int trendEmaLength = 200
int supertrendAtrLength = 10
float supertrendFactor = 3.0
 
chartTrendEma = ta.ema(
     close,
     trendEmaLength
)
 
[supertrendValue, supertrendDirection] = ta.supertrend(
     supertrendFactor,
     supertrendAtrLength
)
 
htfTrendClose = request.security(
     syminfo.tickerid,
     trendTimeframe,
     close,
     gaps=barmerge.gaps_off,
     lookahead=barmerge.lookahead_off
)
 
htfTrendEma = request.security(
     syminfo.tickerid,
     trendTimeframe,
     ta.ema(close, trendEmaLength),
     gaps=barmerge.gaps_off,
     lookahead=barmerge.lookahead_off
)
 
emaTrendBullish =
     not na(chartTrendEma) and
     close > chartTrendEma
 
emaTrendBearish =
     not na(chartTrendEma) and
     close < chartTrendEma
 
supertrendBullish =
     not na(supertrendValue) and
     supertrendDirection < 0
 
supertrendBearish =
     not na(supertrendValue) and
     supertrendDirection > 0
 
htfTrendBullish =
     not na(htfTrendClose) and
     not na(htfTrendEma) and
     htfTrendClose > htfTrendEma
 
htfTrendBearish =
     not na(htfTrendClose) and
     not na(htfTrendEma) and
     htfTrendClose < htfTrendEma
 
longTrendAllowed =
     trendFilterMode == "Off" ?
     true :
     trendFilterMode == "EMA Trend" ?
     emaTrendBullish :
     trendFilterMode == "Supertrend" ?
     supertrendBullish :
     htfTrendBullish
 
shortTrendAllowed =
     trendFilterMode == "Off" ?
     true :
     trendFilterMode == "EMA Trend" ?
     emaTrendBearish :
     trendFilterMode == "Supertrend" ?
     supertrendBearish :
     htfTrendBearish
 
trendReferenceValue =
     trendFilterMode == "EMA Trend" ?
     chartTrendEma :
     trendFilterMode == "Supertrend" ?
     supertrendValue :
     trendFilterMode == "HTF Trend" ?
     htfTrendEma :
     na
 
trendReferenceBullish =
     trendFilterMode == "EMA Trend" ?
     emaTrendBullish :
     trendFilterMode == "Supertrend" ?
     supertrendBullish :
     trendFilterMode == "HTF Trend" ?
     htfTrendBullish :
     false
 
plot(
     trendReferenceValue,
     title="Trend Filter Reference",
     color=trendReferenceBullish ? bullColor : bearColor,
     linewidth=2,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
//==============================================================================
// RAW DIVERGENCE SIGNALS
//==============================================================================
 
rawBuySignal =
     bullCondAlert or
     hiddenBullCondAlert
 
rawSellSignal =
     bearCondAlert or
     hiddenBearCondAlert
 
validBuySignal =
     rawBuySignal and
     not rawSellSignal and
     longTrendAllowed
 
validSellSignal =
     rawSellSignal and
     not rawBuySignal and
     shortTrendAllowed
 
//==============================================================================
// ATR TRADE ENGINE
//
// Entry: Confirmation candle close.
// Stop: Entry +/- ATR × Stop Loss Distance.
// TP1/TP2: Visual intermediate targets only.
// TP3: Final target; only TP3 counts as a win.
// One active trade at a time.
// TP3/SL checks begin on the candle after entry.
// If TP3 and SL touch on the same candle, SL is counted first.
//==============================================================================
 
atrValue = ta.atr(atrLength)
 
var bool tradeActive = false
var int tradeDirection = 0
var int tradeEntryBar = na
 
var float tradeEntryPrice = na
var float tradeStopPrice = na
var float tradeTp1Price = na
var float tradeTp2Price = na
var float tradeTp3Price = na
var float tradeRiskDistance = na
 
// Active risk/reward boxes. Completed boxes remain visible as trade history.
var box activeTpBox = na
var box activeSlBox = na
var array<box> tradeBoxHistory = array.new<box>()
 
// Historical TP labels remain attached to completed trade boxes.
var array<label> historicalTpLabels = array.new<label>()
 
int maxStoredTradeBoxes = 200
int maxStoredHistoricalTpLabels = 240
 
//------------------------------------------------------------------------------
// STATISTICS STATE
//------------------------------------------------------------------------------
 
var int totalTrades = 0
var int winningTrades = 0
var int losingTrades = 0
 
var int longTrades = 0
var int shortTrades = 0
 
var int currentWinStreak = 0
var int currentLossStreak = 0
var int maxWinStreak = 0
var int maxLossStreak = 0
 
var float grossProfitR = 0.0
var float grossLossR = 0.0
 
//------------------------------------------------------------------------------
// ONE-BAR EVENTS
//------------------------------------------------------------------------------
 
bool tradeClosedThisBar = false
bool tpHitThisBar = false
bool slHitThisBar = false
bool buyEntryThisBar = false
bool sellEntryThisBar = false
 
float closedEntryPrice = na
float closedStopPrice = na
float closedTp1Price = na
float closedTp2Price = na
float closedTp3Price = na
 
//------------------------------------------------------------------------------
// EXIT MANAGEMENT
//------------------------------------------------------------------------------
 
if tradeActive and bar_index > tradeEntryBar
    bool longTpTouched =
         tradeDirection == 1 and
         high >= tradeTp3Price
 
    bool longSlTouched =
         tradeDirection == 1 and
         low <= tradeStopPrice
 
    bool shortTpTouched =
         tradeDirection == -1 and
         low <= tradeTp3Price
 
    bool shortSlTouched =
         tradeDirection == -1 and
         high >= tradeStopPrice
 
    bool tpTouched =
         longTpTouched or
         shortTpTouched
 
    bool slTouched =
         longSlTouched or
         shortSlTouched
 
    // Conservative same-candle rule: SL takes priority.
    if slTouched
        tradeClosedThisBar := true
        slHitThisBar := true
 
        closedEntryPrice := tradeEntryPrice
        closedStopPrice := tradeStopPrice
        closedTp1Price := tradeTp1Price
        closedTp2Price := tradeTp2Price
        closedTp3Price := tradeTp3Price
 
        totalTrades += 1
        losingTrades += 1
        grossLossR += 1.0
 
        currentLossStreak += 1
        currentWinStreak := 0
        maxLossStreak := math.max(
             maxLossStreak,
             currentLossStreak
        )
 
        tradeActive := false
        tradeDirection := 0
        tradeEntryBar := na
        tradeEntryPrice := na
        tradeStopPrice := na
        tradeTp1Price := na
        tradeTp2Price := na
        tradeTp3Price := na
        tradeRiskDistance := na
 
    else if tpTouched
        tradeClosedThisBar := true
        tpHitThisBar := true
 
        closedEntryPrice := tradeEntryPrice
        closedStopPrice := tradeStopPrice
        closedTp1Price := tradeTp1Price
        closedTp2Price := tradeTp2Price
        closedTp3Price := tradeTp3Price
 
        totalTrades += 1
        winningTrades += 1
        grossProfitR += tp3RewardRisk
 
        currentWinStreak += 1
        currentLossStreak := 0
        maxWinStreak := math.max(
             maxWinStreak,
             currentWinStreak
        )
 
        tradeActive := false
        tradeDirection := 0
        tradeEntryBar := na
        tradeEntryPrice := na
        tradeStopPrice := na
        tradeTp1Price := na
        tradeTp2Price := na
        tradeTp3Price := na
        tradeRiskDistance := na
 
//------------------------------------------------------------------------------
// ENTRY MANAGEMENT
// A new trade is not opened on the same candle that another trade closes.
//------------------------------------------------------------------------------
 
canOpenTrade =
     not tradeActive and
     not tradeClosedThisBar and
     not na(atrValue) and
     atrValue > 0.0
 
if canOpenTrade and validBuySignal
    float riskDistance = atrValue * atrMultiplier
 
    tradeActive := true
    tradeDirection := 1
    tradeEntryBar := bar_index
 
    tradeEntryPrice := close
    tradeRiskDistance := riskDistance
    tradeStopPrice := close - riskDistance
    tradeTp1Price := close + riskDistance * (tp3RewardRisk / 3.0)
    tradeTp2Price := close + riskDistance * (tp3RewardRisk * 2.0 / 3.0)
    tradeTp3Price := close + riskDistance * tp3RewardRisk
 
    longTrades += 1
    buyEntryThisBar := true
 
else if canOpenTrade and validSellSignal
    float riskDistance = atrValue * atrMultiplier
 
    tradeActive := true
    tradeDirection := -1
    tradeEntryBar := bar_index
 
    tradeEntryPrice := close
    tradeRiskDistance := riskDistance
    tradeStopPrice := close + riskDistance
    tradeTp1Price := close - riskDistance * (tp3RewardRisk / 3.0)
    tradeTp2Price := close - riskDistance * (tp3RewardRisk * 2.0 / 3.0)
    tradeTp3Price := close - riskDistance * tp3RewardRisk
 
    shortTrades += 1
    sellEntryThisBar := true
 
//==============================================================================
// TP / SL RISK-REWARD BOXES
//
// Green box: Entry to TP3.
// Red box: Entry to Stop Loss.
// TP1 and TP2 remain visual guide lines inside the profit box.
// Completed boxes remain visible as historical trades.
//==============================================================================
 
if buyEntryThisBar or sellEntryThisBar
    float tpBoxTop = math.max(
         tradeEntryPrice,
         tradeTp3Price
    )
 
    float tpBoxBottom = math.min(
         tradeEntryPrice,
         tradeTp3Price
    )
 
    float slBoxTop = math.max(
         tradeEntryPrice,
         tradeStopPrice
    )
 
    float slBoxBottom = math.min(
         tradeEntryPrice,
         tradeStopPrice
    )
 
    activeTpBox := box.new(
         left=bar_index,
         top=tpBoxTop,
         right=bar_index + 1,
         bottom=tpBoxBottom,
         xloc=xloc.bar_index,
         border_color=color.new(bullColor, 25),
         border_width=1,
         bgcolor=color.new(bullColor, 88),
         force_overlay=true
    )
 
    activeSlBox := box.new(
         left=bar_index,
         top=slBoxTop,
         right=bar_index + 1,
         bottom=slBoxBottom,
         xloc=xloc.bar_index,
         border_color=color.new(bearColor, 25),
         border_width=1,
         bgcolor=color.new(bearColor, 88),
         force_overlay=true
    )
 
    array.push(
         tradeBoxHistory,
         activeTpBox
    )
 
    array.push(
         tradeBoxHistory,
         activeSlBox
    )
 
    while array.size(tradeBoxHistory) > maxStoredTradeBoxes
        box.delete(
             array.shift(tradeBoxHistory)
        )
 
if tradeActive
    if not na(activeTpBox)
        box.set_right(
             activeTpBox,
             bar_index + 1
        )
 
    if not na(activeSlBox)
        box.set_right(
             activeSlBox,
             bar_index + 1
        )
 
else if tradeClosedThisBar
    if not na(activeTpBox)
        box.set_right(
             activeTpBox,
             bar_index
        )
 
    if not na(activeSlBox)
        box.set_right(
             activeSlBox,
             bar_index
        )
 
    activeTpBox := na
    activeSlBox := na
 
//==============================================================================
// HISTORICAL TP PRICE LABELS
//
// When a tracked trade closes, permanent TP1 / TP2 / TP3 labels are created
// at the right edge of that completed trade. The labels remain visible with
// the historical risk/reward boxes.
//==============================================================================
 
if tradeClosedThisBar
    label historicalTp1Label = label.new(
         x=bar_index,
         y=closedTp1Price,
         text="🎯 TP1  " + str.tostring(closedTp1Price, format.mintick),
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=isLightMode ? color.new(bullColor, 78) : color.new(bullColor, 60),
         style=label.style_label_left,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=size.tiny,
         textalign=text.align_left,
         tooltip="Historical TP1 price",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
    label historicalTp2Label = label.new(
         x=bar_index,
         y=closedTp2Price,
         text="⚡ TP2  " + str.tostring(closedTp2Price, format.mintick),
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=isLightMode ? color.new(bullColor, 66) : color.new(bullColor, 30),
         style=label.style_label_left,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=size.tiny,
         textalign=text.align_left,
         tooltip="Historical TP2 price",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
    label historicalTp3Label = label.new(
         x=bar_index,
         y=closedTp3Price,
         text="🏆 TP3  " + str.tostring(closedTp3Price, format.mintick),
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=isLightMode ? color.new(bullColor, 54) : color.new(bullColor, 5),
         style=label.style_label_left,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=size.tiny,
         textalign=text.align_left,
         tooltip="Historical TP3 price",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
    array.push(
         historicalTpLabels,
         historicalTp1Label
    )
 
    array.push(
         historicalTpLabels,
         historicalTp2Label
    )
 
    array.push(
         historicalTpLabels,
         historicalTp3Label
    )
 
    while array.size(historicalTpLabels) > maxStoredHistoricalTpLabels
        label.delete(
             array.shift(historicalTpLabels)
        )
 
//==============================================================================
// MAIN CHART BUY / SELL LABELS
// Only signals that actually open a tracked trade receive chart labels.
//==============================================================================
 
if showChartLabels and buyEntryThisBar
    label.new(
         x=bar_index,
         y=na,
         text="▲  BULLISH",
         xloc=xloc.bar_index,
         yloc=yloc.belowbar,
         color=bullColor,
         style=label.style_label_up,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=chartSignalLabelSize,
         textalign=text.align_center,
         tooltip="tradewsamet RSI Divergence bullish entry confirmed at candle close.",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
if showChartLabels and sellEntryThisBar
    label.new(
         x=bar_index,
         y=na,
         text="▼  SELL",
         xloc=xloc.bar_index,
         yloc=yloc.belowbar,
         color=bearColor,
         style=label.style_label_up,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=chartSignalLabelSize,
         textalign=text.align_center,
         tooltip="tradewsamet RSI Divergence bearish entry confirmed at candle close.",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// ENTRY / TP / SL GUIDE LINES
//==============================================================================
 
entryLevelToPlot =
     tradeActive ?
     tradeEntryPrice :
     tradeClosedThisBar ?
     closedEntryPrice :
     na
 
stopLevelToPlot =
     tradeActive ?
     tradeStopPrice :
     tradeClosedThisBar ?
     closedStopPrice :
     na
 
tp1LevelToPlot =
     tradeActive ?
     tradeTp1Price :
     tradeClosedThisBar ?
     closedTp1Price :
     na
 
tp2LevelToPlot =
     tradeActive ?
     tradeTp2Price :
     tradeClosedThisBar ?
     closedTp2Price :
     na
 
tp3LevelToPlot =
     tradeActive ?
     tradeTp3Price :
     tradeClosedThisBar ?
     closedTp3Price :
     na
 
plot(
     showTradeLevels ? entryLevelToPlot : na,
     title="Entry Price",
     color=entryColor,
     linewidth=2,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
plot(
     showTradeLevels ? tp1LevelToPlot : na,
     title="TP1",
     color=tp1Color,
     linewidth=1,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
plot(
     showTradeLevels ? tp2LevelToPlot : na,
     title="TP2",
     color=tp2Color,
     linewidth=1,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
plot(
     showTradeLevels ? tp3LevelToPlot : na,
     title="TP3",
     color=tp3Color,
     linewidth=2,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
plot(
     showTradeLevels ? stopLevelToPlot : na,
     title="Stop Loss",
     color=slColor,
     linewidth=2,
     style=plot.style_linebr,
     force_overlay=true,
     display=display.pane
)
 
//==============================================================================
// DYNAMIC PRICE LABELS
// Labels remain at the right side of the active trade lines.
// On the exit candle, the final prices remain visible for that candle.
//==============================================================================
 
var label entryPriceLabel = na
var label stopPriceLabel = na
var label tp1PriceLabel = na
var label tp2PriceLabel = na
var label tp3PriceLabel = na
 
showPriceLabels =
     showTradeLevels and
     (
          tradeActive or
          tradeClosedThisBar
     )
 
priceLabelX = bar_index + 1
 
if showPriceLabels
    string entryLabelText =
         "🚪 ENTRY  " +
         str.tostring(entryLevelToPlot, format.mintick)
 
    string stopLabelText =
         "🛑 SL  " +
         str.tostring(stopLevelToPlot, format.mintick)
 
    string tp1LabelText =
         "🎯 TP1  " +
         str.tostring(tp1LevelToPlot, format.mintick)
 
    string tp2LabelText =
         "⚡ TP2  " +
         str.tostring(tp2LevelToPlot, format.mintick)
 
    string tp3LabelText =
         "🏆 TP3  " +
         str.tostring(tp3LevelToPlot, format.mintick)
 
    if na(entryPriceLabel)
        entryPriceLabel := label.new(
             x=priceLabelX,
             y=entryLevelToPlot,
             text=entryLabelText,
             xloc=xloc.bar_index,
             yloc=yloc.price,
             color=isLightMode ? color.new(brandBlack, 5) : color.new(brandBlack, 5),
             style=label.style_label_left,
             textcolor=isLightMode ? color.white : color.rgb(255, 255, 255),
             size=priceLabelSize,
             textalign=text.align_left,
             text_font_family=font.family_default,
             force_overlay=true,
             text_formatting=text.format_bold + text.format_italic
        )
    else
        label.set_xy(
             entryPriceLabel,
             priceLabelX,
             entryLevelToPlot
        )
        label.set_text(
             entryPriceLabel,
             entryLabelText
        )
 
    if na(stopPriceLabel)
        stopPriceLabel := label.new(
             x=priceLabelX,
             y=stopLevelToPlot,
             text=stopLabelText,
             xloc=xloc.bar_index,
             yloc=yloc.price,
             color=isLightMode ? color.new(bearColor, 62) : color.new(bearColor, 5),
             style=label.style_label_left,
             textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
             size=priceLabelSize,
             textalign=text.align_left,
             text_font_family=font.family_default,
             force_overlay=true,
             text_formatting=text.format_bold + text.format_italic
        )
    else
        label.set_xy(
             stopPriceLabel,
             priceLabelX,
             stopLevelToPlot
        )
        label.set_text(
             stopPriceLabel,
             stopLabelText
        )
 
    if na(tp1PriceLabel)
        tp1PriceLabel := label.new(
             x=priceLabelX,
             y=tp1LevelToPlot,
             text=tp1LabelText,
             xloc=xloc.bar_index,
             yloc=yloc.price,
             color=isLightMode ? color.new(bullColor, 76) : color.new(bullColor, 60),
             style=label.style_label_left,
             textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
             size=priceLabelSize,
             textalign=text.align_left,
             text_font_family=font.family_default,
             force_overlay=true,
             text_formatting=text.format_bold + text.format_italic
        )
    else
        label.set_xy(
             tp1PriceLabel,
             priceLabelX,
             tp1LevelToPlot
        )
        label.set_text(
             tp1PriceLabel,
             tp1LabelText
        )
 
    if na(tp2PriceLabel)
        tp2PriceLabel := label.new(
             x=priceLabelX,
             y=tp2LevelToPlot,
             text=tp2LabelText,
             xloc=xloc.bar_index,
             yloc=yloc.price,
             color=isLightMode ? color.new(bullColor, 64) : color.new(bullColor, 30),
             style=label.style_label_left,
             textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
             size=priceLabelSize,
             textalign=text.align_left,
             text_font_family=font.family_default,
             force_overlay=true,
             text_formatting=text.format_bold + text.format_italic
        )
    else
        label.set_xy(
             tp2PriceLabel,
             priceLabelX,
             tp2LevelToPlot
        )
        label.set_text(
             tp2PriceLabel,
             tp2LabelText
        )
 
    if na(tp3PriceLabel)
        tp3PriceLabel := label.new(
             x=priceLabelX,
             y=tp3LevelToPlot,
             text=tp3LabelText,
             xloc=xloc.bar_index,
             yloc=yloc.price,
             color=isLightMode ? color.new(bullColor, 52) : color.new(bullColor, 5),
             style=label.style_label_left,
             textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
             size=priceLabelSize,
             textalign=text.align_left,
             text_font_family=font.family_default,
             force_overlay=true,
             text_formatting=text.format_bold + text.format_italic
        )
    else
        label.set_xy(
             tp3PriceLabel,
             priceLabelX,
             tp3LevelToPlot
        )
        label.set_text(
             tp3PriceLabel,
             tp3LabelText
        )
 
else
    if not na(entryPriceLabel)
        label.delete(entryPriceLabel)
        entryPriceLabel := na
 
    if not na(stopPriceLabel)
        label.delete(stopPriceLabel)
        stopPriceLabel := na
 
    if not na(tp1PriceLabel)
        label.delete(tp1PriceLabel)
        tp1PriceLabel := na
 
    if not na(tp2PriceLabel)
        label.delete(tp2PriceLabel)
        tp2PriceLabel := na
 
    if not na(tp3PriceLabel)
        label.delete(tp3PriceLabel)
        tp3PriceLabel := na
 
//==============================================================================
// TP3 / SL RESULT LABELS
//==============================================================================
 
if showExitLabels and tpHitThisBar
    label.new(
         x=bar_index,
         y=closedTp3Price,
         text="🏆  TARGET HIT",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=bullColor,
         style=label.style_label_down,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=exitLabelSize,
         textalign=text.align_center,
         tooltip="Final TP3 target reached. The tracked trade is recorded as a win.",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
if showExitLabels and slHitThisBar
    label.new(
         x=bar_index,
         y=closedStopPrice,
         text="✕  SL",
         xloc=xloc.bar_index,
         yloc=yloc.price,
         color=bearColor,
         style=label.style_label_up,
         textcolor=isLightMode ? color.black : color.rgb(255, 255, 255),
         size=size.small,
         textalign=text.align_center,
         tooltip="ATR-based Stop Loss reached. The tracked trade is recorded as a loss.",
         text_font_family=font.family_default,
         force_overlay=true,
         text_formatting=text.format_bold + text.format_italic
    )
 
//==============================================================================
// STATISTICS
//==============================================================================
 
netR =
     grossProfitR -
     grossLossR
 
winRate =
     totalTrades > 0 ?
     winningTrades * 100.0 / totalTrades :
     0.0
 
averageR =
     totalTrades > 0 ?
     netR / totalTrades :
     0.0
 
profitFactor =
     grossLossR > 0.0 ?
     grossProfitR / grossLossR :
     grossProfitR > 0.0 ?
     999.0 :
     0.0
 
activeR =
     tradeActive and not na(tradeRiskDistance) and tradeRiskDistance > 0.0 ?
     tradeDirection == 1 ?
     (close - tradeEntryPrice) / tradeRiskDistance :
     (tradeEntryPrice - close) / tradeRiskDistance :
     0.0
 
tradeStatus =
     not tradeActive ?
     "NO ACTIVE TRADE" :
     tradeDirection == 1 ?
     "ACTIVE BUY" :
     "ACTIVE SELL"
 
statusColor =
     not tradeActive ?
     color.new(themeMutedText, 86) :
     tradeDirection == 1 ?
     color.new(bullColor, isLightMode ? 82 : 70) :
     color.new(bearColor, isLightMode ? 82 : 70)
 
netRColor =
     netR > 0.0 ?
     color.new(bullColor, isLightMode ? 82 : 70) :
     netR < 0.0 ?
     color.new(bearColor, isLightMode ? 82 : 70) :
     color.new(themeMutedText, 86)
 
//==============================================================================
// SIMPLE STATISTICS TABLE
//==============================================================================
 
dashboardRows =
     isMobileTheme ?
     2 :
     11
 
var table statsTable = table.new(
     position.bottom_right,
     2,
     dashboardRows,
     bgcolor=color.new(themeSurface, 4),
     frame_color=isLightMode ? color.new(brandRed, 10) : color.new(brandRed, 20),
     frame_width=1,
     border_width=1,
     border_color=themeBorder,
     force_overlay=true
)
 
if barstate.islast and showStats
    if isMobileTheme
        table.cell(
             statsTable,
             0,
             0,
             "WIN RATE",
             text_color=themeMutedText,
             bgcolor=color.new(themeSurface, 6),
             text_size=size.tiny
        )
 
        table.cell(
             statsTable,
             1,
             0,
             str.tostring(winRate, "#.##") + "%",
             text_color=winRate >= 50.0 ? bullColor : bearColor,
             bgcolor=color.new(themeSurface, 6),
             text_size=size.tiny
        )
 
        table.cell(
             statsTable,
             0,
             1,
             "NET R",
             text_color=themeMutedText,
             bgcolor=color.new(themeSurface, 6),
             text_size=size.tiny
        )
 
        table.cell(
             statsTable,
             1,
             1,
             str.tostring(netR, "#.##") + "R",
             text_color=netR >= 0.0 ? bullColor : bearColor,
             bgcolor=netRColor,
             text_size=size.tiny
        )
 
        for row = 0 to 1
            for column = 0 to 1
                table.cell_set_text_formatting(
                     statsTable,
                     column,
                     row,
                     text.format_bold + text.format_italic
                )
 
    else
        table.cell(
             statsTable,
             0,
             0,
             "RSI DIVERGENCE",
             text_color=themeHeaderText,
             bgcolor=themeHeader,
             text_size=size.small
        )
 
        table.cell(
             statsTable,
             1,
             0,
             "TP3 " + str.tostring(tp3RewardRisk) + "R • " + trendFilterMode,
             text_color=themeHeaderText,
             bgcolor=themeHeader,
             text_size=size.small
        )
 
        table.cell(statsTable, 0, 1, "Status", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             1,
             tradeStatus,
             text_color=themeText,
             bgcolor=statusColor
        )
 
        table.cell(statsTable, 0, 2, "Closed Trades", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(statsTable, 1, 2, str.tostring(totalTrades), text_color=themeText, bgcolor=color.new(themeSurface, 4))
 
        table.cell(statsTable, 0, 3, "TP3 Wins", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(statsTable, 1, 3, str.tostring(winningTrades), text_color=bullColor, bgcolor=color.new(themeSurface, 4))
 
        table.cell(statsTable, 0, 4, "Losses", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(statsTable, 1, 4, str.tostring(losingTrades), text_color=bearColor, bgcolor=color.new(themeSurface, 4))
 
        table.cell(statsTable, 0, 5, "Win Rate", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             5,
             str.tostring(winRate, "#.##") + "%",
             text_color=themeText,
             bgcolor=color.new(themeSurface, 4)
        )
 
        table.cell(statsTable, 0, 6, "NET R", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             6,
             str.tostring(netR, "#.##") + "R",
             text_color=themeText,
             bgcolor=netRColor
        )
 
        table.cell(statsTable, 0, 7, "Gross Profit", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             7,
             "+" + str.tostring(grossProfitR, "#.##") + "R",
             text_color=bullColor,
             bgcolor=color.new(themeSurface, 4)
        )
 
        table.cell(statsTable, 0, 8, "Gross Loss", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             8,
             "-" + str.tostring(grossLossR, "#.##") + "R",
             text_color=bearColor,
             bgcolor=color.new(themeSurface, 4)
        )
 
        table.cell(statsTable, 0, 9, "Average / Trade", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             9,
             str.tostring(averageR, "#.##") + "R",
             text_color=themeText,
             bgcolor=color.new(themeSurface, 4)
        )
 
        table.cell(statsTable, 0, 10, "Profit Factor", text_color=themeText, bgcolor=color.new(themeSurface, 4))
        table.cell(
             statsTable,
             1,
             10,
             str.tostring(profitFactor, "#.##"),
             text_color=themeText,
             bgcolor=color.new(themeSurface, 4)
        )
 
        for row = 0 to 10
            for column = 0 to 1
                table.cell_set_text_formatting(
                     statsTable,
                     column,
                     row,
                     text.format_bold + text.format_italic
                )
 
//==============================================================================
// UNIVERSAL TEXT FORMATTING
// All visible dashboard cells use bold + italic typography.
//==============================================================================
 
if barstate.islast and showStats
    int formattedDashboardRows =
         isMobileTheme ?
         2 :
         11
 
    for row = 0 to formattedDashboardRows - 1
        for column = 0 to 1
            table.cell_set_text_formatting(
                 statsTable,
                 column,
                 row,
                 text.format_bold + text.format_italic
            )
 
//==============================================================================
// ALERT CONDITIONS
//==============================================================================
 
alertcondition(
     bullCondAlert,
     title="Regular Bullish Divergence",
     message="tradewsamet | Regular Bullish RSI Divergence confirmed."
)
 
alertcondition(
     hiddenBullCondAlert,
     title="Hidden Bullish Divergence",
     message="tradewsamet | Hidden Bullish RSI Divergence confirmed."
)
 
alertcondition(
     bearCondAlert,
     title="Regular Bearish Divergence",
     message="tradewsamet | Regular Bearish RSI Divergence confirmed."
)
 
alertcondition(
     hiddenBearCondAlert,
     title="Hidden Bearish Divergence",
     message="tradewsamet | Hidden Bearish RSI Divergence confirmed."
)
 
alertcondition(
     buyEntryThisBar,
     title="BUY Entry",
     message="tradewsamet | RSI Divergence BUY trade opened."
)
 
alertcondition(
     sellEntryThisBar,
     title="SELL Entry",
     message="tradewsamet | RSI Divergence SELL trade opened."
)
 
alertcondition(
     tpHitThisBar,
     title="TP3 Hit",
     message="tradewsamet | RSI Divergence trade reached TP3. The trade is counted as a win."
)
 
alertcondition(
     slHitThisBar,
     title="Stop Loss Hit",
     message="tradewsamet | RSI Divergence trade reached Stop Loss."
)
 
//==============================================================================
// ANY ALERT() FUNCTION CALL
//==============================================================================
 
if buyEntryThisBar
    alert(
         "tradewsamet | RSI DIVERGENCE BUY | " +
         syminfo.ticker +
         " | TF: " +
         timeframe.period +
         " | Entry: " +
         str.tostring(tradeEntryPrice, format.mintick) +
         " | TP1: " +
         str.tostring(tradeTp1Price, format.mintick) +
         " | TP2: " +
         str.tostring(tradeTp2Price, format.mintick) +
         " | TP3: " +
         str.tostring(tradeTp3Price, format.mintick) +
         " | SL: " +
         str.tostring(tradeStopPrice, format.mintick) +
         " | Final Target: " +
         str.tostring(tp3RewardRisk) +
         "R | Trend Filter: " +
         trendFilterMode,
         alert.freq_once_per_bar_close
    )
 
if sellEntryThisBar
    alert(
         "tradewsamet | RSI DIVERGENCE SELL | " +
         syminfo.ticker +
         " | TF: " +
         timeframe.period +
         " | Entry: " +
         str.tostring(tradeEntryPrice, format.mintick) +
         " | TP1: " +
         str.tostring(tradeTp1Price, format.mintick) +
         " | TP2: " +
         str.tostring(tradeTp2Price, format.mintick) +
         " | TP3: " +
         str.tostring(tradeTp3Price, format.mintick) +
         " | SL: " +
         str.tostring(tradeStopPrice, format.mintick) +
         " | Final Target: " +
         str.tostring(tp3RewardRisk) +
         "R | Trend Filter: " +
         trendFilterMode,
         alert.freq_once_per_bar_close
    )
 
if tpHitThisBar
    alert(
         "tradewsamet | RSI DIVERGENCE TP3 HIT | " +
         syminfo.ticker +
         " | TF: " +
         timeframe.period +
         " | Result: +" +
         str.tostring(tp3RewardRisk) +
         "R",
         alert.freq_once_per_bar
    )
 
if slHitThisBar
    alert(
         "tradewsamet | RSI DIVERGENCE SL HIT | " +
         syminfo.ticker +
         " | TF: " +
         timeframe.period +
         " | Result: -1R",
         alert.freq_once_per_bar
    )

← 返回列表