[LanZhu] - Bias With Divergence
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Lanzhu0506

//@version=5

indicator("[LanZhu] - Bias With Divergence", overlay=false)

///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///                         Input & Setting                         ///
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////


// ==========
// ===Bias===
// ==========

biasGroup = '===Bias Setting==='


defaultBiasMA = input.int(defval=6, title="Default Bias MA Length", inline="defaultBias", group=biasGroup, tooltip='Will be used for divergence detection')

isShowBias2 = input.bool(defval=true, title="Show Bias 2", inline="bias2", group=biasGroup)
biasMA2 = input.int(defval=12, title="Bias 2 MA Length", inline="bias2", group=biasGroup)

isShowBias3 = input.bool(defval=true, title="Show Bias 3", inline="bias3", group=biasGroup)
biasMA3 = input.int(defval=24, title="Bias 3 MA Length", inline="bias3", group=biasGroup)

isShowBias4 = input.bool(defval=true, title="Show Bias 4", inline="bias4", group=biasGroup)
biasMA4 = input.int(defval=72, title="Bias 4 MA Length", inline="bias4", group=biasGroup)

extremeOB= input.int(defval=10, title="Extreme Overbought", group=biasGroup)
OB= input.int(defval=5, title="Overbought", group=biasGroup)
OS= input.int(defval=-5, title="Oversold", group=biasGroup)
extremeOS= input.int(defval=-10, title="Extreme Oversold", group=biasGroup)


// ==========================
// ===Divergence Detection===
// ==========================

divergenceGroup = '===Default Bias Divergence Setting==='


lbR = input.int( defval=5, title="Pivot Lookback Right", group=divergenceGroup)
lbL = input(defval=5, title="Pivot Lookback Left", group=divergenceGroup)
rangeUpper = input(defval=100, title="Max of Lookback Range", group=divergenceGroup)
rangeLower = input(defval=5, title="Min of Lookback Range", group=divergenceGroup)
plotBull = input(defval=true, title="Plot Bullish", group=divergenceGroup)
plotHiddenBull = input(defval=true, title="Plot Hidden Bullish", group=divergenceGroup)
plotBear = input(defval=true, title="Plot Bearish", group=divergenceGroup)
plotHiddenBear = input(defval=true, title="Plot Hidden Bearish", group=divergenceGroup)



///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///                 Calculation & Plotting & Alert                 ///
//////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////


// ==========
// ===Bias===
// ==========

defaultBias = ((close - ta.ema(close, defaultBiasMA)) / ta.ema(close, defaultBiasMA)) * 100
bias2 = ((close - ta.ema(close, biasMA2)) / ta.ema(close, biasMA2)) * 100
bias3 = ((close - ta.ema(close, biasMA3)) / ta.ema(close, biasMA3)) * 100
bias4 = ((close - ta.ema(close, biasMA4)) / ta.ema(close, biasMA4)) * 100

plot(defaultBias, title="Default Bias", color=color.blue)
plot(isShowBias2 ? bias2 : na, title="Bias 2", color=color.orange)
plot(isShowBias3 ? bias3 : na, title="Bias 3", color=color.red)
plot(isShowBias4 ? bias4 : na, title="Bias 4", color=color.green)

defaultBiasSell = ta.crossover(defaultBias, OB) 
defaultBiasbuy = ta.crossunder(defaultBias, OS)
bias1Sell = ta.crossover(bias2, OB) 
bias1Buy = ta.crossunder(bias2, OS)
bias2Sell = ta.crossover(bias3, OB)
bias2Buy = ta.crossunder(bias3, OS)

hline(extremeOB, title="Extreme Overbought", color=color.red, linestyle=hline.style_dashed)
hline(OB, title="Overbought", color=color.orange, linestyle=hline.style_dashed)
hline(0, title="Neutral", color=color.gray, linestyle=hline.style_dashed)
hline(OS, title="Oversold", color=color.blue, linestyle=hline.style_dashed)
hline(extremeOS, title="Extreme Oversold", color=color.green, linestyle=hline.style_dashed)


