Weight Gain 4000 - (Adjustable Volume Weighted MA) - [mutantdog]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mutantdog

//@version=5
indicator ('Weight Gain 4000 v2',   'Weight Gain 4k',   true,   explicit_plot_zorder=true)

// v2.1

// |   |

string  S01     =   'open'
string  S02     =   'high'
string  S03     =   'low'
string  S04     =   'close'
string  S11     =   'hl2'
string  S12     =   'hlc3'
string  S13     =   'ohlc4'
string  S14     =   'hlcc4'

string  S51     =   'oc2'
string  S52     =   'hlc2-o2'
string  S53     =   'hl-oc2'
string  S54     =   'cc-ohlc4'


string  M01     =   'SMA'
string  M02     =   'EMA'
string  M03     =   'WMA'
string  M04     =   'RMA'

string  M61     =   'hSMA'
string  M62     =   'DEMA'
string  M63     =   'TEMA'
string  M64     =   'VIDYA'
string  M65     =   'HMA'
string  M66     =   'sEMA'
string  M67     =   'DRMA'


// ---------
// INPUTS
// ---------


auxSource       =   input.source    (close,     'Aux In')
trackerSource   =   input.string    ('hlc2-o2', 'Price Tracker',    [S01, S02, S03, S04, S11, S12, S13, S14, S51, S52, S53, S54, '* AUX', '* DISABLE'])


maActive_1      =   input.bool      (true,      'Active',                                                                                               inline='10',    group='MA 1: Fast')
volFilter_1     =   input.bool      (true,      'Volume Filter',                                                                                        inline='10',    group='MA 1: Fast')

maSource_1      =   input.string    ('hlcc4',   'Source',           [S01, S02, S03, S04, S11, S12, S13, S14, S51, S52, S53, S54,  '* AUX'],             inline='11',    group='MA 1: Fast')
volPower_1      =   input.float     (0.5,       'Volume',                   minval=0,       maxval=1,       step=0.05,                                  inline='11',    group='MA 1: Fast')
maMode_1        =   input.string    ('EMA',     'Mode  ',           [M01, M02, M03, M04, M61, M62, M63, M64, M65, M66, M67],                            inline='12',    group='MA 1: Fast')
maLength_1      =   input.int       (8,         'Length',                   minval=1,                                                                   inline='12',    group='MA 1: Fast')


maActive_2      =   input.bool      (true,      'Active',                                                                                               inline='20',    group='MA 2: Slow')
volFilter_2     =   input.bool      (true,      'Volume Filter',                                                                                        inline='20',    group='MA 2: Slow')
bandActive_2    =   input.bool      (false,     'Dev Bands',                                                                                            inline='20',    group='MA 2: Slow')

maSource_2      =   input.string    ('hlcc4',   'Source',           [S01, S02, S03, S04, S11, S12, S13, S14, S51, S52, S53, S54, '* AUX', '* MA 1'],    inline='21',    group='MA 2: Slow')
volPower_2      =   input.float     (0.5,       'Volume',                   minval=0,       maxval=1,       step=0.05,                                  inline='21',    group='MA 2: Slow')
maMode_2        =   input.string    ('EMA',     'Mode  ',           [M01, M02, M03, M04, M61, M62, M63, M64, M65, M66, M67],                            inline='22',    group='MA 2: Slow')
maLength_2      =   input.int       (21,        'Length',                   minval=1,                                                                   inline='22',    group='MA 2: Slow')
bandMult_2      =   input.float     (2,         'Bands ',                   minval=0,                       step=0.1,                                   inline='23',    group='MA 2: Slow')


