Signs of the Times [LucF]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LucF

//@version=5

indicator("Signs of the Times [LucF]", "SOTT", timeframe = "", timeframe_gaps = false, precision = 2)

// Signs of the Times [LucF]
// v2, 2022.11.06 12:54 — LucF

// 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.0
float LEVEL_HI  =  0.3
float LEVEL_LO  = -0.3

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

// 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 = "SOTT MA"
string CB2 = "MA of MA"
string CB3 = "Channel fill"
string CB4 = "MA fill"

// Tooltips
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_CHANNEL = "'🡑' 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
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    maShowInput             = input.bool(false,     "MA of MA",     inline = "ma")
color   maUpColorInput          = input.color(YELLOW,   " 🡑",           inline = "ma")
color   maDnColorInput          = input.color(BLUE_DK,  "🡓",            inline = "ma")
string  maTypeInput             = input.string(MA01,    "",             inline = "ma", options = [MA01, MA02, MA03, MA04, MA05, MA06, MA07, MA08])
int     maLengthInput           = input.int(20,         "Length",       inline = "ma", minval = 2, tooltip = TT_MA)

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(PURPLE,   "🡓🡓",           inline = "channel", tooltip = TT_CHANNEL)

bool    maFillShowInput         = input.bool(true,      "MA fill",      inline = "maFill")
color   maFillUpColorInput      = input.color(YELLOW,   "   🡑",         inline = "maFill")
color   maFillDnColorInput      = input.color(BLUE,     "🡓",            inline = "maFill", tooltip = TT_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])
//#endregion



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


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

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

// MAs
float signal = LucfTa.ma(signalTypeInput, sott, signalLengthInput)
float ma     = LucfTa.ma(maTypeInput, signal, maLengthInput)

// States
bool  maIsBull      = ma     > LEVEL_MID
bool  signalIsBull  = signal > LEVEL_MID
bool  channelIsBull = signal > ma
//#endregion



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


// Plotting colors
color channelColor      = channelIsBull ? signalIsBull ? channelUpUpColorInput : channelUpColorInput : signalIsBull ? channelDnColorInput : channelDnDnColorInput
color signalColor       = signalIsBull ? signalUpColorInput : signalDnColorInput
color maColor           = maIsBull ? maUpColorInput : maDnColorInput
color maChannelTopColor = maIsBull ? maFillUpColorInput : color.new(maFillDnColorInput, 95)
color maChannelBotColor = maIsBull ? color.new(maFillUpColorInput, 95) : maFillDnColorInput

// Plots
signalPlot = plot(signalShowInput or channelShowInput ? signal : na, "SOTT MA", signalShowInput ? signalColor : na, 2)
maPlot     = plot(ma, "MA of MA", maShowInput ? maColor : na)
zeroPlot   = 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 * 0.7 : LEVEL_MID, maIsBull ? LEVEL_MID : LEVEL_LO * 0.7, maChannelTopColor, maChannelBotColor)

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

// Levels
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.
plot(sott, "Instant SOTT", display = display.data_window)

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