futures_trading.pine
Copy
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Gotrade
//@version=6
strategy("Buy the Dip – Futures 1000x", overlay=true, fill_orders_on_standard_ohlc=true,
default_qty_type=strategy.fixed, default_qty_value=1,
initial_capital=1000000, margin_long=0.1,
commission_type=strategy.commission.percent, commission_value=0.04)
// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS
// ═══════════════════════════════════════════════════════════════════════════════
grp0 = "Portfolio"
portfolioSize = input.float(10000, "Portfolio Size (chart currency)", minval=1, group=grp0)
grp1 = "Signal A — Uptrend Dip"
useAutoCrash = input.bool(true, "Auto-adjust crash % to asset volatility", group=grp1,
tooltip="ON: measures the asset's own historical max dip and enters at a fraction of it. Adapts automatically to SPX (small dips) vs IHSG (large dips) vs BTC (huge dips). OFF: uses the fixed % below.")
autoCrashRatio = input.float(0.5, "Entry at X fraction of historical max dip", minval=0.1, maxval=1.0, step=0.05, group=grp1,
tooltip="0.5 = enter when current dip reaches 50% of the deepest dip ever seen over the lookback window. 0.3 = earlier entry, 0.7 = wait for deeper dip.")
autoCrashLookback = input.int(100, "History window to measure max dip (bars)", minval=10, group=grp1,
tooltip="Rolling window to measure the asset's typical max dip. 100 bars on 1D = ~5 months of recent conditions. Keep SHORT (50-150) so a once-in-a-decade crash (like COVID) doesn't permanently inflate the threshold for years afterward. Longer windows = threshold anchored to historical extremes.")
crashPct = input.float(7.0, "Manual crash % (when auto is OFF)", minval=1.0, step=0.5, group=grp1,
tooltip="Used only when auto-adjust is disabled. SPX≈7%, UK100≈4%, IHSG≈20%, BTC≈30%.")
lookback = input.int(20, "Lookback bars for recent high", minval=5, group=grp1)
useTrendFilter = input.bool(true, "Only enter when price > Trend MA", group=grp1,
tooltip="Buy dips only in uptrending markets.")
trendMAPeriod = input.int(100, "Trend MA period", minval=10, group=grp1)
trendMABuffer = input.float(2.0, "Min % above trend MA to enter", minval=0.0, step=0.5, group=grp1,
tooltip="Require price to be at least X% above the trend MA before entering. Prevents buying right at the boundary where the trend exit would immediately fire. 2% = meaningful clearance.")
grp1d = "Bear Market Regime Filter"
useBearFilter = input.bool(true, "Enable bear market regime detection", group=grp1d,
tooltip="Blocks ALL entries when market is confirmed in a bear regime.")
bearMAPeriod = input.int(200, "Bear regime MA period (200-SMA recommended)", minval=20, group=grp1d,
tooltip="200-bar SMA is the standard long-term trend divider.")
bearConsecBars = input.int(10, "Bars below bear MA to confirm bear regime", minval=1, group=grp1d,
tooltip="10 consecutive bars below 200-SMA = confirmed bear. Prevents false triggers on brief dips.")
bearExitBars = input.int(5, "Bars above bear MA to exit bear regime", minval=1, group=grp1d,
tooltip="5 consecutive bars back above 200-SMA to clear bear status. Asymmetric — slow to enter bear, quick to exit.")
grp1b = "Signal B — EMA Oversold Dip"
useEmaDip = input.bool(true, "Enable: buy when price X% below EMA", group=grp1b,
tooltip="Mean-reversion entry. Catches oversold bounces below a key EMA.")
emaDipPeriod = input.int(50, "EMA period", minval=5, group=grp1b,
tooltip="50-bar EMA is a common mean-reversion reference.")
emaDipPct = input.float(5.0, "Trigger when price X% below EMA", minval=0.1, step=0.5, group=grp1b,
tooltip="5% below EMA = oversold. Lower = more signals, higher = only extreme dips.")
emaDipTrend = input.bool(true, "Require uptrend for EMA dip too", group=grp1b,
tooltip="ON (default): EMA dip entries also require price above trend MA. Turn off only to catch recoveries in corrections — dangerous in prolonged bear markets.")
grp1e = "Signal C — MACD Crossover Dip"
useMacdDip = input.bool(true, "Enable MACD crossover breakout entry", group=grp1e,
tooltip="On bullish MACD crossover, wait for price to rise X% above crossover price before entering. If price drops X% below instead, invalidate and wait for next crossover.")
macdFast = input.int(12, "MACD fast EMA", minval=2, group=grp1e)
macdSlow = input.int(26, "MACD slow EMA", minval=2, group=grp1e)
macdSignal = input.int(9, "MACD signal EMA", minval=2, group=grp1e)
macdEntryPct = input.float(10.0,"Enter when price rises X% above crossover price", minval=0.5, step=0.5, group=grp1e,
tooltip="10% = enter only after price confirms momentum by rising 10% above the MACD bullish crossover price.")
macdInvalidatePct = input.float(10.0,"Invalidate if price drops X% below crossover price", minval=0.5, step=0.5, group=grp1e,
tooltip="10% = if price falls 10% below the crossover price before reaching the entry target, cancel the setup and wait for the next crossover.")
macdDipTrend = input.bool(true, "Require uptrend for MACD entry too", group=grp1e,
tooltip="ON: MACD entries also require price above the trend MA buffer.")
grp1c = "Pyramiding"
maxPyramid = input.int(3, "Max entries per open trade", minval=1, group=grp1c,
tooltip="Signal A, Signal B, Signal C, and Compounding all share this counter. Resets when position closes.")
grp2 = "Risk Management"
useEquityPct = input.bool(true, "Size position as % of equity (recommended)", group=grp2,
tooltip="ON: margin = X% of current equity — positions scale down after losses. OFF: fixed margin amount.")
marginEquityPct = input.float(0.2, "Margin as % of equity per trade", minval=0.01, step=0.01, group=grp2)
marginAmt = input.float(2000, "Fixed margin per trade (when % mode is OFF)", minval=1, group=grp2)
leverage = input.int(1000, "Leverage (x)", minval=1, maxval=1000, group=grp2)
trailPct = input.float(5.0, "Trailing stop % from peak", minval=0.1, step=0.1, group=grp2)
trailActivatePct = input.float(8.0, "Activate trail only after X% profit", minval=0.1, step=0.1, group=grp2,
tooltip="Must be > trailPct. Guarantees trail stop is above entry when it first activates.")
portfolioStopPct = input.float(50.0, "Emergency close when loss ≥ X% of peak equity", minval=1.0, maxval=100.0, step=1.0, group=grp2,
tooltip="Now references peak equity, not fixed initial capital. Scales up as you make profits.")
equityDDFilter = input.bool(true, "Halt new entries when equity drawdown > X% from peak", group=grp2,
tooltip="Circuit breaker: stops all new entries if equity has fallen more than X% from its all-time high. Does NOT close existing positions.")
equityDDPct = input.float(20.0, "Max equity drawdown % from peak before halting", minval=1.0, maxval=99.0, step=1.0, group=grp2,
tooltip="20% = halt entries if equity is 20%+ below its peak. Prevents averaging down into a collapsing position.")
useTrendExit = input.bool(true, "Exit on trend MA crossunder", group=grp2,
tooltip="Closes full position when price crosses below the trend MA. Acts as a regime-change exit.")
useEMAExit = input.bool(false, "Exit on EMA dip MA crossunder", group=grp2,
tooltip="Faster exit using the 50-EMA. More responsive but more whipsaws.")
grp3 = "Compounding"
compoundRatio = input.float(100.0, "Compound when profit ≥ X% of portfolio", minval=1.0, step=1.0, group=grp3,
tooltip="Fires an extra pyramid entry at each profit tier. Counts toward pyramid limit.")
grp4 = "Volatility Filter"
useVolFilter = input.bool(true, "Enable ATR volatility filter", group=grp4,
tooltip="Skips entries or reduces leverage when market volatility is abnormally high.")
atrPeriod = input.int(14, "ATR period", minval=5, group=grp4)
atrHighPct = input.float(3.0, "ATR% threshold: skip entries above this", minval=0.1, step=0.1, group=grp4,
tooltip="ATR% = ATR / close × 100. If above this %, skip all new entries.")
atrModPct = input.float(1.5, "ATR% threshold: reduce leverage below this", minval=0.1, step=0.1, group=grp4,
tooltip="Between this and the skip threshold, leverage scales down proportionally.")
volLeverageMin = input.int(100, "Minimum leverage in elevated-vol regime", minval=1, maxval=1000, group=grp4,
tooltip="Floor for leverage when vol is between the two thresholds.")
// ═══════════════════════════════════════════════════════════════════════════════
// DERIVED CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════
// Clamp equity to a small positive floor so margin never goes negative or zero
safeEquity = math.max(strategy.equity, strategy.initial_capital * 0.001)
effectiveMargin = useEquityPct ? safeEquity * marginEquityPct / 100 : marginAmt
// ── ATR Volatility Filter ──────────────────────────────────────────────────────
atrValue = ta.atr(atrPeriod)
atrPct = atrValue / math.max(close, 0.000001) * 100.0
volTooHigh = useVolFilter and atrPct >= atrHighPct
volElevated = useVolFilter and atrPct >= atrModPct and not volTooHigh
// Scale leverage down linearly between atrModPct and atrHighPct
volLeverageRatio = volElevated ?
math.max(float(volLeverageMin), leverage * (1.0 - (atrPct - atrModPct) / math.max(atrHighPct - atrModPct, 0.001))) :
float(leverage)
effectiveLeverage = volTooHigh ? float(volLeverageMin) : volLeverageRatio
notionalSize = effectiveMargin * effectiveLeverage
qtyContracts = notionalSize / math.max(close, 0.000001)
// ═══════════════════════════════════════════════════════════════════════════════
// TREND MA + BEAR MARKET REGIME DETECTION
// ═══════════════════════════════════════════════════════════════════════════════
trendMA = ta.sma(close, trendMAPeriod)
inUptrend = close > trendMA
// Entry requires price to be trendMABuffer% above the trend MA, not just barely above it.
// This creates a buffer so the trend exit (crossunder) doesn't fire immediately after entry.
trendMAThreshold = trendMA * (1 + trendMABuffer / 100)
entryAllowed = not useTrendFilter or close > trendMAThreshold
// 200-SMA bear regime: confirmed after bearConsecBars consecutive bars below
bearMA = ta.sma(close, bearMAPeriod)
var int barsBelow200 = 0
var int barsAbove200 = 0
if close < bearMA
barsBelow200 := barsBelow200 + 1
barsAbove200 := 0
else
barsAbove200 := barsAbove200 + 1
barsBelow200 := 0
var bool inBearRegime = false
if barsBelow200 >= bearConsecBars
inBearRegime := true
if barsAbove200 >= bearExitBars
inBearRegime := false
bearBlock = useBearFilter and inBearRegime
// ═══════════════════════════════════════════════════════════════════════════════
// SIGNALS
// ═══════════════════════════════════════════════════════════════════════════════
// Signal A: Uptrend Dip
recentHigh = ta.highest(high, lookback)
crashPct_cur = (recentHigh - close) / recentHigh * 100.0
// Auto-crash: rolling max dip over a SHORT recent window (100 bars default).
// Short window = adapts to current volatility regime, not permanently anchored
// to once-in-a-decade events like COVID. After COVID's 25% dip, a 500-bar
// window keeps effectiveCrashPct=12.5% for ~2 years, starving the strategy
// of signals. A 100-bar window recovers once the extreme rolls out (~5 months).
histMaxDip = ta.highest(crashPct_cur, autoCrashLookback)
// Smooth with an EMA of the rolling max to prevent abrupt threshold jumps
// when a new extreme enters or exits the window.
var float smoothedMax = na
smoothedMax := na(smoothedMax) ? histMaxDip : 0.95 * smoothedMax + 0.05 * histMaxDip
effectiveCrashPct = useAutoCrash ? smoothedMax * autoCrashRatio : crashPct
sigA = ta.crossover(crashPct_cur, effectiveCrashPct) and entryAllowed
// Signal B: EMA Oversold Dip
emaDipMA = ta.ema(close, emaDipPeriod)
emaBelowPct = (emaDipMA - close) / emaDipMA * 100.0 // positive = price below EMA
sigB = useEmaDip and ta.crossover(emaBelowPct, emaDipPct) and
(not emaDipTrend or entryAllowed)
// Signal C: MACD Crossover Breakout
// Logic: bullish MACD cross → record crossover price → enter if +X% above it.
// If price falls -X% below crossover before reaching target → invalidate.
// Bearish MACD cross → always invalidate (no trading in downward momentum).
// Step 1 — compute MACD
macdLine = ta.ema(close, macdFast) - ta.ema(close, macdSlow)
signalLine = ta.ema(macdLine, macdSignal)
macdBullCross = ta.crossover(macdLine, signalLine) // momentum turns bullish
macdBearCross = ta.crossunder(macdLine, signalLine) // momentum turns bearish → no trade
// Step 2 — track the price at the latest bullish crossover
var float macdCrossPrice = na
if macdBullCross
macdCrossPrice := close // new setup: record crossover price
if macdBearCross
macdCrossPrice := na // bearish cross: cancel any pending setup
// Step 3 — invalidate if price drops too far below crossover (failed breakout)
macdDropFromCross = not na(macdCrossPrice) ? (macdCrossPrice - close) / macdCrossPrice * 100.0 : 0.0
if not na(macdCrossPrice) and macdDropFromCross >= macdInvalidatePct
macdCrossPrice := na // -10% from crossover = fake breakout, wait for next
// Step 4 — measure rise from crossover price
macdRisePct = not na(macdCrossPrice) ? (close - macdCrossPrice) / macdCrossPrice * 100.0 : 0.0
// Step 5 — fire when price first crosses +entryPct% above crossover
sigC = useMacdDip and not na(macdCrossPrice) and
ta.crossover(macdRisePct, macdEntryPct) and
(not macdDipTrend or entryAllowed)
// ═══════════════════════════════════════════════════════════════════════════════
// POSITION STATE
// ═══════════════════════════════════════════════════════════════════════════════
inPos = strategy.position_size > 0
avgEntry = strategy.position_avg_price
liqPrice = avgEntry > 0 ? avgEntry * (1 - 1.0 / leverage) : na
// Track pyramid count — reset to 0 when flat
var int pyramidCount = 0
if not inPos
pyramidCount := 0
pyramidAllowed = pyramidCount < maxPyramid
// ═══════════════════════════════════════════════════════════════════════════════
// TRAILING STOP
// ═══════════════════════════════════════════════════════════════════════════════
var float peakSinceEntry = na
if inPos
peakSinceEntry := math.max(nz(peakSinceEntry, close), high)
else
peakSinceEntry := na
rawTrailStop = not na(peakSinceEntry) ? peakSinceEntry * (1 - trailPct / 100) : na
// Floor at entry: once trail activates, worst case is breakeven
trailStopPrice = (not na(rawTrailStop) and avgEntry > 0) ? math.max(avgEntry, rawTrailStop) : na
trailActive = inPos and not na(peakSinceEntry) and
peakSinceEntry >= avgEntry * (1 + trailActivatePct / 100)
// ═══════════════════════════════════════════════════════════════════════════════
// EQUITY PEAK TRACKER, CIRCUIT BREAKER, ENTRY GATE
// ═══════════════════════════════════════════════════════════════════════════════
var float equityPeak = strategy.initial_capital
// Reset equity peak when bear regime ends — fresh reference for each new bull cycle.
// Without this, the circuit breaker locks permanently after a crash (equity can't
// recover to the pre-crash peak while no trades are being placed).
bearRegimeJustEnded = not inBearRegime and inBearRegime[1]
if bearRegimeJustEnded
equityPeak := strategy.equity
equityPeak := math.max(equityPeak, strategy.equity)
equityDrawdownPct = (equityPeak - strategy.equity) / equityPeak * 100.0
circuitBreakerOn = equityDDFilter and equityDrawdownPct >= equityDDPct
// Consolidated entry gate: all three protections must clear
entryGate = not circuitBreakerOn and not bearBlock and not volTooHigh
// Emergency stop amount references PEAK equity (not fixed initial_capital)
portfolioStopAmt = equityPeak * portfolioStopPct / 100
// ═══════════════════════════════════════════════════════════════════════════════
// COMPOUNDING LOGIC
// ═══════════════════════════════════════════════════════════════════════════════
compoundLevel = strategy.initial_capital * compoundRatio / 100.0
profitTier = inPos ? math.floor(strategy.openprofit / compoundLevel) : 0
compoundFire = inPos and profitTier > math.floor(strategy.openprofit[1] / compoundLevel)
// ═══════════════════════════════════════════════════════════════════════════════
// ORDERS
// ═══════════════════════════════════════════════════════════════════════════════
// Signal A: uptrend dip
if sigA and pyramidAllowed and entryGate
pyramidCount += 1
strategy.entry("A-Dip #" + str.tostring(pyramidCount), strategy.long, qty=qtyContracts,
comment="A: " + str.tostring(math.round(crashPct_cur, 1)) + "% dip")
// Signal B: EMA oversold dip
if sigB and pyramidAllowed and not sigA and entryGate
pyramidCount += 1
strategy.entry("B-EMA #" + str.tostring(pyramidCount), strategy.long, qty=qtyContracts,
comment="B: -" + str.tostring(math.round(emaBelowPct, 1)) + "% EMA")
// Signal C: MACD crossover breakout
if sigC and pyramidAllowed and not sigA and not sigB and entryGate
pyramidCount += 1
strategy.entry("C-MACD #" + str.tostring(pyramidCount), strategy.long, qty=qtyContracts,
comment="C: +" + str.tostring(math.round(macdRisePct, 1)) + "% MACD xo@" + str.tostring(math.round(macdCrossPrice, 2)))
// Compound on profit — now counts toward pyramid limit
if compoundFire and pyramidAllowed and entryGate
pyramidCount += 1
strategy.entry("Compound x" + str.tostring(profitTier), strategy.long, qty=qtyContracts,
comment="COMPOUND tier " + str.tostring(profitTier) + " [" + str.tostring(pyramidCount) + "/" + str.tostring(maxPyramid) + "]")
// Exit: trailing stop
if trailActive and close <= trailStopPrice
strategy.close_all(comment="TRAIL EXIT")
// Emergency exit: loss >= X% of peak equity
if inPos and strategy.openprofit <= -portfolioStopAmt
strategy.close_all(comment="EMRG STOP " + str.tostring(portfolioStopPct) + "%")
// Exit: trend MA crossunder (regime change exit)
trendCrossunder = ta.crossunder(close, trendMA)
if useTrendExit and inPos and trendCrossunder
strategy.close_all(comment="TREND EXIT MA" + str.tostring(trendMAPeriod))
// Exit: EMA dip MA crossunder (faster exit, optional)
emaCrossunder = ta.crossunder(close, emaDipMA)
if useEMAExit and inPos and emaCrossunder
strategy.close_all(comment="EMA EXIT MA" + str.tostring(emaDipPeriod))
// ═══════════════════════════════════════════════════════════════════════════════
// PLOTS
// ═══════════════════════════════════════════════════════════════════════════════
plot(trendMA, "Trend MA", color=color.new(color.blue, 30), linewidth=2)
plot(bearMA, "Bear MA (200)", color=color.new(color.red, 20), linewidth=2)
plot(emaDipMA, "EMA Dip MA", color=color.new(color.orange, 30), linewidth=1)
plot(recentHigh, "Recent High", color=color.new(color.red, 50), linewidth=1)
plot(inPos ? trailStopPrice : na, "Trailing Stop", color=color.new(color.yellow, 0), linewidth=2, style=plot.style_linebr)
plot(inPos ? peakSinceEntry : na, "Peak", color=color.new(color.green, 50), linewidth=1, style=plot.style_linebr)
plot(inPos ? liqPrice : na, "Liq Price", color=color.new(color.red, 0), linewidth=1, style=plot.style_linebr)
// Background zones
bgcolor(useTrendFilter and not inUptrend ? color.new(color.red, 92) : na, title="Downtrend Zone")
bgcolor(inBearRegime ? color.new(color.red, 80) : na, title="Bear Regime")
bgcolor(circuitBreakerOn ? color.new(color.purple, 85) : na, title="Circuit Breaker Active")
bgcolor(volTooHigh ? color.new(color.orange, 85) : na, title="High Volatility Zone")
// Entry / exit signals
plotshape(sigA and pyramidAllowed and entryGate, "Signal A", shape.triangleup, location.belowbar, color.green, size=size.normal)
plotshape(sigB and pyramidAllowed and not sigA and entryGate, "Signal B (EMA)", shape.triangleup, location.belowbar, color.orange, size=size.small)
plotshape(sigC and pyramidAllowed and not sigA and not sigB and entryGate, "Signal C (MACD)", shape.triangleup, location.belowbar, color.aqua, size=size.small)
plotshape(macdBullCross, "MACD Bull Cross", shape.circle, location.belowbar, color.teal, size=size.tiny)
plotshape(sigA and not pyramidAllowed, "A blocked (max)", shape.xcross, location.belowbar, color.gray, size=size.tiny)
plotshape(compoundFire and not pyramidAllowed, "Compound blocked", shape.xcross, location.abovebar, color.gray, size=size.tiny)
plotshape(compoundFire and pyramidAllowed and entryGate, "Compound", shape.diamond, location.abovebar, color.aqua, size=size.small)
plotshape(useTrendExit and inPos and trendCrossunder, "Trend Exit", shape.triangledown, location.abovebar, color.red, size=size.normal)
// ═══════════════════════════════════════════════════════════════════════════════
// DASHBOARD
// ═══════════════════════════════════════════════════════════════════════════════
var table dash = table.new(position.top_right, 2, 16,
bgcolor=color.new(color.black, 55), border_width=1, border_color=color.new(color.gray, 50))
if barstate.islast
pnlCol = strategy.openprofit >= 0 ? color.lime : color.red
netCol = strategy.netprofit >= 0 ? color.lime : color.red
trendColor = inUptrend ? color.lime : color.red
na_str = "–"
table.cell(dash, 0, 0, "Buy-the-Dip 1000x", text_color=color.white,
text_size=size.small, bgcolor=color.new(color.navy, 30))
table.cell(dash, 1, 0, "", text_color=color.white,
text_size=size.small, bgcolor=color.new(color.navy, 30))
table.cell(dash, 0, 1, "Trend", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 1, (inUptrend ? "▲ UPTREND" : "▼ DOWNTREND") + " | MA" + str.tostring(trendMAPeriod) + "=" + str.tostring(math.round(trendMA, 0)),
text_color=trendColor, text_size=size.small)
table.cell(dash, 0, 2, "Sig A (dip)", text_color=color.silver, text_size=size.small)
autoLabel = useAutoCrash ? (" auto=" + str.tostring(math.round(effectiveCrashPct, 1)) + "% [ref=" + str.tostring(math.round(smoothedMax, 1)) + "%×" + str.tostring(autoCrashRatio) + "]") : ""
table.cell(dash, 1, 2, str.tostring(math.round(effectiveCrashPct, 1)) + "% from " + str.tostring(lookback) + "-bar high" + autoLabel + (entryAllowed ? " ✓" : " ✗"),
text_color=color.green, text_size=size.small)
table.cell(dash, 0, 3, "Sig B (EMA)", text_color=color.silver, text_size=size.small)
emaStatus = useEmaDip ? (str.tostring(emaDipPct) + "% below EMA" + str.tostring(emaDipPeriod) + " | now " + str.tostring(math.round(emaBelowPct, 1)) + "%") : "disabled"
table.cell(dash, 1, 3, emaStatus,
text_color=emaBelowPct >= emaDipPct ? color.orange : color.silver, text_size=size.small)
table.cell(dash, 0, 4, "Pyramid", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 4, str.tostring(pyramidCount) + " / " + str.tostring(maxPyramid) + " entries",
text_color=pyramidAllowed ? color.lime : color.red, text_size=size.small)
table.cell(dash, 0, 5, "Margin / trade", text_color=color.silver, text_size=size.small)
modeStr = useEquityPct ? (str.tostring(marginEquityPct) + "% eq=") : "fixed="
table.cell(dash, 1, 5, modeStr + str.tostring(math.round(effectiveMargin, 0)) + " × " + str.tostring(math.round(effectiveLeverage, 0)) + "x",
text_color=color.yellow, text_size=size.small)
trailWarning = trailActivatePct <= trailPct ? " ⚠" : " ✓"
table.cell(dash, 0, 6, "Trail Stop", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 6, str.tostring(trailPct) + "% / activate +" + str.tostring(trailActivatePct) + "%" + trailWarning,
text_color=trailActivatePct > trailPct ? color.yellow : color.red, text_size=size.small)
table.cell(dash, 0, 7, "Trail Price", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 7, inPos ? (trailActive ? str.tostring(math.round(trailStopPrice, 2)) : "waiting +" + str.tostring(trailActivatePct) + "%") : na_str,
text_color=trailActive ? color.yellow : color.gray, text_size=size.small)
table.cell(dash, 0, 8, "Peak", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 8, inPos ? str.tostring(math.round(peakSinceEntry, 2)) : na_str,
text_color=color.lime, text_size=size.small)
table.cell(dash, 0, 9, "Emrg Stop", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 9, "-" + str.tostring(math.round(portfolioStopAmt, 0)) + " (" + str.tostring(portfolioStopPct) + "% of peak)",
text_color=color.orange, text_size=size.small)
table.cell(dash, 0, 10, "Open P&L", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 10, str.tostring(math.round(strategy.openprofit, 2)),
text_color=pnlCol, text_size=size.small)
table.cell(dash, 0, 11, "Net Profit", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 11, str.tostring(math.round(strategy.netprofit, 2)),
text_color=netCol, text_size=size.small)
table.cell(dash, 0, 12, "Equity Peak", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 12, str.tostring(math.round(equityPeak, 0)) + " | DD: " + str.tostring(math.round(equityDrawdownPct, 1)) + "%",
text_color=equityDrawdownPct > equityDDPct * 0.75 ? color.red : color.lime, text_size=size.small)
table.cell(dash, 0, 13, "Circuit Breaker", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 13, circuitBreakerOn ? "⛔ HALTED" : "✓ ACTIVE",
text_color=circuitBreakerOn ? color.red : color.lime, text_size=size.small)
table.cell(dash, 0, 14, "Bear Regime", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 14, inBearRegime ? ("🐻 BEAR " + str.tostring(barsBelow200) + " bars") : ("✓ BULL " + str.tostring(barsAbove200) + " bars"),
text_color=inBearRegime ? color.red : color.lime, text_size=size.small)
table.cell(dash, 0, 15, "Volatility", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 15, "ATR%=" + str.tostring(math.round(atrPct, 2)) + (volTooHigh ? " ⛔ SKIP" : volElevated ? " ⚠ ×" + str.tostring(math.round(effectiveLeverage, 0)) : " ✓ OK"),
text_color=volTooHigh ? color.red : volElevated ? color.orange : color.lime, text_size=size.small)
Show all 419 lines