AMACD - All Moving Average Convergence Divergence
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © EltAlt

//@version=5

//  -----------------------------------------------------------------------------
//
//  Authors:  @EltAlt
//  Revision: v3.04
//  Date:     18-May-2022
//
//  Description
//  =============================================================================
//  This indicator displays the Moving Average Convergane and Divergence (MACD) of individually configured Fast, Slow and Signal Moving 
//  Averages. Open Long / Close Long / Open Short / Close Short alerts can be set based on moving average crossovers, consecutive 
//  convergence/divergence of the moving averages, directional changes in the histogram moving averages, moving average crossing zero, or
//  divergences between the price and the MACD. Alerts can also be filtered based on the MACD being above or below zero.
//
//  The Fast, Slow and Signal Moving Averages can be set to:
//  Simple Moving Average (SMA)
//  Exponential Moving Average (EMA)
//  Weighted Moving Average (WMA)
//  Volume-Weighted Moving Average (VWMA)
//  Hull Moving Average (HMA) 
//  Exponentially Weighted Moving Average (RMA) (SMMA)
//  Linear regression curve Moving Average (LSMA)
//  Double EMA (DEMA)
//  Double SMA (DSMA)
//  Double WMA (DWMA)
//  Double RMA (DRMA)
//  Triple EMA (TEMA)
//  Triple SMA (TSMA)
//  Triple WMA (TWMA)
//  Triple RMA (TRMA)
//  Symmetrically Weighted Moving Average (SWMA) ** length does not apply **
//  Arnaud Legoux Moving Average (ALMA)
//  Variable Index Dynamic Average (VIDYA)
//  Fractal Adaptive Moving Average (FRAMA)
//
//  If you have a strategy that can buy based on External Indicators you can use the 'Backtest Signal' which plots the values set in
//  the 'Long / Short Signals' section.
//  'Backtest Signal' is plotted to display.none, so change the Style Settings for the chart if you need to see it for testing.
//
//  =============================================================================
//
//  I would gladly accept any suggestions to improve the script.
//  If you encounter any problems please share them with me.
//
//  Thanks to Smartcryptotrade for "MACD Alert [All MA in one] [Smart Crypto Trade (SCT)]" which gave me the initial starting point.
//  Thanks to Jason5480 for your help, discussions and "jason5480/hack_utils/2".
//
//  Changlog
//  =============================================================================
//
//  2.01 • Added separate sources for the fast and slow moving averages.
//       • Added SWMA, because it's "All" moving averages. Interesting that SWMA doesn't take a length, so length will not apply.
//       • Consolidated MA functions for doubles and triples in to the calcMA function.
//       • Neatened up the inputs.
//  2.02 • Renamed to "AMACD - All Moving Average Convergence Divergence".
//       • Added ta.rising and ta.falling, which simplified things a lot, why didn't you tell me about these functions! :)
//       • Added a price plot with display=display.none for testing, color is green when above moving averages, red below and blue when
//         interacting.
//       • First Public release.
//  2.03 • Added a case for no signal smoothing, when signal length = 1.
//       • Re-wrote calcMA as a switch, much more pleasing on the eye.
//       • Removed all the security fluff which I'd never even read, "terms of the Mozilla Public License 2.0" is more comprehensive anyway.
//       • Added check boxes to quickly disable some of the default plots.
//  3.00 • Added options to generate open and close for both long and short positions. So if you are in a long position and your criteria
//         for a negative signal is met it will close your long, if another negative signal is generated it will open a short. If you're 
//         just trading the crossover this will keep you permanently trading short or long, as it's only when there are two or more 
//         consecutive signals are generated that will move you from longs to shorts. 
//       • Plots a Green Triangle for Open Long, a Green Square for Close Long, a Red Triangle for Open Short and a Red Square for 
//         Close Short.
//       • To do this I needed to track the sate of open deals. Could have done this with variables but thought plotting it may help, 
//         so "Deal State" plots a 1 if it's in a long, 0 if no deals are open and -1 if it's in a short, to display.none. Enable it 
//         in Style Settings if you need it for testing.  
//       • If you'd prefer that it just worked as it did before with simple Buy / Sell signals, which makes sense if you're just trading 
//         the crossover, disable the 'Generate Close Signals for Long / Short Positions' setting.
//       • Now that it can generate Open Long, Close Long, Open Short and Close Short signals I added a 'Long / Short Signals' section in 
//         settings, where you can specify what signals your backtester is expecting for each state.
//       • Moving averages are now plotted to display.none as well in case you want to see the price and the moving averages for testing.
//         You're much better off running my other script 'Any Ribbon' on the top pane to show the moving averages ribbon, but these 
//         options enable you to show them here if you want to.
//       • Added the option to buy / sell based on the moving average crossing zero, thanks Bu Bader!
//  3.01 • Added filters for MACD above and below zero.
//       • Added the option to buy / sell based on divergences between the price and the MACD. Thanks to Trading View for the 'Divergence
//         Indicator' and @DaviddTech for his idea to use that as the basis for a MACD Divergence script. 
//       • REMEMBER you can't trigger a divergence before a local top or bottom is CONFIRMED by closing some bars after that local top 
//         or bottom. Replay some bars to see how far after the divergence the signal will actually fire.
//       • Added a bunch of tool tips, I bet there are spelling mistakes in some, tell me if so.
//  3.02 • When 'Generate Close Signals for Long / Short Positions' was disabled close long was plotting as open short (-1). Fixed the
//         logic. Thanks for the testing Bu Bader!
//  3.03 • More signal weirdness, re-wrote the logic completely.
//  3.04 • I've had requests to filter based on a few different indicators, I think that the script is getting too complicated as it is 
//         and I don't want to add a bunch of filters that only one person may use. So I added the option to filter based on the output
//         of an external indicator. You can enable or disable trading based any indicator hitting the level that you set. I've tested a
//         few indicators but you need to to confirm that your indicator is filtering as you expect it to. Enable the plot of 'Trades 
//         Enabled' in Style Settings to see if trades are enabled (1) or disabled (0). I expect that this was requested to only open 
//         longs in an uptrend etc. so it may not be helpful if you want to open longs and shorts.
//         Thanks Jason5480 for hack_utils that made this easier.
//       • The external filter will stop new trades starting but it won't stop any existing trades closing.
//       • The MACD > 0 filter may not have stopped existing deals closing, changed that so that they can close.
//       • Added check to do nothing when buy and sell fire in the same bar.
//       • Corrected signal for consecutive short orders.
//
//
// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
//
//
// ============ "AMACD - All Moving Average Convergence Divergence"

