//============================================================== // 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 PsrCrossover : Indicator { public PsrCrossover() { IndicatorName = "Parabolic SAR Combo Crossover"; PossibleSlots = SlotTypes.OpenFilter | SlotTypes.CloseFilter; IndicatorAuthor = "Ahmed Alhoseny"; IndicatorVersion = "2.0"; IndicatorDescription = "Custom Indicator."; } public override void Initialize(SlotTypes slotType) { SlotType = slotType; // The ComboBox parameters IndParam.ListParam[0].Caption = "Logic"; IndParam.ListParam[0].ItemList = new[] { "Psar1 crosses Psar2 upward", "Psar1 crosses Psar2 downward", "Psar1 is higher than Psar2", "Psar1 is lower than Psar2" }; 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."; // The NumericUpDown parameters IndParam.NumParam[0].Caption = "Starting AF1"; IndParam.NumParam[0].Value = 0.02; IndParam.NumParam[0].Min = 0.00; IndParam.NumParam[0].Max = 1.00; IndParam.NumParam[0].Point = 2; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The starting value of Acceleration Factor."; IndParam.NumParam[1].Caption = "Starting AF2"; IndParam.NumParam[1].Value = 0.02; IndParam.NumParam[1].Min = 0.00; IndParam.NumParam[1].Max = 1.00; IndParam.NumParam[1].Point = 2; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "The starting value of Acceleration Factor."; IndParam.NumParam[2].Caption = "Increment1"; IndParam.NumParam[2].Value = 0.02; IndParam.NumParam[2].Min = 0.01; IndParam.NumParam[2].Max = 1.00; IndParam.NumParam[2].Point = 2; IndParam.NumParam[2].Enabled = true; IndParam.NumParam[2].ToolTip = "Increment value."; IndParam.NumParam[3].Caption = "Increment2"; IndParam.NumParam[3].Value = 0.02; IndParam.NumParam[3].Min = 0.01; IndParam.NumParam[3].Max = 1.00; IndParam.NumParam[3].Point = 2; IndParam.NumParam[3].Enabled = true; IndParam.NumParam[3].ToolTip = "Increment value."; IndParam.NumParam[4].Caption = "Maximum AF1"; IndParam.NumParam[4].Value = 0.01; IndParam.NumParam[4].Min = 0.01; IndParam.NumParam[4].Max = 2.00; IndParam.NumParam[4].Point = 2; IndParam.NumParam[4].Enabled = true; IndParam.NumParam[4].ToolTip = "The maximum value of the Acceleration Factor."; IndParam.NumParam[5].Caption = "Maximum AF2"; IndParam.NumParam[5].Value = 0.01; IndParam.NumParam[5].Min = 0.01; IndParam.NumParam[5].Max = 2.00; IndParam.NumParam[5].Point = 2; IndParam.NumParam[5].Enabled = true; IndParam.NumParam[5].ToolTip = "The maximum value of the Acceleration Factor."; // 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 double dAfMin1 = IndParam.NumParam[0].Value; double dAfMin2 = IndParam.NumParam[1].Value; double dAfInc1 = IndParam.NumParam[2].Value; double dAfInc2 = IndParam.NumParam[3].Value; double dAfMax1 = IndParam.NumParam[4].Value; double dAfMax2 = IndParam.NumParam[5].Value; int previous = IndParam.CheckParam[0].Checked ? 1 : 0; // Reading the parameters double dPExtr1; double dPExtr2; double dadPsarNew1 = 0; double dadPsarNew2 = 0; var aiDir1 = new int[Bars]; var aiDir2 = new int[Bars]; var adPsar1 = new double[Bars]; var adPsar2 = new double[Bars]; //---- Calculating the initial values adPsar1[0] = 0; adPsar2[0] = 0; double dAf1 = dAfMin1; double dAf2 = dAfMin2; int intDirNew1 = 0; int intDirNew2 = 0; if (Close[1] > Open[0]) { aiDir1[0] = 1; aiDir2[0] = 1; aiDir1[1] = 1; aiDir2[1] = 1; dPExtr1 = Math.Max(High[0], High[1]); dPExtr2 = Math.Max(High[0], High[1]); adPsar1[1] = Math.Min(Low[0], Low[1]); adPsar2[1] = Math.Min(Low[0], Low[1]); } else { aiDir1[0] = -1; aiDir2[0] = -1; aiDir1[1] = -1; aiDir2[1] = -1; dPExtr1 = Math.Min(Low[0], Low[1]); dPExtr2 = Math.Min(Low[0], Low[1]); adPsar1[1] = Math.Max(High[0], High[1]); adPsar2[1] = Math.Max(High[0], High[1]); } for (int iBar = 2; iBar < Bars; iBar++) { //---- adPsar for the current period if (intDirNew1 != 0) { // The direction was changed during the last period aiDir1[iBar] = intDirNew1; intDirNew1 = 0; adPsar1[iBar] = dadPsarNew1 + dAf1 * (dPExtr1 - dadPsarNew1); } else { aiDir1[iBar] = aiDir1[iBar - 1]; adPsar1[iBar] = adPsar1[iBar - 1] + dAf1 * (dPExtr1 - adPsar1[iBar - 1]); } //---------------------------------------------------------------------------- if (intDirNew2 != 0) { // The direction was changed during the last period aiDir2[iBar] = intDirNew2; intDirNew2 = 0; adPsar2[iBar] = dadPsarNew2 + dAf2 * (dPExtr2 - dadPsarNew2); } else { aiDir2[iBar] = aiDir2[iBar - 1]; adPsar2[iBar] = adPsar2[iBar - 1] + dAf2 * (dPExtr2 - adPsar2[iBar - 1]); } // adPsar has to be out of the previous two bars limits if (aiDir1[iBar] > 0 && adPsar1[iBar] > Math.Min(Low[iBar - 1], Low[iBar - 2])) adPsar1[iBar] = Math.Min(Low[iBar - 1], Low[iBar - 2]); else if (aiDir1[iBar] < 0 && adPsar1[iBar] < Math.Max(High[iBar - 1], High[iBar - 2])) adPsar1[iBar] = Math.Max(High[iBar - 1], High[iBar - 2]); //------------------------------------------------------------------------------------------- if (aiDir2[iBar] > 0 && adPsar2[iBar] > Math.Min(Low[iBar - 1], Low[iBar - 2])) adPsar2[iBar] = Math.Min(Low[iBar - 1], Low[iBar - 2]); else if (aiDir2[iBar] < 0 && adPsar2[iBar] < Math.Max(High[iBar - 1], High[iBar - 2])) adPsar2[iBar] = Math.Max(High[iBar - 1], High[iBar - 2]); //---- adPsar for the next period // Calculation of the new values of flPExtr and flAF // if there is a new extreme price in the adPsar direction if (aiDir1[iBar] > 0 && High[iBar] > dPExtr1) { dPExtr1 = High[iBar]; dAf1 = Math.Min(dAf1 + dAfInc1, dAfMax1); } if (aiDir1[iBar] < 0 && Low[iBar] < dPExtr1) { dPExtr1 = Low[iBar]; dAf1 = Math.Min(dAf1 + dAfInc1, dAfMax1); } //------------------------------------------- if (aiDir2[iBar] > 0 && High[iBar] > dPExtr2) { dPExtr2 = High[iBar]; dAf2 = Math.Min(dAf2 + dAfInc2, dAfMax2); } if (aiDir2[iBar] < 0 && Low[iBar] < dPExtr2) { dPExtr2 = Low[iBar]; dAf2 = Math.Min(dAf2 + dAfInc2, dAfMax2); } // Whether the price reaches adPsar if (Low[iBar] <= adPsar1[iBar] && adPsar1[iBar] <= High[iBar]) { intDirNew1 = -aiDir1[iBar]; dadPsarNew1 = dPExtr1; dAf1 = dAfMin1; dPExtr1 = intDirNew1 > 0 ? High[iBar] : Low[iBar]; } //--------------------------------------------------------------- if (Low[iBar] <= adPsar2[iBar] && adPsar2[iBar] <= High[iBar]) { intDirNew2 = -aiDir2[iBar]; dadPsarNew2 = dPExtr2; dAf2 = dAfMin2; dPExtr2 = intDirNew2 > 0 ? High[iBar] : Low[iBar]; } } const int firstBar = 8 ; var adMAOscillator = new double[Bars]; for (int iBar = 8; iBar < Bars; iBar++) adMAOscillator[iBar] = adPsar1[iBar] - adPsar2[iBar]; // Saving the components Component = new IndicatorComp[4]; Component[0] = new IndicatorComp { CompName = "Fast Moving Average", ChartColor = Color.Goldenrod, DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, FirstBar = 8, Value = adPsar1 }; Component[1] = new IndicatorComp { CompName = "Slow Moving Average", ChartColor = Color.IndianRed, DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, FirstBar = 8, Value = adPsar2 }; Component[2] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = 8, Value = new double[Bars] }; Component[3] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = 8, Value = new double[Bars] }; // Sets the Component's type if (SlotType == SlotTypes.OpenFilter) { Component[2].DataType = IndComponentType.AllowOpenLong; Component[2].CompName = "Is long entry allowed"; Component[3].DataType = IndComponentType.AllowOpenShort; Component[3].CompName = "Is short entry allowed"; } else if (SlotType == SlotTypes.CloseFilter) { Component[2].DataType = IndComponentType.ForceCloseLong; Component[2].CompName = "Close out long position"; Component[3].DataType = IndComponentType.ForceCloseShort; Component[3].CompName = "Close out short position"; } // Calculation of the logic var indLogic = IndicatorLogic.It_does_not_act_as_a_filter; switch (IndParam.ListParam[0].Text) { case "Psar1 crosses Psar2 upward": indLogic = IndicatorLogic.The_indicator_crosses_the_level_line_upward; break; case "Psar1 crosses Psar2 downward": indLogic = IndicatorLogic.The_indicator_crosses_the_level_line_downward; break; case "Psar1 is higher than Psar2": indLogic = IndicatorLogic.The_indicator_is_higher_than_the_level_line; break; case "Psar1 is lower than Psar2": indLogic = IndicatorLogic.The_indicator_is_lower_than_the_level_line; break; } OscillatorLogic(8, previous, adMAOscillator, 0, 0, ref Component[2], ref Component[3], indLogic); } public override void SetDescription() { EntryFilterLongDescription = ToString() + "; Psar1 "; EntryFilterShortDescription = ToString() + "; Psar1 "; ExitFilterLongDescription = ToString() + "; Psar1 "; ExitFilterShortDescription = ToString() + "; Psar1 "; switch (IndParam.ListParam[0].Text) { case "Psar1 crosses Psar2 upward": EntryFilterLongDescription += "crosses Psar2 upward"; EntryFilterShortDescription += "crosses Psar2 downward"; ExitFilterLongDescription += "crosses Psar2 upward"; ExitFilterShortDescription += "crosses Psar2 downward"; break; case "Psar1 crosses Psar2 downward": EntryFilterLongDescription += "crosses Psar2 downward"; EntryFilterShortDescription += "crosses Psar2 upward"; ExitFilterLongDescription += "crosses Psar2 downward"; ExitFilterShortDescription += "crosses Psar2 upward"; break; case "Psar1 is higher than Psar2": EntryFilterLongDescription += "is higher than Psar2"; EntryFilterShortDescription += "is lower than Psar2"; ExitFilterLongDescription += "is higher than Psar2"; ExitFilterShortDescription += "is lower than Psar2"; break; case "Psar1 is lower than Psar2": EntryFilterLongDescription += "is lower than Psar2"; EntryFilterShortDescription += "is higher than Psar2"; ExitFilterLongDescription += "is lower than Psar2"; ExitFilterShortDescription += "is higher than Psar2"; break; } } public override string ToString() { return IndicatorName + (IndParam.CheckParam[0].Checked ? "* (" : " (") + IndParam.ListParam[1].Text + ", " + // Price IndParam.ListParam[3].Text + ", " + // Psar1 Method IndParam.ListParam[4].Text + ", " + // Psar2 Method IndParam.NumParam[0].ValueToString + ", " + // Psar1 period IndParam.NumParam[1].ValueToString + ", " + // Psar2 period IndParam.NumParam[2].ValueToString + ", " + // Psar1 shift IndParam.NumParam[3].ValueToString + ")"; // Psar2 shift } } }