Source » MACD - source code

// Forex Strategy Builder
// Copyright (c) 2006 - 2008 Miroslav Popov - All rights reserved!
// http://forexsb.com
// info(a)forexsb.com
//
// Last changed on: 2007-09-20

using System;
using System.Drawing;

namespace Forex_Strategy_Builder
{
    /// <summary>
    /// Indicator: MACD
    /// </summary>
    public class MACD : Indicator
    {
        /// <summary>
        /// The default constructor.
        /// </summary>
        public MACD()
        {
        }

        /// <summary>
        /// Sets the default parameters for the designated slot type.
        /// </summary>
        /// <param name="slotType">The slot type.</param>
        public MACD(SlotTypes slotType)
        {
            sIndicatorName  = "MACD";
            parameters      = new IndicatorParam();
            component       = new IndicatorComp[] { };
            afSpecValue     = new float[1] { 0f };
            bSeparatedChart = true;
            bIsCalculated   = false;


            // The indicator name.
            parameters.IndicatorName = sIndicatorName;

            // The slot type.
            parameters.SlotType = slotType;

            // The ComboBox parameters.
            parameters.ListParam[0].Caption = "Logic";
            parameters.ListParam[0].ItemList = new string[]
            {
                "The MACD line rises",
                "The MACD line falls",
                "The MACD line is higher than zero",
                "The MACD line is lower than zero",
                "The MACD line crosses the zero line upward",
                "The MACD line crosses the zero line downward",
                "The MACD line changes its direction upward",
                "The MACD line changes its direction downward",
                "The MACD line crosses the Signal line upward",
                "The MACD line crosses the Signal line downward",
                "The MACD line is higher than the Signal line",
                "The MACD line is lower than the Signal line"
            };
            parameters.ListParam[0].Index    = 0;
            parameters.ListParam[0].Text     = parameters.ListParam[0].ItemList[parameters.ListParam[0].Index];
            parameters.ListParam[0].Enabled  = true;
            parameters.ListParam[0].ToolTip  = "Logic of application of the indicator";

            parameters.ListParam[1].Caption  = "Smoothing method";
            parameters.ListParam[1].ItemList = Enum.GetNames(typeof(MAMethod));
            parameters.ListParam[1].Index    = 2;
            parameters.ListParam[1].Text     = parameters.ListParam[1].ItemList[parameters.ListParam[1].Index];
            parameters.ListParam[1].Enabled  = true;
            parameters.ListParam[1].ToolTip  = "The smoothing method of Moving Averages";

            parameters.ListParam[2].Caption  = "Base price";
            parameters.ListParam[2].ItemList = Enum.GetNames(typeof(BasePrice));
            parameters.ListParam[2].Index    = 3;
            parameters.ListParam[2].Text     = parameters.ListParam[2].ItemList[parameters.ListParam[2].Index];
            parameters.ListParam[2].Enabled  = true;
            parameters.ListParam[2].ToolTip  = "The price the Moving Averages are based on";

            parameters.ListParam[3].Caption  = "Signal line method";
            parameters.ListParam[3].ItemList = Enum.GetNames(typeof(MAMethod));
            parameters.ListParam[3].Index    = 0;
            parameters.ListParam[3].Text     = parameters.ListParam[3].ItemList[parameters.ListParam[3].Index];
            parameters.ListParam[3].Enabled  = true;
            parameters.ListParam[3].ToolTip  = "The smoothing method of the signal line";

            // The NumericUpDown parameters.
            parameters.NumParam[0].Caption = "Slow MA period";
            parameters.NumParam[0].Value   = 26;
            parameters.NumParam[0].Min     = 1;
            parameters.NumParam[0].Max     = 200;
            parameters.NumParam[0].Enabled = true;
            parameters.NumParam[0].ToolTip = "The period of Slow MA";

            parameters.NumParam[1].Caption = "Fast MA period";
            parameters.NumParam[1].Value   = 12;
            parameters.NumParam[1].Min     = 1;
            parameters.NumParam[1].Max     = 200;
            parameters.NumParam[1].Enabled = true;
            parameters.NumParam[1].ToolTip = "The period of Fast MA";

            parameters.NumParam[2].Caption = "Signal line period";
            parameters.NumParam[2].Value   = 9;
            parameters.NumParam[2].Min     = 1;
            parameters.NumParam[2].Max     = 200;
            parameters.NumParam[2].Enabled = true;
            parameters.NumParam[2].ToolTip = "The period of Signal line";

            // The CheckBox parameters.
            parameters.CheckParam[0].Caption = "Use previous bar value";
            parameters.CheckParam[0].Checked = Data.Strategy.PrepareUsePrevBarValueCheckBox(slotType);
            parameters.CheckParam[0].Enabled = true;
            parameters.CheckParam[0].ToolTip = "Use the indicator value from the previous bar";
        }

