adaptive_mfi
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © palitoj_endthen

//@version=5
indicator(title = 'Adaptive Money Flow Index', shorttitle = 'adaptive_mfi', overlay = false)


// input
hp_period = input.int(defval = 48, title = 'High-Pass Period', group = 'Value', tooltip = 'Determines the High-Pass Period e.g. 48, 89, 125, etc')
src = input.source(defval = ohlc4, title = 'Source', group = 'Options', tooltip = 'Determines the source of input data use to compute dominant cycle, default to ohlc4')
color_type = input.string(defval = 'Solid', title = 'Color Scheme', group = 'Options', options = ['Solid', 'Normalized'], tooltip = 'Determines the color scheme of adaptive money flow index')


// check cumulative volume (tradingview)
vol = volume
cum_vol = 0.0
cum_vol += nz(vol)

if barstate.islast and cum_vol == 0
    runtime.error('No volume is provided by the data vendor')


// dominant cycle: determined an applied adaptive input length with dominant cycle - Ehlers
// variable
avg_length = 3
m = 0.00
n = 0.00
x = 0.00
y = 0.09
alpha1 = 0.00
hp = 0.00
a1 = 0.00
b1 = 0.00
c1 = 0.00
c2 = 0.00
c3 = 0.00
filt = 0.00
sx = 0.00
sy = 0.00
sxx = 0.00
syy = 0.00
sxy = 0.00
max_pwr = 0.00
dominant_cycle = 0.00

// array
var corr = array.new_float(50)
var cosine_part = array.new_float(50)
var sine_part = array.new_float(50)
var sq_sum = array.new_float(50)
var r1 = array.new_float(50)
var r2 = array.new_float(50)
var pwr = array.new_float(50)

// high-pass filter cyclic components whose periods are shorter than 48 bars
pi = 2*math.asin(1)
alpha1 := (math.cos(.707*360/hp_period)+math.sin(.707*360/hp_period)-1)/math.cos(.707*360/hp_period)
hp := (1-alpha1/2)*(1-alpha1/2)*(src-2*src[1]+src[2])+2*(1-alpha1)*nz(hp[1])-(1-alpha1)*(1-alpha1)*nz(hp[2])

// smoothed with super smoother filter
a1 := math.exp(-1.414*pi/10)
b1 := 2*a1*math.cos(1.414*180/10)
c2 := b1
c3 := -a1*a1
c1 := 1-c2-c3
filt := c1*(hp+hp[1])/2+c2*nz(filt[1])+c3*nz(filt[2])

// pearson correlation for each value of lag
for lag = 0 to 48
    // set the averaging length as m
    m := avg_length
    if avg_length == 0
        m := lag
    // initialize correlation sums
    sx := 0.00
    sy := 0.00
    sxx := 0.00
    syy := 0.00
    sxy := 0.00
    // advance samples of both data streams and sum pearson components
    for count = 0 to m-1
        x := filt[count]
        y := filt[lag+count]
        sx := sx+x
        sy := sy+y
        sxx := sxx+x*x
        sxy := sxy+x*y
        syy := syy+y*y
    // compute correlation for each value of lag
    if (m*sxx-sx*sx)*(m*syy-sy*sy) > 0
        array.set(corr, lag, ((m*sxy-sx*sy)/math.sqrt((m*sxx-sx*sx)*(m*syy-sy*sy))))

for period = 10 to 48
    array.set(cosine_part, period, 0)
    array.set(sine_part, period, 0)
    for n2 = 3 to 48
        array.set(cosine_part, period, nz(array.get(cosine_part, period))+nz(array.get(corr, n2))*math.cos(360*n2/period))
        array.set(sine_part, period, nz(array.get(sine_part, period))+nz(array.get(corr, n2))*math.sin(360*n2/period))
    array.set(sq_sum, period, nz(array.get(cosine_part, period))*nz(array.get(cosine_part, period))+nz(array.get(sine_part, period))*nz(array.get(sine_part, period)))

for period2 = 10 to 48
    array.set(r2, period2, nz(array.get(r1, period2)))
    array.set(r1, period2, .2*nz(array.get(sq_sum, period2))*nz(array.get(sq_sum, period2))+.8*nz(array.get(r2, period2)))

// find maximum power level for normalization
max_pwr := .991*max_pwr
for period3 = 10 to 48
    if nz(array.get(r1, period3)) > max_pwr
        max_pwr := nz(array.get(r1, period3))
for period4 = 3 to 48
    array.set(pwr, period4, nz(array.get(r1, period4))/max_pwr)

// compute the dominant cycle using the cg of the spectrum
spx = 0.00
sp = 0.00

for period5 = 10 to 48
    if nz(array.get(pwr, period5)) >= .5
        spx := spx+period5*nz(array.get(pwr, period5))
        sp := sp+nz(array.get(pwr, period5))

if sp != 0
    dominant_cycle := spx/sp
if dominant_cycle < 10
    dominant_cycle := 10
if dominant_cycle > 48
    dominant_cycle := 48


// money flow index
// variable
typical_price = hlc3
p_rmfi = 0.00
n_rmfi = 0.00
mfr = 0.00
mfi = 0.00
smfi = 0.00

// raw money flow index
raw_mfi = typical_price*vol

// adaptive money flow index
dc = int(dominant_cycle)

for i = 0 to dc-1
    // positive money flow
    if typical_price[i] > typical_price[i+1]
        p_rmfi += raw_mfi[i]
    // negative money flow
    if typical_price[i] < typical_price[i+1]
        n_rmfi += raw_mfi[i]
    // money flow ratio
    mfr := p_rmfi/n_rmfi
    // money flow index
    mfi := 100 - (100/(1+mfr))
    // smoothed with super-smoother
    smfi := c1*(mfi+mfi[1])/2+c2*nz(smfi[1])+c3*nz(smfi[2])


// visualize
// color scheme 2 - Normalized
high_smfi = ta.highest(smfi, dc)
low_smfi = ta.lowest(smfi, dc)
norm_smfi = (smfi-low_smfi)/(high_smfi-low_smfi)

col(x) =>
    if x > .5
        color.rgb(255*(2-2*x), 255, 0)
    else if x < .5
        color.rgb(255, 2*255*x, 0)

// color scheme
color_fin = color_type == 'Solid' ? color.maroon : col(norm_smfi)

// plot
hline_ = hline(50, color = color.new(color.blue, 50))
plot(smfi, color = color_fin, linewidth = 2)


// create alert
alert_ = norm_smfi > .5
alertcondition((not alert_[1] and alert_), title = 'Entry', message = 'Buy/Long entry detected')
alertcondition((alert_ and not alert_[1]), title = 'Close', message = 'Sell/Short entry detected')


// // strategy test
// percent_sl = input.float(defval = 3, title = 'Stop Loss', group = 'Value', tooltip = 'Determines the stop-loss percentage')
// long_condition = ta.crossover(smfi, 50)
// short_condition = ta.crossunder(smfi, 50)

// long_sl = 0.00
// long_sl := long_condition ? src*(1-percent_sl/100) : nz(long_sl[1])

// if long_condition
//     strategy.entry(id = 'long', direction = strategy.long)
// if not long_condition
//     strategy.exit(id = 'exit-long', from_entry = 'long', stop = long_sl)
