Indicator · Pine Script v6 · Own pane

Reflex RCCE - Engine View

by cianfru

A separate-pane chart port of a scanner's decision logic, intended to read setups bar by bar.

View on GitHub

Repaints

GitHub stars1on the repository
Pine versionv6current
Lines of code620
Settings16inputs
LicenceNone statedfile: MPL-2.0
Last update2 days ago27 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

620 lines of Pine Script v6 from tradingview/reflex_rcce.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

reflex_rcce.pine
// This Pine Script code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
//@version=6
//
// Reflex RCCE - engine view
// -------------------------
// A chart port of the Reflex scanner's decision logic, so setups can be read
// bar by bar. Mirrors, from the backend:
//   engines/rcce_engine.py       regime (z-score, energy, volatility, 6 regime
//                                probabilities, persistence + hysteresis +
//                                bearish-latch release)
//   engines/heatmap_engine.py    heat 0-100 vs the weekly BMSB, heat phase
//   engines/exhaustion_engine.py absorption, climax, floor confirmation
//   signal_synthesizer.py        the 9 core checks and the final signal tree
//   scanner.detect_divergence    BEAR-DIV / BULL-DIV vs BTC's regime
//
// Not reproducible from a chart, so set by hand in the inputs (read them off
// the terminal): market consensus, Fear & Greed, funding regime, stablecoin
// trend. CoinGlass / HyperLens / CVD modifiers and the agent-layer filters
// (cooldown, flapping, inertia) are omitted - they need live feeds and scan
// history. The chart therefore behaves like a Hyperliquid-only symbol
// (9 checks, STRONG_LONG at >= 80% effective).
//
// Known differences from the terminal, all small:
//   * vol_scale is computed per bar here; the scanner applies the latest
//     bar's value to the whole window.
//   * The BMSB uses completed weekly candles (no repainting); the scanner on
//     main includes the in-progress week.
//   * History here is the full chart; the scanner sees the last ~600 bars.
indicator("Reflex RCCE - engine view", shorttitle = "RCCE", overlay = false, precision = 2, max_bars_back = 500, max_labels_count = 500)

// ---------- Inputs ----------
G_CTX  = "Market context (copy from the terminal)"
consIn = input.string("MIXED", "Market consensus", options = ["RISK-ON", "ACCUMULATION", "MIXED", "RISK-OFF", "EUPHORIA"], group = G_CTX)
fgIn   = input.int(50, "Fear & Greed", minval = 0, maxval = 100, group = G_CTX)
fundIn = input.string("NEUTRAL", "Funding regime", options = ["NEUTRAL", "CROWDED_LONG", "CROWDED_SHORT"], group = G_CTX)
stabIn = input.string("STABLE", "Stablecoin supply", options = ["EXPANDING", "STABLE", "CONTRACTING"], group = G_CTX)

G_REF  = "References"
btcSym = input.symbol("BINANCE:BTCUSDT", "BTC (for divergence)", group = G_REF)
useDiv = input.bool(true, "Check BTC divergence", group = G_REF)

G_VIS    = "Display"
showBg   = input.bool(true, "Regime background on price", group = G_VIS)
showBmsb = input.bool(true, "Weekly BMSB band on price", group = G_VIS)
showSig  = input.bool(true, "Setup markers on price (open / upgrade / exit)", group = G_VIS)
showRaw  = input.bool(false, "Raw engine signal changes (debug)", group = G_VIS)
showExh  = input.bool(true, "Absorption / climax / floor markers", group = G_VIS)
showTbl  = input.bool(true, "Engine table", group = G_VIS)
showChk  = input.bool(true, "Include the 9 checks in the table", group = G_VIS)
tblPos   = input.string("top_right", "Table position", options = ["top_right", "top_left", "bottom_right", "bottom_left"], group = G_VIS)
tblSize  = input.string("small", "Table text", options = ["tiny", "small", "normal"], group = G_VIS)
closedOnly = input.bool(true, "Setup changes on closed bars only", group = G_VIS)

// ---------- Engine constants (rcce_engine.py) ----------
LEN_LONG = 200
LEN_SHORT = 30
LEN_REG = 300
Z_BLOWOFF_ENG = 2.5
Z_CAP = -1.0
Z_TRIM = 3.0
Z_TRIM_HARD = 3.5
MIN_REGIME_BARS = 5
HYST = 1.25
DOM_BULL = 0.50
DOM_CUR = 0.10
DOM_BARS = 2
EPS = 1e-10
// signal_synthesizer.py uses its own, tighter blow-off level for entries
Z_BLOWOFF_SYN = 2.0

