RSI.cs // Copyright (C) 2002-2005 Competo Solutions, Inc.
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.

using System;

using Trader.Data;

namespace Trader.Study {
        /// <summary>
        /// Represents a relative strgenth index indicator.
        /// </summary>
        public class RSI : Indicator {
                private double avgGain = 0;
                private double avgLoss = 0;
                private double rsi;
                private int period;

                /// <summary>
                /// ctor.
                /// </summary>
                public RSI() : base("RSI") {
                        base.Position = ChartPosition.Lower;
                        this.period = 14;
                }

                /// <summary>
                /// ctor.
                /// </summary>
                public RSI(int period)  :  base("RSI")                {
                        base.Position = ChartPosition.Lower;
                        this.period = period;
                }

                /// <summary>
                /// Gets the period.
                /// </summary>
                [IndicatorParameter]
                public int Period {
                        get {
                                return this.period;
                        }
                        set {
                                this.period = value;
                        }
                }

                /// <summary>
                /// Calculates the RSI at index.
                /// </summary>
                /// <param name="index"></param>
                /// <param name="series"></param>
                public override double Calculate(int index, Series series) {
                        if (index == 0) {
                                base.Maximum = 0;
                                base.Minimum = 0;
                                this.avgGain = 0;
                                this.avgLoss = 0;
                        }

                        if (index < this.period) {
                                this.rsi = 50;
                                return this.rsi;
                        }

                        if (index == this.period) {
                                for (int i=0; i<index; i++) {
                                        if (series[i+1] >= series[i]) {
                                                this.avgGain += series[i+1] - series[i];
                                        }
                                        else {
                                                avgLoss += series[i] - series[i+1];
                                        }
                                }
                                this.avgGain = this.avgGain/this.period;
                                this.avgLoss = this.avgLoss/this.period;
                                //Console.WriteLine("gain {0}, loss {1}", this.avgGain, this.avgLoss);
                                this.rsi = 100 - 100/(1+this.avgGain/this.avgLoss);
                                return this.rsi;
                        }

                        double currentGain = 0;
                        double currentLoss = 0;
                        if (series[index] >= series[index-1])
                                currentGain = series[index] - series[index-1];
                        else
                                currentLoss = series[index-1] - series[index];

                        this.avgGain = (this.avgGain*(this.period-1) + currentGain)/this.period;
                        this.avgLoss = (this.avgLoss*(this.period-1)+currentLoss)/this.period;
                        //Console.WriteLine("gain {0}, loss {1}", this.avgGain, this.avgLoss);
                        this.rsi = 100 - 100/(1+this.avgGain/this.avgLoss);
                        return this.rsi;
                }

        }
}