XABCD Harmonic Pattern Custom Range Interactive
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RozaniGhani-RG
// Credits to Scott M Carney, author of Harmonic Trading : Volume One, Two and Three

//@version=5
indicator('XABCD Harmonic Pattern Custom Range Interactive', shorttitle = 'XABCD_HP_CRI', overlay = true, precision = 3)
// —— Import {
import RozaniGhani-RG/PriceTimeInteractive/2 as pti
import RozaniGhani-RG/DeleteArrayObject/1    as obj
import RozaniGhani-RG/HarmonicDB/1           as hdb
import RozaniGhani-RG/HarmonicSwitches/1     as sw
import RozaniGhani-RG/HarmonicCalculation/1  as calc
// }
// —— Content {
// 0.  Input
// 1.  Initialization
// 2.  TRADE IDENTIFICATION - Harmonic Trading System Part 1
// 3.  TRADE EXECUTION      - Harmonic Trading System Part 2
// 4.  TRADE MANAGEMENT     - Harmonic Trading System Part 3
// 5.  Common Drawings Custom Functions 
// 6.  Draw XABCD Pattern (Trade Identification)
// 7.  Draw zones
// 8.  Table 
// 9   Plot
// 10. Construct
// }
// —— 0. Input {
// ———— 1) TRADE IDENTIFICATION - TIME POINTS {
int point_X  = timestamp('2022-03')
int point_A  = timestamp('2022-04')
int point_B  = timestamp('2022-05')
int point_C  = timestamp('2022-06')
int time_X   = input.time(point_X, 'Point X', group = '1) TRADE IDENTIFICATION - TIME POINTS', inline = 'X', confirm = true, tooltip = 'Point X must BEFORE Point A')
int time_A   = input.time(point_A, 'Point A', group = '1) TRADE IDENTIFICATION - TIME POINTS', inline = 'A', confirm = true, tooltip = 'Point A must BEFORE Point B')
int time_B   = input.time(point_B, 'Point B', group = '1) TRADE IDENTIFICATION - TIME POINTS', inline = 'B', confirm = true, tooltip = 'Point B must BEFORE Point C')
int time_C   = input.time(point_C, 'Point C', group = '1) TRADE IDENTIFICATION - TIME POINTS', inline = 'C', confirm = true, tooltip = 'Point C must AFTER Point B')
    // }
// ———— 2) TRADE EXECUTION - BC VALIDITY {
i_s_valid_BC = input.string('Text', 'Valid BC Display', group = '2) TRADE EXECUTION - BC VALIDITY', options = ['Text', 'Emoji'], tooltip = 'Display style for BC Validity')
    // }
// ———— 2) TRADE EXECUTION - SPECIAL SITUATION (D = XA) {
G2           = '2) TRADE EXECUTION - SPECIAL SITUATION (D = XA)'
T2           = 'Change value D = XA\n if'
i_f_gart     = input.float(0.786,          'Gartley', group = G2, options =[0.786, 0.886], tooltip = T2 + 'Gartley was found.\nDefault : 0.786\nSpecial : 0.886')
i_f_crab     = input.float(1.618, 'Crab / Deep Crab', group = G2, options =[1.618, 1.902], tooltip = T2 + 'Crab / Deep Crab was found.\nDefault : 1.618\nSpecial : 1.902')
i_f_shark    = input.float(0.886,            'Shark', group = G2, options =[0.886, 1.130], tooltip = T2 + 'Shark was found.\nDefault : 0.886\nSpecial : 1.130')
    // }
// ———— 3) TRADE MANAGEMENT (AUTO) {
T3           = 'To show, go to Chart setting\nGo to Status Line, tick Indicator Titles\nGo to Scales, tick Indicator Name Label\nExtend right will hide label'
T4           = 'Execution Point :\nPoint D (Default)\nPoint C (Offset Point)'
T5           = 'Full : Show all labels and lines\nCompact : Show important labels and lines'
T6           = 'PRZ : Potential Reversal Zone (Trade Execution)\n PL : Profit & Loss (Trade Management)'
i_extend     = input.string(   'None',             'Extend lines', group = '3) TRADE MANAGEMENT (AUTO)', tooltip = T3, options = ['Right',   'None'])
i_execute    = input.string('Price D',          'Execution Point', group = '3) TRADE MANAGEMENT (AUTO)', tooltip = T4, options = ['Price C', 'Price D'])
i_display    = input.string(   'Full', 'Harmonic Pattern Display', group = '3) TRADE MANAGEMENT (AUTO)', tooltip = T5, options = ['Full',    'Compact'])
i_PL         = input.string(     'PL',  'Show Profit & Loss (PL)', group = '3) TRADE MANAGEMENT (AUTO)', tooltip = T6, options = ['None',    'PRZ', 'PL', 'Both'])
    // }
