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

//#region General functions
var tab = table.new(position=position.top_right, columns=7, rows=30,frame_color = color.yellow, frame_width = 1)
msg(int row, int col, string msg_str, clr=color.blue) =>
    if(barstate.islast)
        table.cell(table_id=tab, column=col, row=row, text=msg_str, text_color=clr)

t(val) => str.tostring(val)
method f(float f) => str.tostring(f)
method f(int i) => str.tostring(i)
method f(bool b) => str.tostring(b)
method f(string s) => str.tostring(s)
method fd(int t, string format = "dd-MM-yy HH:mm") => str.format_time(t, format, syminfo.timezone)

dt(val, format = "dd-MM-yy HH:mm") => str.format_time(val, format, syminfo.timezone)
var debug = array.new<string>(1, "")
method clear_log(string [] s) =>
    s.clear()
    s.unshift("")
method log(string [] s, string msg, bool on_last_bar = false) =>
    if((not on_last_bar) or (on_last_bar and barstate.islast))
        if(str.length(s.get(0)) + str.length(msg) < 4095)
            s.set(0, s.get(0) + msg + "\n")
method display(string [] s, where = 'B') =>
    if(not na(s.get(0)))
        if(where == 'B')
            label.new(bar_index, low, yloc = yloc.belowbar, style = label.style_diamond, tooltip = s.get(0), size = size.tiny)
        else
            label.new(bar_index, high, yloc = yloc.abovebar, style = label.style_diamond, tooltip = s.get(0), size = size.tiny)
        debug.clear_log()
//#endregion General functions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    

type class_p_visuals
    bool plot_fl
    string line_style
    color line_color 
    color bg_color
var fixed_tt = "Fiexd value leg (mostly XD leg) patterns are rare, This % value is used to derive the range for such values. Set the % to 0.001% which is very close to fixed value"
//@version=5
indicator('Harmonic Patterns', overlay=true, max_lines_count = 500, max_labels_count = 500, max_polylines_count = 100)
//#region Input Parameters
start_time = input.time(timestamp("01 Jan 1900"))

g1 = 'Zigzag Setup'
lb = input.int(title = 'Left bars', defval = 10, group = g1, inline = 'g11')
rb = input.int(title = 'Right bars', defval = 10, group = g1, inline = 'g11')
color_ctf = input.color(title = 'Zigzag color', defval =color.new(color.blue, 95), group = g1, inline = 'g21')
width_ctf = input.int(title = 'Width', defval = 1, group = g1, inline = 'g21')
plot_ctf_zigzag = input.bool(title = 'Plot Zigzag', defval = true, group = g1, inline = 'g22')
plot_ctf_hhll_labels = input.bool(title = 'Plot HHLL labels', defval = false, group = g1, inline = 'g22')

g2 = 'Harmonic Pattern Setup'
ignore_xd_leg = input.bool(title = 'Ignore XD leg calculations', defval = false, group = g2)
apply_xd = ignore_xd_leg ? false : true
xd_offset_percent = input.float(title = 'Fixed value leg offset %', defval = 10, minval = 0.001, tooltip = fixed_tt)/100
show_pattern_label = input.bool(title = '', defval = true, inline = '90')
pattern_name_color = input.color(title = 'Pattern name label color', defval = color.purple, inline = '90')

var bull_bat = class_p_visuals.new()
bull_bat.plot_fl := input.bool(title = '', defval = true, inline = '100')
bull_bat.line_style := input.string(title = 'Bullish Bat => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '100')
bull_bat.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '100')
bull_bat.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '100')

var bear_bat = class_p_visuals.new()
bear_bat.plot_fl := input.bool(title = '', defval = true, inline = '110')
bear_bat.line_style := input.string(title = 'Bearish Bat => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '110')
bear_bat.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '110')
bear_bat.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '110')

var bull_abat = class_p_visuals.new()
bull_abat.plot_fl := input.bool(title = '', defval = true, inline = '120')
bull_abat.line_style := input.string(title = 'ALT Bullish Bat => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '120')
bull_abat.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '120')
bull_abat.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '120')

var bear_abat = class_p_visuals.new()
bear_abat.plot_fl := input.bool(title = '', defval = true, inline = '130')
bear_abat.line_style := input.string(title = 'ALT Bearish Bat => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '130')
bear_abat.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '130')
bear_abat.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '130')

