DaveSkender / Stock.Indicators

Stock Indicators for .NET is a C# NuGet package that transforms raw equity, commodity, forex, or cryptocurrency financial market price quotes into technical indicators and trading insights. You'll need this essential data in the investment tools that you're building for algorithmic trading, technical analysis, machine learning, or visual charting.
https://dotnet.StockIndicators.dev
Apache License 2.0
964 stars 239 forks source link

RSI Divergence Indicator #434

Closed moslem7026 closed 2 years ago

moslem7026 commented 3 years ago

An RSI divergence indicator signal shows traders when price action and the RSI are no longer showing the same momentum. ... When RSI stops breaking out to higher highs during an uptrend in price or breaking down to lower lows when price is in a down trend then it is said to be an RSI divergence. Screenshot_20210514-054029~2

moslem7026 commented 3 years ago

Sample Code in Pine Script(Trading View) : `

//@version=4
study(title="Divergence Indicator", format=format.price, resolution="")
len = input(title="RSI Period", minval=1, defval=14)
src = input(title="RSI Source", defval=close)
lbR = input(title="Pivot Lookback Right", defval=5)
lbL = input(title="Pivot Lookback Left", defval=5)
rangeUpper = input(title="Max of Lookback Range", defval=60)
rangeLower = input(title="Min of Lookback Range", defval=5)
plotBull = input(title="Plot Bullish", defval=true)
plotHiddenBull = input(title="Plot Hidden Bullish", defval=false)
plotBear = input(title="Plot Bearish", defval=true)
plotHiddenBear = input(title="Plot Hidden Bearish", defval=false)
bearColor = color.red
bullColor = color.green
hiddenBullColor = color.new(color.green, 80)
hiddenBearColor = color.new(color.red, 80)
textColor = color.white
noneColor = color.new(color.white, 100)
osc = rsi(src, len)

plot(osc, title="RSI", linewidth=2, color=#8D1699)
hline(50, title="Middle Line", linestyle=hline.style_dotted)
obLevel = hline(70, title="Overbought", linestyle=hline.style_dotted)
osLevel = hline(30, title="Oversold", linestyle=hline.style_dotted)
fill(obLevel, osLevel, title="Background", color=#9915FF, transp=90)

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

//------------------------------------------------------------------------------
// Regular Bullish
// Osc: Higher Low

oscHL = osc[lbR] > valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])

// Price: Lower Low

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

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

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

//------------------------------------------------------------------------------
// Hidden Bullish
// Osc: Lower Low

oscLL = osc[lbR] < valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])

// Price: Higher Low

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

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

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

//------------------------------------------------------------------------------
// Regular Bearish
// Osc: Lower High

oscLH = osc[lbR] < valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])

// Price: Higher High

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

bearCond = plotBear and priceHH and oscLH and phFound

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

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

//------------------------------------------------------------------------------
// Hidden Bearish
// Osc: Higher High

oscHH = osc[lbR] > valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])

// Price: Lower High

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

hiddenBearCond = plotHiddenBear and priceLH and oscHH and phFound

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

plotshape(
     hiddenBearCond ? osc[lbR] : na,
     offset=-lbR,
     title="Hidden Bearish Label",
     text=" H Bear ",
     style=shape.labeldown,
     location=location.absolute,
     color=bearColor,
     textcolor=textColor,
     transp=0
DaveSkender commented 3 years ago

I’ll take a look this weekend. Thanks for sharing. If you have any other public domain sources of information, please share.

Some general info divergence:

codebeaulieu commented 3 years ago

+1 on this

DaveSkender commented 3 years ago

I'm not finding a lot of great formulas out there for this one, so I might have to use some creative license. I typically like to have a reputable source for these calculations.

@moslem7026 the script you provided identifies the highs and lows with an unspecified formula. I suspect this is something like a Fractal given the windowed look forward and backward approach.

phFound = na(pivothigh(osc, lbL, lbR)) ? false : true

I think I know how to do it, but it may not match 100% with other providers.

moslem7026 commented 3 years ago

this function is built-in in trading View, some resource i have found : Stack OverFlow Youtube and Official Docs

moslem7026 commented 3 years ago

i see that using Pivot is not necessary , here is more simple : https://www.babypips.com/learn/forex/divergence-cheat-sheet i think that Pivotes Make solution very complex

DaveSkender commented 3 years ago

I see that "divergence" can be done with several oscillators: RSI, Stoch, CCI, Williams %R, etc. I think what I'll do here is make a GetRsiExtended method, specifically for RSI, but write it in a way that we can easily extend in the others in future mods.

For the general approach, I think this is always going to be a "hindsight" lagging indicator since you can't identify new low or high points without confirming with additional bars after the HH/LL. The drawn chart lines are also retroactively identified, so on X date, X may not be indicated, but on X+5, X might be indicated (repainting).

Parameters:

Returns:

DaveSkender commented 3 years ago

A lot of these methods seem to use this Higher-High vs Lower-High model. I'm starting to think that this might be simpler to compute by comparing slope values between Price and Oscillator. Most Divergence descriptions are based on old-school hand drawings on charts; it's not clear to me that using an algorithm to identify a specific peak to peak would make much of a difference.

I'll keep working on this peak-to-peak approach, but am thinking of alternatives along the way. Thoughts?

moslem7026 commented 3 years ago

Yes , exactly right Divergence can be done on any oscillators , it check HH ,LL, HL,LH On Prices and oscillators output. for some indicators that have more than one output(Rsi has One Out Put , but Stoch Has two) it should be choose that divergence should check with which output.

an indicator that i have found in Trading View is "Divergence Indicator (any oscillator)" ,

// A modification of the TV builtin "Diverence indicator" (Version 10) that can be applied to any indicator, and can be plotted on price as well. // Usage: // Add your favorite oscilator, klinger, tsi, whatever to a chart. // Click the little ... (More) // Then add this indicator "Divergence Indicator (any oscillator)" on your oscillator of choice. // Click the settings on this indicator and make sure the source is set to the right plot from your oscillator. // Watch for it to plot divergences... // Add it a second time on the price chart (and select the same indicator), but check the box "plot on price (rather than on indicator)"" // See you divergence plotted on price and on indicator

DaveSkender commented 3 years ago

I wonder if we should just have a basic public indicator method to identify all of the HH,LL,HL,LH as a regular Price overlay, and then just use it in a more advanced way to do the Oscillator overlays and then match it up to the Price overlays where they overlap and diverge? This may end up falling into a broad category of candlestick patterns.

codebeaulieu commented 3 years ago

I feel like ZigZag is already doing some of this work internally.

DaveSkender commented 3 years ago

I feel like ZigZag is already doing some of this work internally.

It does, sorta. I'm stuck between using ZigZag and Fractal; both would require further analysis to determine relative height of subsequent points. Both are also forward looking repainters, so they can only plot retroactively (you'd never get a current last day signal).

image

ZigZag relies on a certain percent change threshold, which may miss some of these trends, and Fractal produces too many points or requires a confirmation span. Not sure. Still trying to figure it out.

DaveSkender commented 3 years ago

It’s not immediately obvious to me how to put this into code. Anyone want to take a try at it? I’ve started writing it based on Fractal, see #449 for progress so far.

didaskein commented 3 years ago

@DaveSkender , If it can help some code in pine in order to detect div and hidden div : https://www.tradingview.com/script/zVCxHlgL-TMA-Divergence-Indicator/

DaveSkender commented 3 years ago

Thanks @didaskein, this is helpful. It's similar to what @moslem7026 shared previously. I suspect the mysterious pivothigh and pivotlow methods shown in that TradingView code works like a Williams Fractal, but am not sure.

I think using Fractal and then some sort of user-specified lookback window to constrain the point-pairing analysis will work.

Part of the challenge here is this is more of a subjective (opinionated) visual analysis than a scientific formula, so I'm trying to build in all those parameters so users aren't forced into a limited viewpoint. I'm also thinking about how to abstract this method too, so we can more easily re-apply it to other indicators.

This one is pretty close to the threshold where I'd probably not include it in the library. I only say that because I try to stick to formulas from reputable sources and tend to avoid analysis beyond the base indicators. With that said, I think this one follows a reputable concept of divergence, so it's worth exploring.

didaskein commented 3 years ago

There is not much information indeed :( https://www.tradingview.com/pine-script-reference/#fun_pivothigh

It would be great to have the divergence calculation on RSI, Smooth RSI and Momentum in the library like this script does: https://www.tradingview.com/script/7mYAGmYK-TMA-Divergence-Indicator/

image

image

DaveSkender commented 3 years ago

I set this aside for a while to ponder how to implement it. I think I've come to the conclusion that this is really multiple enabling methods that can then be used to create price/oscillator combos.

  1. I'm creating a GetPivots(leftSpan,rightSpan,minTrendPeriods,endType) method, based on Williams Fractal, that just takes quotes and identifies the HH,LH,HL,LL connections. I think this can be a standalone indicator. It looks something like this:

    image

2) Then will create GetDivergence(this pricePivots,oscPivots) that will evaluate basically what @didaskein is showing in the previous comment; where pricePivots and oscPivots are two results from GetPivots.

Instead of creating a specific RSI Divergence indicator, I think this way will enable the whole universe of combinations. The thought of creating all permutations separately seems myopic, from a long-term implementation standpoint.

We can probably then create a few popular divergence indicators; however, there will be the flexibility for users to do whatever combinations they want, like this:

var pricePivots = quotes.GetPivots(..);

var rsiPivots = quotes.GetRsi(..)
  .ConvertToQuotes()
  .GetPivots(..);

var rsiDivergence = pricePivots
  .GetDivergence(rsiPivots);
DaveSkender commented 3 years ago

One of the challenges I'm having with this concept is that it appears to have a large amount of both contradictory information and false positives. I like the theory behind this one, but I'm not 100% sure this can be computed in a useful or realistic manner. I'm a bit skeptical about it. Maybe I'm just not using the right parameter arguments. What has your experience been with these divergence indicators in other platforms?

image

DaveSkender commented 3 years ago

I have a sneaking suspicion that this might work well with a larger pivot span, but at that point, all you're doing is repainting old history. A late indicator probably doesn't have much value, right?

Salardx commented 2 years ago

Is there any expectation on when this feature is gonna get ready?

DaveSkender commented 2 years ago

I'm not sure. I haven't completely given up on it. I have it "on hold" and made it a lower priority because I'm not certain this indicator meets my sniff test -- meaning, I'm not sure it is good enough to include in the library. With my current approach, I'm not seeing a good correlation between what the indicator is saying vs what the price trend is doing. It seems almost random. If anyone wants to help, to make this usable, please do.

DaveSkender commented 2 years ago

Despite being an interesting concept, given its quirkiness, unclear fit in the library, and many other higher priority opportunities to explore, I’m taking this one out of the backlog.

DaveSkender commented 1 year ago

See #946 for continued discussion and alternate methods