Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rsi divergence #18

Closed
btm2021 opened this issue Jan 2, 2023 · 34 comments
Closed

rsi divergence #18

btm2021 opened this issue Jan 2, 2023 · 34 comments
Labels
enhancement New feature or request

Comments

@btm2021
Copy link

btm2021 commented Jan 2, 2023

hi devs. first thanks your amazing lib.
divergence is important of TA. could you implement to ta.js
example here
https://www.tradingview.com/script/AkWCX6pt-RSI-Divergence-Indicator-w-Alerts/
this is rsi divergence.

thanks for amazing lib.

@Vultwo
Copy link
Member

Vultwo commented Jan 2, 2023

Hi, thank you.
Unfortunately I'm not very good at converting Pine Script code to JavaScript.
I will keep the issue open if anyone wants to decide to help.

@Vultwo Vultwo added enhancement New feature or request help wanted Extra attention is needed labels Jan 2, 2023
@btm2021
Copy link
Author

btm2021 commented Jan 3, 2023

tks for reply.
here is sample about detect diverger
is python :https://github.com/SpiralDevelopment/RSI-divergence-detector
in js : https://github.com/bkawk/divergence

in sample js

To detect the divergence of the relative strength index (RSI) and price in JavaScript, you can use the following steps:

Calculate the RSI values for a given time period, using the following formula:
RSI = 100 - (100 / (1 + (average of up days / average of down days)))

Calculate the price change for the same time period, by subtracting the first closing price from the last closing price.

If the price has increased and the RSI has decreased, or if the price has decreased and the RSI has increased, then there is a divergence between the RSI and price.

Here's some example code that demonstrates these steps:

Copy code
function detectDivergence(prices, timePeriod) {
// Calculate the RSI values
let upDays = 0;
let downDays = 0;
for (let i = 1; i < timePeriod; i++) {
let priceChange = prices[i] - prices[i - 1];
if (priceChange > 0) {
upDays += priceChange;
} else {
downDays -= priceChange;
}
}
let avgUpDays = upDays / timePeriod;
let avgDownDays = downDays / timePeriod;
let rs = avgUpDays / avgDownDays;
let rsi = 100 - (100 / (1 + rs));

// Calculate the price change
let priceChange = prices[timePeriod - 1] - prices[0];

// Check for divergence
if ((priceChange > 0 && rsi < 0) || (priceChange < 0 && rsi > 0)) {
console.log("There is a divergence between the RSI and price");
} else {
console.log("There is no divergence between the RSI and price");
}
}

let prices = [100, 105, 110, 100, 95, 105];
detectDivergence(prices, 3); // There is no divergence between the RSI and price