// ==========================
// ===Divergence Detection===
// ==========================

bearColor = color.red
bullColor = color.green
hiddenBullColor = color.blue
hiddenBearColor = color.purple
textColor = color.white
noneColor = color.new(color.white, 100)

plFound = na(ta.pivotlow(defaultBias, lbL, lbR)) ? false : true
phFound = na(ta.pivothigh(defaultBias, lbL, lbR)) ? false : true
_inRange(cond) =>
	bars = ta.barssince(cond == true)
	rangeLower <= bars and bars <= rangeUpper

//------------------------------------------------------------------------------
// Regular Bullish
// defaultBias: Higher Low

defaultBiasHL = defaultBias[lbR] > ta.valuewhen(plFound, defaultBias[lbR], 1) and _inRange(plFound[1])

// Price: Lower Low

priceLL = low[lbR] < ta.valuewhen(plFound, low[lbR], 1)
bullCond = plotBull and priceLL and defaultBiasHL and plFound

plot(
     plFound ? defaultBias[lbR] : na,
     offset=-lbR,
     title="Regular Bullish",
     linewidth=2,
     color=(bullCond ? bullColor : noneColor)
     )

plotshape(
	 bullCond ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Regular Bullish Label",
	 text=" Bull ",
	 style=shape.labelup,
	 location=location.absolute,
	 color=bullColor,
	 textcolor=textColor
	 )

//------------------------------------------------------------------------------
// Hidden Bullish
// defaultBias: Lower Low

defaultBiasLL = defaultBias[lbR] < ta.valuewhen(plFound, defaultBias[lbR], 1) and _inRange(plFound[1])

// Price: Higher Low

priceHL = low[lbR] > ta.valuewhen(plFound, low[lbR], 1)
hiddenBullCond = plotHiddenBull and priceHL and defaultBiasLL and plFound

plot(
	 plFound ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bullish",
	 linewidth=2,
	 color=(hiddenBullCond ? hiddenBullColor : noneColor)
	 )

plotshape(
	 hiddenBullCond ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bullish Label",
	 text=" H Bull ",
	 style=shape.labelup,
	 location=location.absolute,
	 color=hiddenBullColor,
	 textcolor=textColor
	 )

//------------------------------------------------------------------------------
// Regular Bearish
// defaultBias: Lower High

defaultBiasLH = defaultBias[lbR] < ta.valuewhen(phFound, defaultBias[lbR], 1) and _inRange(phFound[1])

// Price: Higher High

priceHH = high[lbR] > ta.valuewhen(phFound, high[lbR], 1)

bearCond = plotBear and priceHH and defaultBiasLH and phFound

plot(
	 phFound ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Regular Bearish",
	 linewidth=2,
	 color=(bearCond ? bearColor : noneColor)
	 )

plotshape(
	 bearCond ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Regular Bearish Label",
	 text=" Bear ",
	 style=shape.labeldown,
	 location=location.absolute,
	 color=bearColor,
	 textcolor=textColor
	 )

//------------------------------------------------------------------------------
// Hidden Bearish
// defaultBias: Higher High

defaultBiasHH = defaultBias[lbR] > ta.valuewhen(phFound, defaultBias[lbR], 1) and _inRange(phFound[1])

// Price: Lower High

priceLH = high[lbR] < ta.valuewhen(phFound, high[lbR], 1)

hiddenBearCond = plotHiddenBear and priceLH and defaultBiasHH and phFound

plot(
	 phFound ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bearish",
	 linewidth=2,
	 color=(hiddenBearCond ? hiddenBearColor : noneColor)
	 )

plotshape(
	 hiddenBearCond ? defaultBias[lbR] : na,
	 offset=-lbR,
	 title="Hidden Bearish Label",
	 text=" H Bear ",
	 style=shape.labeldown,
	 location=location.absolute,
	 color=hiddenBearColor,
	 textcolor=textColor
	 )