// ———— 3) TRADE MANAGEMENT (MANUAL) {
i_b_SL       = input.bool(false,  'Stop Loss   ', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'SL')
i_f_SL       = input.float(0,         '        ', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'SL',  minval = 0, tooltip = 'Tick and input value')
i_b_TP1      = input.bool(false, 'Take Profit 1', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'TP1')
i_f_TP1      = input.float(0,         '        ', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'TP1', minval = 0, tooltip = 'Tick and input value')
i_b_TP2      = input.bool(false, 'Take Profit 2', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'TP2')
i_f_TP2      = input.float(0,         '        ', group = '3) TRADE MANAGEMENT (MANUAL)', inline = 'TP2', minval = 0, tooltip = 'Tick and input value')
    // }
// ———— 4) TABLE DISPLAY {
T8           = '1) Tick to show table\n2) Small font size recommended for mobile app or multiple layout'
T9           = 'Table must be tick before change table position'
i_b_table    = input.bool(true,         'Show Table |', group = '4) TABLE DISPLAY', inline = 'Table1')
i_s_font     = input.string('normal',      'Font size', group = '4) TABLE DISPLAY', inline = 'Table1', options = ['tiny', 'small',  'normal', 'large', 'huge'], tooltip = T8)
i_s_Y        = input.string('bottom', 'Table Position', group = '4) TABLE DISPLAY', inline = 'Table2', options = ['top',  'middle', 'bottom'])
i_s_X        = input.string('left',                 '', group = '4) TABLE DISPLAY', inline = 'Table2', options = ['left', 'center', 'right'],                   tooltip = T9)
    // }
// ———— 5) OTHERS {
i_b_col      = input.bool(true, 'Use trend color', group = '5) OTHERS', tooltip = 'Show Trend color if true\nTrue : Lime (Bullish), Red (Bearish)\n False : Blue')
i_b_currency = input.bool(true,   'Show Currency', group = '5) OTHERS')
    // }
// }
// —— 1.   Initialization {
[animal_name, spec_B_XA_min, spec_B_XA_max, spec_C_AB_min, spec_C_AB_max, spec_D_BC_min, spec_D_BC_max, spec_D_XA_nom, spec_E_SL_nom] = hdb.animal_db(i_f_crab, i_f_gart, i_f_shark)
// }
// —— 2.   TRADE IDENTIFICATION - Harmonic Trading System Part 1 {
// ———— 2.1  Get Price from Point X to Point C {
[high_X, low_X, close_X] = pti.hlc_time(time_X)
[high_A, low_A, close_A] = pti.hlc_time(time_A)
[high_B, low_B,      _ ] = pti.hlc_time(time_B)
[high_C, low_C,      _ ] = pti.hlc_time(time_C)
    // }
// ———— 2.2  Determine Point X is lower or higher than Point A {
bool X_lower_A  = close_X < close_A
[pr_X, pr_A, pr_B, pr_C]  = sw.TupleSwitchHL(X_lower_A, low_X, high_X, low_A, high_A, low_B, high_B, low_C, high_C)
[style0, style1, col_dir] = sw.TupleSwitchStyleColor(X_lower_A)
[str_dir, str_X, str_A]   = sw.TupleSwitchString(X_lower_A)
    // }
// ———— 2.3  Get ratio and difference for price and time {
y_XA = calc.PriceDiff(pr_A, pr_X), time_XA = calc.TimeDiff(time_A, time_X)
y_AB = calc.PriceDiff(pr_B, pr_A), time_AB = calc.TimeDiff(time_B, time_A), y_XAB = y_AB / y_XA, time_XAB = calc.TimeDiff(time_B, time_X)
y_BC = calc.PriceDiff(pr_C, pr_B), time_BC = calc.TimeDiff(time_C, time_B), y_ABC = y_BC / y_AB
    // }
