相对强度指数

Relative Strength Index

我正在尝试计算金融工具的相对强度指数 RSI。当我将我的计算与商业软件完成的计算进行比较时,它们看起来并不相同。我不知道我做错了什么。谁能帮忙?
RSI formula:

{100} - (100/(1+RS)). Where RS is AvgGain(N periods)/AvgLoss( N periods)

public DataTable RSI(string instrument, int period, string oper, int entryVal)
{



 DataTable dtRSI = new DataTable();      //table to return
    dtRSI.Columns.Add("Date");
    dtRSI.Columns.Add("Instrument");
    dtRSI.Columns.Add("Close");
    dtRSI.Columns.Add("RSI");

    //Load Datatable from database
    DataTable dt = new DataTable();
    dt = conn.ExtractDataFromDb(instrument);       

    int column = 1; //Close price

    //variables to RSI formula
    Queue<float> avgUp = new Queue<float>();
    Queue<float> avgDown = new Queue<float>();
    float close1, close2, rsi, rs;
    float avgUp1, avgUp2, newAvgUp, avgDown1, avgDown2, newAvgDown;

    string[] dateCloseRsi = new string[3];      //row of data to insert into new table
    string date;                                //date of calculation
    string[] splitDate = new string[2];

    //get first close
    close1 = float.Parse(dt.Rows[0][column].ToString());
    dt.Rows.RemoveAt(0);

    //get close for number of periods into the que-list
    for (int i = 1; i <= period; i++)
    {
        close2 = float.Parse(dt.Rows[0][column].ToString());

        //are todays close higher then yesterday?
        if (close2 > close1)
        {
            avgUp.Enqueue(close2 - close1);
            avgDown.Enqueue(0);
        }
        else if (close2<close1)
        {
            avgUp.Enqueue(0);
            avgDown.Enqueue(close1 - close2);
        }
        else
        {
            avgUp.Enqueue(0);
            avgDown.Enqueue(0);
        }

        close1 = close2;

        dt.Rows.RemoveAt(0);
    }


    //iterate datatable and calculate RSI
    foreach (DataRow rows in dt.Rows)
    {

        avgUp1 = float.Parse(avgUp.Average().ToString("n2"));       //calculate yesterdays avg difference on up days
        avgDown1 = float.Parse(avgDown.Average().ToString("n2"));   //calculate yesterdays avg difference on down days
        avgUp.Dequeue();
        avgDown.Dequeue();


        close2 = float.Parse(rows[column].ToString()); //todays close 
        //close today higher then yesterday?
        if (close2 > close1)
        {
            avgUp.Enqueue(close2 - close1);
            avgDown.Enqueue(0);
        }
        else if (close2 < close1)
        {
            avgDown.Enqueue(close1 - close2);
            avgUp.Enqueue(0);
        }
        else
        {
            avgUp.Enqueue(0);
            avgDown.Enqueue(0);
        }

        avgUp2 = float.Parse(avgUp.Average().ToString("n2"));           //todays avg difference on up days
        avgDown2 = float.Parse(avgDown.Average().ToString("n2"));       //todays avg difference on down days
        newAvgUp = ((avgUp1 * (period - 1)) + avgUp2) / period;         //yesterdays and todays avg diff value on up days
        newAvgDown = ((avgDown1 * (period - 1)) + avgDown2) / period;   //yesterdays and todays avg diff value on down days
        newAvgUp = float.Parse(newAvgUp.ToString("n2"));                //round to 2 decimals
        newAvgDown = float.Parse(newAvgDown.ToString("n2"));            //round to 2 decimals


        rs = newAvgUp / newAvgDown;                 //calc Relative Strength
        rs = float.Parse(rs.ToString("n2"));        //round to 2 decimals
        rsi = 100 - (100 / (1 + rs));               //Calc RSI
        rsi = float.Parse(rsi.ToString("n2"));      //round to 2 decimals

        close1 = close2;                            //todays close become yesterdays close for tomorrow

        //remove time from date
        date = rows[0].ToString();
        splitDate = date.Split(' ');
        date = splitDate[0];


        //add data to dtRSI
        DataRow rsiRow = dtRSI.NewRow();
        rsiRow["Date"] = date;
        rsiRow["Instrument"] = instrument;
        rsiRow["Close"] = rows[column];
        rsiRow["RSI"] = rsi;
        dtRSI.Rows.Add(rsiRow);

    }
        return dtRSI;               //returns a table with Date, Instrument, Close Price and RSI

}

