Iván González

CCI Master: +100 and −100 Drawn as Prices on the Chart

Category: Indicators By: Iván González Created: November 4, 2026, 1:46 PM
November 4, 2026, 1:46 PM
Indicators
0 Comments
CCI Master: +100 and −100 Drawn as Prices on the Chart

Introduction

 

A CCI reading of 85 says price is stretched, but not how far it still has to go before the classic +100 signal. That is a price, and it belongs on the price chart.

CCI Master draws it there. The CCI can be solved backwards: knowing the last 19 typical prices, there is exactly one value for the next bar that puts the CCI at +100, and one that puts it at −100. Those prices are the edges of an overbought zone above price and an oversold zone below it, so the distance to each zone is the room price has before the CCI signals. It follows the idea of RSI Master, which does the same with the RSI, and keeps its look.

Theory Behind the Indicator

 

The CCI. CCI = (typical price − its 20-bar mean) / (0.015 × the mean absolute deviation over the same 20 bars), with typical price = (high + low + close) / 3.

Turned into a price. Tomorrow’s window holds the last 19 values and tomorrow’s. Written in terms of tomorrow’s mean, the equation “CCI = 100” is linear between consecutive window values and always rising, so it has exactly one answer: the indicator checks how many of the 19 values fall below it and solves that piece exactly, with no approximation and no search. The same gives −100, and the midline (CCI 0) is just the mean of the 19 values that stay. The edges are smoothed with a 3-bar EMA.

Typical price or close. The classic CCI uses the typical price, so the edges are the typical price the next bar needs. A bar that closes at its high needs a close a third of its range above the edge; a bar that closes mid-range, about the edge itself. Set the source to the close and the edges are exact closes.

A ceiling. A CCI can never go past length / 0.03 in either direction: about 667 with 20 bars, 167 with 5. A level beyond the ceiling has no edge and its zone is not drawn.

The zones, the candles, the dots and the arrows. The overbought zone glows from its edge upwards and fades out 2.2 ATR above it; the oversold zone does the same downwards. Candles stay a soft grey through the middle of the range, warm toward the overbought colour from CCI 30 to 100 and cool toward the oversold colour from −30 to −100. A dot marks the first close into a zone, an arrow the exit. Both are drawn once the bar has closed.

Key Features at a Glance

 

  • +100 and −100 computed as prices, solved exactly from the CCI formula
  • Typical price (classic CCI) or close as source
  • Glowing zones with adjustable depth and brightness
  • Candles that warm and cool with the CCI
  • Entry dots and exit arrows, drawn on closed bars
  • Five themes: Neon, Classic, Aurora, Ice and Custom

How to Read the Indicator

 

  • Between the bands: the distance to each edge is the room price has before the CCI signals. Compare it with the ATR: half an ATR is one ordinary bar away.
  • Inside a band: the CCI is above +100 (or below −100). The edge is now the price that would take it back out.
  • The candles: a warm candle is a CCI on its way to +100, a cool one a CCI on its way to −100.
  • Dots and arrows: a dot is the first close into a zone; an arrow is the close back out of it.

Practical Applications

 

  • Breakout entries: the classic CCI buy is a close above +100. The overbought edge is the level to watch before the bar that does it.
  • Mean reversion: the exit arrow out of a band is the classic CCI return signal, and the opposite edge a live target.
  • Stops: the far side of a band shows how much room the CCI still allows before the move turns extreme.

Indicator Configuration

 

CCI

  • lenIn (default 20, 3 to 100): CCI length.
  • srcIn (default 1): 1 = typical price, the classic CCI; 2 = close.
  • obIn (default 100) and osIn (default −100): overbought and oversold levels.
  • smIn (default 3, 1 to 10): smoothing of the zone edges, in bars.

Look

  • themeIn (default 1): 1 = Neon, 2 = Classic, 3 = Aurora, 4 = Ice, 5 = Custom with the colours cuOs and cuOb.
  • bright (default 3, 1 to 5): brightness of the zones and halos.
  • depthIn (default 2.2, 0.5 to 6): how far the zone glow reaches past its edge, in ATRs.
  • showCandles (default 1), showMid (default 0), showDots (default 1), showTurns (default 1): CCI candles, midline (CCI 0), entry dots and exit arrows.

