SessionVWAPStochasticStepped by Naya

556 downloads / 288 views / Created: 13.06.2025
 Average Rating: 0

Indicator Description

SessionVWAPStochasticStepped

Comments

using System; using System.Drawing; using System.Collections.Generic; using ForexStrategyBuilder.Infrastructure.Entities; using ForexStrategyBuilder.Infrastructure.Enums; using ForexStrategyBuilder.Infrastructure.Interfaces; namespace ForexStrategyBuilder.Indicators.Custom { public class SessionVWAPStochasticStepped : Indicator { public SessionVWAPStochasticStepped() { IndicatorName = "SessionVWAPStochasticStepped"; PossibleSlots = SlotTypes.OpenFilter | SlotTypes.CloseFilter; SeparatedChart = true; SeparatedChartMinValue = 0; SeparatedChartMaxValue = 100; IndicatorAuthor = "NAYA,+237674724684"; IndicatorVersion = "1.0"; IndicatorDescription = "Stochastic calculated from SessionVWAPStepped price with stepped reset periods."; } public override void Initialize(SlotTypes slotType) { SlotType = slotType; // 1) Logic selection IndParam.ListParam[0].Caption = "Logic"; IndParam.ListParam[0].ItemList = new[] { "Slow %D rises", "Slow %D falls", "Slow %D is higher than Level line", "Slow %D is lower than Level line", "Slow %D crosses Level line upward", "Slow %D crosses Level line downward", "Slow %D changes its direction upward", "Slow %D changes its direction downward", "%K is higher than Slow %D", "%K is lower than Slow %D", "%K crosses Slow %D upward", "%K crosses Slow %D downward" }; IndParam.ListParam[0].Index = 0; IndParam.ListParam[0].Text = IndParam.ListParam[0].ItemList[0]; IndParam.ListParam[0].Enabled = true; IndParam.ListParam[0].ToolTip = "Logic of application of the indicator."; // 2) Anchor Hour (0-23) IndParam.ListParam[1].Caption = "Anchor Hour (0-23)"; var hourList = new List(); for (int h = 0; h <= 23; h++) hourList.Add(h.ToString("00")); IndParam.ListParam[1].ItemList = hourList.ToArray(); IndParam.ListParam[1].Index = 0; IndParam.ListParam[1].Text = IndParam.ListParam[1].ItemList[0]; IndParam.ListParam[1].Enabled = true; IndParam.ListParam[1].ToolTip = "Hour component of the anchor time (0-23)."; // 3) Anchor Minute (0-45 by 15) IndParam.ListParam[2].Caption = "Anchor Minute"; var minuteList = new List(); for (int m = 0; m <= 45; m += 15) minuteList.Add(m.ToString("00")); IndParam.ListParam[2].ItemList = minuteList.ToArray(); IndParam.ListParam[2].Index = 0; IndParam.ListParam[2].Text = IndParam.ListParam[2].ItemList[0]; IndParam.ListParam[2].Enabled = true; IndParam.ListParam[2].ToolTip = "Minute component of the anchor time (0-45 by 15)."; // 4) Reset Period (minutes) stepping 15-1440 by 15 IndParam.ListParam[3].Caption = "Reset Period (minutes)"; var resetList = new List(); for (int m = 60; m <= 1440; m += 30) resetList.Add(m.ToString()); IndParam.ListParam[3].ItemList = resetList.ToArray(); int defaultResetIndex = resetList.IndexOf("60"); if (defaultResetIndex < 0) defaultResetIndex = 3; IndParam.ListParam[3].Index = defaultResetIndex; IndParam.ListParam[3].Text = resetList[defaultResetIndex]; IndParam.ListParam[3].Enabled = true; IndParam.ListParam[3].ToolTip = "Select how many minutes before VWAP resets (15-1440 by 15)."; // 5) %K Period IndParam.NumParam[0].Caption = "%K Period"; IndParam.NumParam[0].Value = 5; IndParam.NumParam[0].Min = 2; IndParam.NumParam[0].Max = 30; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The period of %K calculation."; // 6) Fast %D Period IndParam.NumParam[1].Caption = "Fast %D Period"; IndParam.NumParam[1].Value = 3; IndParam.NumParam[1].Min = 2; IndParam.NumParam[1].Max = 30; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "The period of Fast %D calculation."; // 7) Slow %D Period IndParam.NumParam[2].Caption = "Slow %D Period"; IndParam.NumParam[2].Value = 3; IndParam.NumParam[2].Min = 2; IndParam.NumParam[2].Max = 30; IndParam.NumParam[2].Enabled = true; IndParam.NumParam[2].ToolTip = "The period of Slow %D calculation."; // 8) Level IndParam.NumParam[3].Caption = "Level"; IndParam.NumParam[3].Value = 20; IndParam.NumParam[3].Min = 1; IndParam.NumParam[3].Max = 100; IndParam.NumParam[3].Enabled = true; IndParam.NumParam[3].ToolTip = "A critical level (for appropriate logic)."; // 9) Use previous bar value 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; // Read parameters int anchorHour = int.Parse(IndParam.ListParam[1].Text); int anchorMinute = int.Parse(IndParam.ListParam[2].Text); int resetPeriod = int.Parse(IndParam.ListParam[3].Text); int periodK = (int)IndParam.NumParam[0].Value; int periodDFast = (int)IndParam.NumParam[1].Value; int periodDSlow = (int)IndParam.NumParam[2].Value; double level = IndParam.NumParam[3].Value; int previous = IndParam.CheckParam[0].Checked ? 1 : 0; // First calculate SessionVWAPStepped values double[] vwapPrice = CalculateVWAP(anchorHour, anchorMinute, resetPeriod); // Then calculate Stochastic from VWAP prices double[] adK, adDFast, adDSlow; CalculateStochastic(vwapPrice, periodK, periodDFast, periodDSlow, out adK, out adDFast, out adDSlow); // Prepare components int firstBar = periodK + periodDFast + periodDSlow + 3; Component = new IndicatorComp[5]; // %K line Component[0] = new IndicatorComp { CompName = "%K", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Brown, FirstBar = firstBar, Value = adK }; // Fast %D line Component[1] = new IndicatorComp { CompName = "Fast %D", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Gold, FirstBar = firstBar, Value = adDFast }; // Slow %D line Component[2] = new IndicatorComp { CompName = "Slow %D", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = firstBar, Value = adDSlow }; // Filter components Component[3] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = firstBar, Value = new double[Bars] }; Component[4] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = firstBar, Value = new double[Bars] }; // Set component types based on slot if (SlotType == SlotTypes.OpenFilter) { Component[3].DataType = IndComponentType.AllowOpenLong; Component[3].CompName = "Is long entry allowed"; Component[4].DataType = IndComponentType.AllowOpenShort; Component[4].CompName = "Is short entry allowed"; } else if (SlotType == SlotTypes.CloseFilter) { Component[3].DataType = IndComponentType.ForceCloseLong; Component[3].CompName = "Close out long position"; Component[4].DataType = IndComponentType.ForceCloseShort; Component[4].CompName = "Close out short position"; } // Apply logic IndicatorLogic logicRule = IndicatorLogic.It_does_not_act_as_a_filter; if (IndParam.ListParam[0].Text == "%K crosses Slow %D upward") { SpecialValues = new double[1] { 50 }; IndicatorCrossesAnotherIndicatorUpwardLogic(firstBar, previous, adK, adDSlow, ref Component[3], ref Component[4]); return; } else if (IndParam.ListParam[0].Text == "%K crosses Slow %D downward") { SpecialValues = new double[1] { 50 }; IndicatorCrossesAnotherIndicatorDownwardLogic(firstBar, previous, adK, adDSlow, ref Component[3], ref Component[4]); return; } else if (IndParam.ListParam[0].Text == "%K is higher than Slow %D") { SpecialValues = new double[1] { 50 }; IndicatorIsHigherThanAnotherIndicatorLogic(firstBar, previous, adK, adDSlow, ref Component[3], ref Component[4]); return; } else if (IndParam.ListParam[0].Text == "%K is lower than Slow %D") { SpecialValues = new double[1] { 50 }; IndicatorIsLowerThanAnotherIndicatorLogic(firstBar, previous, adK, adDSlow, ref Component[3], ref Component[4]); return; } else { switch (IndParam.ListParam[0].Text) { case "Slow %D rises": logicRule = IndicatorLogic.The_indicator_rises; SpecialValues = new double[1] { 50 }; break; case "Slow %D falls": logicRule = IndicatorLogic.The_indicator_falls; SpecialValues = new double[1] { 50 }; break; case "Slow %D is higher than Level line": logicRule = IndicatorLogic.The_indicator_is_higher_than_the_level_line; SpecialValues = new double[2] { level, 100 - level }; break; case "Slow %D is lower than Level line": logicRule = IndicatorLogic.The_indicator_is_lower_than_the_level_line; SpecialValues = new double[2] { level, 100 - level }; break; case "Slow %D crosses Level line upward": logicRule = IndicatorLogic.The_indicator_crosses_the_level_line_upward; SpecialValues = new double[2] { level, 100 - level }; break; case "Slow %D crosses Level line downward": logicRule = IndicatorLogic.The_indicator_crosses_the_level_line_downward; SpecialValues = new double[2] { level, 100 - level }; break; case "Slow %D changes its direction upward": logicRule = IndicatorLogic.The_indicator_changes_its_direction_upward; SpecialValues = new double[1] { 50 }; break; case "Slow %D changes its direction downward": logicRule = IndicatorLogic.The_indicator_changes_its_direction_downward; SpecialValues = new double[1] { 50 }; break; } OscillatorLogic(firstBar, previous, adDSlow, level, 100 - level, ref Component[3], ref Component[4], logicRule); } } private double[] CalculateVWAP(int anchorHour, int anchorMinute, int resetPeriod) { int firstBar = 3; int bars = Bars; double[] vwapBuffer = new double[bars]; double cumPV = 0.0; double cumV = 0.0; DateTime currentReset = DateTime.MinValue; for (int iBar = firstBar; iBar < bars; iBar++) { DateTime barTime = Time[iBar]; // CHANGED: Removed AddMinutes(Period) to use raw bar opening time DateTime lastReset = GetLastResetTime(barTime, anchorHour, anchorMinute, resetPeriod); if (lastReset != currentReset) { cumPV = 0.0; cumV = 0.0; currentReset = lastReset; } double typicalPrice = (Open[iBar] + High[iBar] + Low[iBar] + Close[iBar]) / 4.0; double volume = Volume[iBar]; cumPV += typicalPrice * volume; cumV += volume; vwapBuffer[iBar] = (cumV > 0.0) ? (cumPV / cumV) : 0.0; } return vwapBuffer; } private DateTime GetLastResetTime(DateTime currentTime, int anchorHour, int anchorMinute, int resetPeriod) { int currentMinutes = currentTime.Hour * 60 + currentTime.Minute; int anchorMinutes = anchorHour * 60 + anchorMinute; DateTime lastReset; if (currentMinutes >= anchorMinutes) { int periods = (currentMinutes - anchorMinutes) / resetPeriod; lastReset = new DateTime( currentTime.Year, currentTime.Month, currentTime.Day, anchorHour, anchorMinute, 0 ).AddMinutes(periods * resetPeriod); } else { DateTime prevDayAnchor = new DateTime( currentTime.Year, currentTime.Month, currentTime.Day, anchorHour, anchorMinute, 0 ).AddDays(-1); int minutesSincePrev = (1440 - anchorMinutes) + currentMinutes; int periods = minutesSincePrev / resetPeriod; lastReset = prevDayAnchor.AddMinutes(periods * resetPeriod); } return lastReset; } private void CalculateStochastic(double[] price, int periodK, int periodDFast, int periodDSlow, out double[] adK, out double[] adDFast, out double[] adDSlow) { int bars = price.Length; adK = new double[bars]; adDFast = new double[bars]; adDSlow = new double[bars]; double[] highs = new double[bars]; double[] lows = new double[bars]; // Calculate highs and lows for %K period for (int bar = 0; bar < periodK; bar++) { double min = double.MaxValue; double max = double.MinValue; for (int i = 0; i < bar; i++) { if (price[bar - i] > max) max = price[bar - i]; if (price[bar - i] < min) min = price[bar - i]; } highs[bar] = max; lows[bar] = min; } for (int bar = periodK; bar < bars; bar++) { double min = double.MaxValue; double max = double.MinValue; for (int i = 0; i < periodK; i++) { if (price[bar - i] > max) max = price[bar - i]; if (price[bar - i] < min) min = price[bar - i]; } highs[bar] = max; lows[bar] = min; } // Calculate %K for (int bar = periodK; bar < bars; bar++) { if (highs[bar] == lows[bar]) adK[bar] = 50; else adK[bar] = 100 * (price[bar] - lows[bar]) / (highs[bar] - lows[bar]); } // Calculate Fast %D (simple moving average of %K) for (int bar = periodDFast; bar < bars; bar++) { double sum = 0; for (int i = 0; i < periodDFast; i++) { sum += adK[bar - i]; } adDFast[bar] = sum / periodDFast; } // Calculate Slow %D (simple moving average of Fast %D) for (int bar = periodDFast + periodDSlow - 1; bar < bars; bar++) { double sum = 0; for (int i = 0; i < periodDSlow; i++) { sum += adDFast[bar - i]; } adDSlow[bar] = sum / periodDSlow; } } public override void SetDescription() { string levelLong = IndParam.NumParam[3].ValueToString; string levelShort = IndParam.NumParam[3].AnotherValueToString(100 - IndParam.NumParam[3].Value); EntryFilterLongDescription = ToString() + " - "; EntryFilterShortDescription = ToString() + " - "; ExitFilterLongDescription = ToString() + " - "; ExitFilterShortDescription = ToString() + " - "; switch (IndParam.ListParam[0].Text) { case "Slow %D rises": EntryFilterLongDescription += "Slow %D rises"; EntryFilterShortDescription += "Slow %D falls"; ExitFilterLongDescription += "Slow %D rises"; ExitFilterShortDescription += "Slow %D falls"; break; case "Slow %D falls": EntryFilterLongDescription += "Slow %D falls"; EntryFilterShortDescription += "Slow %D rises"; ExitFilterLongDescription += "Slow %D falls"; ExitFilterShortDescription += "Slow %D rises"; break; case "Slow %D is higher than Level line": EntryFilterLongDescription += "Slow %D is higher than Level " + levelLong; EntryFilterShortDescription += "Slow %D is lower than Level " + levelShort; ExitFilterLongDescription += "Slow %D is higher than Level " + levelLong; ExitFilterShortDescription += "Slow %D is lower than Level " + levelShort; break; case "Slow %D is lower than Level line": EntryFilterLongDescription += "Slow %D is lower than Level " + levelLong; EntryFilterShortDescription += "Slow %D is higher than Level " + levelShort; ExitFilterLongDescription += "Slow %D is lower than Level " + levelLong; ExitFilterShortDescription += "Slow %D is higher than Level " + levelShort; break; case "Slow %D crosses Level line upward": EntryFilterLongDescription += "Slow %D crosses Level " + levelLong + " upward"; EntryFilterShortDescription += "Slow %D crosses Level " + levelShort + " downward"; ExitFilterLongDescription += "Slow %D crosses Level " + levelLong + " upward"; ExitFilterShortDescription += "Slow %D crosses Level " + levelShort + " downward"; break; case "Slow %D crosses Level line downward": EntryFilterLongDescription += "Slow %D crosses Level " + levelLong + " downward"; EntryFilterShortDescription += "Slow %D crosses Level " + levelShort + " upward"; ExitFilterLongDescription += "Slow %D crosses Level " + levelLong + " downward"; ExitFilterShortDescription += "Slow %D crosses Level " + levelShort + " upward"; break; case "%K crosses Slow %D upward": EntryFilterLongDescription += "%K crosses Slow %D upward"; EntryFilterShortDescription += "%K crosses Slow %D downward"; ExitFilterLongDescription += "%K crosses Slow %D upward"; ExitFilterShortDescription += "%K crosses Slow %D downward"; break; case "%K crosses Slow %D downward": EntryFilterLongDescription += "%K crosses Slow %D downward"; EntryFilterShortDescription += "%K crosses Slow %D upward"; ExitFilterLongDescription += "%K crosses Slow %D downward"; ExitFilterShortDescription += "%K crosses Slow %D upward"; break; case "%K is higher than Slow %D": EntryFilterLongDescription += "%K is higher than Slow %D"; EntryFilterShortDescription += "%K is lower than Slow %D"; ExitFilterLongDescription += "%K is higher than Slow %D"; ExitFilterShortDescription += "%K is lower than Slow %D"; break; case "%K is lower than Slow %D": EntryFilterLongDescription += "%K is lower than Slow %D"; EntryFilterShortDescription += "%K is higher than Slow %D"; ExitFilterLongDescription += "%K is lower than Slow %D"; ExitFilterShortDescription += "%K is higher than Slow %D"; break; case "Slow %D changes its direction upward": EntryFilterLongDescription += "Slow %D changes its direction upward"; EntryFilterShortDescription += "Slow %D changes its direction downward"; ExitFilterLongDescription += "Slow %D changes its direction upward"; ExitFilterShortDescription += "Slow %D changes its direction downward"; break; case "Slow %D changes its direction downward": EntryFilterLongDescription += "Slow %D changes its direction downward"; EntryFilterShortDescription += "Slow %D changes its direction upward"; ExitFilterLongDescription += "Slow %D changes its direction downward"; ExitFilterShortDescription += "Slow %D changes its direction upward"; break; } } public override string ToString() { return IndicatorName + (IndParam.CheckParam[0].Checked ? "* (" : " (") + "Anchor: " + IndParam.ListParam[1].Text + ":" + IndParam.ListParam[2].Text + ", " + "Reset: " + IndParam.ListParam[3].Text + " min, " + "K: " + IndParam.NumParam[0].ValueToString + ", " + "Fast D: " + IndParam.NumParam[1].ValueToString + ", " + "Slow D: " + IndParam.NumParam[2].ValueToString + ")"; } } }
#property copyright "Copyright (C) 2025 NAYA +237674724684" #property link "https://forexsb.com" #property version "1.0" #property strict #include <Forexsb.com/Indicator.mqh> #include <Forexsb.com/Enumerations.mqh> class SessionVWAPStochasticStepped : public Indicator { public: SessionVWAPStochasticStepped(SlotTypes slotType) { SlotType = slotType; IndicatorName = "SessionVWAPStochasticStepped"; WarningMessage = "Stochastic calculated from SessionVWAPStepped price with stepped reset periods."; IsAllowLTF = true; ExecTime = ExecutionTime_DuringTheBar; IsSeparateChart = true; IsDiscreteValues = false; IsDefaultGroupAll = false; } virtual void Calculate(DataSet &dataSet); private: void CalculateVWAP(double &vwapBuffer[], int anchorHour, int anchorMinute, int resetPeriod); void CalculateStochastic(const double &price[], int periodK, int periodDFast, int periodDSlow, double &adK[], double &adDFast[], double &adDSlow[]); datetime GetLastResetTime(datetime currentTime, int anchorHour, int anchorMinute, int resetPeriod); }; //+------------------------------------------------------------------+ void SessionVWAPStochasticStepped::Calculate(DataSet &dataSet) { Data = GetPointer(dataSet); // 1) Read parameters int anchorHour = (int)StringToInteger(ListParam[1].Text); int anchorMinute = (int)StringToInteger(ListParam[2].Text); int resetPeriod = (int)StringToInteger(ListParam[3].Text); int periodK = (int)NumParam[0].Value; int periodDFast = (int)NumParam[1].Value; int periodDSlow = (int)NumParam[2].Value; double level = NumParam[3].Value; int previous = CheckParam[0].Checked ? 1 : 0; int bars = Data.Bars; int firstBar = periodK + periodDFast + periodDSlow + 3; // 2) Compute stepped VWAP double vwapPrice[]; ArrayResize(vwapPrice, bars); ArrayInitialize(vwapPrice, 0.0); CalculateVWAP(vwapPrice, anchorHour, anchorMinute, resetPeriod); // 3) Compute Stochastic on VWAP double adK[], adDFast[], adDSlow[]; ArrayResize(adK, bars); ArrayInitialize(adK, 0.0); ArrayResize(adDFast, bars); ArrayInitialize(adDFast, 0.0); ArrayResize(adDSlow, bars); ArrayInitialize(adDSlow, 0.0); CalculateStochastic(vwapPrice, periodK, periodDFast, periodDSlow, adK, adDFast, adDSlow); // 4) Prepare components ArrayResize(Component, 5); // %K line ArrayResize(Component[0].Value, bars); Component[0].CompName = "%K"; Component[0].DataType = IndComponentType_IndicatorValue; Component[0].FirstBar = firstBar; ArrayCopy(Component[0].Value, adK); // Fast %D line ArrayResize(Component[1].Value, bars); Component[1].CompName = "Fast %D"; Component[1].DataType = IndComponentType_IndicatorValue; Component[1].FirstBar = firstBar; ArrayCopy(Component[1].Value, adDFast); // Slow %D line ArrayResize(Component[2].Value, bars); Component[2].CompName = "Slow %D"; Component[2].DataType = IndComponentType_IndicatorValue; Component[2].FirstBar = firstBar; ArrayCopy(Component[2].Value, adDSlow); // Two filter buffers (no chart) for(int i=3; i<=4; i++) { ArrayResize(Component[i].Value, bars); ArrayInitialize(Component[i].Value, 0.0); Component[i].FirstBar = firstBar; } // Assign filter types if(SlotType == SlotTypes_OpenFilter) { Component[3].DataType = IndComponentType_AllowOpenLong; Component[3].CompName = "Is long entry allowed"; Component[4].DataType = IndComponentType_AllowOpenShort; Component[4].CompName = "Is short entry allowed"; } else // CloseFilter { Component[3].DataType = IndComponentType_ForceCloseLong; Component[3].CompName = "Close out long position"; Component[4].DataType = IndComponentType_ForceCloseShort; Component[4].CompName = "Close out short position"; } // 5) Apply logic IndicatorLogic indLogic = IndicatorLogic_It_does_not_act_as_a_filter; string logic = ListParam[0].Text; if(logic == "%K crosses Slow %D upward") IndicatorCrossesAnotherIndicatorUpwardLogic(firstBar, previous, adK, adDSlow, Component[3], Component[4]); else if(logic == "%K crosses Slow %D downward") IndicatorCrossesAnotherIndicatorDownwardLogic(firstBar, previous, adK, adDSlow, Component[3], Component[4]); else if(logic == "%K is higher than Slow %D") IndicatorIsHigherThanAnotherIndicatorLogic(firstBar, previous, adK, adDSlow, Component[3], Component[4]); else if(logic == "%K is lower than Slow %D") IndicatorIsLowerThanAnotherIndicatorLogic(firstBar, previous, adK, adDSlow, Component[3], Component[4]); else { if(logic == "Slow %D rises") indLogic = IndicatorLogic_The_indicator_rises; else if(logic == "Slow %D falls") indLogic = IndicatorLogic_The_indicator_falls; else if(logic == "Slow %D is higher than Level line") indLogic = IndicatorLogic_The_indicator_is_higher_than_the_level_line; else if(logic == "Slow %D is lower than Level line") indLogic = IndicatorLogic_The_indicator_is_lower_than_the_level_line; else if(logic == "Slow %D crosses Level line upward") indLogic = IndicatorLogic_The_indicator_crosses_the_level_line_upward; else if(logic == "Slow %D crosses Level line downward") indLogic = IndicatorLogic_The_indicator_crosses_the_level_line_downward; else if(logic == "Slow %D changes its direction upward") indLogic = IndicatorLogic_The_indicator_changes_its_direction_upward; else if(logic == "Slow %D changes its direction downward") indLogic = IndicatorLogic_The_indicator_changes_its_direction_downward; OscillatorLogic(firstBar, previous, adDSlow, level, 100.0 - level, Component[3], Component[4], indLogic); } } //+------------------------------------------------------------------+ void SessionVWAPStochasticStepped::CalculateVWAP(double &vwapBuffer[], int anchorHour, int anchorMinute, int resetPeriod) { const int firstStepped = 3; double cumPV = 0.0, cumV = 0.0; datetime currentReset = 0; int bars = Data.Bars; for(int bar = firstStepped; bar < bars; bar++) { // CHANGED: Removed Period()*60 adjustment to use raw bar opening time datetime barTime = Data.Time[bar]; datetime lastReset = GetLastResetTime(barTime, anchorHour, anchorMinute, resetPeriod); if(lastReset != currentReset) { cumPV = 0.0; cumV = 0.0; currentReset = lastReset; } double tp = (Data.Open[bar] + Data.High[bar] + Data.Low[bar] + Data.Close[bar]) / 4.0; double vol = (double)Data.Volume[bar]; cumPV += tp * vol; cumV += vol; vwapBuffer[bar] = (cumV > 0.0) ? (cumPV / cumV) : 0.0; } } //+------------------------------------------------------------------+ void SessionVWAPStochasticStepped::CalculateStochastic(const double &price[], int periodK, int periodDFast, int periodDSlow, double &adK[], double &adDFast[], double &adDSlow[]) { int bars = ArraySize(price); double highs[], lows[]; ArrayResize(highs, bars); ArrayInitialize(highs, 0.0); ArrayResize(lows, bars); ArrayInitialize(lows, 0.0); // Calculate highs and lows for %K period for(int bar = 0; bar < periodK; bar++) { double min = DBL_MAX; double max = DBL_MIN; for(int i = 0; i < bar; i++) { if(price[bar - i] > max) max = price[bar - i]; if(price[bar - i] < min) min = price[bar - i]; } highs[bar] = max; lows[bar] = min; } for(int bar = periodK; bar < bars; bar++) { double min = DBL_MAX; double max = DBL_MIN; for(int i = 0; i < periodK; i++) { if(price[bar - i] > max) max = price[bar - i]; if(price[bar - i] < min) min = price[bar - i]; } highs[bar] = max; lows[bar] = min; } // Calculate %K for(int bar = periodK; bar < bars; bar++) { if(highs[bar] == lows[bar]) adK[bar] = 50; else adK[bar] = 100 * (price[bar] - lows[bar]) / (highs[bar] - lows[bar]); } // Calculate Fast %D (simple moving average of %K) for(int bar = periodDFast; bar < bars; bar++) { double sum = 0; for(int i = 0; i < periodDFast; i++) { sum += adK[bar - i]; } adDFast[bar] = sum / periodDFast; } // Calculate Slow %D (simple moving average of Fast %D) for(int bar = periodDFast + periodDSlow - 1; bar < bars; bar++) { double sum = 0; for(int i = 0; i < periodDSlow; i++) { sum += adDFast[bar - i]; } adDSlow[bar] = sum / periodDSlow; } } //+------------------------------------------------------------------+ datetime SessionVWAPStochasticStepped::GetLastResetTime(datetime currentTime, int anchorHour, int anchorMinute, int resetPeriod) { MqlDateTime tm; TimeToStruct(currentTime, tm); int currentMinutes = tm.hour*60 + tm.min; int anchorMinutes = anchorHour*60 + anchorMinute; datetime lastReset; if(currentMinutes >= anchorMinutes) { tm.hour = anchorHour; tm.min = anchorMinute; tm.sec = 0; datetime anchorToday = StructToTime(tm); int periods = (currentMinutes - anchorMinutes) / resetPeriod; lastReset = anchorToday + (datetime)(periods * resetPeriod * 60); } else { tm.hour = anchorHour; tm.min = anchorMinute; tm.sec = 0; datetime anchorPrev = StructToTime(tm) - 86400; int minutesSincePrev = (1440 - anchorMinutes) + currentMinutes; int periods = minutesSincePrev / resetPeriod; lastReset = anchorPrev + (datetime)(periods * resetPeriod * 60); } return(lastReset); } //+------------------------------------------------------------------+
Risk warning: Forex, spread bets and CFD are leveraged products. They may not be suitable for you as they carry a high degree of risk to your capital and you can lose more than your initial investment. You should ensure you understand all of the risks.
Copyright © 2006 - 2025, Forex Software Ltd.;