here is javascript convert of pinescript
function rsiDivergenceIndicator(data, len, src, lbR, lbL, rangeUpper, rangeLower, plotBull, plotHiddenBull, plotBear, plotHiddenBear) {
const osc = rsi(src, len);
const obLevel = hline(70);
const osLevel = hline(30);
const plFound = pivotlow(osc, lbL, lbR);
const phFound = pivothigh(osc, lbL, lbR);
const _inRange = (cond) => {
const bars = barssince(cond === true);
return rangeLower <= bars && bars <= rangeUpper;
}

// Regular Bullish
const oscHL = osc[lbR] > valuewhen(plFound, osc[lbR], 1) && _inRange(plFound[1]);
const priceLL = low[lbR] < valuewhen(plFound, low[lbR], 1);
const bullCond = plotBull && priceLL && oscHL && plFound;

// Hidden Bullish
const oscLL = osc[lbR] < valuewhen(plFound, osc[lbR], 1) && _inRange(plFound[1]);
const priceHL = low[lbR] > valuewhen(plFound, low[lbR], 1);
const hiddenBullCond = plotHiddenBull && priceHL && oscLL && plFound;

// Regular Bearish
const oscLH = osc[lbR] < valuewhen(phFound, osc[lbR], 1) && _inRange(phFound[1]);
const priceHH = high[lbR] > valuewhen(phFound, high[lbR], 1);
const bearCond = plotBear && priceHH && oscLH && phFound;

// Hidden Bearish
const oscHH = osc[lbR] > valuewhen(phFound, osc[lbR], 1) && _inRange(phFound[1]);
const priceLH = high[lbR] < valuewhen(phFound, high[lbR], 1);
const hiddenBearCond = plotHiddenBear && priceLH && oscHH && phFound;

please consider add to your lib. tks so much.

@Vultwo
Copy link
Member

Vultwo commented Jan 8, 2023

Thanks for the code, I'll try to add this as soon as possible.
I hope to have a updated version of the library online by next week.

@btm2021
Copy link
Author

btm2021 commented Jan 9, 2023

if lib have divengencer it is big move.
tks so much.

@Vultwo
Copy link
Member

Vultwo commented Jan 12, 2023

Hi, I have uploaded a new version.
Could you check if it actually does what you need it to do.
I couldn't figure out what these values meant:

// Regular Bullish
const oscHL = osc[lbR] > valuewhen(plFound, osc[lbR], 1) && _inRange(plFound[1]);
const priceLL = low[lbR] < valuewhen(plFound, low[lbR], 1);
const bullCond = plotBull && priceLL && oscHL && plFound;

// Hidden Bullish
const oscLL = osc[lbR] < valuewhen(plFound, osc[lbR], 1) && _inRange(plFound[1]);
const priceHL = low[lbR] > valuewhen(plFound, low[lbR], 1);
const hiddenBullCond = plotHiddenBull && priceHL && oscLL && plFound;

// Regular Bearish
const oscLH = osc[lbR] < valuewhen(phFound, osc[lbR], 1) && _inRange(phFound[1]);
const priceHH = high[lbR] > valuewhen(phFound, high[lbR], 1);
const bearCond = plotBear && priceHH && oscLH && phFound;

// Hidden Bearish
const oscHH = osc[lbR] > valuewhen(phFound, osc[lbR], 1) && _inRange(phFound[1]);
const priceLH = high[lbR] < valuewhen(phFound, high[lbR], 1);
const hiddenBearCond = plotHiddenBear && priceLH && oscHH && phFound;

@Vultwo
Copy link
Member

Vultwo commented Jan 12, 2023

RSI Divergence (from docs)

var data = [74,83,66,78,69,70,84,73,74,73,83];
var rsi_length = 5;
var rsi_function = ta.wrsi; // default (the tradingview rsi indicator)
await ta.rsi_divergence(data, rsi_length, rsi_function);
// output (array)
// [0, 0, 1, 0, 1, 0] (better to quantify if needed)

Code:

async function rsi_divergence(data, length, rs) {
  if(!rs) rs = module.exports.wrsi;
  var rd = await rs(data, length), out = [];
  data = await module.exports.mom(data.slice(length-1, data.length), 2);
  for(var i = 0; i < data.length; i++) {
    if((data[i] > 0 && rd[i] < 0) || (data[i] < 0 && rd[i] > 0)) {
      out.push(1);
    } else {
      out.push(0);
    }
  }
  return out;
}

@btm2021
Copy link
Author

btm2021 commented Jan 15, 2023

Screen Shot 2023-01-15 at 7 28 16 PM

Screen Shot 2023-01-15 at 7 28 39 PM

work like a charm. tks so much. good job men.

@btm2021 btm2021 closed this as completed Jan 15, 2023
@phattranky
Copy link

Hi @btm2021 ,

Could you share your code how do you map the 0 1 in the result to the price position as the above screenshot. Thanks

@phattranky
Copy link

Let's say I have the result is

[0,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,1,0]

How can I know which point is the start point and endpoint to draw the line ?

@Vultwo
Copy link
Member

Vultwo commented Jan 28, 2023

Let's say I have the result is

[0,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,1,0,0,1,0,1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,1,0,1,0,1,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,1,0]

How can I know which point is the start point and endpoint to draw the line ?

@phattranky I'm not really sure how he maps the values in the array, my best guess is he just loops over it using a for loop.
The index zero of the output is the first value (oldest data point).
So you should splice the first values from the original data before putting them into the array.

@phattranky
Copy link

Thanks @Vultwo

As I know, There are 6 kinds of Divergence. I mean with your function How can we detect it?

diverCapture

As your example

var data = [74,83,66,78,69,70,84,73,74,73,83];
var rsi_length = 5;
var rsi_function = ta.wrsi; // default (the tradingview rsi indicator)
await ta.rsi_divergence(data, rsi_length, rsi_function);
// output (array)
// [0, 0, 1, 0, 1, 0] (better to quantify if needed)

How can We know the divergence is bear or bull and which Candles (closed price) are connected become a line ?

@btm2021 in case you can help.

Thanks a lot

@phattranky
Copy link

Here is the code of TradingView, But I don't how to convert it to Javascript

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © JayTradingCharts

//@version=4
//@version=4  
//---- thank to mohanee for the base code. we modified this to not give entries but instead alert on the just the divs 
study(title="RSI Divergence Indicator w/Alerts", 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
	 )
	 
	 

alertcondition(bullCond, title="Bull", message="Regular Bull Div {{ticker}} XXmin")
alertcondition(bearCond, title="Bear", message="Regular Bear Div {{ticker}} XXmin")
alertcondition(hiddenBullCond, title="H Bull", message="Hidden Bull Div {{ticker}} XXmin")
alertcondition(hiddenBearCond, title="H Bear", message="Hidden Bear Div {{ticker}} XXmin")

@Vultwo
Copy link
Member

Vultwo commented Jan 29, 2023

@phattranky The code seems to make use of pivot points to determine wether the current state is in regular or hidden.
This library also contains a function for calculating these pivot points (fractals or zigzag).
You could calculate the current state by determining wether the pivot points of the rsi and price are also diverging.
I will create a function for this, but I don't know when it's ready.

As I know, There are 6 kinds of Divergence. I mean with your function How can we detect it?

diverCapture

@Vultwo Vultwo reopened this Jan 29, 2023
@Vultwo Vultwo removed the help wanted Extra attention is needed label Jan 29, 2023
@phattranky
Copy link

@Vultwo Thanks bro. Hope We can have it soon. It must a great function.

@btm2021
Copy link
Author

btm2021 commented Feb 9, 2023

hello all, sorry because i in my holiday.
@phattranky i just get result and compare with timestamp of ohvcl.
in my picture is tradingview library. you can get here https://www.tradingview.com/HTML5-stock-forex-bitcoin-charting-library/?feature=technical-analysis-charts.
get result of scan and format to right timestamp and use tradingview lib mark this scan.
it not thing else.

@btm2021
Copy link
Author

btm2021 commented Feb 9, 2023

important when check div is use right point. example. u can use pivot of ta.js and detect important zone of price and important zone of rsi and use function div to check.
hidden div i think not useful because it not right, hidden div just simple lag of price or bigboy make market move. if you use hidden div it very noise. just check div regular. and make your choice.

@btm2021
Copy link
Author

btm2021 commented Feb 9, 2023

and important. div is technical like rsi or bb. you should combine more signal to confirm your signal.

@btm2021
Copy link
Author

btm2021 commented Feb 9, 2023

here my function got result and compare with ohcvl
function arrangeResult(result, length) {
for (i = 0; i < length - 1; i++) {
result.unshift(0)
}
return result;
}
example ema.
let result = await ta.ema(data, period);
result = arrangeResult(result, period);
because nodejs not pandas like python. use this func and put together.

@btm2021
Copy link
Author

btm2021 commented Feb 9, 2023

@Vultwo, i have write some function check swing high and swing low. and some func. utils. can you add to your lib ?

@phattranky
Copy link

Thanks @btm2021 ,

Instead of drawing on the chart, can we detect it on the code side? My idea is to create a bot that scans all the candle values in a period of time and notify to the user when they detect any divergence.

The result expected may be like

BTC has the regular bear closed on 15:00 - 1H

@btm2021
Copy link
Author

btm2021 commented Feb 10, 2023

@phattranky hi, sorry i just write frond-end ui, grap data and show to chart, your idead seem interesting but i don't know how to write for that. sorry man

@phattranky
Copy link

Thanks @btm2021 . Yes scanning all the coins at the background is more effective than We have to check the UI one by one =))

