Pine Script: Master Harami Candlestick Patterns (Bullish & Bearish)

Decode market indecision and potential reversals with this comprehensive guide to detecting and strategizing with Harami patterns in TradingView's Pine Script.

Posted: Expertise: Intermediate/Advanced

Why Harami Patterns Matter in Pine Script

The Harami candlestick pattern is a two-candle reversal pattern that signals market indecision and a potential shift in momentum. The word "Harami" means "pregnant" in Japanese, referring to the pattern's appearance where a small second candle is "pregnant" within the larger body of the first candle. Unlike engulfing patterns which show aggression, Harami patterns indicate a slowdown or exhaustion of the previous trend, making them valuable for:

Understanding Bullish and Bearish Harami Patterns

A Harami pattern consists of two candles with distinct characteristics:

  1. First Candle (Large Body): A large candle (bullish or bearish, depending on the preceding trend) indicating strong directional movement.
  2. Second Candle (Small Body/Inside Bar): A small-bodied candle (can be bullish or bearish) that opens and closes *completely within the real body* of the first candle. The second candle is often referred to as an "inside bar."

The color of the second candle is generally opposite to the first, but the key is that its body is contained within the first. The overall pattern suggests that the strong directional move of the first candle was followed by a period of consolidation or indecision, indicating a loss of momentum.

Bullish Harami Pattern

Inside Bar

A large bearish candle followed by a small bullish candle whose entire body is contained within the body of the first. Often after a downtrend.

Bearish Harami Pattern

Inside Bar

A large bullish candle followed by a small bearish candle whose entire body is contained within the body of the first. Often after an uptrend.

Key Characteristics:

Basic Harami Pattern Detection in Pine Script

Here's how to create a basic indicator to detect both Bullish and Bearish Harami patterns in Pine Script v5:

//@version=5
indicator("Harami Pattern Detector", overlay=true)

// User input for body size thresholds
largeBodyMinRatio = input.float(0.5, title="Large Body Min Ratio (of ATR)", minval=0.1, maxval=1.0)
smallBodyMaxRatio = input.float(0.3, title="Small Body Max Ratio (of ATR)", minval=0.01, maxval=0.5)

// Helper function to check if a candle's body is large relative to ATR
isLargeBody(idx) =>
    math.abs(close[idx] - open[idx]) > ta.atr(14)[idx] * largeBodyMinRatio

// Helper function to check if a candle's body is small relative to ATR
isSmallBody(idx) =>
    math.abs(close[idx] - open[idx]) < ta.atr(14)[idx] * smallBodyMaxRatio

// --- Bullish Harami Criteria ---
// 1. Previous candle is a large bearish candle
isC1BearishLarge = close[1] < open[1] and isLargeBody(1)

// 2. Current candle is a small bullish candle
isC2BullishSmall = close > open and isSmallBody(0) // 0 for current bar

// 3. Current candle's body is completely contained within the previous candle's body
// This means current high is below prev open (for bearish C1), and current low is above prev close (for bearish C1)
isC2InsideC1Body = math.max(open, close) < open[1] and math.min(open, close) > close[1]

// Combine for Bullish Harami
isBullishHarami = isC1BearishLarge and isC2BullishSmall and isC2InsideC1Body

// --- Bearish Harami Criteria ---
// 1. Previous candle is a large bullish candle
isC1BullishLarge = close[1] > open[1] and isLargeBody(1)

// 2. Current candle is a small bearish candle
isC2BearishSmall = close < open and isSmallBody(0) // 0 for current bar

// 3. Current candle's body is completely contained within the previous candle's body
// This means current high is below prev close (for bullish C1), and current low is above prev open (for bullish C1)
isC2InsideC1BodyBearish = math.max(open, close) < close[1] and math.min(open, close) > open[1]

// Combine for Bearish Harami
isBearishHarami = isC1BullishLarge and isC2BearishSmall and isC2InsideC1BodyBearish

// Plot signals on the chart
plotshape(isBullishHarami, title="Bullish Harami", location=location.belowbar, color=color.new(color.green, 0), style=shape.triangleup, size=size.small)
plotshape(isBearishHarami, title="Bearish Harami", location=location.abovebar, color=color.new(color.red, 0), style=shape.triangledown, size=size.small)