indicator(title='AMACD - All Moving Average Convergence Divergence',
          shorttitle='AMACD',
          overlay = false, 
          timeframe='', 
          timeframe_gaps=true)

import jason5480/hack_utils/2 as hu

// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Inputs

MATip = 'Simple Moving Average (SMA)\nExponential Moving Average (EMA)\nWeighted Moving Average (WMA)\nVolume-Weighted Moving Average (VWMA)\nHull Moving Average (HMA)\nExponentially Weighted Moving Average (RMA) (SMMA)\nLinear regression curve Moving Average (LSMA)\nDouble EMA (DEMA)\nDouble SMA (DSMA)\nDouble WMA (DWMA)\nDouble RMA (DRMA)\nTriple EMA (TEMA)\nTriple SMA (TSMA)\nTriple WMA (TWMA)\nTriple RMA (TRMA)\nSymmetrically Weighted Moving Average (SWMA)\n** length does not apply to SWMA **\nArnaud Legoux Moving Average (ALMA)\nVariable Index Dynamic Average (VIDYA)\nFractal Adaptive Moving Average (FRAMA)'
FastType   = input.string('EMA', title='Fast Moving Average Type', group='Moving Averages', options=['EMA', 'SMA', 'WMA', 'VWMA', 'HMA', 'RMA', 'LSMA', 'Double EMA', 'Double SMA', 'Double WMA', 'Double RMA', 'Triple EMA', 'Triple SMA', 'Triple WMA', 'Triple RMA', 'SWMA', 'ALMA', 'VIDYA', 'FRAMA'], tooltip = MATip)
FastSource = hu.str_to_src(input.string (defval = 'close', title='Fast Source', inline='Fast', group='Moving Averages', options = ['open', 'high', 'low', 'close', 'hl2', 'hlc3', 'ohlc4', 'hlcc4']))
FastLength = input.int (12, title='Fast Length', inline='Fast', group='Moving Averages', minval=2, maxval=1000)

