1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
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.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Pattern Strength
int
3
patternStrength
Body/Range Ratio
float
0.65
bodyRatio
Shadow/Body Ratio
float
2.2
shadowRatio
Pattern Lookback
int
3
patternLookback
Min Pattern Size (ATR)
float
0.5
minPatternSize
Hammer & Hanging Man
bool
true
enableHammer
Doji Family
bool
true
enableDoji
Engulfing Patterns
bool
true
enableEngulfing
Morning/Evening Star
bool
true
enableStar
Harami Patterns
bool
true
enableHarami
Piercing Line/Dark Cloud
bool
true
enablePiercing
Shooting Star
bool
true
enableShootingStar
Show all 38 settings
Setting
Type
Default
Variable
Inverted Hammer
bool
true
enableInvertedHammer
Volume Confirmation
bool
true
useVolumeConfirmation
Volume Multiple
float
1.15
volumeMultiplier
Trend Confirmation
bool
true
useTrendConfirmation
Trend EMA Period
int
20
trendPeriod
RSI Confirmation
bool
true
useRSIConfirmation
RSI Period
int
14
rsiPeriod
RSI Overbought
int
70
rsiOverbought
RSI Oversold
int
30
rsiOversold
Moving Average Filter
bool
false
useMAConfirmation
Fast MA Period
int
9
maFastPeriod
Slow MA Period
int
21
maSlowPeriod
Volatility Filter
bool
false
useVolatilityFilter
Volatility Period
int
20
volatilityPeriod
Min Volatility Threshold
float
0.8
minVolatility
Stop Loss Type
string
ATR
stopLossType
Stop Loss %
float
1.5
stopLossPercent
ATR Period
int
14
atrPeriod
ATR Multiplier
float
1.6
atrMultiplier
Risk/Reward Ratio
float
3.2
takeProfitRatio
Trailing Stop
bool
true
useTrailingStop
Trailing Stop %
float
1.0
trailingStopPercent
Move to Breakeven
bool
true
useBreakeven
Breakeven at R:R
float
1.0
breakevenRatio
Dynamic Position Sizing
bool
true
useDynamicSizing
Max Risk Per Trade %
float
1.0
maxRiskPerTrade
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.
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
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
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
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
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
This strategy identifies multiple classic candlestick patterns, including Engulfing, Harami, Morning and Evening Stars, and Three White Soldiers. It executes trades directly on the price chart when selected bullish or bearish patterns trigger. Users can toggle