3

我无法获得平滑的 RSI。下图来自 freestockcharts.com。计算使用此代码。

public static double CalculateRsi(IEnumerable<double> closePrices)
{
    var prices = closePrices as double[] ?? closePrices.ToArray();

    double sumGain = 0;
    double sumLoss = 0;
    for (int i = 1; i < prices.Length; i++)
    {
        var difference = prices[i] - prices[i - 1];
        if (difference >= 0)
        {
            sumGain += difference;
        }
        else
        {
            sumLoss -= difference;
        }
    }

    if (sumGain == 0) return 0;
    if (Math.Abs(sumLoss) < Tolerance) return 100;

    var relativeStrength = sumGain / sumLoss;

    return 100.0 - (100.0 / (1 + relativeStrength));
}

https://stackoverflow.com/questions/...th-index-using-some-programming-language-js-c

这似乎是没有平滑的纯 RSI。如何计算平滑 RSI?我尝试更改它以适应这两个站点的定义,但是输出不正确。它几乎没有平滑。

(我没有足够的代表来发布链接)

tc2000 -> Indicators -> RSI_and_Wilder_s_RSI (Wilder's smoothing = Previous MA value + (1/n periods * (Close - Previous MA)))

priceactionlab -> wilders-cutlers-and-harris-relative-strength-index (RS = EMA(Gain(n), n)/EMA(Loss(n), n))

有人真的可以用一些样本数据进行计算吗?

怀尔德的 RSI 与 RSI 在此处输入图像描述

4

2 回答 2

4

In order to calculate the RSI, you need a period to calculate it with. As noted on Wikipedia, 14 is used quite often.

So the calculation steps would be as follows:

Period 1 - 13, RSI = 0

Period 14:

AverageGain = TotalGain / PeriodCount;
AverageLoss = TotalLoss / PeriodCount;
RS = AverageGain / AverageLoss;
RSI = 100 - 100 / (1 + RS);

Period 15 - to period (N):

if (Period(N)Change > 0
  AverageGain(N) = ((AverageGain(N - 1) * (PeriodCount - 1)) + Period(N)Change) / PeriodCount;
else
  AverageGain(N) = (AverageGain(N - 1) * (PeriodCount - 1)) / PeriodCount;

if (this.Change < 0)
  AverageLoss(N) = ((AverageLoss(N - 1) * (PeriodCount - 1)) + Math.Abs(Period(N)Change)) / PeriodCount;
else
  AverageLoss(N) = (AverageLoss(N - 1) * (PeriodCount - 1)) / PeriodCount;

RS = AverageGain / AverageLoss;
RSI = 100 - (100 / (1 + RS));

Thereafter, to smooth the values, you need to apply a moving average of a certain period to your RSI values. To do that, traverse your RSI values from the last index to the first and calculate your average for the current period based on the preceding x smoothing periods.

Once done, just reverse the list of values to get the expected order:

List<double> SmoothedRSI(IEnumerable<double> rsiValues, int smoothingPeriod)
{
  if (rsiValues.Count() <= smoothingPeriod)
    throw new Exception("Smoothing period too large or too few RSI values passed.");

  List<double> results = new List<double>();
  List<double> reversedRSIValues = rsiValues.Reverse().ToList();

  for (int i = 1; i < reversedRSIValues.Count() - smoothingPeriod - 1; i++)
    results.Add(reversedRSIValues.Subset(i, i + smoothingPeriod).Average());

  return results.Reverse().ToList();
}

The Subset method is just a simple extension method as follows:

public static List<double> Subset(this List<double> values, int start, int end)
{
  List<double> results = new List<double>();

  for (int i = start; i <= end; i++)
    results.Add(values[i]);

  return results;
}

Disclaimer, I did not test the code, but it should give you an idea of how the smoothing is applied.

于 2018-04-26T20:54:52.700 回答
0

如果没有缓冲区/全局变量来存储数据,您将无法获得准确的值。

这是一个平滑指标,这意味着它不仅使用 14 根柱线,而且使用所有柱线:这是一步一步的文章,如果价格和可用柱线的数量相同,则可以使用经过验证的源代码生成完全相同的值,当然(您只需要从您的来源加载价格数据):

测试和验证:

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 -以编程方式-a6a604a06b77

PS 函数仅适用于简单指标(简单移动平均线),即使指数移动平均线、平均真实范围绝对需要全局变量来存储以前的值。

于 2021-03-16T23:48:59.627 回答