Strategi Momentum Dua Hala Indeks Bank

KERNEL VWAP CVD RSI ATR
Tarikh penciptaan: 2025-10-29 15:57:59 Akhirnya diubah suai: 2025-10-29 15:57:59
Salin: 0 Bilangan klik: 151
2
fokus pada
319
Pengikut

Strategi Momentum Dua Hala Indeks Bank Strategi Momentum Dua Hala Indeks Bank

Jadi, apa yang anda lakukan dengan taktik ini?

Tidak seperti strategi satu arah yang tetap, ia boleh bertukar arah mengikut keadaan pasaran. Bayangkan jika anda mempunyai pemandu lama yang boleh memandu dan berbalik, dan dapat mengikuti pergerakan pasaran ke arah mana pun!

Kumpulan Indeks Teknologi Inti

Strategi ini menggunakan gabungan lima petanda yang sangat kuat:

  • Kembali ke KernelIa adalah seperti navigasi GPS yang menunjukkan arah trend harga.
  • VWAP: Jumlah transaksi dengan harga purata yang bertimbangan, memberitahu anda di mana ‘uang besar’
  • CVD berpunca daripada ketidakseimbangan“Saya tidak tahu apa-apa tentang apa yang berlaku di Malaysia, saya tidak tahu apa yang berlaku di Malaysia.
  • Indeks RSI yang agak lemahMencegah terjatuh dari kedudukan yang melampau
  • Julat turun naik sebenar ATR“Dynamic adjustment to stop loss, adapt to market fluctuation” (Dinamik penyesuaian to stop loss untuk menyesuaikan diri dengan turun naik pasaran)

Mekanisme pengesahan pelbagai

