Most trend tools smooth price and call the slope a trend. PhantomFlow Trend Detector, by PhantomFlow_s666ex_, takes a structural route instead: it reads the trend straight from the geometry of swing points. It tracks the market’s fractal highs and lows, groups them into what it calls liquidity waves — runs of three same-side swings that line up in an orderly staircase — and uses the most recent of those waves to decide whether price is in an uptrend, a downtrend, or neither. The verdict is painted directly on the candles as a colour gradient, so the chart itself becomes the read-out: no oscillator, no separate panel.
The result is a trend indicator that only commits when market structure actually agrees. A single swing means nothing; the indicator waits for three aligned swings before it draws a conclusion, which filters out most of the bar-to-bar noise that fools moving-average crossovers. And because the colour is a gradient rather than a binary green/red, it carries a second layer of information: not just which way the trend points, but how close price sits to the level that would invalidate it.
Everything starts from fractal swing points, in the classic Bill Williams sense. A bar is a fractal high when its high is the highest of the five-bar window centred on it; a fractal low when its low is the lowest of that window:
fractal high : high[2] = highest(5) of high
fractal low : low[2] = lowest(5) of low
Because the window is centred, a fractal is only confirmed two bars after the fact (nZigzag = 2 bars on each side). That lag is the price of certainty — a swing is not declared until the two bars after it fail to exceed it.
Raw fractals are noisy: several highs can print before a single low does. The indicator runs them through a zigzag filter so the structure alternates cleanly between highs and lows:
This is the standard zigzag discipline, implemented with a small state machine that remembers whether the last accepted pivot was a high or a low. What comes out is a clean alternating sequence of swing highs and swing lows.
This is what makes PhantomFlow more than a zigzag. The indicator watches for three consecutive same-side swings that move in an orderly staircase:
Each wave defines a price band (its highest and lowest swing) and, crucially, a pivot level that becomes the trend threshold:
waveUpLow). Hold above it and the structure of higher-lows-of-the-highs is intact; lose it and the up-structure breaks.waveDownHigh). Stay below it and the down-structure holds; reclaim it and the down-structure breaks.These staircases are where resting liquidity tends to pool — under a run of lower highs, over a run of higher lows — which is where the indicator takes its name.
The trend verdict is read from where the current close sits relative to the last active wave (or waves):
close > waveUpLow.close < waveDownHigh.If none of those conditions holds, the indicator declares no trend and leaves the candles a neutral grey. This is the conservative core of the tool: it would rather say “nothing” than force a direction.
Once a direction is set, the active wave gives a high and a low, and the close is normalised to a 0–1 position inside that band:
norm = (close - lastLow) / (lastHigh - lastLow) , clamped to [0, 1]
That fraction drives a two-colour interpolation, computed channel by channel:
The candle is then drawn in that exact colour. The gradient is the whole point: a chart of fading-to-yellow green candles is an uptrend losing its grip, long before the colour actually flips.
waveUpLow. A flip to the red family confirms the break after the fact; the fade hints at it first.waveUpLow for longs, waveDownHigh for shorts — is a natural structural stop. A close back through it is exactly what turns the candle colour over, so the chart and the risk level agree by construction.nZigzag (default 2): the number of bars on each side of a fractal swing. The default of 2 (a five-bar window) is responsive and well suited to intraday charts, but it produces many swings. On daily or weekly timeframes, raise it to 4–5 for cleaner, more significant waves and less noise.The gradient colours are defined as plain RGB constants at the top of the code (upStart/upEnd for the uptrend ramp, downStart/downEnd for the downtrend ramp). Edit those values to recolour the indicator to taste — for example, swap the yellow→green ramp for a single-hue fade if you prefer a more subdued look.
//-----------------------------------------------------
//PRC_PhantomFlow TrendDetector
//version = 0
//11.05.2026
//Ivan Gonzalez @ www.prorealcode.com
//Sharing ProRealTime knowledge
// Original: PhantomFlow_s666ex_ (TradingView, MPL 2.0)
//-----------------------------------------------------
// === Inputs ===
//-----------------------------------------------------
nZigzag = 2
// Up Trend gradient (low -> high)
upStartR = 255
upStartG = 253
upStartB = 106
upEndR = 0
upEndG = 255
upEndB = 0
// Down Trend gradient (low -> high)
downStartR = 255
downStartG = 89
downStartB = 255
downEndR = 255
downEndG = 0
downEndB = 0
//-----------------------------------------------------
// === Inicializacion (primera barra) ===
//-----------------------------------------------------
IF barindex = 0 THEN
fracUp1 = 0
fracUp2 = 0
fracUp3 = 0
fracDown1 = 0
fracDown2 = 0
fracDown3 = 0
numUp = 0
numDown = 0
isLastUp = -1
waveUpStart = 0
waveUpEnd = 0
waveUpHigh = 0
waveUpLow = 0
hasWaveUp = 0
waveDownStart = 0
waveDownEnd = 0
waveDownHigh = 0
waveDownLow = 0
hasWaveDown = 0
lastLow = 0
lastHigh = 0
ENDIF
addUpWave = 0
addDownWave = 0
//-----------------------------------------------------
// === Deteccion de fractales ===
// (simetricos n=2, ventana = 5 barras)
//-----------------------------------------------------
canSearchFractal = barindex >= 2 * nZigzag
IF canSearchFractal THEN
// Fractal up: high[2] es maximo de high[0..4]
IF high[nZigzag] = highest[2 * nZigzag + 1](high) THEN
isUpFractal = 1
ELSE
isUpFractal = 0
ENDIF
// Fractal down: low[2] es minimo de low[0..4]
IF low[nZigzag] = lowest[2 * nZigzag + 1](low) THEN
isDownFractal = 1
ELSE
isDownFractal = 0
ENDIF
barFrac = barindex - nZigzag
priceUpFrac = high[nZigzag]
priceDownFrac = low[nZigzag]
// --- Procesar fractal up ---
IF isUpFractal = 1 THEN
IF numUp = 0 AND numDown = 0 THEN
fracUp1 = barFrac
numUp = 1
isLastUp = 1
ELSE
IF isLastUp = 1 THEN
// Ultimo era up: si el nuevo es mas alto, reemplazar (pop + push)
IF high[barindex - fracUp1] < priceUpFrac THEN
fracUp1 = barFrac
addUpWave = 1
ENDIF
ELSE
// Ultimo era down: confirmar zigzag si new high > last down low
IF low[barindex - fracDown1] < priceUpFrac THEN
fracUp3 = fracUp2
fracUp2 = fracUp1
fracUp1 = barFrac
numUp = numUp + 1
isLastUp = 1
addUpWave = 1
ENDIF
ENDIF
ENDIF
ENDIF
// Check is_add_up_liquidity: 3 ups consecutivos con highs decrecientes
IF addUpWave = 1 AND numUp >= 3 THEN
h1 = high[barindex - fracUp1]
h2 = high[barindex - fracUp2]
h3 = high[barindex - fracUp3]
IF h1 < h2 AND h2 < h3 THEN
IF hasWaveUp = 1 AND fracUp3 >= waveUpStart AND fracUp3 < waveUpEnd THEN
// Extender wave
waveUpEnd = fracUp1
waveUpLow = h1
ELSE
// Nueva wave
waveUpStart = fracUp3
waveUpEnd = fracUp1
waveUpHigh = h3
waveUpLow = h1
ENDIF
hasWaveUp = 1
ENDIF
ENDIF
// --- Procesar fractal down ---
IF isDownFractal = 1 THEN
IF numDown = 0 AND numUp = 0 THEN
fracDown1 = barFrac
numDown = 1
isLastUp = 0
ELSE
IF isLastUp = 0 THEN
// Ultimo era down: si el nuevo es mas bajo, reemplazar
IF low[barindex - fracDown1] > priceDownFrac THEN
fracDown1 = barFrac
addDownWave = 1
ENDIF
ELSE
// Ultimo era up: confirmar zigzag si last up high > new down low
IF high[barindex - fracUp1] > priceDownFrac THEN
fracDown3 = fracDown2
fracDown2 = fracDown1
fracDown1 = barFrac
numDown = numDown + 1
isLastUp = 0
addDownWave = 1
ENDIF
ENDIF
ENDIF
ENDIF
// Check is_add_down_liquidity: 3 downs consecutivos con lows crecientes
IF addDownWave = 1 AND numDown >= 3 THEN
l1 = low[barindex - fracDown1]
l2 = low[barindex - fracDown2]
l3 = low[barindex - fracDown3]
IF l1 > l2 AND l2 > l3 THEN
IF hasWaveDown = 1 AND fracDown3 >= waveDownStart AND fracDown3 < waveDownEnd THEN
// Extender wave
waveDownEnd = fracDown1
waveDownHigh = l1
ELSE
// Nueva wave
waveDownStart = fracDown3
waveDownEnd = fracDown1
waveDownLow = l3
waveDownHigh = l1
ENDIF
hasWaveDown = 1
ENDIF
ENDIF
ENDIF
//-----------------------------------------------------
// === Determinar tendencia ===
//-----------------------------------------------------
isUpTrend = 0
isDownTrend = 0
IF hasWaveUp = 1 AND hasWaveDown = 1 THEN
IF close < waveDownHigh AND close > waveUpLow THEN
IF waveDownEnd < waveUpEnd THEN
isUpTrend = 1
lastLow = waveUpLow
lastHigh = waveUpHigh
ELSE
isDownTrend = 1
lastLow = waveDownLow
lastHigh = waveDownHigh
ENDIF
ENDIF
IF close >= waveDownHigh AND close > waveUpLow THEN
isUpTrend = 1
lastLow = waveUpLow
lastHigh = waveUpHigh
ENDIF
IF close < waveDownHigh AND close <= waveUpLow THEN
isDownTrend = 1
lastLow = waveDownLow
lastHigh = waveDownHigh
ENDIF
ENDIF
IF hasWaveUp = 1 AND hasWaveDown = 0 THEN
IF close > waveUpLow THEN
isUpTrend = 1
lastLow = waveUpLow
lastHigh = waveUpHigh
ENDIF
ENDIF
IF hasWaveDown = 1 AND hasWaveUp = 0 THEN
IF close < waveDownHigh THEN
isDownTrend = 1
lastLow = waveDownLow
lastHigh = waveDownHigh
ENDIF
ENDIF
//-----------------------------------------------------
// === Color gradient interpolado ===
// (signal = close, ema(1) = close)
//-----------------------------------------------------
signal = close
IF lastHigh - lastLow <= 0 THEN
norm = 0.5
ELSE
norm = (signal - lastLow) / (lastHigh - lastLow)
IF norm < 0 THEN
norm = 0
ENDIF
IF norm > 1 THEN
norm = 1
ENDIF
ENDIF
paintR = 128
paintG = 128
paintB = 128
IF isUpTrend = 1 THEN
// Up: upStart (low) -> upEnd (high)
paintR = ROUND(upStartR + (upEndR - upStartR) * norm)
paintG = ROUND(upStartG + (upEndG - upStartG) * norm)
paintB = ROUND(upStartB + (upEndB - upStartB) * norm)
ENDIF
IF isDownTrend = 1 THEN
// Down: downEnd (low) -> downStart (high)
paintR = ROUND(downEndR + (downStartR - downEndR) * norm)
paintG = ROUND(downEndG + (downStartG - downEndG) * norm)
paintB = ROUND(downEndB + (downStartB - downEndB) * norm)
ENDIF
DRAWCANDLE(open, high, low, close) COLOURED(paintR, paintG, paintB)
//-----------------------------------------------------
RETURN