Signal #1
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/


//@version=5

int MAX_BARS_BACK = 1000
indicator("Signal #1", max_bars_back = MAX_BARS_BACK, timeframe = "", timeframe_gaps = false, precision = 2)


// v3, 2022.11.06 13:05 

// This code was written using the recommendations from the Pine Script™ User Manual's Style Guide:
//   https://www.tradingview.com/pine-script-docs/en/v5/writing/Style_guide.html


import LucF/ta/2 as LucfTa



//#region ———————————————————— Constants and inputs


// Key levels
float LEVEL_MID = 0.
float LEVEL_HI  = 0.3
float LEVEL_LO  = -0.3

// Colors
color BLUE    = #3179f5
color GRAY    = #434651
color GRAY_LT = #9598a1
color GREEN   = #006200
color LIME    = #00FF00
color MAROON  = #800000
color ORANGE  = #e65100
color PINK    = #FF0080
color YELLOW  = #fbc02d
color BLUE_DK = #013bca
color PURPLE  = #C314EB

// MAs
string MA01 = "Simple MA"
string MA02 = "Exponential MA"
string MA03 = "Wilder MA"
string MA04 = "Weighted MA"
string MA05 = "Volume-weighted MA"
string MA06 = "Arnaud Legoux MA"
string MA07 = "Hull MA"
string MA08 = "Symmetrically-weighted MA"

// Bar coloring modes
string CB1 = "Buoyancy line"
string CB2 = "MA line"
string CB3 = "Channel fill"
string CB4 = "MA fill"
// Bar coloring modes 2
string CB12 = "SOTT MA"
string CB22 = "MA of MA"
string CB32 = "Channel fill"
string CB42 = "MA fill"
// Tooltips
string TT_TARGET    = "This value specifies the number of bars for which volume is added to calculate the target."
string TT_LINE      = "'🡑' and '🡓' indicate bull/bear conditions, which occur when the line is above/below the centerline."
string TT_CHANNEL   = "'🡑' and '🡓' indicate bull/bear conditions, which occur when buoyancy is above/below its MA while not also being above/below the centerline.
  \n\n'🡑🡑' and '🡓🡓' indicate strong bull/bear conditions, which require buoyancy to be above/below its MA, and above/below the centerline."
// Tooltips 2
string TT_SIGNAL  = "You specify here the type and length of the MA you want applied to the instant SOTT value. 
  You can view the instant value by using a length of 1.
  \n\nNOTE: The length of this MA must be smaller than that of the second MA defined below.
  \n\n'🡑' and '🡓' indicate bull/bear conditions, which occur when the line is above/below the centerline."
string TT_MA      = "You specify here the type and length of the MA you want applied to the MA of SOTT defined above, so this is an MA of an MA.
  \n\n'🡑' and '🡓' indicate bull/bear conditions, which occur when the line is above/below the centerline."
string TT_CHANNEL2 = "'🡑' and '🡓' indicate bull/bear conditions, which occur when the first MA is above/below the second MA while not also being above/below the centerline.
  \n\n'🡑🡑' and '🡓🡓' indicate strong bull/bear conditions, which require the first MA to be above/below the second MA, and above/below the centerline."
string TT_MAFILL  = "'🡑' and '🡓' indicate bull/bear conditions, which occur when the second MA is above/below the centerline."
// Inputs
int     periodInput             = input.int(20,         "Target bars",      inline = "target", minval = 1, maxval = int(MAX_BARS_BACK / 4), tooltip = TT_TARGET)
bool    buoyancyShowInput       = input.bool(true,      "Buoyancy",         inline = "buoyancy")
color   buoyancyUpColorInput    = input.color(GRAY_LT,  "🡑",                inline = "buoyancy")
color   buoyancyDnColorInput    = input.color(GRAY_LT,  "🡓",                inline = "buoyancy", tooltip = TT_LINE)

bool    maShowInput             = input.bool(false,     "MA line",          inline = "ma")
color   maUpColorInput          = input.color(YELLOW,   " 🡑",               inline = "ma")
color   maDnColorInput          = input.color(ORANGE,   "🡓",                inline = "ma")
string  maTypeInput             = input.string(MA06,    "",                 inline = "ma", options = [MA01, MA02, MA03, MA04, MA05, MA06, MA07, MA08])

