'How to recreate the exact RSI calculation from tradingview in java?
I have read every related post on stackoverflow but i just still cant seem to replicate the exact same RSI calculation that tradingview uses. I've spend over dozens of hours trying to get this right. At this point it is really sucking the joy out of my hobby project. Any help would be greatly appreciated.
If any other info or something is required please let me know and i will add it.
What the tradingview documentation says about how the calculation is done:
* For a practical example, the built-in Pine Script function rsi(), could be replicated in long form as follows.
* change = change(close)
* gain = change >= 0 ? change : 0.0
* loss = change < 0 ? (-1) * change : 0.0
* avgGain = rma(gain, 14)
* avgLoss = rma(loss, 14)
* rs = avgGain / avgLoss
* rsi = 100 - (100 / (1 + rs))
*
*
* where
* RMA = alpha * source + (1-alpha) * RMA[1]
* alpha = 1/length
I just cant seem to get the RMA part right, i just dont have a clue anymore on how to interperted it. Below is my class with at the bottom some sample data. If someone has managed to get a exact or near RSI calculation to to the tradingview could you please walk me through the steps.
Rsi_indicator.class
public class Rsi_indicator {
static Candlestick[] candles = getCandleSticks();
static double[] gain_array = new double[candles.length];
static double[] loss_array = new double[candles.length];
public static final int RSI_PERIOD = 14;
public static void main(String[] args) {
/**
* 1. Calculate change over closes
*
* */
for (int i = 0; i < candles.length; i++) {
double gain = 0;
double loss = 0;
if (i >= 1) {
double change = candles[i - 1].getClose() - candles[i].getClose();
gain_array[i] = change >= 0 ? change : 0.0d;
loss_array[i] = change < 0 ? (-1) * change : 0.0d;
}
}
/**
* 2. Calculate AVG gain
*
* According to trading view they use this --> avgGain = rma(gain, 14)
* Where
* RMA = alpha * source + (1-alpha) * RMA[1]
* alpha = 1/length
*/
double alpha = 1.0 / RSI_PERIOD;
RMA rma_gain = new RMA(alpha);
RMA rma_loss = new RMA(alpha);
/*
TODO HOW EXACTLY TO IMPLEMENT THE ABOVE RMA?
what is exactly meant by source ? and RMA[1] is this the previous value that was calculated?
*/
/**
* 4. Calculate relative strength
* */
double RS = avg_gain / avg_loss;
/**
* 5. Calculate RSI
* */
double rsi = 100 - (100 / (1 + RS));
/**
* The last 4 calculated rsi values should be:
* 7 nov 2021 --> 59.68
* 8 nov 2021 --> 67.65
* 9 nov 2021 --> 65.75
* 10 nov 2021 --> 59.33
*/
System.out.println("RSI: " + rsi);
}
static class RMA {
private double alpha;
private Double oldValue;
public RMA(double alpha) {
this.alpha = alpha;
}
public double average(double value) {
if (oldValue == null) {
oldValue = value;
return value;
}
double newValue = oldValue + alpha * (value - oldValue);
return newValue;
}}
/**
* This is just for you to have a working sample instantly
* The sample data i pulled from the binance api is the
* 1D BINANCE BTCUSDT pair from 2021-10-20T02:00 TO 2021-11-10T01:00.
*/
static Candlestick[] getCandleSticks() {
String[] data =
{"1634688000000,64280.59,67000.0,63481.4,66001.41,1634774399999",
"1634774400000,66001.4,66639.74,62000.0,62193.15,1634860799999",
"1634860800000,62193.15,63732.39,60000.0,60688.22,1634947199999",
"1634947200000,60688.23,61747.64,59562.15,61286.75,1635033599999",
"1635033600000,61286.75,61500.0,59510.63,60852.22,1635119999999",
"1635120000000,60852.22,63710.63,60650.0,63078.78,1635206399999",
"1635206400000,63078.78,63293.48,59817.55,60328.81,1635292799999",
"1635292800000,60328.81,61496.0,58000.0,58413.44,1635379199999",
"1635379200000,58413.44,62499.0,57820.0,60575.89,1635465599999",
"1635465600000,60575.9,62980.0,60174.81,62253.71,1635551999999",
"1635552000000,62253.7,62359.25,60673.0,61859.19,1635638399999",
"1635638400000,61859.19,62405.3,59945.36,61299.8,1635724799999",
"1635724800000,61299.81,62437.74,59405.0,60911.11,1635811199999",
"1635811200000,60911.12,64270.0,60624.68,63219.99,1635897599999",
"1635897600000,63220.57,63500.0,60382.76,62896.48,1635983999999",
"1635984000000,62896.49,63086.31,60677.01,61395.01,1636070399999",
"1636070400000,61395.01,62595.72,60721.0,60937.12,1636156799999",
"1636156800000,60940.18,61560.49,60050.0,61470.61,1636243199999",
"1636243200000,61470.62,63286.35,61322.78,63273.59,1636329599999",
"1636329600000,63273.58,67789.0,63273.58,67525.83,1636415999999",
"1636416000000,67525.82,68524.25,66222.4,66947.66,1636502399999",
"1636502400000,66947.67,69000.0,62822.9,64882.43,1636588799999",
};
List<Candlestick>list = new ArrayList<>();
for (String s: data) {
Candlestick c = new Candlestick();
String[] sArr = s.split(",");
c.setOpenTime(Long.valueOf(sArr[0]));
c.setOpen(sArr[1]);
c.setHigh(sArr[2]);
c.setLow(sArr[3]);
c.setClose(sArr[4]);
c.setCloseTime(Long.valueOf(sArr[5]));
list.add(c);
}
return list.stream().toArray(Candlestick[]::new);
}
}
Candlestick.class
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class Candlestick {
private Long openTime;
private double open;
private double high;
private double low;
private double close;
private double volume;
private Long closeTime;
public Long getOpenTime() {
return openTime;
}
public void setOpenTime(Long openTime) {
this.openTime = openTime;
}
public double getOpen() {
return open;
}
public void setOpen(String open) {
this.open = toDouble(open);
}
public double getHigh() {
return high;
}
public void setHigh(String high) {
this.high = toDouble(high);
}
public double getLow() {
return low;
}
public void setLow(String low) {
this.low = toDouble(low);
}
public double getClose() {
return close;
}
public void setClose(String close) {
this.close = toDouble(close);
}
public Long getCloseTime() {
return closeTime;
}
public void setCloseTime(Long closeTime) {
this.closeTime = closeTime;
}
public LocalDateTime getFormattedOpenTime() {
return Instant.ofEpochMilli(openTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
public LocalDateTime getFormattedCloseTime() {
return Instant.ofEpochMilli(closeTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
public double toDouble(String a) {
return Double.parseDouble(a);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
