This screener is the scanning companion to the ABC on Recursive Zigzag indicator. The indicator draws every ABC pattern it finds on a single chart; the screener asks the same question across your whole watchlist at once: where is an ABC structure forming right now?
It runs the same engine. A zigzag is built on the price, then distilled recursively into higher levels, and at every level the last three pivots are tested as an ABC. What changes is the output: instead of drawings and statistics, you get a filtered list of instruments with the pattern direction, the swing scale it appeared on, and how far price sits from the entry.
An ABC is accepted when leg BC retraces between 61.8% and 78.6% of leg AB. That window is the classic continuation retracement: deep enough to shake out the impulse, shallow enough that the structure is not simply reversing.
The recursive part is what makes it worth scanning with. Level 0 is the ordinary zigzag. Level 1 keeps only the level 0 pivots that are extremes within their own series, level 2 does the same to level 1, and so on. A pattern found on level 2 is a far larger structure than one on level 0, even though both come from the same settings. The screener reports which level produced the hit, so you can sort your results by swing size.
The same pattern is interesting at three different moments, so the screener offers three modes through the signalMode setting:
Two extra filters narrow things further: dirFilter restricts results to bullish or bearish setups only, and tradeCondition filters by the type of the A and B pivots, separating continuation structures from counter-trend ones.
The screener returns four columns:
Sorting by Nivel descending puts the largest structures at the top. Sorting by Dist% ascending puts the most imminent setups first.
A practical note on stopRatio: the default of 0 places the stop exactly at point C, which invalidates patterns quickly. Loosening it to -0.2 or -0.5 leaves noticeably more patterns alive and will widen your result list.
Modes 1 and 2 are deliberately selective, since they target a single moment in the pattern’s life rather than a state. If they come back empty on a small watchlist, that is expected behaviour, not a fault: raise nearPct or maxBarsAge to widen the window.
// === PRC ABC on Recursive Zigzag - Screener ===
// Filtra instrumentos con un patron ABC valido sobre zigzag recursivo
// multinivel. C retrocede entre el 61.8% y el 78.6% de la pata AB.
// Tres modos de senal: patron fresco / precio acercandose / entrada activada.
// --- Inputs: zigzag ---
zigzagLength = 13 // Ventana del zigzag de nivel 0
maxLevel = 2 // Nivel maximo recursivo (el histor. del screener no da para mas)
minLevel = 0 // Nivel minimo a escanear
maxPivots = 60 // Pivotes de nivel 0 usados en el escaneo
// --- Inputs: patron y niveles ---
baseMode = 1 // 1 = ABC Extension, 2 = BC Retracement
entryRatio = 0.3 // Ratio de entrada
targetRatio = 1.0 // Ratio de objetivo
stopRatio = 0.0 // Ratio de stop (<= 0)
useLogScale = 0 // 1 = calcular en escala logaritmica
tradeCondition = 0 // 0 any, 1 trend, 2 reverse, 3 contracting, 4 expanding
// --- Inputs: filtrado ---
signalMode = 0 // 0 = patron fresco, 1 = precio acercandose, 2 = entrada activada
maxBarsAge = 5 // Antiguedad maxima (barras) del evento buscado
nearPct = 3.0 // Solo signalMode = 1: distancia maxima a la entrada en %
dirFilter = 0 // 0 = ambos, 1 = solo alcista, -1 = solo bajista
// --- Estado persistente ---
ONCE npv = 0 // Pivotes de nivel 0 acumulados
ONCE prevDir = 0
ONCE hasPat = 0 // 1 = hay patron vigente
ONCE patDir = 0 // 1 alcista, -1 bajista
ONCE patLevel = 0 // Nivel del zigzag donde se detecto
ONCE patRatio = 0 // Retroceso BC/AB medido
ONCE patEntry = 0
ONCE patStop = 0
ONCE patTgt = 0
ONCE patBar = 0 // Barra de deteccion
ONCE patPA = 0 // A y B del patron vigente (anti-duplicado)
ONCE patPB = 0
ONCE trigged = 0 // 1 = la entrada del patron vigente ya se activo
// Registro de la ultima activacion, INDEPENDIENTE del ciclo de vida del patron:
// una vez activada la entrada el precio corre hacia objetivo o stop y el patron
// se cierra enseguida, asi que "activado y todavia vigente" casi nunca se cumple.
ONCE trigEver = 0
ONCE trigEverBar = 0
ONCE trigEverDir = 0
// ============================================================
// === 1. NIVEL 0: DETECCION DE PIVOTES ===
// ============================================================
newPivot = 0
IF barindex >= zigzagLength THEN
hb = highestbars[zigzagLength](high)
lb = lowestbars[zigzagLength](low)
IF hb = 0 AND lb <> 0 THEN
pvDir = 1
pvVal = high
ELSIF lb = 0 AND hb <> 0 THEN
pvDir = -1
pvVal = low
ELSIF hb = 0 AND lb = 0 THEN
pvDir = prevDir
IF pvDir = 1 THEN
pvVal = high
ELSE
pvVal = low
ENDIF
ELSE
pvDir = 0
pvVal = 0
ENDIF
IF pvDir <> 0 THEN
IF pvDir = 1 THEN
isHi = 1
ELSE
isHi = 0
ENDIF
IF npv = 0 THEN
$zI[0] = barindex
$zP[0] = pvVal
$zH[0] = isHi
npv = 1
newPivot = 1
ELSE
lastH = $zH[npv-1]
IF lastH = isHi THEN
lastP = $zP[npv-1]
IF isHi = 1 THEN
IF pvVal > lastP THEN
$zI[npv-1] = barindex
$zP[npv-1] = pvVal
newPivot = 1
ENDIF
ELSE
IF pvVal < lastP THEN
$zI[npv-1] = barindex
$zP[npv-1] = pvVal
newPivot = 1
ENDIF
ENDIF
ELSE
$zI[npv] = barindex
$zP[npv] = pvVal
$zH[npv] = isHi
npv = npv + 1
newPivot = 1
ENDIF
ENDIF
prevDir = pvDir
ENDIF
ENDIF
// ============================================================
// === 2. ESCANEO MULTINIVEL DEL PATRON ABC ===
// ============================================================
IF newPivot = 1 AND npv >= 4 THEN
startK = npv - maxPivots
IF startK < 0 THEN
startK = 0
ENDIF
nw = 0
FOR k = startK TO npv - 1 DO
$wI[nw] = $zI[k]
$wP[nw] = $zP[k]
$wH[nw] = $zH[k]
nw = nw + 1
NEXT
FOR lev = 0 TO maxLevel DO
IF nw >= 4 THEN
// dir de cada pivote: +-1 retroceso, +-2 superacion
FOR k = 0 TO nw - 1 DO
IF $wH[k] = 1 THEN
$wD[k] = 1
ELSE
$wD[k] = -1
ENDIF
IF k >= 2 THEN
prevSame = $wP[k-2]
IF $wH[k] = 1 THEN
IF $wP[k] > prevSame THEN
$wD[k] = 2
ENDIF
ELSE
IF $wP[k] < prevSame THEN
$wD[k] = -2
ENDIF
ENDIF
ENDIF
NEXT
IF lev >= minLevel THEN
cK = nw - 1
bK = nw - 2
aK = nw - 3
pA = $wP[aK]
pB = $wP[bK]
pC = $wP[cK]
legAB = abs(pB - pA)
legBC = abs(pC - pB)
abcRatio = 0
IF legAB > 0 THEN
abcRatio = legBC / legAB
ENDIF
ratioOk = 0
IF abcRatio >= 0.618 AND abcRatio <= 0.786 THEN
ratioOk = 1
ENDIF
aDir = abs($wD[aK])
bDir = abs($wD[bK])
condOk = 0
IF tradeCondition = 0 THEN
condOk = 1
ELSIF tradeCondition = 1 AND aDir = 1 AND bDir = 2 THEN
condOk = 1
ELSIF tradeCondition = 2 AND aDir = 2 AND bDir = 1 THEN
condOk = 1
ELSIF tradeCondition = 3 AND aDir = 1 AND bDir = 1 THEN
condOk = 1
ELSIF tradeCondition = 4 AND aDir = 2 AND bDir = 2 THEN
condOk = 1
ENDIF
IF ratioOk = 1 AND condOk = 1 THEN
// Distinto del patron vigente?
isNew = 1
IF hasPat = 1 THEN
IF patPA = pA AND patPB = pB THEN
isNew = 0
ENDIF
ENDIF
IF isNew = 1 THEN
IF pB > pC THEN
pDirn = 1
ELSE
pDirn = -1
ENDIF
IF useLogScale = 1 AND pA > 0 AND pB > 0 AND pC > 0 THEN
lA = log(pA)
lB = log(pB)
lC = log(pC)
IF baseMode = 1 THEN
spanL = lB - lA
ELSE
spanL = lB - lC
ENDIF
eLvl = exp(lC + spanL * entryRatio)
tLvl = exp(lC + spanL * targetRatio)
sLvl = exp(lC + spanL * stopRatio)
ELSE
IF baseMode = 1 THEN
spanP = pB - pA
ELSE
spanP = pB - pC
ENDIF
eLvl = pC + spanP * entryRatio
tLvl = pC + spanP * targetRatio
sLvl = pC + spanP * stopRatio
ENDIF
// Solo se registra si la entrada aun no se alcanzo
IF close * pDirn < eLvl * pDirn THEN
hasPat = 1
patDir = pDirn
patLevel = lev
patRatio = abcRatio
patEntry = eLvl
patStop = sLvl
patTgt = tLvl
patBar = barindex
patPA = pA
patPB = pB
trigged = 0
ENDIF
ENDIF
ENDIF
ENDIF
// Construir el zigzag del nivel siguiente
IF lev < maxLevel THEN
nv = 0
FOR k = 0 TO nw - 1 DO
keep = 1
IF k < nw - 1 THEN
IF k >= 2 THEN
prevSame = $wP[k-2]
IF $wH[k] = 1 THEN
IF $wP[k] < prevSame THEN
keep = 0
ENDIF
ELSE
IF $wP[k] > prevSame THEN
keep = 0
ENDIF
ENDIF
ENDIF
IF k + 2 <= nw - 1 THEN
nextSame = $wP[k+2]
IF $wH[k] = 1 THEN
IF $wP[k] < nextSame THEN
keep = 0
ENDIF
ELSE
IF $wP[k] > nextSame THEN
keep = 0
ENDIF
ENDIF
ENDIF
ENDIF
IF keep = 1 THEN
doPush = 1
IF nv > 0 THEN
prevH = $vH[nv-1]
IF prevH = $wH[k] THEN
doPush = 0
prevP = $vP[nv-1]
IF $wH[k] = 1 THEN
IF $wP[k] > prevP THEN
$vP[nv-1] = $wP[k]
$vI[nv-1] = $wI[k]
ENDIF
ELSE
IF $wP[k] < prevP THEN
$vP[nv-1] = $wP[k]
$vI[nv-1] = $wI[k]
ENDIF
ENDIF
ENDIF
ENDIF
IF doPush = 1 THEN
$vI[nv] = $wI[k]
$vP[nv] = $wP[k]
$vH[nv] = $wH[k]
nv = nv + 1
ENDIF
ENDIF
NEXT
FOR k = 0 TO nv - 1 DO
$wI[k] = $vI[k]
$wP[k] = $vP[k]
$wH[k] = $vH[k]
NEXT
nw = nv
ENDIF
ENDIF
NEXT
ENDIF
// ============================================================
// === 3. SEGUIMIENTO DEL PATRON VIGENTE ===
// ============================================================
IF hasPat = 1 THEN
// Entrada activada
IF trigged = 0 THEN
IF close * patDir >= patEntry * patDir THEN
trigged = 1
trigEver = 1
trigEverBar = barindex
trigEverDir = patDir
ENDIF
ENDIF
// Cierre: objetivo alcanzado, o stop roto
patClosed = 0
IF close * patDir >= patTgt * patDir THEN
patClosed = 1
ENDIF
IF close * patDir <= patStop * patDir THEN
patClosed = 1
ENDIF
IF patClosed = 1 THEN
hasPat = 0
trigged = 0
ENDIF
ENDIF
// ============================================================
// === 4. CONDICION DEL SCREENER ===
// ============================================================
patAge = barindex - patBar
trigAge = barindex - trigEverBar
// Distancia del precio a la entrada, en %
distPct = 0
IF close > 0 THEN
distPct = abs(patEntry - close) / close * 100
ENDIF
// Direccion relevante segun el modo: los modos 0 y 1 miran el patron
// vigente, el modo 2 mira la ultima activacion registrada.
IF signalMode = 2 THEN
sigDir = trigEverDir
ELSE
sigDir = patDir
ENDIF
// Filtro por direccion
dirOk = 1
IF dirFilter = 1 AND sigDir <> 1 THEN
dirOk = 0
ENDIF
IF dirFilter = -1 AND sigDir <> -1 THEN
dirOk = 0
ENDIF
// Senal segun modo
sigOk = 0
IF signalMode = 0 THEN
// Patron vigente detectado recientemente
IF hasPat = 1 AND patAge <= maxBarsAge THEN
sigOk = 1
ENDIF
ELSIF signalMode = 1 THEN
// Precio acercandose a la entrada, sin haberla alcanzado aun
IF hasPat = 1 AND trigged = 0 AND distPct <= nearPct THEN
sigOk = 1
ENDIF
ELSE
// Entrada activada en las ultimas maxBarsAge barras (aunque el
// patron ya se haya resuelto despues)
IF trigEver = 1 AND trigAge <= maxBarsAge THEN
sigOk = 1
ENDIF
ENDIF
cond = 0
IF sigOk = 1 THEN
IF dirOk = 1 THEN
cond = 1
ENDIF
ENDIF
// Columnas de salida
dirCol = 0
IF sigDir = 1 THEN
dirCol = 1
ENDIF
ratioCol = round(patRatio * 1000) / 1000
distCol = round(distPct * 100) / 100
SCREENER[cond = 1](dirCol AS "Alcista", patLevel AS "Nivel", ratioCol AS "Ratio", distCol AS "Dist%")