【问题标题】:Calculate RSI based on Kraken OHLC根据 Kraken OHLC 计算 RSI
【发布时间】:2018-10-16 15:14:55
【问题描述】:

我想精确地反映cryptowatch.de 上的 RSI 值(在我的例子中是 LTC-EUR),我使用了网站 stockcharts.com,它解释了如何计算 RSI,并用 Javascript(节点)编写计算器。

到目前为止我的代码:

// data is an array of open-prices in descending date order (the current price is the last element)
function calculateRSI(data) {
  data = data.reverse(); // Reverse to handle it better
  let avgGain = 0;
  let aveLoss = 0;

  // Calculate first 14 periods
  for (let i = 0; i < 14; i++) {
    const ch = data[i] - data[i + 1];

    if (ch >= 0) {
      avgGain += ch;
    } else {
      aveLoss -= ch;
    }
  }

  avgGain /= 14;
  aveLoss /= 14;

  // Smooth values 250 times
  for (let i = 14; i < 264; i++) {
    const ch = data[i] - data[i + 1];

    if (ch >= 0) {
      avgGain = (avgGain * 13 + ch) / 14;
      aveLoss = (aveLoss * 13) / 14;
    } else {
      avgGain = (avgGain * 13) / 14;
      aveLoss = (aveLoss * 13 - ch) / 14;
    }
  }

  // Calculate relative strength index
  const rs = avgGain / aveLoss;
  return 100 - 100 / (1 + rs);
}

但结果总是与cryptowatch.de 上显示的值相差甚远,怎么了?如何正确计算? (其他编程语言发帖也可以)

谢谢@jingx 但结果还是错了