The Code

 

//-----------------------------------------------------------------------
//PRC_CCI Master
//version = 0
//02.11.2026
//Iván González @ www.prorealcode.com
//Sharing ProRealTime knowledge
//-----------------------------------------------------------------------
// Apply ON THE PRICE CHART.
//
// The CCI turned into price: the overbought and oversold edges are the
// prices the next bar would have to reach for the CCI to hit those levels,
// worked out exactly from the CCI formula. The overbought zone glows above
// its edge and the oversold zone below its edge; candles warm toward the
// overbought colour and cool toward the oversold colour as the CCI moves.
// Dots mark the first close into a zone, arrows the exits.
//
// The classic CCI is computed on the typical price, (high + low + close)
// / 3, so with that source the edges are the typical price the next bar
// needs: a bar that closes at its high needs a close a third of its range
// above the edge. With the close as source the edges are exact closes.
//
// A CCI has a ceiling: it can never go past length / 0.03 either way
// (about 667 with 20 bars, 167 with 5). A level beyond it has no edge.
//
// Dots and arrows are drawn on the bar where they happened once that bar
// has CLOSED (when the next one opens), so they never appear and vanish
// inside a bar.
//-----------------------------------------------------------------------

// ===================== INPUTS =====================
// --- CCI ---
lenIn = 20           // CCI length (3 to 100)
srcIn = 1            // 1 = typical price (the classic CCI), 2 = close
obIn = 100           // overbought level
osIn = -100          // oversold level
smIn = 3             // smoothing of the zone edges, in bars (1 to 10)
// --- Look ---
themeIn = 1          // 1 = Neon, 2 = Classic, 3 = Aurora, 4 = Ice, 5 = Custom (the two colours below)
cuOsR = 0            // custom oversold colour #00FFA3
cuOsG = 255
cuOsB = 163
cuObR = 255          // custom overbought colour #FF3D71
cuObG = 61
cuObB = 113
bright = 3           // brightness (1 to 5)
depthIn = 2.2        // how far the zone glow reaches past its edge, in ATRs (0.5 to 6)
showCandles = 1      // 1 = CCI candles
showMid = 0          // 1 = midline (CCI 0)
showDots = 1         // 1 = entry dots
showTurns = 1        // 1 = exit arrows

// ===================== COLOURS =====================
IF themeIn = 2 THEN
   osR = 0           // #00FF31
   osG = 255
   osB = 49
   obR = 255         // #FF0013
   obG = 0
   obB = 19
ELSIF themeIn = 3 THEN
   osR = 52          // #34D399
   osG = 211
   osB = 153
   obR = 244         // #F472B6
   obG = 114
   obB = 182
ELSIF themeIn = 4 THEN
   osR = 125         // #7DD3FC
   osG = 211
   osB = 252
   obR = 253         // #FDA4AF
   obG = 164
   obB = 175
ELSIF themeIn = 5 THEN
   osR = cuOsR
   osG = cuOsG
   osB = cuOsB
   obR = cuObR
   obG = cuObG
   obB = cuObB
ELSE
   osR = 0           // Neon: #00FFA3 oversold, #FF3D71 overbought
   osG = 255
   osB = 163
   obR = 255
   obG = 61
   obB = 113
ENDIF
brightN = max(1, min(5, round(bright)))
brightMul = 0.4 + 0.2 * brightN
// Arrows and dots sit straight on the chart: a zone colour too light to read on a white background
// (the mint, the Ice theme) is darkened just enough, to a contrast of 4 to 1 against white; a colour
// that already reads is kept
lumS = 0.2126 * pow(osR / 255, 2.2) + 0.7152 * pow(osG / 255, 2.2) + 0.0722 * pow(osB / 255, 2.2)
kS = 1
IF lumS > 0.2125 THEN
   kS = pow(0.2125 / lumS, 1 / 2.2)
ENDIF
osTR = round(osR * kS)
osTG = round(osG * kS)
osTB = round(osB * kS)
lumO = 0.2126 * pow(obR / 255, 2.2) + 0.7152 * pow(obG / 255, 2.2) + 0.0722 * pow(obB / 255, 2.2)
kO = 1
IF lumO > 0.2125 THEN
   kO = pow(0.2125 / lumO, 1 / 2.2)
ENDIF
obTR = round(obR * kO)
obTG = round(obG * kO)
obTB = round(obB * kO)

// ===================== CCI, AND THE PRICES BEHIND IT =====================
lnC = max(3, min(100, round(lenIn)))
smN = max(1, min(10, round(smIn)))
// ATR(14), the bar range until it exists, never below one tick
atr14 = averagetruerange[14](close)
IF barindex >= 13 THEN
   atrV = atr14
ELSE
   atrV = high - low
ENDIF
atrV = max(atrV, ticksize)
IF srcIn = 2 THEN
   srcV = close
ELSE
   srcV = typicalprice
ENDIF
// Every bar's source value, by bar number: the loops below read the window from here
$srcA[barindex] = srcV
// CCI: distance from the mean over 0.015 mean absolute deviations; a window with no deviation reads 0
cciOk = 0
cciV = 0
IF barindex >= lnC - 1 THEN
   cciOk = 1
   meanC = summation[lnC](srcV) / lnC
   devC = 0
   FOR i = 0 TO lnC - 1 DO
      devC = devC + abs($srcA[barindex - i] - meanC)
   NEXT
   devC = devC / lnC
   IF devC > 0 THEN
      cciV = (srcV - meanC) / (0.015 * devC)
   ENDIF
ENDIF

// The source value next bar that would put the CCI exactly at a level. Tomorrow's window is the last
// lnC - 1 values plus tomorrow's; written in terms of tomorrow's mean m, the CCI equation is linear
// between consecutive window values and always rising, so it is enough to count how many of them
// fall below the answer and solve that piece exactly. The midline (CCI 0) is the mean of the
// lnC - 1 values that stay
obRaw = close
osRaw = close
midRaw = close
obRch = 0
osRch = 0
IF cciOk = 1 THEN
   nC = lnC
   sumP = summation[lnC - 1](srcV)
   midRaw = sumP / (nC - 1)
   kOB = 0.015 * obIn
   kOS = 0.015 * osIn
   IF abs(kOB) < nC / 2 THEN
      obRch = 1
   ENDIF
   IF abs(kOS) < nC / 2 THEN
      osRch = 1
   ENDIF
   aOB = nC - abs(kOB)
   aOS = nC - abs(kOS)
   cbOB = 0
   sbOB = 0
   cbOS = 0
   sbOS = 0
   FOR j = 0 TO lnC - 2 DO
      pj = $srcA[barindex - j]
      // total absolute deviation of the window values around pj
      dj = 0
      FOR i = 0 TO lnC - 2 DO
         dj = dj + abs($srcA[barindex - i] - pj)
      NEXT
      gj = ((nC - 1) * pj - sumP) * aOB - kOB * dj
      IF gj <= 0 THEN
         cbOB = cbOB + 1
         sbOB = sbOB + pj
      ENDIF
      gj = ((nC - 1) * pj - sumP) * aOS - kOS * dj
      IF gj <= 0 THEN
         cbOS = cbOS + 1
         sbOS = sbOS + pj
      ENDIF
   NEXT
   IF obRch = 1 THEN
      mOB = (sumP * aOB + kOB * ((sumP - sbOB) - sbOB)) / ((nC - 1) * aOB - kOB * (cbOB - (nC - 1 - cbOB)))
      obRaw = nC * mOB - sumP
   ENDIF
   IF osRch = 1 THEN
      mOS = (sumP * aOS + kOS * ((sumP - sbOS) - sbOS)) / ((nC - 1) * aOS - kOS * (cbOS - (nC - 1 - cbOS)))
      osRaw = nC * mOS - sumP
   ENDIF
ENDIF
// EMA of each edge, seeded with the simple mean of its first smN values
lvlStart = lnC + smN - 2
aSm = 2 / (smN + 1)
lvlOk = 0
IF barindex = lvlStart THEN
   obE = summation[smN](obRaw) / smN
   osE = summation[smN](osRaw) / smN
   midE = summation[smN](midRaw) / smN
ELSIF barindex > lvlStart THEN
   obE = obE + aSm * (obRaw - obE)
   osE = osE + aSm * (osRaw - osE)
   midE = midE + aSm * (midRaw - midE)
ENDIF
IF barindex >= lvlStart THEN
   lvlOk = 1
ELSE
   obE = close
   osE = close
   midE = close
ENDIF

inOB = 0
inOS = 0
IF cciOk = 1 THEN
   IF cciV >= obIn THEN
      inOB = 1
   ENDIF
   IF cciV <= osIn THEN
      inOS = 1
   ENDIF
ENDIF
enterOB = 0
exitOB = 0
enterOS = 0
exitOS = 0
IF barindex > lnC - 1 THEN
   IF inOB = 1 AND inOB[1] = 0 THEN
      enterOB = 1
   ENDIF
   IF inOB = 0 AND inOB[1] = 1 THEN
      exitOB = 1
   ENDIF
   IF inOS = 1 AND inOS[1] = 0 THEN
      enterOS = 1
   ENDIF
   IF inOS = 0 AND inOS[1] = 1 THEN
      exitOS = 1
   ENDIF
ENDIF

// ===================== DRAWING =====================
// --- The zones: full at the edge, fading away from price, in bands of constant opacity ---
obTop = obE + depthIn * atrV
osBot = osE - depthIn * atrV
zA = 0
IF lvlOk = 1 THEN
   zA = round(255 * min(max(0.26 * brightMul, 0), 1))
ENDIF
zAo = zA * obRch
zAs = zA * osRch
zStep = depthIn * atrV / 8
COLORBETWEEN(obE, obE + zStep, obR, obG, obB, round(zAo * 15 / 16))
COLORBETWEEN(obE + zStep, obE + 2 * zStep, obR, obG, obB, round(zAo * 13 / 16))
COLORBETWEEN(obE + 2 * zStep, obE + 3 * zStep, obR, obG, obB, round(zAo * 11 / 16))
COLORBETWEEN(obE + 3 * zStep, obE + 4 * zStep, obR, obG, obB, round(zAo * 9 / 16))
COLORBETWEEN(obE + 4 * zStep, obE + 5 * zStep, obR, obG, obB, round(zAo * 7 / 16))
COLORBETWEEN(obE + 5 * zStep, obE + 6 * zStep, obR, obG, obB, round(zAo * 5 / 16))
COLORBETWEEN(obE + 6 * zStep, obE + 7 * zStep, obR, obG, obB, round(zAo * 3 / 16))
COLORBETWEEN(obE + 7 * zStep, obTop, obR, obG, obB, round(zAo * 1 / 16))
COLORBETWEEN(osE, osE - zStep, osR, osG, osB, round(zAs * 15 / 16))
COLORBETWEEN(osE - zStep, osE - 2 * zStep, osR, osG, osB, round(zAs * 13 / 16))
COLORBETWEEN(osE - 2 * zStep, osE - 3 * zStep, osR, osG, osB, round(zAs * 11 / 16))
COLORBETWEEN(osE - 3 * zStep, osE - 4 * zStep, osR, osG, osB, round(zAs * 9 / 16))
COLORBETWEEN(osE - 4 * zStep, osE - 5 * zStep, osR, osG, osB, round(zAs * 7 / 16))
COLORBETWEEN(osE - 5 * zStep, osE - 6 * zStep, osR, osG, osB, round(zAs * 5 / 16))
COLORBETWEEN(osE - 6 * zStep, osE - 7 * zStep, osR, osG, osB, round(zAs * 3 / 16))
COLORBETWEEN(osE - 7 * zStep, osBot, osR, osG, osB, round(zAs * 1 / 16))

