curve
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © kaigouthro
import wlhm/UnicodeReplacementFunction/1 as uni
//@version=5

// @description Regression array Creator and Visualizer
library("curve",true)

// @function Curve Regression Values Tool
// @param    _size  (float) Number of Steps rquired (float works, future consideration)
// @param    _power (float) Strength of value decrease
// @returns  (float[]) Array of multipliers from 1 downwards
export curve(float _size = 10, float _power = 0)=>
    _array  = array.new<float>()
    _step   = (_power == 0 ? 0.1 :math.max(1/math.abs(_size/_power),_power))
    _val    = 1.
    _out    = 1.
    while array.size(_array) <= _size 
        _val *= 1 + _step/100
        _out := 1 / _val
        array.push(_array, math.max(0, _out * _size * _step))
    _rng  = array.range (_array)  
    _min  = array.max   (_array) - _rng
    for [index,_value] in _array
        array.set(_array,index, math.max(0,  (_value - _min) / _rng))
    _array

    
// @function Visible bottom Helper
// @returns  lowest since time viewable
getsize()=>
    varip _dn = float(na)
    varip _up = float(na)
    _dn := time > chart.left_visible_bar_time ? math.min(nz(_dn,close),close) : na
    _up := time > chart.left_visible_bar_time ? math.max(nz(_up,close),close) : na
    [_dn,_up] 
    
