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.;
Copyright © 2006 - 2025, Forex Software Ltd.;