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

//@version=5

// @description This is a library which only functions to make the McNicholl's Bollinger Bands modifications. It's also my first library, so I'll probably screw some things up.
// I know that global variables are evil, but damn, do I want to use them. Maybe I could do a "gambiarra", but I'll be a good boy and do the right thing. For now.
library("McNichollBands")

calcEMA(float alpha, float modifier) => 
    var lastValue = 0.0
    
    newValue = alpha * modifier + (1 - alpha) * lastValue
    lastValue := newValue
    
    newValue

expIfLog(bool useLogScale, float value) =>
    if useLogScale
        math.exp(value)
    else
        value

calcBand(bool useLogScale, float centerLine, float widthMultiplier, float bCenterLine, int sign) =>
    band = centerLine + widthMultiplier * bCenterLine * sign
    expIfLog(useLogScale, band)
        
calcCenterLine(float alpha, float m, float u) =>
    ((2 - alpha) * m - u) / 
         (1 - alpha)

// @function Calculates the McNicholl's Bollinger Bands modifications.
// @param alpha The alpha constant to be used on the EMA calculations.
// @param useLogScale Whether to use the log version of the prices or not.
// @param widthMultiplier The number that shall be multiplied by the volatility to form the bands.
// @returns A tuple containing the lower band, the center line, and the upper band.
export mcNichollBands(float alpha, float widthMultiplier, bool useLogScale) =>
	// Getting the right close
    
    rClose = useLogScale ? math.log(close) : close
    
    // Getting the bands
    
    M = calcEMA(alpha, rClose)
    U = calcEMA(alpha, M)
    centerLine = calcCenterLine(alpha, M, U)
    
    bM = calcEMA(alpha, math.abs(rClose - M))
    bU = calcEMA(alpha, bM)
    bCenterLine = calcCenterLine(alpha, bM, bU)
    
    upperBand = calcBand(useLogScale, centerLine, widthMultiplier, bCenterLine, 1)
    lowerBand = calcBand(useLogScale, centerLine, widthMultiplier, bCenterLine, -1)
    centerLineLog = expIfLog(useLogScale, centerLine)
    
    // Returning
    
    [lowerBand, centerLineLog, upperBand]
