Strategy · Pine Script v5 · On the chart

Advanced Candlestick Pattern Strategy

by ChipaDevTeam

This strategy trades reversal candlestick patterns such as hammer, doji, engulfing, stars, harami, piercing line and shooting star on the price chart.

View on GitHub

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code341
Settings38inputs
LicenceApache-2.0
Last update6 months ago11 Apr 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

341 lines of Pine Script v5 from test_strategy.pine, published under Apache-2.0. Keep the author's credit and licence lines when you reuse it.

test_strategy.pine
//@version=5
strategy("Advanced Candlestick Pattern Strategy", overlay=true)

// ============================================
// INPUT PARAMETERS
// ============================================

// Pattern Detection Settings
patternStrength = input.int(3, "Pattern Strength", minval=1, maxval=5, group="Pattern Detection")
bodyRatio = input.float(0.65, "Body/Range Ratio", minval=0.1, maxval=0.9, step=0.05, group="Pattern Detection")
shadowRatio = input.float(2.2, "Shadow/Body Ratio", minval=1.0, maxval=5.0, step=0.1, group="Pattern Detection")
patternLookback = input.int(3, "Pattern Lookback", minval=1, maxval=10, group="Pattern Detection")
minPatternSize = input.float(0.5, "Min Pattern Size (ATR)", minval=0.3, maxval=2.0, step=0.1, group="Pattern Detection")

// Enable/Disable Patterns
enableHammer = input.bool(true, "Hammer & Hanging Man", group="Reversal Patterns")
enableDoji = input.bool(true, "Doji Family", group="Reversal Patterns")
enableEngulfing = input.bool(true, "Engulfing Patterns", group="Reversal Patterns")
enableStar = input.bool(true, "Morning/Evening Star", group="Reversal Patterns")
enableHarami = input.bool(true, "Harami Patterns", group="Reversal Patterns")
enablePiercing = input.bool(true, "Piercing Line/Dark Cloud", group="Reversal Patterns")
enableShootingStar = input.bool(true, "Shooting Star", group="Reversal Patterns")
enableInvertedHammer = input.bool(true, "Inverted Hammer", group="Reversal Patterns")

// Confirmation Settings
useVolumeConfirmation = input.bool(true, "Volume Confirmation", group="Confirmations")
volumeMultiplier = input.float(1.15, "Volume Multiple", minval=1.0, maxval=3.0, step=0.1, group="Confirmations")
useTrendConfirmation = input.bool(true, "Trend Confirmation", group="Confirmations")
trendPeriod = input.int(20, "Trend EMA Period", minval=5, maxval=50, group="Confirmations")
useRSIConfirmation = input.bool(true, "RSI Confirmation", group="Confirmations")
rsiPeriod = input.int(14, "RSI Period", minval=5, maxval=30, group="Confirmations")
rsiOverbought = input.int(70, "RSI Overbought", minval=60, maxval=90, group="Confirmations")
rsiOversold = input.int(30, "RSI Oversold", minval=10, maxval=40, group="Confirmations")
useMAConfirmation = input.bool(false, "Moving Average Filter", group="Confirmations")
maFastPeriod = input.int(9, "Fast MA Period", minval=5, maxval=20, group="Confirmations")
maSlowPeriod = input.int(21, "Slow MA Period", minval=10, maxval=50, group="Confirmations")
useVolatilityFilter = input.bool(false, "Volatility Filter", group="Confirmations")
volatilityPeriod = input.int(20, "Volatility Period", minval=10, maxval=50, group="Confirmations")
minVolatility = input.float(0.8, "Min Volatility Threshold", minval=0.5, maxval=3.0, step=0.1, group="Confirmations")

// Risk Management
stopLossType = input.string("ATR", "Stop Loss Type", options=["Percentage", "ATR", "Pattern Based"], group="Risk Management")
stopLossPercent = input.float(1.5, "Stop Loss %", minval=0.5, maxval=10, step=0.1, group="Risk Management")
atrPeriod = input.int(14, "ATR Period", minval=5, maxval=30, group="Risk Management")
atrMultiplier = input.float(1.6, "ATR Multiplier", minval=1.0, maxval=5.0, step=0.1, group="Risk Management")
takeProfitRatio = input.float(3.2, "Risk/Reward Ratio", minval=1.0, maxval=10.0, step=0.5, group="Risk Management")
useTrailingStop = input.bool(true, "Trailing Stop", group="Risk Management")
trailingStopPercent = input.float(1.0, "Trailing Stop %", minval=0.5, maxval=5.0, step=0.1, group="Risk Management")
useBreakeven = input.bool(true, "Move to Breakeven", group="Risk Management")
breakevenRatio = input.float(1.0, "Breakeven at R:R", minval=0.5, maxval=2.0, step=0.1, group="Risk Management")
useDynamicSizing = input.bool(true, "Dynamic Position Sizing", group="Risk Management")
maxRiskPerTrade = input.float(1.0, "Max Risk Per Trade %", minval=0.1, maxval=5.0, step=0.1, group="Risk Management")

