3

我想准确地反映cryptowatch.de上的 RSI 值(在我的情况下为 LTC-EUR),我使用了解释如何计算 RSI的网站 stockcharts.com 用Ja​​vascript (节点)编写计算器。

到目前为止我的代码:

// 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,但结果仍然错误

4

4 回答 4

2

我知道这是一个记录时间,但我只是遇到了这个问题并且得到了正确的技术。这让我花了很长时间才弄清楚在 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 的值的数量,在我的情况下默认为“关闭/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

于 2020-07-18T16:46:29.397 回答
1

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

好吧,让我从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 计算的公式。看到差异是很常见的,因此“精确”匹配需要对他们实际用于生成数据的内容进行调查(如果使用 D1-time-frame ,还要注意各自的行政 UTC 偏移差异)。

于 2018-05-07T12:29:17.830 回答
0

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

有关详细的分步说明,我写了一篇长文,您可以在这里查看: https ://turmanauli.medium.com/a-step-by-step-guide-for-calculating-reliable-rsi-值-以编程方式-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);
          }
          
      }
  }
于 2021-03-16T23:59:55.397 回答
0

avgLoss当它是一个增益时,你可能错过了平滑,avgGain当它是一个损失时,即在平滑循环中:

if (ch >= 0) {
  avgGain = (avgGain * 13 + ch) / 14;
  aveLoss = (aveLoss * 13) / 14;
} else {
  avgGain = (avgGain * 13) / 14;
  aveLoss = (aveLoss * 13 - ch) / 14;
}
于 2018-05-06T23:48:10.283 回答