        /// <summary>
        /// Calculates the indicator's components.
        /// </summary>
        /// <param name="slotType">The slot type.</param>
        public override void Calculate(SlotTypes slotType)
        {
            if (parameters.SlotType == SlotTypes.NotDefined) return;

            // Reading the parameters
            MAMethod  maMethod  = (MAMethod )Enum.GetValues(typeof(MAMethod )).GetValue(parameters.ListParam[1].Index);
            MAMethod  slMethod  = (MAMethod )Enum.GetValues(typeof(MAMethod )).GetValue(parameters.ListParam[3].Index);
            BasePrice basePrice = (BasePrice)Enum.GetValues(typeof(BasePrice)).GetValue(parameters.ListParam[2].Index);
            int       nSlow     = (int)parameters.NumParam[0].Value;
            int       nFast     = (int)parameters.NumParam[1].Value;
            int       nSignal   = (int)parameters.NumParam[2].Value;
            int       iPrvs     = parameters.CheckParam[0].Checked ? 1 : 0;

            // Calculation
            int iFirstBar = nSlow + nFast + 2;

            float[] maSlow = MovingAverage(nSlow, 0, maMethod, Price(basePrice));
            float[] maFast = MovingAverage(nFast, 0, maMethod, Price(basePrice));

            float[] afMACD = new float[Bars];

            for (int iBar = nSlow - 1; iBar < Bars; iBar++)
                afMACD[iBar] = maFast[iBar] - maSlow[iBar];

            float[] maSignalLine = MovingAverage(nSignal, 0, slMethod, afMACD);

            // afHistogram reprezents the MACD oscillator
            float[] afHistogram = new float[Bars];
            for (int iBar = nSlow + nSignal - 1; iBar < Bars; iBar++)
                afHistogram[iBar] = afMACD[iBar] - maSignalLine[iBar];

            // Saving the components
            component = new IndicatorComp[5];

            component[0] = new IndicatorComp();
            component[0].CompName   = "Histogram";
            component[0].DataType   = IndComponentType.IndicatorValue;
            component[0].ChartType  = IndChartType.Histogram;
            component[0].FirstBar   = iFirstBar;
            component[0].Value      = afHistogram;

            component[1] = new IndicatorComp();
            component[1].CompName   = "Signal line";
            component[1].DataType   = IndComponentType.IndicatorValue;
            component[1].ChartType  = IndChartType.Line;
            component[1].ChartColor = Color.Yellow;
            component[1].FirstBar   = iFirstBar;
            component[1].Value      = maSignalLine;

            component[2] = new IndicatorComp();
            component[2].CompName   = "MACD line";
            component[2].DataType   = IndComponentType.IndicatorValue;
            component[2].ChartType  = IndChartType.Line;
            component[2].ChartColor = Color.Blue;
            component[2].FirstBar   = iFirstBar;
            component[2].Value      = afMACD;

            component[3] = new IndicatorComp();
            component[3].ChartType = IndChartType.NoChart;
            component[3].FirstBar  = iFirstBar;
            component[3].Value     = new float[Bars];

            component[4] = new IndicatorComp();
            component[4].ChartType = IndChartType.NoChart;
            component[4].FirstBar  = iFirstBar;
            component[4].Value     = new float[Bars];

            // Sets the component's type.
            if (slotType == SlotTypes.OpenFilter)
            {
                component[3].DataType = IndComponentType.AllowOpenLong;
                component[3].CompName = "Allows long positions opening";
                component[4].DataType = IndComponentType.AllowOpenShort;
                component[4].CompName = "Allows short positions opening";
            }
            else if (slotType == SlotTypes.CloseFilter)
            {
                component[3].DataType = IndComponentType.ForceCloseLong;
                component[3].CompName = "Forces long positions closing";
                component[4].DataType = IndComponentType.ForceCloseShort;
                component[4].CompName = "Forces short positions closing";
            }

            switch (parameters.ListParam[0].Text)
            {
                case "The MACD line rises":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = afMACD[iBar - iPrvs - 1] < afMACD[iBar - iPrvs] ? 1 : 0;
                        component[4].Value[iBar] = afMACD[iBar - iPrvs - 1] > afMACD[iBar - iPrvs] ? 1 : 0;
                    }
                    break;

                case "The MACD line falls":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = afMACD[iBar - iPrvs - 1] > afMACD[iBar - iPrvs] ? 1 : 0;
                        component[4].Value[iBar] = afMACD[iBar - iPrvs - 1] < afMACD[iBar - iPrvs] ? 1 : 0;
                    }
                    break;

