【问题标题】:RSI calculation element by element instead of all at once逐个元素计算 RSI,而不是一次全部计算
【发布时间】:2020-06-28 16:24:19
【问题描述】:

以下代码的缺点是它一次计算所有价格的 RSI。如果我必须添加新价格怎么办?它将重新计算所有内容,因为数组中有一个额外的价格。这比我备份 AverageGain/AverageLoss 需要更长的时间。

public class RSI
{
    private readonly int _period;

    public RSI(int period)
    {
        _period = period;
    }

    public decimal[] Calculate(decimal[] prices)
    {
        var rsi = new decimal[prices.Length];

        decimal gain = 0m;
        decimal loss = 0m;

        rsi[0] = 0m;

        for (int i = 1; i <= _period; ++i)
        {
            var diff = prices[i] - prices[i - 1];
            if (diff >= 0)
            {
                gain += diff;
            }
            else
            {
                loss -= diff;
            }
        }

        decimal avrg = gain / _period;
        decimal avrl = loss / _period;
        decimal rs = gain / loss;
        rsi[_period] = 100m - (100m / (1m + rs));

        for (int i = _period + 1; i < prices.Length; ++i)
        {
            var diff = prices[i] - prices[i - 1];

            if (diff >= 0)
            {
                avrg = ((avrg * (_period - 1)) + diff) / _period;
                avrl = (avrl * (_period - 1)) / _period;
            }
            else
            {
                avrl = ((avrl * (_period - 1)) - diff) / _period;
                avrg = (avrg * (_period - 1)) / _period;
            }

            rs = avrg / avrl;

            rsi[i] = 100m - (100m / (1m + rs));
        }

        return rsi;
    }
}

我的想法是做一些能记住之前输入的东西并根据它计算 RSI,就像this one。现在,此代码不起作用,因为 _period 根本没有涉及。那个 github 中的那些人做到了,但由于所有这些继承的类/接口,我仍在努力做到这一点。我不想实现所有的接口/抽象类。我在下面提取的对我来说已经足够了。

// Trying to achieve this:
var candles = _client.GetKlines(bot.Symbol, KlineInterval.OneHour).Data.ToList();

RelativeStrengthIndex rsi = new RelativeStrengthIndex(12);

for (int i = 0; i < candles.Count - 1; i++)
{
    var result = rsi.ComputeNextValue(new InputData(candles[i].Close));
    Console.WriteLine($"RSI(12) = {result}");
}

// New candle data
var newResult = rsi.ComputeNextValue(new InputData(0.01256m));
Console.WriteLine($"RSI(12) = {newResult}");
public abstract class Indicator
{
    public abstract decimal ComputeNextValue(InputData input);

    public abstract void Reset();
}

public class InputData
{
    public decimal Value { get; private set; }

    public InputData(decimal value)
    {
        Value = value;
    }
}

public class RelativeStrengthIndex : Indicator
{
    private int _period;
    private InputData _previousInput;

    public decimal AverageGain { get; private set; }

    public decimal AverageLoss { get; private set; }

    public RelativeStrengthIndex(int period)
    {
        _period = period;
    }

    public override decimal ComputeNextValue(InputData input)
    {
        if (_previousInput != null && input.Value >= _previousInput.Value)
        {
            AverageGain = input.Value - _previousInput.Value;
            AverageLoss = 0m;
        }
        else if (_previousInput != null && input.Value < _previousInput.Value)
        {
            AverageGain = 0m;
            AverageLoss = _previousInput.Value - input.Value;
        }

        _previousInput = input;
        if (AverageLoss == 0m)
        {
            return 100m;
        }

        var rs = AverageGain / AverageLoss;
        return 100m - (100m / (1 + rs));
    }

    public override void Reset()
    {
        _previousInput = default;
    }
}

【问题讨论】:

    标签: c#


    【解决方案1】:

    我自己做的。如果您有任何建议/改进,请在 cmets 中注明。

    public class RelativeStrengthIndex : Indicator
    {
        private readonly int _period;
    
        private InputData _previousInput;
        private int _index;
        private decimal _gain;
        private decimal _loss;
        private decimal _averageGain;
        private decimal _averageLoss;
    
        public RelativeStrengthIndex(int period)
        {
            _period = period;
    
            _index = 0;
            _gain = 0;
            _loss = 0;
            _averageGain = 0;
            _averageLoss = 0;
        }
    
        public override decimal ComputeNextValue(InputData input)
        {
            // Formula: https://stackoverflow.com/questions/38481354/rsi-vs-wilders-rsi-calculation-problems?rq=1
            _index++;
    
            if (_previousInput != null)
            {
                var diff = input.Value - _previousInput.Value;
                _previousInput = input;
    
                if (_index <= _period)
                {
                    if (diff >= 0)
                    {
                        _totalGain += diff;
                    }
                    else
                    {
                        _totalLoss -= diff;
                    }
                }
    
                if (_index < _period)
                {
                    return 0;
                }
                else if (_index == _period)
                {
                    _averageGain = _totalGain / _period;
                    _averageLoss = _totalLoss / _period;
    
                    decimal rs = _averageGain / _averageLoss;
                    return 100 - (100 / (1 + rs));
                }
                else // if (_index >= _period + 1)
                {
                    if (diff >= 0)
                    {
                        _averageGain = ((_averageGain * (_period - 1)) + diff) / _period;
                        _averageLoss = (_averageLoss * (_period - 1)) / _period;
                    }
                    else
                    {
                        _averageGain = (_averageGain * (_period - 1)) / _period;
                        _averageLoss = ((_averageLoss * (_period - 1)) - diff) / _period;
                    }
    
                    decimal rs = _averageGain / _averageLoss;
                    return 100 - (100 / (1 + rs));
                }
            }
    
            _previousInput = input;
            return 0;
        }
    
        public override void Reset()
        {
            _previousInput = null;
            _index = 0;
            _gain = 0;
            _loss = 0;
            _averageGain = 0;
            _averageLoss = 0;
        }
    }
    

    【讨论】:

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