// ============================================
// TECHNICAL INDICATORS
// ============================================

// ATR for volatility-based stops
atrValue = ta.atr(atrPeriod)

// Trend confirmation
ema = ta.ema(close, trendPeriod)
uptrend = close > ema
downtrend = close < ema

// Moving Average Filter
maFast = ta.ema(close, maFastPeriod)
maSlow = ta.ema(close, maSlowPeriod)
bullishTrendMA = maFast > maSlow and close > maFast
bearishTrendMA = maFast < maSlow and close < maFast

// RSI for momentum confirmation
rsi = ta.rsi(close, rsiPeriod)
rsiOverboughtCondition = rsi > rsiOverbought
rsiOversoldCondition = rsi < rsiOversold
rsiNeutral = rsi > 40 and rsi < 60

// Volume confirmation
avgVolume = ta.sma(volume, 20)
highVolume = volume > avgVolume * volumeMultiplier

// Volatility Filter
volatility = ta.stdev(ta.change(close), volatilityPeriod) / close * 100
highVolatility = volatility > minVolatility

// ============================================
// CANDLESTICK PATTERN FUNCTIONS
// ============================================

// Basic candle properties
bodySize = math.abs(close - open)
totalRange = high - low
upperShadow = high - math.max(close, open)
lowerShadow = math.min(close, open) - low
bodyRatioActual = totalRange > 0 ? bodySize / totalRange : 0
upperShadowRatio = bodySize > 0 ? upperShadow / bodySize : 0
lowerShadowRatio = bodySize > 0 ? lowerShadow / bodySize : 0

// Color determination
bullishCandle = close > open
bearishCandle = close < open

// ============================================
// PATTERN DETECTION FUNCTIONS
// ============================================

// Doji Pattern
isDoji() =>
    bodyRatioActual < 0.1 and totalRange > atrValue * 0.5

// Hammer Pattern (bullish reversal at bottom)
isHammer() => lowerShadow >= bodySize * shadowRatio and upperShadow <= bodySize * 0.5 and bodyRatioActual >= bodyRatio * 0.5 and bodyRatioActual <= 0.8

// Shooting Star Pattern (bearish reversal at top)
isShootingStar() => upperShadow >= bodySize * shadowRatio and lowerShadow <= bodySize * 0.5 and bodyRatioActual >= bodyRatio * 0.5 and bodyRatioActual <= 0.8

// Inverted Hammer (bullish reversal at bottom)
isInvertedHammer() => upperShadow >= bodySize * shadowRatio and lowerShadow <= bodySize * 0.5 and bodyRatioActual >= bodyRatio * 0.5

// Bullish Engulfing
isBullishEngulfing() => bearishCandle[1] and bullishCandle and open <= close[1] and close > open[1] and bodySize > bodySize[1] * 1.2

// Bearish Engulfing
isBearishEngulfing() => bullishCandle[1] and bearishCandle and open >= close[1] and close < open[1] and bodySize > bodySize[1] * 1.2

// Morning Star (3-candle bullish reversal)
isMorningStar() => bearishCandle[2] and bodySize[2] > atrValue and bodyRatioActual[1] < 0.3 and bullishCandle and close > (open[2] + close[2]) / 2

// Evening Star (3-candle bearish reversal)
isEveningStar() => bullishCandle[2] and bodySize[2] > atrValue and bodyRatioActual[1] < 0.3 and bearishCandle and close < (open[2] + close[2]) / 2

// Bullish Harami
isBullishHarami() => bearishCandle[1] and bullishCandle and open > close[1] and close < open[1] and bodySize < bodySize[1] * 0.7

// Bearish Harami
isBearishHarami() => bullishCandle[1] and bearishCandle and open < close[1] and close > open[1] and bodySize < bodySize[1] * 0.7

// Piercing Line (bullish reversal)
isPiercingLine() => bearishCandle[1] and bullishCandle and open < low[1] and close > (open[1] + close[1]) / 2 and close < open[1]

