Screener ABC Patterns

Category: Screeners By: Iván González Created: July 24, 2026, 10:03 AM
July 24, 2026, 10:03 AM
Screeners
0 Comments

1. Introduction

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.

2. What the Screener Looks For

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.

3. The Three Signal Modes

The same pattern is interesting at three different moments, so the screener offers three modes through the signalMode setting:

 

  • Mode 0 – Fresh pattern (default). The ABC was detected within the last maxBarsAge bars and the entry is still ahead. This is the discovery mode: it shows you structures as they form, while there is still something to plan.
  • Mode 1 – Price approaching. Price is within nearPct% of the entry level without having reached it yet. This is the watchlist mode: candidates about to trigger.
  • Mode 2 – Entry triggered. The entry level was crossed within the last maxBarsAge bars. This is the execution mode, and the most selective of the three.

 

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.

4. Reading the Results

The screener returns four columns:

 

  • Alcista: 1 for a bullish pattern (long setup), 0 for bearish.
  • Nivel: the recursive zigzag level where the pattern was found. 0 is the base zigzag and produces the smallest structures; higher levels mean larger swings.
  • Ratio: the measured BC/AB retracement. Always between 0.618 and 0.786 by construction, so it tells you whether the pullback is shallow or deep within that band.
  • Dist%: distance from the current close to the entry level, in percent.

 

Sorting by Nivel descending puts the largest structures at the top. Sorting by Dist% ascending puts the most imminent setups first.

5. Screener Settings

  • zigzagLength (default 13): the base zigzag window. Larger values produce fewer and bigger swings.
  • maxLevel (default 2): how many recursive levels to scan. There is little point going higher, since the screener’s history simply does not contain enough pivots to build a fourth level.
  • minLevel (default 0): raise it to ignore the smallest structures entirely.
  • maxPivots (default 60): how many base pivots feed the scan. This is the performance lever.
  • baseMode (default 1): 1 projects from the AB extension, 2 from the BC retracement.
  • entryRatio / targetRatio / stopRatio (0.3 / 1.0 / 0.0): the three projected levels. stopRatio should stay at or below zero.
  • useLogScale (default 0): compute the projections on a logarithmic scale.
  • tradeCondition (default 0): 0 any, 1 trend, 2 reverse, 3 contracting, 4 expanding.
  • signalMode (default 0): 0 fresh pattern, 1 price approaching, 2 entry triggered.
  • maxBarsAge (default 5): how recent the event must be, in bars.
  • nearPct (default 3.0): proximity threshold for mode 1, in percent.
  • dirFilter (default 0): 0 both, 1 bullish only, -1 bearish only.

 

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.

6. ABC on Recursive Zigzag Screener Code

 

// === 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%")

Download
Filename: SCR_ABC.itf
Downloads: 7
Iván González Legend
Operating in the shadows, I hack problems one by one. My bio is currently encrypted by a complex algorithm. Decryption underway...
Author’s Profile

Comments

Logo Logo
Loading...