Session VWAP CCI Stepped by Naya

150 downloads / 59 views / Created: 17.06.2025
 Average Rating: 0

Indicator Description

SessionVWAPCCIStepped

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 SessionVWAPCCIStepped : Indicator { public SessionVWAPCCIStepped() { IndicatorName = "SessionVWAPCCIStepped"; PossibleSlots = SlotTypes.OpenFilter | SlotTypes.CloseFilter; SeparatedChart = true; SeparatedChartMinValue = -200; SeparatedChartMaxValue = 200; IndicatorAuthor = "NAYA,+237674724684"; IndicatorVersion = "1.0"; IndicatorDescription = "CCI 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[] { "SessionVWAPCCI rises", "SessionVWAPCCI falls", "SessionVWAPCCI is higher than the Level line", "SessionVWAPCCI is lower than the Level line", "SessionVWAPCCI crosses the Level line upward", "SessionVWAPCCI crosses the Level line downward", "SessionVWAPCCI changes its direction upward", "SessionVWAPCCI changes its direction 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) CCI Period IndParam.NumParam[0].Caption = "CCI Period"; IndParam.NumParam[0].Value = 14; IndParam.NumParam[0].Min = 2; IndParam.NumParam[0].Max = 30; IndParam.NumParam[0].Enabled = true; IndParam.NumParam[0].ToolTip = "The period of CCI calculation."; // 6) Level IndParam.NumParam[1].Caption = "Level"; IndParam.NumParam[1].Value = 100; IndParam.NumParam[1].Min = 0; IndParam.NumParam[1].Max = 1000; IndParam.NumParam[1].Enabled = true; IndParam.NumParam[1].ToolTip = "A signal level."; // 7) Multiplier IndParam.NumParam[2].Caption = "Multiplier"; IndParam.NumParam[2].Value = 0.020; IndParam.NumParam[2].Min = 0; IndParam.NumParam[2].Max = 2; IndParam.NumParam[2].Point = 3; IndParam.NumParam[2].Enabled = true; IndParam.NumParam[2].ToolTip = "The multiplier value for CCI calculation."; // 8) 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 cciPeriod = (int)IndParam.NumParam[0].Value; double level = IndParam.NumParam[1].Value; double multiplier = IndParam.NumParam[2].Value; int previous = IndParam.CheckParam[0].Checked ? 1 : 0; // First calculate SessionVWAPStepped values double[] vwapPrice = CalculateVWAP(anchorHour, anchorMinute, resetPeriod); // Then calculate CCI from VWAP prices double[] cci = CalculateCCI(vwapPrice, cciPeriod, multiplier); // Prepare components int firstBar = cciPeriod + previous + 2; Component = new IndicatorComp[3]; // Main CCI line Component[0] = new IndicatorComp { CompName = "SessionVWAPCCI", DataType = IndComponentType.IndicatorValue, ChartType = IndChartType.Line, ChartColor = Color.DodgerBlue, FirstBar = firstBar, Value = cci }; // Filter components Component[1] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = firstBar, Value = new double[Bars] }; Component[2] = new IndicatorComp { ChartType = IndChartType.NoChart, FirstBar = firstBar, Value = new double[Bars] }; // Set component types based on slot if (SlotType == SlotTypes.OpenFilter) { Component[1].DataType = IndComponentType.AllowOpenLong; Component[1].CompName = "Is long entry allowed"; Component[2].DataType = IndComponentType.AllowOpenShort; Component[2].CompName = "Is short entry allowed"; } else if (SlotType == SlotTypes.CloseFilter) { Component[1].DataType = IndComponentType.ForceCloseLong; Component[1].CompName = "Close out long position"; Component[2].DataType = IndComponentType.ForceCloseShort; Component[2].CompName = "Close out short position"; } // Apply logic var logicRule = IndicatorLogic.It_does_not_act_as_a_filter; switch (IndParam.ListParam[0].Text) { case "SessionVWAPCCI rises": logicRule = IndicatorLogic.The_indicator_rises; break; case "SessionVWAPCCI falls": logicRule = IndicatorLogic.The_indicator_falls; break; case "SessionVWAPCCI is higher than the Level line": logicRule = IndicatorLogic.The_indicator_is_higher_than_the_level_line; break; case "SessionVWAPCCI is lower than the Level line": logicRule = IndicatorLogic.The_indicator_is_lower_than_the_level_line; break; case "SessionVWAPCCI crosses the Level line upward": logicRule = IndicatorLogic.The_indicator_crosses_the_level_line_upward; break; case "SessionVWAPCCI crosses the Level line downward": logicRule = IndicatorLogic.The_indicator_crosses_the_level_line_downward; break; case "SessionVWAPCCI changes its direction upward": logicRule = IndicatorLogic.The_indicator_changes_its_direction_upward; break; case "SessionVWAPCCI changes its direction downward": logicRule = IndicatorLogic.The_indicator_changes_its_direction_downward; break; } OscillatorLogic(firstBar, previous, cci, level, -level, ref Component[1], ref Component[2], 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 double[] CalculateCCI(double[] price, int period, double multiplier) { int bars = price.Length; double[] cci = new double[bars]; double[] sma = new double[bars]; double[] meanDev = new double[bars]; // Calculate SMA for (int bar = period; bar < bars; bar++) { double sum = 0; for (int i = 0; i < period; i++) { sum += price[bar - i]; } sma[bar] = sum / period; } // Calculate Mean Deviation for (int bar = period; bar < bars; bar++) { double sum = 0; for (int i = 0; i < period; i++) { sum += Math.Abs(price[bar - i] - sma[bar]); } meanDev[bar] = sum / period; } // Calculate CCI for (int bar = period; bar < bars; bar++) { if (Math.Abs(meanDev[bar]) > 0.0000001) // Epsilon { cci[bar] = (price[bar] - sma[bar]) / (multiplier * meanDev[bar]); } else { cci[bar] = 0; } } return cci; } public override void SetDescription() { string levelLong = IndParam.NumParam[1].ValueToString; string levelShort = IndParam.NumParam[1].AnotherValueToString(-IndParam.NumParam[1].Value); EntryFilterLongDescription = ToString() + " "; EntryFilterShortDescription = ToString() + " "; ExitFilterLongDescription = ToString() + " "; ExitFilterShortDescription = ToString() + " "; switch (IndParam.ListParam[0].Text) { case "SessionVWAPCCI rises": EntryFilterLongDescription += "rises"; EntryFilterShortDescription += "falls"; ExitFilterLongDescription += "rises"; ExitFilterShortDescription += "falls"; break; case "SessionVWAPCCI falls": EntryFilterLongDescription += "falls"; EntryFilterShortDescription += "rises"; ExitFilterLongDescription += "falls"; ExitFilterShortDescription += "rises"; break; case "SessionVWAPCCI is higher than the Level line": EntryFilterLongDescription += "is higher than the Level " + levelLong; EntryFilterShortDescription += "is lower than the Level " + levelShort; ExitFilterLongDescription += "is higher than the Level " + levelLong; ExitFilterShortDescription += "is lower than the Level " + levelShort; break; case "SessionVWAPCCI is lower than the Level line": EntryFilterLongDescription += "is lower than the Level " + levelLong; EntryFilterShortDescription += "is higher than the Level " + levelShort; ExitFilterLongDescription += "is lower than the Level " + levelLong; ExitFilterShortDescription += "is higher than the Level " + levelShort; break; case "SessionVWAPCCI crosses the Level line upward": EntryFilterLongDescription += "crosses the Level " + levelLong + " upward"; EntryFilterShortDescription += "crosses the Level " + levelShort + " downward"; ExitFilterLongDescription += "crosses the Level " + levelLong + " upward"; ExitFilterShortDescription += "crosses the Level " + levelShort + " downward"; break; case "SessionVWAPCCI crosses the Level line downward": EntryFilterLongDescription += "crosses the Level " + levelLong + " downward"; EntryFilterShortDescription += "crosses the Level " + levelShort + " upward"; ExitFilterLongDescription += "crosses the Level " + levelLong + " downward"; ExitFilterShortDescription += "crosses the Level " + levelShort + " upward"; break; case "SessionVWAPCCI changes its direction upward": EntryFilterLongDescription += "changes its direction upward"; EntryFilterShortDescription += "changes its direction downward"; ExitFilterLongDescription += "changes its direction upward"; ExitFilterShortDescription += "changes its direction downward"; break; case "SessionVWAPCCI changes its direction downward": EntryFilterLongDescription += "changes its direction downward"; EntryFilterShortDescription += "changes its direction upward"; ExitFilterLongDescription += "changes its direction downward"; ExitFilterShortDescription += "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, " + "Period: " + IndParam.NumParam[0].ValueToString + ", " + "Multiplier: " + 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 SessionVWAPCCIStepped : public Indicator { public: SessionVWAPCCIStepped(SlotTypes slotType) { SlotType = slotType; IndicatorName = "SessionVWAPCCIStepped"; WarningMessage = "CCI 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 CalculateCCI(const double &price[], double &cci[], int period, double multiplier); datetime GetLastResetTime(datetime currentTime, int anchorHour, int anchorMinute, int resetPeriod); }; //+------------------------------------------------------------------+ void SessionVWAPCCIStepped::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 cciPeriod = (int)NumParam[0].Value; double level = NumParam[1].Value; double multiplier = NumParam[2].Value; int previous = CheckParam[0].Checked ? 1 : 0; int bars = Data.Bars; int firstBar = cciPeriod + previous + 2; // 2) Compute stepped VWAP double vwapPrice[]; ArrayResize(vwapPrice, bars); ArrayInitialize(vwapPrice, 0.0); CalculateVWAP(vwapPrice, anchorHour, anchorMinute, resetPeriod); // 3) Compute CCI on VWAP double cci[]; ArrayResize(cci, bars); ArrayInitialize(cci, 0.0); CalculateCCI(vwapPrice, cci, cciPeriod, multiplier); // 4) Prepare components ArrayResize(Component, 3); // Main CCI line ArrayResize(Component[0].Value, bars); Component[0].CompName = "SessionVWAPCCI"; Component[0].DataType = IndComponentType_IndicatorValue; Component[0].FirstBar = firstBar; ArrayCopy(Component[0].Value, cci); // Two filter buffers (no chart) for(int i=1; i<=2; i++) { ArrayResize(Component[i].Value, bars); ArrayInitialize(Component[i].Value, 0.0); Component[i].FirstBar = firstBar; } // Assign filter types if(SlotType == SlotTypes_OpenFilter) { Component[1].DataType = IndComponentType_AllowOpenLong; Component[1].CompName = "Is long entry allowed"; Component[2].DataType = IndComponentType_AllowOpenShort; Component[2].CompName = "Is short entry allowed"; } else // CloseFilter { Component[1].DataType = IndComponentType_ForceCloseLong; Component[1].CompName = "Close out long position"; Component[2].DataType = IndComponentType_ForceCloseShort; Component[2].CompName = "Close out short position"; } // 5) Apply logic IndicatorLogic logicRule = IndicatorLogic_It_does_not_act_as_a_filter; string logic = ListParam[0].Text; if(logic == "SessionVWAPCCI rises") logicRule = IndicatorLogic_The_indicator_rises; else if(logic == "SessionVWAPCCI falls") logicRule = IndicatorLogic_The_indicator_falls; else if(logic == "SessionVWAPCCI is higher than the Level line") logicRule = IndicatorLogic_The_indicator_is_higher_than_the_level_line; else if(logic == "SessionVWAPCCI is lower than the Level line") logicRule = IndicatorLogic_The_indicator_is_lower_than_the_level_line; else if(logic == "SessionVWAPCCI crosses the Level line upward") logicRule = IndicatorLogic_The_indicator_crosses_the_level_line_upward; else if(logic == "SessionVWAPCCI crosses the Level line downward") logicRule = IndicatorLogic_The_indicator_crosses_the_level_line_downward; else if(logic == "SessionVWAPCCI changes its direction upward") logicRule = IndicatorLogic_The_indicator_changes_its_direction_upward; else if(logic == "SessionVWAPCCI changes its direction downward") logicRule = IndicatorLogic_The_indicator_changes_its_direction_downward; OscillatorLogic(firstBar, previous, cci, level, -level, Component[1], Component[2], logicRule); } //+------------------------------------------------------------------+ void SessionVWAPCCIStepped::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 SessionVWAPCCIStepped::CalculateCCI(const double &price[], double &cci[], int period, double multiplier) { int bars = ArraySize(price); double sma[], meanDev[]; ArrayResize(sma, bars); ArrayInitialize(sma, 0.0); ArrayResize(meanDev, bars); ArrayInitialize(meanDev, 0.0); // 1) Calculate SMA for(int bar = period; bar < bars; bar++) { double sum = 0; for(int i = 0; i < period; i++) sum += price[bar - i]; sma[bar] = sum / period; } // 2) Calculate Mean Deviation for(int bar = period; bar < bars; bar++) { double sum = 0; for(int i = 0; i < period; i++) sum += MathAbs(price[bar - i] - sma[bar]); meanDev[bar] = sum / period; } // 3) Calculate CCI ArrayResize(cci, bars); ArrayInitialize(cci, 0.0); for(int bar = period; bar < bars; bar++) { if(MathAbs(meanDev[bar]) > 0.0000001) // Epsilon cci[bar] = (price[bar] - sma[bar]) / (multiplier * meanDev[bar]); else cci[bar] = 0; } } //+------------------------------------------------------------------+ datetime SessionVWAPCCIStepped::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.;