@Vultwo
Copy link
Member

Vultwo commented Feb 12, 2023

@Vultwo, i have write some function check swing high and swing low. and some func. utils. can you add to your lib ?

Is this different from the zigzag and fractal indicators that are already in the library? All functions are welcome if you're willing to share them.

@btm2021
Copy link
Author

btm2021 commented Feb 13, 2023

oh, i checked, it calc base high low and high swing and your zigzag do the same. my bad.

@Vultwo
Copy link
Member

Vultwo commented Mar 24, 2023

Sorry for the long wait @phattranky I'm still developing the function. The function won't be perfect though. The divergence can be in multiple states at once. The historical signal values of the function also wouldn't be perfect as the states can changes as more data is coming in. I'm finishing the function over the weekend.

@Vultwo
Copy link
Member

Vultwo commented Mar 27, 2023

I have finished the function. It would be appreciated if someone could check the function for correctness. Beware this function can 'repaint' as new data comes available. The function is by no means perfect, that's why I have put it in the experimental section.

var data1 = [48,34,43,54,56,64,43,51,52,53,55,51,48,45,40,42,44,45];
var data2 = [76,74,43,55,34,32,45,47,48,53,54,54,50,52,49,47,48,46];
var length = 12; // array length to check
var lookback = 3; // lookback length to check for recent_low / recent_high (please check function code for more info)
var threshold_exaggerated = 0.03; // percentual change threshold for 'exaggerated' divergence
var threshold_normal = 0.01; // percentual change threshold for 'normal' and 'hidden' divergence
ta.divergence_state(data1, data2, length, lookback, threshold_exaggerated, threshold_normal);
// output (array of arrays)
// [['convergence'],['divergence'],['convergence'],['divergence'],['convergence'],['exaggerated_bearish']]
// it is possible for multiple states to exist at once
function divergence_state(data1, data2, length, lb, threshold_ex=0.03, threshold_nm=0.01) { // [close]
  if(data1.length > data2.length) data1.splice(0,data1.length-data2.length);
  if(data2.length > data1.length) data2.splice(0,data2.length-data1.length);
  for(var i = length, out = []; i < data1.length; i++) {
    var pl1 = data1.slice(i-length,i+1);
    var support1 = support(pl1, recent_low(pl1, lb));
    var support1_delta = support1.slope / support1.lowest;
    var resistance1 = resistance(pl1, recent_high(pl1, lb));
    var resistance1_delta = resistance1.slope / resistance1.highest;
    var pl2 = data2.slice(i-length,i+1);
    var support2 = support(pl2, recent_low(pl2, lb));
    var support2_delta = support2.slope / support2.lowest;
    var resistance2 = resistance(pl2, recent_high(pl2, lb));
    var resistance2_delta = resistance2.slope / resistance2.highest;
    if((data1[i] > data1[i-1] && data2[i] < data2[i-1]) || (data1[i] < data1[i-1] && data2[i] > data2[i-1])) {
      var obj = [];
      if(resistance1_delta < -threshold_ex && resistance2_delta > -threshold_nm) obj.push('exaggerated_bearish');
      if(support1_delta < threshold_nm && support2_delta > threshold_ex) obj.push('exaggerated_bullish');
      if(resistance1_delta < -threshold_nm && resistance2_delta < threshold_nm) obj.push('hidden_bearish');
      if(support1_delta > threshold_nm && support2_delta < -threshold_nm) obj.push('hidden_bullish');
      if(resistance1_delta > threshold_nm && resistance2_delta < -threshold_nm) obj.push('regular_bearish');
      if(support1_delta < -threshold_nm && support2_delta > threshold_nm) obj.push('regular_bullish');
      if(obj.length <= 0) obj.push('divergence')
      out.push(obj);
    } else {
      out.push(['convergence'])
    }
  }
  return out;
}