int     maLengthInput           = input.int(20,         "Length",           inline = "ma", minval = 2, tooltip = TT_LINE)
bool    channelShowInput        = input.bool(true,      "Channel",          inline = "channel")
color   channelUpColorInput     = input.color(GREEN,    "  🡑",              inline = "channel")
color   channelDnColorInput     = input.color(MAROON,   "🡓",                inline = "channel")
color   channelUpUpColorInput   = input.color(LIME,     "🡑🡑",               inline = "channel")
color   channelDnDnColorInput   = input.color(PINK,     "🡓🡓",               inline = "channel", tooltip = TT_CHANNEL)

bool    maFillShowInput         = input.bool(true,      "MA fill",          inline = "maFill")
color   maFillUpColorInput      = input.color(GRAY,     "   🡑",             inline = "maFill")
color   maFillDnColorInput      = input.color(BLUE,     "🡓",                inline = "maFill")

bool    colorBarsInput          = input.bool(false,     "Color chart bars using the color of", inline = "bars")
string  colorBarsModeInput      = input.string(CB3,     "",                 inline = "bars", options = [CB1, CB2, CB3, CB4])

// Inputs2
bool    signalShowInput         = input.bool(true,      "SOTT MA",      inline = "signal")
color   signalUpColorInput      = input.color(GREEN,    "  🡑",          inline = "signal")
color   signalDnColorInput      = input.color(MAROON,   "🡓",            inline = "signal")
string  signalTypeInput         = input.string(MA06,    "",             inline = "signal", options = [MA01, MA02, MA03, MA04, MA05, MA06, MA07, MA08])
int     signalLengthInput       = input.int(20,         "Length",       inline = "signal", minval = 1, tooltip = TT_SIGNAL)

bool    maShowInput2             = input.bool(false,     "MA of MA",     inline = "ma2")
color   maUpColorInput2          = input.color(YELLOW,   " 🡑",           inline = "ma2")
color   maDnColorInput2          = input.color(BLUE_DK,  "🡓",            inline = "ma2")
string  maTypeInput2             = input.string(MA01,    "",             inline = "ma2", options = [MA01, MA02, MA03, MA04, MA05, MA06, MA07, MA08])
int     maLengthInput2           = input.int(20,         "Length",       inline = "ma2", minval = 2, tooltip = TT_MA)

bool    channelShowInput2        = input.bool(true,      "Channel",      inline = "channel2")
color   channelUpColorInput2     = input.color(GREEN,    "  🡑",          inline = "channel2")
color   channelDnColorInput2     = input.color(MAROON,   "🡓",            inline = "channel2")
color   channelUpUpColorInput2   = input.color(LIME,     "🡑🡑",           inline = "channel2")
color   channelDnDnColorInput2   = input.color(PURPLE,   "🡓🡓",           inline = "channel2", tooltip = TT_CHANNEL2)

bool    maFillShowInput2         = input.bool(true,      "MA fill",      inline = "maFill2")
color   maFillUpColorInput2      = input.color(YELLOW,   "   🡑",         inline = "maFill2")
color   maFillDnColorInput2      = input.color(BLUE,     "🡓",            inline = "maFill2", tooltip = TT_MAFILL)

bool    colorBarsInput2          = input.bool(false,     "Color chart bars using the color of", inline = "bars")
string  colorBarsModeInput2      = input.string(CB3,     "",                 inline = "bars", options = [CB1, CB2, CB3, CB4])

//#endregion



//#region ———————————————————— Calculations


// Stop the indicator on charts with no volume.
if barstate.islast and ta.cum(nz(volume)) == 0
    runtime.error("No volume is provided by the data vendor.")

// Calculate buoyancy and its MA.
float buoyancy = LucfTa.buoyancy(volume, periodInput, MAX_BARS_BACK)
float ma       = LucfTa.ma(maTypeInput, buoyancy, maLengthInput)

// States
bool  maIsBull       = ma       > LEVEL_MID
bool  buoyancyIsBull = buoyancy > LEVEL_MID
bool  channelIsBull  = buoyancy > ma


// Validate MA lengths.2
if signalLengthInput > maLengthInput
	runtime.error("The length of the SOTT MA must be less than or equal to that of the second MA.")

// Instant SOTT2
float sott 	 = LucfTa.sott()

// MAs2
float signal = LucfTa.ma(signalTypeInput, sott, signalLengthInput)
float ma2     = LucfTa.ma(maTypeInput2, signal, maLengthInput2)