SlowType   = input.string ('SMA', title='Slow Moving Average Type', group='Moving Averages', options=['EMA', 'SMA', 'WMA', 'VWMA', 'HMA', 'RMA', 'LSMA', 'Double EMA', 'Double SMA', 'Double WMA', 'Double RMA', 'Triple EMA', 'Triple SMA', 'Triple WMA', 'Triple RMA', 'SWMA', 'ALMA', 'VIDYA', 'FRAMA'], tooltip = MATip)
SlowSource = hu.str_to_src(input.string (defval = 'close', title='Slow Source', inline='Slow', group='Moving Averages', options = ['open', 'high', 'low', 'close', 'hl2', 'hlc3', 'ohlc4', 'hlcc4']))
SlowLength = input.int (26, title='Slow Length', inline='Slow', group='Moving Averages', minval=2, maxval=1000)

sigMATip = 'Setting the Signal Moving Average Length to 1 will disable smoothing and trade based on the Fast and Slow Moving Averages directly.' 
SignalType   = input.string('EMA', inline='Signal', group='Moving Averages', title='Signal Moving Average Type', options=['EMA', 'SMA', 'WMA', 'VWMA', 'HMA', 'RMA', 'LSMA', 'Double EMA', 'Double SMA', 'Double WMA', 'Double RMA', 'Triple EMA', 'Triple SMA', 'Triple WMA', 'Triple RMA', 'SWMA', 'ALMA', 'VIDYA', 'FRAMA'], tooltip = sigMATip)
SignalLength = input.int   (9,     inline='Signal', group='Moving Averages',title='Signal Length', minval=1, maxval=1000)

extTip = 'Take an input from another indicator to enable or disable new trades.\nWhile new longs or shorts will not be opened any existing trade will still be closed.\nThe filter will remain applied until the counter signal is received.'
MACDAboveZero  = input.bool   (true,  inline='1', group='Filters', title='Long Only When MACD is Above 0')
MACDBelowZero  = input.bool   (true,  inline='1', group='Filters', title='Short Only When MACD is Below 0')
externalFilter = input.bool   (false, inline='2', group='Filters', title= 'Enable External Filter', tooltip = extTip)
externalSource = input        (close, inline='2', group='Filters', title= '   External Source', tooltip = extTip)
extStartOp     = input.string ('==',  inline='3', group='Filters', title = 'Enable Trades When External Input', options=['==', '<', '>', '<=', '>=', 'crossover', 'crossunder'])
extStart       = input.int    (1,     inline='3', group='Filters', title='')
extStopOp      = input.string ('==',  inline='4', group='Filters', title = 'Disable Trades When Extranal Input', options=['==', '<', '>', '<=', '>=', 'crossover', 'crossunder'])
extStop        = input.int    (2,     inline='4', group='Filters', title='')

signalTip = 'Here you can set the signals that will enable backtester to open and close deals.\nIf the backtester you are using can only work with long OR short deals you may need to save diffent chart layouts for longs and shorts.\nIf \'Generate Close Signals for Long / Short Positions\' is not selected only the \'Open Long\' and \'Close Long\' settings will plot.'
generateClose    = input.bool (true, inline='0', group='Long / Short Signals', title='Generate Close Signals for Long / Short Positions', tooltip = signalTip)
longOpenSignal   = input.int  (1,    inline='1', group='Long / Short Signals', title='Open Long = ')
longCloseSignal  = input.int  (2,    inline='1', group='Long / Short Signals', title='Close Long = ')
shortOpenSignal  = input.int  (-1,   inline='2', group='Long / Short Signals', title='Open Short = ')
shortCloseSignal = input.int  (-2,   inline='2', group='Long / Short Signals', title='Close Short = ')

