// TRIX
        public static void CalculateTRIX(out string key, out string key2, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, int period2, out int offset, out int min, out int max, bool leverage = false)
        {
            min = int.MaxValue;
            max = int.MinValue;

            key = string.Format("TRIX({0}-{1})", period.ToString("00"), period2.ToString("00"));
            key2 = string.Format("TRIX-Smooth-({0}-{1})", period.ToString("00"), period2.ToString("00"));

            offset = 3 * (period > period2 ? period : period2);
            ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period);
            ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period);
            ExponentialMovingAverage ema3 = new ExponentialMovingAverage(period);
            ExponentialMovingAverage ema4 = new ExponentialMovingAverage(period2);
            double singleSmooth;
            double doubleSmooth;
            double tripleSmooth;
            double prevTriplesmooth = -1;
            double trix;

            int i = 0;
            foreach (StockPoint point in data)
            {
                ema1.AddValue(point.Close);
                if (i < period)
                {
                    i++;
                }
                else
                {
                    singleSmooth = ema1.MovingAverage;
                    ema2.AddValue(singleSmooth);
                    if (i < 2 * period)
                    {
                        i++;
                    }
                    else
                    {
                        doubleSmooth = ema2.MovingAverage;
                        ema3.AddValue(doubleSmooth);
                        if (i < 3 * period)
                        {
                            i++;
                        }
                        else
                        {
                            tripleSmooth = ema3.MovingAverage;
                            if (prevTriplesmooth != -1)
                            {
                                trix = (double)decimal.Round((((decimal)tripleSmooth - (decimal)prevTriplesmooth) / (decimal)tripleSmooth) * 100 * (leverage ? 100 : 1), 4);
                                ema4.AddValue(trix);

                                AddValue(point.PointDateTime, key, trix, indicators);
                                AddValue(point.PointDateTime, key2, ema4.MovingAverage, indicators);

                                if (min > trix)
                                    min = (int)Math.Floor(trix);

                                if (max < trix)
                                    max = (int)Math.Ceiling(trix);
                            }
                            prevTriplesmooth = tripleSmooth;
                        }
                    }
                }
            }
        }
        // Stochastic RSI
        public static void CalculateStochasticRSI(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset, bool leverage = true)
        {
            key = string.Format("StocRSI({0})", period.ToString("00"));
            ExponentialMovingAverage gains = new ExponentialMovingAverage(period);
            ExponentialMovingAverage losses = new ExponentialMovingAverage(period);
            offset = period * 2;

            double rsi;
            double stochRSI;
            double highestRSI;
            double lowestRSI;

            Queue<double> rsiQueue = new Queue<double>();

            StockPoint previousPoint = data[0];
            int i = 0;
            foreach (StockPoint point in data.Skip(1))
            {
                if (previousPoint.Close > point.Close)
                {
                    losses.AddValue(previousPoint.Close - point.Close);
                    gains.AddValue(0);
                }
                else if (previousPoint.Close < point.Close)
                {
                    gains.AddValue(point.Close - previousPoint.Close);
                    losses.AddValue(0);
                }

                if (i < period - 1)
                {
                    i++;
                }
                else
                {
                    rsi = 100 - (100 / (1 + (gains.MovingAverage / losses.MovingAverage)));

                    rsiQueue.Enqueue(rsi);
                    if (rsiQueue.Count > period)
                    {
                        rsiQueue.Dequeue();
                    }

                    if (rsiQueue.Count == period)
                    {
                        highestRSI = rsiQueue.Max();
                        lowestRSI = rsiQueue.Min();

                        stochRSI = (rsi - lowestRSI) / (highestRSI - lowestRSI) * (leverage ? 100 : 1);

                        AddValue(point.PointDateTime, key, stochRSI, indicators);
                    }
                }

                previousPoint = point;
            }
        }
        // RSI
        /// <summary>
        /// Calculates the Relative Strength Index and fills indicators with the data needed to graph it.
        /// </summary>
        /// <param name="key">Name of the set to put in the graph key</param>
        /// <param name="data">StockPoints to calculate the Relative Strength Index with.</param>
        /// <param name="indicators">The mfvvalues needed to graph the RSI.</param>
        /// <param name="period">The number of days gained/lost to consider.</param>
        /// <param name="offset">Where to start the graph.</param>
        public static void CalculateRsi(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset)
        {
            key = "RSI(" + period.ToString("00") + ")";
            ExponentialMovingAverage gains = new ExponentialMovingAverage(period);
            ExponentialMovingAverage losses = new ExponentialMovingAverage(period);
            offset = period;
            int i = 0;
            StockPoint previousPoint = data[0];
            foreach (StockPoint point in data.Skip(1))
            {
                if (previousPoint.Close > point.Close)
                {
                    losses.AddValue(previousPoint.Close - point.Close);
                    gains.AddValue(0);
                }
                else if (previousPoint.Close < point.Close)
                {
                    gains.AddValue(point.Close - previousPoint.Close);
                    losses.AddValue(0);
                }

                if (i < period - 1)
                {
                    i++;
                }
                else
                {
                    double rsi = 100 - (100 / (1 + (gains.MovingAverage / losses.MovingAverage)));
                    AddValue(point.PointDateTime, key, rsi, indicators);
                }

                previousPoint = point;
            }
        }
        // MACD
        public static void CalculateMACD(out string key, out string key2, out double[] key3, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period1, int period2, int period3, out int offset, out int min, out int max)
        {
            min = int.MaxValue;
            max = int.MinValue;

            key = string.Format("MACD({0}-{1}-{2})", period1.ToString("00"), period2.ToString("00"), period3.ToString("00"));
            key2 = string.Format("MACD-SignalLine({0}-{1}-{2})", period1.ToString("00"), period2.ToString("00"), period3.ToString("00"));
            List<double> hist = new List<double>();

            offset = (new List<int>(){period1, period2}.Max()) - 1;

            ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period1);
            ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period2);
            ExponentialMovingAverage ema3 = new ExponentialMovingAverage(period3);

            int i = 0;
            foreach(StockPoint point in data)
            {
                ema1.AddValue(point.Close);
                ema2.AddValue(point.Close);

                double EMA1 = ema1.MovingAverage;
                double EMA2 = ema2.MovingAverage;

                double MACDLine = EMA1 - EMA2;

                ema3.AddValue(MACDLine);

                if (i < offset)
                {
                    i++;
                    hist.Add(0);
                }
                else
                {
                    double SignalLine = ema3.MovingAverage;

                    if (min > MACDLine || min > SignalLine)
                    {
                        min = (int)(Math.Floor(MACDLine < SignalLine ? MACDLine : SignalLine));
                    }

                    if (max < MACDLine || max < SignalLine)
                    {
                        max = (int)(Math.Ceiling(MACDLine > SignalLine ? MACDLine : SignalLine));
                    }

                    AddValue(point.PointDateTime, key, MACDLine, indicators);
                    AddValue(point.PointDateTime, key2, SignalLine, indicators);

                    hist.Add(MACDLine - SignalLine);
                }
            }

            key3 = hist.ToArray();
        }
 // EMA
 /// <summary>
 /// Calculates the Exponential Moving Average and fills indicators with the data needed to graph it.
 /// </summary>
 /// <param name="key">Name of the set to put in the graph key</param>
 /// <param name="data">StockPoints to calculate the EMA with.</param>
 /// <param name="indicators">The mfvvalues needed to graph the EMA.</param>
 /// <param name="period">The number of days to average.</param>
 /// <param name="offset">Where to start the graph.</param>
 public static void CalculateEma(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period, out int offset)
 {
     key = "EMA(" + period.ToString("00") + ")";
     ExponentialMovingAverage ema = new ExponentialMovingAverage(period);
     offset = period - 1;
     int i = 0;
     foreach (StockPoint point in data)
     {
         ema.AddValue(point.Close);
         if (i < offset)
         {
             i++;
         }
         else
         {
             AddValue(point.PointDateTime, key, ema.MovingAverage, indicators);
         }
     }
 }
        // Chaikin Oscillator
        public static void CalculateChaikinOscillator(out string key, StockPoints data, Dictionary<DateTime, Dictionary<string, double>> indicators, int period1, int period2, out int offset, out int min, out int max)
        {
            key = string.Format("ChiOsc({0}:{1})", period1.ToString("00"), period2.ToString("00"));
            offset = (period2 > period1 ? period2 : period1) - 1;

            min = int.MaxValue;
            max = int.MinValue;

            // Money Flow Multiplier = [(Close  -  Low) - (High - Close)] /(High - Low)
            double mfm;

            // Money Flow Volume = Money Flow Multiplier x Volume for the Period
            double mfv;

            // ADL = Previous ADL + Current Period's Money Flow Volume
            double adl = 0D;

            // CHaikin Oscillator
            double co;

            ExponentialMovingAverage ema1 = new ExponentialMovingAverage(period1);
            ExponentialMovingAverage ema2 = new ExponentialMovingAverage(period2);
            int i = 0;
            foreach (StockPoint point in data)
            {
                mfm = ((point.Close - point.Low) - (point.High - point.Close)) / (point.High - point.Low == 0 ? 1 : point.High - point.Low);

                mfv = mfm * point.Volume;

                adl = adl + mfv;

                ema1.AddValue(adl);
                ema2.AddValue(adl);

                if (i < period2 - 1)
                {
                    i++;
                }
                else
                {
                    co = ema1.MovingAverage - ema2.MovingAverage;

                    if (min > co)
                        min = (int)Math.Floor(co);
                    if (max < co)
                        max = (int)Math.Ceiling(co);

                    AddValue(point.PointDateTime, key, co, indicators);
                }
            }
        }