using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; using System.Threading.Tasks; namespace XTS.Base.Data.TI { [IndicatorScaleAttribute(IndicatorScale.Custom, 0, 100)] [IndicatorAttribute("{95C1C6DA-9495-45DD-8266-33A1D9400107}", "RSI", "Relative Streangth Index", "SYMPH", IndicatorCategory = IndicatorCategoryType.Custom)] public class RSI : IndicatorBase { [Parameter("LengthPeriod", Description = "The length of the RSI", DefaultValue = 12)] private int _lengthPeriod = 12; [Parameter("UpperLimit", Description = "Over Bought Value", DefaultValue = 70)] private int _upperLimit = 70; [Parameter("LowerLimit", Description = "Over Sold Value", DefaultValue = 30)] private int _lowerLimit = 30; private double _lastUpwardPriceChangeSmooth = 0; private double _lastDownwardPriceChangeSmooth = 0; [Output("RSIValue", DefaultValue = double.NaN, LineColor = "Red")] private DoubleSeries _rsiDoubleValueSeries = new DoubleSeries(); [Output("UpperLimit", DefaultValue = double.NaN, LineColor = "Gray", LineStyle = DashStyle.DashDot)] private DoubleSeries _rsiUpperLimitDoubleValueSeries = new DoubleSeries(); [Output("LowerLimit", DefaultValue = double.NaN, LineColor = "Gray", LineStyle = DashStyle.DashDot)] private DoubleSeries _rsiLowerLimitDoubleValueSeries = new DoubleSeries(); public RSI(TimeDataSeries timeDataSeries, int lengthPeriod) : base(timeDataSeries){ if (lengthPeriod <= 0) throw new ArgumentException("Invalid RSI length"); _lengthPeriod = lengthPeriod; } public RSI() : base(null){} public RSI(TimeDataSeries timeDataSeries): base(timeDataSeries){} /// /// Calculates the Indicator Function value at the index. /// /// The index at which Indicator Function value need to be calculated. /// /// The calculated Indicator function value at the index. /// protected override double Calculate(int index){ double priceUpward = 0; double priceDownward = 0; int checkValue = _lengthPeriod; _rsiUpperLimitDoubleValueSeries[index] = _upperLimit; _rsiLowerLimitDoubleValueSeries[index] = _lowerLimit; if (index < checkValue) _rsiDoubleValueSeries[index] = double.NaN; else if (index == checkValue){ int startIndex = Math.Max(index - _lengthPeriod, 1); double barPricePrevious = this.TimeDataSeries[startIndex].Close; for (int counter = startIndex + 1; counter <= index; counter++){ double barPriceCurrent = this.TimeDataSeries[counter].Close; if (barPriceCurrent > barPricePrevious) // Upward price movement priceUpward += (barPriceCurrent - barPricePrevious); else if (barPriceCurrent < barPricePrevious) // Downward price movement priceDownward += (barPricePrevious - barPriceCurrent); barPricePrevious = barPriceCurrent; } _lastUpwardPriceChangeSmooth = priceUpward / _lengthPeriod; _lastDownwardPriceChangeSmooth = priceDownward / _lengthPeriod; double rsiValue = 100 - (100 / (1 + (_lastUpwardPriceChangeSmooth / _lastDownwardPriceChangeSmooth))); _rsiDoubleValueSeries[index] = Math.Round(rsiValue, 2); }else{ double currentDownwardPriceChange; double currentUpwardPriceChange; double rsiValue = 0.0; currentUpwardPriceChange = this.TimeDataSeries[index].Close - this.TimeDataSeries[index - 1].Close; if (currentUpwardPriceChange >= 0) currentDownwardPriceChange = 0; else{ currentDownwardPriceChange = -currentUpwardPriceChange; currentUpwardPriceChange = 0; } _lastUpwardPriceChangeSmooth = ((_lengthPeriod - 1) * _lastUpwardPriceChangeSmooth + currentUpwardPriceChange) / _lengthPeriod; _lastDownwardPriceChangeSmooth = ((_lengthPeriod - 1) * _lastDownwardPriceChangeSmooth + currentDownwardPriceChange) / _lengthPeriod; if (_lastUpwardPriceChangeSmooth + _lastDownwardPriceChangeSmooth != 0) rsiValue = 100 * _lastUpwardPriceChangeSmooth / (_lastUpwardPriceChangeSmooth + _lastDownwardPriceChangeSmooth); _rsiDoubleValueSeries[index] = Math.Round(rsiValue, 2); } return _rsiDoubleValueSeries[index]; } } }