// Dark Cloud Cover (bearish reversal)
isDarkCloud() => bullishCandle[1] and bearishCandle and open > high[1] and close < (open[1] + close[1]) / 2 and close > open[1]

// ============================================
// PATTERN DETECTION LOGIC
// ============================================

// Bullish patterns
bullishDoji = enableDoji and isDoji() and downtrend
bullishHammer = enableHammer and isHammer() and downtrend
bullishInvertedHammer = enableInvertedHammer and isInvertedHammer() and downtrend
bullishEngulfing = enableEngulfing and isBullishEngulfing()
bullishMorningStar = enableStar and isMorningStar()
bullishHarami = enableHarami and isBullishHarami()
bullishPiercing = enablePiercing and isPiercingLine()

// Bearish patterns
bearishDoji = enableDoji and isDoji() and uptrend
bearishShootingStar = enableShootingStar and isShootingStar() and uptrend
bearishHangingMan = enableHammer and isHammer() and uptrend
bearishEngulfing = enableEngulfing and isBearishEngulfing()
bearishEveningStar = enableStar and isEveningStar()
bearishHarami = enableHarami and isBearishHarami()
bearishDarkCloud = enablePiercing and isDarkCloud()

// Combined pattern signals
bullishPatternDetected = bullishDoji or bullishHammer or bullishInvertedHammer or bullishEngulfing or bullishMorningStar or bullishHarami or bullishPiercing
bearishPatternDetected = bearishDoji or bearishShootingStar or bearishHangingMan or bearishEngulfing or bearishEveningStar or bearishHarami or bearishDarkCloud

// ============================================
// CONFIRMATION CONDITIONS
// ============================================

// Volume confirmation
volumeConfirmed = useVolumeConfirmation ? highVolume : true

// Trend confirmation - more relaxed
trendConfirmedBullish = useTrendConfirmation ? (close > ema * 0.99 or not uptrend) : true
trendConfirmedBearish = useTrendConfirmation ? (close < ema * 1.01 or not downtrend) : true

// MA confirmation
maConfirmedBullish = useMAConfirmation ? bullishTrendMA : true
maConfirmedBearish = useMAConfirmation ? bearishTrendMA : true

// RSI confirmation - more relaxed
rsiConfirmedBullish = useRSIConfirmation ? (rsi < 55 and not rsiOverboughtCondition) : true
rsiConfirmedBearish = useRSIConfirmation ? (rsi > 45 and not rsiOversoldCondition) : true

// Volatility confirmation
volatilityConfirmed = useVolatilityFilter ? highVolatility : true

// ============================================
// ENTRY CONDITIONS
// ============================================

// Long entry condition - balanced
longCondition = bullishPatternDetected and volumeConfirmed and trendConfirmedBullish and rsiConfirmedBullish

// Short entry condition - balanced
shortCondition = bearishPatternDetected and volumeConfirmed and trendConfirmedBearish and rsiConfirmedBearish

// ============================================
// STOP LOSS CALCULATION
// ============================================

calculateStopLoss(isLong) =>
    if stopLossType == "Percentage"
        if isLong
            close * (1 - stopLossPercent / 100)
        else
            close * (1 + stopLossPercent / 100)
    else if stopLossType == "ATR"
        if isLong
            close - atrValue * atrMultiplier
        else
            close + atrValue * atrMultiplier
    else // Pattern Based
        if isLong
            math.min(low, low[1]) - atrValue * 0.5
        else
            math.max(high, high[1]) + atrValue * 0.5

// ============================================
// POSITION MANAGEMENT
// ============================================

var float longStopLoss = na
var float shortStopLoss = na
var float longTakeProfit = na
var float shortTakeProfit = na

calculatePositionSize(stopDistance) =>
    if useDynamicSizing
        riskAmount = strategy.equity * maxRiskPerTrade / 100
        math.min(riskAmount / stopDistance, strategy.equity * 0.1)
    else
        strategy.equity * 0.08

// Execute long trades with dynamic sizing
if longCondition and strategy.position_size == 0
    stopLoss = calculateStopLoss(true)
    stopDistance = close - stopLoss
    takeProfit = close + stopDistance * takeProfitRatio
    posSize = calculatePositionSize(stopDistance)
    
    strategy.entry("Long", strategy.long, qty=posSize)
    longStopLoss := stopLoss
    longTakeProfit := takeProfit