// Alert conditions (optional)
alertcondition(isBullishHarami, title="Bullish Harami Alert", message="Bullish Harami Pattern Detected!")
alertcondition(isBearishHarami, title="Bearish Harami Alert", message="Bearish Harami Pattern Detected!")

Advanced Harami Strategies

Harami patterns signal indecision, but their true power emerges when confirmed by the market context and other indicators. They act as "warnings" that the trend might be losing steam.

1. Harami with Trend Confirmation (Using Moving Average)

//@version=5
strategy("Harami 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

// Harami Pattern Detection (simplified from basic example)
largeBodyMinRatio = 0.5
smallBodyMaxRatio = 0.3

isLargeBody(idx) => math.abs(close[idx] - open[idx]) > ta.atr(14)[idx] * largeBodyMinRatio
isSmallBody(idx) => math.abs(close[idx] - open[idx]) < ta.atr(14)[idx] * smallBodyMaxRatio

// Bullish Harami
isC1BearishLarge = close[1] < open[1] and isLargeBody(1)
isC2BullishSmall = close > open and isSmallBody(0)
isC2InsideC1Body = math.max(open, close) < open[1] and math.min(open, close) > close[1]
isBullishHarami = isC1BearishLarge and isC2BullishSmall and isC2InsideC1Body

// Bearish Harami
isC1BullishLarge = close[1] > open[1] and isLargeBody(1)
isC2BearishSmall = close < open and isSmallBody(0)
isC2InsideC1BodyBearish = math.max(open, close) < close[1] and math.min(open, close) > open[1]
isBearishHarami = isC1BullishLarge and isC2BearishSmall and isC2InsideC1BodyBearish

// Trend Context:
// Bullish Harami is more significant after a downtrend (price below MA)
isDowntrend = close < ma and ma < ma[1]
// Bearish Harami is more significant after an uptrend (price above MA)
isUptrend = close > ma and ma > ma[1]

// Strategy Logic with Trend Confirmation
longSignal = isBullishHarami and isDowntrend
shortSignal = isBearishHarami and isUptrend // Corrected typo from `isBearamiHarami`

if (longSignal)
    strategy.entry("Long", strategy.long)
    
if (shortSignal)
    strategy.entry("Short", strategy.short)

// Plot MA
plot(ma, "Trend MA", color.blue)

// Plot confirmed signals
plotshape(longSignal, title="Confirmed Bullish Harami", location=location.belowbar, color=color.new(color.navy, 0), style=shape.arrowup, size=size.normal)
plotshape(shortSignal, title="Confirmed Bearish Harami", location=location.abovebar, color=color.new(color.fuchsia, 0), style=shape.arrowdown, size=size.normal)

2. Harami with Volume Confirmation

//@version=5
indicator("Harami with Volume Confirmation", overlay=true)

// Harami Pattern Detection (simplified)
largeBodyMinRatio = 0.5
smallBodyMaxRatio = 0.3

isLargeBody(idx) => math.abs(close[idx] - open[idx]) > ta.atr(14)[idx] * largeBodyMinRatio
isSmallBody(idx) => math.abs(close[idx] - open[idx]) < ta.atr(14)[idx] * smallBodyMaxRatio

isC1BearishLarge = close[1] < open[1] and isLargeBody(1)
isC2BullishSmall = close > open and isSmallBody(0)
isC2InsideC1Body = math.max(open, close) < open[1] and math.min(open, close) > close[1]
isBullishHarami = isC1BearishLarge and isC2BullishSmall and isC2InsideC1Body

isC1BullishLarge = close[1] > open[1] and isLargeBody(1)
isC2BearishSmall = close < open and isSmallBody(0)
isC2InsideC1BodyBearish = math.max(open, close) < close[1] and math.min(open, close) > open[1]
isBearishHarami = isC1BullishLarge and isC2BearishSmall and isC2InsideC1BodyBearish


// Volume Confirmation:
// Volume on the second (smaller) candle should be lower than the first, indicating reduced momentum.
// Or, if it's a "Harami Cross" (second candle is a Doji), volume might be significant.
// For general Harami, reduced volume on the second candle emphasizes indecision.
isVolumeReduced = volume < volume[1] * 0.8 // Current volume is less than 80% of previous

// Combined signals
confirmedBullishHarami = isBullishHarami and isVolumeReduced
confirmedBearishHarami = isBearishHarami and isVolumeReduced

// Plot confirmed signals
barcolor(confirmedBullishHarami ? color.new(color.aqua, 60) : na)
barcolor(confirmedBearishHarami ? color.new(color.purple, 60) : na)

plotshape(confirmedBullishHarami, title="Bullish Harami (Vol Reduced)", location=location.belowbar, color=color.new(color.green, 0), style=shape.labelup, size=size.small, text="BH Vol")
plotshape(confirmedBearishHarami, title="Bearish Harami (Vol Reduced)", location=location.abovebar, color=color.new(color.red, 0), style=shape.labeldown, size=size.small, text="BB Vol")

// Optional: Plot volume for visual check
plot(volume, title="Volume", color=color.gray, style=plot.style_columns)

3. Harami with RSI Confirmation

//@version=5
indicator("Harami with RSI Confirmation", overlay=true)

// RSI Inputs
rsiLength = input(14, "RSI Length")
overbought = input(70, "RSI Overbought Level")
oversold = input(30, "RSI Oversold Level")

// Calculate RSI
rsiValue = ta.rsi(close, rsiLength)

// Harami Pattern Detection (simplified)
largeBodyMinRatio = 0.5
smallBodyMaxRatio = 0.3

isLargeBody(idx) => math.abs(close[idx] - open[idx]) > ta.atr(14)[idx] * largeBodyMinRatio
isSmallBody(idx) => math.abs(close[idx] - open[idx]) < ta.atr(14)[idx] * smallBodyMaxRatio

isC1BearishLarge = close[1] < open[1] and isLargeBody(1)
isC2BullishSmall = close > open and isSmallBody(0)
isC2InsideC1Body = math.max(open, close) < open[1] and math.min(open, close) > close[1]
isBullishHarami = isC1BearishLarge and isC2BullishSmall and isC2InsideC1Body

isC1BullishLarge = close[1] > open[1] and isLargeBody(1)
isC2BearishSmall = close < open and isSmallBody(0)
isC2InsideC1BodyBearish = math.max(open, close) < close[1] and math.min(open, close) > open[1]
isBearishHarami = isC1BullishLarge and isC2BearishSmall and isC2InsideC1BodyBearish

// RSI Confirmation:
// Bullish Harami: RSI in oversold territory or showing bullish divergence
rsiBullishConfirm = rsiValue <= oversold or (rsiValue[1] < oversold and rsiValue > rsiValue[1])
// Bearish Harami: RSI in overbought territory or showing bearish divergence
rsiBearishConfirm = rsiValue >= overbought or (rsiValue[1] > overbought and rsiValue < rsiValue[1])

// Combined signals
signalBullishHarami = isBullishHarami and rsiBullishConfirm
signalBearishHarami = isBearishHarami and rsiBearishConfirm

// Plot signals
plotshape(signalBullishHarami, title="Bullish Harami (RSI Confirmed)", location=location.belowbar, color=color.new(color.lime, 0), style=shape.arrowup, size=size.normal)
plotshape(signalBearishHarami, title="Bearish Harami (RSI Confirmed)", location=location.abovebar, color=color.new(color.orange, 0), style=shape.arrowdown, size=size.normal)

// Plot RSI in a separate pane
plot(rsiValue, "RSI", color.blue, linewidth=2, display=display.pane)
hline(overbought, "Overbought", color.red)
hline(oversold, "Oversold", color.green)

Optimizing Harami Pattern Performance

To maximize the effectiveness of Harami patterns in your Pine Script strategies:

Common Harami Pattern Pitfalls to Avoid

Warning: The Harami is a pattern of indecision. Do not interpret it as an immediate strong reversal signal without further confirmation and contextual analysis.

Conclusion

The Harami candlestick pattern is a subtle yet powerful signal of market indecision and potential trend exhaustion. By understanding its precise two-candle formation—where the second candle's body is contained within the first's—and its contextual importance after a clear trend, you can leverage it effectively in your trading. Implementing Harami detection in Pine Script allows you to automate signal generation, combine it with complementary indicators like volume and oscillators for higher probability trades, and enhance your price action analysis to make more informed trading decisions on TradingView. Remember, the Harami is a yellow light, signaling caution and the need for confirmation before a potential shift in direction.