crossoverTip = 'Generate buy signals when the fast moving average crosses up on the slow moving average, or sell signals when the fast moving average crosses down on the slow moving average.\nThis is the same as the histogram crossing zero.'
cross0Tip = 'Generate buy signals when the MACD crossses zero moving upwards, or sell signals when the MACD crossses zero moving downwards'
backtestBuyCrossover    = input.bool (true,  inline='1', group='Buy / Sell Moving Averages', title='Buy Moving Average Crossover', tooltip = crossoverTip)
backtestSellCrossover   = input.bool (true,  inline='1', group='Buy / Sell Moving Averages', title='Sell Moving Average Crossover')
backtestMACrossUpZero   = input.bool (false, inline='2', group='Buy / Sell Moving Averages', title='Buy MACD Crossing Zero', tooltip = cross0Tip)
backtestMACrossDownZero = input.bool (false, inline='2', group='Buy / Sell Moving Averages', title='Sell MACD Average Crossing Zero')

divTip = 'Generate buy and sell signals based on divergences between the MACD and the close price. \nREMEMBER you can\'t trigger a divergence before a local top or bottom is CONFIRMED by closing some bars after that local top or bottom.'
lbR            = input.int  (5,     inline='1', group='MACD Divergences', title ='Pivot Lookback Right', tooltip = divTip)
lbL            = input.int  (5,     inline='1', group='MACD Divergences', title ='Pivot Lookback Left')
rangeUpper     = input.int  (60,    inline='2', group='MACD Divergences', title ='Lookback Range Max')
rangeLower     = input.int  (5,     inline='2', group='MACD Divergences', title ='Lookback Range Min')
plotBull       = input.bool (true,  inline='3', group='MACD Divergences', title ='Buy Bullish Divergence')
plotHiddenBull = input.bool (false, inline='3', group='MACD Divergences', title ='Buy Hidden Bullish Divergence')
plotBear       = input.bool (true,  inline='4', group='MACD Divergences', title ='Sell Bearish Divergence')
plotHiddenBear = input.bool (false, inline='4', group='MACD Divergences', title ='Sell Hidden Bearish Divergence')

histMATip = 'Generate buy signals when the histogram goes above the histogram moving average, this shows that the histogram is in an uptrend. \nGenerate sell signals when the histogram goes below the histogram moving average, this shows that the histogram is in an downtrend.'
backtestBuyHistMA  = input.bool  (false,       inline='1', group='Buy / Sell Histogram Moving Averages', title='Buy Histogram MA Positive', tooltip = histMATip)
backtestSellHistMA = input.bool  (false,       inline='1', group='Buy / Sell Histogram Moving Averages', title='Sell Histogram MA Negative')
MAHistLength       = input.int   (5, minval=2, inline='2', group='Buy / Sell Histogram Moving Averages', title='Histogram MA Length')
MAHistType         = input.string('EMA',       inline='2', group='Buy / Sell Histogram Moving Averages', title='Histogram MA Type', options=['EMA', 'VWMA', 'SMA', 'WMA', 'HMA', 'RMA', 'ALMA', 'Double EMA', 'Double SMA', 'Double WMA', 'Double RMA', 'Triple EMA', 'Triple SMA', 'Triple WMA', 'Triple RMA', 'LSMA', 'VIDYA', 'FRAMA'])