// Execute short trades with dynamic sizing
if shortCondition and strategy.position_size == 0
    stopLoss = calculateStopLoss(false)
    stopDistance = stopLoss - close
    takeProfit = close - stopDistance * takeProfitRatio
    posSize = calculatePositionSize(stopDistance)
    
    strategy.entry("Short", strategy.short, qty=posSize)
    shortStopLoss := stopLoss
    shortTakeProfit := takeProfit

// Breakeven logic
if useBreakeven and strategy.position_size > 0
    breakevenPrice = strategy.position_avg_price + (longTakeProfit - strategy.position_avg_price) * breakevenRatio / takeProfitRatio
    if close >= breakevenPrice and longStopLoss < strategy.position_avg_price
        longStopLoss := strategy.position_avg_price + atrValue * 0.1

if useBreakeven and strategy.position_size < 0
    breakevenPrice = strategy.position_avg_price - (strategy.position_avg_price - shortTakeProfit) * breakevenRatio / takeProfitRatio
    if close <= breakevenPrice and shortStopLoss > strategy.position_avg_price
        shortStopLoss := strategy.position_avg_price - atrValue * 0.1

// Partial profit taking
if strategy.position_size > 0
    // Take 30% profit at 1.5R
    if close >= strategy.position_avg_price + (longTakeProfit - strategy.position_avg_price) * 0.6
        strategy.close("Long", qty_percent=30, comment="Partial TP 1")
    
    // Take another 30% at 2R
    if close >= strategy.position_avg_price + (longTakeProfit - strategy.position_avg_price) * 0.8
        strategy.close("Long", qty_percent=30, comment="Partial TP 2")
    
    strategy.exit("Long Exit", "Long", stop=longStopLoss, limit=longTakeProfit)
    
    // Enhanced trailing stop
    if useTrailingStop and close > strategy.position_avg_price * (1 + trailingStopPercent / 100)
        trailDistance = atrValue * 1.5
        newStop = close - trailDistance
        if newStop > longStopLoss
            longStopLoss := newStop

if strategy.position_size < 0
    // Take 30% profit at 1.5R
    if close <= strategy.position_avg_price - (strategy.position_avg_price - shortTakeProfit) * 0.6
        strategy.close("Short", qty_percent=30, comment="Partial TP 1")
    
    // Take another 30% at 2R
    if close <= strategy.position_avg_price - (strategy.position_avg_price - shortTakeProfit) * 0.8
        strategy.close("Short", qty_percent=30, comment="Partial TP 2")
    
    strategy.exit("Short Exit", "Short", stop=shortStopLoss, limit=shortTakeProfit)
    
    // Enhanced trailing stop
    if useTrailingStop and close < strategy.position_avg_price * (1 - trailingStopPercent / 100)
        trailDistance = atrValue * 1.5
        newStop = close + trailDistance
        if newStop < shortStopLoss
            shortStopLoss := newStop

// ============================================
// VISUALIZATION
// ============================================

// Plot trend EMA
plot(ema, "Trend EMA", color=color.orange, linewidth=1)
plot(maFast, "Fast MA", color=color.blue, linewidth=1)
plot(maSlow, "Slow MA", color=color.red, linewidth=1)