Di sinilah panduan untuk mengelakkan terowong! bahagian yang paling bijak dalam taktik ini adalah “multi-verifikasi”, seperti membeli rumah dengan melihat kawasan, jenis rumah, dan harga, ia meminta:

  • Pergerakan trend ((Kernel + VWAP double confirmation)
  • Perpaduan kuantiti (sama ada peningkatan atau peningkatan berterusan)
  • K-Line Form Transition (≥60% entiti, mengelakkan perangkap bintang salib)
  • Pembatasan Jendela Masa: Berdagang pada 9:15-15:15 sahaja, mengelakkan kekacauan pembukaan dan penutupan.

️ Pengurusan Risiko Pintar

Strategi untuk mengawal risiko ini adalah seperti buku teks!

  • Dinamika Hentikan KerugianTerdapat tiga mod untuk dipilih: ATR, Fixed Score, Swing High Low
  • PenghantaranTarget 1: Menghapuskan 50 peratus kedudukan dan membiarkan keuntungan berlari
  • Tracking Stop Loss: Stop loss akan dipindahkan secara automatik selepas keuntungan, dan keuntungan akan dikunci
  • Had harian“Saya tidak tahu apa-apa tentang apa yang berlaku di Malaysia, tetapi saya tidak tahu apa yang berlaku di Malaysia.
  • Pengurusan wangPerdagangan: Riska terkawal dalam 1%

Cadangan untuk kegunaan dalam peperangan

Jika anda ingin menggunakan strategi ini, ingat beberapa perkara:

  1. Kitaran terbaikGraf 5 minit adalah yang terbaik kerana ia dapat menangkap pergerakan jangka pendek dan tidak terlalu kerap
  2. Varieti yang boleh digunakanIa direka khas untuk indeks bank, tetapi indeks lain juga boleh dirujuk.
  3. Masa urus niagaWaktu di India: 9:15-15:15, mengelakkan bunyi bunyi dua tali K di hadapan cakera.
  4. Kawalan KedudukanCadangan: 25 - 75 kontrak untuk setiap tangan, maksimum 200 tangan

Yang paling menarik dari strategi ini ialah “bertabrakan dan berpatah balik”, pasaran lembu boleh melakukan lebih banyak, pasaran beruang boleh kosong, dan pasaran bergolak tidak takut! Seperti pisau tentera Switzerland, ia boleh menangani apa sahaja.

Kod sumber strategi
/*backtest
start: 2025-01-01 00:00:00
end: 2025-10-28 00:00:00
period: 10m
basePeriod: 10m
exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT"}]
*/

//@version=5
strategy("BankNifty LONG & SHORT Multi-Confluence", 
     shorttitle="BN Long-Short",
     overlay=true)

// ═══════════════════════════════════════════════════════════
// 📊 STRATEGY INFO
// ═══════════════════════════════════════════════════════════
// Timeframe: 5-MINUTE CHART (Recommended)
// Direction: LONG & SHORT (Both directions)
// Asset: BankNifty Futures
// Style: Intraday Momentum Trading
// ═══════════════════════════════════════════════════════════

// ═══════════════════════════════════════════════════════════
// ⚙️ INPUT PARAMETERS
// ═══════════════════════════════════════════════════════════

// Trading Direction
tradingDirection = input.string("Both", "Trading Direction", 
     options=["Long Only", "Short Only", "Both"], group="🎯 Strategy Type")

// Trading Hours (IST)
startHour = input.int(9, "Start Hour", minval=0, maxval=23, group="⏰ Trading Session")
startMinute = input.int(15, "Start Minute", minval=0, maxval=59, group="⏰ Trading Session")
endHour = input.int(15, "End Hour", minval=0, maxval=23, group="⏰ Trading Session")
endMinute = input.int(15, "End Minute", minval=0, maxval=59, group="⏰ Trading Session")
avoidFirstCandles = input.int(2, "Skip First N Candles", minval=0, maxval=10, group="⏰ Trading Session")

// Position Sizing
lotSize = input.int(25, "Lot Size", minval=15, maxval=75, group="💰 Position Management")
maxContracts = input.int(75, "Max Contracts", minval=25, maxval=200, step=25, group="💰 Position Management")
riskPercent = input.float(1.0, "Risk % Per Trade", minval=0.5, maxval=3.0, step=0.1, group="💰 Position Management")

// Kernel Regression
kernelLength = input.int(20, "Kernel Length", minval=10, maxval=50, group="📈 Indicators")

// VWAP
vwapSource = input.string("Session", "VWAP Type", options=["Session", "Rolling"], group="📈 Indicators")
vwapRollingLength = input.int(20, "Rolling VWAP Length", minval=10, maxval=100, group="📈 Indicators")

// Volume
volumeLength = input.int(20, "Volume MA Length", minval=10, maxval=50, group="📊 Volume")
volumeMultiplier = input.float(1.5, "Volume Spike", minval=1.1, maxval=3.0, step=0.1, group="📊 Volume")

// CVD
useCVD = input.bool(true, "Use CVD Filter", group="📊 Volume")
cvdLength = input.int(10, "CVD Smoothing", minval=5, maxval=30, group="📊 Volume")

// RSI
useRSI = input.bool(true, "Use RSI Filter", group="🎯 Filters")
rsiLength = input.int(14, "RSI Length", minval=7, maxval=30, group="🎯 Filters")
rsiOverbought = input.int(70, "RSI Overbought", minval=60, maxval=85, group="🎯 Filters")
rsiOversold = input.int(30, "RSI Oversold", minval=15, maxval=40, group="🎯 Filters")

// Price Action
candleBodyPercent = input.float(0.6, "Min Body %", minval=0.4, maxval=0.9, step=0.05, group="🎯 Filters")
minCandlePoints = input.float(20.0, "Min Candle Size", minval=10.0, maxval=100.0, step=5.0, group="🎯 Filters")

// Stop Loss
stopLossType = input.string("ATR", "Stop Loss Type", options=["Fixed", "ATR", "Swing"], group="🛡️ Exits")
atrLength = input.int(14, "ATR Length", minval=7, maxval=30, group="🛡️ Exits")
atrMultiplier = input.float(1.5, "ATR Multiplier", minval=0.5, maxval=3.0, step=0.1, group="🛡️ Exits")
fixedStopLoss = input.float(50.0, "Fixed SL (points)", minval=20.0, maxval=200.0, step=10.0, group="🛡️ Exits")
swingLookback = input.int(10, "Swing Lookback", minval=5, maxval=30, group="🛡️ Exits")

// Targets
rrTarget1 = input.float(1.5, "Target 1 R:R", minval=0.5, maxval=3.0, step=0.1, group="🛡️ Exits")
rrTarget2 = input.float(2.5, "Target 2 R:R", minval=1.0, maxval=5.0, step=0.5, group="🛡️ Exits")
partialExitPercent = input.int(50, "Partial Exit %", minval=25, maxval=75, step=5, group="🛡️ Exits")

// Trailing
useTrailing = input.bool(true, "Trailing Stop", group="🛡️ Exits")
trailActivationRR = input.float(1.2, "Activate at R:R", minval=0.5, maxval=2.0, step=0.1, group="🛡️ Exits")
trailStopRR = input.float(0.8, "Trail Stop R:R", minval=0.3, maxval=1.5, step=0.1, group="🛡️ Exits")

// Risk Management
maxTradesPerDay = input.int(5, "Max Trades/Day", minval=1, maxval=20, group="🚨 Risk")
maxConsecutiveLosses = input.int(2, "Stop After Losses", minval=1, maxval=5, group="🚨 Risk")
dailyLossLimit = input.float(2.5, "Daily Loss %", minval=1.0, maxval=10.0, step=0.5, group="🚨 Risk")
dailyProfitTarget = input.float(5.0, "Daily Target %", minval=2.0, maxval=20.0, step=0.5, group="🚨 Risk")

// ═══════════════════════════════════════════════════════════
// 📊 INDICATORS
// ═══════════════════════════════════════════════════════════

// Kernel Regression
kernel = ta.linreg(close, kernelLength, 0)
kernelSlope = kernel - kernel[1]

// VWAP
vwapValue = vwapSource == "Session" ? ta.vwap(close) : ta.sma(hlc3, vwapRollingLength)
vwapSlope = vwapValue - vwapValue[1]

// Volume
volumeMA = ta.sma(volume, volumeLength)
highVolume = volume > volumeMA * volumeMultiplier
volumeIncreasing = volume > volume[1] and volume[1] > volume[2]

// CVD
buyVolume = close > open ? volume : 0
sellVolume = close < open ? volume : 0
volumeDelta = buyVolume - sellVolume
cvd = ta.cum(volumeDelta)
cvdMA = ta.sma(cvd, cvdLength)

// RSI
rsi = ta.rsi(close, rsiLength)

// ATR
atr = ta.atr(atrLength)

// Price Action
candleRange = high - low
candleBody = math.abs(close - open)
bodyPercent = candleRange > 0 ? candleBody / candleRange : 0

// Swing High/Low
swingHigh = ta.highest(high, swingLookback)
swingLow = ta.lowest(low, swingLookback)

// ═══════════════════════════════════════════════════════════
// ⏰ TIME MANAGEMENT
// ═══════════════════════════════════════════════════════════

currentMinutes = hour * 60 + minute
startMinutes = startHour * 60 + startMinute
endMinutes = endHour * 60 + endMinute
tradingTime = currentMinutes >= startMinutes and currentMinutes <= endMinutes

var int barsToday = 0
newDay = ta.change(dayofweek)
if newDay
    barsToday := 0
if tradingTime
    barsToday += 1

skipInitialBars = barsToday <= avoidFirstCandles
forceExitTime = currentMinutes >= (endMinutes - 5)

// ═══════════════════════════════════════════════════════════
// 💼 POSITION TRACKING
// ═══════════════════════════════════════════════════════════

var int todayTrades = 0
var int consecutiveLosses = 0
var float todayPnL = 0.0
var float entryPrice = na
var int entryBar = 0
var float stopLoss = na
var float target1 = na
var float target2 = na
var float trailStop = na
var bool target1Hit = false
var bool trailActive = false

// Daily Reset
if newDay
    todayTrades := 0
    consecutiveLosses := 0
    todayPnL := 0.0

// Track P&L
if strategy.closedtrades > 0 and strategy.closedtrades != strategy.closedtrades[1]
    lastPnL = strategy.closedtrades.profit(strategy.closedtrades - 1)
    todayPnL += lastPnL
    if lastPnL < 0
        consecutiveLosses += 1
    else
        consecutiveLosses := 0

// Risk Limits
lossLimit = strategy.initial_capital * (dailyLossLimit / 100)
profitTarget = strategy.initial_capital * (dailyProfitTarget / 100)
hitDailyTarget = todayPnL >= profitTarget
hitLossLimit = math.abs(todayPnL) >= lossLimit

canTrade = todayTrades < maxTradesPerDay and
     consecutiveLosses < maxConsecutiveLosses and
     not hitDailyTarget and
     not hitLossLimit and
     tradingTime and
     not skipInitialBars and
     strategy.position_size == 0

// ═══════════════════════════════════════════════════════════
// 🎯 LONG ENTRY CONDITIONS
// ═══════════════════════════════════════════════════════════

// Bullish Trend
longTrend = kernelSlope > 0 and close > kernel
longVWAP = close > vwapValue and vwapSlope > 0
longCVD = useCVD ? cvd > cvdMA and ta.rising(cvd, 2) : true
longRSI = useRSI ? rsi > rsiOversold and rsi < rsiOverbought : true
longVolume = highVolume or volumeIncreasing
longCandle = close > open and bodyPercent >= candleBodyPercent and 
     candleRange >= minCandlePoints and close >= (high - (candleRange * 0.25))

longSignal = longTrend and longVWAP and longCVD and longRSI and longVolume and longCandle and canTrade and
     (tradingDirection == "Long Only" or tradingDirection == "Both")

// ═══════════════════════════════════════════════════════════
// 🎯 SHORT ENTRY CONDITIONS
// ═══════════════════════════════════════════════════════════

// Bearish Trend
shortTrend = kernelSlope < 0 and close < kernel
shortVWAP = close < vwapValue and vwapSlope < 0
shortCVD = useCVD ? cvd < cvdMA and ta.falling(cvd, 2) : true
shortRSI = useRSI ? rsi < rsiOverbought and rsi > rsiOversold : true
shortVolume = highVolume or volumeIncreasing
shortCandle = close < open and bodyPercent >= candleBodyPercent and 
     candleRange >= minCandlePoints and close <= (low + (candleRange * 0.25))

shortSignal = shortTrend and shortVWAP and shortCVD and shortRSI and shortVolume and shortCandle and canTrade and
     (tradingDirection == "Short Only" or tradingDirection == "Both")

// ═══════════════════════════════════════════════════════════
// 💰 POSITION SIZING
// ═══════════════════════════════════════════════════════════

calcPositionSize(stopDistance) =>
    riskAmount = strategy.initial_capital * (riskPercent / 100)
    contracts = math.floor(riskAmount / stopDistance)
    math.min(contracts, maxContracts)

// ═══════════════════════════════════════════════════════════
// 📥 LONG ENTRY
// ═══════════════════════════════════════════════════════════

if longSignal
    entryPrice := close
    entryBar := bar_index
    
    // Calculate Stop Loss
    if stopLossType == "ATR"
        stopLoss := close - (atr * atrMultiplier)
    else if stopLossType == "Swing"
        stopLoss := math.min(swingLow, close - (atr * atrMultiplier))
    else
        stopLoss := close - fixedStopLoss
    
    risk = entryPrice - stopLoss
    target1 := entryPrice + (risk * rrTarget1)
    target2 := entryPrice + (risk * rrTarget2)
    
    qty = calcPositionSize(risk)
    
    trailStop := stopLoss
    target1Hit := false
    trailActive := false
    todayTrades += 1
    
    strategy.entry("LONG", strategy.long, qty=qty, comment="Long-" + str.tostring(todayTrades))

// ═══════════════════════════════════════════════════════════
// 📥 SHORT ENTRY
// ═══════════════════════════════════════════════════════════

if shortSignal
    entryPrice := close
    entryBar := bar_index
    
    // Calculate Stop Loss
    if stopLossType == "ATR"
        stopLoss := close + (atr * atrMultiplier)
    else if stopLossType == "Swing"
        stopLoss := math.max(swingHigh, close + (atr * atrMultiplier))
    else
        stopLoss := close + fixedStopLoss
    
    risk = stopLoss - entryPrice
    target1 := entryPrice - (risk * rrTarget1)
    target2 := entryPrice - (risk * rrTarget2)
    
    qty = calcPositionSize(risk)
    
    trailStop := stopLoss
    target1Hit := false
    trailActive := false
    todayTrades += 1
    
    strategy.entry("SHORT", strategy.short, qty=qty, comment="Short-" + str.tostring(todayTrades))

// ═══════════════════════════════════════════════════════════
// 🏃 TRAILING STOP (LONG)
// ═══════════════════════════════════════════════════════════

if strategy.position_size > 0 and useTrailing
    unrealizedProfit = close - entryPrice
    risk = entryPrice - stopLoss
    
    if unrealizedProfit >= (risk * trailActivationRR) and not trailActive
        trailActive := true
        trailStop := close - (risk * trailStopRR)
    
    if trailActive
        newTrailStop = close - (risk * trailStopRR)
        if newTrailStop > trailStop
            trailStop := newTrailStop

// ═══════════════════════════════════════════════════════════
// 🏃 TRAILING STOP (SHORT)
// ═══════════════════════════════════════════════════════════

if strategy.position_size < 0 and useTrailing
    unrealizedProfit = entryPrice - close
    risk = stopLoss - entryPrice
    
    if unrealizedProfit >= (risk * trailActivationRR) and not trailActive
        trailActive := true
        trailStop := close + (risk * trailStopRR)
    
    if trailActive
        newTrailStop = close + (risk * trailStopRR)
        if newTrailStop < trailStop
            trailStop := newTrailStop

// ═══════════════════════════════════════════════════════════
// 📤 LONG EXIT
// ═══════════════════════════════════════════════════════════

if strategy.position_size > 0
    activeSL = trailActive and useTrailing ? trailStop : stopLoss
    
    // Stop Loss
    if low <= activeSL
        strategy.close("LONG", comment="Long-SL")
    
    // Target 1
    else if high >= target1 and not target1Hit
        exitQty = math.floor(strategy.position_size * (partialExitPercent / 100))
        strategy.close("LONG", qty=exitQty, comment="Long-T1")
        target1Hit := true
        stopLoss := entryPrice
    
    // Target 2
    else if high >= target2
        strategy.close("LONG", comment="Long-T2")
    
    // Force Exit
    else if forceExitTime
        strategy.close("LONG", comment="Long-EOD")

// ═══════════════════════════════════════════════════════════
// 📤 SHORT EXIT
// ═══════════════════════════════════════════════════════════

if strategy.position_size < 0
    activeSL = trailActive and useTrailing ? trailStop : stopLoss
    
    // Stop Loss
    if high >= activeSL
        strategy.close("SHORT", comment="Short-SL")
    
    // Target 1
    else if low <= target1 and not target1Hit
        exitQty = math.floor(math.abs(strategy.position_size) * (partialExitPercent / 100))
        strategy.close("SHORT", qty=exitQty, comment="Short-T1")
        target1Hit := true
        stopLoss := entryPrice
    
    // Target 2
    else if low <= target2
        strategy.close("SHORT", comment="Short-T2")
    
    // Force Exit
    else if forceExitTime
        strategy.close("SHORT", comment="Short-EOD")

// ═══════════════════════════════════════════════════════════
// ⚠️ REVERSAL EXIT
// ═══════════════════════════════════════════════════════════

longReversal = strategy.position_size > 0 and (close < kernel and kernelSlope < 0 or close < vwapValue)
shortReversal = strategy.position_size < 0 and (close > kernel and kernelSlope > 0 or close > vwapValue)

if longReversal and target1Hit
    strategy.close("LONG", comment="Long-Rev")
if shortReversal and target1Hit
    strategy.close("SHORT", comment="Short-Rev")

// ═══════════════════════════════════════════════════════════
// 🎨 VISUALIZATION
// ═══════════════════════════════════════════════════════════

// Indicators
plot(kernel, "Kernel", color=color.new(color.purple, 0), linewidth=2)
plot(vwapValue, "VWAP", color=color.new(color.orange, 0), linewidth=2)

kernelUpper = kernel + atr
kernelLower = kernel - atr
plot(kernelUpper, "K Upper", color=color.new(color.purple, 70), linewidth=1, style=plot.style_circles)
plot(kernelLower, "K Lower", color=color.new(color.purple, 70), linewidth=1, style=plot.style_circles)

// Signals
plotshape(longSignal, "LONG", shape.triangleup, location.belowbar, 
     color=color.new(color.lime, 0), size=size.normal, text="LONG")
plotshape(shortSignal, "SHORT", shape.triangledown, location.abovebar, 
     color=color.new(color.red, 0), size=size.normal, text="SHORT")

// Position Levels
posColor = strategy.position_size > 0 ? color.blue : strategy.position_size < 0 ? color.orange : na
plot(strategy.position_size != 0 ? entryPrice : na, "Entry", 
     color=color.new(posColor, 0), style=plot.style_linebr, linewidth=2)

slColor = strategy.position_size > 0 ? color.red : color.fuchsia
plot(strategy.position_size != 0 ? stopLoss : na, "SL", 
     color=color.new(slColor, 0), style=plot.style_linebr, linewidth=2)

t1Color = strategy.position_size > 0 ? color.green : color.aqua
plot(strategy.position_size != 0 ? target1 : na, "T1", 
     color=color.new(t1Color, 0), style=plot.style_linebr, linewidth=1)
plot(strategy.position_size != 0 ? target2 : na, "T2", 
     color=color.new(t1Color, 0), style=plot.style_linebr, linewidth=2)

plot(strategy.position_size != 0 and trailActive ? trailStop : na, "Trail", 
     color=color.new(color.yellow, 0), style=plot.style_linebr, linewidth=2)

// Volume
barcolor(highVolume ? color.new(color.blue, 70) : na)

// Background
bgcolor(tradingTime ? color.new(color.green, 98) : color.new(color.gray, 95))
bgcolor(strategy.position_size > 0 ? color.new(color.blue, 97) : 
     strategy.position_size < 0 ? color.new(color.orange, 97) : na)
bgcolor(hitDailyTarget ? color.new(color.green, 92) : hitLossLimit ? color.new(color.red, 92) : na)

// ═══════════════════════════════════════════════════════════
// 📊 STATS TABLE
// ═══════════════════════════════════════════════════════════

var table stats = table.new(position.top_right, 2, 11, border_width=1)

if barstate.islast
    // Header
    table.cell(stats, 0, 0, "📊 LONG & SHORT", bgcolor=color.blue, text_color=color.white, text_size=size.small)
    table.cell(stats, 1, 0, "STRATEGY", bgcolor=color.blue, text_color=color.white, text_size=size.small)
    
    // Trades
    table.cell(stats, 0, 1, "Trades", text_size=size.small)
    table.cell(stats, 1, 1, str.tostring(todayTrades) + "/" + str.tostring(maxTradesPerDay), 
         bgcolor=todayTrades >= maxTradesPerDay ? color.red : color.green, text_color=color.white, text_size=size.small)
    
    // Losses
    table.cell(stats, 0, 2, "Losses", text_size=size.small)
    table.cell(stats, 1, 2, str.tostring(consecutiveLosses), 
         bgcolor=consecutiveLosses >= maxConsecutiveLosses ? color.red : color.green, 
         text_color=color.white, text_size=size.small)
    
    // P&L
    pnlPct = (todayPnL / strategy.initial_capital) * 100
    table.cell(stats, 0, 3, "P&L", text_size=size.small)
    table.cell(stats, 1, 3, str.tostring(todayPnL, "#,###") + "\n" + str.tostring(pnlPct, "#.##") + "%", 
         bgcolor=todayPnL > 0 ? color.green : todayPnL < 0 ? color.red : color.gray, 
         text_color=color.white, text_size=size.small)
    
    // Position
    table.cell(stats, 0, 4, "Position", text_size=size.small)
    posText = strategy.position_size > 0 ? "LONG\n" + str.tostring(strategy.position_size) : 
         strategy.position_size < 0 ? "SHORT\n" + str.tostring(math.abs(strategy.position_size)) : "FLAT"
    posBg = strategy.position_size > 0 ? color.blue : strategy.position_size < 0 ? color.orange : color.gray
    table.cell(stats, 1, 4, posText, bgcolor=posBg, text_color=color.white, text_size=size.small)
    
    if strategy.position_size != 0
        // Entry
        table.cell(stats, 0, 5, "Entry", text_size=size.small)
        table.cell(stats, 1, 5, str.tostring(entryPrice, "#.##"), text_size=size.small)
        
        // Live P&L
        livePnL = strategy.position_size > 0 ? (close - entryPrice) * strategy.position_size : 
             (entryPrice - close) * math.abs(strategy.position_size)
        livePct = strategy.position_size > 0 ? ((close - entryPrice) / entryPrice) * 100 : 
             ((entryPrice - close) / entryPrice) * 100
        table.cell(stats, 0, 6, "Live P&L", text_size=size.small)
        table.cell(stats, 1, 6, str.tostring(livePnL, "#,###") + "\n" + str.tostring(livePct, "#.##") + "%", 
             bgcolor=livePnL > 0 ? color.green : color.red, text_color=color.white, text_size=size.small)
        
        // Bars
        bars = bar_index - entryBar
        table.cell(stats, 0, 7, "Bars", text_size=size.small)
        table.cell(stats, 1, 7, str.tostring(bars), text_size=size.small)
        
        // Stop
        table.cell(stats, 0, 8, "Stop", text_size=size.small)
        table.cell(stats, 1, 8, str.tostring(trailActive ? trailStop : stopLoss, "#.##") + 
             (trailActive ? " 🟡" : ""), text_size=size.small)
        
        // T1
        table.cell(stats, 0, 9, "T1", text_size=size.small)
        table.cell(stats, 1, 9, str.tostring(target1, "#.##") + (target1Hit ? " ✓" : ""), text_size=size.small)
        
        // T2
        table.cell(stats, 0, 10, "T2", text_size=size.small)
        table.cell(stats, 1, 10, str.tostring(target2, "#.##"), text_size=size.small)

// ═══════════════════════════════════════════════════════════
// 🔔 ALERTS
// ═══════════════════════════════════════════════════════════

alertcondition(longSignal, "🟢 LONG SIGNAL", "LONG Entry Signal")
alertcondition(shortSignal, "🔴 SHORT SIGNAL", "SHORT Entry Signal")
alertcondition(longReversal or shortReversal, "⚠️ REVERSAL", "Reversal Detected")