Why Doji Patterns Matter in Pine Script
A Doji candlestick pattern is a crucial signal in technical analysis, characterized by a very small or non-existent real body, meaning the opening and closing prices are virtually the same. This indicates market indecision, where buyers and sellers are in a state of balance. While a single Doji candle alone may not be a definitive reversal signal, its appearance, especially after a prolonged trend or at key support/resistance levels, can indicate potential exhaustion of the current trend and a possible reversal. This makes Doji patterns invaluable for:
- Signaling market indecision and a pause in momentum.
- Indicating potential trend reversals when combined with context.
- Highlighting periods of balance between supply and demand.
Understanding Various Doji Candlestick Patterns
While all Doji share the characteristic of a small body, their wick lengths and positions create different variations, each conveying a slightly different message:
Standard Doji
A cross shape, indicating perfect balance between buyers and sellers. Common in sideways markets.
Long-Legged Doji
Long upper and lower wicks, signifying strong indecision and volatility, but no clear direction.
Dragonfly Doji
Long lower wick, no upper wick. Price rejected lower levels. Bullish reversal signal if after downtrend.
Gravestone Doji
Long upper wick, no lower wick. Price rejected higher levels. Bearish reversal signal if after uptrend.
Four Price Doji
Open, high, low, and close are all the same. Extremely rare, indicating extreme indecision or very low liquidity.
- Small/Non-existent Real Body: Open and close prices are very close, often at the same level.
- Indecision: Represents a balance between buying and selling forces.
- Context is Crucial: A Doji's significance increases dramatically when it appears after a strong trend or at key support/resistance levels.
Basic Doji Pattern Detection in Pine Script
Here's how to create a basic indicator to detect a standard Doji pattern in Pine Script v5. We'll define a "small body" as a percentage of the total candle range:
//@version=5
indicator("Doji Pattern Detector", overlay=true)
// User input for threshold to define a "small body"
bodyRatioThreshold = input.float(0.1, title="Doji Body Ratio Threshold (e.g., 0.1 for 10%)", minval=0.01, maxval=0.5)
// Calculate candle body size
bodySize = math.abs(close - open)
// Calculate total candle range
candleRange = high - low
// Check if it's a Doji (body size is very small relative to the candle's total range)
// Avoid division by zero if candleRange is 0 (occurs with Four Price Doji)
isDoji = if candleRange > 0
bodySize / candleRange <= bodyRatioThreshold
else // Handle Four Price Doji case (open==high==low==close)
true
// Plot signal on the chart
plotshape(isDoji, title="Doji Detected", location=location.belowbar, color=color.new(color.silver, 0), style=shape.circle, size=size.small)
// Alert condition (optional)
alertcondition(isDoji, title="Doji Detected", message="Doji Candlestick Pattern Detected!")
Detecting Specific Doji Types
We can refine the detection to identify specific Doji variations:
//@version=5
indicator("Specific Doji Patterns", overlay=true)
// Input for threshold to define a "small body"
bodyRatioThreshold = input.float(0.1, title="Doji Body Ratio Threshold (e.g., 0.1 for 10%)", minval=0.01, maxval=0.5)
// Input for wick ratio to define "long" or "short" wicks
wickRatioThreshold = input.float(0.4, title="Long Wick Ratio Threshold (e.g., 0.4 for 40%)", minval=0.1, maxval=0.9)
// Helper function to check for small body
isSmallBody(open_val, close_val, high_val, low_val) =>
bodySize = math.abs(close_val - open_val)
candleRange = high_val - low_val
candleRange > 0 ? (bodySize / candleRange <= bodyRatioThreshold) : true // Handles Four Price Doji
// Calculate wick lengths
upperShadow = high - math.max(open, close)
lowerShadow = math.min(open, close) - low
totalRange = high - low
// --- Standard Doji ---
// Small body, relatively balanced upper and lower shadows (or overall short wicks)
isStandardDoji = isSmallBody(open, close, high, low) and
(upperShadow / totalRange > 0.1 and lowerShadow / totalRange > 0.1) // Some wicks
// More balanced wick check: math.abs(upperShadow - lowerShadow) / totalRange < 0.2
// --- Long-Legged Doji ---
// Small body, very long upper and lower shadows
isLongLeggedDoji = isSmallBody(open, close, high, low) and
upperShadow / totalRange >= wickRatioThreshold and
lowerShadow / totalRange >= wickRatioThreshold
// --- Dragonfly Doji ---
// Small body (or non-existent) at the top of the candle, long lower shadow, little to no upper shadow
isDragonflyDoji = isSmallBody(open, close, high, low) and
lowerShadow / totalRange >= wickRatioThreshold and
upperShadow / totalRange < bodyRatioThreshold * 0.5 // Upper shadow is tiny
// --- Gravestone Doji ---
// Small body (or non-existent) at the bottom of the candle, long upper shadow, little to no lower shadow
isGravestoneDoji = isSmallBody(open, close, high, low) and
upperShadow / totalRange >= wickRatioThreshold and
lowerShadow / totalRange < bodyRatioThreshold * 0.5 // Lower shadow is tiny
// --- Four Price Doji ---
// Open, high, low, close are all the same
isFourPriceDoji = (open == high) and (high == low) and (low == close)
// Plot shapes for detected patterns
plotshape(isStandardDoji, title="Standard Doji", location=location.belowbar, color=color.new(color.gray, 0), style=shape.circle, size=size.small, text="SD")
plotshape(isLongLeggedDoji, title="Long-Legged Doji", location=location.belowbar, color=color.new(color.orange, 0), style=shape.circle, size=size.normal, text="LLD")
plotshape(isDragonflyDoji, title="Dragonfly Doji", location=location.belowbar, color=color.new(color.green, 0), style=shape.triangleup, size=size.normal, text="DFD")
plotshape(isGravestoneDoji, title="Gravestone Doji", location=location.abovebar, color=color.new(color.red, 0), style=shape.triangledown, size=size.normal, text="GSD")
plotshape(isFourPriceDoji, title="Four Price Doji", location=location.belowbar, color=color.new(color.purple, 0), style=shape.diamond, size=size.small, text="4PD")
// Alerts (optional)
alertcondition(isLongLeggedDoji, title="Long-Legged Doji Alert", message="Long-Legged Doji Detected!")
alertcondition(isDragonflyDoji, title="Dragonfly Doji Alert", message="Dragonfly Doji Detected!")
alertcondition(isGravestoneDoji, title="Gravestone Doji Alert", message="Gravestone Doji Detected!")
Advanced Doji Strategies
Doji patterns are powerful signals of indecision, but their true predictive value shines when combined with other indicators and market context. They act as "warnings" that a trend might be losing momentum, rather than direct entry signals.
1. Doji with Trend Confirmation (Using Moving Average)
//@version=5
strategy("Doji with Trend Reversal Confirmation", overlay=true)
// Input for Moving Average length
maLength = input(50, "MA Length (for trend)")
ma = ta.ema(close, maLength) // Using EMA for trend detection
// Doji Pattern Detection (using a general Doji definition for simplicity)
bodyRatioThreshold = 0.1
bodySize = math.abs(close - open)
candleRange = high - low
isDoji = if candleRange > 0
bodySize / candleRange <= bodyRatioThreshold
else
true
// Trend Context:
// Potential Bullish Reversal: Doji after a downtrend AND near MA support
isPotentialBullishReversal = isDoji and close < ma and close[1] < ma[1] and ma > ma[1] // price below MA, MA sloping down
// Potential Bearish Reversal: Doji after an uptrend AND near MA resistance
isPotentialBearishReversal = isDoji and close > ma and close[1] > ma[1] and ma < ma[1] // price above MA, MA sloping up
// Plot signals
plotshape(isPotentialBullishReversal, title="Doji (Bullish Reversal Context)", location=location.belowbar, color=color.new(color.blue, 0), style=shape.arrowup, size=size.normal)
plotshape(isPotentialBearishReversal, title="Doji (Bearish Reversal Context)", location=location.abovebar, color=color.new(color.purple, 0), style=shape.arrowdown, size=size.normal)
// Plot MA
plot(ma, "Trend MA", color.blue)
2. Doji with Volume Confirmation
//@version=5
indicator("Doji with Volume Confirmation", overlay=true)
// Doji Pattern Detection (from basic example)
bodyRatioThreshold = input.float(0.1, title="Doji Body Ratio Threshold", minval=0.01, maxval=0.5)
bodySize = math.abs(close - open)
candleRange = high - low
isDoji = if candleRange > 0
bodySize / candleRange <= bodyRatioThreshold
else
true
// Volume Confirmation:
// Volume on the Doji candle should be higher than average volume, indicating significant indecision.
avgVolume = ta.sma(volume, 20) // 20-period Simple Moving Average of Volume
isVolumeConfirmed = volume > avgVolume * 1.5 // Volume is 1.5x average
// Combined signal
confirmedDoji = isDoji and isVolumeConfirmed
// Plot confirmed signals
barcolor(confirmedDoji ? color.new(color.teal, 60) : na)
plotshape(confirmedDoji, title="Doji (Vol Confirmed)", location=location.belowbar, color=color.new(color.yellow, 0), style=shape.labeldown, size=size.small, text="Doji Vol")
// Optional: Plot volume for visual check
plot(volume, title="Volume", color=color.gray, style=plot.style_columns)
plot(avgVolume, title="Avg Volume", color=color.orange, style=plot.style_line)
3. Doji at Support/Resistance Zones
//@version=5
indicator("Doji at S/R Zones", overlay=true)
// User input for threshold to define a "small body"
bodyRatioThreshold = input.float(0.1, title="Doji Body Ratio Threshold", minval=0.01, maxval=0.5)
// Define sensitivity for S/R zone detection
srTolerance = input.float(0.005, title="S/R Zone Tolerance (as % of price)", minval=0.001, maxval=0.02)
// Calculate candle body size
bodySize = math.abs(close - open)
candleRange = high - low
isDoji = if candleRange > 0
bodySize / candleRange <= bodyRatioThreshold
else
true
// Simple S/R line detection (e.g., using previous swing highs/lows)
// This is a simplified example; real S/R can be complex.
lookback = input(20, "S/R Lookback Periods")
prevHigh = ta.highest(high[1], lookback)
prevLow = ta.lowest(low[1], lookback)
// Check if Doji is near Resistance
isNearResistance = isDoji and math.abs(high - prevHigh) / high <= srTolerance and close > open // Bullish close might be a breakout failure or test
// Check if Doji is near Support
isNearSupport = isDoji and math.abs(low - prevLow) / low <= srTolerance and close < open // Bearish close might be a breakdown failure or test
// Plot signals
plotshape(isNearResistance, title="Doji at Resistance", location=location.abovebar, color=color.new(color.red, 0), style=shape.square, size=size.normal, text="R-Doji")
plotshape(isNearSupport, title="Doji at Support", location=location.belowbar, color=color.new(color.green, 0), style=shape.square, size=size.normal, text="S-Doji")
// Plot S/R lines (for visual confirmation)
plot(prevHigh, "Previous High (Resistance)", color.red, linewidth=1, style=plot.style_stepline)
plot(prevLow, "Previous Low (Support)", color.green, linewidth=1, style=plot.style_stepline)
Optimizing Doji Pattern Performance
To maximize the effectiveness of Doji patterns in your Pine Script strategies:
- Context is Paramount: A Doji's meaning is highly dependent on the preceding price action and where it forms on the chart. A Doji after a strong trend is more significant than one in a choppy market.
- Confirmation: Always wait for confirmation from the next candle or other indicators. A Doji merely signals indecision; the subsequent candle confirms who won the battle between buyers and sellers.
- Volume Analysis: A Doji accompanied by high volume can indicate a significant battle between bulls and bears, suggesting a stronger potential reversal than a low-volume Doji.
- Support & Resistance: Doji patterns that form exactly at key support or resistance levels (or pivot points) are generally more reliable reversal signals.
- Timeframe: Doji on higher timeframes (e.g., daily, weekly) carry more weight and are more reliable for signaling significant shifts than those on lower timeframes.
Common Doji Pattern Pitfalls to Avoid
- Trading in Isolation: Never trade solely based on a Doji. Always combine it with other technical analysis tools (trendlines, moving averages, volume, oscillators) for confirmation.
- Ignoring Trend: A Doji has little significance in a sideways or ranging market where indecision is common. Its power comes from appearing after a sustained trend.
- Misinterpreting Small Body: A small body is essential, but the overall range and wick lengths distinguish between different Doji types and their implications.
- Assuming Reversal: A Doji signals indecision, but it doesn't guarantee a reversal. Price could consolidate before continuing in the original direction. Always wait for confirmation from the following candle.
- Over-Optimization: Don't try to create overly complex Doji detection rules that might fit historical data but fail in live trading. Keep rules simple and robust.
Conclusion
The Doji candlestick pattern is a foundational concept in technical analysis, offering invaluable insights into market indecision and potential turning points. While simple in appearance, its various forms (Standard, Long-Legged, Dragonfly, Gravestone, Four Price) each convey nuanced messages when interpreted within the correct market context. By implementing Doji detection in Pine Script, you can automate the identification of these critical moments, integrate them into broader trading strategies with confirmation from other indicators, and enhance your ability to anticipate shifts in market sentiment on TradingView. Remember, the Doji is a signal of pause; the subsequent price action confirms the new direction.