// States2
bool  maIsBull2      = ma2     > LEVEL_MID
bool  signalIsBull2  = signal > LEVEL_MID
bool  channelIsBull2 = signal > ma2



//#endregion



//#region ———————————————————— Plots


// Plotting colors
color channelColor      = channelIsBull ? buoyancyIsBull ? channelUpUpColorInput : channelUpColorInput : buoyancyIsBull ? channelDnColorInput : channelDnDnColorInput
color buoyancyColor     = buoyancyIsBull ? buoyancyUpColorInput : buoyancyDnColorInput
color maColor           = maIsBull ? maUpColorInput : maDnColorInput
color maChannelTopColor = maIsBull ? maFillUpColorInput : color.new(maFillDnColorInput, 95)
color maChannelBotColor = maIsBull ? color.new(maFillUpColorInput, 95) : maFillDnColorInput

// Plotting colors2
color channelColor2      = channelIsBull2 ? signalIsBull2 ? channelUpUpColorInput2 : channelUpColorInput2 : signalIsBull2 ? channelDnColorInput2 : channelDnDnColorInput2
color signalColor       = signalIsBull2 ? signalUpColorInput : signalDnColorInput
color maColor2           = maIsBull ? maUpColorInput : maDnColorInput
color maChannelTopColor2 = maIsBull ? maFillUpColorInput : color.new(maFillDnColorInput, 95)
color maChannelBotColor2 = maIsBull ? color.new(maFillUpColorInput, 95) : maFillDnColorInput

// Plots
buoyancyPlot = plot(buoyancy, "Buoyancy", buoyancyShowInput ? buoyancyColor : na)
maPlot       = plot(ma, "MA", maShowInput ? maColor : na)
zeroPlot     = plot(LEVEL_MID, "Phantom Mid Level", display = display.none)

// Plots2
signalPlot = plot(signalShowInput or channelShowInput ? signal : na, "SOTT MA", signalShowInput ? signalColor : na, 2)
maPlot2     = plot(ma, "MA of MA", maShowInput ? maColor : na)
zeroPlot2   = plot(LEVEL_MID, "Phantom Mid Level", display = display.none)

// Fill the MA channel (the space between the middle level and the MA).
fill(maPlot, zeroPlot, not maFillShowInput ? na : maIsBull ? LEVEL_HI : LEVEL_MID, maIsBull ? LEVEL_MID : LEVEL_LO, maChannelTopColor, maChannelBotColor)

// Fill the MA channel (the space between the middle level and the MA).2
fill(maPlot, zeroPlot, not maFillShowInput ? na : maIsBull ? LEVEL_HI * 0.7 : LEVEL_MID, maIsBull ? LEVEL_MID : LEVEL_LO * 0.7, maChannelTopColor, maChannelBotColor)

// Fill the buoyancy channel (between the buoyancy line and its MA).
fill(maPlot, buoyancyPlot, ma, not channelShowInput ? na : buoyancy, color.new(channelColor, 70), channelColor)

// Fill the signal channel (between the two MAs).2
fill(maPlot, signalPlot, ma, not channelShowInput ? na : signal, color.new(channelColor, 70), channelColor)

// Levels
hline(LEVEL_HI,  "High level", buoyancyUpColorInput, hline.style_dotted)
hline(LEVEL_MID, "Mid level",  color.gray, hline.style_dotted)
hline(LEVEL_LO,  "Low level",  buoyancyDnColorInput, hline.style_dotted)


// Levels2
hline(LEVEL_HI,  "High level", signalUpColorInput, hline.style_dotted)
hline(LEVEL_MID, "Mid level",  color.gray, hline.style_dotted)
hline(LEVEL_LO,  "Low level",  signalDnColorInput, hline.style_dotted)


// Instant SOTT for Data Window.2
plot(sott, "Instant SOTT", display = display.data_window)

// Color bars
color barColor = 
  switch colorBarsModeInput
    CB1 => buoyancyColor
    CB2 => maColor
    CB3 => channelColor
    CB4 => maIsBull ? maFillUpColorInput : maFillDnColorInput
    => na
barcolor(colorBarsInput ? barColor : na)

// Color bars
color barColor2 = 
  switch colorBarsModeInput
    CB12 => signalColor
    CB22 => maColor
    CB32 => channelColor
    CB42 => maIsBull ? maFillUpColorInput : maFillDnColorInput
    => na
barcolor(colorBarsInput ? barColor : na)
//#endregion
