Relative Andean Scalping
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0
// This script uses source code of Andean Oscilator by @alexgrover and Relative Bandwith Filter by @HeWhoMustNotBeNamed
// This is an experimental signal indicator and should be used with caution.
// © serkany88

//@version=5
indicator("Relative Andean Scalping", precision=3, overlay=true)

// Functions used later
f_ideal_TimesInLast(_cond, _len) =>  math.sum(_cond ? 1 : 0, _len)

//------------------------------------------------------------------------------
//Andean Settings and Calculation by @alexgrover
//-----------------------------------------------------------------------------{
and_length     = input.int(100, minval=1, title='Andean Length', group='Andean Oscilator Settings')

and_sig_length = input.int(13, title='Andean Signal Length', group='Andean Oscilator Settings')

//Andean Calculation
var alpha = 2/(and_length+1)

var up1 = 0.,var up2 = 0.
var dn1 = 0.,var dn2 = 0.

C = close
O = open

up1 := nz(math.max(C, O, up1[1] - (up1[1] - C) * alpha), C)
up2 := nz(math.max(C * C, O * O, up2[1] - (up2[1] - C * C) * alpha), C * C)

dn1 := nz(math.min(C, O, dn1[1] + (C - dn1[1]) * alpha), C)
dn2 := nz(math.min(C * C, O * O, dn2[1] + (C * C - dn2[1]) * alpha), C * C)

bull = math.sqrt(dn2 - dn1 * dn1)
bear = math.sqrt(up2 - up1 * up1)

signal = ta.ema(math.max(bull, bear), and_sig_length)
//-----------------------------------------------------------------------------}

//------------------------------------------------------------------------------
//Relative Bandwith Filter by @HeWhoMustNotBeNamed
//-----------------------------------------------------------------------------{
import HeWhoMustNotBeNamed/enhanced_ta/14 as eta

bandType = input.string("KC", title="Bands Type", group="Relative Bandwith Filter Bands", options=["BB", "KC", "DC"])
bmasource = input.source(close, title="Bands Source", group="Relative Bandwith Filter Bands")
bmatype = input.string("linreg", title="Bands Type", group="Relative Bandwith Filter Bands", options=["sma", "ema", "hma", "rma", "wma", "vwma", "swma", "linreg", "median"])
bmalength = input.int(34, title="Bands Length", group="Relative Bandwith Filter Bands")
multiplier = input.float(2.0, step=0.5, title="Bands Multiplier", group="Relative Bandwith Filter Bands")
useTrueRange = input.bool(true, title="Bands Use True Range (KC)", group="Relative Bandwith Filter Bands")
useAlternateSource = input.bool(false, title="Bands Use Alternate Source (DC)", group="Relative Bandwith Filter Bands")
bsticky = input.bool(true, title="Sticky Lines", group="Relative Bandwith Filter Bands")

atrLength = input.int(34, 'ATR Length', group='Relative Bandwith Filter ATR')

bbmatype = input.string("linreg", title="BBands Type", group="Relative Bandwith Filter BBands", options=["sma", "ema", "hma", "rma", "wma", "vwma", "linreg", "median"])
bbmalength = input.int(100, title="BBands Length", group="Relative Bandwith Filter BBands")
mmultiplier = input.float(1.0, step=0.5, title="BBands Multiplier", group="Relative Bandwith Filter BBands")

desiredCondition = input.string("Higher Bandwidth", "Desired Condition", options=["Higher Bandwidth", "Lower Bandwidth"], group="Relative Bandwith Filter")
referenceBand = input.string("Middle", options=["Upper", "Lower", "Middle"], group="Relative Bandwith Filter")

var cloudTransparency = 90
[bbmiddle, bbupper, bblower] = eta.bb(bmasource, bmatype, bmalength, multiplier, sticky=bsticky)
[kcmiddle, kcupper, kclower] = eta.kc(bmasource, bmatype, bmalength, multiplier, useTrueRange, sticky=bsticky)
[dcmiddle, dcupper, dclower] = eta.dc(bmalength, useAlternateSource, bmasource, sticky=bsticky)

upper = bandType == "BB"? bbupper : bandType == "KC"? kcupper : dcupper
lower = bandType == "BB"? bblower : bandType == "KC"? kclower : dclower
middle = bandType == "BB"? bbmiddle : bandType == "KC"? kcmiddle : dcmiddle

atr = ta.atr(atrLength)

relativeBandwidth = (upper-lower)/atr

[mmiddle, uupper, llower] = eta.bb(relativeBandwidth, bbmatype, bbmalength, mmultiplier, sticky=false)

reference = referenceBand == "Middle"? mmiddle : referenceBand == "Upper"? uupper : llower
bbsignal = relativeBandwidth > reference? 2 : 0
bbsignal := desiredCondition == "Lower Bandwidth"? math.abs(bbsignal-2) : bbsignal
//-----------------------------------------------------------------------------}

//------------------------------------------------------------------------------
//Entry Condition Signals
//-----------------------------------------------------------------------------{
longCond = relativeBandwidth < mmiddle and bull > bear and ta.crossover(bull, signal)
shortCond = relativeBandwidth < mmiddle and bear > bull and ta.crossover(bear, signal)

//Define last signal condition to update later
var bool last_signal = false

plotshape(longCond and not(last_signal), title='Long Signal', style=shape.labelup, location=location.belowbar, color=color.green, text='Long', textcolor=color.white, size=size.small)
plotshape(shortCond and not(last_signal), title='Short Signal', style=shape.labeldown, location=location.abovebar, color=color.red, text='Short', textcolor=color.white, size=size.small)

//Alerts
alertcondition(longCond and not(last_signal), "Long Signal", message='Long Signal at Price: {{close}} @ {{ticker}}')
alertcondition(shortCond and not(last_signal), "Short Signal", message='Short Signal at Price: {{close}} @ {{ticker}}')
alertcondition((longCond and not(last_signal)) or (shortCond and not(last_signal)), "Long or Short Signal", message='Signal at Price: {{close}} @ {{ticker}}')

//We check if there is any signal in last 5 bars and if there is we won't show any signal to avoid confusion and filter out some bad signals
last_signal := f_ideal_TimesInLast(longCond or shortCond, 5) >= 1