// Regime index: 0 MARKUP, 1 BLOWOFF, 2 REACC, 3 MARKDOWN, 4 CAP, 5 ACCUM
var REG_NAME = array.from("MARKUP", "BLOWOFF", "REACC", "MARKDOWN", "CAP", "ACCUM")
var REG_HINT = array.from("Uptrend", "Overheated", "Re-accumulating", "Downtrend", "Capitulation", "Accumulation")
var REG_COL  = array.from(#97FCE4, #f87171, #b5a5db, #cf9185, #c084fc, #91b9e8)

// ---------- Helpers ----------
f_gate(float x, float c, float w) =>
    1.0 / (1.0 + math.exp(-(x - c) / math.max(w, 0.01)))

f_isBull(int r) =>
    r == 0 or r == 2 or r == 5

f_argmax(array<float> p) =>
    int best = 0
    for i = 1 to 5
        if array.get(p, i) > array.get(p, best)
            best := i
    best

// Within the bullish family the held regime is favoured: others must beat it by HYST.
f_pick(int cur, array<float> p) =>
    int best = f_argmax(p)
    if f_isBull(cur)
        float bestV = -1.0
        for i = 0 to 5
            float v = array.get(p, i)
            if f_isBull(i) and i != cur
                v := v / HYST
            if v > bestV
                bestV := v
                best := i
    best

// numpy.percentile(method="linear") over the trailing window, ignoring na.
f_pctLinear(float src, int n, float pct) =>
    float result = na
    if bar_index >= n - 1
        vals = array.new_float(0)
        for i = 0 to n - 1
            float v = src[i]
            if not na(v)
                array.push(vals, v)
        int sz = array.size(vals)
        if sz > 0
            array.sort(vals)
            float pos = pct / 100.0 * (sz - 1)
            int lo = int(math.floor(pos))
            int hi = math.min(lo + 1, sz - 1)
            result := array.get(vals, lo) + (array.get(vals, hi) - array.get(vals, lo)) * (pos - lo)
    result

f_volScale(float r) =>
    r < 0.8 ? 0.85 : r < 1.1 ? 1.0 : r < 1.5 ? 1.15 : 1.25

// ---------- RCCE regime engine ----------
f_rcce() =>
    // 1. Hybrid z-score: log price vs linreg(300), SMA(200) fallback, normalised over 200 bars
    float logp = math.log(math.max(close, EPS))
    float logMa = ta.sma(logp, LEN_LONG)
    float logReg = ta.linreg(logp, LEN_REG, 0)
    float dev = logp - (na(logReg) ? logMa : logReg)
    float mDev = ta.sma(dev, LEN_LONG)
    float sDev = ta.stdev(dev, LEN_LONG)
    float z = na(dev) or na(sDev) ? na : sDev < EPS ? 0.0 : (dev - mDev) / sDev

    // 2. Volatility state: stdev(30)/price vs its own 25th/75th percentile
    float volS = ta.stdev(close, LEN_SHORT) / math.max(close, EPS)
    float p25 = f_pctLinear(volS, LEN_SHORT, 25)
    float p75 = f_pctLinear(volS, LEN_SHORT, 75)
    bool volLow = not na(volS) and not na(p25) and volS < p25
    bool volHigh = not na(volS) and not na(p75) and volS > p75

    // 3. Energy: stdev(14) / stdev(50)
    float sS = ta.stdev(close, 50)
    float energy = ta.stdev(close, 14) / (na(sS) or sS == 0 ? EPS : sS)

    // 3b. Threshold scaling from ATR(14)/ATR(50), both simple averages of TR
    float trv = ta.tr(true)
    float atrS = ta.sma(trv, 50)
    float atrRatio = na(atrS) or atrS <= EPS ? 1.0 : nz(ta.sma(trv, 14), 1.0) / atrS
    float vs = f_volScale(atrRatio)

    // 4. Regime probabilities (soft-gated, normalised)
    float zS = nz(z)
    float eS = nz(energy)
    float vS = nz(volS)
    float vlB = 0.15 + 0.85 * (volLow ? 1.0 : 0.0)
    float vhB = 0.15 + 0.85 * (volHigh ? 1.0 : 0.0)
    float nvhB = 0.15 + 0.85 * (volHigh ? 0.0 : 1.0)
    float dead = 0.3 * vs + math.max(0.0, eS - 1.1) * 0.3
    float zMk = zS + dead
    float zRe = zS - dead
    float zBo = Z_BLOWOFF_ENG * vs
    float zCp = Z_CAP * vs
    float pMk = math.max(0.0, zMk) * (0.5 + 0.5 * f_gate(eS, 1.0, 0.2))
    float pBo = math.max(0.0, zS - zBo) * f_gate(zS, zBo, 0.2)
    float pRe = math.max(0.0, -zRe) * f_gate(-zRe, 0.0, 0.2) * nvhB
    float pMd = vS * 2.0 * f_gate(-zS, 0.0, 0.2) * vhB
    // Markdown only while price is falling over LEN_SHORT bars (engine: MARKDOWN_TREND_GATE)
    float trend30 = bar_index >= LEN_SHORT ? math.log(close / close[LEN_SHORT]) : 0.0
    pMd := pMd * f_gate(-trend30, 0.0, 0.03)
    float pCp = math.max(0.0, -zS) * f_gate(-zS, -zCp, 0.3) * vlB
    float pAc = f_gate(zS, -0.5, 0.15) * (1.0 - f_gate(zS, 0.5, 0.15)) * vlB
    float sumP = pMk + pBo + pRe + pMd + pCp + pAc + EPS
    p = array.from(pMk / sumP, pBo / sumP, pRe / sumP, pMd / sumP, pCp / sumP, pAc / sumP)

    // 5. Persistence: MIN_REGIME_BARS to switch, hysteresis inside the bullish
    //    family, family-exit counting and the 2-bar dominance release from bearish.
    var int cur = na
    var int pend = na
    var int pcount = 0
    var int bullStreak = 0
    var int domStreak = 0
    if not na(z)
        if na(cur)
            cur := f_argmax(p)
            pend := cur
            pcount := 1
        bool released = false
        if not f_isBull(cur)
            int bb = array.get(p, 2) > array.get(p, 0) ? 2 : 0
            bb := array.get(p, 5) > array.get(p, bb) ? 5 : bb
            if array.get(p, bb) > DOM_BULL and array.get(p, cur) < DOM_CUR
                domStreak += 1
                if domStreak >= DOM_BARS
                    cur := bb
                    pend := cur
                    pcount := 0
                    bullStreak := 0
                    domStreak := 0
                    released := true
            else
                domStreak := 0
        else
            domStreak := 0
        if not released
            int cand = f_pick(cur, p)
            if not f_isBull(cur) and f_isBull(cand)
                bullStreak += 1
                pend := cand
                pcount := bullStreak
                if bullStreak >= MIN_REGIME_BARS
                    cur := cand
                    pcount := 0
                    bullStreak := 0
            else
                bullStreak := 0
                if cand == cur
                    pend := cur
                    pcount := 0
                else if cand == pend
                    pcount += 1
                    if pcount >= MIN_REGIME_BARS
                        cur := pend
                        pcount := 0
                else
                    pend := cand
                    pcount := 1
    float conf = na(cur) ? na : array.get(p, nz(cur))
    [z, energy, volLow, volHigh, vs, atrRatio, cur, conf, pend, pcount, array.get(p, 0), array.get(p, 1), array.get(p, 2), array.get(p, 3), array.get(p, 4), array.get(p, 5)]

f_regimeOnly() =>
    [_z, _e, _vl, _vh, _vs, _ar, r, _c, _pd, _pc, _p0, _p1, _p2, _p3, _p4, _p5] = f_rcce()
    r

[z, energy, volLow, volHigh, vs, atrRatio, regime, conf, pendReg, pendCount, pMk, pBo, pRe, pMd, pCp, pAc] = f_rcce()
bool hasRegime = not na(regime)
int regIdx = nz(regime)
string regName = hasRegime ? array.get(REG_NAME, regIdx) : "FLAT"
color regCol = hasRegime ? array.get(REG_COL, regIdx) : #52525b

// Regime instability: 3+ label changes in the last 7 days caps STRONG_LONG
var changeTimes = array.new_int(0)
if hasRegime and not na(regime[1]) and regime != regime[1]
    array.push(changeTimes, time)
while array.size(changeTimes) > 0 and array.get(changeTimes, 0) < time - 7 * 86400000
    array.shift(changeTimes)
int changes7d = array.size(changeTimes)
bool unstable = changes7d >= 3

// ---------- Weekly BMSB + heat (heatmap_engine.py) ----------
f_weekly() =>
    float e = ta.ema(close, 21)
    float s = ta.sma(close, 20)
    float a = ta.atr(14)
    [((e + s) / 2.0)[1], e[1], s[1], a[1], ta.sma(a, 20)[1]]

[wMid, wEma, wSma, wAtr, wAtrSma] = request.security(syminfo.tickerid, "W", f_weekly(), lookahead = barmerge.lookahead_on)

float atrD = ta.atr(14)
bool bmsbValid = not na(wMid) and not na(atrD) and atrD > 0
bool wAtrOk = not na(wAtr) and wAtr > 0 and not na(wAtrSma) and wAtrSma > 0
float r3 = wAtrOk ? (atrD / wAtr) * (wAtr / wAtrSma) : 0.15

// Heat of a close, measured with the CURRENT bar's ATR / r3 / BMSB (as the backend does)
f_heatOf(float c) =>
    bmsbValid and not na(c) ? math.min(100, math.round(math.abs(c - wMid) / atrD * r3 * 12.5)) : 0

int heat = f_heatOf(close)
int heatP1 = f_heatOf(close[1])
int heatP2 = f_heatOf(close[2])
int heatDir = bmsbValid ? (close >= wMid ? 1 : -1) : 0
bool exhaustPeak = heatP1 > 80 and heatP1 > heat and heatP1 > heatP2
string heatPhase = exhaustPeak ? "Exhaustion" : heat > 80 and heatDir > 0 and heatP1 <= 80 ? "Entry" : heat - heatP1 < 0 and heat > 40 ? "Fading" : heat > 20 ? "Extension" : "Neutral"
int prevHeat = nz(heat[1])
bool macroBlocked = not bmsbValid or heatDir < 0

// ---------- Exhaustion (exhaustion_engine.py) ----------
float trE = ta.tr(true)
float atrE = nz(ta.atr(14), 1.0)
float effDown = (close < close[1] ? math.abs(close - close[1]) : 0.0) / atrE
float effS = nz(ta.sma(effDown, 3))
bool effortPeak = effS > nz(ta.sma(effS, 20)) * 1.2
bool isRed = close < open
float body = math.abs(close - open)
float lowerWick = isRed ? close - low : open - low
float upperWick = isRed ? high - open : high - close
bool downZone = not na(wMid) and close < wMid
bool absorption = downZone and isRed and trE < atrE and effortPeak
bool climax = downZone and trE > atrE * 1.5 and lowerWick > body * 1.5 and lowerWick > upperWick and effortPeak
int aquaCount = int(nz(math.sum(absorption ? 1 : 0, 10)))
var float startVol = na
if absorption and aquaCount == 1
    startVol := volume
bool floorOk = aquaCount >= 3 and not na(startVol) and volume < startVol
string exhState = floorOk ? "EXHAUSTED_FLOOR" : climax ? "CLIMAX" : absorption ? "ABSORBING" : downZone ? "BEAR_ZONE" : "NEUTRAL"

// ---------- BTC divergence (scanner.detect_divergence) ----------
int btcRegRaw = request.security(btcSym, timeframe.period, f_regimeOnly())
int btcReg = useDiv ? btcRegRaw : na
string divergence = na(btcReg) or not hasRegime ? "" : (regime == 0 or regime == 2) and btcReg == 3 ? "BEAR-DIV" : (regime == 3 or regime == 4) and btcReg == 0 ? "BULL-DIV" : ""
bool bearDiv = divergence == "BEAR-DIV"

// ---------- Signal synthesis (signal_synthesizer.py) ----------
float zz = nz(z)
float cf = nz(conf)
int heatForce = regName == "BLOWOFF" ? 85 : (regName == "CAP" or regName == "ACCUM") ? 100 : 95
int heatBlock = regName == "BLOWOFF" ? 75 : (regName == "CAP" or regName == "ACCUM") ? 100 : 85
float zTrim = Z_TRIM * vs
float zTrimHard = Z_TRIM_HARD * vs
float zBlowSyn = Z_BLOWOFF_SYN * vs

bool c1 = regName == "MARKUP" or regName == "ACCUM"
bool c2 = consIn == "RISK-ON" or consIn == "ACCUMULATION"
bool c3 = zz >= -0.5 and zz <= 2.5
bool c4 = not bearDiv
bool c5 = heat < heatBlock
bool c6 = not climax
bool c7 = fundIn != "CROWDED_LONG"
bool c8 = fgIn < 70
bool c9 = stabIn != "CONTRACTING"
int coreMet = (c1 ? 1 : 0) + (c2 ? 1 : 0) + (c3 ? 1 : 0) + (c4 ? 1 : 0) + (c5 ? 1 : 0) + (c6 ? 1 : 0) + (c7 ? 1 : 0) + (c8 ? 1 : 0) + (c9 ? 1 : 0)

float effective = coreMet
if regName == "CAP" or regName == "ACCUM"
    effective += (floorOk ? 2.0 : 0.0) + (absorption ? 1.0 : 0.0)
if regName == "MARKUP" and (heatPhase == "Fading" or heatPhase == "Exhaustion")
    effective -= 1.0
float effPct = effective / 9.0

string sig = "WAIT"
string why = ""
bool decided = false

if not hasRegime
    why := "Warming up (needs ~" + str.tostring(LEN_LONG * 2) + " bars)"
    decided := true
else if heat >= heatForce
    sig := "TRIM"
    why := "Heat " + str.tostring(heat) + " >= " + str.tostring(heatForce)
    decided := true
else if regName == "BLOWOFF" and zz > zTrimHard
    sig := "TRIM_HARD"
    why := "BLOWOFF, z above hard trim"
    decided := true
else if regName == "BLOWOFF" and zz > zTrim
    sig := "TRIM"
    why := "BLOWOFF, z above trim"
    decided := true
else if regName == "MARKDOWN" and consIn == "RISK-OFF" and not macroBlocked
    sig := "RISK_OFF"
    why := "MARKDOWN + consensus RISK-OFF"
    decided := true
else if bearDiv and cf < 0.5
    sig := "NO_LONG"
    why := "BEAR-DIV with confidence < 50%"
    decided := true
else if consIn == "EUPHORIA" and zz > zBlowSyn
    sig := "NO_LONG"
    why := "EUPHORIA + extended z"
    decided := true
else if regName == "MARKDOWN" and not macroBlocked
    why := "MARKDOWN regime"
    decided := true
else if climax
    why := "Exhaustion climax - entries blocked"
    decided := true
else if macroBlocked
    if not bmsbValid
        why := "No weekly BMSB - all entries blocked"
    else if zz >= 0.3 and zz <= 1.2 and heat >= 20 and heat <= prevHeat and divergence != "BULL-DIV" and fundIn != "CROWDED_SHORT" and cf > 0.30
        sig := "LIGHT_SHORT"
        why := "Below BMSB: stalling bear rally"
    else
        why := "Below weekly BMSB - longs blocked"
    decided := true

// Entry rules (evaluated by strength)
if not decided and effPct >= 0.80 and not bearDiv
    string strong = unstable ? "LIGHT_LONG" : "STRONG_LONG"
    if regName == "MARKUP" and effPct >= 0.85 and zz > 0 and zz < 1.0
        sig := strong
        why := "MARKUP strict band" + (unstable ? " (capped: regime chop)" : "")
        decided := true
    else if regName == "MARKUP" and zz > -0.5 and zz < zBlowSyn
        sig := "LIGHT_LONG"
        why := "MARKUP outside strict band"
        decided := true
    else if regName == "ACCUM" or regName == "CAP"
        sig := strong
        why := regName + " full confirmation" + (unstable ? " (capped: regime chop)" : "")
        decided := true
else if not decided and effPct >= 0.55 and not c7
    if (regName == "MARKUP" or regName == "ACCUM") and not bearDiv
        sig := "LIGHT_LONG"
        why := "Would be STRONG but funding crowded long"
        decided := true

if not decided and regName == "ACCUM" and zz < 0 and volLow and cf > 0.40 and consIn != "RISK-OFF" and heat < 70 and fgIn <= 40
    sig := "ACCUMULATE"
    why := "ACCUM, low vol, fear"
    decided := true

if not decided and absorption and (regName == "ACCUM" or regName == "REACC") and consIn != "RISK-OFF" and cf > 0.40 and heat < 70
    sig := "ACCUMULATE"
    why := "Absorption in " + regName
    decided := true

if not decided and regName == "CAP" and zz < -1.0 and volHigh and cf > 0.30 and consIn != "RISK-OFF" and fgIn <= 40
    sig := floorOk ? "REVIVAL_SEED_CONFIRMED" : "REVIVAL_SEED"
    why := "Capitulation, high vol, fear" + (floorOk ? " + floor" : "")
    decided := true

if not decided and effPct >= 0.40 and (regName == "MARKUP" or regName == "REACC" or regName == "ACCUM")
    if regName == "MARKUP" and zz > 1.0 and zz < zBlowSyn and cf > 0.50 and heat < 80 and consIn != "RISK-OFF" and not bearDiv
        sig := "LIGHT_LONG"
        why := "MARKUP, z 1.0 to blow-off"
        decided := true
    else if regName == "MARKUP" and zz > 0 and zz < zBlowSyn and cf > 0.50 and heat < heatBlock and (consIn == "RISK-ON" or consIn == "MIXED") and not bearDiv
        sig := "LIGHT_LONG"
        why := "MARKUP, z 0 to blow-off"
        decided := true
    else if regName == "REACC" and zz < 0.5 and cf > 0.50 and heat < 80 and (consIn == "RISK-ON" or consIn == "MIXED")
        sig := "ACCUMULATE"
        why := "REACC pullback"
        decided := true

if not decided and regName == "CAP" and zz < -1.0 and cf > 0.30 and absorption
    sig := "ACCUMULATE"
    why := "CAP + absorption"
    decided := true

if not decided
    why := "No entry rule met (" + str.tostring(effPct * 100, "#") + "% effective)"

// ---------- Pane: z-score ----------
hline(0, "Zero", color = color.new(#71717a, 60), linestyle = hline.style_dotted)
hBandLo = hline(-0.5, "Strong band low", color = color.new(#34d399, 70), linestyle = hline.style_dotted)
hBandHi = hline(1.0, "Strong band high", color = color.new(#34d399, 70), linestyle = hline.style_dotted)
fill(hBandLo, hBandHi, color = color.new(#34d399, 94), title = "MARKUP STRONG_LONG z band")
plot(Z_BLOWOFF_ENG * vs, "Blow-off (regime)", color = color.new(#f87171, 40), style = plot.style_stepline)
plot(zTrim, "Trim", color = color.new(#fbbf24, 40), style = plot.style_stepline)
plot(Z_CAP * vs, "Capitulation", color = color.new(#c084fc, 40), style = plot.style_stepline)
plot(z, "Z-score", color = regCol, linewidth = 2)

// ---------- Price chart ----------
bgcolor(showBg and hasRegime ? color.new(regCol, 88) : na, title = "Regime", force_overlay = true)
plot(showBmsb ? wMid : na, "BMSB mid", color = color.new(#e4e4e7, 20), linewidth = 2, force_overlay = true)
plot(showBmsb ? wEma : na, "BMSB EMA21", color = color.new(#a1a1aa, 50), force_overlay = true)
plot(showBmsb ? wSma : na, "BMSB SMA20", color = color.new(#a1a1aa, 50), force_overlay = true)

// ---------- Setup: one position until it is upgraded or cancelled ----------
// Long grades rise REVIVAL_SEED < REVIVAL_SEED_CONFIRMED < ACCUMULATE < LIGHT_LONG < STRONG_LONG.
// An open long holds through WAIT and through equal or weaker long signals, is
// upgraded only by a stronger one, and closes only on an exit signal (TRIM,
// TRIM_HARD, RISK_OFF, NO_LONG) or an opposite LIGHT_SHORT. An open short
// closes when any long entry fires. Moves are close-to-close from the signal
// bar, with no stop, fees or funding: a read of the signal, not a trade result.
f_longRank(string s) =>
    switch s
        "REVIVAL_SEED" => 0
        "REVIVAL_SEED_CONFIRMED" => 1
        "ACCUMULATE" => 2
        "LIGHT_LONG" => 3
        "STRONG_LONG" => 4
        => -1

f_isExit(string s) =>
    s == "TRIM" or s == "TRIM_HARD" or s == "RISK_OFF" or s == "NO_LONG"

var string setup = "NONE"
var float entryPx = na
var int entryTime = na
string opened = ""
string upgraded = ""
string closedBy = ""
float closedMove = na
bool step = hasRegime and (not closedOnly or barstate.isconfirmed)
if step
    int rank = f_longRank(sig)
    if setup == "NONE"
        if rank >= 0 or sig == "LIGHT_SHORT"
            opened := sig
    else if f_longRank(setup) >= 0
        if f_isExit(sig) or sig == "LIGHT_SHORT"
            closedBy := sig
            closedMove := (close / entryPx - 1.0) * 100.0
            setup := "NONE"
            if sig == "LIGHT_SHORT"
                opened := sig
        else if rank > f_longRank(setup)
            upgraded := sig
            setup := sig
    else if rank >= 0
        closedBy := sig
        closedMove := (entryPx - close) / entryPx * 100.0
        setup := "NONE"
        opened := sig
    if opened != ""
        setup := opened
        entryPx := close
        entryTime := time

bool inLong = f_longRank(setup) >= 0
bool inShort = setup == "LIGHT_SHORT"
float openMove = inLong ? (close / entryPx - 1.0) * 100.0 : inShort ? (entryPx - close) / entryPx * 100.0 : na

f_open(string s) =>
    showSig and opened == s
f_up(string s) =>
    showSig and upgraded == s

plot(showSig and setup != "NONE" ? entryPx : na, "Setup entry price", color = inShort ? color.new(#fb923c, 30) : color.new(#34d399, 30), style = plot.style_linebr, force_overlay = true)
plotshape(f_open("STRONG_LONG"), "Open STRONG", shape.labelup, location.belowbar, color.new(#34d399, 0), text = "STRONG", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_open("LIGHT_LONG"), "Open LIGHT", shape.labelup, location.belowbar, color.new(#6ee7b7, 0), text = "LIGHT", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_open("ACCUMULATE"), "Open ACC", shape.labelup, location.belowbar, color.new(#97FCE4, 0), text = "ACC", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_open("REVIVAL_SEED"), "Open REV", shape.labelup, location.belowbar, color.new(#b8fff0, 0), text = "REV", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_open("REVIVAL_SEED_CONFIRMED"), "Open REV+", shape.labelup, location.belowbar, color.new(#b8fff0, 0), text = "REV+", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_open("LIGHT_SHORT"), "Open SHORT", shape.labeldown, location.abovebar, color.new(#fb923c, 0), text = "SHORT", textcolor = #09090b, size = size.tiny, force_overlay = true)
plotshape(f_up("STRONG_LONG"), "Upgrade to STRONG", shape.triangleup, location.belowbar, color.new(#34d399, 0), text = "UP STRONG", textcolor = #34d399, size = size.tiny, force_overlay = true)
plotshape(f_up("LIGHT_LONG"), "Upgrade to LIGHT", shape.triangleup, location.belowbar, color.new(#6ee7b7, 0), text = "UP LIGHT", textcolor = #6ee7b7, size = size.tiny, force_overlay = true)
plotshape(f_up("ACCUMULATE"), "Upgrade to ACC", shape.triangleup, location.belowbar, color.new(#97FCE4, 0), text = "UP ACC", textcolor = #97FCE4, size = size.tiny, force_overlay = true)
plotshape(f_up("REVIVAL_SEED_CONFIRMED"), "Upgrade to REV+", shape.triangleup, location.belowbar, color.new(#b8fff0, 0), text = "UP REV+", textcolor = #b8fff0, size = size.tiny, force_overlay = true)

if showSig and closedBy != ""
    string exitTxt = closedBy == "LIGHT_SHORT" ? "FLIP TO SHORT" : f_longRank(closedBy) >= 0 ? "SHORT CLOSED" : "EXIT " + closedBy
    string moveTxt = (closedMove >= 0 ? "+" : "") + str.tostring(closedMove, "#.#") + "%"
    label.new(bar_index, na, exitTxt + "\n" + moveTxt, yloc = f_longRank(closedBy) >= 0 ? yloc.belowbar : yloc.abovebar, style = f_longRank(closedBy) >= 0 ? label.style_label_up : label.style_label_down, color = closedMove >= 0 ? color.new(#34d399, 10) : color.new(#f87171, 10), textcolor = #09090b, size = size.tiny, force_overlay = true)

// Raw engine output, bar by bar (debug): every change of the synthesizer's label
bool isNew = sig != sig[1]
f_mark(string s) =>
    showRaw and step and isNew and sig == s

plotshape(f_mark("STRONG_LONG"), "Raw STRONG_LONG", shape.circle, location.bottom, color.new(#34d399, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("LIGHT_LONG"), "Raw LIGHT_LONG", shape.circle, location.bottom, color.new(#6ee7b7, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("ACCUMULATE"), "Raw ACCUMULATE", shape.circle, location.bottom, color.new(#97FCE4, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("REVIVAL_SEED") or f_mark("REVIVAL_SEED_CONFIRMED"), "Raw REVIVAL", shape.circle, location.bottom, color.new(#b8fff0, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("TRIM") or f_mark("TRIM_HARD"), "Raw TRIM", shape.circle, location.top, color.new(#fbbf24, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("RISK_OFF") or f_mark("NO_LONG"), "Raw RISK_OFF / NO_LONG", shape.circle, location.top, color.new(#ef4444, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("LIGHT_SHORT"), "Raw LIGHT_SHORT", shape.circle, location.top, color.new(#fb923c, 40), size = size.tiny, force_overlay = true)
plotshape(f_mark("WAIT"), "Raw WAIT", shape.xcross, location.bottom, color.new(#71717a, 50), size = size.tiny, force_overlay = true)

plotshape(showExh and absorption, "Absorption", shape.diamond, location.belowbar, color.new(#b8fff0, 20), size = size.auto, force_overlay = true)
plotshape(showExh and climax, "Climax", shape.triangleup, location.belowbar, color.new(#fbbf24, 10), size = size.tiny, force_overlay = true)
plotshape(showExh and floorOk and not floorOk[1], "Floor confirmed", shape.circle, location.belowbar, color.new(#34d399, 0), text = "FLOOR", textcolor = #34d399, size = size.tiny, force_overlay = true)

// ---------- Engine table ----------
f_pos(string p) =>
    switch p
        "top_left" => position.top_left
        "bottom_right" => position.bottom_right
        "bottom_left" => position.bottom_left
        => position.top_right

f_size(string s) =>
    switch s
        "tiny" => size.tiny
        "normal" => size.normal
        => size.small

f_sigCol(string s) =>
    switch s
        "STRONG_LONG" => #34d399
        "LIGHT_LONG" => #6ee7b7
        "ACCUMULATE" => #97FCE4
        "REVIVAL_SEED" => #b8fff0
        "REVIVAL_SEED_CONFIRMED" => #b8fff0
        "TRIM" => #fbbf24
        "TRIM_HARD" => #f87171
        "RISK_OFF" => #ef4444
        "NO_LONG" => #d8b4fe
        "LIGHT_SHORT" => #fb923c
        => #a1a1aa

var table tbl = table.new(f_pos(tblPos), 2, 24, bgcolor = color.new(#09090b, 8), border_color = color.new(#27272a, 0), border_width = 1, frame_color = color.new(#3f3f46, 0), frame_width = 1)

f_row(int r, string k, string v, color vc) =>
    table.cell(tbl, 0, r, k, text_color = #a1a1aa, text_size = f_size(tblSize), text_halign = text.align_left)
    table.cell(tbl, 1, r, v, text_color = vc, text_size = f_size(tblSize), text_halign = text.align_right)

f_check(int r, string k, bool ok) =>
    f_row(r, k, ok ? "PASS" : "FAIL", ok ? #34d399 : #f87171)

if showTbl and barstate.islast
    table.clear(tbl, 0, 0, 1, 23)
    string pendTxt = hasRegime and not na(pendReg) and pendReg != regime and pendCount > 0 ? "to " + array.get(REG_NAME, nz(pendReg)) + "  " + str.tostring(pendCount) + "/" + str.tostring(MIN_REGIME_BARS) : "none"
    string volTxt = (volHigh ? "HIGH" : volLow ? "LOW" : "MID") + "  x" + str.tostring(vs, "#.##")
    string heatTxt = str.tostring(heat) + "  " + heatPhase + (heatDir > 0 ? "  above BMSB" : heatDir < 0 ? "  below BMSB" : "")
    string sinceTxt = setup == "NONE" ? "no open setup" : str.format_time(entryTime, "yyyy-MM-dd HH:mm", syminfo.timezone) + "   " + (openMove >= 0 ? "+" : "") + str.tostring(openMove, "#.#") + "%"
    f_row(0, "RCCE  " + timeframe.period + "  setup", setup == "NONE" ? "none" : setup, f_sigCol(setup))
    f_row(1, "Open since", sinceTxt, setup == "NONE" ? #a1a1aa : openMove >= 0 ? #34d399 : #f87171)
    f_row(2, "Engine this bar", sig, f_sigCol(sig))
    f_row(3, "Why", why, #e4e4e7)
    f_row(4, "Regime", hasRegime ? regName + "  " + str.tostring(cf * 100, "#") + "%  " + array.get(REG_HINT, regIdx) : "FLAT", regCol)
    f_row(5, "Pending switch", pendTxt, #e4e4e7)
    f_row(6, "Z-score", str.tostring(zz, "#.##"), #e4e4e7)
    f_row(7, "Energy", str.tostring(nz(energy), "#.##"), #e4e4e7)
    f_row(8, "Volatility", volTxt, #e4e4e7)
    f_row(9, "Heat", heatTxt, heat >= 80 ? #fbbf24 : #e4e4e7)
    f_row(10, "Exhaustion", exhState, exhState == "NEUTRAL" ? #e4e4e7 : #b8fff0)
    f_row(11, "BTC divergence", divergence == "" ? "none" : divergence, bearDiv ? #f87171 : divergence == "BULL-DIV" ? #34d399 : #e4e4e7)
    f_row(12, "Regime changes 7d", str.tostring(changes7d) + (unstable ? "  (chop)" : ""), unstable ? #fbbf24 : #e4e4e7)
    f_row(13, "Checks", str.tostring(coreMet) + "/9   effective " + str.tostring(effPct * 100, "#") + "%", effPct >= 0.80 ? #34d399 : effPct >= 0.55 ? #fbbf24 : #a1a1aa)
    if showChk
        f_check(14, "  Regime MARKUP/ACCUM", c1)
        f_check(15, "  Consensus " + consIn, c2)
        f_check(16, "  Z in -0.5 .. 2.5", c3)
        f_check(17, "  No bear divergence", c4)
        f_check(18, "  Heat < " + str.tostring(heatBlock), c5)
        f_check(19, "  No climax", c6)
        f_check(20, "  Funding " + fundIn, c7)
        f_check(21, "  Fear & Greed " + str.tostring(fgIn) + " < 70", c8)
        f_check(22, "  Stablecoins " + stabIn, c9)

// ---------- Alerts ----------
alertcondition(opened != "", "Setup opened", "RCCE: setup opened on {{ticker}} {{interval}}")
alertcondition(upgraded != "", "Setup upgraded", "RCCE: setup upgraded on {{ticker}} {{interval}}")
alertcondition(closedBy != "", "Setup closed", "RCCE: setup closed on {{ticker}} {{interval}}")
alertcondition(hasRegime and regime != regime[1], "RCCE regime change", "RCCE: regime changed on {{ticker}} {{interval}}")

Overview

Reflex RCCE - Engine View reproduces a Z-score regime engine, a weekly midline heat phase, absorption and climax markers, nine core checks and a final signal tree, plus an optional divergence check against BTC. Market consensus, Fear and Greed, funding and stablecoin context are set by hand in the inputs. Options toggle the background, markers and table, and setup changes can be limited to closed bars.

Details

Published by

cianfru on GitHub

Draws

Separate pane below the chart

Markets

Crypto

Timeframes

Any timeframe

Risk Notes

  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Market consensusstringMIXEDconsIn
Fear & Greedint50fgIn
Funding regimestringNEUTRALfundIn
Stablecoin supplystringSTABLEstabIn
BTC (for divergence)symbolBINANCE:BTCUSDTbtcSym
Check BTC divergencebooltrueuseDiv
Regime background on pricebooltrueshowBg
Weekly BMSB band on pricebooltrueshowBmsb
Setup markers on price (open / upgrade / exit)booltrueshowSig
Raw engine signal changes (debug)boolfalseshowRaw
Absorption / climax / floor markersbooltrueshowExh
Engine tablebooltrueshowTbl
Show all 16 settings
SettingTypeDefaultVariable
Include the 9 checks in the tablebooltrueshowChk
Table positionstringtop_righttblPos
Table textstringsmalltblSize
Setup changes on closed bars onlybooltrueclosedOnly
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Trend Compass 15m

by chris-c-thomas
14 stars

Trend Compass 15m is an intraday trend analysis overlay designed for 15-minute charts. It calculates a triple exponential moving average ribbon, higher-timeframe reference EMAs from 1H, 4H, and Daily periods, RSI and MACD divergences, On-Balance Volume trends,

Indicator v6 TrendMoving averages Repaints
Updated 6 months ago · MIT GitHub repository of Trend Compass 15m

Adaptive Fair Value Cloud calculates a volatility-adaptive fair value channel around a selectable centerline, such as KAMA, EMA, linear regression, or VWMA. It blends ATR and mean deviation with volatility percentiles and trend sensors, including ADX, Efficien

Indicator v6 Volatility & bandsTrend
Updated 2 days ago · MIT GitHub repository of Adaptive Fair Value Cloud [WavesUnchained]

Kernal Cipher 1

by kdricha0602
1 stars

A large price-chart overlay that combines many filters into tagged signal markers. It uses a 21, 50 and 200 EMA stack with slope, a higher-timeframe reference, Supertrend, ADX regime, WaveTrend, StochRSI, regular and hidden divergence, relative strength agains

Indicator v6 TrendOscillators & momentum
Updated 5 weeks ago · MIT GitHub repository of Kernal Cipher 1

This indicator scans a pasted list of symbols for RSI directional momentum and shows matching long and short signals in a table in a separate pane. The user chooses continuous break, continuous retracement, flip break, flip retracement, divergence, or hidden d

Indicator v6 Oscillators & momentumDivergence
Updated 1 year ago · MPL-2.0 GitHub repository of Momentum Setup - RSI Directional Momentum Scanner
228 stars

Multi-Timeframe Analysis Suite calculates trend direction and momentum conditions across five user-selected timeframes using moving averages, RSI, and Stochastic oscillators. It evaluates moving average slope and oscillator levels to compute trend alignment, m

Indicator v6 Screeners & dashboardsTrend
Updated 3 months ago · None stated GitHub repository of Multi-Timeframe Analysis Suite

KamaFama

by Mastaaa1987
141 stars

KamaFama is an indicator that translates a Freqtrade trading strategy into Pine Script for visualization. It combines Kaufman Adaptive Moving Average (KAMA), MAMA/FAMA calculations derived via Hilbert Transform, Williams %R, and correlation trend filters to ev

Indicator v6 Moving averagesOscillators & momentum
Updated 6 weeks ago · MIT GitHub repository of KamaFama

More Trend scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers