Candlestick Patterns Screener [By MUQWISHI]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © MUQWISHI

//@version=5
indicator("Candle Patterns Screener", overlay = true)
import MUQWISHI/CandlestickPatterns/2 as cp
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                   INPUT                                    |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// +++++++ Table Settings
// Location 
tablePos = input.string("Middle Right", "Table Location", 
             ["Top Right", "Middle Right"  , "Bottom Right" , 
             "Top Center", "Middle Center" , "Bottom Center", 
             "Top Left"  , "Middle Left"   , "Bottom Left" ], inline = "1", group = "Table Setting")

// Size
tableSiz = input.string("Small", " Size", 
             ["Auto", "Huge", "Large", "Normal", "Small", "Tiny"], inline = "1", group = "Table Setting")

// Timezone
timzon = input.string("GMT-4", "Timezone  ",                group = "Table Setting", inline = "2")

// Number of rows
rowNum = input.int(20, " № of Rows   ‏", 0, 100,     group = "Table Setting", inline = "3")

// Table Color
tBgCol = input.color(#696969, "   Titles ‏ ‏", group = "Table Setting", inline = "2")
txtCol = input.color(#ffffff, "   Text  ",  group = "Table Setting" , inline = "3")

bulCol = input.color(#006400, "Bullish",   group = "Table Setting" , inline = "4")
berCol = input.color(#882336, "  Bearish", group = "Table Setting" , inline = "4")
neuCol = input.color(#929191, "  Neutral", group = "Table Setting" , inline = "4")

// +++++++ Technical Settings
// Moving Average
maChk   = input.bool(true, "Detect Trend Based on SMA", inline = "0", group = "Technical")
maLen   = input.int(50, "", 1,                          inline = "0", group = "Technical")

// +++++++ Candle Patterns
// Type
ptrnTyp = input.string("Both", "Pattern Type", ["Bullish", "Bearish", "Both"], group = "Candle Patterns")

// Patterns
abandonedBabyChk       = input.bool(true, "Abandoned Baby",        group = "Candle Patterns", inline = "01") 
dbarkCloudCoverChk     = input.bool(true, "Dark Cloud Cover",      group = "Candle Patterns", inline = "01") 
dojiChk                = input.bool(true, "Doji",                  group = "Candle Patterns", inline = "02") 
dojiStarChk            = input.bool(true, "Doji Star",             group = "Candle Patterns", inline = "02") 
downsideTasukiGapChk   = input.bool(true, "Downside Tasuki Gap",   group = "Candle Patterns", inline = "02") 
dragonflyDojiChk       = input.bool(true, "Dragonfly Doji",        group = "Candle Patterns", inline = "03") 
engulfingChk           = input.bool(true, "Engulfing",             group = "Candle Patterns", inline = "03")
eveningDojiStarChk     = input.bool(true, "Evening Doji Star",     group = "Candle Patterns", inline = "03") 
eveningStarChk         = input.bool(true, "Evening Star",          group = "Candle Patterns", inline = "04") 
fallingThreeMethodsChk = input.bool(true, "Falling Three Methods", group = "Candle Patterns", inline = "04") 
fallingWindowChk       = input.bool(true, "Falling Window",        group = "Candle Patterns", inline = "05") 
gravestoneDojiChk      = input.bool(true, "Gravestone Doji",       group = "Candle Patterns", inline = "05") 
hammerChk              = input.bool(true, "Hammer",                group = "Candle Patterns", inline = "05") 
hangingManChk          = input.bool(true, "Hanging Man",           group = "Candle Patterns", inline = "06") 
haramiCrossChk         = input.bool(true, "Harami Cross",          group = "Candle Patterns", inline = "06") 
haramiChk              = input.bool(true, "Harami",                group = "Candle Patterns", inline = "06")
invertedHammerChk      = input.bool(true, "Inverted Hammer",       group = "Candle Patterns", inline = "07") 
kickingChk             = input.bool(true, "Kicking",               group = "Candle Patterns", inline = "07") 
longLowerShadowChk     = input.bool(true, "Long Lower Shadow",     group = "Candle Patterns", inline = "08") 
longUpperShadowChk     = input.bool(true, "Long Upper Shadow",     group = "Candle Patterns", inline = "08") 
marubozuBlackChk       = input.bool(true, "Marubozu Black",        group = "Candle Patterns", inline = "09") 
marubozuWhiteChk       = input.bool(true, "Marubozu White",        group = "Candle Patterns", inline = "09") 
morningDojiStarChk     = input.bool(true, "Morning Doji Star",     group = "Candle Patterns", inline = "10") 
morningStarChk         = input.bool(true, "Morning Star",          group = "Candle Patterns", inline = "10") 
onNeckChk              = input.bool(true, "On Neck",               group = "Candle Patterns", inline = "10") 
piercingChk            = input.bool(true, "Piercing",              group = "Candle Patterns", inline = "11") 
risingThreeMethodsChk  = input.bool(true, "Rising Three Methods",  group = "Candle Patterns", inline = "11") 
risingWindowChk        = input.bool(true, "Rising Window",         group = "Candle Patterns", inline = "12") 
shootingStarChk        = input.bool(true, "Shooting Star ",        group = "Candle Patterns", inline = "12") 
spinningTopBlackChk    = input.bool(true, "Spinning Top Black",    group = "Candle Patterns", inline = "13") 
spinningTopWhiteChk    = input.bool(true, "Spinning Top White",    group = "Candle Patterns", inline = "13") 
threeBlackCrowsChk     = input.bool(true, "Three Black Crows",     group = "Candle Patterns", inline = "14") 
threeWhiteSoldiersChk  = input.bool(true, "Three White Soldiers",  group = "Candle Patterns", inline = "14") 
triStarChk             = input.bool(true, "Tri-Star",              group = "Candle Patterns", inline = "15") 
tweezerBottomChk       = input.bool(true, "Tweezer Bottom",        group = "Candle Patterns", inline = "15") 
tweezerTopChk          = input.bool(true, "Tweezer Top",           group = "Candle Patterns", inline = "15") 
upsideTasukiGapChk     = input.bool(true, "Upside Tasuki Gap",     group = "Candle Patterns", inline = "16") 

// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                  SYMBOLS                                   |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// Symbols Checkmark
c01 = input.bool(true,  "", group = "Symbols", inline = "s01")
c02 = input.bool(true,  "", group = "Symbols", inline = "s02")
c03 = input.bool(true,  "", group = "Symbols", inline = "s03")
c04 = input.bool(true,  "", group = "Symbols", inline = "s04")
c05 = input.bool(true,  "", group = "Symbols", inline = "s05")
c06 = input.bool(true,  "", group = "Symbols", inline = "s06")
c07 = input.bool(true,  "", group = "Symbols", inline = "s07")
c08 = input.bool(true,  "", group = "Symbols", inline = "s08")
c09 = input.bool(true,  "", group = "Symbols", inline = "s09")
c10 = input.bool(true,  "", group = "Symbols", inline = "s10")
c11 = input.bool(true,  "", group = "Symbols", inline = "s11")
c12 = input.bool(true,  "", group = "Symbols", inline = "s12")
c13 = input.bool(true,  "", group = "Symbols", inline = "s13")
c14 = input.bool(true,  "", group = "Symbols", inline = "s14")
c15 = input.bool(true,  "", group = "Symbols", inline = "s15")
c16 = input.bool(true,  "", group = "Symbols", inline = "s16")
c17 = input.bool(true,  "", group = "Symbols", inline = "s17")
c18 = input.bool(true,  "", group = "Symbols", inline = "s18")
c19 = input.bool(true,  "", group = "Symbols", inline = "s19")
c20 = input.bool(true,  "", group = "Symbols", inline = "s20")
c21 = input.bool(true,  "", group = "Symbols", inline = "s21")
c22 = input.bool(true,  "", group = "Symbols", inline = "s22")
c23 = input.bool(true,  "", group = "Symbols", inline = "s23")
c24 = input.bool(true,  "", group = "Symbols", inline = "s24")
c25 = input.bool(true,  "", group = "Symbols", inline = "s25")
c26 = input.bool(true,  "", group = "Symbols", inline = "s26")
c27 = input.bool(true,  "", group = "Symbols", inline = "s27")
c28 = input.bool(true,  "", group = "Symbols", inline = "s28")
c29 = input.bool(true,  "", group = "Symbols", inline = "s29")
c30 = input.bool(true,  "", group = "Symbols", inline = "s30")
c31 = input.bool(true,  "", group = "Symbols", inline = "s31")
c32 = input.bool(true,  "", group = "Symbols", inline = "s32")
c33 = input.bool(true,  "", group = "Symbols", inline = "s33")
c34 = input.bool(true,  "", group = "Symbols", inline = "s34")
c35 = input.bool(true,  "", group = "Symbols", inline = "s35")
c36 = input.bool(false, "", group = "Symbols", inline = "s36")
c37 = input.bool(false, "", group = "Symbols", inline = "s37")
c38 = input.bool(false, "", group = "Symbols", inline = "s38")
c39 = input.bool(false, "", group = "Symbols", inline = "s39")
c40 = input.bool(false, "", group = "Symbols", inline = "s40")

// Symbol Input
s01 = input.symbol("QQQ",  "", group = "Symbols", inline = "s01")
s02 = input.symbol("TSLA", "", group = "Symbols", inline = "s02")
s03 = input.symbol("AAPL", "", group = "Symbols", inline = "s03")
s04 = input.symbol("META", "", group = "Symbols", inline = "s04")
s05 = input.symbol("AMZN", "", group = "Symbols", inline = "s05")
s06 = input.symbol("MSFT", "", group = "Symbols", inline = "s06")
s07 = input.symbol("NVDA", "", group = "Symbols", inline = "s07")
s08 = input.symbol("AMD",  "", group = "Symbols", inline = "s08")
s09 = input.symbol("OXY",  "", group = "Symbols", inline = "s09")
s10 = input.symbol("NIO",  "", group = "Symbols", inline = "s10")
s11 = input.symbol("RIVN", "", group = "Symbols", inline = "s11")
s12 = input.symbol("PYPL", "", group = "Symbols", inline = "s12")
s13 = input.symbol("PLUG", "", group = "Symbols", inline = "s13")
s14 = input.symbol("ZM",   "", group = "Symbols", inline = "s14")
s15 = input.symbol("AMC",  "", group = "Symbols", inline = "s15")
s16 = input.symbol("GME",  "", group = "Symbols", inline = "s16")
s17 = input.symbol("BABA", "", group = "Symbols", inline = "s17")
s18 = input.symbol("LCID", "", group = "Symbols", inline = "s18")
s19 = input.symbol("AAL",  "", group = "Symbols", inline = "s19")
s20 = input.symbol("RBLX", "", group = "Symbols", inline = "s20")
s21 = input.symbol("NFLX", "", group = "Symbols", inline = "s21")
s22 = input.symbol("XPEV", "", group = "Symbols", inline = "s22")
s23 = input.symbol("CCL",  "", group = "Symbols", inline = "s23")
s24 = input.symbol("BILI", "", group = "Symbols", inline = "s24")
s25 = input.symbol("UBER", "", group = "Symbols", inline = "s25")
s26 = input.symbol("GOOG", "", group = "Symbols", inline = "s26")
s27 = input.symbol("JNJ",  "", group = "Symbols", inline = "s27")
s28 = input.symbol("UNH",  "", group = "Symbols", inline = "s28")
s29 = input.symbol("V",    "", group = "Symbols", inline = "s29")
s30 = input.symbol("XOM",  "", group = "Symbols", inline = "s30")
s31 = input.symbol("JPM",  "", group = "Symbols", inline = "s31")
s32 = input.symbol("MA",   "", group = "Symbols", inline = "s32")
s33 = input.symbol("WMT",  "", group = "Symbols", inline = "s33")
s34 = input.symbol("CVX",  "", group = "Symbols", inline = "s34")
s35 = input.symbol("PFE",  "", group = "Symbols", inline = "s35")
s36 = input.symbol("HD",   "", group = "Symbols", inline = "s36")
s37 = input.symbol("BAC",  "", group = "Symbols", inline = "s37")
s38 = input.symbol("LLY",  "", group = "Symbols", inline = "s38")
s39 = input.symbol("KO",   "", group = "Symbols", inline = "s39")
s40 = input.symbol("SPCE", "", group = "Symbols", inline = "s40")

// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                CALCULATION                                 |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
bull = not(ptrnTyp == "Bearish")
bear = not(ptrnTyp == "Bullish")

main(flg) =>
    uTrd = maChk ? close > ta.sma(close, maLen) : true
    dTrd = maChk ? close < ta.sma(close, maLen) : true

    prc = float(na), tim = int(na), pt  = "", typ = int(na) 
    if flg and barstate.isconfirmed
        if fallingThreeMethodsChk and cp.fallingThreeMethods() and bear and dTrd[4]
            pt := "Falling Three Methods", typ := -1

        else if risingThreeMethodsChk and cp.risingThreeMethods() and bull and uTrd[4]
            pt := "Rising Three Methods", typ := 1

        else if abandonedBabyChk and cp.abandonedBaby("bull") and bull and dTrd[2]
            pt := "Abandoned Baby", typ := 1

        else if abandonedBabyChk and  cp.abandonedBaby("bear") and bear and uTrd[2]
            pt := "Abandoned Baby", typ := -1

        else if downsideTasukiGapChk and cp.downsideTasukiGap() and bear and dTrd
            pt := "Downside Tasuki Gap", typ := -1

        else if eveningDojiStarChk and cp.eveningDojiStar() and bear and uTrd
            pt := "Evening Doji Star", typ := -1

        else if eveningStarChk and cp.eveningStar() and bear and uTrd
            pt := "Evening Star", typ := -1

        else if morningDojiStarChk and cp.morningDojiStar() and bull and dTrd
            pt := "Morning Doji Star", typ := 1

        else if morningStarChk and cp.morningStar() and bull and dTrd
            pt := "Morning Star", typ := 1

        else if threeBlackCrowsChk and cp.threeBlackCrows() and bear
            pt := "Three Black Crows", typ := -1

        else if threeWhiteSoldiersChk and cp.threeWhiteSoldiers() and bull
            pt := "Three White Soldiers", typ := 1

        else if triStarChk and cp.triStar("bear") and bear and uTrd[2]
            pt := "Tri Star", typ := -1

        else if triStarChk and cp.triStar("bull") and bull and dTrd[2]
            pt := "Tri Star", typ := 1

        else if upsideTasukiGapChk and cp.upsideTasukiGap() and bull and uTrd
            pt := "Upside Tasuki Gap", typ := 1

        else if dbarkCloudCoverChk and cp.darkCloudCover() and bear and uTrd[1]
            pt := "Dark Cloud Cover", typ := -1

        else if dojiStarChk and cp.dojiStar("bear") and bear and uTrd
            pt := "Doji Star", typ := -1

        else if dojiStarChk and cp.dojiStar("bull") and bull and dTrd
            pt := "Doji Star", typ := 1

        else if engulfingChk and cp.engulfing("bull") and bull and dTrd
            pt := "Engulfing", typ := 1

        else if engulfingChk and cp.engulfing("bear") and bear and uTrd
            pt := "Engulfing", typ := -1

        else if fallingWindowChk and cp.fallingWindow() and bear and dTrd[1]
            pt := "Falling Window", typ := -1

        else if haramiCrossChk and cp.haramiCross("bull") and bull and dTrd[1]
            pt := "Harami Cross", typ := 1

        else if haramiCrossChk and cp.haramiCross("bear") and bear and uTrd[1]
            pt := "Harami Cross", typ := -1

        else if haramiChk and cp.harami("bull") and bull and dTrd[1]
            pt := "Harami", typ := 1

        else if haramiChk and cp.harami("bear") and bear and uTrd[1]
            pt := "Harami", typ := -1

        else if kickingChk and cp.kicking("bull") and bull
            pt := "Kicking", typ := 1

        else if kickingChk and cp.kicking("bear") and bear
            pt := "Kicking", typ := -1

        else if onNeckChk and cp.onNeck() and bear and dTrd
            pt := "On Neck", typ := -1

        else if piercingChk and cp.piercing() and bull and dTrd[1]
            pt := "Piercing", typ := 1

        else if risingWindowChk and cp.risingWindow() and bull and uTrd[1]
            pt := "Rising Window", typ := 1

        else if tweezerBottomChk and cp.tweezerBottom() and bull and dTrd[1]
            pt := "Tweezer Bottom", typ := 1

        else if tweezerTopChk and cp.tweezerTop() and bear and uTrd[1]
            pt := "Tweezer Top", typ := -1

        else if dojiChk and cp.doji()
            pt := "Doji", typ := 0

        else if dragonflyDojiChk and cp.dragonflyDoji() and bull
            pt := "Dragon Fly Doji", typ := 1

        else if gravestoneDojiChk and cp.gravestoneDoji() and bear 
            pt := "Gravestone Doji", typ := -1

        else if hammerChk and cp.hammer() and bull and dTrd
            pt := "Hammer", typ := 1

        else if hangingManChk and cp.hangingMan() and bear and uTrd
            pt := "Hanging Man", typ := -1

        else if invertedHammerChk and cp.invertedHammer() and bull and dTrd
            pt := "Inverted Hammer", typ := 1

        else if longLowerShadowChk and cp.longLowerShadow() and bull 
            pt := "Long Lower Shadow", typ := 1

        else if longUpperShadowChk and cp.longUpperShadow() and bear 
            pt := "Long Upper Shadow", typ := -1

        else if marubozuBlackChk and cp.marubozuBlack() and bear 
            pt := "Marubozu Black", typ := -1

        else if marubozuWhiteChk and cp.marubozuWhite() and bull
            pt := "Marubozu White", typ := 1

        else if shootingStarChk and cp.shootingStar() and bear and uTrd
            pt := "Shooting Star", typ := -1

        else if spinningTopBlackChk and cp.spinningTopBlack()
            pt := "Spinning Top Black", typ := 0

        else if spinningTopWhiteChk and cp.spinningTopWhite()
            pt := "Spinning Top White", typ := 0

        if not na(typ)
            prc := math.round_to_mintick(close)
            tim := time
    
    [prc, pt, tim, typ]


// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                  SCREENER                                  |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// Get Time Format 
timForm(x) =>
    timeframe.isintraday ? str.format_time(x, "HH:mm  MM-dd-yyyy", timzon) :
     str.format_time(x, "MM-dd-yyyy", timzon)

// Get Symbol Name
symbol(s) => 
    array.get(str.split(s, ":"), 1)

// Set Up Matrix
var mtx = matrix.new<string>(0, 5, na)

mtxFun(symbol, price, pattern, tim, typ) =>
    matrix.add_row(mtx, 0, array.from(symbol, price, pattern, tim, typ))

// Screener Function
screenerFun(s, flg) =>
    sym = ticker.modify(s, syminfo.session)
    [prc, pt, tim, typ] = request.security(sym, timeframe.period, main(flg))

    if flg
        if not na(typ) and tim == time
            mtxFun(symbol(s), str.tostring(prc), pt, timForm(tim), str.tostring(typ))

// Call Symbols
screenerFun(s01, c01),  screenerFun(s02, c02),  screenerFun(s03, c03),  screenerFun(s04, c04),  
screenerFun(s05, c05),  screenerFun(s06, c06),  screenerFun(s07, c07),  screenerFun(s08, c08),  
screenerFun(s09, c09),  screenerFun(s10, c10),  screenerFun(s11, c11),  screenerFun(s12, c12),
screenerFun(s13, c13),  screenerFun(s14, c14),  screenerFun(s15, c15),  screenerFun(s16, c16),
screenerFun(s17, c17),  screenerFun(s18, c18),  screenerFun(s19, c19),  screenerFun(s20, c20),  
screenerFun(s21, c21),  screenerFun(s22, c22),  screenerFun(s23, c23),  screenerFun(s24, c24),  
screenerFun(s25, c25),  screenerFun(s26, c26),  screenerFun(s27, c27),  screenerFun(s28, c28),  
screenerFun(s29, c29),  screenerFun(s30, c30),  screenerFun(s31, c31),  screenerFun(s32, c32),  
screenerFun(s33, c33),  screenerFun(s34, c34),  screenerFun(s35, c35),  screenerFun(s36, c36),
screenerFun(s37, c37),  screenerFun(s38, c38),  screenerFun(s39, c39),  screenerFun(s40, c40),

if matrix.rows(mtx) > rowNum
    while matrix.rows(mtx) > rowNum
        matrix.remove_row(mtx, matrix.rows(mtx)-1)

// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// |                                   TABLE                                    |
// |++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++|
// Get Tbale Location & Size
locNsze(x) => 
    y   = str.split(str.lower(x), " ")
    out = ""
    for i = 0 to array.size(y) - 1
        out := out + array.get(y, i)
        if i != array.size(y) - 1
            out := out + "_"
    out

// Create Table
var tbl = table.new(locNsze(tablePos), 4, 102,
          frame_width  = 1, frame_color  = color.new(tBgCol, 100), 
          border_width = 1, border_color = color.new(tBgCol, 100))

// Cell Function
cell(col, row, txt, color) => 
    table.cell(tbl, col, row, text = txt, text_color = txtCol, bgcolor = color, 
     text_size = locNsze(tableSiz))


if barstate.islast
    table.clear(tbl, 0, 0, 3, 101)
    cell(0, 0, "Symbol",      tBgCol)
    cell(1, 0, "Price",       tBgCol)
    cell(2, 0, "Pattern" ,    tBgCol)
    cell(3, 0, "Signal Time", tBgCol)
 
    j = 1
    if matrix.rows(mtx) > 0
        for i = 0 to matrix.rows(mtx) - 1
            col = matrix.get(mtx, i, 4) ==  "1" ? bulCol :
                  matrix.get(mtx, i, 4) == "-1" ? berCol : neuCol

            cell(0, j, matrix.get(mtx, i, 0), tBgCol)
            cell(1, j, matrix.get(mtx, i, 1),    col)
            cell(2, j, matrix.get(mtx, i, 2),    col)
            cell(3, j, matrix.get(mtx, i, 3),    col)

            j += 1
