[GTH decimals heatmap] (wide screen advised)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © gehteha

//@version=5
indicator("[GTH decimals heatmap]", overlay = false)

pre = input.bool(false, "Pre-market", tooltip = "ETH must be selected on the chart")
main = input.bool(true, "Main market", tooltip = "If only \"Main market\" is chosen, select RTH on the chart to have more data available.")
post = input.bool(false, "Post-market", tooltip = "ETH must be selected on the chart")

size_x = input.string(defval = size.tiny, title = "Size X", options = [size.auto, size.tiny, size.small, size.normal, size.large, size.huge])
size_y = input.string(defval = size.auto, title = "Size Y", options = [size.auto, size.tiny, size.small, size.normal, size.large, size.huge])
norm = input.bool(defval=false, title = "Normalize", tooltip = "If actived, black is assigned to the lowest number of occurrences. Otherwise, black is assigned to zero occurrences.")
prt_val = input.bool(false, title = "Print Values")

var o_cents = array.new_int(100, 0)
var h_cents = array.new_int(100, 0)
var l_cents = array.new_int(100, 0)
var c_cents = array.new_int(100, 0)

var col_hi = color.white
var col_lo = color.black
var hm_color = col_hi
var tbl_hdr_col = col_lo

var tbl = table.new(position = position.bottom_center, columns = 101, rows = 5, bgcolor = col_lo, frame_color = color.white, frame_width = 1)


cl(val, min, max) =>
    mn = norm ? min : 0
    st = (max - mn) / 100
    100 - ((val - mn) / st)
//
frac(v) =>
    i = (math.round(v, 2) - int(v)) * 100

    int ret = 0
    for a = 0 to 99
        if i == a
            ret := a
            break
    ret
//
col(v, mn, mx) =>
    if v == mn
        color.white
    else
        if v == mx
            color.black
        else
            if v > 50
                color.white
            else
                color.black
// 
set_field(src, min, max, i, c) =>
    tmp = cl(src, min, max)
    table.cell_set_text_color(tbl, i+1, c, col(tmp, min, max))
    table.cell_set_bgcolor(tbl, i+1, c, color.new(hm_color, tmp))
    table.cell_set_text_size(tbl, i+1, c, size_x)
    if src == min
        table.cell_set_bgcolor(tbl, i+1, c, color.rgb(0, 0, 255))
        table.cell_set_text_color(tbl, i+1, c, color.white)
    if src == max
        table.cell_set_bgcolor(tbl, i+1, c, color.rgb(134, 201, 255))
        table.cell_set_text_color(tbl, i+1, c, color.black)
// 
inc(ar, i) =>
    array.set(ar, i, array.get(ar, i) + 1)

//

if (session.ispremarket and pre) or (session.ispostmarket and post) or (session.ismarket and main)
    o_fr = frac(open)
    h_fr = frac(high)
    l_fr = frac(low)
    c_fr = frac(close)

    inc(o_cents, o_fr)
    inc(h_cents, h_fr)
    inc(l_cents, l_fr)
    inc(c_cents, c_fr)

if barstate.isfirst
    table.cell(tbl, 0, 0, "", text_color = color.white, bgcolor = tbl_hdr_col, text_size = size_x)
    table.cell(tbl, 0, 1, "O", text_color = color.white, bgcolor = tbl_hdr_col, text_size = size_y)
    table.cell(tbl, 0, 2, "H", text_color = color.white, bgcolor = tbl_hdr_col, text_size = size_y)
    table.cell(tbl, 0, 3, "L", text_color = color.white, bgcolor = tbl_hdr_col, text_size = size_y)
    table.cell(tbl, 0, 4, "C", text_color = color.white, bgcolor = tbl_hdr_col, text_size = size_y)

    for a = 1 to 100
        table.cell(tbl, a, 0, str.tostring(a-1, "00"), text_color = (a==51) ? color.black : color.white, bgcolor = (a==51) ? color.white : color.black, text_size = size_x)

if barstate.islastconfirmedhistory
    max_o = array.max(o_cents)
    max_h = array.max(h_cents)
    max_l = array.max(l_cents)
    max_c = array.max(c_cents)

    min_o = array.min(o_cents)
    min_h = array.min(h_cents)
    min_l = array.min(l_cents)
    min_c = array.min(c_cents)

    for a = 0 to 99
        o = array.get(o_cents, a)
        h = array.get(h_cents, a)
        l = array.get(l_cents, a)
        c = array.get(c_cents, a)

        if prt_val
            table.cell_set_text(tbl, a+1, 1, str.tostring(o,"#"))

        set_field(o, min_o, max_o, a, 1)
        
        //   
        if prt_val
            table.cell_set_text(tbl, a+1, 2, str.tostring(h,"#"))

        set_field(h, min_h, max_h, a, 2)

        if prt_val
            table.cell_set_text(tbl, a+1, 3, str.tostring(l,"#"))

        set_field(l, min_l, max_l, a, 3)

        if prt_val
            table.cell_set_text(tbl, a+1, 4, str.tostring(c,"#"))
        
        set_field(c, min_c, max_c, a, 4)

curr_dec_idx = frac(close) + 1

if barstate.islast
    if curr_dec_idx[1] == 51
        table.cell_set_bgcolor(tbl, curr_dec_idx[1], 0, color.white)    
        table.cell_set_text_color(tbl, curr_dec_idx[1], 0, color.black)
    else
        table.cell_set_bgcolor(tbl, curr_dec_idx[1], 0, color.black)
        table.cell_set_text_color(tbl, curr_dec_idx[1], 0, color.white)
    
    table.cell_set_bgcolor(tbl, curr_dec_idx, 0, color.red)
    table.cell_set_text_color(tbl, curr_dec_idx, 0, color.white)