risingHistTip = 'Generate buy and sell signals when the histogram has been rising / falling for a number of consecutive bars.'
backtestBuyRisingHist        = input.bool (false,       inline='1', group='Buy / Sell Histogram Rising / Falling', title='Buy Histogram Rising', tooltip = risingHistTip)
backtestBuyRisingHistBelow   = input.bool (false,       inline='1', group='Buy / Sell Histogram Rising / Falling', title='Buy Histogram Rising Only Below Zero')
risingHistLength             = input.int  (1, minval=1, inline='2', group='Buy / Sell Histogram Rising / Falling', title='Consecutive Rising Bars to Trigger Buy')
backtestSellFallingHist      = input.bool (false,       inline='3', group='Buy / Sell Histogram Rising / Falling', title='Sell Histogram Falling')
backtestSellFallingHistAbove = input.bool (false,       inline='3', group='Buy / Sell Histogram Rising / Falling', title='Sell Histogram Falling Only Above Zero')
fallingHistLength            = input.int  (1, minval=1, inline='4', group='Buy / Sell Histogram Rising / Falling', title='Consecutive Falling Bars to Trigger Sell')

almaTip = 'Only required if ALMA is used as one of the moving averages.'
offset_alma = input       (0.85, title='ALMA Offset', inline='1', group='Alma', tooltip = almaTip)
sigma_alma  = input.float (6,    title='ALMA Sigma',  inline='1', group='Alma')

framaTip = 'Only required if FRAMA is used as one of the moving averages.'
FC = input.int(1,   minval=1, title='FRAMA lower shift limit (FC)', inline='1', group='Frama', tooltip = framaTip)
SC = input.int(198, minval=1, title='FRAMA upper shift limit (SC)', inline='1', group='Frama')

plotAlerts    = input.bool (true,  inline='1', group='Plot Options', title='Plot Alerts')
plotMA        = input.bool (true,  inline='1', group='Plot Options', title='Plot Moving Average')
plotSig       = input.bool (true,  inline='1', group='Plot Options', title='Plot Signal')
plotH         = input.bool (true,  inline='2', group='Plot Options', title='Plot Histogram')
plotHMA       = input.bool (true,  inline='2', group='Plot Options', title='Plot Histogram Moving Average')
plotDivLabels = input.bool (false, inline='3', group='Plot Options', title="Plot Divergence Labels")
plotDivLines  = input.bool (true,  inline='3', group='Plot Options', title="Plot Divergence Lines")

