Why is my Rust RSI calculation different from the TradingView indicator?

79 Views Asked by At

I am attempting to replicate the RSI indicator value from TradingView using Rust and the Mexc API, but the value displayed is incorrect. Can you help me identify what I am doing wrong?

async fn get_symbol_rsi(client: Client, symbol: &str) -> AppResult<f64> {
    let candles: Klines = client
        .get(format!(
            "https://contract.mexc.com/api/v1/contract/kline/{symbol}?interval=Min15"
        ))
        .send()
        .await?
        .json()
        .await?;

    let mut closes = candles
        .data
        .close
        .into_iter()
        .rev() // So it shows from new candles
        .take(15) // take the last 15 new candles (1 more because of the first one?)
        .rev(); // reverse it back to the original order older to newer

    // Get the gains and losses percentages
    let mut gains = Vec::new();
    let mut losses = Vec::new();

    let prev_close = closes.next().unwrap();
    for close in closes {
        let diff = close - prev_close;

        if diff > 0.0 {
            gains.push(diff);
            losses.push(0.0);
        } else {
            gains.push(0.0);
            losses.push(diff.abs());
        }
    }

    // Calculate the RSI based on RMA
    let alpha = 1.0 / 14.0;
    let mut rma_gains = gains[0];
    let mut rma_losses = losses[0];

    for i in 1..14 {
        rma_gains = alpha * gains[i] + (1.0 - alpha) * rma_gains;
        rma_losses = alpha * losses[i] + (1.0 - alpha) * rma_losses;
    }

    let rs = rma_gains / rma_losses;
    let rsi = 100.0 - (100.0 / (1.0 + rs));

    Ok(rsi)
}
1

There are 1 best solutions below

7
Rakesh Poluri On

The main difference from what I see is that you are using a Simple Moving Average for the avg_up and avg_down variables.

TradingView uses a modified Exponential Moving Average called Relative Moving Average (RMA) for use in their Relative Strength Index (RSI) for those variables.

The difference is in the alpha variable:

Where EMA has alpha = 2 / (length + 1)

RMA has alpha = 1 / length

Below is a function for RMA in Rust:

fn rma(price_ndarray: &Array1<f32>, period: usize) -> Array1<f32>{
    let length = price_ndarray.len() - period +1;
    let mut result = Array1::<f32>::zeros(length);
    result[0] = price_ndarray.slice(s![0..period]).sum();
    for i in 1..length{
        result[i] = result[i-1]+(price_ndarray[i+period-1]-result[i-1])*(1.0/(period as f32));
    }
    
    result
}