【问题标题】:RSI vs Wilder's RSI Calculation ProblemsRSI vs Wilder 的 RSI 计算问题
【发布时间】:2016-11-23 16:41:53
【问题描述】:

我无法获得平滑的 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))

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

Wilder's RSI vs RSI

【问题讨论】:

    标签: c# algorithm technical-indicator


    【解决方案1】:

    为了计算 RSI,您需要一个周期来计算它。 As noted on Wikipedia, 14 is used quite often.

    所以计算步骤如下:

    期间 1 - 13,RSI = 0

    第 14 期:

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

    期间 15 - 到期间 (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));
    

    此后,为了平滑这些值,您需要将某个时期的移动平均线应用于您的 RSI 值。为此,将您的 RSI 值从最后一个指标遍历到第一个指标,并根据之前的 x 个平滑周期计算当前周期的平均值。

    完成后,只需反转值列表即可获得预期的顺序:

    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();
    }
    

    Subset 方法只是一个简单的扩展方法,如下:

    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;
    }
    

    免责声明,我没有测试代码,但它应该让您了解如何应用平滑。

    【讨论】:

    • 此答案未解决问题中提出的 Wilders 平滑计算。
    • @DonF - 请查看更新后的答案。我没有测试它的准确性,但它应该给你一个想法,因为平滑是通过使用 x 个周期的移动平均值来计算的。
    【解决方案2】:

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

    这是一个平滑指标,这意味着它不仅使用 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-programmatically-a6a604a06b77

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

    【讨论】:

    • 请停止在多个问题中发布相同的链接。如果您与您发布的链接有任何关联,you must disclose your affiliation in your answers。如果没有此披露,您的帖子可能会被视为垃圾邮件。
    • 您好,我是这篇文章的作者,文章作者在medium上可见,还有什么需要透露的?上面甚至还有我的照片..
    • 如果您包含指向您自己的外部文章或其他产品或服务的链接,那么您需要在在答案本身中披露您是作者,否则它可以被视为self-promotion 并按此处理。你可以edit你的回答是说“我写了一篇关于[x]的文章,你可以在这里阅读”,这通常就足够了,只要你清楚地表明你是作者。使用相同的个人资料图片或名称,或在您的个人资料中包含指向您网站的链接是不够的披露。
    • 谢谢,我会的!
    • 没问题,请确保您对其他答案也这样做!
    猜你喜欢
    • 2020-10-07
    • 2017-11-26
    • 2023-03-13
    • 1970-01-01
    • 2018-10-16
    • 1970-01-01
    • 2020-07-23
    • 2019-11-22
    • 1970-01-01
    相关资源
    最近更新 更多