Moving averages & clouds
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mickes

//@version=5
indicator("Moving averages & clouds", overlay = true)

import TradingView/ta/5

_timeFrame = input.timeframe("", "Time frame", group = "General")

_ma1Length = input.int(21, "Length", group = "Moving average 1")
_ma1Type = input.string("EMA", "Type", ["SMA", "EMA", "HMA", "WMA", "VWMA", "DEMA"], group = "Moving average 1")
_ma1Alert = input.string("None", "Type", ["None", "Price cross", "Price cross up", "Price cross down"], group = "Moving average 1")
_ma2Length = input.int(50, "Length", group = "Moving average 2")
_ma2Type = input.string("SMA", "Type", ["SMA", "EMA", "HMA", "WMA", "VWMA", "DEMA"], group = "Moving average 2")
_ma2Alert = input.string("None", "Type", ["None", "Cross", "Cross up", "Cross down"], group = "Moving average 2")
_ma3Length = input.int(200, "Length", group = "Moving average 3")
_ma3Type = input.string("SMA", "Type", ["SMA", "EMA", "HMA", "WMA", "VWMA", "DEMA"], group = "Moving average 3")
_ma3Alert = input.string("None", "Type", ["None", "Cross", "Cross up", "Cross down"], group = "Moving average 3")

_alertFrequency = input.string(alert.freq_all, "Frequecy", [alert.freq_all, alert.freq_once_per_bar, alert.freq_once_per_bar_close], group = "Alert")

type movingAverage
    float Price

getMovingAverage(movingAverageType, length) =>
    ma = movingAverage.new()
    switch movingAverageType
        "SMA" => ma.Price := ta.sma(close, length)
        "EMA" => ma.Price := ta.ema(close, length)
        "HMA" => ma.Price := ta.hma(close, length)
        "WMA" => ma.Price := ta.wma(close, length)
        "VWMA" => ma.Price := ta.vwma(close, length)
        "DEMA" => ma.Price := ta.dema2(close, length)

    ma
alertUser(movingAveragePrice, alertType, message) =>
    lowCrossUp = ta.crossover(low, movingAveragePrice)
    highCrossDown = ta.crossunder(high, movingAveragePrice)
    var highCrossedDown = false
    var lowCrossedUp = false

    if highCrossDown
        highCrossedDown := true
    if lowCrossUp
        lowCrossedUp := true

    switch alertType
        "Price cross" =>
            if (lowCrossUp and highCrossedDown)
              or (highCrossDown and lowCrossedUp)
                alert(str.format("Price crossed {0}", message), _alertFrequency)
                highCrossedDown := false
                lowCrossedUp := false
                label.new(bar_index, high, str.format("Price crossed {0}", message))
        "Price cross up" =>
            if lowCrossUp
              and highCrossedDown
                alert(str.format("Price crossed {0} up", message), _alertFrequency)
                highCrossedDown := false
                label.new(bar_index, high, str.format("Price crossed {0} up", message))
        "Price cross down" =>
            if highCrossDown
              and lowCrossedUp
                alert(str.format("Price crossed {0} down", message), _alertFrequency)
                lowCrossedUp := false
                label.new(bar_index, high, str.format("Price crossed {0} down", message))

ma1 = request.security(syminfo.tickerid, _timeFrame, getMovingAverage(_ma1Type, _ma1Length), lookahead = barmerge.lookahead_on)
ma2 = request.security(syminfo.tickerid, _timeFrame, getMovingAverage(_ma2Type, _ma2Length), lookahead = barmerge.lookahead_on)
ma3 = request.security(syminfo.tickerid, _timeFrame, getMovingAverage(_ma3Type, _ma3Length), lookahead = barmerge.lookahead_on)

ma1Plot = plot(ma1.Price, "MA 1", color = color.blue)
ma2Plot = plot(ma2.Price, "MA 2", color = color.orange)
ma3Plot = plot(ma3.Price, "MA 3", color = color.red)

fill(ma1Plot, ma2Plot, title = "Cloud 1 <-> 2", color = color.new(na, 100))
fill(ma1Plot, ma3Plot, title = "Cloud 1 <-> 3", color = color.new(na, 100))
fill(ma2Plot, ma3Plot, title = "Cloud 2 <-> 3", color = color.new(color.red, 85))

alertUser(ma1.Price, _ma1Alert, str.format("Moving average 1 ({0} {1} {2}) on {3} chart", _ma1Length, _ma1Type, _timeFrame, timeframe.period))
alertUser(ma2.Price, _ma2Alert, str.format("Moving average 2 ({0} {1} {2}) on {3} chart", _ma1Length, _ma1Type, _timeFrame, timeframe.period))
alertUser(ma3.Price, _ma3Alert, str.format("Moving average 3 ({0} {1} {2}) on {3} chart", _ma1Length, _ma1Type, _timeFrame, timeframe.period))