Quantum Breakout AI - AnkeAlgo's Pine v6 indicator

Description

Quantum Breakout AI — Community Description Quantum Breakout AI is an institutional-grade breakout detection system that combines volatility compression analysis, multi-factor scoring, and automated trade management into a single indicator. Ported from AnkeAlgo's Pine v6 release to the SXVNT SDK. What it does The script hunts for high-probability breakouts by waiting for the market to coil — measured as ATR-normalized range compression — and then grading every breakout candidate across four independent scoring axes before drawing a signal. Each accepted breakout auto-projects its full trade plan (entry, stop, three targets) and the running stats table tracks how the system is actually performing on your chart. Key features ATR compression engine — detects when recent bar ranges have compressed below a configurable multiple of ATR, the precondition for explosive expansion Power score — measures breakout candle strength relative to surrounding volatility Whale score — volume-based confirmation looking for unusual participation on the trigger bar Lifecycle score — tracks how long the compression has been building (longer coils = stronger releases) Quality score — composite filter that gates whether a breakout is plotted at all Directional bias analysis — reads recent structure to weight long vs short setups Automatic risk model — SL placed at structural invalidation, TP1 at 1R, TP2 at 1.5R, TP3 at 2R Energy bar — visual gauge showing real-time compression buildup so you can see a setup forming before it triggers Breakout arrows — clean directional markers (▲ long / ▼ short) at the trigger bar Live stats table — tracks wins, losses, win rate, and average R-multiple across the chart ~30 configurable inputs — every threshold, multiplier, length, and color is tunable How to use Add the indicator to a chart and let it scan a few sessions of history Watch the energy bar — when it fills toward the top, compression is high and a breakout is imminent When the arrow prints, the SL / TP1 / TP2 / TP3 levels are drawn automatically Use the stats table to gauge whether the current settings are profitable for the instrument and timeframe you're trading Tune the quality score threshold higher for fewer/cleaner signals, lower for more setups Math Compression is measured as range(N) / ATR(N) — when this ratio drops below your threshold, the market is statistically quiet relative to its own recent volatility. The four scores combine into a composite confidence value that must clear the quality gate before a signal fires. R-multiples are computed live so the stats table reflects realized performance, not hypothetical fills. Best on liquid futures (ES, NQ, CL, GC) on 1m–15m timeframes. Pairs well with VWAP bands and session anchors for confluence.

Categories & Tags

Comments (0)

0/2000

Loading comments…

Source code

// Quantum Breakout AI — SXVNT port of AnkeAlgo's Pine v6 indicator
//
// Detects ATR-compressed consolidation ranges, scores them by power /
// whale activity / lifecycle / directional bias, then maps confirmed
// breakouts to SL + 1R/1.5R/2R targets. Tracks per-trade stats for
// the on-chart stats table.

