Source » Starc Bands - 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-10-04

using System;
using System.Drawing;

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

        /// <summary>
        /// Sets the default parameters for the designated slot type.
        /// </summary>
        /// <param name="slotType">The slot type.</param>
        public Starc_Bands(SlotTypes slotType)
        {
            sIndicatorName  = "Starc Bands";
            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 long at the Up Band",
                    "Enter long at the Down Band"
                };

            else if (slotType == SlotTypes.OpenFilter)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "The bar opens below the Up Band",
                    "The bar opens above the Up Band",
                    "The bar opens below the Down Band",
                    "The bar opens above the Down Band",
                    "The position opens below the Up Band",
                    "The position opens above the Up Band",
                    "The position opens below the Down Band",
                    "The position opens above the Down Band"
                };

            else if (slotType == SlotTypes.Close)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "Exit long at the Up Band",
                    "Exit long at the Down Band"
                };

            else if (slotType == SlotTypes.CloseFilter)
                parameters.ListParam[0].ItemList = new string[]
                {
                    "The bar closes below the Up Band",
                    "The bar closes above the Up Band",
                    "The bar closes below the Down Band",
                    "The bar closes above the Down Band"
                };

            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    = 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 smoothing of central Moving Average";

            parameters.ListParam[2].Caption  = "Base price";
            parameters.ListParam[2].ItemList = new string [] {"Close"};
            parameters.ListParam[2].Index    = 0;
            parameters.ListParam[2].Text     = "Close";
            parameters.ListParam[2].Enabled  = true;
            parameters.ListParam[2].ToolTip  = "The price the central Moving Average is based on";

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

            parameters.NumParam[1].Caption = "Multiplier";
            parameters.NumParam[1].Value   = 2f;
            parameters.NumParam[1].Min     = 1;
            parameters.NumParam[1].Max     = 5;
            parameters.NumParam[1].Point   = 2;
            parameters.NumParam[1].Enabled = true;
            parameters.NumParam[1].ToolTip = "Determines the width of the Starc Bands";

            // 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.Close;
            int       nMA      = (int)parameters.NumParam[0].Value;
            float     fMpl     = parameters.NumParam[1].Value;
            int       iPrvs    = parameters.CheckParam[0].Checked ? 1 : 0;
    
            // Calculation
            float[] afPrice   = Price(price);
            float[] afMA      = MovingAverage(nMA, 0, maMethod, afPrice);
            float[] afUpBand  = new float[Bars];
            float[] afDnBand  = new float[Bars];

            int iFirstBar = nMA + iPrvs + 1;

            float[] afATR = new float[Bars];

            for (int iBar = 1; iBar < Bars; iBar++)
            {
                afATR[iBar] = Math.Max(Math.Abs(High[iBar] - Close[iBar - 1]), Math.Abs(Close[iBar - 1] - Low[iBar]));
                afATR[iBar] = Math.Max(Math.Abs(High[iBar] - Low[iBar]), afATR[iBar]);
            }

            afATR = MovingAverage(nMA, 0, maMethod, afATR);

            for (int iBar = nMA; iBar < Bars; iBar++)
            {
                afUpBand[iBar] = afMA[iBar] + fMpl * afATR[iBar];
                afDnBand[iBar] = afMA[iBar] - fMpl * afATR[iBar];
            }

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

            component[0] = new IndicatorComp();
            component[0].CompName   = "Up Band";
            component[0].DataType   = IndComponentType.IndicatorValue;
            component[0].ChartType  = IndChartType.Line;
            component[0].ChartColor = Color.Blue;
            component[0].FirstBar   = iFirstBar;
            component[0].Value      = afUpBand;

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

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

            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.Open)
            {
                component[3].DataType = IndComponentType.OpenLongPrice;
                component[3].CompName = "Long positions opening price";
                component[4].DataType = IndComponentType.OpenShortPrice;
                component[4].CompName = "Short positions opening price";
            }
            else 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.Close)
            {
                component[3].DataType = IndComponentType.CloseLongPrice;
                component[3].CompName = "Long positions closing price";
                component[4].DataType = IndComponentType.CloseShortPrice;
                component[4].CompName = "Short positions closing price";
            }
            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";
            }

            if (slotType == SlotTypes.Open || slotType == SlotTypes.Close)
            {
                if (nMA > 1)
                {
                    for (int iBar = 2; iBar < Bars; iBar++)
                    {
                        // Covers the cases when the price can pass through the band without a signal
                        float fValueUp   = afUpBand[iBar - iPrvs];     // Current value
                        float fValueUp1  = afUpBand[iBar - iPrvs - 1]; // Previous value
                        float fTempValUp = fValueUp;

                        if ((fValueUp1 > High[iBar - 1] && fValueUp < Low[iBar])  || // It jumps below the current bar
                            (fValueUp1 < Low[iBar  - 1] && fValueUp > High[iBar]) || // It jumps above the current bar
                            (Close[iBar - 1] < fValueUp && fValueUp < Open[iBar]) || // Positive gap
                            (Close[iBar - 1] > fValueUp && fValueUp > Open[iBar]))   // Negative gap
                            fTempValUp = Open[iBar];

                        float fValueDown   = afDnBand[iBar - iPrvs];     // Current value
                        float fValueDown1  = afDnBand[iBar - iPrvs - 1]; // Previous value
                        float fTempValDown = fValueDown;

                        if ((fValueDown1 > High[iBar - 1] && fValueDown < Low[iBar])  || // It jumps below the current bar
                            (fValueDown1 < Low[iBar  - 1] && fValueDown > High[iBar]) || // It jumps above the current bar
                            (Close[iBar - 1] < fValueDown && fValueDown < Open[iBar]) || // Positive gap
                            (Close[iBar - 1] > fValueDown && fValueDown > Open[iBar]))   // Negative gap
                            fTempValDown = Open[iBar];

                        if (parameters.ListParam[0].Text == "Enter long at the Up Band" ||
                            parameters.ListParam[0].Text == "Exit long at the Up Band")
                        {
                            component[3].Value[iBar] = fTempValUp;
                            component[4].Value[iBar] = fTempValDown;
                        }
                        else
                        {
                            component[3].Value[iBar] = fTempValDown;
                            component[4].Value[iBar] = fTempValUp;
                        }
                    }
                }
                else
                {
                    for (int iBar = 2; iBar < Bars; iBar++)
                    {
                        if (parameters.ListParam[0].Text == "Enter long at the Up Band" ||
                            parameters.ListParam[0].Text == "Exit long at the Up Band")
                        {
                            component[3].Value[iBar] = afUpBand[iBar - iPrvs];
                            component[4].Value[iBar] = afDnBand[iBar - iPrvs];
                        }
                        else
                        {
                            component[3].Value[iBar] = afDnBand[iBar - iPrvs];
                            component[4].Value[iBar] = afUpBand[iBar - iPrvs];
                        }
                    }
                }
            }
            else
            {
                switch (parameters.ListParam[0].Text)
                {
                    case "The bar opens below the Up Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Open[iBar] < afUpBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Open[iBar] > afDnBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar opens above the Up Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Open[iBar] > afUpBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Open[iBar] < afDnBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar opens below the Down Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Open[iBar] < afDnBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Open[iBar] > afUpBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar opens above the Down Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Open[iBar] > afDnBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Open[iBar] < afUpBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The position opens above the Up Band":
                        component[0].PosPriceDependence = PositionPriceDependence.PriceBuyHigher;
                        component[2].PosPriceDependence = PositionPriceDependence.PriceSellLower;
                        component[0].UsePreviousBar = iPrvs;
                        component[2].UsePreviousBar = iPrvs;
                        component[3].DataType = IndComponentType.Other;
                        component[4].DataType = IndComponentType.Other;
                        component[3].ShowInDynInfo = false;
                        component[4].ShowInDynInfo = false;
                        break;

                    case "The position opens below the Up Band":
                        component[0].PosPriceDependence = PositionPriceDependence.PriceBuyLower;
                        component[2].PosPriceDependence = PositionPriceDependence.PriceSellHigher;
                        component[0].UsePreviousBar = iPrvs;
                        component[2].UsePreviousBar = iPrvs;
                        component[3].DataType = IndComponentType.Other;
                        component[4].DataType = IndComponentType.Other;
                        component[3].ShowInDynInfo = false;
                        component[4].ShowInDynInfo = false;
                        break;

                    case "The position opens above the Down Band":
                        component[0].PosPriceDependence = PositionPriceDependence.PriceSellLower;
                        component[2].PosPriceDependence = PositionPriceDependence.PriceBuyHigher;
                        component[0].UsePreviousBar = iPrvs;
                        component[2].UsePreviousBar = iPrvs;
                        component[3].DataType = IndComponentType.Other;
                        component[4].DataType = IndComponentType.Other;
                        component[3].ShowInDynInfo = false;
                        component[4].ShowInDynInfo = false;
                        break;

                    case "The position opens below the Down Band":
                        component[0].PosPriceDependence = PositionPriceDependence.PriceSellHigher;
                        component[2].PosPriceDependence = PositionPriceDependence.PriceBuyLower;
                        component[0].UsePreviousBar = iPrvs;
                        component[2].UsePreviousBar = iPrvs;
                        component[3].DataType = IndComponentType.Other;
                        component[4].DataType = IndComponentType.Other;
                        component[3].ShowInDynInfo = false;
                        component[4].ShowInDynInfo = false;
                        break;

                    case "The bar closes below the Up Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Close[iBar] < afUpBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Close[iBar] > afDnBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar closes above the Up Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Close[iBar] > afUpBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Close[iBar] < afDnBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar closes below the Down Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Close[iBar] < afDnBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Close[iBar] > afUpBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    case "The bar closes above the Down Band":
                        for (int iBar = iFirstBar; iBar < Bars; iBar++)
                        {
                            component[3].Value[iBar] = Close[iBar] > afDnBand[iBar - iPrvs] ? 1 : 0;
                            component[4].Value[iBar] = Close[iBar] < afUpBand[iBar - iPrvs] ? 1 : 0;
                        }
                        break;

                    default:
                        break;
                }
            }

            bIsCalculated = true;

            return;
        }
    }
}

Top