// ════════════════════════════════════════════════════════════════════
// HA 6-PATTERN SYSTEM | CatShack Capital
// Heikin-Ashi pattern recognition across 6 repeatable setups:
//
// P1 CGR — Clean Green Run (3+ solid green streak)
// P2 SHR — Stop Hunt Reclaim (wick flush + solid follow)
// P3 CC — Compression Coil (narrowing bodies → breakout)
// P4 FR — First Responder (wide green after red run)
// P5 SMP — SMA Magnetic Pull (solid green after SMA touch)
// P6 BCD — Body Count Divergence (warning: momentum fading)
//
// Apply to a REGULAR candlestick chart.
// HA values are computed internally via request.security.
// ════════════════════════════════════════════════════════════════════
//@version=6
indicator("HA 6-Pattern System | CatShack Capital",
overlay = true,
max_labels_count = 500,
max_lines_count = 200)
// ────────────────────────────────────────────────────────────────────
// SECTION 1 — INPUTS
// ────────────────────────────────────────────────────────────────────
// ── Instrument Mode ──────────────────────────────────────────────────
var string GRP_MODE = "🎚 Instrument Mode"
i_etfMode = input.bool(false, "ETF Mode (QQQ / SPY) — looser SHR & FR thresholds", group=GRP_MODE,
tooltip="OFF = Futures/Futures ETF (MNQ, ES, NQ) — tight thresholds for volatile HA wicks\nON = ETF (QQQ, SPY) — smoother HA candles, relaxed wick & body requirements for SHR and FR")
// ── General ──────────────────────────────────────────────────────────
var string GRP_GEN = "⚙ General"
i_smaLen = input.int (200, "SMA Length", group=GRP_GEN, minval=10, maxval=500)
i_smaSlope = input.int (5, "SMA Slope Lookback (bars)", group=GRP_GEN, minval=1, maxval=20)
i_solidMax = input.float (0.15, "Solid candle: max wick/body", group=GRP_GEN, minval=0.01, maxval=0.4, step=0.01)
// ── P1 CGR ───────────────────────────────────────────────────────────
var string GRP_CGR = "P1 — Clean Green Run (CGR) 🟢🟢🟢"
i_showCGR = input.bool (true, "Show CGR", group=GRP_CGR)
i_cgrMin = input.int (3, "Min consecutive solid bars", group=GRP_CGR, minval=2, maxval=7)
// ── P2 SHR ───────────────────────────────────────────────────────────
var string GRP_SHR = "P2 — Stop Hunt Reclaim (SHR) ⚡"
i_showSHR = input.bool (true, "Show SHR", group=GRP_SHR)
i_shrWick = input.float (0.80, "Hunt candle: min lower wick/body", group=GRP_SHR, minval=0.3, maxval=2.0, step=0.05,
tooltip="Futures default: 0.80 | ETF mode auto-uses 0.55. Lower = more sensitive to smaller wicks (needed for ETF smooth HA candles)")
i_shrBody = input.float (0.90, "Reclaim: min body vs hunt body", group=GRP_SHR, minval=0.3, maxval=1.5, step=0.05,
tooltip="Futures default: 0.90 | ETF mode auto-uses 0.70. ETF recovery bars are often smaller relative to the crash candle")
// ── P3 CC ────────────────────────────────────────────────────────────
var string GRP_CC = "P3 — Compression Coil (CC) 🌀"
i_showCC = input.bool (true, "Show CC", group=GRP_CC)
i_ccBars = input.int (4, "Min coil bars", group=GRP_CC, minval=3, maxval=8)
i_ccMult = input.float (1.5, "Breakout size multiplier", group=GRP_CC, minval=1.1, maxval=3.0, step=0.1)
// ── P4 FR ────────────────────────────────────────────────────────────
var string GRP_FR = "P4 — First Responder (FR) 🔄"
i_showFR = input.bool (true, "Show FR", group=GRP_FR)
i_frRed = input.int (3, "Min prior red bars", group=GRP_FR, minval=2, maxval=7,
tooltip="Futures default: 3 | ETF mode auto-uses 5. ETF crashes tend to have more red bars before the reversal")
i_frUpWick = input.float (0.20, "Max upper wick/body (clean top)", group=GRP_FR, minval=0.0, maxval=0.5, step=0.05,
tooltip="Futures default: 0.20 | ETF mode auto-uses 0.35. ETF first-responder bars often have small upper wicks and still work")
// ── P5 SMP ───────────────────────────────────────────────────────────
var string GRP_SMP = "P5 — SMA Magnetic Pull (SMP) 🧲"
i_showSMP = input.bool (true, "Show SMP", group=GRP_SMP)
i_smpZone = input.float (1.5, "SMA proximity zone (%)", group=GRP_SMP, minval=0.25, maxval=5.0, step=0.25)
// ── P6 BCD ───────────────────────────────────────────────────────────
var string GRP_BCD = "P6 — Body Count Divergence (BCD) ⚠️"
i_showBCD = input.bool (true, "Show BCD", group=GRP_BCD)
i_bcdRatio = input.float (0.45, "Body shrink ratio (warning)", group=GRP_BCD, minval=0.1, maxval=0.7, step=0.05)
i_bcdWick = input.float (0.35, "Min lower wick/body to trigger",group=GRP_BCD, minval=0.1, maxval=0.8, step=0.05)
i_bcdStreak = input.int (5, "Min green streak before signal",group=GRP_BCD, minval=3, maxval=10)
// ── Display ──────────────────────────────────────────────────────────
var string GRP_DISP = "🎨 Display"
i_showBG = input.bool(true, "Background tints on signals", group=GRP_DISP)
i_showLabels = input.bool(true, "Detail labels (SHR, streak)", group=GRP_DISP)
i_showScore = input.bool(true, "Show composite score on entry",group=GRP_DISP)
// ────────────────────────────────────────────────────────────────────
// SECTION 2 — HEIKIN-ASHI DATA
// Pull true HA OHLC via request.security so this works on any chart
// ────────────────────────────────────────────────────────────────────
haSymbol = ticker.heikinashi(syminfo.tickerid)
[haO, haH, haL, haC] = request.security(haSymbol, timeframe.period,
[open, high, low, close],
gaps = barmerge.gaps_off,
lookahead = barmerge.lookahead_off)
// ── Core measurements ────────────────────────────────────────────────
haBodyTop = math.max(haO, haC)
haBodyBot = math.min(haO, haC)
haBody = haBodyTop - haBodyBot // body size (always ≥ 0)
haUpWick = haH - haBodyTop // upper wick
haDnWick = haBodyBot - haL // lower wick
isGreen = haC > haO
isRed = haC < haO
isDoji = math.abs(haC - haO) < (haH - haL) * 0.10
// ── Running body average (must be declared before quality flags) ──────
avgBody5 = math.avg(haBody[1], haBody[2], haBody[3], haBody[4], haBody[5])
avgBody3 = math.avg(haBody[1], haBody[2], haBody[3])
// ── Quality flags ────────────────────────────────────────────────────
// "Solid" = almost no wick in the momentum direction AND meaningful body size
solidGreen = isGreen and haBody > 0
and (haDnWick <= haBody * i_solidMax)
and (haBody >= avgBody5 * 0.6) // must be at least 60% of avg body size
solidRed = isRed and haBody > 0
and (haUpWick <= haBody * i_solidMax)
and (haBody >= avgBody5 * 0.6)
// Hunt candle: green HA bar with large lower wick (stop-sweep)
// ETF mode: lower wick threshold (0.55 vs 0.80) — ETF HA candles are smoother
// ETF mode: removes the sweep-below-prior-low requirement (ETFs gap less aggressively)
shrWickThresh = i_etfMode ? 0.55 : i_shrWick
shrBodyThresh = i_etfMode ? 0.70 : i_shrBody
huntCandle = isGreen and haBody > 0
and (haDnWick >= haBody * shrWickThresh)
and (i_etfMode ? true : haL < haL[1]) // ETF: skip sweep requirement; Futures: must sweep below prior low
and (haBody >= avgBody5 * 0.5) // body must be meaningful, not a doji
// ── (avgBody5/avgBody3 moved above — removed duplicate) ──────────────
// ────────────────────────────────────────────────────────────────────
// SECTION 3 — SMA + TREND CONTEXT
// ────────────────────────────────────────────────────────────────────
sma = ta.sma(close, i_smaLen)
smaRising = sma > sma[i_smaSlope]
aboveSMA = close > sma
smaPct = i_smpZone / 100.0
nearSMA_1 = haL[1] <= sma[1] * (1.0 + smaPct) and haL[1] >= sma[1] * (1.0 - smaPct)
nearSMA_2 = haL[2] <= sma[2] * (1.0 + smaPct) and haL[2] >= sma[2] * (1.0 - smaPct)
smaTouched = nearSMA_1 or nearSMA_2
// ────────────────────────────────────────────────────────────────────
// SECTION 4 — RUNNING STREAKS
// ────────────────────────────────────────────────────────────────────
var int greenStreak = 0
var int redStreak = 0
var int solidStreak = 0
greenStreak := isGreen ? greenStreak + 1 : 0
redStreak := isRed ? redStreak + 1 : 0
solidStreak := solidGreen ? solidStreak + 1 : 0
// ────────────────────────────────────────────────────────────────────
// SECTION 5 — PATTERN SIGNALS
// ────────────────────────────────────────────────────────────────────
// ── P1: CLEAN GREEN RUN (CGR) ─────────────────────────────────────────
// Fires when streak hits minimum — with 5-bar cooldown to prevent clustering
var int cgrCooldown = 0
cgrCooldown := cgrCooldown > 0 ? cgrCooldown - 1 : 0
cgrRaw = solidStreak == i_cgrMin and aboveSMA and smaRising
cgrSignal = i_showCGR and cgrRaw and cgrCooldown == 0
if cgrSignal
cgrCooldown := 5
// ── P2: STOP HUNT RECLAIM (SHR) ──────────────────────────────────────
// Bar[-1] = hunt candle (green + big lower wick)
// Bar[ 0] = solid green follow-through
// ETF mode: body comparison uses looser threshold (0.70 vs 0.90)
shrSignal = i_showSHR
and huntCandle[1]
and solidGreen
and haBody >= haBody[1] * shrBodyThresh
// ── P3: COMPRESSION COIL (CC) ────────────────────────────────────────
// Prior N bars show narrowing HA bodies (each ≤ 1.2× the one before)
// Then current bar: body >= avgCoil × multiplier (expansion breakout)
//
// Build compressed flag across i_ccBars prior bars
b1 = haBody[1]
b2 = haBody[2]
b3 = haBody[3]
b4 = haBody[4]
b5 = haBody[5]
b6 = haBody[6]
// 4-bar coil (always checked)
compressed4 = b1 <= b2 * 1.2 and b2 <= b3 * 1.2 and b3 <= b4 * 1.2
// 5-bar coil extension
compressed5 = compressed4 and b4 <= b5 * 1.2
// 6-bar coil extension
compressed6 = compressed5 and b5 <= b6 * 1.2
coilBase = i_ccBars <= 4 ? compressed4 :
i_ccBars <= 5 ? compressed5 : compressed6
coilAvgBody = i_ccBars <= 4 ? (b1+b2+b3+b4)/4.0 :
i_ccBars <= 5 ? (b1+b2+b3+b4+b5)/5.0 : (b1+b2+b3+b4+b5+b6)/6.0
ccBull = i_showCC and coilBase and isGreen and haBody >= coilAvgBody * i_ccMult and smaRising and aboveSMA
ccBear = i_showCC and coilBase and isRed and haBody >= coilAvgBody * i_ccMult and not smaRising
// ── P4: FIRST RESPONDER (FR) ─────────────────────────────────────────
// Futures: 3+ consecutive red bars, first wide green, tight upper wick
// ETF mode: 5+ red bars required (ETF crashes are slower),
// body compared to 10-bar avg (not just 3 prior reds),
// looser upper wick allowance (0.35 vs 0.20)
frRedMin = i_etfMode ? 5 : i_frRed
frUpWickMax = i_etfMode ? 0.35 : i_frUpWick
// ETF: compare body to 10-bar lookback average (handles large crash candles)
avgBody10 = (haBody[1]+haBody[2]+haBody[3]+haBody[4]+haBody[5]+
haBody[6]+haBody[7]+haBody[8]+haBody[9]+haBody[10]) / 10.0
avgPriorRed = redStreak[1] >= 3 ?
(haBody[1]+haBody[2]+haBody[3]) / 3.0 : 0.0
// ETF: body only needs to be 50% of avg (crash red bars are huge; first green looks small)
frBodyRef = i_etfMode ? avgBody10 * 0.50 : avgPriorRed * 0.85
frSignal = i_showFR
and redStreak[1] >= frRedMin
and isGreen
and haBody >= frBodyRef
and haUpWick <= haBody * frUpWickMax
// ── P5: SMA MAGNETIC PULL (SMP) ──────────────────────────────────────
// Solid green candle after price touched/brushed the SMA within 2 bars
// Only valid in rising SMA environment
smpSignal = i_showSMP
and solidGreen
and smaTouched
and smaRising
and aboveSMA
// ── P6: BODY COUNT DIVERGENCE (BCD) ──────────────────────────────────
// WARNING — momentum fading:
// - Currently in a green run (≥ i_bcdStreak bars)
// - Current green candle body is much smaller than prior (shrinking)
// - Lower wick appearing for first time in the run
inGreenRun = greenStreak[1] >= i_bcdStreak
bodyShrinking = isGreen and haBody > 0
and haBody < haBody[1] * i_bcdRatio
and haBody < avgBody5 * i_bcdRatio // also below the recent average
wickEmerging = haDnWick > haBody * i_bcdWick
priorSolid = solidGreen[1] and solidGreen[2] // TWO solid bars before (not just one)
bcdSignal = i_showBCD
and inGreenRun
and bodyShrinking
and wickEmerging
and priorSolid
// ────────────────────────────────────────────────────────────────────
// SECTION 6 — COMPOSITE QUALITY SCORE
// Useful to size positions and filter marginal setups
// ────────────────────────────────────────────────────────────────────
// +2 SHR (highest conviction — flush + reclaim)
// +1 CGR (streak confirmation)
// +1 SMP (level confluence with SMA)
// +1 FR (reversal + wide body)
// +1 CCBull
// −2 BCD (momentum warning overrides)
score = 0
score += shrSignal ? 2 : 0
score += cgrSignal ? 1 : 0
score += smpSignal ? 1 : 0
score += frSignal ? 1 : 0
score += ccBull ? 1 : 0
score -= bcdSignal ? 2 : 0
anyBullSignal = cgrSignal or shrSignal or frSignal or smpSignal or ccBull
// ────────────────────────────────────────────────────────────────────
// SECTION 7 — VISUAL OUTPUT
// ────────────────────────────────────────────────────────────────────
// ── SMA ──────────────────────────────────────────────────────────────
plot(sma, "SMA", color.new(color.blue, 0), linewidth=2)
// ── P1 CGR — lime triangle below bar ─────────────────────────────────
plotshape(cgrSignal,
title = "P1 CGR — Clean Green Run",
style = shape.triangleup,
location = location.belowbar,
color = color.new(color.lime, 0),
size = size.small,
text = "CGR",
textcolor = color.lime)
// ── P2 SHR — gold star below bar (highest signal) ────────────────────
plotshape(shrSignal,
title = "P2 SHR — Stop Hunt Reclaim",
style = shape.labelup,
location = location.belowbar,
color = color.new(color.yellow, 0),
size = size.large,
text = "SHR",
textcolor = color.yellow)
// ── P3 CC Bull — cyan diamond below ──────────────────────────────────
plotshape(ccBull,
title = "P3 CC — Coil Breakout Up",
style = shape.diamond,
location = location.belowbar,
color = color.new(color.aqua, 0),
size = size.small,
text = "CC↑",
textcolor = color.aqua)
// ── P3 CC Bear — cyan diamond above ──────────────────────────────────
plotshape(ccBear,
title = "P3 CC — Coil Breakdown",
style = shape.diamond,
location = location.abovebar,
color = color.new(color.aqua, 20),
size = size.small,
text = "CC↓",
textcolor = color.aqua)
// ── P4 FR — orange arrow up below ────────────────────────────────────
plotshape(frSignal,
title = "P4 FR — First Responder",
style = shape.arrowup,
location = location.belowbar,
color = color.new(color.orange, 0),
size = size.normal,
text = "FR",
textcolor = color.orange)
// ── P5 SMP — teal circle below ───────────────────────────────────────
plotshape(smpSignal,
title = "P5 SMP — SMA Magnetic Pull",
style = shape.circle,
location = location.belowbar,
color = color.new(color.teal, 0),
size = size.small,
text = "SMP",
textcolor = color.teal)
// ── P6 BCD — red triangle down above ─────────────────────────────────
plotshape(bcdSignal,
title = "P6 BCD — Divergence Warning",
style = shape.triangledown,
location = location.abovebar,
color = color.new(color.red, 0),
size = size.normal,
text = "BCD",
textcolor = color.red)
// ────────────────────────────────────────────────────────────────────
// SECTION 8 — BACKGROUND TINTS (subtle, not distracting)
// ────────────────────────────────────────────────────────────────────
bgcolor(i_showBG and cgrSignal ? color.new(color.lime, 93) : na, title="CGR BG")
bgcolor(i_showBG and shrSignal ? color.new(color.yellow, 90) : na, title="SHR BG")
bgcolor(i_showBG and (smpSignal or frSignal) ? color.new(color.teal, 93) : na, title="SMP/FR BG")
bgcolor(i_showBG and bcdSignal ? color.new(color.red, 94) : na, title="BCD Warning BG")
// ────────────────────────────────────────────────────────────────────
// SECTION 9 — DETAIL LABELS
// ────────────────────────────────────────────────────────────────────
// Green streak counter (small, above each solid green bar in run)
if i_showLabels and solidGreen and solidStreak > 0 and solidStreak < i_cgrMin
label.new(bar_index, haH,
str.tostring(solidStreak) + "G",
color = color.new(color.lime, 75),
textcolor = color.white,
style = label.style_label_down,
size = size.tiny,
tooltip = "Solid green streak: " + str.tostring(solidStreak) + " bar(s). Need " + str.tostring(i_cgrMin) + " for CGR signal.")
// SHR detail label — shows the wick ratio of the hunt candle
if i_showLabels and shrSignal
wickRatio = math.round(haDnWick[1] / math.max(haBody[1], 0.0001) * 100)
label.new(bar_index, haL,
"RECLAIM\nWick " + str.tostring(wickRatio) + "%",
color = color.new(color.yellow, 60),
textcolor = color.black,
style = label.style_label_up,
size = size.small,
tooltip = "Hunt candle lower wick was " + str.tostring(wickRatio) + "% of body. Follow-through confirmed.")
// FR: note that this is day-1 — wait for confirmation
if i_showLabels and frSignal
label.new(bar_index, haL,
"FR\nWait D2",
color = color.new(color.orange, 65),
textcolor = color.black,
style = label.style_label_up,
size = size.tiny,
tooltip = "First Responder after " + str.tostring(redStreak[1]) + " red bars. Consider waiting for second green candle to confirm.")
// Composite score label on any bull signal
if i_showScore and anyBullSignal and not bcdSignal
scoreColor = score >= 3 ? color.new(color.green, 60) :
score >= 2 ? color.new(color.lime, 70) :
color.new(color.gray, 70)
label.new(bar_index, haH,
"Q" + str.tostring(score),
color = scoreColor,
textcolor = color.white,
style = label.style_label_down,
size = size.tiny,
tooltip = "Signal quality score: " + str.tostring(score) + "/5. CGR=" + str.tostring(cgrSignal?1:0) + " SHR=" + str.tostring(shrSignal?2:0) + " SMP=" + str.tostring(smpSignal?1:0) + " FR=" + str.tostring(frSignal?1:0))
// ────────────────────────────────────────────────────────────────────
// SECTION 10 — HUNT CANDLE MARKER
// Mark the hunt candle itself (bar[-1] when SHR fires) with a dot
// ────────────────────────────────────────────────────────────────────
// We need to mark bar[-1] — detect it by looking one bar ahead
huntConfirmed = shrSignal[1] == false and shrSignal // SHR just fired THIS bar
if huntConfirmed and i_showLabels
line.new(bar_index - 1, haBodyBot[1], bar_index - 1, haL[1],
color = color.new(color.yellow, 0),
width = 2,
style = line.style_dotted)
// ────────────────────────────────────────────────────────────────────
// SECTION 11 — ALERT CONDITIONS
// ────────────────────────────────────────────────────────────────────
alertcondition(cgrSignal,
title = "P1 CGR — Clean Green Run",
message = "CGR SIGNAL: Consecutive solid green HA candles confirmed. Above rising SMA. Enter bull put spread at open.")
alertcondition(shrSignal,
title = "P2 SHR — Stop Hunt Reclaim (HIGH PRIORITY)",
message = "SHR SIGNAL: Stop hunt reclaim confirmed. Hunt candle swept low, solid green follow-through. Highest probability entry. Enter DSE spread at open.")
alertcondition(frSignal,
title = "P4 FR — First Responder",
message = "FR SIGNAL: Wide green candle after red bars. Day-1 signal — consider waiting for second green bar to confirm.")
alertcondition(smpSignal,
title = "P5 SMP — SMA Magnetic Pull",
message = "SMP SIGNAL: Solid green candle after SMA touch. Trend continuation setup. Check quality score before entry.")
alertcondition(bcdSignal,
title = "P6 BCD — Divergence WARNING",
message = "BCD WARNING: Body shrinking and lower wick appearing. Momentum fading. Avoid new bull entries. Consider early exit on open positions.")
alertcondition(ccBull,
title = "P3 CC — Coil Breakout Up",
message = "CC BULL: Compression coil breakout to upside. Body expansion confirmed. Trend aligned.")
alertcondition(ccBear,
title = "P3 CC — Coil Breakdown",
message = "CC BEAR: Compression coil breakdown to downside. No new bull spreads. Defensive posture.")
alertcondition(anyBullSignal and score >= 3,
title = "HIGH QUALITY SIGNAL (Score 3+)",
message = "HIGH QUALITY: Multiple pattern confluence detected. Priority DSE entry. Check score table for details.")
// ────────────────────────────────────────────────────────────────────
// SECTION 12 — INFO TABLE (top-right corner)
// Shows current bar's active signals and quality score
// ────────────────────────────────────────────────────────────────────
if barstate.islast
tbl = table.new(position.top_right, 2, 10,
bgcolor = color.new(color.black, 70),
border_color = color.new(color.gray, 60),
border_width = 1,
frame_color = color.new(color.gray, 50),
frame_width = 1)
// Mode header row
modeLabel = i_etfMode ? "ETF MODE (QQQ/SPY)" : "FUTURES MODE (MNQ/ES)"
modeColor = i_etfMode ? color.new(color.teal, 30) : color.new(color.orange, 30)
table.cell(tbl, 0, 0, modeLabel, text_color=color.white, text_size=size.tiny, bgcolor=modeColor)
table.cell(tbl, 1, 0, "", text_color=color.white, text_size=size.tiny, bgcolor=modeColor)
// Header row 2
table.cell(tbl, 0, 1, "PATTERN", text_color=color.new(color.white, 30), text_size=size.tiny, bgcolor=color.new(color.navy, 20))
table.cell(tbl, 1, 1, "STATUS", text_color=color.new(color.white, 30), text_size=size.tiny, bgcolor=color.new(color.navy, 20))
// P1 CGR
table.cell(tbl, 0, 2, "P1 CGR", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 2, cgrSignal ? "FIRE (" + str.tostring(solidStreak) + "G)" : solidStreak > 0 ? str.tostring(solidStreak) + "G building" : "-",
text_color = cgrSignal ? color.lime : solidStreak > 0 ? color.new(color.lime, 40) : color.new(color.white, 50),
text_size = size.tiny)
// P2 SHR
table.cell(tbl, 0, 3, "P2 SHR", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 3, shrSignal ? "FIRE" : huntCandle ? "Hunt bar" : "-",
text_color = shrSignal ? color.yellow : huntCandle ? color.new(color.yellow, 40) : color.new(color.white, 50),
text_size = size.tiny)
// P3 CC
table.cell(tbl, 0, 4, "P3 CC", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 4, ccBull ? "BULL" : ccBear ? "BEAR" : coilBase ? "Coiled" : "-",
text_color = ccBull ? color.aqua : ccBear ? color.new(color.aqua, 40) : color.new(color.white, 50),
text_size = size.tiny)
// P4 FR
table.cell(tbl, 0, 5, "P4 FR", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 5, frSignal ? "DAY 1" : redStreak >= frRedMin ? str.tostring(redStreak) + " red" : "-",
text_color = frSignal ? color.orange : redStreak >= frRedMin ? color.new(color.orange, 40) : color.new(color.white, 50),
text_size = size.tiny)
// P5 SMP
table.cell(tbl, 0, 6, "P5 SMP", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 6, smpSignal ? "FIRE" : smaTouched ? "Near SMA" : "-",
text_color = smpSignal ? color.teal : smaTouched ? color.new(color.teal, 40) : color.new(color.white, 50),
text_size = size.tiny)
// P6 BCD
table.cell(tbl, 0, 7, "P6 BCD", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 7, bcdSignal ? "WARN" : "-",
text_color = bcdSignal ? color.red : color.new(color.white, 50),
text_size = size.tiny)
// Divider
table.cell(tbl, 0, 8, "----", text_color=color.new(color.white, 60), text_size=size.tiny)
table.cell(tbl, 1, 8, "----", text_color=color.new(color.white, 60), text_size=size.tiny)
// Quality score
scoreLabel = score >= 4 ? "** HIGH" : score >= 2 ? "* MED" : score <= -1 ? "AVOID" : "LOW"
scoreCol = score >= 4 ? color.lime : score >= 2 ? color.yellow : score <= -1 ? color.red : color.new(color.white, 50)
table.cell(tbl, 0, 9, "SCORE", text_color=color.white, text_size=size.tiny)
table.cell(tbl, 1, 9, str.tostring(score) + "/5 " + scoreLabel,
text_color = scoreCol, text_size=size.tiny)