function calculate(bars, ctx) {
  // ─── INPUTS ─────────────────────────────────────────────────────
  // Core
  const showBreakoutArrows = ctx.input('Breakout Arrows', true);
  const showDirection      = ctx.input('Direction Marker', true);
  const showEnergyBar      = ctx.input('Energy Bar', true);
  const showEnergyPercent  = ctx.input('Show Energy %', true);
  const showSLTP           = ctx.input('SL/TP', true);
  const slAtrMult          = ctx.input('SL ATR Mult', 0.5, { min: 0.1, max: 2.0, step: 0.1 });

  // Detection
  const atrPeriod       = ctx.input('ATR Period', 14, { min: 5, max: 50, step: 1 });
  const rangeATRMult    = ctx.input('Range ATR Mult', 2.5, { min: 1.0, max: 5.0, step: 0.1 });
  const minBarsInRange  = ctx.input('Min Bars In Range', 15, { min: 5, max: 100, step: 1 });

  // Targets
  const showTP2 = ctx.input('Show TP2 (1.5R)', true);
  const showTP3 = ctx.input('Show TP3 (2R)', true);
  const slColor = ctx.input('SL Color', '#FF6D00');
  const tpColor = ctx.input('TP Color', '#00BFA5');

  // Energy
  const energyHighThresh     = ctx.input('Energy High Threshold', 60.0, { min: 30, max: 80, step: 1 });
  const energyCriticalThresh = ctx.input('Energy Critical Threshold', 80.0, { min: 50, max: 100, step: 1 });

  // Stats
  const showStatsTable   = ctx.input('Show Stats Table', true);
  const statsRangePreset = ctx.input('Stats Range', 'Last 90 Days', {
    options: ['All', 'Last 30 Days', 'Last 90 Days', 'Last 180 Days', 'Year 2025']
  });

  // Advanced
  const maxDisplayBars   = ctx.input('Max Lookback Bars', 2000, { min: 300, max: 20000, step: 100 });
  const maxZonesToDraw   = ctx.input('Max Drawn Zones', 400, { min: 50, max: 500, step: 10 });
  const activeExtendBars = ctx.input('Active Extend Bars', 5, { min: 0, max: 100, step: 1 });
  const volAnomalyMult   = ctx.input('Volume Anomaly Multiplier', 2.0, { min: 1.5, max: 4.0, step: 0.1 });
  const dirConfidenceMin = ctx.input('Min Confidence %', 55.0, { min: 50, max: 90, step: 1 });

  // Colors
  const bullColor       = ctx.input('Bullish Color', '#00E676');
  const bearColor       = ctx.input('Bearish Color', '#FF5252');
  const neutralColor    = ctx.input('Neutral Color', '#9E9E9E');
  const boxMainColor    = ctx.input('Box Main Color', '#00E5FF');
  const energyLowColor  = ctx.input('Energy Low Color',     '#4CAF50');
  const energyMedColor  = ctx.input('Energy Medium Color',  '#2979FF');
  const energyHighColor = ctx.input('Energy High Color',    '#AA00FF');
  const energyCritColor = ctx.input('Energy Critical Color','#F44336');

  // ─── CONSTANTS ──────────────────────────────────────────────────
  const tp1Ratio = 1.0, tp2Ratio = 1.5, tp3Ratio = 2.0;
  const PHASE_FORMING = 'Forming', PHASE_GROWTH = 'Growth',
        PHASE_MATURE  = 'Mature',  PHASE_EXHAUSTION = 'Exhaustion';
  const DIR_BULLISH = 'Bullish', DIR_BEARISH = 'Bearish', DIR_NEUTRAL = 'Neutral';

  // ─── PRICE / VOLUME / TA ────────────────────────────────────────
  const high   = ctx.price.high;
  const low    = ctx.price.low;
  const close  = ctx.price.close;
  const volume = ctx.price.volume;
  const n = bars.length;

  // ATR signature in this SDK: (high, low, close, period) — NOT (period).
  const atrArr = ctx.ta.atr(high, low, close, atrPeriod);
  const avgVolArr = ctx.ta.sma(volume, 20);

  // ─── HELPERS ────────────────────────────────────────────────────
  function highestN(arr, period, idx) {
    let h = -Infinity;
    const start = Math.max(0, idx - period + 1);
    for (let j = start; j <= idx; j++) if (arr[j] > h) h = arr[j];
    return h;
  }
  function lowestN(arr, period, idx) {
    let l = Infinity;
    const start = Math.max(0, idx - period + 1);
    for (let j = start; j <= idx; j++) if (arr[j] < l) l = arr[j];
    return l;
  }
  function clamp(v, lo, hi) { return Math.max(lo, Math.min(hi, v)); }

  function computeCompressionScore(dur, h, vol) {
    if (h <= 0 || vol <= 0 || dur <= 0) return 0;
    const squeezeRatio = vol / h;
    const squeezeScore = Math.min(squeezeRatio * 45, 40);
    const durationScore = Math.min(dur * 2, 35);
    const ageBonus = dur >= 30 ? 15 : dur >= 20 ? 10 : dur >= 15 ? 5 : 0;
    const tightBonus = h < vol * 0.5 ? 10 : h < vol * 0.75 ? 5 : 0;
    return clamp(squeezeScore + durationScore + ageBonus + tightBonus, 5, 100);
  }

  function getVolumeWeightedMean(upper, lower, t1, t2) {
    let sumPV = 0, sumV = 0;
    const len = Math.min(t2 - t1, 500);
    for (let j = t2 - len; j <= t2; j++) {
      if (j < 0 || j >= n) continue;
      const mp = (high[j] + low[j] + close[j]) / 3;
      if (mp <= upper && mp >= lower) { sumPV += mp * volume[j]; sumV += volume[j]; }
    }
    return sumV > 0 ? sumPV / sumV : (upper + lower) / 2;
  }

  function getRejectionCount(lvl, tol, t1, t2, checkHigh) {
    let cnt = 0;
    const len = Math.min(t2 - t1, 500);
    for (let j = t2 - len; j <= t2; j++) {
      if (j < 0 || j >= n) continue;
      const isTouch = checkHigh
        ? (high[j] >= lvl - tol && high[j] <= lvl + tol)
        : (low[j]  >= lvl - tol && low[j]  <= lvl + tol);
      const isWick = checkHigh ? (close[j] < high[j] - tol) : (close[j] > low[j] + tol);
      if (isTouch && isWick) cnt++;
    }
    return cnt;
  }

  function analyzeBreakoutBias(vwap, upper, lower, topRej, btmRej) {
    const h = upper - lower;
    const mid = (upper + lower) / 2;
    const volBias  = (vwap - mid) / (h / 2);
    const wickBias = (topRej > 0 || btmRej > 0) ? (btmRej - topRej) / Math.max(topRej + btmRej, 1) : 0;
    const totalBias = volBias * 0.55 + wickBias * 0.45;
    const conf = Math.abs(totalBias) * 100;
    const dir = totalBias > 0.1 ? DIR_BULLISH : totalBias < -0.1 ? DIR_BEARISH : DIR_NEUTRAL;
    return { dir, conf: Math.min(conf + 50, 100) };
  }

  function scanWhaleActivity(t1, t2, upper, lower, avgVol) {
    let spikes = 0, spikeVol = 0;
    const len = Math.min(t2 - t1, 500);
    let counted = 0;
    for (let j = t2 - len; j <= t2; j++) {
      if (j < 0 || j >= n) continue;
      counted++;
      if (high[j] <= upper && low[j] >= lower && volume[j] > avgVol * volAnomalyMult) {
        spikes++;
        spikeVol += volume[j];
      }
    }
    const spikeRatio = counted > 0 ? (spikes / counted) * 100 : 0;
    const intensity  = (avgVol > 0 && spikes > 0) ? spikeVol / (avgVol * spikes) : 0;
    return Math.min(spikeRatio * 0.6 + Math.min(intensity * 8, 50), 100);
  }

  function determineLifecycle(dur) {
    return dur < 10 ? PHASE_FORMING : dur < 25 ? PHASE_GROWTH : dur < 50 ? PHASE_MATURE : PHASE_EXHAUSTION;
  }

  function evaluateZoneQuality(pwr, whale, cycle, conf) {
    const cycleVal = cycle === PHASE_FORMING ? 20 : cycle === PHASE_GROWTH ? 50
                   : cycle === PHASE_MATURE ? 80 : cycle === PHASE_EXHAUSTION ? 60 : 50;
    return Math.min(pwr * 0.35 + whale * 0.2 + cycleVal * 0.25 + conf * 0.2, 100);
  }

  function getEnergyColor(e) {
    return e >= energyCriticalThresh ? energyCritColor
         : e >= energyHighThresh ? energyHighColor
         : e >= 40 ? energyMedColor : energyLowColor;
  }

  function withAlpha(hex, a) {
    const h = hex.replace('#', '');
    const r = parseInt(h.slice(0, 2), 16);
    const g = parseInt(h.slice(2, 4), 16);
    const b = parseInt(h.slice(4, 6), 16);
    return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
  }

  // ─── SINGLE PASS: detect ranges → form zones → fire breakouts ──
  const zones = [];
  const trades = [];
  let rangeHigh = null, rangeLow = null, rangeStartBar = null, barsInRange = 0;
  let currentZone = null;
  let activeTrade = null;

  for (let i = 0; i < n; i++) {
    const a = atrArr[i] || 0;
    const avgV = avgVolArr[i] || 0;
    if (!a || !isFinite(a)) continue;

    const lookHi = highestN(high, 5, i);
    const lookLo = lowestN(low, 5, i);
    const compressed = (lookHi - lookLo) < a * rangeATRMult;

    if (compressed) {
      if (rangeHigh === null) {
        rangeHigh = lookHi;
        rangeLow  = lookLo;
        rangeStartBar = Math.max(0, i - 4);
        barsInRange = 5;
      } else if (high[i] <= rangeHigh + a * 0.1 && low[i] >= rangeLow - a * 0.1) {
        rangeHigh = Math.max(rangeHigh, high[i]);
        rangeLow  = Math.min(rangeLow,  low[i]);
        barsInRange++;
      } else {
        rangeHigh = null; rangeLow = null; barsInRange = 0;
      }
    } else {
      if (rangeHigh !== null && barsInRange >= minBarsInRange && currentZone) {
        currentZone.isLive = false;
        currentZone.endIdx = i - 1;
      }
      rangeHigh = null; rangeLow = null; barsInRange = 0;
    }

    if (barsInRange === minBarsInRange && rangeHigh !== null) {
      if (currentZone) currentZone.isLive = false;
      currentZone = {
        startIdx: rangeStartBar, endIdx: i,
        upperLevel: rangeHigh, lowerLevel: rangeLow,
        isLive: true, isBreached: false, breakSide: '',
        powerScore: 0, vwapLevel: 0,
        topRejections: 0, btmRejections: 0,
        whaleActivity: 0, lifeCycle: PHASE_FORMING,
        biasDir: DIR_NEUTRAL, biasStrength: 0, qualityScore: 0,
        entryPx: null, stopPx: null,
        tp1: null, tp2: null, tp3: null,
        labelY: null,
      };
      zones.push(currentZone);
    }

    if (currentZone && currentZone.isLive) {
      const dur = i - currentZone.startIdx;
      const rangeH = currentZone.upperLevel - currentZone.lowerLevel;
      const tol = rangeH * 0.1;
      if (high[i] <= currentZone.upperLevel + tol && low[i] >= currentZone.lowerLevel - tol) {
        currentZone.endIdx = i;
        currentZone.powerScore   = computeCompressionScore(dur, rangeH, a);
        currentZone.vwapLevel    = getVolumeWeightedMean(currentZone.upperLevel, currentZone.lowerLevel, currentZone.startIdx, i);
        currentZone.topRejections= getRejectionCount(currentZone.upperLevel, tol, currentZone.startIdx, i, true);
        currentZone.btmRejections= getRejectionCount(currentZone.lowerLevel, tol, currentZone.startIdx, i, false);
        currentZone.whaleActivity= scanWhaleActivity(currentZone.startIdx, i, currentZone.upperLevel, currentZone.lowerLevel, avgV);
        currentZone.lifeCycle    = determineLifecycle(dur);
        const bias = analyzeBreakoutBias(currentZone.vwapLevel, currentZone.upperLevel, currentZone.lowerLevel, currentZone.topRejections, currentZone.btmRejections);
        currentZone.biasDir      = bias.dir;
        currentZone.biasStrength = bias.conf;
        currentZone.qualityScore = evaluateZoneQuality(currentZone.powerScore, currentZone.whaleActivity, currentZone.lifeCycle, currentZone.biasStrength);
      }
    }

    if (currentZone && currentZone.isLive) {
      const up = close[i] > currentZone.upperLevel;
      const dn = close[i] < currentZone.lowerLevel;
      if (up || dn) {
        currentZone.isLive = false;
        currentZone.isBreached = true;
        currentZone.breakSide = up ? DIR_BULLISH : DIR_BEARISH;
        currentZone.endIdx = i;

        const buf = a * slAtrMult;
        if (up) {
          currentZone.entryPx = currentZone.upperLevel;
          currentZone.stopPx  = currentZone.lowerLevel - buf;
          const risk = currentZone.entryPx - currentZone.stopPx;
          currentZone.tp1 = currentZone.entryPx + risk * tp1Ratio;
          currentZone.tp2 = currentZone.entryPx + risk * tp2Ratio;
          currentZone.tp3 = currentZone.entryPx + risk * tp3Ratio;
        } else {
          currentZone.entryPx = currentZone.lowerLevel;
          currentZone.stopPx  = currentZone.upperLevel + buf;
          const risk = currentZone.stopPx - currentZone.entryPx;
          currentZone.tp1 = currentZone.entryPx - risk * tp1Ratio;
          currentZone.tp2 = currentZone.entryPx - risk * tp2Ratio;
          currentZone.tp3 = currentZone.entryPx - risk * tp3Ratio;
        }

        if (showDirection && currentZone.biasDir === currentZone.breakSide && currentZone.biasStrength >= dirConfidenceMin) {
          const rangeH = currentZone.upperLevel - currentZone.lowerLevel;
          currentZone.labelY = up ? currentZone.lowerLevel - rangeH * 0.5 - a * 0.1
                                  : currentZone.stopPx + a * 0.2;
        }

        activeTrade = {
          entryBar: i, entryTime: bars[i].timestamp,
          isLong: up, entry: currentZone.entryPx,
          sl: currentZone.stopPx,
          tp1: currentZone.tp1, tp2: currentZone.tp2, tp3: currentZone.tp3,
          status: 0, exitBar: null, exitTime: null,
        };
        trades.push(activeTrade);
      }
    }

    if (activeTrade && activeTrade.status === 0 && i > activeTrade.entryBar) {
      const slHit = activeTrade.isLong ? low[i] <= activeTrade.sl : high[i] >= activeTrade.sl;
      const finalTP = showTP3 ? activeTrade.tp3 : showTP2 ? activeTrade.tp2 : activeTrade.tp1;
      const finalHit = activeTrade.isLong ? high[i] >= finalTP : low[i] <= finalTP;
      if (slHit) {
        activeTrade.status = -1;
        activeTrade.exitBar = i; activeTrade.exitTime = bars[i].timestamp;
        activeTrade = null;
      } else if (finalHit) {
        activeTrade.status = 1;
        activeTrade.exitBar = i; activeTrade.exitTime = bars[i].timestamp;
        activeTrade = null;
      }
    }
  }

  // ─── RENDERING ──────────────────────────────────────────────────
  const lastBar = n - 1;
  const zonesToDraw = zones.slice(-maxZonesToDraw);

  let lastBreachedSltp = null;

  for (const z of zonesToDraw) {
    if (lastBar - z.startIdx > maxDisplayBars) continue;
    const rightBar = z.isLive ? lastBar + activeExtendBars : z.endIdx;

    const h = z.upperLevel - z.lowerLevel;
    const shadowOff = h * 0.05;
    ctx.box(z.startIdx, z.upperLevel - shadowOff, rightBar, z.lowerLevel - shadowOff, {
      borderColor: 'rgba(0,0,0,0)',
      borderWidth: 0,
      fillColor: 'rgba(0,0,0,0.4)',
    });
    ctx.box(z.startIdx, z.upperLevel, rightBar, z.lowerLevel, {
      borderColor: boxMainColor,
      borderWidth: 1,
      fillColor: withAlpha(boxMainColor, 0.15),
    });

    if (showEnergyBar) {
      const rangeH = z.upperLevel - z.lowerLevel;
      const barH = rangeH * 0.25;
      const barBot = z.lowerLevel - barH * 2;
      const barTop = barBot + barH;
      const widthBars = rightBar - z.startIdx;
      const filledWidth = Math.round(widthBars * (z.powerScore / 100));
      ctx.box(z.startIdx, barTop, rightBar, barBot, {
        borderColor: 'rgba(158,158,158,0.5)',
        borderWidth: 1,
        fillColor: 'rgba(0,0,0,0.8)',
      });
      if (filledWidth > 0) {
        const eColor = getEnergyColor(z.powerScore);
        ctx.box(z.startIdx, barTop, z.startIdx + filledWidth, barBot, {
          borderColor: 'rgba(0,0,0,0)',
          borderWidth: 0,
          fillColor: withAlpha(eColor, 0.8),
        });
      }
      if (showEnergyPercent) {
        ctx.label(Math.round((z.startIdx + rightBar) / 2), (barTop + barBot) / 2,
          z.powerScore.toFixed(0) + '%',
          { color: 'rgba(0,0,0,0)', textColor: '#FFFFFF' });
      }
    }

    if (z.labelY != null) {
      const mid = Math.round((z.startIdx + z.endIdx) / 2);
      const txt = z.breakSide === DIR_BULLISH ? 'B' : 'S';
      const c = z.breakSide === DIR_BULLISH ? bullColor : bearColor;
      ctx.label(mid, z.labelY, txt, { color: withAlpha(c, 0.2), textColor: c });
    }

    if (z.isBreached) lastBreachedSltp = z;
  }

  if (showSLTP && lastBreachedSltp) {
    const z = lastBreachedSltp;
    const left = z.startIdx;
    const right = activeTrade ? lastBar : (lastBreachedSltp === zones[zones.length - 1] ? lastBar : z.endIdx + 30);

    ctx.line(left, z.entryPx, right, z.entryPx, {
      color: 'rgba(255,255,255,0.5)', lineWidth: 1, lineStyle: 'dashed',
    });
    ctx.line(left, z.stopPx, right, z.stopPx, {
      color: slColor, lineWidth: 2, lineStyle: 'solid',
    });
    ctx.label(left, z.stopPx, 'SL ' + z.stopPx.toFixed(2), { color: 'rgba(0,0,0,0)', textColor: slColor });

    ctx.line(left, z.tp1, right, z.tp1, {
      color: withAlpha(tpColor, 0.7), lineWidth: 1, lineStyle: 'dashed',
    });
    ctx.label(left, z.tp1, 'TP1 ' + z.tp1.toFixed(2), { color: 'rgba(0,0,0,0)', textColor: tpColor });

    if (showTP2) {
      ctx.line(left, z.tp2, right, z.tp2, {
        color: withAlpha(tpColor, 0.8), lineWidth: 1, lineStyle: 'dashed',
      });
      ctx.label(left, z.tp2, 'TP2 ' + z.tp2.toFixed(2), { color: 'rgba(0,0,0,0)', textColor: tpColor });
    }
    if (showTP3) {
      ctx.line(left, z.tp3, right, z.tp3, {
        color: tpColor, lineWidth: 2, lineStyle: 'solid',
      });
      ctx.label(left, z.tp3, 'TP3 ' + z.tp3.toFixed(2), { color: 'rgba(0,0,0,0)', textColor: tpColor });
    }
  }

  if (showBreakoutArrows && lastBreachedSltp && lastBreachedSltp.endIdx >= n - 5) {
    const z = lastBreachedSltp;
    if (z.breakSide === DIR_BULLISH) {
      const rangeH = z.upperLevel - z.lowerLevel;
      const arrowY = z.lowerLevel - rangeH * 0.5 - rangeH * 0.1;
      ctx.shape(z.endIdx, 'arrow_up', { position: 'absolute', price: arrowY, color: bullColor });
    } else {
      const a = atrArr[z.endIdx] || 0;
      const arrowY = z.stopPx + a * 0.2;
      ctx.shape(z.endIdx, 'arrow_down', { position: 'absolute', price: arrowY, color: bearColor });
    }
  }

  // ─── STATS TABLE ────────────────────────────────────────────────
  if (showStatsTable) {
    const lastTs = bars[lastBar].timestamp;
    const DAY = 86400000;
    let startT = 0, endT = lastTs;
    if (statsRangePreset === 'Last 30 Days')      startT = lastTs - 30 * DAY;
    else if (statsRangePreset === 'Last 90 Days') startT = lastTs - 90 * DAY;
    else if (statsRangePreset === 'Last 180 Days')startT = lastTs - 180 * DAY;
    else if (statsRangePreset === 'Year 2025') {
      startT = new Date(2025, 0, 1).getTime();
      endT   = new Date(2025, 11, 31, 23, 59).getTime();
    }

    let total = 0, longs = 0, shorts = 0, wins = 0, losses = 0, equity = 1.0;
    for (const t of trades) {
      if (t.entryTime < startT || t.entryTime > endT) continue;
      total++;
      if (t.isLong) longs++; else shorts++;
      if (t.status === 1) {
        wins++;
        const tpFinal = showTP3 ? t.tp3 : showTP2 ? t.tp2 : t.tp1;
        const pct = t.isLong ? (tpFinal - t.entry) / t.entry : (t.entry - tpFinal) / t.entry;
        equity *= (1 + pct);
      } else if (t.status === -1) {
        losses++;
        const pct = t.isLong ? (t.sl - t.entry) / t.entry : (t.entry - t.sl) / t.entry;
        equity *= (1 + pct);
      }
    }
    const closed = wins + losses;
    const totalReturn = closed > 0 ? (equity - 1) * 100 : null;
    const winRate = closed > 0 ? wins / closed * 100 : null;

    ctx.table('top_right', {
      bgColor: 'rgba(11,16,32,0.9)',
      borderColor: '#00E5FF',
    });
    const titleBg = '#131A2A';
    const rowBgA = '#0B1020', rowBgB = '#0E1630';
    ctx.cell(0, 0, 'Quantum Breakout', { textColor: '#FFFFFF', bgColor: titleBg, colspan: 2 });
    ctx.cell(0, 1, 'Total Orders',  { bgColor: rowBgA, textColor: '#FFFFFF' });
    ctx.cell(1, 1, String(total),   { bgColor: rowBgA, textColor: '#00E5FF' });
    ctx.cell(0, 2, 'Long Orders',   { bgColor: rowBgB, textColor: '#FFFFFF' });
    ctx.cell(1, 2, String(longs),   { bgColor: rowBgB, textColor: bullColor });
    ctx.cell(0, 3, 'Short Orders',  { bgColor: rowBgA, textColor: '#FFFFFF' });
    ctx.cell(1, 3, String(shorts),  { bgColor: rowBgA, textColor: bearColor });
    ctx.cell(0, 4, 'TP Wins',       { bgColor: rowBgB, textColor: '#FFFFFF' });
    ctx.cell(1, 4, String(wins),    { bgColor: rowBgB, textColor: '#00E676' });
    ctx.cell(0, 5, 'Stop Losses',   { bgColor: rowBgA, textColor: '#FFFFFF' });
    ctx.cell(1, 5, String(losses),  { bgColor: rowBgA, textColor: '#FF5252' });
    ctx.cell(0, 6, 'Total Return',  { bgColor: rowBgB, textColor: '#FFFFFF' });
    ctx.cell(1, 6,
      totalReturn == null ? 'n/a' : totalReturn.toFixed(2) + '%',
      { bgColor: rowBgB, textColor: totalReturn != null && totalReturn >= 0 ? '#00E676' : '#FF5252' });
    ctx.cell(0, 7, 'Win Rate',      { bgColor: rowBgA, textColor: '#FFFFFF' });
    ctx.cell(1, 7,
      winRate == null ? 'n/a' : winRate.toFixed(2) + '%',
      { bgColor: rowBgA, textColor: '#00E676' });
  }

  if (currentZone && currentZone.isLive && currentZone.qualityScore >= 70 &&
      currentZone.powerScore >= energyCriticalThresh) {
    ctx.log('[Quantum] Imminent breakout — energy ' + currentZone.powerScore.toFixed(0) + '%');
  }
}