Session VWAP Bollinger Bands Stepped by Naya

573 downloads / 274 views / Created: 11.06.2025
 Average Rating: 0

Indicator Description

This indicator combines Volume-Weighted Average Price (VWAP) with Bollinger Bands, using stepped reset periods for session-based trading. It helps identify mean-reversion setups, volatility breakouts, and dynamic support/resistance levels.

Key Features:
- Calculates VWAP starting from a customizable anchor time (hour/minute)
- Resets VWAP at adjustable intervals (15-1440 minutes in 15-min steps)
- Applies Bollinger Bands around VWAP (MA period 2-50, multiplier 0.2-5)
- Multiple logic options for entries/exits and filters

Trading Uses:
- Enter trades at Upper/Lower Band
- Filter entries when price opens/closes above/below bands
- Exit positions at band extremes
- Track volatility expansions/contractions

Works in Forex Strategy Builder for Open, Close, and Filter slots.

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 SessionVWAPBollingerBandsStepped : Indicator { public SessionVWAPBollingerBandsStepped() { IndicatorName = "SessionVWAPBollingerBandsStepped"; PossibleSlots = SlotTypes.Open | SlotTypes.OpenFilter | SlotTypes.Close | SlotTypes.CloseFilter; IndicatorAuthor = "NAYA,+237674724684"; IndicatorVersion = "1.0"; IndicatorDescription = "Bollinger Bands applied to SessionVWAPStepped with stepped reset periods."; } public override void Initialize(SlotTypes slotType) { SlotType = slotType; // 1) Logic selection IndParam.ListParam[0].Caption = "Logic"; switch (SlotType) { case SlotTypes.Open: IndParam.ListParam[0].ItemList = new[] { "Enter long at Upper Band", "Enter long at Lower Band" }; break; case SlotTypes.OpenFilter: IndParam.ListParam[0].ItemList = new[] { "The bar opens below Upper Band", "The bar opens above Upper Band", "The bar opens below Lower Band", "The bar opens above Lower Band", "The position opens above Upper Band", "The position opens below Upper Band", "The position opens above Lower Band", "The position opens below Lower Band", "The bar opens below Upper Band after opening above it", "The bar opens above Upper Band after opening below it", "The bar opens below Lower Band after opening above it", "The bar opens above Lower Band after opening below it" }; break; case SlotTypes.Close: IndParam.ListParam[0].ItemList = new[] { "Exit long at Upper Band", "Exit long at Lower Band" }; break; case SlotTypes.CloseFilter: IndParam.ListParam[0].ItemList = new[] { "The bar closes below Upper Band", "The bar closes above Upper Band", "The bar closes below Lower Band", "The bar closes above Lower Band" }; break; default: IndParam.ListParam[0].ItemList = new[] { "Not Defined" }; break; } 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-59, stepped by 15) IndParam.ListParam[2].Caption = "Anchor Minute (0-59)"; 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-59)."; // 4) Reset Period (15-1440 minutes, stepped 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) MA Period (for Bollinger Bands) IndParam.NumParam[0].Caption = "MA Period"; IndParam.NumParam[0].Value = 20; IndParam.NumParam[0].Min = 2; IndParam.NumParam[0].Max = 50; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The central Moving Average period for Bollinger Bands."; // 6) Multiplier (for Bollinger Bands) IndParam.NumParam[1].Caption = "Multiplier"; IndParam.NumParam[1].Value = 2; IndParam.NumParam[1].Min = 0.2; IndParam.NumParam[1].Max = 5; IndParam.NumParam[1].Point = 1; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "Determines the width of Bollinger Bands."; // 7) 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 maPeriod = (int)IndParam.NumParam[0].Value; double multiplier = IndParam.NumParam[1].Value; int usePrevious = IndParam.CheckParam[0].Checked ? 1 : 0; int firstBar = maPeriod + 3; int bars = Bars; // Calculate SessionVWAPStepped values double[] vwapBuffer = CalculateSessionVWAP(anchorHour, anchorMinute, resetPeriod); // Calculate Bollinger Bands on the VWAP values double[] ma = SimpleMA(maPeriod, vwapBuffer); double[] upperBand = new double[bars]; double[] lowerBand = new double[bars]; for (int bar = maPeriod; bar < bars; bar++) { double sum = 0; for (int i = 0; i < maPeriod; i++) { double delta = vwapBuffer[bar - i] - ma[bar]; sum += delta * delta; } double stdDev = Math.Sqrt(sum / maPeriod); upperBand[bar] = ma[bar] + multiplier * stdDev; lowerBand[bar] = ma[bar] - multiplier * stdDev; } // Set components Component = new IndicatorComp[5]; // Upper Band Component[0] = new IndicatorComp { CompName = "Upper Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = firstBar, Value = upperBand }; // Middle Line (MA of VWAP) Component[1] = new IndicatorComp { CompName = "Middle Line", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Gold, FirstBar = firstBar, Value = ma }; // Lower Band Component[2] = new IndicatorComp { CompName = "Lower Band", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.Blue, FirstBar = firstBar, Value = lowerBand }; // Signal 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 type switch (SlotType) { case SlotTypes.Open: Component[3].DataType = IndComponentType.OpenLongPrice; Component[3].CompName = "Long position entry price"; Component[4].DataType = IndComponentType.OpenShortPrice; Component[4].CompName = "Short position entry price"; break; case 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"; break; case SlotTypes.Close: Component[3].DataType = IndComponentType.CloseLongPrice; Component[3].CompName = "Long position closing price"; Component[4].DataType = IndComponentType.CloseShortPrice; Component[4].CompName = "Short position closing price"; break; case 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"; break; } // Apply logic for Open/Close slots if (SlotType == SlotTypes.Open || SlotType == SlotTypes.Close) { for (int bar = firstBar; bar < bars; bar++) { double open = Open[bar]; double upperValue = upperBand[bar - usePrevious]; double lowerValue = lowerBand[bar - usePrevious]; // Handle price gaps if ((upperBand[bar - usePrevious - 1] > High[bar - 1] && upperValue < open) || (upperBand[bar - usePrevious - 1] < Low[bar - 1] && upperValue > open) || (Close[bar - 1] < upperValue && upperValue < open) || (Close[bar - 1] > upperValue && upperValue > open)) { upperValue = open; } if ((lowerBand[bar - usePrevious - 1] > High[bar - 1] && lowerValue < open) || (lowerBand[bar - usePrevious - 1] < Low[bar - 1] && lowerValue > open) || (Close[bar - 1] < lowerValue && lowerValue < open) || (Close[bar - 1] > lowerValue && lowerValue > open)) { lowerValue = open; } if (IndParam.ListParam[0].Text == "Enter long at Upper Band" || IndParam.ListParam[0].Text == "Exit long at Upper Band") { Component[3].Value[bar] = upperValue; Component[4].Value[bar] = lowerValue; } else { Component[3].Value[bar] = lowerValue; Component[4].Value[bar] = upperValue; } } } else { // Apply filter logic switch (IndParam.ListParam[0].Text) { case "The bar opens below Upper Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_below_the_Upper_Band); break; case "The bar opens above Upper Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_above_the_Upper_Band); break; case "The bar opens below Lower Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_below_the_Lower_Band); break; case "The bar opens above Lower Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_above_the_Lower_Band); break; case "The position opens above Upper Band": Component[0].PosPriceDependence = PositionPriceDependence.PriceBuyHigher; Component[2].PosPriceDependence = PositionPriceDependence.PriceSellLower; Component[3].DataType = IndComponentType.Other; Component[4].DataType = IndComponentType.Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; break; case "The position opens below Upper Band": Component[0].PosPriceDependence = PositionPriceDependence.PriceBuyLower; Component[2].PosPriceDependence = PositionPriceDependence.PriceSellHigher; Component[3].DataType = IndComponentType.Other; Component[4].DataType = IndComponentType.Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; break; case "The position opens above Lower Band": Component[0].PosPriceDependence = PositionPriceDependence.PriceSellLower; Component[2].PosPriceDependence = PositionPriceDependence.PriceBuyHigher; Component[3].DataType = IndComponentType.Other; Component[4].DataType = IndComponentType.Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; break; case "The position opens below Lower Band": Component[0].PosPriceDependence = PositionPriceDependence.PriceSellHigher; Component[2].PosPriceDependence = PositionPriceDependence.PriceBuyLower; Component[3].DataType = IndComponentType.Other; Component[4].DataType = IndComponentType.Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; break; case "The bar opens below Upper Band after opening above it": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_below_the_Upper_Band_after_opening_above_it); break; case "The bar opens above Upper Band after opening below it": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_above_the_Upper_Band_after_opening_below_it); break; case "The bar opens below Lower Band after opening above it": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_below_the_Lower_Band_after_opening_above_it); break; case "The bar opens above Lower Band after opening below it": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_opens_above_the_Lower_Band_after_opening_below_it); break; case "The bar closes below Upper Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_closes_below_the_Upper_Band); break; case "The bar closes above Upper Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_closes_above_the_Upper_Band); break; case "The bar closes below Lower Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_closes_below_the_Lower_Band); break; case "The bar closes above Lower Band": BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, ref Component[3], ref Component[4], BandIndLogic.The_bar_closes_above_the_Lower_Band); break; } } } private double[] CalculateSessionVWAP(int anchorHour, int anchorMinute, int resetPeriod) { int bars = Bars; double[] vwapBuffer = new double[bars]; double cumPV = 0.0; double cumV = 0.0; DateTime currentReset = DateTime.MinValue; for (int iBar = 3; iBar < bars; iBar++) { DateTime barTime = Time[iBar]; // Using bar opening time directly 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) { DateTime anchorToday = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, anchorHour, anchorMinute, 0); // Calculate time difference between current time and anchor time TimeSpan timeDiff = currentTime - anchorToday; if (timeDiff.TotalMinutes >= 0) { // Current time is after anchor time today int periods = (int)(timeDiff.TotalMinutes / resetPeriod); return anchorToday.AddMinutes(periods * resetPeriod); } else { // Current time is before anchor time today - look at previous day DateTime prevDayAnchor = anchorToday.AddDays(-1); TimeSpan prevDiff = currentTime - prevDayAnchor; int periods = (int)(prevDiff.TotalMinutes / resetPeriod); return prevDayAnchor.AddMinutes(periods * resetPeriod); } } private double[] SimpleMA(int period, double[] price) { double[] ma = new double[price.Length]; for (int bar = period - 1; bar < price.Length; bar++) { double sum = 0; for (int i = 0; i < period; i++) { sum += price[bar - i]; } ma[bar] = sum / period; } return ma; } public override void SetDescription() { switch (IndParam.ListParam[0].Text) { case "Enter long at Upper Band": EntryPointLongDescription = "at Upper Band of " + ToString(); EntryPointShortDescription = "at Lower Band of " + ToString(); break; case "Enter long at Lower Band": EntryPointLongDescription = "at Lower Band of " + ToString(); EntryPointShortDescription = "at Upper Band of " + ToString(); break; case "Exit long at Upper Band": ExitPointLongDescription = "at Upper Band of " + ToString(); ExitPointShortDescription = "at Lower Band of " + ToString(); break; case "Exit long at Lower Band": ExitPointLongDescription = "at Lower Band of " + ToString(); ExitPointShortDescription = "at Upper Band of " + ToString(); break; case "The bar opens below Upper Band": EntryFilterLongDescription = "the bar opens below Upper Band of " + ToString(); EntryFilterShortDescription = "the bar opens above Lower Band of " + ToString(); break; case "The bar opens above Upper Band": EntryFilterLongDescription = "the bar opens above Upper Band of " + ToString(); EntryFilterShortDescription = "the bar opens below Lower Band of " + ToString(); break; case "The bar opens below Lower Band": EntryFilterLongDescription = "the bar opens below Lower Band of " + ToString(); EntryFilterShortDescription = "the bar opens above Upper Band of " + ToString(); break; case "The bar opens above Lower Band": EntryFilterLongDescription = "the bar opens above Lower Band of " + ToString(); EntryFilterShortDescription = "the bar opens below Upper Band of " + ToString(); break; case "The bar opens below Upper Band after opening above it": EntryFilterLongDescription = "the bar opens below Upper Band of " + ToString() + " after the previous bar has opened above it"; EntryFilterShortDescription = "the bar opens above Lower Band of " + ToString() + " after the previous bar has opened below it"; break; case "The bar opens above Upper Band after opening below it": EntryFilterLongDescription = "the bar opens above Upper Band of " + ToString() + " after the previous bar has opened below it"; EntryFilterShortDescription = "the bar opens below Lower Band of " + ToString() + " after the previous bar has opened above it"; break; case "The bar opens below Lower Band after opening above it": EntryFilterLongDescription = "the bar opens below Lower Band of " + ToString() + " after the previous bar has opened above it"; EntryFilterShortDescription = "the bar opens above Upper Band of " + ToString() + " after the previous bar has opened below it"; break; case "The bar opens above Lower Band after opening below it": EntryFilterLongDescription = "the bar opens above Lower Band of " + ToString() + " after the previous bar has opened below it"; EntryFilterShortDescription = "the bar opens below Upper Band of " + ToString() + " after the previous bar has opened above it"; break; case "The bar closes below Upper Band": ExitFilterLongDescription = "the bar closes below Upper Band of " + ToString(); ExitFilterShortDescription = "the bar closes above Lower Band of " + ToString(); break; case "The bar closes above Upper Band": ExitFilterLongDescription = "the bar closes above Upper Band of " + ToString(); ExitFilterShortDescription = "the bar closes below Lower Band of " + ToString(); break; case "The bar closes below Lower Band": ExitFilterLongDescription = "the bar closes below Lower Band of " + ToString(); ExitFilterShortDescription = "the bar closes above Upper Band of " + ToString(); break; case "The bar closes above Lower Band": ExitFilterLongDescription = "the bar closes above Lower Band of " + ToString(); ExitFilterShortDescription = "the bar closes below Upper Band of " + ToString(); break; } } public override string ToString() { bool usePrev = IndParam.CheckParam[0].Checked; return IndicatorName + (usePrev ? "* (" : " (") + "Anchor: " + IndParam.ListParam[1].Text + ":" + IndParam.ListParam[2].Text + ", " + "Reset: " + IndParam.ListParam[3].Text + " min, " + "MA: " + IndParam.NumParam[0].Value + ", " + "Multiplier: " + IndParam.NumParam[1].Value + ")"; } } }
#property copyright "Copyright (C) 2025 NAYA +237674724684" #property link "NAYA +237674724684" #property version "1.0" #property strict #include <Forexsb.com/Indicator.mqh> #include <Forexsb.com/Enumerations.mqh> class SessionVWAPBollingerBandsStepped : public Indicator { public: SessionVWAPBollingerBandsStepped(SlotTypes slotType) { SlotType = slotType; IndicatorName = "SessionVWAPBollingerBandsStepped"; WarningMessage = "Bollinger Bands applied to SessionVWAPStepped with stepped reset periods."; IsAllowLTF = true; ExecTime = ExecutionTime_DuringTheBar; IsSeparateChart = false; IsDiscreteValues = false; IsDefaultGroupAll = false; } virtual void Calculate(DataSet &dataSet); private: void CalculateSessionVWAP(int anchorHour, int anchorMinute, int resetPeriod, double &vwapBuffer[]); datetime GetLastResetTime(datetime currentTime, int anchorHour, int anchorMinute, int resetPeriod); void SimpleMA(int period, double &price[], double &ma[]); }; void SessionVWAPBollingerBandsStepped::Calculate(DataSet &dataSet) { Data = GetPointer(dataSet); // Read parameters int anchorHour = (int)StringToInteger(ListParam[1].Text); int anchorMinute = (int)StringToInteger(ListParam[2].Text); int resetPeriod = (int)StringToInteger(ListParam[3].Text); int maPeriod = (int)NumParam[0].Value; double multiplier = NumParam[1].Value; int usePrevious = CheckParam[0].Checked ? 1 : 0; int firstBar = maPeriod + 3; int bars = Data.Bars; // Calculate SessionVWAPStepped values double vwapBuffer[]; CalculateSessionVWAP(anchorHour, anchorMinute, resetPeriod, vwapBuffer); // Calculate Bollinger Bands on the VWAP values double ma[]; SimpleMA(maPeriod, vwapBuffer, ma); double upperBand[]; ArrayResize(upperBand, bars); ArrayInitialize(upperBand, 0.0); double lowerBand[]; ArrayResize(lowerBand, bars); ArrayInitialize(lowerBand, 0.0); for(int bar = maPeriod; bar < bars; bar++) { double sum = 0; for(int i = 0; i < maPeriod; i++) { double delta = vwapBuffer[bar - i] - ma[bar]; sum += delta * delta; } double stdDev = MathSqrt(sum / maPeriod); upperBand[bar] = ma[bar] + multiplier * stdDev; lowerBand[bar] = ma[bar] - multiplier * stdDev; } // Set components ArrayResize(Component[0].Value, bars); Component[0].CompName = "Upper Band"; Component[0].DataType = IndComponentType_IndicatorValue; Component[0].FirstBar = firstBar; ArrayCopy(Component[0].Value, upperBand); ArrayResize(Component[1].Value, bars); Component[1].CompName = "Middle Line"; Component[1].DataType = IndComponentType_IndicatorValue; Component[1].FirstBar = firstBar; ArrayCopy(Component[1].Value, ma); ArrayResize(Component[2].Value, bars); Component[2].CompName = "Lower Band"; Component[2].DataType = IndComponentType_IndicatorValue; Component[2].FirstBar = firstBar; ArrayCopy(Component[2].Value, lowerBand); ArrayResize(Component[3].Value, bars); ArrayInitialize(Component[3].Value, 0.0); ArrayResize(Component[4].Value, bars); ArrayInitialize(Component[4].Value, 0.0); // Set component types based on slot type if(SlotType == SlotTypes_Open) { Component[3].DataType = IndComponentType_OpenLongPrice; Component[3].CompName = "Long position entry price"; Component[4].DataType = IndComponentType_OpenShortPrice; Component[4].CompName = "Short position entry price"; } else 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_Close) { Component[3].DataType = IndComponentType_CloseLongPrice; Component[3].CompName = "Long position closing price"; Component[4].DataType = IndComponentType_CloseShortPrice; Component[4].CompName = "Short position closing price"; } 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 for Open/Close slots if(SlotType == SlotTypes_Open || SlotType == SlotTypes_Close) { for(int bar = firstBar; bar < bars; bar++) { double open = Data.Open[bar]; double upperValue = upperBand[bar - usePrevious]; double lowerValue = lowerBand[bar - usePrevious]; // Handle price gaps if((upperBand[bar - usePrevious - 1] > Data.High[bar - 1] && upperValue < open) || (upperBand[bar - usePrevious - 1] < Data.Low[bar - 1] && upperValue > open) || (Data.Close[bar - 1] < upperValue && upperValue < open) || (Data.Close[bar - 1] > upperValue && upperValue > open)) { upperValue = open; } if((lowerBand[bar - usePrevious - 1] > Data.High[bar - 1] && lowerValue < open) || (lowerBand[bar - usePrevious - 1] < Data.Low[bar - 1] && lowerValue > open) || (Data.Close[bar - 1] < lowerValue && lowerValue < open) || (Data.Close[bar - 1] > lowerValue && lowerValue > open)) { lowerValue = open; } if(ListParam[0].Text == "Enter long at Upper Band" || ListParam[0].Text == "Exit long at Upper Band") { Component[3].Value[bar] = upperValue; Component[4].Value[bar] = lowerValue; } else { Component[3].Value[bar] = lowerValue; Component[4].Value[bar] = upperValue; } } } else { // Apply filter logic string logic = ListParam[0].Text; if(logic == "The bar opens below Upper Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_below_the_Upper_Band); else if(logic == "The bar opens above Upper Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_above_the_Upper_Band); else if(logic == "The bar opens below Lower Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_below_the_Lower_Band); else if(logic == "The bar opens above Lower Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_above_the_Lower_Band); else if(logic == "The position opens above Upper Band") { Component[0].PosPriceDependence = PositionPriceDependence_PriceBuyHigher; Component[2].PosPriceDependence = PositionPriceDependence_PriceSellLower; Component[3].DataType = IndComponentType_Other; Component[4].DataType = IndComponentType_Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; } else if(logic == "The position opens below Upper Band") { Component[0].PosPriceDependence = PositionPriceDependence_PriceBuyLower; Component[2].PosPriceDependence = PositionPriceDependence_PriceSellHigher; Component[3].DataType = IndComponentType_Other; Component[4].DataType = IndComponentType_Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; } else if(logic == "The position opens above Lower Band") { Component[0].PosPriceDependence = PositionPriceDependence_PriceSellLower; Component[2].PosPriceDependence = PositionPriceDependence_PriceBuyHigher; Component[3].DataType = IndComponentType_Other; Component[4].DataType = IndComponentType_Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; } else if(logic == "The position opens below Lower Band") { Component[0].PosPriceDependence = PositionPriceDependence_PriceSellHigher; Component[2].PosPriceDependence = PositionPriceDependence_PriceBuyLower; Component[3].DataType = IndComponentType_Other; Component[4].DataType = IndComponentType_Other; Component[3].ShowInDynInfo = false; Component[4].ShowInDynInfo = false; } else if(logic == "The bar opens below Upper Band after opening above it") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_below_Upper_Band_after_above); else if(logic == "The bar opens above Upper Band after opening below it") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_above_Upper_Band_after_below); else if(logic == "The bar opens below Lower Band after opening above it") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_below_Lower_Band_after_above); else if(logic == "The bar opens above Lower Band after opening below it") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_opens_above_Lower_Band_after_below); else if(logic == "The bar closes below Upper Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_closes_below_the_Upper_Band); else if(logic == "The bar closes above Upper Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_closes_above_the_Upper_Band); else if(logic == "The bar closes below Lower Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_closes_below_the_Lower_Band); else if(logic == "The bar closes above Lower Band") BandIndicatorLogic(firstBar, usePrevious, upperBand, lowerBand, Component[3], Component[4], BandIndLogic_The_bar_closes_above_the_Lower_Band); } } void SessionVWAPBollingerBandsStepped::CalculateSessionVWAP(int anchorHour, int anchorMinute, int resetPeriod, double &vwapBuffer[]) { int bars = Data.Bars; ArrayResize(vwapBuffer, bars); ArrayInitialize(vwapBuffer, 0.0); double cumPV = 0.0; double cumV = 0.0; datetime currentReset = 0; for(int bar = 3; bar < bars; bar++) { datetime barTime = Data.Time[bar]; // Using bar opening time directly datetime lastReset = GetLastResetTime(barTime, anchorHour, anchorMinute, resetPeriod); if(lastReset != currentReset) { cumPV = 0.0; cumV = 0.0; currentReset = lastReset; } double typicalPrice = (Data.Open[bar] + Data.High[bar] + Data.Low[bar] + Data.Close[bar]) / 4.0; double volume = (double)Data.Volume[bar]; cumPV += typicalPrice * volume; cumV += volume; vwapBuffer[bar] = (cumV > 0.0) ? (cumPV / cumV) : 0.0; } } datetime SessionVWAPBollingerBandsStepped::GetLastResetTime(datetime currentTime, int anchorHour, int anchorMinute, int resetPeriod) { MqlDateTime tm; TimeToStruct(currentTime, tm); // Create anchor time for today MqlDateTime anchorStruct = tm; anchorStruct.hour = anchorHour; anchorStruct.min = anchorMinute; anchorStruct.sec = 0; datetime anchorToday = StructToTime(anchorStruct); if(currentTime >= anchorToday) { // Current time is after anchor time today int minutesSinceAnchor = (int)((currentTime - anchorToday) / 60); int periods = minutesSinceAnchor / resetPeriod; return anchorToday + (periods * resetPeriod * 60); } else { // Current time is before anchor time today - look at previous day datetime prevDayAnchor = anchorToday - 86400; int minutesSincePrev = (int)((currentTime - prevDayAnchor) / 60); int periods = minutesSincePrev / resetPeriod; return prevDayAnchor + (periods * resetPeriod * 60); } } void SessionVWAPBollingerBandsStepped::SimpleMA(int period, double &price[], double &ma[]) { ArrayResize(ma, ArraySize(price)); ArrayInitialize(ma, 0.0); for(int bar = period - 1; bar < ArraySize(price); bar++) { double sum = 0; for(int i = 0; i < period; i++) { sum += price[bar - i]; } ma[bar] = sum / period; } }
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.;