MACD.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 System.Drawing;

using Trader.Data;

namespace Trader.Study
{
        /// <summary>
        /// Represents a MACD (Moving Average Convergence and Divergence).
        /// </summary>
        public class MACD : Indicator
        {
                private Series m = new Series();
                private double s, h;
                private int x, y, z, lastIndex = 0;
                private EMA emaX;
                private EMA emaY;
                private EMA emaZ;
                private SerializableColor macdColor = new SerializableColor(Color.Blue);
                private SerializableColor signalColor = new SerializableColor(Color.Red);
                private SerializableColor histoColor = new SerializableColor(Color.Gray);

                /// <summary>
                /// ctor.
                /// </summary>
                public MACD() : base("MACD") {
                        this.x = 12;
                        this.y = 26;
                        this.z = 9;
                        this.emaX = new EMA(this.x);
                        this.emaY = new EMA(this.y);
                        this.emaZ = new EMA(this.z);
                        base.Position = ChartPosition.Lower;
                        this.NeedQuotes = false;
                }

                /// <summary>
                /// ctor.
                /// </summary>
                /// <param name="x"></param>
                /// <param name="y"></param>
                /// <param name="z"></param>
                public MACD(int x, int y, int z)  : base("MACD") {
                        this.x = x;
                        this.y = y;
                        this.z = z;
                        this.emaX = new EMA(this.x);
                        this.emaY = new EMA(this.y);
                        this.emaZ = new EMA(this.z);
                        base.Position = ChartPosition.Lower;
                        this.NeedQuotes = false;
                }

                /// <summary>
                /// Gets or sets the x.
                /// </summary>
                [IndicatorParameter]
                public int X {
                        get {
                                return this.x;
                        }
                        set {
                                this.x = value;
                                this.emaX.Period = value;
                        }
                }

                /// <summary>
                /// Gets or sets the y.
                /// </summary>
                [IndicatorParameter]
                public int Y {
                        get {
                                return this.y;
                        }
                        set {
                                this.y = value;
                                this.emaY.Period = value;
                        }
                }

                [IndicatorParameter]
                public int Z {
                        get {
                                return this.z;
                        }
                        set {
                                this.z = value;
                                this.emaZ.Period = value;
                        }
                }

                /// <summary>
                /// Calculates the MACD value from a quote.
                /// </summary>
                /// <remarks>
                /// It returns the MACD value.
                /// </remarks>
                /// <param name="index"></param>
                /// <param name="series"></param>
                /// <returns></returns>
                public override double Calculate(int index, Series series) {
                        if (index == 0) {
                                base.Maximum = 0;
                                base.Minimum = 0;
                        }

                        this.lastIndex = index;
                        double m1 = series.Accept(index, this.emaX) - series.Accept(index, this.emaY);
                        
                        this.m[index] = m1;
                        this.s = this.m.Accept(index, this.emaZ);
                        this.h = m1 - this.s;

                        if (base.Maximum < m1)
                                base.Maximum = m1;

                        if (base.Maximum < this.s)
                                base.Maximum = this.s;

                        if (base.Minimum > m1)
                                base.Minimum = m1;

                        if (base.Minimum > this.s)
                                base.Minimum = this.s;

                        return m1;

                }

                /// <summary>
                /// Gets the MACD.
                /// </summary>
                [IndicatorValue]
                public double MACD_ {
                        get {
                                if (this.m.Count == 0) return double.NaN;

                                return this.m[this.lastIndex];
                        }
                }

                /// <summary>
                /// Gets the Signal.
                /// </summary>
                [IndicatorValue]
                public double Signal {
                        get {
                                return this.s;
                        }
                }

                /// <summary>
                /// Gets the Histogram.
                /// </summary>
                [IndicatorValue]
                public double DivergenceHistogram {
                        get {
                                return this.h;
                        }
                }

                /// <summary>
                /// Gets or sets the color for K.
                /// </summary>
                [IndicatorParameter]
                public SerializableColor MACD_Color {
                        get {
                                return this.macdColor;
                        }
                        set {
                                this.macdColor = value;
                        }
                }

                /// <summary>
                /// Gets or sets the color for signal.
                /// </summary>
                [IndicatorParameter]
                public SerializableColor SignalColor {
                        get {
                                return this.signalColor;
                        }
                        set {
                                this.signalColor = value;
                        }
                }

                /// <summary>
                /// Gets or sets the color for histogram.
                /// </summary>
                [IndicatorParameter]
                public SerializableColor DivergenceHistogramColor {
                        get {
                                return this.histoColor;
                        }
                        set {
                                this.histoColor = value;
                        }
                }

        }
}