var bull_bfly = class_p_visuals.new()
bull_bfly.plot_fl := input.bool(title = '', defval = true, inline = '140')
bull_bfly.line_style := input.string(title = 'Bullish Butterfly => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '140')
bull_bfly.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '140')
bull_bfly.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '140')

var bear_bfly = class_p_visuals.new()
bear_bfly.plot_fl := input.bool(title = '', defval = true, inline = '150')
bear_bfly.line_style := input.string(title = 'Bearish Butterfly => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '150')
bear_bfly.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '150')
bear_bfly.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '150')

var bull_crab = class_p_visuals.new()
bull_crab.plot_fl := input.bool(title = '', defval = true, inline = '160')
bull_crab.line_style := input.string(title = 'Bullish CRAB => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '160')
bull_crab.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '160')
bull_crab.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '160')

var bear_crab = class_p_visuals.new()
bear_crab.plot_fl := input.bool(title = '', defval = true, inline = '170')
bear_crab.line_style := input.string(title = 'Bearish CRAB => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '170')
bear_crab.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '170')
bear_crab.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '170')

var bull_dcrab = class_p_visuals.new()
bull_dcrab.plot_fl := input.bool(title = '', defval = true, inline = '180')
bull_dcrab.line_style := input.string(title = 'Bullish Deep CRAB => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '180')
bull_dcrab.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '180')
bull_dcrab.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '180')

var bear_dcrab = class_p_visuals.new()
bear_dcrab.plot_fl := input.bool(title = '', defval = true, inline = '190')
bear_dcrab.line_style := input.string(title = 'Bearish Deep CRAB => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '190')
bear_dcrab.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '190')
bear_dcrab.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '190')

var bull_gartley = class_p_visuals.new()
bull_gartley.plot_fl := input.bool(title = '', defval = true, inline = '200')
bull_gartley.line_style := input.string(title = 'Bullish Gartley => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '200')
bull_gartley.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '200')
bull_gartley.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '200')

var bear_gartley = class_p_visuals.new()
bear_gartley.plot_fl := input.bool(title = '', defval = true, inline = '210')
bear_gartley.line_style := input.string(title = 'Berish Gartley => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '210')
bear_gartley.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '210')
bear_gartley.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '210')

var bull_shark = class_p_visuals.new()
bull_shark.plot_fl := input.bool(title = '', defval = true, inline = '220')
bull_shark.line_style := input.string(title = 'Bullish Shark => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '220')
bull_shark.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '220')
bull_shark.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '220')

var bear_shark = class_p_visuals.new()
bear_shark.plot_fl := input.bool(title = '', defval = true, inline = '230')
bear_shark.line_style := input.string(title = 'Berish Shark => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '230')
bear_shark.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '230')
bear_shark.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '230')

var bull_cypher = class_p_visuals.new()
bull_cypher.plot_fl := input.bool(title = '', defval = true, inline = '240')
bull_cypher.line_style := input.string(title = 'Bullish Cypher => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '240')
bull_cypher.line_color := input.color(title = 'Color', defval = color.new(color.green, 0), inline = '240')
bull_cypher.bg_color := input.color(title = 'BG', defval = color.new(color.green, 85), inline = '240')

var bear_cypher = class_p_visuals.new()
bear_cypher.plot_fl := input.bool(title = '', defval = true, inline = '250')
bear_cypher.line_style := input.string(title = 'Berish Cypher => Style', defval = line.style_solid, options = [line.style_solid, line.style_dotted, line.style_dashed], inline = '250')
bear_cypher.line_color := input.color(title = 'Color', defval = color.new(color.red, 0), inline = '250')
bear_cypher.bg_color := input.color(title = 'BG', defval = color.new(color.red, 85), inline = '250')


//#endregion Input Parameters
var ctf = t(timeframe.period)

var v_map = map.new<string, class_p_visuals>()
if(bar_index == 0)
    v_map.put("BULL-BAT", bull_bat)
    v_map.put("BEAR-BAT", bear_bat)
    v_map.put("BULL-ABAT", bull_abat)
    v_map.put("BEAR-ABAT", bear_abat)
    v_map.put("BULL-BFLY", bull_bfly)
    v_map.put("BEAR-BFLY", bear_bfly)
    v_map.put("BULL-CRAB", bull_crab)
    v_map.put("BEAR-CRAB", bear_crab)
    v_map.put("BULL-DCRAB", bull_dcrab)
    v_map.put("BEAR-DCRAB", bear_dcrab)
    v_map.put("BULL-GARTLEY", bull_gartley)
    v_map.put("BEAR-GARTLEY", bear_gartley)
    v_map.put("BULL-SHARK", bull_shark)
    v_map.put("BEAR-SHARK", bear_shark)   
    v_map.put("BULL-CYPHER", bull_cypher)
    v_map.put("BEAR-CYPHER", bear_cypher)        
type class_visuals
    bool plot_line = false
    bool plot_label = false
    color clr
    int width
var visuals  = map.new<string, class_visuals>()
if(bar_index == 0)
    visuals.put('CTF', class_visuals.new(plot_ctf_zigzag, plot_ctf_hhll_labels, color_ctf, width_ctf))

//objects 
type class_hhll
    string group //H or l
    string sub_group // HH, LL, LH, HL
    int bar_id 
    int bar_time
    float pivot_pp 
    line ln
    label lbl
    string tf
    bool is_new = false
var array<class_hhll> hhll_ctf = array.new<class_hhll>()

type class_ohlc
    bool pivot
    float pp
    int bar_id
    int bar_time

type class_fib_levels
    float f_382
    float f_382u
    float f_382l    
    float f_50
    float f_618
    float f_618u
    float f_618l     
    float f_886
    float f_886u
    float f_886l
    float f_1618
    float f_1618u
    float f_1618l    
    float f_2618
    float f_3618
    float f_200
    float f_113 
    float f_113u
    float f_113l
    float f_786
    float f_786u
    float f_786l
    float f_224 
    float f_127 
    float f_141
    float f_fake1
    float f_fake2 

type class_legs
    string l1_key
    float l1_val
    string l2_key
    float l2_val

type class_xabcd
    string name
    class_legs xb 
    class_legs ac
    class_legs bd 
    class_legs xd
    bool bull_fl 
    bool bear_fl
    int bull_cnt = 0
    int bear_cnt = 0
    int last_bull
    int last_bear
var array<class_xabcd> p_xabcd = array.new<class_xabcd>()
if(bar_index == 0)
    p_xabcd.push(class_xabcd.new(name = "BAT"
         , xb = class_legs.new(l1_key = 'F_382', l2_key = 'F_50')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_1618', l2_key = 'F_2618')
         , xd = class_legs.new(l1_key = 'F_886L', l2_key = 'F_886U')
         )) 
        
    p_xabcd.push(class_xabcd.new(name = "ABAT"
         , xb = class_legs.new(l1_key = 'F_382L', l2_key = 'F_382U')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_200', l2_key = 'F_3618')
         , xd = class_legs.new(l1_key = 'F_113L', l2_key = 'F_113U')
         )) 

    p_xabcd.push(class_xabcd.new(name = "BFLY"
         , xb = class_legs.new(l1_key = 'F_786L', l2_key = 'F_786U')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_1618', l2_key = 'F_224')
         , xd = class_legs.new(l1_key = 'F_127', l2_key = 'F_141')
         )) 

    p_xabcd.push(class_xabcd.new(name = "CRAB"
         , xb = class_legs.new(l1_key = 'F_382', l2_key = 'F_618')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_2618', l2_key = 'F_3618')
         , xd = class_legs.new(l1_key = 'F_1618L', l2_key = 'F_1618U')
         )) 

    p_xabcd.push(class_xabcd.new(name = "DCRAB"
         , xb = class_legs.new(l1_key = 'F_886L', l2_key = 'F_886U')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_200', l2_key = 'F_3618')
         , xd = class_legs.new(l1_key = 'F_1618L', l2_key = 'F_1618U')
         )) 

    p_xabcd.push(class_xabcd.new(name = "GARTLEY"
         , xb = class_legs.new(l1_key = 'F_618L', l2_key = 'F_618U')
         , ac = class_legs.new(l1_key = 'F_382', l2_key = 'F_886')
         , bd = class_legs.new(l1_key = 'F_113', l2_key = 'F_1618')
         , xd = class_legs.new(l1_key = 'F_786L', l2_key = 'F_786U')
         )) 
    p_xabcd.push(class_xabcd.new(name = "SHARK"
         , xb = class_legs.new(l1_key = 'F_FAKE1', l2_key = 'F_FAKE2')
         , ac = class_legs.new(l1_key = 'F_113', l2_key = 'F_1618')
         , bd = class_legs.new(l1_key = 'F_1618', l2_key = 'F_224')
         , xd = class_legs.new(l1_key = 'F_886', l2_key = 'F_113')
         )) 
    p_xabcd.push(class_xabcd.new(name = "CYPHER"
         , xb = class_legs.new(l1_key = 'F_382', l2_key = 'F_618')
         , ac = class_legs.new(l1_key = 'F_113', l2_key = 'F_141')
         , bd = class_legs.new(l1_key = 'F_127', l2_key = 'F_200')
         , xd = class_legs.new(l1_key = 'F_786L', l2_key = 'F_786U')
         ))          
//
get_ph_pl(i) =>
    ph = class_ohlc.new(pivot = false)
    pl = class_ohlc.new(pivot = false)
    _ph = ta.pivothigh(high[i], lb, rb) 
    _pl = ta.pivotlow(low[i], lb, rb) 
    
    if((_ph > 0  or _pl > 0) and time >= start_time)
        rec = class_ohlc.new(
             pivot = true,
             pp = _ph > 0 ? high[rb+i] : low[rb+i],
             bar_id = bar_index[rb+i],
             bar_time = time[rb+i])
        ph := not na(_ph) ? rec : ph
        pl := not na(_pl) ? rec : pl
        
    [ph, pl]
//
method get(array<class_hhll> hhll, id) => hhll.size() > id ? hhll.get(id)  : class_hhll.new()
//
method add_ph(array<class_hhll> hhll, class_ohlc ph, class_visuals v, tf) =>
    if(ph.pivot)
        pp = ph.pp 
        bar_id = ph.bar_id 
        bar_time = ph.bar_time
        class_hhll prev = hhll.get(0)
        rec_deleted = false
        if(prev.group == 'H')
            if(pp > prev.pivot_pp)
                rec_deleted := true
                prev.ln.delete()
                prev.lbl.delete()
                hhll.shift()
                prev := hhll.get(0)
        if(prev.group != 'H')
            move = math.round((pp - nz(prev.pivot_pp, 0)) / pp * 100, 2)
            change = math.round_to_mintick(pp - nz(prev.pivot_pp))
            new_rec = class_hhll.new(group = 'H', bar_id = bar_id, bar_time = bar_time, pivot_pp = pp, tf = t(tf), is_new = true)

            if(na(prev.group))
                new_rec.sub_group := 'HH'
                if(v.plot_line)
                    new_rec.ln := line.new(bar_time, pp, bar_time, pp, xloc = xloc.bar_time, color = v.clr, width = v.width)
                if(v.plot_label)
                    tt = "" //new_rec.get_tt()
                    new_rec.lbl := label.new(bar_time, pp, text = new_rec.sub_group, xloc = xloc.bar_time, style = label.style_label_down, size = size.tiny,
                         color = v.clr, tooltip = tt)
            else
                class_hhll prev_ph = hhll.get(1)
                new_rec.sub_group := pp > prev_ph.pivot_pp ? 'HH' : 'LH'
                if(v.plot_line)
                    new_rec.ln := line.new(prev.bar_time, prev.pivot_pp, bar_time, pp, xloc = xloc.bar_time, color = v.clr, width = v.width)
                if(v.plot_label)
                    tt = "" //new_rec.get_tt()
                    new_rec.lbl := label.new(bar_time, pp, text = new_rec.sub_group, xloc = xloc.bar_time, style = label.style_label_down, size = size.tiny, color = v.clr, tooltip = tt)
            hhll.unshift(new_rec)
    true
//
method add_pl(array<class_hhll> hhll, class_ohlc pl, class_visuals v, tf) =>
    if(pl.pivot)
        pp = pl.pp 
        bar_id = pl.bar_id 
        bar_time = pl.bar_time
        class_hhll prev = hhll.get(0)
        rec_deleted = false
        if(prev.group == 'L')
            if(pp < prev.pivot_pp)
                rec_deleted := true
                prev.ln.delete()
                prev.lbl.delete()
                hhll.shift()
                prev := hhll.get(0)
        if(prev.group != 'L')
            move = math.round((pp - nz(prev.pivot_pp, 0)) / pp * 100, 2)
            change = math.round_to_mintick(pp - nz(prev.pivot_pp))
            new_rec = class_hhll.new(group = 'L', bar_id = bar_id, bar_time = bar_time, pivot_pp = pp, tf = t(tf), is_new = true)
            
            if(na(prev.group))
                new_rec.sub_group := 'LL'
                if(v.plot_line)
                    new_rec.ln := line.new(bar_time, pp, bar_time, pp, xloc = xloc.bar_time, color = v.clr, width = v.width)
                if(v.plot_label)
                    tt = "" //new_rec.get_tt()
                    new_rec.lbl := label.new(bar_time, pp, text = new_rec.sub_group, xloc = xloc.bar_time, style = label.style_label_up, size = size.tiny, color = v.clr, tooltip = tt)
            else
                class_hhll prev_pl = hhll.get(1)
                new_rec.sub_group := pp < prev_pl.pivot_pp ? 'LL' : 'HL'
                if(v.plot_line)
                    new_rec.ln := line.new(prev.bar_time, prev.pivot_pp, bar_time, pp, xloc = xloc.bar_time, color = v.clr, width = v.width)
                if(v.plot_label)
                    tt = "" //new_rec.get_tt()
                    new_rec.lbl := label.new(bar_time, pp, text = new_rec.sub_group, xloc = xloc.bar_time, style = label.style_label_up, size = size.tiny, color = v.clr, tooltip = tt)


            hhll.unshift(new_rec)
    true 
//
fib_levels(class_hhll pp1, class_hhll pp2, log = false) =>
    class_fib_levels fib = class_fib_levels.new()
    diff = math.abs(pp1.pivot_pp - pp2.pivot_pp)
    minus = pp2.pivot_pp > pp1.pivot_pp
        
    fib.f_382 :=  minus ? pp2.pivot_pp - (diff * 0.382) : pp2.pivot_pp + (diff * 0.382)
    fib.f_382u := minus ? pp2.pivot_pp - (diff * (0.382 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (0.382*(1+xd_offset_percent)))
    fib.f_382l := minus ? pp2.pivot_pp - (diff * (0.382 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (0.382*(1-xd_offset_percent)))

    fib.f_50 := minus ? pp2.pivot_pp - (diff * 0.5) :  pp2.pivot_pp + (diff * 0.5)

    fib.f_618 := minus ? pp2.pivot_pp - (diff * 0.618) : pp2.pivot_pp + (diff * 0.618)
    fib.f_618u := minus ? pp2.pivot_pp - (diff * (0.618 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (0.618*(1+xd_offset_percent)))
    fib.f_618l := minus ? pp2.pivot_pp - (diff * (0.618 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (0.618*(1-xd_offset_percent)))

    fib.f_886 := minus ? pp2.pivot_pp - (diff * 0.886) : pp2.pivot_pp + (diff * 0.886)
    fib.f_886u := minus ? pp2.pivot_pp - (diff * (0.886 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (0.886*(1+xd_offset_percent)))
    fib.f_886l := minus ? pp2.pivot_pp - (diff * (0.886 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (0.886*(1-xd_offset_percent)))


    fib.f_1618 := minus ? pp2.pivot_pp - (diff * 1.618) : pp2.pivot_pp + (diff * 1.618)
    fib.f_1618u := minus ? pp2.pivot_pp - (diff * (1.618 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (1.618*(1+xd_offset_percent)))
    fib.f_1618l := minus ? pp2.pivot_pp - (diff * (1.618 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (1.618*(1-xd_offset_percent)))

    fib.f_2618 := minus ? pp2.pivot_pp - (diff * 2.618) : pp2.pivot_pp + (diff * 2.618)
    fib.f_3618 := minus ? pp2.pivot_pp - (diff * 3.618) : pp2.pivot_pp + (diff * 3.618)

    fib.f_200 := minus ? pp2.pivot_pp - (diff * 2.00) : pp2.pivot_pp + (diff * 2.00)

    fib.f_113 := minus ? pp2.pivot_pp - (diff * 1.13) : pp2.pivot_pp + (diff * 1.13)
    fib.f_113u := minus ? pp2.pivot_pp - (diff * (1.13 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (1.13*(1+xd_offset_percent)))
    fib.f_113l := minus ? pp2.pivot_pp - (diff * (1.13 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (1.13*(1-xd_offset_percent)))

    fib.f_786 :=  minus ? pp2.pivot_pp - (diff * 0.786) : pp2.pivot_pp + (diff * 0.786)
    fib.f_786u := minus ? pp2.pivot_pp - (diff * (0.786 * (1+xd_offset_percent))) : pp2.pivot_pp + (diff * (0.786*(1+xd_offset_percent)))
    fib.f_786l := minus ? pp2.pivot_pp - (diff * (0.786 * (1-xd_offset_percent))) : pp2.pivot_pp + (diff * (0.786*(1-xd_offset_percent)))    

    fib.f_224 :=  minus ? pp2.pivot_pp - (diff * 2.24) : pp2.pivot_pp + (diff * 2.24)
    fib.f_127 :=  minus ? pp2.pivot_pp - (diff * 1.27) : pp2.pivot_pp + (diff * 1.27)
    fib.f_141 :=  minus ? pp2.pivot_pp - (diff * 1.41) : pp2.pivot_pp + (diff * 1.41)
    fib.f_fake1 := minus ? pp2.pivot_pp - (diff * 0.00001) : pp2.pivot_pp + (diff * 0.00001)
    fib.f_fake2 := minus ? pp2.pivot_pp - (diff * 100) : pp2.pivot_pp + (diff * 100)
    fib
//
get_val(string key, class_fib_levels fib) =>
    result = switch(key)
        'F_382'  =>   fib.f_382
        'F_382U'  =>   fib.f_382u
        'F_382L'  =>   fib.f_382l
        'F_50'  =>   fib.f_50
        'F_618'  =>   fib.f_618
        'F_618U'  =>   fib.f_618u
        'F_618L'  =>   fib.f_618l               
        'F_886'  =>   fib.f_886
        'F_886U'  =>   fib.f_886u
        'F_886L'  =>   fib.f_886l
        'F_1618'  =>   fib.f_1618
        'F_1618U'  =>   fib.f_1618u
        'F_1618L'  =>   fib.f_1618l        
        'F_2618'  =>   fib.f_2618
        'F_3618'  =>   fib.f_3618
        'F_200'  =>   fib.f_200
        'F_113'  =>   fib.f_113
        'F_113U'  =>   fib.f_113u
        'F_113L'  =>   fib.f_113l
        'F_786'  =>   fib.f_786
        'F_786U'  =>   fib.f_786u
        'F_786L'  =>   fib.f_786l
        'F_224'  =>   fib.f_224
        'F_127'  =>   fib.f_127
        'F_141'  =>   fib.f_141
        'F_FAKE1'  =>  fib.f_fake1
        'F_FAKE2'  =>  fib.f_fake2
        => -1
    if(result == -1)
        runtime.error("Key = "+ key + " Not found")
    result
//
method set(class_legs leg, class_fib_levels fib) =>
    leg.l1_val := get_val(leg.l1_key, fib)
    leg.l2_val := get_val(leg.l2_key, fib)
//
method get_v_prop(map<string, class_p_visuals> v, class_xabcd rec) =>
    class_p_visuals result = na
    if(rec.bull_fl)
        result := v.get("BULL-" + rec.name)
    else
        result := v.get("BEAR-" + rec.name)
    result
//
method xabcd_patterns(array<class_hhll> hhll, array<class_xabcd> xabcd, map<string, class_p_visuals> v) =>
    d = hhll.get(0)
    c = hhll.get(1)
    b = hhll.get(2)
    a = hhll.get(3)
    x = hhll.get(4) 
    points = array.new<chart.point>()
    size = xabcd.size()
    for i = 0  to size - 1
        rec = xabcd.get(i)
        fib_xb = fib_levels(x, a)
        rec.xb.set(fib_xb)
        rec.bull_fl := b.pivot_pp <= rec.xb.l1_val and b.pivot_pp >= rec.xb.l2_val
        rec.bear_fl := b.pivot_pp >= rec.xb.l1_val and b.pivot_pp <= rec.xb.l2_val
        if(not rec.bull_fl and not rec.bear_fl)
            continue
        fib_ac = fib_levels(a, b)
        rec.ac.set(fib_ac)
        rec.bull_fl := c.pivot_pp >= rec.ac.l1_val and c.pivot_pp <= rec.ac.l2_val
        rec.bear_fl := c.pivot_pp <= rec.ac.l1_val and c.pivot_pp >= rec.ac.l2_val
        if(not rec.bull_fl and not rec.bear_fl)
            continue
        fib_bd = fib_levels(b, c)
        rec.bd.set(fib_bd)
        rec.bull_fl := d.pivot_pp <= rec.bd.l1_val and d.pivot_pp >= rec.bd.l2_val
        rec.bear_fl := d.pivot_pp >= rec.bd.l1_val and d.pivot_pp <= rec.bd.l2_val
        if(not rec.bull_fl and not rec.bear_fl)
            continue
        if(apply_xd)
            fib_xd = fib_levels(x, a)
            rec.xd.set(fib_xd)
            rec.bull_fl := d.pivot_pp <= rec.xd.l1_val and d.pivot_pp >= rec.xd.l2_val
            rec.bear_fl := d.pivot_pp >= rec.xd.l1_val and d.pivot_pp <= rec.xd.l2_val
            if(not rec.bull_fl and not rec.bear_fl)
                continue
        rec.bull_cnt := rec.bull_fl ? rec.bull_cnt + 1 : rec.bull_cnt
        rec.bear_cnt := rec.bear_fl ? rec.bear_cnt + 1 : rec.bear_cnt
        rec.last_bull := rec.bull_fl ? time : rec.last_bull
        rec.last_bear := rec.bear_fl ? time : rec.last_bear
        class_p_visuals visual = v.get_v_prop(rec) //v.get(v_prop)
        if(visual.plot_fl)
            ln_style = visual.line_style
            ln_color = visual.line_color 
            bg_color = visual.bg_color 

            points.push(chart.point.from_time(x.bar_time, x.pivot_pp))
            points.push(chart.point.from_time(a.bar_time, a.pivot_pp))
            points.push(chart.point.from_time(b.bar_time, b.pivot_pp))
            points.push(chart.point.from_time(x.bar_time, x.pivot_pp))

            points.push(chart.point.from_time(b.bar_time, b.pivot_pp))
            points.push(chart.point.from_time(c.bar_time, c.pivot_pp))
            points.push(chart.point.from_time(d.bar_time, d.pivot_pp))
            points.push(chart.point.from_time(b.bar_time, b.pivot_pp))
            polyline.new(points, curved = false, closed = false, xloc = xloc.bar_time, line_style = ln_style, line_color = ln_color, fill_color = bg_color)
            if(show_pattern_label)
                lbl_txt = rec.bull_fl ? "Bullish " + rec.name : "Bearish "  + rec.name
                label.new(a.bar_time, a.pivot_pp, style = label.style_none, text = lbl_txt, xloc = xloc.bar_time, textcolor = pattern_name_color)
            
//#endregion Definitions and functios

//#region Main 
//main code
[ph_ctf, pl_ctf] = get_ph_pl(0)
pre_size = hhll_ctf.size()
hhll_ctf.add_ph(ph_ctf, visuals.get('CTF'), ctf)
hhll_ctf.add_pl(pl_ctf, visuals.get('CTF'), ctf)
post_size = hhll_ctf.size()

if(post_size > pre_size)
    hhll_ctf.xabcd_patterns(p_xabcd, v_map)

sz = p_xabcd.size()
if(sz > 0 and barstate.islast)
    debug.log("Pattern name, Count, Latest Pattern Date")
    debug.log("========================================")
    for i = 0 to sz - 1
        rec = p_xabcd.get(i)
        debug.log(str.format("BULL {0} patterns = {1}", rec.name, rec.bull_cnt) + "  " + (na(rec.last_bull) ? "-NA-" : dt(rec.last_bull)))
        debug.log(str.format("BEAR {0} patterns = {1}", rec.name, rec.bear_cnt) + "  " + (na(rec.last_bear) ? "-NA-" : dt(rec.last_bear)))
    debug.display()  
//#endregion Main 
