//============================================================== // Forex Strategy Builder // Copyright © Miroslav Popov. All rights reserved. //============================================================== // THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, // EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE. //============================================================== using System; using System.Drawing; using ForexStrategyBuilder.Infrastructure.Entities; using ForexStrategyBuilder.Infrastructure.Enums; using ForexStrategyBuilder.Infrastructure.Interfaces; namespace ForexStrategyBuilder.Indicators.Store { public class KeltnerChannel : Indicator { public KeltnerChannel() { IndicatorName = "Keltner Channel Crossover"; PossibleSlots = SlotTypes.OpenFilter | SlotTypes.CloseFilter; IndicatorAuthor = "Andrew Sumner"; IndicatorVersion = "2.5"; IndicatorDescription = "Compares channels."; } public override void Initialize(SlotTypes slotType) { SlotType = slotType; // The ComboBox parameters IndParam.ListParam[0].Caption = "Logic"; IndParam.ListParam[0].ItemList = new[] { "Fast Channel High crosses Slow Channel Low upward", "Fast Channel High crosses Slow Channel Low downward", "Fast Channel High crosses Slow Channel High upward", "Fast Channel High crosses Slow Channel High downward", "Fast Channel Low crosses Slow Channel Low upward", "Fast Channel Low crosses Slow Channel Low downward", "Fast Channel Low crosses Slow Channel High upward", "Fast Channel Low crosses Slow Channel High downward", "Fast Channel High is higher than Slow Channel Low", "Fast Channel High is higher than Slow Channel High", "Fast Channel Low is higher than Slow Channel Low", "Fast Channel Low is higher than Slow Channel High", "Fast Channel High is lower than Slow Channel Low", "Fast Channel High is lower than Slow Channel High", "Fast Channel Low is lower than Slow Channel Low", "Fast Channel Low is lower than Slow Channel High" }; IndParam.ListParam[0].Index = 0; IndParam.ListParam[0].Text = IndParam.ListParam[0].ItemList[IndParam.ListParam[0].Index]; IndParam.ListParam[0].Enabled = true; IndParam.ListParam[0].ToolTip = "Logic of application of the indicator."; IndParam.ListParam[2].Caption = "Base price"; IndParam.ListParam[2].ItemList = Enum.GetNames(typeof (BasePrice)); IndParam.ListParam[2].Index = (int) BasePrice.Close; IndParam.ListParam[2].Text = IndParam.ListParam[2].ItemList[IndParam.ListParam[2].Index]; IndParam.ListParam[2].Enabled = true; IndParam.ListParam[2].ToolTip = "The price the central Moving Average is based on."; IndParam.ListParam[3].Caption = "Fast Channel MA method"; IndParam.ListParam[3].ItemList = Enum.GetNames(typeof (MAMethod)); IndParam.ListParam[3].Index = (int) MAMethod.Exponential; IndParam.ListParam[3].Text = IndParam.ListParam[3].ItemList[IndParam.ListParam[3].Index]; IndParam.ListParam[3].Enabled = true; IndParam.ListParam[3].ToolTip = "The method of smoothing of Fast central Moving Average."; IndParam.ListParam[4].Caption = "Slow Channel MA method"; IndParam.ListParam[4].ItemList = Enum.GetNames(typeof (MAMethod)); IndParam.ListParam[4].Index = (int) MAMethod.Exponential; IndParam.ListParam[4].Text = IndParam.ListParam[4].ItemList[IndParam.ListParam[4].Index]; IndParam.ListParam[4].Enabled = true; IndParam.ListParam[4].ToolTip = "The method of smoothing of Slow central Moving Average."; // The NumericUpDown parameters IndParam.NumParam[0].Caption = "Fast MA period"; IndParam.NumParam[0].Value = 10; IndParam.NumParam[0].Min = 1; IndParam.NumParam[0].Max = 400; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The Slow Moving Average period."; IndParam.NumParam[1].Caption = "Slow MA period"; IndParam.NumParam[1].Value = 40; IndParam.NumParam[1].Min = 1; IndParam.NumParam[1].Max = 400; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "The Slow Moving Average period."; IndParam.NumParam[2].Caption = "Fast ATR period"; IndParam.NumParam[2].Value = 5; IndParam.NumParam[2].Min = 1; IndParam.NumParam[2].Max = 200; IndParam.NumParam[2].Point = 0; IndParam.NumParam[2].Enabled = true; IndParam.NumParam[2].ToolTip = "Fast Average True Range Period."; IndParam.NumParam[3].Caption = "Slow ATR period"; IndParam.NumParam[3].Value = 10; IndParam.NumParam[3].Min = 1; IndParam.NumParam[3].Max = 200; IndParam.NumParam[3].Point = 0; IndParam.NumParam[3].Enabled = true; IndParam.NumParam[3].ToolTip = "Slow Average True Range Period."; IndParam.NumParam[4].Caption = "Fast ATR multiplier"; IndParam.NumParam[4].Value = 2; IndParam.NumParam[4].Min = 0.1; IndParam.NumParam[4].Max = 10; IndParam.NumParam[4].Point = 1; IndParam.NumParam[4].Enabled = true; IndParam.NumParam[4].ToolTip = "Fast Average True Range Multiplier."; IndParam.NumParam[5].Caption = "Slow ATR multiplier"; IndParam.NumParam[5].Value = 2; IndParam.NumParam[5].Min = 0.1; IndParam.NumParam[5].Max = 10; IndParam.NumParam[5].Point = 1; IndParam.NumParam[5].Enabled = true; IndParam.NumParam[5].ToolTip = "Fast Average True Range Multiplier."; // The CheckBox parameters IndParam.CheckParam[0].Caption = "Use previous bar value"; IndParam.CheckParam[0].Enabled = true; IndParam.CheckParam[0].ToolTip = "Use the indicator value from the previous bar."; } public override void Calculate(IDataSet dataSet) { DataSet = dataSet; // Reading the parameters var price = (BasePrice) IndParam.ListParam[2].Index; var fastmaMethod = (MAMethod) IndParam.ListParam[3].Index; var fastnMA = (int) IndParam.NumParam[0].Value; var fastatrPeriod = (int) IndParam.NumParam[2].Value; var fastatrMultiplier = (double) IndParam.NumParam[4].Value; var slowmaMethod = (MAMethod) IndParam.ListParam[4].Index; var slownMA = (int) IndParam.NumParam[1].Value; var slowatrPeriod = (int) IndParam.NumParam[3].Value; var slowatrMultiplier = (double) IndParam.NumParam[5].Value; int previous = IndParam.CheckParam[0].Checked ? 1 : 0; // Calculation int iFirstBar = Math.Max(Math.Max(fastnMA, fastatrPeriod), Math.Max(slownMA, slowatrPeriod)) + previous + 2; double[] adMAFast = MovingAverage(fastnMA, 0, fastmaMethod, Price(price)); var adAtrFast = new double[Bars]; var adUpBandFast = new double[Bars]; var adDnBandFast = new double[Bars]; double[] adMASlow = MovingAverage(slownMA, 0, slowmaMethod, Price(price)); var adAtrSlow = new double[Bars]; var adUpBandSlow = new double[Bars]; var adDnBandSlow = new double[Bars]; for (int iBar = 3; iBar < Bars; iBar++) { adAtrFast[iBar] = Math.Max(Math.Abs(High[iBar-1] - Close[iBar - 2]), Math.Abs(Close[iBar - 2] - Low[iBar-1])); adAtrFast[iBar] = Math.Max(Math.Abs(High[iBar-1] - Low[iBar-1]), adAtrFast[iBar]); adAtrSlow[iBar] = Math.Max(Math.Abs(High[iBar-1] - Close[iBar - 2]), Math.Abs(Close[iBar - 2] - Low[iBar-1])); adAtrSlow[iBar] = Math.Max(Math.Abs(High[iBar-1] - Low[iBar-1]), adAtrSlow[iBar]); } adAtrFast = MovingAverage(fastatrPeriod, 0, fastmaMethod, adAtrFast); adAtrSlow = MovingAverage(slowatrPeriod, 0, slowmaMethod, adAtrSlow); for (int iBar = Math.Max(fastnMA, slownMA); iBar < Bars; iBar++) { adUpBandFast[iBar] = adMAFast[iBar] + adAtrFast[iBar]*fastatrMultiplier; adDnBandFast[iBar] = adMAFast[iBar] - adAtrFast[iBar]*fastatrMultiplier; adUpBandSlow[iBar] = adMASlow[iBar] + adAtrSlow[iBar]*slowatrMultiplier; adDnBandSlow[iBar] = adMASlow[iBar] - adAtrSlow[iBar]*slowatrMultiplier; } // Saving the components Component = new IndicatorComp[7]; Component[0] = new IndicatorComp { CompName = "Fast Upper Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = iFirstBar, Value = adUpBandFast }; Component[1] = new IndicatorComp { CompName = "Slow Upper Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Brown, FirstBar = iFirstBar, Value = adUpBandSlow }; Component[2] = new IndicatorComp { CompName = "Fast Lower Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = iFirstBar, Value = adDnBandFast }; Component[3] = new IndicatorComp { CompName = "Slow Lower Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Brown, FirstBar = iFirstBar, Value = adDnBandSlow }; Component[4] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = iFirstBar, Value = new double[Bars] }; Component[5] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = iFirstBar, Value = new double[Bars] }; Component[6] = new IndicatorComp { CompName = "Dummy component", ShowInDynInfo = false, ChartType = IndChartType.NoChart, FirstBar = iFirstBar, DataType = IndComponentType.IndicatorValue, Value = new double[Bars] }; // Sets the Component's type if (SlotType == SlotTypes.OpenFilter) { Component[4].DataType = IndComponentType.AllowOpenLong; Component[4].CompName = "Is long entry allowed"; Component[5].DataType = IndComponentType.AllowOpenShort; Component[5].CompName = "Is short entry allowed"; } else if (SlotType == SlotTypes.CloseFilter) { Component[4].DataType = IndComponentType.ForceCloseLong; Component[4].CompName = "Close out long position"; Component[5].DataType = IndComponentType.ForceCloseShort; Component[5].CompName = "Close out short position"; } switch (IndParam.ListParam[0].Text) { case "Fast Channel High crosses Slow Channel Low upward": IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High crosses Slow Channel High upward": IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low crosses Slow Channel Low upward": IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low crosses Slow Channel High upward": IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorUpwardLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High crosses Slow Channel Low downward": IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High crosses Slow Channel High downward": IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low crosses Slow Channel Low downward": IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low crosses Slow Channel High downward": IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorCrossesAnotherIndicatorDownwardLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High is higher than Slow Channel Low": IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High is higher than Slow Channel High": IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low is higher than Slow Channel Low": IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low is higher than Slow Channel High": IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorIsHigherThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High is lower than Slow Channel Low": IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel High is lower than Slow Channel High": IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[4], ref Component[6]); IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low is lower than Slow Channel Low": IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; case "Fast Channel Low is lower than Slow Channel High": IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adUpBandFast, adDnBandSlow, ref Component[4], ref Component[6]); IndicatorIsLowerThanAnotherIndicatorLogic(iFirstBar, previous, adDnBandFast, adUpBandSlow, ref Component[6], ref Component[5]); break; } } public override void SetDescription() { EntryFilterLongDescription = ToString() + "; Fast Channel "; EntryFilterShortDescription = ToString() + "; Fast Channel "; ExitFilterLongDescription = ToString() + "; Fast Channel "; ExitFilterShortDescription = ToString() + "; Fast Channel "; switch (IndParam.ListParam[0].Text) { case "Fast Channel High crosses Slow Channel Low upward": EntryFilterLongDescription += "High crosses above Slow Channel Low"; EntryFilterShortDescription = "High crosses under Slow Channel Low"; ExitFilterLongDescription += "High crosses above Slow Channel Low"; ExitFilterShortDescription = "High crosses under Slow Channel Low"; break; case "Fast Channel High crosses Slow Channel High upward": EntryFilterLongDescription += "High crosses above Slow Channel High"; EntryFilterShortDescription = "High crosses under Slow Channel High"; ExitFilterLongDescription += "High crosses above Slow Channel High"; ExitFilterShortDescription = "High crosses under Slow Channel High"; break; case "Fast Channel Low crosses Slow Channel Low upward": EntryFilterLongDescription += "Low crosses above Slow Channel Low"; EntryFilterShortDescription = "Low crosses under Slow Channel Low"; ExitFilterLongDescription += "Low crosses above Slow Channel Low"; ExitFilterShortDescription = "Low crosses under Slow Channel Low"; break; case "Fast Channel Low crosses Slow Channel High upward": EntryFilterLongDescription += "Low crosses above Slow Channel High"; EntryFilterShortDescription = "Low crosses under Slow Channel High"; ExitFilterLongDescription += "Low crosses above Slow Channel High"; ExitFilterShortDescription = "Low crosses under Slow Channel High"; break; case "Fast Channel High crosses Slow Channel Low downward": EntryFilterLongDescription += "High crosses under Slow Channel Low"; EntryFilterShortDescription = "High crosses above Slow Channel Low"; ExitFilterLongDescription += "High crosses under Slow Channel Low"; ExitFilterShortDescription = "High crosses above Slow Channel Low"; break; case "Fast Channel High crosses Slow Channel High downward": EntryFilterLongDescription += "High crosses under Slow Channel High"; EntryFilterShortDescription = "High crosses above Slow Channel High"; ExitFilterLongDescription += "High crosses under Slow Channel High"; ExitFilterShortDescription = "High crosses above Slow Channel High"; break; case "Fast Channel Low crosses Slow Channel Low downward": EntryFilterLongDescription += "Low crosses under Slow Channel Low"; EntryFilterShortDescription = "Low crosses above Slow Channel Low"; ExitFilterLongDescription += "Low crosses under Slow Channel Low"; ExitFilterShortDescription = "Low crosses above Slow Channel Low"; break; case "Fast Channel Low crosses Slow Channel High downward": EntryFilterLongDescription += "Low crosses under Slow Channel High"; EntryFilterShortDescription = "Low crosses above Slow Channel High"; ExitFilterLongDescription += "Low crosses under Slow Channel High"; ExitFilterShortDescription = "Low crosses above Slow Channel High"; break; case "Fast Channel High is higher than Slow Channel Low": EntryFilterLongDescription += "High is above Slow Channel Low"; EntryFilterShortDescription = "High is under Slow Channel Low"; ExitFilterLongDescription += "High is above Slow Channel Low"; ExitFilterShortDescription = "High is under Slow Channel Low"; break; case "Fast Channel High is higher than Slow Channel High": EntryFilterLongDescription += "High is above Slow Channel High"; EntryFilterShortDescription = "High is under Slow Channel High"; ExitFilterLongDescription += "High is above Slow Channel High"; ExitFilterShortDescription = "High is under Slow Channel High"; break; case "Fast Channel Low is higher than Slow Channel Low": EntryFilterLongDescription += "Low is above Slow Channel Low"; EntryFilterShortDescription = "Low is under Slow Channel Low"; ExitFilterLongDescription += "Low is above Slow Channel Low"; ExitFilterShortDescription = "Low is under Slow Channel Low"; break; case "Fast Channel Low is higher than Slow Channel High": EntryFilterLongDescription += "Low is above Slow Channel High"; EntryFilterShortDescription = "Low is under Slow Channel High"; ExitFilterLongDescription += "Low is above Slow Channel High"; ExitFilterShortDescription = "Low is under Slow Channel High"; break; case "Fast Channel High is lower than Slow Channel Low": EntryFilterLongDescription += "High is under Slow Channel Low"; EntryFilterShortDescription = "High is above Slow Channel Low"; ExitFilterLongDescription += "High is under Slow Channel Low"; ExitFilterShortDescription = "High is above Slow Channel Low"; break; case "Fast Channel High is lower than Slow Channel High": EntryFilterLongDescription += "High is under Slow Channel High"; EntryFilterShortDescription = "High is above Slow Channel High"; ExitFilterLongDescription += "High is under Slow Channel High"; ExitFilterShortDescription = "High is above Slow Channel High"; break; case "Fast Channel Low is lower than Slow Channel Low": EntryFilterLongDescription += "Low is under Slow Channel High"; EntryFilterShortDescription = "Low is above Slow Channel High"; ExitFilterLongDescription += "Low is under Slow Channel High"; ExitFilterShortDescription = "Low is above Slow Channel High"; break; case "Fast Channel Low is lower than Slow Channel High": EntryFilterLongDescription += "Low is under Slow Channel High"; EntryFilterShortDescription = "Low is above Slow Channel High"; ExitFilterLongDescription += "Low is under Slow Channel High"; ExitFilterShortDescription = "Low is above Slow Channel High"; break; } } public override string ToString() { return IndicatorName + (IndParam.CheckParam[0].Checked ? "* (" : " (") + IndParam.ListParam[1].Text + ", " + // Price IndParam.ListParam[3].Text + ", " + // Fast Price IndParam.ListParam[4].Text + ", " + // Slow Price IndParam.NumParam[0].ValueToString + ", " + // Fast MA period IndParam.NumParam[1].ValueToString + ")"; // Slow MA Period } } }