Master these dynamic price channels in TradingView's Pinescript that identify fractals as key support and resistance levels, aiding in trend identification and breakout signals.
Fractal Chaos Bands are a technical indicator developed by Bill Williams, derived from his concept of fractals. Unlike traditional moving average-based channels (like Bollinger Bands or Keltner Channels), Fractal Chaos Bands utilize fractal patterns-specific sequences of candlesticks that indicate market turning points (highs or lows). These bands identify the highest high and lowest low within a defined number of bars around a central fractal, creating dynamic support and resistance levels.
The primary purpose of Fractal Chaos Bands is to visualize price movements relative to these fractal-based boundaries, helping traders to:
The calculation of Fractal Chaos Bands is based on identifying "fractal highs" and "fractal lows." A fractal typically consists of 5 bars where the middle bar is the highest (for a bullish fractal) or lowest (for a bearish fractal) compared to the two bars immediately preceding it and the two bars immediately following it. The `length` parameter refers to how many bars left and right define the fractal.
//@version=5
indicator("My Fractal Chaos Bands", overlay=true) // overlay=true to plot directly on the price chart
// Input for fractal length (number of bars to left/right for fractal calculation)
// A common fractal length is 2, creating a 5-bar pattern (2 left + center + 2 right)
length = input.int(2, title="Fractal Length (Bars Left/Right)", minval=1)
// --- Custom Fractal Calculation (Illustrative) ---
// Pinescript's ta.fractal() simplifies this greatly, but this shows the logic.
// Define a function to get the highest high for the upper band
highestHighFractal(len) =>
result = high[len] // Start with the high at the center of the fractal
isFractalHigh = true
for i = 1 to len // Check bars to the left
if high[len] <= high[len - i]
isFractalHigh := false
for i = 1 to len // Check bars to the right
if high[len] <= high[len + i]
isFractalHigh := false
isFractalHigh ? high[len] : na // Return high if it's a fractal high, else na
// Define a function to get the lowest low for the lower band
lowestLowFractal(len) =>
result = low[len] // Start with the low at the center of the fractal
isFractalLow = true
for i = 1 to len // Check bars to the left
if low[len] >= low[len - i]
isFractalLow := false
for i = 1 to len // Check bars to the right
if low[len] >= low[len + i]
isFractalLow := false
isFractalLow ? low[len] : na // Return low if it's a fractal low, else na
// Calculate the fractal high and low for current bar's perspective
// Since we need to look 'length' bars to the right, we plot on 'length' bars back
// This is typically done by using 'offset' in plot or by plotting at a delayed index.
// For simpler plotting, we can get the 'last' fractal high/low.
// --- Using Pinescript's Built-in ta.fractal() ---
// This built-in function returns 'true' if a fractal is found at current bar's index.
// We then need to capture the price of that fractal.
// For the upper band, we need the HIGHEST high that was a fractal within the lookback period.
// For the lower band, we need the LOWEST low that was a fractal within the lookback period.
// It's more common for Fractal Chaos Bands to simply connect the highest/lowest fractals found.
// The built-in `ta.fractal()` flags when a fractal *forms*.
// For continuous bands, we need to store the *most recent* fractal high/low.
// Let's create persistent variables to hold the most recent fractal high/low values
var float upperBand = na
var float lowerBand = na
// Update bands only when a new fractal high/low is found
if not na(ta.fractal.high(length))
upperBand := ta.fractal.high(length)
if not na(ta.fractal.low(length))
lowerBand := ta.fractal.low(length)
// Plot the bands
plot(upperBand, title="Upper Fractal Band", color=color.lime, linewidth=2, style=plot.style_stepline)
plot(lowerBand, title="Lower Fractal Band", color=color.fuchsia, linewidth=2, style=plot.style_stepline)
// Optionally, plot the actual fractal points
plotshape(ta.fractal.high(length), title="Fractal High", location=location.abovebar, color=color.green, style=shape.triangledown, size=size.small)
plotshape(ta.fractal.low(length), title="Fractal Low", location=location.belowbar, color=color.red, style=shape.triangleup, size=size.small)
A key aspect of Bill Williams' fractals is that they are confirmed with a delay (after `length` bars to the right have passed). This means the bands will repaint until a fractal is fully confirmed.
//@version=5
strategy("Fractal Chaos Breakout Strategy", overlay=true)
length = input.int(2, title="Fractal Length", minval=1)
// Calculate Fractal Chaos Bands
var float upperBand = na
var float lowerBand = na
if not na(ta.fractal.high(length))
upperBand := ta.fractal.high(length)
if not na(ta.fractal.low(length))
lowerBand := ta.fractal.low(length)
// Plot for visualization
plot(upperBand, "Upper Fractal Band", color.lime, linewidth=2, style=plot.style_stepline)
plot(lowerBand, "Lower Fractal Band", color.fuchsia, linewidth=2, style=plot.style_stepline)
// Long entry: Close price breaks above the upper fractal band
// Use `close[1]` and `upperBand[1]` for confirmed previous bar's band
longCondition = close > upperBand[1] and close[1] <= upperBand[1] and not na(upperBand[1])
// Short entry: Close price breaks below the lower fractal band
shortCondition = close < lowerBand[1] and close[1] >= lowerBand[1] and not na(lowerBand[1])
if (longCondition)
strategy.entry("Long Break", strategy.long)
if (shortCondition)
strategy.entry("Short Break", strategy.short)
// Example exits: Close on touch of opposite band, fixed stop loss, or target
// For simplification, let's use a very basic exit for this example
strategy.exit("Long Exit", from_entry="Long Break", stop=lowerBand) // Stop at lower band
strategy.exit("Short Exit", from_entry="Short Break", stop=upperBand) // Stop at upper band
//@version=5
indicator("Fractal SR Zones", overlay=true)
length = input.int(2, title="Fractal Length", minval=1)
var float upperBand = na
var float lowerBand = na
if not na(ta.fractal.high(length))
upperBand := ta.fractal.high(length)
if not na(ta.fractal.low(length))
lowerBand := ta.fractal.low(length)
plot(upperBand, "Upper Fractal Band", color.lime, linewidth=2, style=plot.style_stepline)
plot(lowerBand, "Lower Fractal Band", color.fuchsia, linewidth=2, style=plot.style_stepline)
// Detect price approaching and potentially respecting bands
// These are visual signals, hard to automate without complex price action logic
priceNearUpper = (high > upperBand[1] * 0.99) and (high < upperBand[1] * 1.01) // Within 1% of upper band
priceNearLower = (low < lowerBand[1] * 1.01) and (low > lowerBand[1] * 0.99) // Within 1% of lower band
// Example: Color candles that are near bands
barcolor(priceNearUpper ? color.new(color.orange, 50) : na)
barcolor(priceNearLower ? color.new(color.new(color.blue, 50), 50) : na)
// You'd combine this with candlestick patterns (e.g., pin bars, engulfing patterns)
// at these levels for actual trade signals.
// alertcondition(priceNearUpper and close < open, "Price Rejected Upper Band", "Price is near Upper Fractal Band and showing bearish reversal.")
// alertcondition(priceNearLower and close > open, "Price Bounced Lower Band", "Price is near Lower Fractal Band and showing bullish reversal.")
//@version=5
indicator("Fractal Chaos Consolidation", overlay=true)
length = input.int(2, title="Fractal Length", minval=1)
var float upperBand = na
var float lowerBand = na
if not na(ta.fractal.high(length))
upperBand := ta.fractal.high(length)
if not na(ta.fractal.low(length))
lowerBand := ta.fractal.low(length)
plot(upperBand, "Upper Fractal Band", color.lime, linewidth=2, style=plot.style_stepline)
plot(lowerBand, "Lower Fractal Band", color.fuchsia, linewidth=2, style=plot.style_stepline)
fill(upperBand, lowerBand, color.new(color.aqua, 95)) // Light fill
// Measure the width of the channel
channelWidth = upperBand - lowerBand
avgChannelWidth = ta.ema(channelWidth, 14) // EMA of channel width
// Detect if price is contained within bands and channel width is relatively narrow
// Using a simple check: is the current high below the upper band and low above the lower band
// AND is the channel width below a certain percentage of average price
isContained = high < upperBand[1] and low > lowerBand[1]
isNarrowing = channelWidth < avgChannelWidth * 0.8 // Current width is 20% less than its average
isConsolidating = isContained and isNarrowing
bgcolor(isConsolidating ? color.new(color.yellow, 90) : na, title="Consolidation Zone")
alertcondition(isConsolidating, "Fractal Consolidation", "Market is consolidating within Fractal Chaos Bands.")
To get the most from Fractal Chaos Bands in Pinescript:
Fractal Chaos Bands offer a unique way to visualize market structure based on Bill Williams' fractal theory, highlighting key levels where reversals or accelerations have occurred historically.
Fractal Chaos Bands are a distinct and insightful technical indicator in Pinescript for TradingView, offering a unique perspective on market dynamics based on Bill Williams' fractal concept. By providing dynamic support and resistance levels derived from confirmed fractal highs and lows, they can be highly effective in identifying trend direction, anticipating breakouts from consolidation, and confirming market shifts. While understanding their inherent repainting nature and confirmation delay is crucial, by thoughtfully tuning their parameters, combining them with appropriate confirmation indicators, and implementing sound risk management, you can leverage Fractal Chaos Bands to enhance your trading decisions and gain deeper insights into the underlying structure of price action.
Get a high-performance Pinescript analysis tool for actionable market insights, designed for traders on the move.
This strategy runs in live mode on TradingView, helping you identify potential opportunities.
Get Pinescript Strategy