Source » Moving Average - 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-06-12

using System;
using System.Drawing;

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

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

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

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

            // The ComboBox parameters.
            parameters.ListParam[0].Caption = "Logic";

            if (slotType == SlotTypes.Open)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "Enter the market at the MA value "
                };

            else if (slotType == SlotTypes.OpenFilter)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "The Moving Average rises",
                    "The Moving Average falls",
                    "The bar opens above the MA value",
                    "The bar opens below the MA value",
                    "The position opens above the MA value",
                    "The position opens below the MA value",
                };

            else if (slotType == SlotTypes.Close)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "Exit the market at the MA value "
                };

            else if (slotType == SlotTypes.CloseFilter)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "The Moving Average rises",
                    "The Moving Average falls",
                    "The bar closes below the MA value",
                    "The bar closes above the MA value",
                };

            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 Moving Average";

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

            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 Average is based on";

            // The NumericUpDown parameters.
            parameters.NumParam[0].Caption   = "Period";
            parameters.NumParam[0].Value     = 21;
            parameters.NumParam[0].Min       = 1;
            parameters.NumParam[0].Max       = 200;
            parameters.NumParam[0].Enabled   = true;
            parameters.NumParam[0].ToolTip   = "The Moving Average period";

            parameters.NumParam[1].Caption   = "Shift";
            parameters.NumParam[1].Value     = 0;
            parameters.NumParam[1].Min       = 0;
            parameters.NumParam[1].Max       = 200;
            parameters.NumParam[1].Enabled   = true;
            parameters.NumParam[1].ToolTip   = "How many bars to shift with";

            // 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);
            BasePrice price    = (BasePrice)Enum.GetValues(typeof(BasePrice)).GetValue(parameters.ListParam[2].Index);
            int       iPeriod  = (int)parameters.NumParam[0].Value;
            int       iShift   = (int)parameters.NumParam[1].Value;
            int       iPrvs    = parameters.CheckParam[0].Checked ? 1 : 0;

            // TimeExecution
            if (price == BasePrice.Open && iPeriod == 1 && iShift == 0)
                timeExecution = TimeExecution.Opening;
            else if (price == BasePrice.Close && iPeriod == 1 && iShift == 0)
                timeExecution = TimeExecution.Closing;

            // Calculation
            float[] afMA = MovingAverage(iPeriod, iShift, maMethod, Price(price));
            int iFirstBar = iPeriod + iShift + 1 + iPrvs;

            // Saving the components
            if (slotType == SlotTypes.Open || slotType == SlotTypes.Close)
            {
                component = new IndicatorComp[2];
                component[1] = new IndicatorComp();
                component[1].Value = new float[Bars];
                for (int iBar = 2; iBar < Bars; iBar++)
                {
                    // Covers the cases when the price can pass through the MA without a signal
                    float fValue   = afMA[iBar - iPrvs];     // Current value
                    float fValue1  = afMA[iBar - iPrvs - 1]; // Previous value
                    float fTempVal = fValue;
                    if ((fValue1 > High[iBar - 1] && fValue < Low[iBar]) || // It jumps bellow the current bar
                        (fValue1 < Low[iBar - 1] && fValue > High[iBar]) || // It jumps above the current bar
                        (Close[iBar - 1] < fValue && fValue < Open[iBar])|| // Positive gap
                        (Close[iBar - 1] > fValue && fValue > Open[iBar]))  // Negative gap
                        fTempVal = Open[iBar];

                    component[1].Value[iBar] = fTempVal;
                }
            }
            else
            {
                component = new IndicatorComp[3];

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

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

            component[0] = new IndicatorComp();
            component[0].CompName   = "MA Value";
            component[0].DataType   = IndComponentType.IndicatorValue;
            component[0].ChartType  = IndChartType.Line;
            component[0].ChartColor = Color.Red;
            component[0].FirstBar   = iFirstBar;
            component[0].Value      = afMA;

            if (slotType == SlotTypes.Open)
            {
                component[1].CompName = "Position's opening price";
                component[1].DataType = IndComponentType.OpenPrice;
            }
            else if (slotType == SlotTypes.OpenFilter)
            {
                component[1].DataType  = IndComponentType.AllowOpenLong;
                component[1].CompName  = "Allows long positions opening";
                component[2].DataType  = IndComponentType.AllowOpenShort;
                component[2].CompName  = "Allows short positions opening";
            }
            else if (slotType == SlotTypes.Close)
            {
                component[1].CompName = "Position's closing price";
                component[1].DataType = IndComponentType.ClosePrice;
            }
            else if (slotType == SlotTypes.CloseFilter)
            {
                component[1].DataType  = IndComponentType.ForceCloseLong;
                component[1].CompName  = "Forces long positions closing";
                component[2].DataType  = IndComponentType.ForceCloseShort;
                component[2].CompName  = "Forces short positions closing";
            }

            if (slotType == SlotTypes.OpenFilter || slotType == SlotTypes.CloseFilter)
            {
                switch (parameters.ListParam[0].Text)
                {
                    case "The Moving Average rises":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = afMA[iBar - iPrvs - 1] < afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = afMA[iBar - iPrvs - 1] > afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The Moving Average falls":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = afMA[iBar - iPrvs - 1] > afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = afMA[iBar - iPrvs - 1] < afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar opens below the MA value":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = Open[iBar] < afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = Open[iBar] > afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar opens above the MA value":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = Open[iBar] > afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = Open[iBar] < afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The position opens above the MA value":
                        component[0].PosPriceDependence = PositionPriceDependence.BuyHigherSellLower;
                        component[0].UsePreviousBar     = iPrvs;
                        component[1].DataType           = IndComponentType.Other;
                        component[1].ShowInDynInfo      = false;
                        component[2].DataType           = IndComponentType.Other;
                        component[2].ShowInDynInfo      = false;
                        break;

                    case "The position opens below the MA value":
                        component[0].PosPriceDependence = PositionPriceDependence.BuyLowerSelHigher;
                        component[0].UsePreviousBar     = iPrvs;
                        component[1].DataType           = IndComponentType.Other;
                        component[1].ShowInDynInfo      = false;
                        component[2].DataType           = IndComponentType.Other;
                        component[2].ShowInDynInfo      = false;
                        break;

                    case "The bar closes below the MA value":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = Close[iBar] < afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = Close[iBar] > afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar closes above the MA value":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[1].Value[iBar] = Close[iBar] > afMA[iBar - iPrvs] ? 1 : 0;
                            component[2].Value[iBar] = Close[iBar] < afMA[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    default:
                        break;
                }
            }

            bIsCalculated = true;
        }
    }
}

Top