Please let me know if you require any changes or if something isn't working as expected.

@phattranky
Copy link

Great. Thanks a lot, @Vultwo . I will check and get back to you later

@phattranky
Copy link

Hi @Vultwo

I have some questions, Could you help me to clarify?

  1. The data1 and data2 are the closed price values and RSI values, right?
  2. The convergence is meaning the normal state, right?
  3. If the question 2 is correct. Could you identify the bearish and bullish divergence like the exaggerated_bearish and exaggerated_bullish?

Thanks.

@phattranky
Copy link

About the data for testing. You can use the below API

https://fapi.binance.com/fapi/v1/continuousKlines?pair=ADAUSDT&contractType=PERPETUAL&interval=1h&startTime=1679436000000&endTime=1679612400000

And use the indicator Rsi diverence with Alert to backtest

2ADAUSDTPERP 0 3870 ▲ +5 19% Vô danh 2023-03-29 18-03-33
9999ADAUSDTPERP 0 3863 ▲ +5% Vô danh 2023-03-29 18-02-16

@Vultwo
Copy link
Member

Vultwo commented Mar 29, 2023

Hi @phattranky,

  1. Yes.
  2. Convergence is the state when no divergence takes place.
  3. The outputted states are: "exaggerated_bearish", "exaggerated_bullish", "hidden_bearish", "hidden_bullish", "regular_bearish", "regular_bullish". When none of these states is found (according to the threshold values for exaggerated / regular) the value outputted will be "divergence".

The problem with the trading view indicator is that the states only become known after the data has past. It is hard to predict the state as the data is coming in as it easily changes the state.

@phattranky
Copy link

Thanks @Vultwo

I will check again. Because I'm confusing the state of your example. I see it is

// output (array of arrays)
// [['convergence'],['divergence'],['convergence'],['divergence'],['convergence'],['exaggerated_bearish']]

So I thought those are the state values.

@phattranky
Copy link

Hi @Vultwo

I wrote an example code here https://github.com/phattranky/ta-rsi-divergence-example/blob/main/index.js

Could you help me to check why it doesn't have any divergence? Any wrong with my configuration?
I found some divergence in that range on the Chart.

You can try to change the pair and startTime endTime on my code for back testing.

5555LINKUSDTPERP 7 401 ▲ +6 57% Vô danh 2023-03-30 04-52-34
44444index js — ta-rsi-divergence-example 2023-03-30 04-50-08

@Vultwo
Copy link
Member

Vultwo commented Mar 30, 2023

Hi @phattranky,

I have updated the readme to be more clear. The outputted values are just of the example values.

I have sent you a pull request on your test example with a working example.
I have added a smoother function to compare for divergence further back than the previous value.

@phattranky
Copy link

Thanks @Vultwo .

You're so nice. Seems it's working. Let's me test more and get back to you later

@Vultwo Vultwo closed this as completed May 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants