Japanese Candlestick Patterns
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Marceeelll

//@version=5
indicator("Japanese Candlestick Patterns", overlay=true, max_labels_count = 500)

import Marceeelll/JapaneseCandlestickPatterns/1 as jcp


///////////////////
// --- TREND --- //
///////////////////

var GROUP_TREND = "TREND"
C_TrendRuleSMA = "SMA"
I_TrendRule = input.string(C_TrendRuleSMA, "Detect Trend Based On", options = [C_TrendRuleSMA, "No Trend"], group = GROUP_TREND)
I_TrendLength = input.int(50, 'Trend Length', 0, group = GROUP_TREND)
I_PlotTrendLine = input.bool(true, 'Show Trend Line', group = GROUP_TREND)

C_IsDownTrend = true
C_IsUpTrend = true

sma = ta.sma(close, I_TrendLength)
plot(I_TrendRule == C_TrendRuleSMA and I_PlotTrendLine ? sma : na, color = color.red, title = "Trend Line")

if I_TrendRule == C_TrendRuleSMA
    C_IsDownTrend := close < sma
    C_IsUpTrend := close > sma


/////////////////////////////
// --- CANDLE SETTINGS --- //
/////////////////////////////

I_CandleType = input.string(title = "Pattern Type", defval="Both", options=["Bullish", "Bearish", "Both"])
C_IsCandleTypeBoth = I_CandleType == "Both"
C_IsCandleTypeBearish = I_CandleType == "Bearish"
C_IsCandleTypeBullish = I_CandleType == "Bullish"


///////////////////
// --- STYLE --- //
///////////////////

var GROUP_STYLE = "Style"
C_LabelColorBullish = input(color.rgb(73, 151, 75), "Label Color Bullish", group = GROUP_STYLE)
C_LabelColorBearish = input(color.rgb(195, 67, 67), "Label Color Bearish", group = GROUP_STYLE)
C_LabelColorNeutral = input(color.gray, "Label Color Neutral", group = GROUP_STYLE)


////////////////////////////////
// --- DETECTION SETTINGS --- //
////////////////////////////////

var GROUP_REVERSAL_PATTERNS = "Reversal Patterns"
I_ShowCounterattackLines = input(title ="Counterattack Lines", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowDarkCloudCover = input(title="Dark-Cloud Cover", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowEngulfing = input(title="Engulfing", defval = true, group=GROUP_REVERSAL_PATTERNS)
I_ShowHammer = input(title="Hammer", defval=true, group=GROUP_REVERSAL_PATTERNS)
I_ShowHangingMan = input(title="Hanging Man", defval=true, group=GROUP_REVERSAL_PATTERNS)
I_ShowHarami = input(title ="Harami", defval=true, group=GROUP_REVERSAL_PATTERNS)
I_ShowInNeck = input(title="In Neck", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowOnNeck = input(title="On Neck", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowPiercing = input(title="Piercing", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowThreeBlackCrows = input(title ="Three Black Crows", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowThrusting = input(title="Thrusting", defval=false, group=GROUP_REVERSAL_PATTERNS)
I_ShowUpsideGapTwoCrows = input(title ="Upside Gap Two Crows", defval=false, group=GROUP_REVERSAL_PATTERNS)

var GROUP_STARS_PATTERNS = "Stars"
I_ShowAbandonedBaby = input(title ="Abandoned Baby", defval=false, group=GROUP_STARS_PATTERNS)
I_ShowEveningStar = input(title ="Evening star", defval=true, group=GROUP_STARS_PATTERNS)
I_ShowInvertedHammer = input(title ="Inverted Hammer", defval=true, group=GROUP_STARS_PATTERNS)
I_ShowMorningStar = input(title ="Morning Star", defval=true, group=GROUP_STARS_PATTERNS)
I_ShowShootingStar = input(title ="Shooting Star", defval=false, group=GROUP_STARS_PATTERNS)

var GROUP_DOJI_PATTERNS = "Doji"
I_ShowDoji = input(title="Doji", defval = false, group=GROUP_DOJI_PATTERNS)
I_ShowDragonflyDoji = input(title="Dragonfly Doji", defval = false, group=GROUP_DOJI_PATTERNS)
I_ShowEveningDojiStar = input(title="Evening Doji Star", defval = true, group=GROUP_DOJI_PATTERNS)
I_ShowGravestoneDoji = input(title="Gravestone Doji", defval = false, group=GROUP_DOJI_PATTERNS)
I_ShowLongLeggedDoji = input(title="Long Legged Doji", defval = false, group=GROUP_DOJI_PATTERNS)
I_ShowMorningDojiStar = input(title="Morning Doji Star", defval = true, group=GROUP_DOJI_PATTERNS)

var GROUP_CONTINUATION_PATTERNS = "Continuation Patterns"
I_ShowRisingThreeMethods = input(title ="Falling Three Methods", defval=false, group=GROUP_CONTINUATION_PATTERNS)
I_ShowFallingThreeMethods = input(title ="Rising Three Methods", defval=false, group=GROUP_CONTINUATION_PATTERNS)
I_ShowTasuki = input(title ="Tasuki", defval=false, group=GROUP_CONTINUATION_PATTERNS)

var GROUP_UTILITY_PATTERNS = "Utility"
I_ShowLongLowerShadow = input(title ="Long Lower Shadow", defval=false, group=GROUP_UTILITY_PATTERNS)
I_ShowLongUpperShadow = input(title ="Long Upper Shadow", defval=false, group=GROUP_UTILITY_PATTERNS)


////////////////////
// --- LABELS --- //
////////////////////

LABEL_BULLISH_TITLES = array.new_string()
LABEL_BULLISH_DESCRIPTIONS = array.new_string()
LABEL_BEARISH_TITLES = array.new_string()
LABEL_BEARISH_DESCRIPTIONS = array.new_string()
LABEL_NEUTRAL_TITLES = array.new_string()
LABEL_NEUTRAL_DESCRIPTIONS = array.new_string()


////////////////////////////
// --- HELPER METHODS --- //
////////////////////////////

str_array_to_string(array, separator) =>
    result = ""
    lastIndex = array.size(array) - 1
    for i = 0 to lastIndex
        result := result + array.get(array, lastIndex - i) + (i == lastIndex ? "" : "\n")
    result


///////////////////////////
// --- DOJI PATTERNS --- //
///////////////////////////

//
// --- DOJI PATTERN ---
//

if I_ShowDoji and jcp.isDojiCandle()
    LABEL_NEUTRAL_TITLES.push("Doji")
    LABEL_NEUTRAL_DESCRIPTIONS.push("Doji")


//
// --- GRAVESTONE DOJI PATTERN ---
//

if I_ShowGravestoneDoji and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isGravestoneDojiCandle()
    LABEL_BEARISH_TITLES.push('GD')
    LABEL_BEARISH_DESCRIPTIONS.push('Gravestone Doji')


//
// --- DRAGONFLY DOJI PATTERN ---
//

if I_ShowDragonflyDoji and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isDragonflyDojiCandle()
    LABEL_BULLISH_TITLES.push('DD')
    LABEL_BULLISH_DESCRIPTIONS.push('Dragonfly Doji')


//
// --- EVENING DOJI STAR PATTERN ---
//

if I_ShowEveningDojiStar and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isEveningDojiStarCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('EDS')
    LABEL_BEARISH_DESCRIPTIONS.push('Evening Doji Star')


//
// --- LONG LEGGED DOJI PATTERN ---
//

if I_ShowLongLeggedDoji and jcp.isLongLeggedDojiCandle()
    LABEL_NEUTRAL_TITLES.push('LLD')
    LABEL_NEUTRAL_DESCRIPTIONS.push('Long Legged Doji')


//
// --- MORNING DOJI STAR PATTERN ---
//

if I_ShowMorningDojiStar and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isMorningDojiStarCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('MDJ')
    LABEL_BULLISH_DESCRIPTIONS.push('Morning Doji Star')


///////////////////////////////
// --- REVERSAL PATTERNS --- //
///////////////////////////////

//
// --- COUNTERATTACK LINES PATTERN ---
//

if I_ShowCounterattackLines and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isBullishCounterattackLinesCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('CAL')
    LABEL_BULLISH_DESCRIPTIONS.push('Counterattack Lines')

if I_ShowCounterattackLines and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isBearishCounterattackLinesCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('CAL')
    LABEL_BEARISH_DESCRIPTIONS.push('Counterattack Lines')


//
// --- DARK-CLOUD COVER PATTERN ---
//

if I_ShowDarkCloudCover and (C_IsCandleTypeBoth or C_IsCandleTypeBearish)
    [darkCloudCoverPattern, darkCloudCoverPatternPenetrationInPercentage] = jcp.isDarkCloudCoverCandle(isUpTrend = C_IsUpTrend)
    if darkCloudCoverPattern
        LABEL_BEARISH_TITLES.push("DCC (" + str.tostring(darkCloudCoverPatternPenetrationInPercentage, "#.##") + "%)")
        LABEL_BEARISH_DESCRIPTIONS.push("Dark-Cloud Cover (Penetration " + str.tostring(darkCloudCoverPatternPenetrationInPercentage, "#.##") + "%)")


//
// --- ENGULFING PATTERN ---
//

if I_ShowEngulfing and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isBullishEngulfingCandle()
    LABEL_BULLISH_TITLES.push("EG")
    LABEL_BULLISH_DESCRIPTIONS.push("Engulfing")

if I_ShowEngulfing and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isBearishEngulfingCandle()
    LABEL_BEARISH_TITLES.push("EG")
    LABEL_BEARISH_DESCRIPTIONS.push("Engulfing")


//
// --- HAMMER & HANGING MAN PATTERN ---
//

if I_ShowHammer and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isHammerCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push("HM")
    LABEL_BULLISH_DESCRIPTIONS.push("Hammer")

//
// --- HAMMER & HANGING MAN PATTERN ---
//

if I_ShowHangingMan and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isHangingManCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push("HM")
    LABEL_BEARISH_DESCRIPTIONS.push("Hanging Man")


//
// --- HARAMI PATTERN ---
//

if I_ShowHarami and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isHaramiBearishCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('HR')
    LABEL_BEARISH_DESCRIPTIONS.push('Harami')

if I_ShowHarami and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isHaramiBullishCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('HR')
    LABEL_BULLISH_DESCRIPTIONS.push('Harami')


//
// --- IN-NECK PATTERN ---
//

if I_ShowInNeck and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isInNeckCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('IN')
    LABEL_BULLISH_DESCRIPTIONS.push('In Neck')


//
// --- ON-NECK PATTERN ---
//

if I_ShowOnNeck and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isOnNeckCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('ON')
    LABEL_BULLISH_DESCRIPTIONS.push('On Neck')


//
// --- PIERCING PATTERN ---
//

if I_ShowPiercing and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isPiercingCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('PI')
    LABEL_BULLISH_DESCRIPTIONS.push('Piercing')


//
// --- THREE BLACK CROWS PATTERN ---
//

if I_ShowThreeBlackCrows and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.threeBlackCrowsCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('3BC')
    LABEL_BEARISH_DESCRIPTIONS.push('Three Black Crows')


//
// --- THRUSTING-NECK PATTERN ---
//

if I_ShowThrusting and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isThrustingNeckCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('TN')
    LABEL_BULLISH_DESCRIPTIONS.push('Thrusting Neck')

//
// --- UPSIDE-GAP TWO CROWS PATTERN ---
//

if I_ShowUpsideGapTwoCrows and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isUpsideGapTwoCrowsCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('UGTC')
    LABEL_BEARISH_DESCRIPTIONS.push('Upside-Gap Two Crows')


///////////////////////////
// --- STAR PATTERNS --- //
///////////////////////////

//
// --- ABANDONED BABY TOP (BEARISH) PATTERN ---
//

if I_ShowAbandonedBaby and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isAbandonedBabyTopCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('ABT')
    LABEL_BEARISH_DESCRIPTIONS.push('Abandoned Baby Top')

//
// --- ABANDONED BABY BOTTOM (BULLISH) PATTERN ---
//

if I_ShowAbandonedBaby and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isAbandonedBabyBottomCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('ABB')
    LABEL_BULLISH_DESCRIPTIONS.push('Abandoned Baby Bottom')


//
// --- EVENING STAR PATTERN ---
//

if I_ShowEveningStar and (C_IsCandleTypeBoth or C_IsCandleTypeBearish)
    [isEveningStarPattern, isEveningStarPatternIdeal] = jcp.isEveningStarCandle(isUpTrend = C_IsUpTrend)

    if isEveningStarPattern
        LABEL_BEARISH_TITLES.push(isEveningStarPatternIdeal ? 'ES (i)' : 'ES')
        LABEL_BEARISH_DESCRIPTIONS.push(isEveningStarPatternIdeal ? 'Evening Star (ideal)' : 'Evening Star')


//
// --- INVERTED HAMMER PATTERN ---
//

if I_ShowInvertedHammer and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isInvertedHammerCandle(isDownTrend = C_IsDownTrend)
    LABEL_BULLISH_TITLES.push('IH')
    LABEL_BULLISH_DESCRIPTIONS.push('Inverted Hammer')


//
// --- MORNING STAR PATTERN ---
//

if I_ShowMorningStar and (C_IsCandleTypeBoth or C_IsCandleTypeBullish)
    [isMorningStarPattern, isMorningStarPatternIdeal] = jcp.isMorningStarCandle(isDownTrend = C_IsDownTrend)

    if isMorningStarPattern
        LABEL_BULLISH_TITLES.push(isMorningStarPatternIdeal ? 'MS (i)' : 'MS')
        LABEL_BULLISH_DESCRIPTIONS.push(isMorningStarPatternIdeal ? 'Morning Star (ideal)' : 'Morning Star')


//
// --- SHOOTING STAR ---
//

if I_ShowShootingStar and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isShootingStarCandle(isUpTrend = C_IsUpTrend)
    LABEL_BEARISH_TITLES.push('SS')
    LABEL_BEARISH_DESCRIPTIONS.push('Shooting Star')


///////////////////////////////////
// --- CONTINUATION PATTERNS --- //
///////////////////////////////////

//
// --- RISING THREE METHODS PATTERN ---
//

if I_ShowRisingThreeMethods and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isRisingThreeMethodsCandle(isUpTrend = C_IsUpTrend)
    LABEL_BULLISH_TITLES.push('RTM')
    LABEL_BULLISH_DESCRIPTIONS.push('Rising Three Methods')


//
// --- FALLING THREE METHODS PATTERN ---
//

if I_ShowFallingThreeMethods and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isFallingThreeMethodsCandle(isDownTrend = C_IsDownTrend)
    LABEL_BEARISH_TITLES.push('FTM')
    LABEL_BEARISH_DESCRIPTIONS.push('Falling Three Methods')


//
// --- UPSIDE TASUKI GAP PATTERN ---
//

if I_ShowTasuki and (C_IsCandleTypeBoth or C_IsCandleTypeBullish) and jcp.isUpsideTasukiGapCandle(isUpTrend = C_IsUpTrend)
    LABEL_BULLISH_TITLES.push('UTG')
    LABEL_BULLISH_DESCRIPTIONS.push('Upside Tasuki Gap')


//
// --- DOWNSIDE TASUKI GAP PATTERN ---
//

if I_ShowTasuki and (C_IsCandleTypeBoth or C_IsCandleTypeBearish) and jcp.isDownsideGapTasukiCandle(isDownTrend = C_IsDownTrend)
    LABEL_BEARISH_TITLES.push('DTG 2')
    LABEL_BEARISH_DESCRIPTIONS.push('Downside Tasuki Gap')


///////////////////////
// --- UTILITIES --- //
///////////////////////

//
// --- LONG LOWER SHADDOW ---
//

if I_ShowLongLowerShadow and jcp.isLongLowerShadowCandle()
    LABEL_BULLISH_TITLES.push('LLS')
    LABEL_BULLISH_DESCRIPTIONS.push('Long Lower Shaddow')


//
// --- LONG UPPER SHADDOW ---
//

if I_ShowLongUpperShadow and jcp.isLongUpperShadowCandle()
    LABEL_BEARISH_TITLES.push('LUS')
    LABEL_BEARISH_DESCRIPTIONS.push('Long Upper Shaddow')


//////////////////////
// --- PAINTING --- //
//////////////////////

if LABEL_NEUTRAL_TITLES.size() != 0
    label.new(bar_index, high, text=str_array_to_string(LABEL_NEUTRAL_TITLES, "\n") , yloc=yloc.abovebar, style=label.style_label_down, color=C_LabelColorNeutral, textcolor=color.white, tooltip=str_array_to_string(LABEL_NEUTRAL_DESCRIPTIONS, "\n"), size=size.small)

if LABEL_BEARISH_TITLES.size() != 0
    label.new(bar_index, high, text=str_array_to_string(LABEL_BEARISH_TITLES, "\n") , yloc=yloc.abovebar, style=label.style_label_down, color=C_LabelColorBearish, textcolor=color.white, tooltip=str_array_to_string(LABEL_BEARISH_DESCRIPTIONS, "\n"), size=size.small)

if LABEL_BULLISH_TITLES.size() != 0
    label.new(bar_index, high, text=str_array_to_string(LABEL_BULLISH_TITLES, "\n") , yloc=yloc.belowbar, style=label.style_label_up, color=C_LabelColorBullish, textcolor=color.white, tooltip=str_array_to_string(LABEL_BULLISH_DESCRIPTIONS, "\n"), size=size.small)