// ———— 2.4  Variables for Point D {
bool c_ret = math.abs(y_ABC) >= 0.382 and math.abs(y_ABC) <=  0.886
bool c_pro = math.abs(y_ABC) >= 1.130 and math.abs(y_ABC) <=  1.618
var bool_animal = array.new_bool(7), var string animal = na, var int animal_number = na
    // }
// ———— 2.5  Get time for Point D {
int time_D = na, time_D  := time_C + time_XAB
    // }
// ———— 2.6  Verify animal type {
f_bool(int _index) => math.abs(y_XAB) >= array.get(spec_B_XA_min, _index) and math.abs(y_XAB) <= array.get(spec_B_XA_max, _index)
for x = 0 to 5
    array.set(bool_animal, x, f_bool(x) and c_ret)
array.set(bool_animal, 6, f_bool(6) and c_pro)
if array.includes(bool_animal, true)
    animal        := array.get(    animal_name, array.indexof( bool_animal, array.includes(bool_animal, true)))
    animal_number := array.indexof(bool_animal, array.includes(bool_animal, true))
    // }
// ———— 2.7  Calculations for Point D {
[D_XA , D_BC1, D_BC2] = calc.ReturnIndexOf3Arrays(spec_D_XA_nom, spec_D_BC_min, spec_D_BC_max, animal_number)
    // }
// ———— 2.8  Remove price from negative sign to compare with D = BC {
pr_D = calc.AbsoluteRange(pr_A, y_XA, D_XA)
y_CD = calc.PriceDiff(pr_D, pr_C), time_CD = calc.TimeDiff(time_D, time_C)
y_AD = calc.PriceDiff(pr_D, pr_A), time_AD = calc.TimeDiff(time_D, time_A)
    // }
// ———— 2.9  Check D = BC validity {
[str_invalid, str_valid] = sw.TupleSwitchValid(i_s_valid_BC)
y_BCD    = y_CD / y_BC
valid_BC = math.abs(y_BCD) > math.abs(D_BC2) ? str_invalid : math.abs(y_BCD) < math.abs(D_BC1) ? str_invalid : str_valid
    // }
// ———— 2.10 Calculate average price and time {
// To be used later in labels
y_XB = calc.PriceAverage(pr_X, pr_B), x_XB = calc.TimeAverage(time_X, time_B)
y_AC = calc.PriceAverage(pr_A, pr_C), x_AC = calc.TimeAverage(time_A, time_C)
y_BD = calc.PriceAverage(pr_B, pr_D), x_BD = calc.TimeAverage(time_B, time_D)
y_XD = calc.PriceAverage(pr_X, pr_D), x_XD = calc.TimeAverage(time_X, time_D)
    // }
// }
// —— 3.   TRADE EXECUTION - Harmonic Trading System Part 2 {
// ———— 3.1  D = BC variables {
pr_BC1 = calc.AbsoluteRange(pr_C, y_BC, D_BC1)
pr_BC2 = calc.AbsoluteRange(pr_C, y_BC, D_BC2)
    // }
// ———— 3.2  Execution Points {
// [E1, E2] = switch i_execute
[E1, E2] = sw.TupleSwitchTime(i_execute, time_C, time_D, time_XA)
x_DE     = calc.TimeAverage(time_D, E2)
    // }
// }
// —— 4.   TRADE MANAGEMENT - Harmonic Trading System Part 3 {
F_SL   = array.get(spec_E_SL_nom, animal_number)
pr_SL  = i_b_SL  ? i_f_SL  : calc.AbsoluteRange(pr_A, y_XA, F_SL)               // Stop Loss
pr_TP1 = i_b_TP1 ? i_f_TP1 : calc.AbsoluteRange(pr_D, y_AD, 0.382)              // Take Profit 1
pr_TP2 = i_b_TP2 ? i_f_TP2 : calc.AbsoluteRange(pr_D, y_AD, 0.618)              // Take Profit 2
// }
// —— 5.   Common Drawings Custom Functions {
// ———— 5.1  String format format for price {
f_str(float _value, bool _bool = false, string _text = '') =>
    if _bool
        string str = ' ' + _text
        str.tostring(_value, '0.000') + str
    else
        str.tostring(_value, '0.000')
    // }
// ———— 5.2  Get price difference from point D in percent format {
// To be used during TRADE EXECUTION and TRADE MANAGEMENT
f_pct(float _price) =>
    string pct = na
    bear_bool =  (_price - pr_D) / pr_D > 0 ? ' ▼' :  (_price - pr_D) / pr_D > 0 ? ' ▲' : ''
    bull_bool = -(pr_D - _price) / pr_D > 0 ? ' ▲' : -(pr_D - _price) / pr_D < 0 ? ' ▼' : ''
    if str_dir == 'BEARISH'
        pct := str.tostring((_price - pr_D) / pr_D, '##.## %') + bear_bool
    else
        pct := str.tostring(-(pr_D - _price) / pr_D, '##.## %') + bull_bool
    pct
    // }
// ———— 5.4  Shared variable and array values {
//                          0,      1,      2,      3,      4
str_XABCD = array.from(   'X',    'A',    'B',    'C',    'D') // To be used with f_label_XABCD()
arr_pr    = array.from(  pr_X,   pr_A,   pr_B,   pr_C,   pr_D) // To be used with f_label_XABCD()
arr_time  = array.from(time_X, time_A, time_B, time_C, time_D) // To be used with f_label_XABCD(), f_line()
y_ratio   = array.from(  y_XB,   y_AC,   y_BD,   y_BD,   y_XD)
x_ratio   = array.from(  x_XB,   x_AC, time_B,   x_BD,   x_XD)
arr_ratio = array.from(f_str(math.abs(y_XAB), true, 'XA'),
                         f_str(math.abs(y_ABC), true, 'AB'),
                         '',
                         f_str(math.abs(y_BCD), true, 'BC') + '\n' + valid_BC)

//                    price,                                                 spec, ratio / percent
price_X   = calc.PriceCurrency(i_b_currency, pr_X)
price_A   = calc.PriceCurrency(i_b_currency, pr_A)
price_B   = calc.PriceCurrency(i_b_currency, pr_B),   spec_B   = calc.RangeText(spec_B_XA_min, spec_B_XA_max, animal_number, 'XA'), ratio_B  = calc.RatioText(y_XAB, 'XA')
price_C   = calc.PriceCurrency(i_b_currency, pr_C),   spec_C   = calc.RangeText(spec_C_AB_min, spec_C_AB_max, animal_number, 'AB'), ratio_C  = calc.RatioText(y_ABC, 'AB')
price_D   = calc.PriceCurrency(i_b_currency, pr_D),   spec_D   =                                       calc.RatioText(D_XA,  'XA'), ratio_D  = calc.RatioText(D_XA,  'XA')
price_BC  = calc.PriceCurrency(i_b_currency, pr_D),   spec_BC  = calc.RangeText(spec_D_BC_min, spec_D_BC_max, animal_number, 'BC'), ratio_BC = calc.RatioText(y_BCD, 'BC')
price_BC1 = calc.PriceCurrency(i_b_currency, pr_BC1), spec_BC1 =                                       calc.RatioText(D_BC1, 'BC'),                                      pct_BC1 = f_pct(pr_BC1)
price_BC2 = calc.PriceCurrency(i_b_currency, pr_BC2), spec_BC2 =                                       calc.RatioText(D_BC2, 'BC'),                                      pct_BC2 = f_pct(pr_BC2)
price_SL  = calc.PriceCurrency(i_b_currency, pr_SL),  spec_SL  =                                       calc.RatioText(F_SL,  'XA'), ratio_SL  = i_b_SL  ? 'MANUAL' : '', pct_SL  = f_pct(pr_SL)
price_TP1 = calc.PriceCurrency(i_b_currency, pr_TP1), spec_TP1 =                                       calc.RatioText(0.382, 'AD'), ratio_TP1 = i_b_TP1 ? 'MANUAL' : '', pct_TP1 = f_pct(pr_TP1)
price_TP2 = calc.PriceCurrency(i_b_currency, pr_TP2), spec_TP2 =                                       calc.RatioText(0.618, 'AD'), ratio_TP2 = i_b_TP2 ? 'MANUAL' : '', pct_TP2 = f_pct(pr_TP2)

//                             0,         1,        2,         3,          4
row_0       = array.from('POINT',   'RATIO',   'SPEC',   'PRICE',  'PERCENT')
row_1       = array.from(    'X',        '',  str_X,   price_X,           '')
row_2       = array.from(    'A',        '',  str_A,   price_A,           '')
row_3       = array.from(    'B', ratio_B,   spec_B,   price_B,           '')
row_4       = array.from(    'C', ratio_C,   spec_C,   price_C,           '')
row_5       = array.from(    'D', ratio_D,   spec_D,   price_D,  'REF POINT')
row_6       = array.from(  'PRZ', ratio_BC,  spec_BC,  price_BC,   valid_BC)
row_7       = array.from(  'BC1',       '',  spec_BC1, price_BC1,    pct_BC1)
row_8       = array.from(  'BC2',       '',  spec_BC2, price_BC2,    pct_BC2)
row_9       = array.from(   'SL', ratio_SL,  spec_SL,  price_SL,     pct_SL)
row_10      = array.from(  'TP1', ratio_TP1, spec_TP1, price_TP1,    pct_TP1)
row_11      = array.from(  'TP2', ratio_TP2, spec_TP2, price_TP2,    pct_TP2)
col_valid   = sw.SwitchColor(valid_BC) 
_extend     = sw.SwitchExtend(i_extend)
str_special = i_f_gart == 0.886 or i_f_crab == 1.902 or i_f_shark == 1.130 ? '\nSPECIAL SITUATION' : ''
    // }
// }
// —— 6.   Draw XABCD Pattern (Trade Identification) {
// ———— 6.1  Initialize arrays {
//                                                                                     0,  1,  2,   3,  4, 5
var label_XABCD  = array.new_label(6),    obj.delete(label_XABCD) // Labels       for  X,  A,  B,   C, D
var ratio_XABCD  = array.new_label(4),    obj.delete(ratio_XABCD) // Labels       for XA, AB, BC, XA
var solid_XABCD  = array.new_line(4),     obj.delete(solid_XABCD) // Solid  lines for XA, AB, BC, CD
var dot_XABCD    = array.new_line(4),     obj.delete(  dot_XABCD) // Dotted lines for     XB,     AC, BD, XD
var fill_XABCD   = array.new_linefill(2), obj.delete( fill_XABCD) // Line    fill for XA-XB,  BC-AC
var box[] box_XA = array.new_box(1),      obj.delete(  box_XA)    // Text box     for XA
// }
// ———— 6.2  XABCD custom functions {
f_label_XABCD(int _x, color _col = color.blue) =>
    label.new(
     x         = array.get(arr_time,  _x),
     y         = array.get(arr_pr, _x),
     text      = array.get(str_XABCD, _x), 
     xloc      = xloc.bar_time,
     color     = color.new(color.blue, 100),
     style     = _x % 2 ? style1 : style0,
     textcolor = i_b_col ? col_dir : _col)

f_ratio_XABCD(int _x, color _col = color.blue) =>
    label.new(
     x     = array.get(x_ratio,  _x),
     y     = array.get(y_ratio, _x),
     text  = array.get(arr_ratio, _x),
     xloc  = xloc.bar_time,
     style = label.style_label_center,
     textcolor = i_b_col ? color.black : color.white,
     color = i_b_col ? col_dir : _col)

f_line(int _x1, int _y1, int _x2, int _y2, bool _bool = true, int _width = 1, int _transp = 0) =>
    _style = switch _bool
        true  => line.style_solid
        false => line.style_dotted
    line.new(   x1 = array.get(arr_time, _x1),
                 y1    = array.get(arr_pr, _y1),
                 x2    = array.get(arr_time, _x2),
                 y2    = array.get(arr_pr, _y2),
                 xloc  = xloc.bar_time,
                 color =  i_b_col ? color.new(col_dir, _transp) : color.new(color.blue, _transp), 
                 style = _style,
                 width = _width)

f_fill_XABCD(int _x1 = 0, int _x2 = 0, color _col = color.blue) =>
    linefill.new(array.get(solid_XABCD, _x1), array.get(dot_XABCD, _x2), i_b_col ? color.new(col_dir, 80) : color.new(_col, 80))

f_box() => box.new(
     left         = time_X,
     top          = pr_X,
     right        = time_D,
     bottom       = pr_SL,
     xloc         = xloc.bar_time,
     bgcolor      = color.new(color.blue, 100),
     border_color = color.new(color.blue, 100),
     text         = str_dir + ' ' + animal + ' ' + f_str(math.abs(D_XA), true, 'XA') + str_special,
     text_color   = color.blue,
     text_wrap    = text.wrap_auto,
     text_size    = size.normal)
