Smarter Pullback + Candlestick Pattern (Steven Hart)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © hanabil

//@version=5
indicator("Smarter Pullback + Candlestick Pattern", overlay=true)

gr1             = 'Pullback'
minimumPullback = input.int(2, 'Previous Candle of Pullback', 1, 5, group=gr1)

gr2             = 'Candlestick Pattern of Pullback'
engulfing       = input(true, 'Engulfing', group=gr2)
doji            = input(true, 'Doji', group=gr2)
hs              = input(true, 'Hammer - Shooting Star', group=gr2)

gr3             = 'EMA Trend Filter'
trendFilter     = input(true, 'Trend Filter By EMA', group=gr3)
emaLen          = input(50, 'EMA Period', group=gr3)
ema             = ta.ema(close, emaLen)

gr4             = 'Styling'
showPattern     = input(true, 'Show Pattern Name', group=gr4)
textCol         = input.color(color.white, 'Text Color', group=gr4)
bullText        = input('🔼', 'Bull', '', '1', gr4)
bullCol         = input.color(#2962ff, '', '', '1', gr4)
bearText        = input('🔽', 'Bear', '', '2', gr4)
bearCol         = input.color(#f23645, '', '', '2', gr4)

fLabel(x, y, pn)=>
    labelStyle  = y==high? label.style_label_down : label.style_label_up
    labelCol    = y==high? bearCol  : bullCol
    labelText_  = y==high? bearText : bullText
    labelText   = showPattern? labelText_ + pn : labelText_
    if x
        label.new(bar_index, y, labelText, style=labelStyle, color=labelCol, size=size.small, textcolor=textCol)


plot(ema, 'EMA', color=color.blue)
bullEmaFilter   = close>ema
bearEmaFilter   = close<ema

isGreen         = close>open
isRed           = close<open

prevIs(x, y)=>
    y<=2? x[1] and x[2] :
     y<=3? x[1] and x[2] and x[3] :
     y<=4? x[1] and x[2] and x[3] and x[4] :
     y<=5? x[1] and x[2] and x[3] and x[4] and x[5] : na

bullPb      = prevIs(isRed  , minimumPullback)
bearPb      = prevIs(isGreen, minimumPullback)

// Engulfing
bullEngulf  = open<=close[1] and open<open[1] and close>open[1]
bearEngulf  = open>=close[1] and open>open[1] and close<open[1]
bullPbEn    = bullEngulf and bullPb and bullEmaFilter and engulfing
bearPbEn    = bearEngulf and bearPb and bearEmaFilter and engulfing

fLabel(bullPbEn, low , ' EN')
fLabel(bearPbEn, high, ' EN')
alertcondition(bullPbEn, 'Bull Engulfing Pullback', 'Bull Engulfing Pullback Found')
alertcondition(bearPbEn, 'Bear Engulfing Pullback', 'Bear Engulfing Pullback Found')


// Doji
wickPercent = 5.0
wickEqualPercent = 100.0
bodyPercent = 5.0
factor      = 2

bodyHi      = math.max(close, open)
bodyLo      = math.min(close, open)
body        = bodyHi - bodyLo
shadowUp    = high - bodyHi
shadowDn    = bodyLo - low
candleRange = high-low
shadowSize  = shadowUp == shadowDn or (math.abs(shadowUp - shadowDn) / shadowDn * 100) < wickEqualPercent and (math.abs(shadowDn - shadowUp) / shadowUp * 100) < wickEqualPercent
bodyAvg     = ta.ema(body, 14)
smallBody   = body < bodyAvg
hasShadowUp = shadowUp > wickPercent / 100 * body
hasShadowDn = shadowDn > wickPercent / 100 * body

isDojiBody  = candleRange > 0 and body <= candleRange * bodyPercent / 100
isDoji      = isDojiBody and shadowSize

bullPbDj    = isDoji[1] and bullPb and bullEmaFilter and doji
bearPbDj    = isDoji[1] and bearPb and bearEmaFilter and doji

fLabel(bullPbDj, low , ' DJ')
fLabel(bearPbDj, high, ' DJ')
alertcondition(bullPbDj, 'Bull Doji Pullback', 'Bull Doji Pullback Found')
alertcondition(bearPbDj, 'Bear Doji Pullback', 'Bear Doji Pullback Found')

// Hammer - Shooting Star
bullHs      = smallBody and body > 0 and bodyLo > hl2 and (shadowDn >= factor * body) and not hasShadowUp
bearHs      = smallBody and body > 0 and bodyHi < hl2 and (shadowUp >= factor * body) and not hasShadowDn

bullPbHs    = bullHs and bullPb and bullEmaFilter and hs
bearPbHs    = bearHs and bearPb and bearEmaFilter and hs

fLabel(bullPbHs, low , ' H')
fLabel(bearPbHs, high, ' SS')
alertcondition(bullPbHs, 'Bull Hammer Pullback', 'Bull Hammer Pullback Found')
alertcondition(bearPbHs, 'Bear Shooting-Star Pullback', 'Bear Shooting-Star Pullback Found')


// ------
// quotes
gr50        = 'QUOTES'
showTable   = input(true, 'Show Quotes Table', group=gr50)
quote       = input('Keep Spirit 😗', 'Drop Your Quotes Here', group=gr50)
tabPosI_    = input.string('Top', 'Table Position', ['Top', 'Middle', 'Bot'], group=gr50)
tabPos_     = tabPosI_=='Top'? position.top_right : tabPosI_=='Bot'? position.bottom_right : position.middle_right
tabColor    = input.color(color.new(#512da8, 35) , 'Background', group=gr50)
borderCol   = input.color(color.black , 'Border', group=gr50)
tabTextCol  = input.color(color.white, 'Text', group=gr50)

var saTable     = table.new(tabPos_, 10, 10, tabColor, borderCol, 1, borderCol, 1)
if showTable
    table.cell(saTable, 0, 0, '🎓 SmarterAlgo 🎓', text_color=tabTextCol, text_size=size.small)
    table.cell(saTable, 0, 1, quote, text_color=tabTextCol, text_size=size.small)
    