// --- The candles: a soft neutral through the middle of the range, warming to the overbought colour
// over the last stretch before the zone and cooling to the oversold colour on the way down, with up
// candles a shade brighter than down candles ---
IF showCandles = 1 AND cciOk = 1 THEN
   IF close >= open THEN
      nuR = 163       // #A3ABBD
      nuG = 171
      nuB = 189
   ELSE
      nuR = 95        // #5F6677
      nuG = 102
      nuB = 119
   ENDIF
   warmFrom = obIn * 0.3
   coolFrom = osIn * 0.3
   IF cciV >= 0 THEN
      tW = pow(min(max((cciV - warmFrom) / (obIn - warmFrom), 0), 1), 1.4)
      cdR = nuR + (obR - nuR) * tW
      cdG = nuG + (obG - nuG) * tW
      cdB = nuB + (obB - nuB) * tW
   ELSE
      tC = pow(min(max((coolFrom - cciV) / (coolFrom - osIn), 0), 1), 1.4)
      cdR = nuR + (osR - nuR) * tC
      cdG = nuG + (osG - nuG) * tC
      cdB = nuB + (osB - nuB) * tC
   ENDIF
   DRAWCANDLE(open, high, low, close) COLOURED(cdR, cdG, cdB) BORDERCOLOR(cdR, cdG, cdB)
ENDIF

// --- Exit arrows: when price flickers in and out of a zone over a few bars, only the first exit gets
// an arrow ---
ONCE lastArOB = 0 - 10
ONCE lastArOS = 0 - 10
arrowOB = 0
arrowOS = 0
IF exitOB = 1 AND barindex - lastArOB > 3 THEN
   arrowOB = 1
   lastArOB = barindex
ENDIF
IF exitOS = 1 AND barindex - lastArOS > 3 THEN
   arrowOS = 1
   lastArOS = barindex
ENDIF

// --- Events of the bar that has just CLOSED (offset 1), drawn on that bar ---
IF barindex > lvlStart THEN
   xE = barindex - 1
   // The first close into a zone: a soft halo and a solid dot
   IF showDots = 1 AND enterOB[1] = 1 THEN
      DRAWPOINT(xE, high[1], 4) COLOURED(obR, obG, obB, round(255 * min(0.18 * brightMul, 1)))
      DRAWPOINT(xE, high[1], 2) COLOURED(obTR, obTG, obTB, 255)
   ENDIF
   IF showDots = 1 AND enterOS[1] = 1 THEN
      DRAWPOINT(xE, low[1], 4) COLOURED(osR, osG, osB, round(255 * min(0.18 * brightMul, 1)))
      DRAWPOINT(xE, low[1], 2) COLOURED(osTR, osTG, osTB, 255)
   ENDIF
   // Where price leaves a zone: down out of overbought, up out of oversold
   IF showTurns = 1 AND arrowOB[1] = 1 THEN
      DRAWTEXT("▼", xE, high[1] + 0.5 * atrV[1], dialog, bold, 12) COLOURED(obTR, obTG, obTB, 255)
   ENDIF
   IF showTurns = 1 AND arrowOS[1] = 1 THEN
      DRAWTEXT("▲", xE, low[1] - 0.5 * atrV[1], dialog, bold, 12) COLOURED(osTR, osTG, osTB, 255)
   ENDIF
ENDIF

// --- Returned series: the edges with a soft halo, and the midline. Before the CCI exists they sit on
// the close with alpha 0, so they do not squash the price scale; a level past the CCI's ceiling has
// no edge and stays hidden ---
edA = 0
glA = 0
IF lvlOk = 1 THEN
   edA = 255
   glA = round(255 * min(max(0.16 * brightMul, 0), 1))
ENDIF
mdA = 0
IF showMid = 1 AND lvlOk = 1 THEN
   mdA = 115
ENDIF
edAo = edA * obRch
glAo = glA * obRch
edAs = edA * osRch
glAs = glA * osRch

RETURN obE COLOURED(obR, obG, obB, glAo) STYLE(line, 5) AS "Overbought glow", obE COLOURED(obR, obG, obB, edAo) STYLE(line, 2) AS "Overbought", osE COLOURED(osR, osG, osB, glAs) STYLE(line, 5) AS "Oversold glow", osE COLOURED(osR, osG, osB, edAs) STYLE(line, 2) AS "Oversold", midE COLOURED(123, 156, 255, mdA) STYLE(point, 1) AS "Midline"

Download
Filename: PRC_CCI-Master.itf
Downloads: 0
Iván González
Iván González Legend
As an architect of digital worlds, my own description remains a mystery. Think of me as an undeclared variable, existing somewhere in the code.
Author’s Profile

Comments

ProRealCode ProRealCode
Loading...