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