// Plot pattern signals
// Plot pattern signals
plotshape(bullishPatternDetected and volumeConfirmed, title="Bullish Pattern", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(bearishPatternDetected and volumeConfirmed, title="Bearish Pattern", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)

// Plot entry signals
plotshape(longCondition, title="Long Entry", location=location.belowbar, color=color.lime, style=shape.arrowup, size=size.normal)
plotshape(shortCondition, title="Short Entry", location=location.abovebar, color=color.fuchsia, style=shape.arrowdown, size=size.normal)

// Plot stop levels
plot(strategy.position_size > 0 ? longStopLoss : na, "Long Stop", color=color.red, style=plot.style_linebr)
plot(strategy.position_size < 0 ? shortStopLoss : na, "Short Stop", color=color.red, style=plot.style_linebr)
plot(strategy.position_size > 0 ? longTakeProfit : na, "Long Target", color=color.green, style=plot.style_linebr)
plot(strategy.position_size < 0 ? shortTakeProfit : na, "Short Target", color=color.green, style=plot.style_linebr)

// Background color for trend
bgcolor(uptrend ? color.new(color.green, 95) : color.new(color.red, 95), title="Trend Background")

// ============================================
// ALERTS
// ============================================

alertcondition(longCondition, title="Bullish Pattern Alert", message="Bullish candlestick pattern detected - Consider LONG")
alertcondition(shortCondition, title="Bearish Pattern Alert", message="Bearish candlestick pattern detected - Consider SHORT")

Overview

Pattern strength, ratios and size are adjustable, and optional filters use volume, a trend EMA, RSI, moving averages and a volatility minimum. Stop loss can be a percentage, an ATR multiple or pattern based, with a take profit from a risk to reward ratio and an optional trailing stop. It is the strategy version of a matching indicator.

Details

Published by

ChipaDevTeam on GitHub

Type

Strategy, Pine Script v5

Draws

On the price chart

Category

Candlestick patterns

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Pattern Strengthint3patternStrength
Body/Range Ratiofloat0.65bodyRatio
Shadow/Body Ratiofloat2.2shadowRatio
Pattern Lookbackint3patternLookback
Min Pattern Size (ATR)float0.5minPatternSize
Hammer & Hanging ManbooltrueenableHammer
Doji FamilybooltrueenableDoji
Engulfing PatternsbooltrueenableEngulfing
Morning/Evening StarbooltrueenableStar
Harami PatternsbooltrueenableHarami
Piercing Line/Dark CloudbooltrueenablePiercing
Shooting StarbooltrueenableShootingStar
Show all 38 settings
SettingTypeDefaultVariable
Inverted HammerbooltrueenableInvertedHammer
Volume ConfirmationbooltrueuseVolumeConfirmation
Volume Multiplefloat1.15volumeMultiplier
Trend ConfirmationbooltrueuseTrendConfirmation
Trend EMA Periodint20trendPeriod
RSI ConfirmationbooltrueuseRSIConfirmation
RSI Periodint14rsiPeriod
RSI Overboughtint70rsiOverbought
RSI Oversoldint30rsiOversold
Moving Average FilterboolfalseuseMAConfirmation
Fast MA Periodint9maFastPeriod
Slow MA Periodint21maSlowPeriod
Volatility FilterboolfalseuseVolatilityFilter
Volatility Periodint20volatilityPeriod
Min Volatility Thresholdfloat0.8minVolatility
Stop Loss TypestringATRstopLossType
Stop Loss %float1.5stopLossPercent
ATR Periodint14atrPeriod
ATR Multiplierfloat1.6atrMultiplier
Risk/Reward Ratiofloat3.2takeProfitRatio
Trailing StopbooltrueuseTrailingStop
Trailing Stop %float1.0trailingStopPercent
Move to BreakevenbooltrueuseBreakeven
Breakeven at R:Rfloat1.0breakevenRatio
Dynamic Position SizingbooltrueuseDynamicSizing
Max Risk Per Trade %float1.0maxRiskPerTrade
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

330 stars

Exceeded Candle [Alorse] is a mean-reversion strategy that identifies candlestick engulfing patterns combined with Bollinger Bands filters. It enters a long position when a green candle surpasses the body of the previous red candle while price is below the mid

Strategy v4 Mean reversionCandlestick patterns
Updated 2 months ago · None stated GitHub repository of Exceeded candle [Alorse]
285 stars

Mean Reversion Strategy is an overlay strategy that identifies pullbacks using a long-term EMA, RSI, and candlestick patterns. It generates long signals when a bullish engulfing candle forms below the EMA while RSI is oversold, and short signals when a bearish

Strategy v4 Mean reversionCandlestick patterns
Updated 3 years ago · None stated GitHub repository of Mean Reversion Strategy

ESU2023-10M - V1

by dearvn
257 stars

ESU2023-10M - V1 is an intraday trend-reversal strategy designed for index futures contracts on the price chart. It calculates a 3-period moving average of candle highs and lows alongside specific three-bar price action patterns to detect short-term swing high

Strategy v5 TrendCandlestick patterns
Updated 6 weeks ago · None stated GitHub repository of ESU2023-10M - V1

STRG One Bar Pursuit

by harryguiacorn
219 stars

The STRG One Bar Pursuit strategy identifies single-bar momentum reversals by monitoring shifts between bullish and bearish candlesticks starting from the year 2024. It enters a long position when a bullish candle follows a bearish candle and enters a short po

Strategy v5 Candlestick patternsMean reversion
Updated 1 year ago · None stated GitHub repository of STRG One Bar Pursuit
218 stars

This strategy identifies trade opportunities based on candlestick wick imbalances relative to the Average True Range. It enters positions when candle wicks exceed defined thresholds and filters out doji candles using a minimum body ATR requirement. Exits are h

Strategy v6 Candlestick patternsVolatility & bands Repaints
Updated 3 months ago · None stated GitHub repository of Super Negative R:R Wick Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers