[PlayBit]Correlation-Co _OI
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © FFriZz inspired by © mortdiggiddy

//@version=5
indicator('[PlayBit]Correlation-Co _OI', shorttitle='[PlayBit]Cor-Co _OI',format = format.price)

//sym1 = input.symbol('Binance:BTCUSDT', 'sym₿ol 1')
autoSym = input.bool(true,'Auto Change to Chart Open Interest | On/Off?',group='Read Tooltip')
sym2 = input.symbol('BTCUSDTPERP', 'Crypto/Stock/Future(Read Tooltip)',group='Read Tooltip',inline='a',tooltip='If indicator moves up it means the 2 assets are correlating(moving together) and it goes down it means the 2 assets are diverging(moving differently). If comparing a Stock or Future to Crypto chart the Stock or Future and change indicator to the Crypto you want to compare. The reason is Crypto is open 24/7 and will have more bars than an asset with closed hours causing the indicator to produce gaps in the data, if comparing crypto to crypto disreguard this information.')
length = input.int(14, 'Ammount of bars data is correlated(Similar to length of a MA)', minval=1)
length2 = input.int(14, 'Length of MA', minval=1)


sym = syminfo.ticker//+'PERP_OI'
symm = str.replace(sym,'USDT.P','USDTPERP')
symmm = str.replace(symm,'_OI','')
sym33 = symmm + '_OI'
sym3 = 'Binance:'+ sym33

symTable = autoSym ? sym33 : sym2

src1 = input.source(close,'Source of Chart Asset')
src2ind = input.source(close,'Source of symbol of indicator Asset') 
//TF = input.timeframe('D','TimeFrame')
//src1 = request.security(sym1,timeframe.period, src1ind ,gaps=barmerge.gaps_off)
src3 = request.security(sym2,timeframe.period, src2ind ,gaps=barmerge.gaps_off)
src4 = request.security(sym3,timeframe.period, src2ind ,gaps=barmerge.gaps_off)


maof = input(true,'MA on/off')

float src2 = na

if autoSym
    src2 := src4
else
    src2 := src3


var a1 = array.new_float(0)
var a2 = array.new_float(0)
var a1_sorted = array.new_float(0)
var a2_sorted = array.new_float(0)

var a1_ranked = array.new_float(length, 0)
var a2_ranked = array.new_float(length, 0)
var diff = array.new_float(length, 0)

// initially the array sizes are zero at the very first bar 
// index, they grow to 'length' as the chart data is traversed

if array.size(a1) <= length
    array.unshift(a1, src1)
    array.unshift(a2, src2)
    
// pop off last value if a.size > 'length'

if array.size(a1) > length
    array.pop(a1)
    
if array.size(a2) > length 
    array.pop(a2)
    
// update arrays with the current values at the array head

array.set(a1, 0, src1)
array.set(a2, 0, src2)

rank(a, sorted, ranked) =>
    dupe = array.new_float(0)
    size = array.size(a)
    
    // re-populate and re-sort

    array.clear(sorted)
    array.concat(sorted, a)
    array.sort(sorted, order.ascending) 
    
    for i = 0 to (size - 1)
        v = array.get(sorted, i)
        
        if not array.includes(dupe, v)
            // locate the original index of the sorted value at index 'i'
            
            index = array.indexof(a, v)
            lastIndex = array.lastindexof(a, v)
            
            if index >= 0
                // we have to check for duplicate entries
                //
                // ex)        a = [1   5   3  7   5   9  8]
                //     a_ranked = [1  3.5  2  5  3.5  6  7]
                
                rank = if index != lastIndex
                    array.push(dupe, v)
                    
                    total = array.lastindexof(sorted, v) - i + 1
                    mod = i
                    
                    for j = 1 to (total - 1)
                        mod := mod + i + j
                    
                    rank = mod / total
                else
                    rank = i
                
                // assign the rank to all occurrences of the value
                
                for j = index to lastIndex
                    if array.get(a, j) == v
                        array.set(ranked, j, rank)
                    
    tie = array.size(dupe)
                
corr(tie) =>
    // https://i.imgur.com/W6yPFGk.png
    
    size = array.size(a1)
    d2_sum = 0.0
    
    corr = if tie == 0
        for i = 0 to (size - 1)
            v1 = array.get(a1_ranked, i)
            v2 = array.get(a2_ranked, i)
            
            d2_sum := d2_sum + (v1 - v2) * (v1 - v2)
            
        corr = 1 - (6 * d2_sum / (size * (size * size - 1)))
    else
        // Tied Ranks (Full calc): https://i.imgur.com/iVieah3.png
        
        r1_avg = array.avg(array.slice(a1_ranked, 0, size)) 
        r2_avg = array.avg(array.slice(a2_ranked, 0, size))
        
        covar = 0.0
        r1_sq_sum = 0.0
        r2_sq_sum = 0.0
        
        for i = 0 to (size - 1)
            v1 = array.get(a1_ranked, i) - r1_avg
            v2 = array.get(a2_ranked, i) - r2_avg
            
            covar := covar + v1 * v2
            
            r1_sq_sum := r1_sq_sum + v1 * v1 
            r2_sq_sum := r2_sq_sum + v2 * v2
            
        corr = covar / math.sqrt(r1_sq_sum * r2_sq_sum)
            
    corr

tie1 = rank(a1, a1_sorted, a1_ranked)
tie2 = rank(a2, a2_sorted, a2_ranked)

correlation = corr(tie1 + tie2)
//HOURSP= hours ? PL : ZL 
//HOURSN= hours ? NL : ZL


var table Tbl = table.new(position.top_right,columns = 1 ,rows = 1, bgcolor = color.new(chart.bg_color,100), 
 frame_color = color.new(chart.fg_color,0), frame_width =  1, border_color = color.new(chart.fg_color, 0), border_width = 1)
if barstate.islast
    table.cell(Tbl,0,0,symTable,text_color = chart.fg_color,text_size = size.small)


colorUp =  1
colorDn =  -1
cu=input.color(color.new(#00FF00FF,0),'Color Up Correlation')
cd=input.color(color.new(#FF0000FF,0),'Color Down Correlation')
ccu=input.color(color.new(#000000,0),'Color MA')

bgc=input.color(color.new(color.black,100),'Background Color')

colorg=color.from_gradient(correlation,colorDn,colorUp,cd,cu) 
c=correlation * src2
plot(correlation * src2, 'P₿ Correlation', color=colorg, style=plot.style_columns)
bgcolor(color=bgc, title= 'BG Color')

ComCp = maof ? ta.sma(correlation,length) * ta.sma(src2, length2) : na
plot(ComCp,'Asset Selected MA',color=ccu,style=plot.style_line,linewidth=2)