// @function Helper 
// @param    _in Value of array to get time dist for
// @param    index array index value
// @returns  time of bar for instance
timeMult(_in, index)=> tdis = timeframe.in_seconds(timeframe.period)*1000 , int(time[0] - tdis * _in )

    
// @function display show curve 
// @param       _array         Values to draw
// @param       _timedist      Show   Seconds
// @param       _expandLength  Grow   over time ( 1/value)
// @param       _onbar         Show on bar (overlay)
// @param       _src           Value for overlay
// @returns  void
export display(float[] _array, bool _timedist = true, bool _expandLength = false, bool _onbar = true, float  _src = high) =>
    [_flr,_roof] = getsize()
    _hgt = (_roof-_flr)
    if barstate.islast
        _size                      = array.size          (_array    )
        _colors                    = ca.makeGradient     (_size + 1 )
        var label   [] _labels     = array.new<label>    (_size+1 ) 
        var linefill[] _linefills  = array.new<linefill> (_size) 
        var line    [] _lines      = array.new<line>     (_size) 
        var line    [] _fill_lines = array.new<line>     (_size) 
        var string  _isbar    = _timedist ? 'sec' : 'bars'
        _yvals = array.new<float>    ( )
        for i = 0 to math.min(bar_index,500)
            array.push(_yvals,_src[i])
        _alllines     = line.all
        for itm in _alllines    
            line.delete(itm)
        _alllabels    = label.all
        for itm in _alllabels   
            label.delete(itm)
        _alllinefills = linefill.all
        for itm in _alllinefills
            linefill.delete(itm)
        for [index , _value] in _array
            _baris     =  math.min(500,_expandLength ? int((index-1) + 1/(math.max(1/100,_value)))  :  index)
            lval       =  _onbar ? array.get(_yvals,_baris) : _hgt*_value + _flr
            _timeis    =  switch
                _timedist => _expandLength ? timeMult((index-1) + 1/_value  , index) : timeMult(index , index)
                => bar_index[_baris]
            _ltimeis   =  _timedist ? (last_bar_time[0] - _timeis)/1000 :  last_bar_index - _timeis
            _locis     =  _timedist?xloc.bar_time: xloc.bar_index  
            _lastis    =  _timedist?last_bar_time+(time[0]-time[1]) : last_bar_index +1  
            _color     =  color.new(array.get(_colors , _size -index) , 100 - (_value * (_onbar?20:70) ))
            _lbl       =  label.new(_timeis , lval , uni.replaceFont(str.format('﹟{0}   \n {1,number,#} ⇠ '+_isbar+'\n {2,number,percent}' , 
             index, _ltimeis, _value),'Regional Indicator'), _locis , yloc.price , color.new(_color,93) ,
             label.style_label_down, color.new(_color , 10) , size.small)
            array.unshift      (          _fill_lines  , line.new    (_timeis , _onbar ? lval  : _flr , _lastis , _onbar ? lval : _hgt*_value + _flr, _locis , extend.none , color.new(#000000 , 100)))
            array.unshift      (          _lines       , line.new    (_timeis ,          lval             , _lastis ,          lval          , _locis , extend.none ,             _color))
            array.unshift      (          _linefills   , linefill.new(array.get(_fill_lines, 0) , array.get(_lines,1) , color.new(_color , int(100 - _value * (_onbar ? 5:25)))))
            array.unshift      (          _labels      , _lbl)
            // linefill.delete    (array.pop(_linefills   ))
            // label.delete       (array.pop(_labels      ))
            // line.delete        (array.pop(_fill_lines  ))
            // line.delete        (array.pop(_lines       ))
            

// Demo
import kaigouthro/ColorArray/1 as ca

_array   = array.new<float>(0)
_power   = input.float(1,'power of curve',0,100,0.1)
_size    = input.float(10,'size of curve ',2,50,1)
_array  := curve(_size , _power)

display ( _array , 
     input.bool(true, 'Time based?',group='Options', inline = '_'),  
     input.bool(true, 'Grow      ?',group='Options', inline = '_'), 
     input.bool(true, 'Overlay   ?',group='Options', inline = '_'))


// Bonus Feature


cma(int _len, float _pwr = 2, int _dep = 3)=>
    varip init        =   true     
    varip ctx         =   matrix.new<float>   ( _dep , _len + _dep + 2 )
    if init           
        vals          =   array.new<float>    ((_len+2)*(2+_len) ,0)
        value         =   float(na)
        for i         =   0 to _dep -1 by 1
            vals      :=  curve(_len + i, (i+1)*_pwr)
            for k     =   0 to _len -1 by 1
                value :=  array.get(vals,i+k)*(1-i/_dep)
                matrix.set(ctx,i, k,value)
        init:= false
    ctx


_demoMTXma(float src, int _len, int _dep = 3, float _pwr = 2)=>
    switch 
        _pwr <= 0 => runtime.error('Power  must be above 0')
        _len <= 1 => runtime.error('Length must be above 0')
        _dep <= 1 => runtime.error('Depth  must be above 0')
    var mtx    = matrix.new<float>   ( _dep , _len + _dep + 2 )
    var mtx2   = matrix.new<float>   ( _dep , _len + _dep + 2 )
    var ctx    = cma      (_len , _pwr , _dep)
    rg = ta.sma(math.abs(ta.mom(src, _dep))*ta.range(src,_dep),_dep)
    ra = rg/ta.sma(rg,_len)
    for i = 0 to _dep -1
        for k = 0 to _len - 1
            w = k+i
            a = ra[i] * (math.sum(ta.atr(2),i+1)/src)/(1+k+i) * matrix.get(ctx , i, k) * 1/(1+w)
            r = src[w]* a
            matrix.set(mtx , i ,  k , r)
            matrix.set(mtx2, i ,  k , a)
    matrix.avg(mtx)/matrix.avg(mtx2)


_dep             = input.int   (5 ,'Depth ' , 2,100     ,group = 'MA Demo') 
_len             = input.int   (5 ,'Length' , 2,100     ,group = 'MA Demo') 
_pwr             = input.float (1 ,'Power ' , step=0.1  ,group = 'MA Demo') 
_showma          =input(false)
_val             = _showma ? _demoMTXma(close, _len, _dep, _pwr) : float(na)
plot(_showma?_val:na,'out', ta.change(_val)>0 ? color.aqua:color.orange)
bgcolor(#101010)

    