Triangular Momentum Oscillator & Real Time Divergences

https://www.tradingview.com/script/0XxPH6A2-Triangular-Momentum-Oscillator-Real-Time-Divergences/

Oscillators are widely used in technical analysis and can return a large amount of information to the trader depending on their design. It is common to use oscillators to detect divergences with the price, divergences occur when the tops/bottoms made by the oscillator and price are negatively correlated. The following oscillator is based on the momentum of a triangular moving average, hence the name "triangular momentum" because of the very smooth property of the triangular moving average, we aimed at a real-time detection of divergences instead of using more common methods such as relying on pivot high/low detection which are suitable for more noisy oscillators. The oscillator can also be colored based on a gradient derived from the correlation between its output and the price which can be useful to detect when the oscillator is out of phase (significantly lagging or leading the price).

Settings

  • Length: Period of the oscillator, higher values return a smoother output.

  • Src : Source input of the indicator

  • Show Lines: Show lines connecting the current top/bottom with the previous one made by the oscillator when a divergence is detected. True by default.

  • Color Based On Price/Oscillator Correlation: Allows the color of the oscillator to change based on its correlation with the price, with red colors suggesting a negative correlation.

Usage

The advantage of having a smoother oscillator for divergences detection is that it can be done in real-time since a top or bottom is present when the oscillator first difference cross 0. Smoother oscillators are also easier to interpret, however, they will still suffer from lag.

The divergences detected by the oscillator are regular divergences, where the oscillator leads price variations.

Using higher values of length allows the oscillator to filter out longer-term variations thus being smoother as a result.

By using the color mode based on the price/oscillator correlation we can see where the oscillator leads or lag the price, and since divergences are based on the price and oscillator going in the opposite direction we can have information where price might reverse.

It is also possible to interpret the oscillator without relying on the divergence detection, with a decreasing value of the oscillator indicating a downtrend and an increasing value indicating an uptrend.

Code

// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=4
study("Triangular Momentum Oscillator & Real Time Divergences","TMO")
length = input(14)
src = input(close)
show_lines = input(true,"Show Lines")
colcor = input(false,"Color Based On Price/Oscillator Correlation")
//----
var css = array.new_color(na)
if barstate.isfirst
array.push(css,#FF1100), array.push(css,#FF1200), array.push(css,#FF1400), array.push(css,#FF1500), array.push(css,#FF1700), array.push(css,#FF1800), array.push(css,#FF1A00), array.push(css,#FF1B00), array.push(css,#FF1D00), array.push(css,#FF1F00), array.push(css,#FF2000), array.push(css,#FF2200), array.push(css,#FF2300), array.push(css,#FF2500), array.push(css,#FF2600), array.push(css,#FF2800), array.push(css,#FF2900), array.push(css,#FF2B00), array.push(css,#FF2D00), array.push(css,#FF2E00), array.push(css,#FF3000), array.push(css,#FF3100), array.push(css,#FF3300), array.push(css,#FF3400), array.push(css,#FF3600), array.push(css,#FF3700), array.push(css,#FF3900), array.push(css,#FF3B00), array.push(css,#FF3C00), array.push(css,#FF3E00), array.push(css,#FF3F00), array.push(css,#FF4100), array.push(css,#FF4200), array.push(css,#FF4400), array.push(css,#FF4500), array.push(css,#FF4700), array.push(css,#FF4900), array.push(css,#FF4A00), array.push(css,#FF4C00), array.push(css,#FF4D00), array.push(css,#FF4F00), array.push(css,#FF5000), array.push(css,#FF5200), array.push(css,#FF5300), array.push(css,#FF5500), array.push(css,#FF5700), array.push(css,#FF5800), array.push(css,#FF5A00), array.push(css,#FF5B00), array.push(css,#FF5D00), array.push(css,#FF5E00), array.push(css,#FF6000), array.push(css,#FF6200), array.push(css,#FF6300), array.push(css,#FF6500), array.push(css,#FF6600), array.push(css,#FF6800), array.push(css,#FF6900), array.push(css,#FF6B00), array.push(css,#FF6C00), array.push(css,#FF6E00), array.push(css,#FF7000), array.push(css,#FF7100), array.push(css,#FF7300), array.push(css,#FF7400), array.push(css,#FF7600), array.push(css,#FF7700), array.push(css,#FF7900), array.push(css,#FF7A00), array.push(css,#FF7C00), array.push(css,#FF7E00), array.push(css,#FF7F00), array.push(css,#FF8100), array.push(css,#FF8200), array.push(css,#FF8400), array.push(css,#FF8500), array.push(css,#FF8700), array.push(css,#FF8800), array.push(css,#FF8A00), array.push(css,#FF8C00), array.push(css,#FF8D00), array.push(css,#FF8F00), array.push(css,#FF9000), array.push(css,#FF9200), array.push(css,#FF9300), array.push(css,#FF9500), array.push(css,#FF9600), array.push(css,#FF9800), array.push(css,#FF9A00), array.push(css,#FF9B00), array.push(css,#FF9D00), array.push(css,#FF9E00), array.push(css,#FFA000), array.push(css,#FFA100), array.push(css,#FFA300), array.push(css,#FFA400), array.push(css,#FFA600), array.push(css,#FFA800), array.push(css,#FFA900), array.push(css,#FFAB00), array.push(css,#FDAC00), array.push(css,#FBAD02), array.push(css,#F9AE03), array.push(css,#F7AE04), array.push(css,#F5AF06), array.push(css,#F3B007), array.push(css,#F1B108), array.push(css,#EFB20A), array.push(css,#EDB30B), array.push(css,#EBB30C), array.push(css,#E9B40E), array.push(css,#E7B50F), array.push(css,#E4B610), array.push(css,#E2B712), array.push(css,#E0B813), array.push(css,#DEB814), array.push(css,#DCB916), array.push(css,#DABA17), array.push(css,#D8BB18), array.push(css,#D6BC1A), array.push(css,#D4BD1B), array.push(css,#D2BD1C), array.push(css,#D0BE1E), array.push(css,#CEBF1F), array.push(css,#CCC020), array.push(css,#C9C122), array.push(css,#C7C223), array.push(css,#C5C224), array.push(css,#C3C326), array.push(css,#C1C427), array.push(css,#BFC528), array.push(css,#BDC62A), array.push(css,#BBC72B), array.push(css,#B9C72C), array.push(css,#B7C82E), array.push(css,#B5C92F), array.push(css,#B3CA30), array.push(css,#B0CB32), array.push(css,#AECC33), array.push(css,#ACCC34), array.push(css,#AACD36), array.push(css,#A8CE37), array.push(css,#A6CF38), array.push(css,#A4D03A), array.push(css,#A2D13B), array.push(css,#A0D13C), array.push(css,#9ED23E), array.push(css,#9CD33F), array.push(css,#9AD440), array.push(css,#98D542), array.push(css,#95D643), array.push(css,#93D644), array.push(css,#91D746), array.push(css,#8FD847), array.push(css,#8DD948), array.push(css,#8BDA4A), array.push(css,#89DB4B), array.push(css,#87DB4C), array.push(css,#85DC4E), array.push(css,#83DD4F), array.push(css,#81DE50), array.push(css,#7FDF52), array.push(css,#7CE053), array.push(css,#7AE054), array.push(css,#78E156), array.push(css,#76E257), array.push(css,#74E358), array.push(css,#72E45A), array.push(css,#70E55B), array.push(css,#6EE55C), array.push(css,#6CE65E), array.push(css,#6AE75F), array.push(css,#68E860), array.push(css,#66E962), array.push(css,#64EA63), array.push(css,#61EA64), array.push(css,#5FEB66), array.push(css,#5DEC67), array.push(css,#5BED68), array.push(css,#59EE6A), array.push(css,#57EF6B), array.push(css,#55EF6C), array.push(css,#53F06E), array.push(css,#51F16F), array.push(css,#4FF270), array.push(css,#4DF372), array.push(css,#4BF473), array.push(css,#48F474), array.push(css,#46F576), array.push(css,#44F677), array.push(css,#42F778), array.push(css,#40F87A), array.push(css,#3EF97B), array.push(css,#3CF97C), array.push(css,#3AFA7E), array.push(css,#38FB7F), array.push(css,#36FC80), array.push(css,#34FD82), array.push(css,#32FE83), array.push(css,#30FF85),
//----
up = highest(src,length)
dn = lowest(src,length)
osc = mom(sma(sma(src,length),length),length)
phosc = crossunder(change(osc),0)
plosc = crossover(change(osc),0)
bear = osc > 0 and phosc and valuewhen(phosc,osc,0) < valuewhen(phosc,osc,1)
and valuewhen(phosc,up,0) > valuewhen(phosc,up,1) ? 1 : 0
bull = osc < 0 and plosc and valuewhen(plosc,osc,0) > valuewhen(plosc,osc,1)
and valuewhen(plosc,dn,0) < valuewhen(plosc,dn,1) ? 1 : 0
//----
simple_css = osc > osc[1] and osc > 0 ? #00c42b : osc < osc[1] and osc > 0 ? #4ee567 :
osc < osc[1] and osc < 0 ? #ff441f : osc > osc[1] and osc < 0 ? #c03920 : na
cor_css = array.get(css,round((.5*correlation(osc,close,length)+.5)*199))
plot(osc,"Osc",colcor ? cor_css : simple_css,3,plot.style_histogram)
plotshape(iff(bull,osc,na),"Bullish Circle",shape.circle,location.absolute,#00c42b,0,size=size.tiny)
plotshape(iff(bear,osc,na),"Bearish Circle",shape.circle,location.absolute,#ff441f,0,size=size.tiny)
plotshape(iff(bull,osc,na),"Bullish Label",shape.labelup,location.absolute,#00c42b,0,text="Buy",textcolor=color.white,size=size.tiny)
plotshape(iff(bear,osc,na),"Bearish Label",shape.labeldown,location.absolute,#ff441f,0,text="Sell",textcolor=color.white,size=size.tiny)
//----
n = bar_index
bull_x1 = valuewhen(plosc,n,1),bull_y1 = valuewhen(plosc,osc,1)
bear_x1 = valuewhen(phosc,n,1),bear_y1 = valuewhen(phosc,osc,1)
var line bull_line = na,var line bear_line = na
if show_lines
if bull
bull_line := line.new(bull_x1,bull_y1,n,osc,color=#00c42b)
else if bear
bear_line := line.new(bear_x1,bear_y1,n,osc,color=#ff441f)