bullHue         =   input.color     (#22B747,   '',                                                                                                     inline='55',    group='Visual')
bearHue         =   input.color     (#B7143C,   '',                                                                                                     inline='55',    group='Visual')
bandHue         =   input.color     (#336680,   '',                                                                                                     inline='55',    group='Visual')
neutralHue      =   input.color     (#808080,   '',                                                                                                     inline='55',    group='Visual')

mainOpacP       =   input.int       (100,       'Main   ',                  minval=0,       maxval=100,     step=5,                                     inline='61',    group='Visual')
mainOpacF       =   input.int       (40,        'Fill',                     minval=0,       maxval=100,     step=5,                                     inline='61',    group='Visual')
bandOpacP       =   input.int       (80,        'Bands  ',                  minval=0,       maxval=100,     step=5,                                     inline='62',    group='Visual')
bandOpacF       =   input.int       (10,        'Fill',                     minval=0,       maxval=100,     step=5,                                     inline='62',    group='Visual')
trackOpacP      =   input.int       (50,        'Tracker',                  minval=0,       maxval=100,     step=5,                                     inline='63',    group='Visual')


showMax_12      =   input.bool      (false,     'MA1 x MA2        ',                                                                                    inline='81',    group='Visual')
showMax_t2      =   input.bool      (false,     'Price x MA2',                                                                                          inline='81',    group='Visual')
showBx_in       =   input.bool      (false,     'Price x Inside Bands',                                                                                 inline='82',    group='Visual')
showBx_out      =   input.bool      (false,     'Price x Outside Bands',                                                                                inline='82',    group='Visual')




// ---------
// FUNCTIONS
// ---------


source_switch (src, aux) => 
    source = switch src
        'open'      =>  open
        'high'      =>  high
        'low'       =>  low
        'close'     =>  close
        'hl2'       =>  hl2
        'hlc3'      =>  hlc3
        'ohlc4'     =>  ohlc4
        'hlcc4'     =>  hlcc4
        'oc2'       =>  (open + close) / 2
        'hlc2-o2'   =>  (high + low + close - open) / 2
        'hl-oc2'    =>  (high + low) - (open + close) / 2
        'cc-ohlc4'  =>  2 * close - ohlc4

        '* AUX'     =>  aux
//

// --- MAs

weightgain_sma  (src, len, vol)     =>      ta.sma (src * vol, len)     /   ta.sma (vol, len)
weightgain_hsma (src, len, vol)     =>      ta.sma (vol, len)           /   ta.sma (vol / src, len)
weightgain_wma  (src, len, vol)     =>      ta.wma (src * vol, len)     /   ta.wma (vol, len)
weightgain_sema (src, len, vol)     =>      ta.ema (src * vol, len)     /   ta.ema (vol, len)

weightgain_elastic (src, alpha, mode) =>
    var float   e0  =   na       
    var float   e1  =   na       
    var float   e2  =   na       

    e0      :=  alpha * src     +   (1 - alpha) * nz(e0[1], src[1])
    e1      :=  alpha * e0      +   (1 - alpha) * nz(e1[1], e0[1])
    e2      :=  alpha * e1      +   (1 - alpha) * nz(e2[1], e1[1])
    
    ed      =   2 * e0  -   e1
    et      =   (3 * e0 - 3 * e1)   +   e2

    output      =   switch mode
        1       =>  e0
        2       =>  ed
        3       =>  et
//
weightgain_hma (src, len, vol) =>
    halfLen     =   math.max (int (len / 2), 2)
    rootLen     =   int (math.sqrt (len))

    wmaBasic    =   ta.wma (src * vol, len)             /   ta.wma (vol, len)
    wmaHalf     =   ta.wma (src * vol, halfLen)         /   ta.wma (vol, halfLen)
    hmaComp     =   2 * wmaHalf - wmaBasic
    hmaFinal    =   ta.wma (hmaComp * vol, rootLen)     /   ta.wma (vol, rootLen)
//
weightgain_vidya_vx (src, len, vol) =>
    variSum         =   0.0
    volSum          =   0.0

    smaBasic        =   ta.sma (src * vol, len)     /   ta.sma (vol, len)

    for i = 0 to len - 1
        variSum     :=  variSum     +   vol[i] * math.pow (smaBasic - src[i], 2)
        volSum      :=  volSum      +   vol[i]

    devSigma        =   math.sqrt (variSum / volSum)
    smaSigma        =   ta.sma (devSigma * vol, len)    /   ta.sma (vol, len)
    vxSigma         =   devSigma    /   smaSigma
//

// --- Deviations

weightgain_sigma_standard (src, len, vol, lwt, ref) =>
    variSum         =   0.0
    weightSum       =   0.0

    for i = 0 to len - 1
        volWeight   =   vol[i]
        linWeight   =   lwt     ?   len - i     :   0
        sumWeight   =   nz (linWeight + volWeight, 1)

        variSum     :=  variSum         +   sumWeight * math.pow (ref - src[i], 2)
        weightSum   :=  weightSum       +   sumWeight

    sigmaDev        =   math.sqrt (variSum / weightSum)
//
weightgain_sigma_elastic (src, alpha, ref) =>
    var float   vari    =   na 

    vari        :=  (1 - alpha) * ((alpha * math.pow (src - ref[1], 2))     +   nz(vari[1]))
    dev         =   math.sqrt (vari)
//
weightgain_sigma_sema (src, len, vol) =>
    emaSrcsq    =   ta.ema (src * src * vol, len)       /   ta.ema (vol, len)
    emasqSrc    =   math.pow (ta.ema (src * vol, len)   /   ta.ema (vol, len), 2)
    semaDev     =   math.sqrt (emaSrcsq - emasqSrc)
//

// Main Process

weightgain_main_process (src, len, mult, filt, mode) =>
    fixVolume   =   volume > 1  ?   math.pow (volume, mult)     :   1                                       
    wmaOmega    =   filt        ?   ta.wma (fixVolume, 4)       :   fixVolume
    rmaOmega    =   filt        ?   ta.rma (fixVolume, 2)       :   fixVolume

    emaAlpha    =   2 * rmaOmega    /   (math.sum (rmaOmega, len) + rmaOmega)
    rmaAlpha    =   rmaOmega        /   math.sum (rmaOmega, len)
    vidyaAlpha  =   mode == 'VIDYA'     ?   weightgain_vidya_vx (src, len, rmaOmega) * rmaAlpha     :   na


    vwmaSwitch  =   switch  mode
        'SMA'       =>  weightgain_sma              (src,   len,    wmaOmega)   
        'EMA'       =>  weightgain_elastic          (src,                       emaAlpha,   1)   
        'WMA'       =>  weightgain_wma              (src,   len,    wmaOmega)   
        'RMA'       =>  weightgain_elastic          (src,                       rmaAlpha,   1)   
        'hSMA'      =>  weightgain_hsma             (src,   len,    wmaOmega)
        'DEMA'      =>  weightgain_elastic          (src,                       emaAlpha,   2)
        'TEMA'      =>  weightgain_elastic          (src,                       emaAlpha,   3)
        'VIDYA'     =>  weightgain_elastic          (src,                       vidyaAlpha, 1)
        'HMA'       =>  weightgain_hma              (src,   len,    wmaOmega) 
        'sEMA'      =>  weightgain_sema             (src,   len,    wmaOmega)
        'DRMA'      =>  weightgain_elastic          (src,                       rmaAlpha,   2)

    sigmaSwitch =   switch  mode
        'SMA'       =>  weightgain_sigma_standard   (src,   len,    wmaOmega,               false,  vwmaSwitch)   
        'EMA'       =>  weightgain_sigma_elastic    (src,                       emaAlpha,           vwmaSwitch)   
        'WMA'       =>  weightgain_sigma_standard   (src,   len,    wmaOmega,               true,   vwmaSwitch)   
        'RMA'       =>  weightgain_sigma_elastic    (src,                       rmaAlpha,           vwmaSwitch)   
        'hSMA'      =>  weightgain_sigma_standard   (src,   len,    wmaOmega,               false,  vwmaSwitch)
        'DEMA'      =>  weightgain_sigma_elastic    (src,                       emaAlpha,           vwmaSwitch)
        'TEMA'      =>  weightgain_sigma_elastic    (src,                       emaAlpha,           vwmaSwitch)
        'VIDYA'     =>  weightgain_sigma_elastic    (src,                       vidyaAlpha,         vwmaSwitch)
        'HMA'       =>  weightgain_sigma_standard   (src,   len,    wmaOmega,               true,   vwmaSwitch) 
        'sEMA'      =>  weightgain_sigma_sema       (src,   len,    rmaOmega)
        'DRMA'      =>  weightgain_sigma_elastic    (src,                       rmaAlpha,           vwmaSwitch)

    [vwmaSwitch, sigmaSwitch]
//


// -------
// PROCESS
// -------

tracker                         =   source_switch (trackerSource, auxSource)

source_1                        =   maActive_1      ?   source_switch (maSource_1, auxSource)               :  na
[maProcess_1, sigmaProcess_1]   =   weightgain_main_process (source_1, maLength_1, volPower_1, volFilter_1, maMode_1)

source_2                        =   maActive_2      ?   maSource_2 == '* MA 1'      ?   maProcess_1         :   source_switch (maSource_2, auxSource)       :   na 
[maProcess_2, sigmaProcess_2]   =   weightgain_main_process (source_2, maLength_2, volPower_2, volFilter_2, maMode_2)

hiBand_2                        =   bandActive_2    ?   maProcess_2     +   bandMult_2 * sigmaProcess_2     :   na
loBand_2                        =   bandActive_2    ?   maProcess_2     -   bandMult_2 * sigmaProcess_2     :   na



// ----------------
// VISUALS & ALERTS
// ----------------

// - Colours

weightgain_gradient (ma1, ma2, dev, bear, bull, mid, mult) =>
    bearstrong  =   color.new (bear,    100 - mult)
    bearweak    =   color.new (bear,    100 - mult / 10)
    bullstrong  =   color.new (bull,    100 - mult)
    bullweak    =   color.new (bull,    100 - mult / 10)

    base        =   color.new (mid,     100 - mult / 10)

    beargrad    =   dev !=  0   ?   color.from_gradient (ma1, ma2 - dev, ma2, bearstrong, bearweak)     :   bearstrong
    bullgrad    =   dev !=  0   ?   color.from_gradient (ma1, ma2, ma2 + dev, bullweak, bullstrong)     :   bullstrong

    color   colourgrad          =   ma1 < ma2   ?   beargrad        :   ma1 > ma2   ?   bullgrad        :   base
//

bullColour      =   color.new (bullHue,     100 - mainOpacP)
bearColour      =   color.new (bearHue,     100 - mainOpacP)
neutColour      =   color.new (neutralHue,  100 - mainOpacP / 2)
bandColour      =   color.new (bandHue,     100 - bandOpacP)
bandFill        =   color.new (bandHue,     100 - bandOpacF)
trackColour     =   color.new (neutralHue,  100 - trackOpacP)

maColour        =   maProcess_1 > maProcess_2   ?   bullColour      :   maProcess_1 < maProcess_2   ? bearColour    :   neutColour

fillGrad        =   (sigmaProcess_1 + sigmaProcess_2)
fillColour      =   weightgain_gradient (maProcess_1, maProcess_2, fillGrad, bearHue, bullHue, neutralHue, mainOpacF)



// - Plots

hibandPlot      =   plot (hiBand_2,     'Hi Band',          bandColour,     1)
lobandPlot      =   plot (loBand_2,     'Lo Band',          bandColour,     1)

fill (hibandPlot,   lobandPlot,     bandFill,       'Band Area Fill')

trackerPlot     =   plot (tracker,      'Price Tracker',    trackColour,    1,      plot.style_stepline)

maPlot_1        =   plot (maProcess_1,  'MA 1 Plot',        maColour,       2)
maPlot_2        =   plot (maProcess_2,  'MA 2 Plot',        maColour,       2)

fill (maPlot_1,     maPlot_2,       fillColour,     'MA Area Fill')


// - Alerts

maxo_12         =   ta.crossover    (maProcess_1, maProcess_2)
maxu_12         =   ta.crossunder   (maProcess_1, maProcess_2)

maxo_t2         =   ta.crossover    (tracker, maProcess_2)
maxu_t2         =   ta.crossunder   (tracker, maProcess_2)

tbxo_lo         =   bandActive_2    ?   ta.crossover    (tracker, loBand_2)     :   na
tbxu_lo         =   bandActive_2    ?   ta.crossunder   (tracker, loBand_2)     :   na
tbxo_hi         =   bandActive_2    ?   ta.crossover    (tracker, hiBand_2)     :   na
tbxu_hi         =   bandActive_2    ?   ta.crossunder   (tracker, hiBand_2)     :   na





plotatr         =   ta.atr (4)

plotshape (maxo_12 and showMax_12   ?   maProcess_2 - plotatr   : na,   'MA Cross: Bull',       shape.triangleup,       location.absolute,      maColour,       size=size.tiny,     display=display.pane)
plotshape (maxu_12 and showMax_12   ?   maProcess_2 + plotatr   : na,   'MA Cross: Bear',       shape.triangledown,     location.absolute,      maColour,       size=size.tiny,     display=display.pane)

plotshape (tbxo_lo and showBx_in    ?   loBand_2                : na,   'Inside Lo Band',       shape.triangleup,       location.belowbar,      bandColour,     size=size.tiny,     display=display.pane)
plotshape (tbxu_hi and showBx_in    ?   hiBand_2                : na,   'Inside Hi Band',       shape.triangledown,     location.abovebar,      bandColour,     size=size.tiny,     display=display.pane)
plotshape (tbxu_lo and showBx_out   ?   loBand_2                : na,   'Outside Lo Band',      shape.triangledown,     location.belowbar,      bandColour,     size=size.tiny,     display=display.pane)
plotshape (tbxo_hi and showBx_out   ?   hiBand_2                : na,   'Outside Hi Band',      shape.triangleup,       location.abovebar,      bandColour,     size=size.tiny,     display=display.pane)

plotshape (maxo_t2 and showMax_t2   ?   maProcess_2 - plotatr   : na,   'Price x-over MA2',     shape.triangleup,       location.absolute,      trackColour,    size=size.tiny,     display=display.pane)
plotshape (maxu_t2 and showMax_t2   ?   maProcess_2 + plotatr   : na,   'Price x-under MA2',    shape.triangledown,     location.absolute,      trackColour,    size=size.tiny,     display=display.pane)

alertcondition  (maxo_12,               '00: MA1 Above MA2',            'BUY ALERT:     MA1 Crossed Above MA2')
alertcondition  (maxu_12,               '00: MA1 Below MA2',            'SELL ALERT:    MA1 Crossed Below MA2')
alertcondition  (maxo_12 or maxu_12,    '00: MA1 Crossed MA2',          'MIXED ALERT:   MA1 Crossed Above or Below MA2')

alertcondition  (tbxo_lo,               '01: Price Inside LoBand',      'DIP ALERT:     Price Tracker Crossed Inside Lo Band')
alertcondition  (tbxu_lo,               '01: Price Outside LoBand',     'DIP ALERT:     Price Tracker Crossed Outside Lo Band')
alertcondition  (tbxu_hi,               '02: Price Inside HiBand',      'RIP ALERT:     Price Tracker Crossed Inside Hi Band')
alertcondition  (tbxo_hi,               '02: Price Outside HiBand',     'RIP ALERT:     Price Tracker Crossed Outside Hi Band')

alertcondition  (maxo_t2,               '03: Price Above MA2',          'BUY ALERT:     Price Tracker Crossed Above MA2')
alertcondition  (maxu_t2,               '03: Price Below MA2',          'SELL ALERT:    Price Tracker Crossed Below MA2')




