//+------------------------------------------------------------------+ //| Chapter3.mqh | //| Copyright 2026, Concrete Goonies | //| https://concrete-goonies.web.app | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Concrete Goonies" #property link "https://concrete-goonies.web.app" #property version "1.00" #include "Liquidity/EqualLiquidity.mqh" #include "Liquidity/StructuralLiquidity.mqh" #include "Liquidity/MomentumShiftLiquidity.mqh" #include "Liquidity/TrendlineLiquidity.mqh" #include "Liquidity/ImbalanceLiquidity.mqh" //#include "Liquidity/TrendlineLiquidity.mqh" // 1. Hyperparameters (Inputs) input double InpMomMaxPercent = 60.0; // MS: Max Percent input double InpMomMinPercent = 45.0; // MS: Min Percent input int InpMomTolerancePoints = 50; // MS: Tolerance (Points) input int InpMomMaxSwingCount = 10; // MS: Max Pullback Swings //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class Chapter3: public AbstractAnalyser { private: Indicator* ind; TimeFrameDataSeries* bar; CArrayList* liquidityScanners; LiquidityConfigs configs; CArrayList* states; LiqState* activeState; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ TimePrice MakeSwingHigh(int i) { TimePrice tp; tp.i = i; tp.x = bar.Time(i); tp.y = bar.High(i); return tp; } //--- TimePrice MakeSwingLow(int i) { TimePrice tp; tp.i = i; tp.x = bar.Time(i); tp.y = bar.Low(i); return tp; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int FindExist(string symbol, ENUM_TIMEFRAMES tf) { for(int i = 0; i < states.Size(); i++) { LiqState* data = states.At(i); if(data.symbol == symbol && data.tf == tf) return i; } return -1; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void DetectAndNotifySwings(int i) { if(IsSwingHigh(i, ind)) { TimePrice swing = MakeSwingHigh(i); if(!activeState.HasSwingAt(swing.x, true)) { ZigzagSwing s; s.point = swing; s.isHigh = true; activeState.m_swings.Add(s); activeState.m_swingHighs.Add(swing); for(int j = 0; j < liquidityScanners.Size(); j++) liquidityScanners.At(j).OnSwing(swing, true); } } //+------------------------------------------------------------------+ if(IsSwingLow(i, ind)) { TimePrice swing = MakeSwingLow(i); if(!activeState.HasSwingAt(swing.x, false)) { ZigzagSwing s; s.point = swing; s.isHigh = false; activeState.m_swings.Add(s); activeState.m_swingLows.Add(swing); for(int j = 0; j < liquidityScanners.Size(); j++) liquidityScanners.At(j).OnSwing(swing, false); } } } public: Chapter3() { liquidityScanners = new CArrayList(); // AbstractLiquidity* eqLiq = new EqualLiquidity(); // liquidityScanners.Add(eqLiq); //AbstractLiquidity* structLiq = new StructuralLiquidity(); //liquidityScanners.Add(structLiq); //AbstractLiquidity* momShiftLiq = new MomentumShiftLiquidity(); // liquidityScanners.Add(momShiftLiq); //AbstractLiquidity* trendLiq = new TrendlineLiquidity(); // liquidityScanners.Add(trendLiq); AbstractLiquidity* imbLiq = new ImbalanceLiquidity(); liquidityScanners.Add(imbLiq); configs.eqConfigs.tolerance = 150000 * _Point; configs.eqConfigs.minSwingCount = 0; configs.eqConfigs.lookBack = 75; configs.structConfigs.lookBack = 5; configs.structConfigs.maxPercent = 60; configs.structConfigs.minPercent = 45; //configs.momShiftConfigs.lookBack = 5; // 3. Configuration Initialization configs.momShiftConfigs.maxPercent = InpMomMaxPercent; configs.momShiftConfigs.minPercent = InpMomMinPercent; configs.momShiftConfigs.tolerance = InpMomTolerancePoints * _Point; // Converted to price format configs.momShiftConfigs.maxSwingCount = InpMomMaxSwingCount; states = new CArrayList(); } ~Chapter3() { for(int i = 0; i < liquidityScanners.Size(); i++) { AbstractLiquidity* liquidityScanner = liquidityScanners.At(i); delete liquidityScanner; } for(int i = 0; i < states.Size(); i++) { LiqState* state = states.At(i); delete state; } delete liquidityScanners; delete states; } virtual void Init(EventBus* bus) { AbstractAnalyser::Init(bus); for(int i = 0; i < liquidityScanners.Size(); i++) { AbstractLiquidity* liquidityScanner = liquidityScanners.At(i); liquidityScanner.Init(bus); liquidityScanner.SetConfigs(configs); } } void SetConfigs(LiquidityConfigs &c) { configs = c; for(int i = 0; i < liquidityScanners.Size(); i++) { liquidityScanners.At(i).SetConfigs(configs); } } virtual string GetAnalyserName() override { return "Chapter3"; } virtual void ProcessBar(TimeFrameDataSeries* series, int i) override { ind = series.GetIndicator(0); bar = series; int stateIndex = FindExist(series.symbol, series.tf); if(stateIndex < 0) { LiqState* s = new LiqState(); s.symbol = series.symbol; s.tf = series.tf; states.Add(s); activeState = s; } else { activeState = states.At(stateIndex); } for(int j = 0; j < liquidityScanners.Size(); j++) { AbstractLiquidity* liquidityScanner = liquidityScanners.At(j); liquidityScanner.ProcessBar(activeState, ind, series, i); } DetectAndNotifySwings(i); } }; //+------------------------------------------------------------------+