col_macd       = input.color(#2962FF, 'MACD Line  ',           group='Color Settings', inline='MACD')
col_signal     = input.color(#FF6D00, ' Signal Line  ',        group='Color Settings', inline='MACD')
col_grow_above = input.color(#26A69A, 'Histogram Above  Grow', group='Color Settings', inline='Above')
col_fall_above = input.color(#B2DFDB, 'Fall',                  group='Color Settings', inline='Above')
col_grow_below = input.color(#FFCDD2, 'Histogram Below  Grow', group='Color Settings', inline='Below')
col_fall_below = input.color(#FF5252, 'Fall',                  group='Color Settings', inline='Below')

// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Functions

getCMO(src, length) =>
    mom     = ta.change(src)
    upSum   = math.sum(math.max(mom, 0), length)
    downSum = math.sum(-math.min(mom, 0), length)
    out     = (upSum - downSum) / (upSum + downSum)
    out

vidya(src, length) =>
    alpha  = 2 / (length + 1)
    cmo    = math.abs(getCMO(src, length))
    vidya  = 0.0
    vidya := src * alpha * cmo + nz(vidya[1]) * (1 - alpha * cmo)
    vidya

frama(x, y, z, v) =>
    // x = source , y = length , z = FC , v = SC
    HL        = (ta.highest(high, y) - ta.lowest(low, y)) / y
    HL1       = (ta.highest(high, y / 2) - ta.lowest(low, y / 2)) / (y / 2)
    HL2       = (ta.highest(high, y / 2)[y / 2] - ta.lowest(low, y / 2)[y / 2]) / (y / 2)
    D         = (math.log(HL1 + HL2) - math.log(HL)) / math.log(2)
    dim       = HL1 > 0 and HL2 > 0 and HL > 0 ? D : nz(D[1])
    w         = math.log(2 / (v + 1))
    alpha     = math.exp(w * (dim - 1))
    alpha1    = alpha > 1 ? 1 : alpha < 0.01 ? 0.01 : alpha
    oldN      = (2 - alpha1) / alpha1
    newN      = (v - z) * (oldN - 1) / (v - 1) + z
    newalpha  = 2 / (newN + 1)
    newalpha1 = newalpha < 2 / (v + 1) ? 2 / (v + 1) : newalpha > 1 ? 1 : newalpha
    frama     = 0.0
    frama    := (1 - newalpha1) * nz(frama[1]) + newalpha1 * x
    frama

calcMA(_type, _src, _length) =>
    switch _type 
        'EMA'        => ta.ema(_src, _length)
        'SMA'        => ta.sma(_src, _length)
        'WMA'        => ta.wma(_src, _length)
        'VWMA'       => ta.vwma(_src, _length)
        'HMA'        => ta.hma(_src, _length)
        'RMA'        => ta.rma(_src, _length)
        'LSMA'       => ta.linreg(_src, _length, 0)
        'Double EMA' => 2 * ta.ema(_src, _length) - ta.ema(ta.ema(_src, _length), _length)
        'Double SMA' => 2 * ta.sma(_src, _length) - ta.sma(ta.sma(_src, _length), _length)
        'Double WMA' => 2 * ta.wma(_src, _length) - ta.wma(ta.wma(_src, _length), _length)
        'Double RMA' => 2 * ta.rma(_src, _length) - ta.rma(ta.rma(_src, _length), _length)
        'Triple EMA' => 3 * (ta.ema(_src, _length) - ta.ema(ta.ema(_src, _length), _length)) + ta.ema(ta.ema(ta.ema(_src, _length), _length), _length)
        'Triple SMA' => 3 * (ta.sma(_src, _length) - ta.sma(ta.sma(_src, _length), _length)) + ta.sma(ta.sma(ta.sma(_src, _length), _length), _length)
        'Triple WMA' => 3 * (ta.wma(_src, _length) - ta.wma(ta.wma(_src, _length), _length)) + ta.wma(ta.wma(ta.wma(_src, _length), _length), _length)
        'Triple RMA' => 3 * (ta.rma(_src, _length) - ta.rma(ta.rma(_src, _length), _length)) + ta.rma(ta.rma(ta.rma(_src, _length), _length), _length)
        'SWMA'       => ta.swma(_src)        // No Length for SWMA
        'ALMA'       => ta.alma(_src, _length, offset_alma, sigma_alma)
        'VIDYA'      => vidya(_src, _length)
        'FRAMA'      => frama(_src, _length, FC, SC)

// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Calculations

MA_fast = calcMA(FastType, FastSource, FastLength)
MA_slow = calcMA(SlowType, SlowSource, SlowLength)

macd   = MA_fast - MA_slow
signal = SignalLength > 1 ? calcMA(SignalType, macd, SignalLength) : 0
hist   = macd - signal
histMA = calcMA(MAHistType, hist, MAHistLength)

// ------------ Divergences

osc = macd

plFound = na(ta.pivotlow (osc, lbL, lbR)) ? false : true
phFound = na(ta.pivothigh(osc, lbL, lbR)) ? false : true
_inRange(cond) =>
	bars = ta.barssince(cond == true)
	rangeLower <= bars and bars <= rangeUpper

// Regular Bullish, Osc: Higher Low, Price: Lower Low

oscHL = osc[lbR] > ta.valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
priceLL = low[lbR] < ta.valuewhen(plFound, low[lbR], 1)
bullCond = plotBull and priceLL and oscHL and plFound

// Hidden Bullish, Osc: Lower Low, Higher Low

oscLL = osc[lbR] < ta.valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
priceHL = low[lbR] > ta.valuewhen(plFound, low[lbR], 1)
hiddenBullCond = plotHiddenBull and priceHL and oscLL and plFound

// Regular Bearish, Osc: Lower High, Price: Higher High

oscLH = osc[lbR] < ta.valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
priceHH = high[lbR] > ta.valuewhen(phFound, high[lbR], 1)
bearCond = plotBear and priceHH and oscLH and phFound

// Hidden Bearish, Osc: Higher High, Price: Lower High

oscHH = osc[lbR] > ta.valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
priceLH = high[lbR] < ta.valuewhen(phFound, high[lbR], 1)
hiddenBearCond = plotHiddenBear and priceLH and oscHH and phFound


// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Logic

var bool tradesEnabled = true

tradesEnabled := externalFilter ? hu.eval_cond(externalSource, extStopOp, extStop) ? false : hu.eval_cond(externalSource, extStartOp, extStart) ? true : tradesEnabled[1] : tradesEnabled==true

longSignal  = ta.crossover(hist, 0)
shortSignal = ta.crossunder(hist, 0)

MACrossUpZero   = ta.crossover(macd, 0)
MACrossDownZero = ta.crossover(macd, 0)

longHistMA  = histMA > histMA[1]
shortHistMA = histMA < histMA[1]

risingHist  = ta.rising  (hist, risingHistLength)  and (hist < 0 or not backtestBuyRisingHistBelow)
fallingHist = ta.falling (hist, fallingHistLength) and (hist > 0 or not backtestSellFallingHistAbove)

var int dealstate = 0

bool openLong   = false
bool closeLong  = false
bool openShort  = false
bool closeShort = false

backtestBuy = (backtestBuyCrossover      and longSignal)
               or (backtestBuyHistMA     and longHistMA and not longHistMA[1])
               or (backtestBuyRisingHist and risingHist and not risingHist[1])
               or (backtestMACrossUpZero and MACrossUpZero)
               or (plotBull              and bullCond)
               or (plotHiddenBull        and hiddenBullCond)

backtestSell = (backtestSellCrossover      and shortSignal)
               or (backtestSellHistMA      and shortHistMA and not shortHistMA[1])
               or (backtestSellFallingHist and fallingHist and not fallingHist[1])
               or (backtestMACrossDownZero and MACrossDownZero)
               or (plotBear                and bearCond)
               or (plotHiddenBear          and hiddenBearCond)

if backtestBuy and not backtestSell
    if tradesEnabled and (macd > 0 or not MACDAboveZero)
        if generateClose and dealstate == -1
            closeShort := true
            dealstate := 0
        else
            openLong := true
            dealstate := 1
    else
        if generateClose and dealstate == -1
            closeShort := true
            dealstate := 0

if backtestSell and not backtestBuy
    if tradesEnabled and (macd < 0 or not MACDBelowZero)
        if generateClose and dealstate <= 0
            openShort := true
            dealstate := -1
        else
            closeLong := true
            dealstate := 0
    else
        if generateClose and dealstate == 1
            closeLong := true
            dealstate := 0


// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Plot

plot(plotH   ? hist   : na, title='Histogram', style=plot.style_columns, color=hist >= 0 ? hist[1] < hist ? col_grow_above : col_fall_above : hist[1] < hist ? col_grow_below : col_fall_below, linewidth=2)
plot(plotHMA ? histMA : na, title='Histogram Moving Average', color=histMA > histMA[1] ? col_grow_above : col_fall_below, linewidth=2)
plot(plotMA  ? macd   : na, title='Moving Average', color=col_macd, linewidth=2)
plot(plotSig ? signal : na, title='Signal', color=col_signal, linewidth=2)

plot(closeShort ? shortCloseSignal : openLong ? longOpenSignal : closeLong ? longCloseSignal : openShort ? shortOpenSignal : 0, 'Backtest Signal', color=openLong or closeShort ? color.lime : openShort or closeLong? color.red : color.gray, display=display.none)

plot(close, title='Price', display=display.none, color = (low > MA_fast and low > MA_slow ? true : false) ? color.lime : (high < MA_fast and high < MA_slow ? true : false) ? color.red : color.blue)
plot(MA_fast, title= 'Fast Moving Average', display=display.none, color = color.red)
plot(MA_slow, title= 'Slow Moving Average', display=display.none, color = color.green)
plot(tradesEnabled ? 1 : 0 , title= 'Trades Enabled', display=display.none)
plot(dealstate, title='Deal State', display=display.none, color = (dealstate > 0 ? color.lime : dealstate < 0 ? color.red : color.gray))

// ------------ Divergences

bearColor = color.red
bullColor = color.green
hiddenBullColor = color.new(color.green, 50)
hiddenBearColor = color.new(color.red,   50)
textColor = color.white
noneColor = color.new(color.white, 100)

// Regular Bullish

plot(
     plFound and plotDivLines ? osc[lbR] : na,
     offset=-lbR,
     title="Regular Bullish",
     linewidth=2,
     color=(bullCond ? bullColor : noneColor)
     )

plotshape(
	 bullCond and plotDivLabels ? osc[lbR] : na,
	 offset=-lbR,
	 title="Regular Bullish Label",
	 text=" Bull ",
	 style=shape.labelup,
	 location=location.absolute,
	 color=bullColor,
	 textcolor=textColor
	 )

// Hidden Bullish

plot(
	 plFound and plotDivLines ? osc[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bullish",
	 linewidth=2,
	 color=(hiddenBullCond ? hiddenBullColor : noneColor)
	 )

plotshape(
	 hiddenBullCond and plotDivLabels ? osc[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bullish Label",
	 text=" H Bull ",
	 style=shape.labelup,
	 location=location.absolute,
	 color=bullColor,
	 textcolor=textColor
	 )

// Regular Bearish

plot(
	 phFound and plotDivLines ? osc[lbR] : na,
	 offset=-lbR,
	 title="Regular Bearish",
	 linewidth=2,
	 color=(bearCond ? bearColor : noneColor)
	 )

plotshape(
	 bearCond and plotDivLabels ? osc[lbR] : na,
	 offset=-lbR,
	 title="Regular Bearish Label",
	 text=" Bear ",
	 style=shape.labeldown,
	 location=location.absolute,
	 color=bearColor,
	 textcolor=textColor
	 )

// Hidden Bearish

plot(
	 phFound and plotDivLines ? osc[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bearish",
	 linewidth=2,
	 color=(hiddenBearCond ? hiddenBearColor : noneColor)
	 )

plotshape(
	 hiddenBearCond and plotDivLabels ? osc[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bearish Label",
	 text=" H Bear ",
	 style=shape.labeldown,
	 location=location.absolute,
	 color=bearColor,
	 textcolor=textColor
	 )


// ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
// ============ Alerts

alertcondition (openLong,   title='AMACD Open Long!',   message='Buy signal, put your JSON here to open longs or start bots.')
alertcondition (openShort,  title='AMACD Open Short!',  message='Sell signal, put your JSON here to open shorts or stop bots.')
alertcondition (closeShort, title='AMACD Close Short!', message='Buy signal, put your JSON here to close shorts or start bots.')
alertcondition (closeLong,  title='AMACD Close Long!',  message='Sell signal, put your JSON here to close longs or stop bots.')

plotshape (plotAlerts ? openLong and longOpenSignal     : na, style=shape.triangleup,   color=color.lime, location=location.bottom, size=size.tiny, title='Open Long')
plotshape (plotAlerts ? closeLong and longCloseSignal   : na, style=shape.square,       color=color.lime, location=location.bottom, size=size.tiny, title='Close Long')
plotshape (plotAlerts ? openShort and shortOpenSignal   : na, style=shape.triangledown, color=color.red,  location=location.bottom, size=size.tiny, title='Open Short')
plotshape (plotAlerts ? closeShort and shortCloseSignal : na, style=shape.square,       color=color.red,  location=location.bottom, size=size.tiny, title='Close Short')