                case "The MACD line is higher than zero":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = afMACD[iBar - iPrvs] > 0 ? 1 : 0;
                        component[4].Value[iBar] = afMACD[iBar - iPrvs] < 0 ? 1 : 0;
                    }
                    break;

                case "The MACD line is lower than zero":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = afMACD[iBar - iPrvs] < 0 ? 1 : 0;
                        component[4].Value[iBar] = afMACD[iBar - iPrvs] > 0 ? 1 : 0;
                    }
                    break;

                case "The MACD line crosses the zero line upward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afMACD[iBar - iPrvs - 1] < 0 && afMACD[iBar - iPrvs] > 0) ? 1 : 0;
                        component[4].Value[iBar] = (afMACD[iBar - iPrvs - 1] > 0 && afMACD[iBar - iPrvs] < 0) ? 1 : 0;
                    }
                    break;

                case "The MACD line crosses the zero line downward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afMACD[iBar - iPrvs - 1] > 0 && afMACD[iBar - iPrvs] < 0) ? 1 : 0;
                        component[4].Value[iBar] = (afMACD[iBar - iPrvs - 1] < 0 && afMACD[iBar - iPrvs] > 0) ? 1 : 0;
                    }
                    break;

                case "The MACD line changes its direction upward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afMACD[iBar - iPrvs - 2] > afMACD[iBar - iPrvs - 1] && afMACD[iBar - iPrvs - 1] < afMACD[iBar - iPrvs]) ? 1 : 0;
                        component[4].Value[iBar] = (afMACD[iBar - iPrvs - 2] < afMACD[iBar - iPrvs - 1] && afMACD[iBar - iPrvs - 1] > afMACD[iBar - iPrvs]) ? 1 : 0;
                    }
                    break;

                case "The MACD line changes its direction downward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afMACD[iBar - iPrvs - 2] < afMACD[iBar - iPrvs - 1] && afMACD[iBar - iPrvs - 1] > afMACD[iBar - iPrvs]) ? 1 : 0;
                        component[4].Value[iBar] = (afMACD[iBar - iPrvs - 2] > afMACD[iBar - iPrvs - 1] && afMACD[iBar - iPrvs - 1] < afMACD[iBar - iPrvs]) ? 1 : 0;
                    }
                    break;

                case "The MACD line crosses the Signal line upward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afHistogram[iBar - iPrvs - 1] < 0 && afHistogram[iBar - iPrvs] > 0) ? 1 : 0;
                        component[4].Value[iBar] = (afHistogram[iBar - iPrvs - 1] > 0 && afHistogram[iBar - iPrvs] < 0) ? 1 : 0;
                    }
                    break;

                case "The MACD line crosses the Signal line downward":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afHistogram[iBar - iPrvs - 1] > 0 && afHistogram[iBar - iPrvs] < 0) ? 1 : 0;
                        component[4].Value[iBar] = (afHistogram[iBar - iPrvs - 1] < 0 && afHistogram[iBar - iPrvs] > 0) ? 1 : 0;
                    }
                    break;

                case "The MACD line is higher than the Signal line":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afHistogram[iBar - iPrvs - 1] > 0) ? 1 : 0;
                        component[4].Value[iBar] = (afHistogram[iBar - iPrvs - 1] < 0) ? 1 : 0;
                    }
                    break;

                case "The MACD line is lower than the Signal line":
                    for (int iBar = iFirstBar; iBar < Bars; iBar++)
                    {
                        component[3].Value[iBar] = (afHistogram[iBar - iPrvs - 1] < 0) ? 1 : 0;
                        component[4].Value[iBar] = (afHistogram[iBar - iPrvs - 1] > 0) ? 1 : 0;
                    }
                    break;

                default:
                    break;
            }

            bIsCalculated = true;
        }
    }
}

Top