【问题讨论】:

    标签: javascript algorithm trading kraken.com


    【解决方案1】:

    我知道这是一个记录时间,但我只是遇到了这个问题并且得到了正确的技术。我花了很长时间才弄明白,所以在 C# 中很享受。

    第 1 步。您从 API 接收从过去 [0] 到现在 [x] 的值。对于“收盘/14”,您必须计算“收盘”值(利润/损失)的差异,如下所示:

                var profitAndLoss = new List<double>();
                for (int i = 0; i < values.Count - 1; i++)
                    profitAndLoss.Add(values[i + 1] - values[i]); //newer - older value will give you negative values for losses and positiv values for profits
    

    第 2 步。计算您的初始 rsi 值(通常称为 RSI StepOne),请注意我没有反转收到的值。此初始计算是使用“最旧”值完成的。 _samples 是您在我的情况下最初用于计算 RSI 的值的数量,默认为 'Close/14' _samples = 14:

                var avgGain = 0.0;
                var avgLoss = 0.0;
    
                //initial
                for (int i = 0; i < _samples; i++)
                {
                    var value = profitAndLoss[i];
                    if (value >= 0)
                        avgGain += value;
                    else
                        avgLoss += value * -1; //here i multiply -1 so i only have positive values
                }
    
                avgGain /= _samples;
                avgLoss /= _samples;
    

    第 3 步。使用从 API 获得的剩余值平滑平均值:

                //smooth with given values
                for (int i = _samples; i < profitAndLoss.Count; i++)
                {
                    var value = profitAndLoss[i];
                    if (value >= 0)
                    {
                        avgGain = (avgGain * (_samples - 1) + value) / _samples;
                        avgLoss = (avgLoss * (_samples - 1)) / _samples;
                    }
                    else
                    {
                        value *= -1;
                        avgLoss = (avgLoss * (_samples - 1) + value) / _samples;
                        avgGain = (avgGain * (_samples - 1)) / _samples;
                    }
                }
    

    第 4 步。计算 RSI 的时间:

                var rs = avgGain / avgLoss;
                var rsi = 100 - (100 / (1 + rs));
    

    这将为您提供与 Kraken 在其 RSI 图表中相同的值(+/- 0.05,取决于您的更新频率)

    结果图片1

    【讨论】:

      【解决方案2】:

      如何正确计算?(其他编程语言发帖也可以)

      好吧,让我添加一个这样的,来自 QuantFX 模块

      可能会遇到许多公式,有些带有示例,有些带有验证数据集,所以让我选择一个这样的公式,使用 numba.jit 装饰的 Python 代码,以及一些 numpy 矢量化技巧:

      def RSI_func( priceVEC, RSI_period = 14 ):
          """
          __doc__ 
          USE:
                   RSI_func( priceVEC, RSI_period = 14 )
      
                   Developed by J. Welles Wilder and introduced in his 1978 book,
                   New Concepts in Technical Trading Systems, the Relative Strength Index
                   (RSI) is an extremely useful and popular momentum oscillator.
      
                   The RSI compares the magnitude of a stock's recent gains
                   to the magnitude of its recent losses and turns that information
                   into a number that ranges from 0 to 100.
      
                   It takes a single parameter, the number of time periods to use
                   in the calculation. In his book, Wilder recommends using 14 periods.
      
                   The RSI's full name is actually rather unfortunate as it is easily
                   confused with other forms of Relative Strength analysis such as
                   John Murphy's "Relative Strength" charts and IBD's "Relative Strength"
                   rankings.
      
                   Most other kinds of "Relative Strength" stuff involve using
                   more than one stock in the calculation. Like most true indicators,
                   the RSI only needs one stock to be computed.
      
                   In order to avoid confusion,
                   many people avoid using the RSI's full name and just call it "the RSI."
      
                   ( Written by Nicholas Fisher)
      
          PARAMS:  
                   pricesVEC  - a vector of price-DOMAIN-alike data in natural order
                   RSI_period - a positive integer for an RSI averaging period
      
          RETURNS:
                   a vector of RSI values
      
          EXAMPLE:
                   >>> RSI_func( np.asarray( [ 46.1250, 47.1250, 46.4375, 46.9375, 44.9375,
                                               44.2500, 44.6250, 45.7500, 47.8125, 47.5625,
                                               47.0000, 44.5625, 46.3125, 47.6875, 46.6875,
                                               45.6875, 43.0625, 43.5625, 44.8750, 43.6875
                                               ]
                                             ),
                                 RSI_period = 14  
                                 )
      
                   array( [ 51.77865613,  51.77865613,  51.77865613,  51.77865613,  51.77865613,  51.77865613,  51.77865613,
                            51.77865613,  51.77865613,  51.77865613,  51.77865613,  51.77865613,  51.77865613,
                            51.77865613,  48.47708511,  41.07344947,  42.86342911,  47.38184958,  43.99211059
                            ]
                          )
                   OUGHT BE:
                            51.779,       48.477,       41.073,       42.863,       47.382,       43.992
                   [PASSED]
          Ref.s:
                   >>> http://cns.bu.edu/~gsc/CN710/fincast/Technical%20_indicators/Relative%20Strength%20Index%20(RSI).htm
          """
          deltas           =  np.diff( priceVEC )
          seed             =  deltas[:RSI_period]
          up               =  seed[seed >= 0].sum() / RSI_period
          down             = -seed[seed <  0].sum() / RSI_period
          rs               =  up / down
          rsi              =   50. * np.ones_like( priceVEC )                 # NEUTRAL VALUE PRE-FILL
          rsi[:RSI_period] =  100. - ( 100. / ( 1. + rs ) )
      
          for i in np.arange( RSI_period, len( priceVEC )-1 ):
              delta = deltas[i]
      
              if  delta   >  0:
                  upval   =  delta
                  downval =  0.
              else:
                  upval   =  0.
                  downval = -delta
      
              up   = ( up   * ( RSI_period - 1 ) + upval   ) / RSI_period
              down = ( down * ( RSI_period - 1 ) + downval ) / RSI_period
      
              rs      = up / down
      
              rsi[i]  = 100. - ( 100. / ( 1. + rs ) )
      
          return rsi[:-1]
      

      鉴于您的愿望是“完全镜像”他人的图表,有一种最安全的模式可以交叉检查他们实际用于 RSI 计算的公式。看到差异是很常见的,因此“exact”匹配需要对他们实际用于生成数据的内容进行某种调查(如果使用 D1,还要注意各自的行政 UTC 偏移差异) -时间框架)。

      【讨论】:

        【解决方案3】:

        您可能错过了平滑 avgLoss 时的增益,以及 avgGain 时的损失,即在平滑循环中:

        if (ch >= 0) {
          avgGain = (avgGain * 13 + ch) / 14;
          aveLoss = (aveLoss * 13) / 14;
        } else {
          avgGain = (avgGain * 13) / 14;
          aveLoss = (aveLoss * 13 - ch) / 14;
        }
        

        【讨论】:

        • @SimonW。股票图表的公式使用 250 个平滑周期。加密手表可能不会。您是否尝试过股票图表数据并查看是否得到与 stockcharts 结果相同的 RSI?
        • 例如,如果您查看@user3666197 的答案,它似乎使用了 14 的滚动平滑期。
        【解决方案4】:

        您需要缓冲区来存储以前的值,换句话说,您需要全局变量,而不仅仅是函数(除非您正在为像 SMA 这样的简单指标创建函数)。

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

        在您下方看到一个最终类 (C#),它经过测试和验证,生成 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);
                  }
                  
              }
          }
        

        【讨论】:

          猜你喜欢
          • 2020-07-23
          • 2016-11-23
          • 1970-01-01
          • 2017-11-26
          • 2023-03-13
          • 2018-07-08
          • 2021-07-22
          • 2020-12-16
          • 1970-01-01
          相关资源
          最近更新 更多