// }
// ———— 6.3  Finalized Drawing For Trade Identification {
f_dwg_identification() =>
    array.set(ratio_XABCD, 3, f_ratio_XABCD(3, col_valid))
    if i_display == 'Full'
        for x = 0 to 4
            array.set(label_XABCD, x, f_label_XABCD(x))
        array.set(label_XABCD, 4, f_label_XABCD(4, col_valid))
        for x = 0 to 1
            array.set(ratio_XABCD, x, f_ratio_XABCD(x))
        for x = 0 to 3
            array.set(solid_XABCD,  x, f_line(x, x, x + 1, x + 1, true, 4))
        for x = 0 to 2
            array.set(dot_XABCD,  x, f_line(x, x, x + 2, x + 2, false))
    else if i_display == 'Compact'
        for x = 0 to 3
            array.set(solid_XABCD,  x, f_line(x, x, x + 1, x + 1, true, 4, 100))
        for x = 0 to 2
            array.set(dot_XABCD,  x, f_line(x, x, x + 2, x + 2, false, 1, x % 2 ? 0 : 100))
    array.set(dot_XABCD, 3, f_line(0, 0, 4, 4, false))
    f_fill_XABCD(), f_fill_XABCD(2, 2, col_valid)
    array.set(box_XA, 0, f_box())
// }
// }
// —— 7.   Draw zones {
// ———— 7.1  Zone arrays {
var line_zone  = array.new_line(6),     obj.delete(line_zone)
var fill_zone  = array.new_linefill(5), obj.delete(fill_zone)
// }
// ———— 7.2  Zones custom functions {
f_label_zone(float _y, string _text, string _price, string _percent, color _col = color.blue) =>
    var label id = na
    label.delete(id)
    id := label.new(x = E2, y = _y, text  = _text + ' : ' + _price + ' , ' + _percent,
     xloc  = xloc.bar_time,
     style = label.style_label_left, color = color.new(color.blue, 100), textcolor = _col)

f_line_zone(float _pr, color _color = color.orange) => line.new(x1 = E1, y1 = _pr, x2 = E2, y2 = _pr, xloc  = xloc.bar_time, extend = _extend, color = color.new(_color, 0))
f_fill_zone(int _x1 = 0,   int _x2 = 1, color _col = color.orange) => linefill.new(array.get(line_zone,   _x1), array.get(line_zone, _x2), color.new(_col, 80))
// }
// ———— 7.3  Finalized Drawing For Trade Execution {
f_dwg_execution() =>
    array.set(line_zone, 1, f_line_zone(pr_BC1)), array.set(fill_zone, 0, f_fill_zone())
    array.set(line_zone, 2, f_line_zone(pr_BC2)), array.set(fill_zone, 1, f_fill_zone(0, 2, color.orange))
    if i_extend == 'None'
        f_label_zone(pr_BC1, 'BC1', price_BC1, pct_BC1, color.orange), f_label_zone(pr_BC2, 'BC2', price_BC2, pct_BC2, color.orange)
// }
// ———— 7.4  Finalized Drawing For Trade Management {
f_dwg_management() =>
    array.set(line_zone, 3, f_line_zone(pr_SL,  color.red))
    array.set(line_zone, 4, f_line_zone(pr_TP1, color.lime))
    array.set(line_zone, 5, f_line_zone(pr_TP2, color.lime)), array.set(fill_zone, 4, f_fill_zone(4, 5, color.lime))
    if i_extend == 'None'
        f_label_zone(pr_SL,  'SL' , price_SL , pct_SL,  color.red)
        f_label_zone(pr_TP1, 'TP1', price_TP1, pct_TP1, color.lime), f_label_zone(pr_TP2, 'TP2', price_TP2, pct_TP2, color.lime)
    if i_PL == 'Both'
        array.set(fill_zone, 2, f_fill_zone(2, 3, color.red)), array.set(fill_zone, 3, f_fill_zone(1, 4, color.lime))
    else if i_PL == 'PL'
        array.set(fill_zone, 2, f_fill_zone(0, 3, color.red)), array.set(fill_zone, 3, f_fill_zone(0, 4, color.lime))
// }
// }
// —— 8.   Table {
// ———— 8.1  Table variable {
var table_XABCD = table.new(position = i_s_Y + '_' + i_s_X, columns =7, rows = 16, bgcolor = color.black, border_color = color.gray, border_width = 1)
// }
// ———— 8.2  Table custom functions {
f_cell(int _column, int _row, _id, color _col1 = color.black, color _col2 = color.white, bool halign = true) =>
    table.cell(table_XABCD, _column, _row, array.get(_id, _column), text_color = _col1, text_size = i_s_font, 
     text_halign = halign ? text.align_right : text.align_center, bgcolor = _col2)

f_row_title() =>
    for _row = 0 to 2
        f_cell(_row, 0, row_0, color.white, col_valid, false)
    if i_extend == 'Right'
        for _row = 3 to 4
            f_cell(_row, 0, row_0, color.white, col_valid, false)

f_row(int _row, _id, color _col1 = color.black, color _col2 = color.white) =>
    f_cell(0,  _row, _id, _col1, _col2, false), f_cell(1,  _row, _id, _col1, _col2), f_cell(2,  _row, _id, _col1, _col2)
    if i_extend == 'Right'
        f_cell(3,  _row, _id, _col1, _col2)
        f_cell(4,  _row, _id, _col1, _col2)

f_row_twin(int _row1, _id1, int _row2, _id2, color _col1, color _col2) => f_row(_row1, _id1, _col1, _col2), f_row(_row2, _id2, _col1, _col2)
// }
// ———— 8.3  Finalized table {
f_table_array() =>
    if i_b_table
        if i_display != 'Full' or i_PL != 'None'
            f_row_title()
        if i_display == 'Compact'
            f_row_twin(1, row_1, 2, row_2, color.blue, color.white), f_row_twin(3, row_3, 4, row_4, color.blue, color.white), f_row(5, row_5, color.white, col_valid)
        if i_PL == 'PRZ' or i_PL == 'Both'
            f_row(6, row_6,  color.white, col_valid), f_row_twin(7, row_7, 8, row_8, color.black, color.orange)
        if i_PL == 'PL' or i_PL == 'Both'
            f_row( 9, row_9,  color.white, color.red), f_row_twin(10, row_10, 11, row_11, color.black, color.lime)
// }
// ———— 8.4  Invalid table {
f_table_invalid() =>
    if i_b_table
        f_row_title()
        f_row_twin(1, row_1, 2, row_2, color.blue, color.white)
        f_row_twin(3, row_3, 4, row_4, color.blue, color.white)
        f_row(5, row_5, color.white, col_valid)
        f_row(6, row_6, color.white, col_valid)
// }           
// }           
// —— 9    Plot {
// ———— 9.1  Plot custom functions {
f_plot(float _float)     => (valid_BC == 'VALID' or valid_BC == '✅') and i_extend == 'Right' ? _float : na
f_plot_exe(float _float) => (valid_BC == 'VALID' or valid_BC == '✅') and i_extend == 'Right' and i_PL != 'PL'  and i_PL != 'None' ? _float : na
f_plot_mgt(float _float) => (valid_BC == 'VALID' or valid_BC == '✅') and i_extend == 'Right' and i_PL != 'PRZ' and i_PL != 'None' ? _float : na
f_col(color _color)      => color.new(_color, 100)
// }
// ———— 9.2  Plot Trade Execution {
plot(f_plot(pr_D),       'PRZ', f_col(color.blue),   editable = false)
plot(f_plot_exe(pr_BC1), 'BC1', f_col(color.orange), editable = false)
plot(f_plot_exe(pr_BC2), 'BC2', f_col(color.orange), editable = false)
// }
// ———— 9.3  Plot Trade Management {
plot(f_plot_mgt(pr_SL),  'SL',  f_col(color.red),    editable = false)
plot(f_plot_mgt(pr_TP1), 'TP1', f_col(color.lime),   editable = false)
plot(f_plot_mgt(pr_TP2), 'TP2', f_col(color.lime),   editable = false)
// }
// }
// —— 10.  Construct {
if barstate.islast
    f_dwg_identification()
    if time_A < time_B and time_B < time_C
        if valid_BC == 'VALID' or valid_BC == '✅'
            array.set(line_zone, 0, f_line_zone(pr_D, color.blue))
            if i_extend == 'None'
                f_label_zone(pr_D, 'PRZ', price_D, 'REF POINT', color.blue)
            if i_PL == 'Both'
                f_dwg_execution()
                f_dwg_management()
            else if i_PL == 'PRZ'
                f_dwg_execution()
            else if i_PL == 'PL'
                f_dwg_management()
            f_table_array()
        else if valid_BC == 'INVALID' or valid_BC == '❌'
            f_table_invalid()
// }