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

//@version=5
//@description=The fast and slow moving average combine to help visualize the current trend and potential changes in trend.
indicator("Swing Ribbon", overlay = true)

// - Is used for both fast and slow moving averages.
// - Allows for selecting a moving average by a string parameter instead of having to define a switch locally.
import Electrified/MovingAverages/10 as MA

// - Time.spanToIntLen is used repeatedly here to simplify getting the number bars for a given timeframe.
// - If "Minutes" or "Days" are selected, changing the timeframe on the chart, this indicator should still look about the same.
import Electrified/Time/7

// Constants
SMA = 'SMA', EMA = 'EMA', WMA = 'WMA', VWMA = 'VWMA', VAWMA = 'VAWMA'
MINUTES = "Minutes", DAYS = "Days", BARS = "Bars"
MOVING_AVERAGES = "Moving Averages"
FAST = "Fast", SLOW = "Slow"

// HLCC4 is typically very near the close. This is just a default.
source = input.source(hlcc4, "Source")

// fastMA default: WMA of 5 days.
fastMA = MA.get(
  input.string(WMA, FAST, options = [SMA, EMA, WMA, VWMA, VAWMA], inline = FAST, group = MOVING_AVERAGES),
  Time.spanToIntLen(
  input.float(5, "", inline = FAST, group = MOVING_AVERAGES),
  input.string(DAYS, "", options = [BARS, MINUTES, DAYS], inline = FAST, group = MOVING_AVERAGES)),
  source)

// slowMA default: WMA of 7 days.
// This can also be set to SMA of 5 days to create a useful divergence and visualization to demonstrate the difference in the two.
slowMA = MA.get(
  input.string(WMA, SLOW, options = [SMA, EMA, WMA, VWMA, VAWMA], inline = SLOW, group = MOVING_AVERAGES),
  Time.spanToIntLen(
  input.float(7, "", inline = SLOW, group = MOVING_AVERAGES),
  input.string(DAYS, "", options = [BARS, MINUTES, DAYS], inline = SLOW, group = MOVING_AVERAGES)),
  source)

// As the tooltip says, this gives a volatility tolerance that when set to something greater than one, will need more than one bar before a change in direction is confirmed.
tolerance = input.int(2, "Tolerance", 1, tooltip = "The number of bars to measure the direction of the moving averages.")

// Simply a way of forcing a fixed integer value in order to measure a valid signal.
quantize(float k, int value = 1) =>
    k > 0 ? value : k < 0 ? -value : 0

// Where is the close (live value) relative to the fastMA
closeP = close - fastMA
// What is the fastMA's direction?
fastD = quantize(ta.change(fastMA, tolerance))
// What is the slowMA's direction?
slowD = quantize(ta.change(slowMA, tolerance))

if input.bool(true, "Include price in warning condition",
  tooltip = "When this is checked, the visual warning condition will displayed if the price is on the opposite side of the fast moving average even if the direction hasn't changed.")
    if closeP < 0
        fastD := math.min(fastD, -1)
    if closeP > 0
        fastD := math.max(fastD, +1)

D = fastD + slowD

THEME = "Theme"
clearColor = color.new(color.gray, 100)
upColor = input.color(color.green, "▲", group = THEME, inline = THEME)
dnColor = input.color(color.red, "▼", group = THEME, inline = THEME)
warnColor = input.color(color.yellow, "⚠", group = THEME, inline = THEME)
dirctionColor(value) => value > 0 ? upColor : value < 0 ? dnColor : warnColor

fillColor = dirctionColor(D)
slowPlot = plot(slowMA, "Slow", clearColor, 2)
fastPlot = plot(fastMA, "Fast", fillColor, 2)

fill(fastPlot, slowPlot, fastMA, slowMA, color.new(fillColor, 20), color.new(fillColor, 90))