您好,这是一个经过测试和验证的 C# class,它可以生成 100% 准确度的 RSI 值:

using System;
using System.Data;
using System.Globalization;

namespace YourNameSpace
  {
   class PriceEngine
      {
        public static DataTable data;
        public static double[] positiveChanges;
        public static double[] negativeChanges;
        public static double[] averageGain;
        public static double[] averageLoss;
        public static double[] rsi;
        
        public static double CalculateDifference(double current_price, double previous_price)
          {
              return current_price - previous_price;
          }

        public static double CalculatePositiveChange(double difference)
          {
              return difference > 0 ? difference : 0;
          }

        public static double CalculateNegativeChange(double difference)
          {
              return difference < 0 ? difference * -1 : 0;
          }

        public static void CalculateRSI(int rsi_period, int price_index = 5)
          {
              for(int i = 0; i < PriceEngine.data.Rows.Count; i++)
              {
                  double current_difference = 0.0;
                  if (i > 0)
                  {
                      double previous_close = Convert.ToDouble(PriceEngine.data.Rows[i-1].Field<string>(price_index));
                      double current_close = Convert.ToDouble(PriceEngine.data.Rows[i].Field<string>(price_index));
                      current_difference = CalculateDifference(current_close, previous_close);
                  }
                  PriceEngine.positiveChanges[i] = CalculatePositiveChange(current_difference);
                  PriceEngine.negativeChanges[i] = CalculateNegativeChange(current_difference);

                  if(i == Math.Max(1,rsi_period))
                  {
                      double gain_sum = 0.0;
                      double loss_sum = 0.0;
                      for(int x = Math.Max(1,rsi_period); x > 0; x--)
                      {
                          gain_sum += PriceEngine.positiveChanges[x];
                          loss_sum += PriceEngine.negativeChanges[x];
                      }

                      PriceEngine.averageGain[i] = gain_sum / Math.Max(1,rsi_period);
                      PriceEngine.averageLoss[i] = loss_sum / Math.Max(1,rsi_period);

                  }else if (i > Math.Max(1,rsi_period))
                  {
                      PriceEngine.averageGain[i] = ( PriceEngine.averageGain[i-1]*(rsi_period-1) + PriceEngine.positiveChanges[i]) / Math.Max(1, rsi_period);
                      PriceEngine.averageLoss[i] = ( PriceEngine.averageLoss[i-1]*(rsi_period-1) + PriceEngine.negativeChanges[i]) / Math.Max(1, rsi_period);
                      PriceEngine.rsi[i] = PriceEngine.averageLoss[i] == 0 ? 100 : PriceEngine.averageGain[i] == 0 ? 0 : Math.Round(100 - (100 / (1 + PriceEngine.averageGain[i] / PriceEngine.averageLoss[i])), 5);
                  }
              }
          }
          
        public static void Launch()
          {
            PriceEngine.data = new DataTable();            
            //load {date, time, open, high, low, close} values in PriceEngine.data (6th column (index #5) = close price) here
            
            positiveChanges = new double[PriceEngine.data.Rows.Count];
            negativeChanges = new double[PriceEngine.data.Rows.Count];
            averageGain = new double[PriceEngine.data.Rows.Count];
            averageLoss = new double[PriceEngine.data.Rows.Count];
            rsi = new double[PriceEngine.data.Rows.Count];
            
            CalculateRSI(14);
          }
          
      }
  }

详细的步骤说明,我写了一篇很长的文章,你可以在这里查看: https://turmanauli.medium.com/a-step-by-step-guide-for-calculating-reliable-rsi-values-programmatically-a6a604a06b77

P.S。您需要全局变量来存储先前的值,这不是 RSI 等指标的选项,简单函数仅适用于简单移动平均线等简单指标。所有平滑/加权指标都需要缓冲区/全局数组来存储数据。