Gann Angle Table Calculator Plotter
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © RozaniGhani-RG


//@version=4
study("Gann Angle Table Calculator Plotter", shorttitle = "GA", overlay = true, precision = 2)


// 1. Input
// 2. Variables
// 3. Ternary Conditional Operator
// 4. Array
// 5. Custom functions
// 6. Construct
// 7. Plot


// 1. Input
// Tooltip
string T0 = "Enter Price High or Low or any Price value."
string T1 = "Direction depends Price.\nUntick to reverse color."
string T2 = "Change table position."
string T3 = "Enable price to use decimal (0 to 3) and currency."
string T4 = "Hide table."
string T5 = "Track Plot."
// Group
var string G1 = "Table        Font          Position"
var string G2 = "Gann Angle              Track Plot"
// Inline
var string I1 = "Cardinal 1"
var string I2 = "Cross"
var string I3 = "Cardinal 2"
// Price
i_price         = input(0,            "Price      ", inline = "0", type    = input.float, minval= 0)
col_price       = input(color.yellow, "     ",       inline = "0", tooltip = T0)
i_dir           = input("Positive",   "Direction  ", inline = "1", options = ["Positive", "Negative"])
i_reverse       = input(true,         "",            inline = "1")
i_pos           = input(color.lime,   "",            inline = "1")
i_neg           = input(color.red,    "",            inline = "1", tooltip = T1)
// Table
// Table 0
i_show_0        = input(true,         "Gann   ",     inline = "2", group = G1)
string i_font_0 = input("normal",     "",            inline = "2", group = G1, options = ["tiny", "small", "normal", "large", "huge"])
string i_Y_0    = input("bottom",     "",            inline = "2", group = G1, options = ["top", "middle", "bottom"])
string i_X_0    = input("right",      "",            inline = "2", group = G1, options = ["left", "center", "right"])
// Table 1
i_show_1        = input(true,         "Formula",     inline = "3", group = G1)
string i_font_1 = input("normal",     "",            inline = "3", group = G1, options = ["tiny", "small", "normal", "large", "huge"])
string i_Y_1    = input("bottom",     "",            inline = "3", group = G1, options = ["top", "middle", "bottom"])
string i_X_1    = input("left",       "",            inline = "3", group = G1, options = ["left", "center", "right"])
// Other table setting
i_value         = input(false,        "Price    ",   inline = "4", group = G1)
i_currency      = input(false,        "Currency  ",  inline = "4", group = G1)
i_decimal       = input(0,            "",            inline = "4", group = G1, tooltip = T3, options = [0, 1, 2, 3])
// Gann Angle
g_025         = input(true,           "45 ",         inline =  I1, group = G2)
g_050         = input(true,           "90  ",        inline =  I1, group = G2)
g_075         = input(true,           "135  ",       inline =  I1, group = G2)
track_price   = input(false,          "Price",       inline =  I1, group = G2)
//
g_200         = input(true,           "360",         inline =  I2, group = G2)
g_price       = input(true,           "Price",       inline =  I2, group = G2)
g_100         = input(true,           "180  ",       inline =  I2, group = G2)
track_gann    = input(false,          "Gann",        inline =  I2, group = G2)
//
g_175         = input(true,           "315",         inline =  I3, group = G2)
g_150         = input(true,           "270 ",        inline =  I3, group = G2)
g_125         = input(true,           "225",         inline =  I3, group = G2)

// 2. Variables
var gann_table = table.new(position = i_Y_0 + "_" + i_X_0, columns = 7, rows = 5,  bgcolor = color.new(color.blue,100))
var calc_table = table.new(position = i_Y_1 + "_" + i_X_1, columns = 7, rows = 10, bgcolor = color.new(color.blue,100), border_color = color.new(color.blue, 100), border_width = 1)


// 3. Ternary Conditional Operator
col_pos       = i_reverse ? i_pos : i_neg
col_neg       = i_reverse ? i_neg : i_pos
ter_currency  = i_currency ? syminfo.currency + "\n" : ""
price_text    = i_dir == "Positive" ? "+++" : "---"
decimal       = i_decimal == 1 ? "#.#" : i_decimal == 2 ? "#.##" : i_decimal == 3 ? "#.###" : "#"


// 4. Array
// Array for both table
arr_deg       = array.new_int(),   array.push(arr_deg, 0)
arr_mult      = array.new_float(), array.push(arr_mult, 0)
arr_pos       = array.new_float()
arr_neg       = array.new_float()
sqrt_price    = sqrt(i_price)
// Gann Degree
for d = 0 to 7
    array.push(arr_deg,  array.get(arr_deg,  d) +   45)
    array.push(arr_mult, array.get(arr_mult, d) + 0.25)
array.remove(arr_deg,  0)
array.remove(arr_mult, 0)
// Gann Formula
for n = 0 to 7
    array.push(arr_pos, pow(sqrt_price + ((n + 1) * 0.25), 2))
    array.push(arr_neg, pow(sqrt_price - ((n + 1) * 0.25), 2))


// 5. Custom functions
td(_id) => tostring(array.get(arr_deg,  _id))
tm(_id) => tostring(array.get(arr_mult, _id))
tp(_id) => tostring(array.get(arr_pos,  _id), decimal)
tn(_id) => tostring(array.get(arr_neg,  _id), decimal)
ip      =  tostring(i_price, decimal)
sym     = i_dir == "Positive" ? ") + " : ") - "

// Table custom functions for Gann Table
fun_cell_0(_column, _row, _text, _color) => table.cell(gann_table, _column, _row, _text, bgcolor = _color, text_color = color.black, text_size = i_font_0)
fun_pos(_column,  _row, _text)           => fun_cell_0(_column, _row, _text,  col_pos)
fun_neg(_column,  _row, _text)           => fun_cell_0(_column, _row, _text,  col_neg)
fun_trans_0(_column,   _row)             => fun_cell_0(_column, _row, "   ", color.new(color.blue,100))
fun_blank_0()                            => fun_trans_0(5, 2), fun_trans_0(6, 2)
fun_price()                              => g_price ? i_price : na
fun_cond_0(_expr, _index)                => i_dir == "Positive" and _expr ? array.get(arr_pos, _index) : na
fun_cond_1(_expr, _index)                => i_dir == "Negative" and _expr ? array.get(arr_neg, _index) : na
fun_val(_column, _row, _index) =>
    if i_value
        if i_dir  == "Positive"
            table.cell_set_text(gann_table, _column, _row, ter_currency + tostring(array.get(arr_pos, _index), decimal))
        else
            table.cell_set_text(gann_table, _column, _row, ter_currency + tostring(array.get(arr_neg, _index), decimal))
fun_ref() =>
    if i_value
        table.cell_set_text(gann_table, 2, 2, ter_currency + tostring(i_price, decimal))
// Table custom functions for Formula
fun_cell_1(_column, _row, _text, _color) =>
    table.cell(calc_table, _column, _row, _text, bgcolor = _color, text_color = color.black, text_size = i_font_1)
fun_trans_1(_column,   _row)             => fun_cell_1(_column, _row, "   ", color.new(color.blue,100))
fun_blank_1()                            => fun_trans_1(4, 0), fun_trans_1(5, 0), fun_trans_1(6, 0)
dir(_id) =>
    if i_dir == "Positive" 
        tp(_id)
    else
        tn(_id)
cal_pos(_row) =>
    table.cell_set_bgcolor(calc_table, 0, _row, col_pos), table.cell_set_bgcolor(calc_table, 1, _row, col_pos)
    table.cell_set_bgcolor(calc_table, 2, _row, col_pos), table.cell_set_bgcolor(calc_table, 3, _row, col_pos)
cal_neg(_row) =>
    table.cell_set_bgcolor(calc_table, 0, _row, col_neg), table.cell_set_bgcolor(calc_table, 1, _row, col_neg)
    table.cell_set_bgcolor(calc_table, 2, _row, col_neg), table.cell_set_bgcolor(calc_table, 3, _row, col_neg)
fun_clear_1(_input, _pos) =>
    if _input == false
        table.clear(calc_table, 0, _pos, 4, _pos)
// Custom functions for Formula
fun_cond(_expr, _index) => i_dir == "Positive" and _expr ? array.get(arr_pos, _index) : i_dir == "Negative" and _expr ? array.get(arr_neg, _index) : na


// 6. Construct
if barstate.islast
    // Gann Table
    if i_show_0
        fun_blank_0()
        fun_cell_0(2, 2, price_text, col_price)
        fun_pos(1,  1, "   "), fun_pos(3, 1, "   "), fun_pos(3, 3, "   "), fun_pos(1, 3, "   ")
        fun_neg(1,  2, "   "), fun_neg(2, 1, "   "), fun_neg(3, 2, "   "), fun_neg(2, 3, "   ")
        fun_pos(0, 0, td(0)), fun_val(0, 0, 0)
        fun_neg(2, 0, td(1)), fun_val(2, 0, 1)
        fun_pos(4, 0, td(2)), fun_val(4, 0, 2)
        fun_neg(4, 2, td(3)), fun_val(4, 2, 3)
        fun_pos(4, 4, td(4)), fun_val(4, 4, 4)
        fun_neg(2, 4, td(5)), fun_val(2, 4, 5)
        fun_pos(0, 4, td(6)), fun_val(0, 4, 6)
        fun_neg(0, 2, td(7)), fun_val(0, 2, 7)
        // Default Price
        fun_ref() 
        if g_025 == false
            table.clear(gann_table, 0, 0, 1, 1)
        if g_050 == false
            table.clear(gann_table, 2, 0, 2, 1)
        if g_075 == false
            table.clear(gann_table, 3, 0, 4, 1)
        if g_100 == false
            table.clear(gann_table, 3, 2, 4, 2)
        if g_125 == false
            table.clear(gann_table, 3, 3, 4, 4)
        if g_150 == false
            table.clear(gann_table, 2, 3, 2, 4)
        if g_175 == false
            table.clear(gann_table, 0, 3, 1, 4)
        if g_200 == false
            table.clear(gann_table, 0, 2, 1, 2)
    // Calculation Table
    if i_show_1
        fun_cell_1(0, 0, "Direction",   color.yellow)
        fun_cell_1(1, 0, i_dir,   color.yellow)
        fun_cell_1(2, 0, "Reference Price",   color.yellow)
        fun_cell_1(3, 0, ip,   color.yellow)
        fun_cell_1(0, 1, "Degree",      color.blue)
        fun_cell_1(1, 1, "Multiplier",  color.blue)
        fun_cell_1(2, 1, "Calculation", color.blue)
        fun_cell_1(3, 1, "Gann\nPrice", color.blue)
        // Cell Formula
        for id = 0 to 7
            fun_cell_1(0, abs(id - 9), td(id), color.white)
            fun_cell_1(1, abs(id - 9), tm(id), color.white)
            fun_cell_1(2, abs(id - 9), "(sqrt(" + tm(id) + sym + ip + ")^2", color.white)
            fun_cell_1(3, abs(id - 9), dir(id), color.white)
        // Cell blank
        fun_blank_1()
        // Cell color
        cal_neg(2) // 360
        cal_pos(3) // 315
        cal_neg(4) // 270
        cal_pos(5) // 225
        cal_neg(6) // 180
        cal_pos(7) // 135
        cal_neg(8) // 90 
        cal_pos(9) // 45 
        // Clear cell if input is selected
        fun_clear_1(g_200, 2) // 360
        fun_clear_1(g_175, 3) // 315
        fun_clear_1(g_150, 4) // 270
        fun_clear_1(g_125, 5) // 225
        fun_clear_1(g_100, 6) // 180
        fun_clear_1(g_075, 7) // 135
        fun_clear_1(g_050, 8) // 90 
        fun_clear_1(g_025, 9) // 45 


// 7. Plot
// Plot Price
plot(fun_price(),       "Price", col_price, 1, trackprice = track_price, editable = false)
// Plot Cardinal
plot(fun_cond_0(g_025, 0),   "45",   col_pos, 1, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_075, 2),  "135",   col_pos, 2, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_125, 4),  "225",   col_pos, 3, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_175, 6),  "315",   col_pos, 4, trackprice =  track_gann, editable = false)
// Plot Cross
plot(fun_cond_0(g_050,1 ),   "90",   col_neg, 1, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_100,3 ),  "180",   col_neg, 2, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_150,5 ),  "270",   col_neg, 3, trackprice =  track_gann, editable = false)
plot(fun_cond_0(g_200,7 ),  "360",   col_neg, 4, trackprice =  track_gann, editable = false)
// Plot Cardinal
plot(fun_cond_1(g_025, 0),   "45",   col_pos, 1, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_075, 2),  "135",   col_pos, 2, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_125, 4),  "225",   col_pos, 3, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_175, 6),  "315",   col_pos, 4, trackprice =  track_gann, editable = false)
// Plot Cross
plot(fun_cond_1(g_050,1 ),   "90",   col_neg, 1, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_100,3 ),  "180",   col_neg, 2, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_150,5 ),  "270",   col_neg, 3, trackprice =  track_gann, editable = false)
plot(fun_cond_1(g_200,7 ),  "360",   col_neg, 4, trackprice =  track_gann, editable = false)