//+------------------------------------------------------------------+ //| MomentumShiftLiquidity.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 "AbstractLiquidity.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class MomentumShiftLiquidity : public AbstractLiquidity { private: double CalcLegPercent(double firstLiquidityPrice, double legExtremePrice, double secondLiquidityPrice) { double leg = MathAbs(legExtremePrice - firstLiquidityPrice); if(leg <= 0.0) return -1.0; return (MathAbs(secondLiquidityPrice - firstLiquidityPrice) / leg) * 100.0; } public: MomentumShiftLiquidity() {} ~MomentumShiftLiquidity() {} virtual string GetAnalyserName() override { return "MomentumShiftLiquidity"; } virtual void OnSwing(TimePrice &swing, bool isHigh) override { // ====================================================== // 1. Pullback monitoring (if active) // ====================================================== if(state.pullbackActive) { // Draw pullback leg CreateTrendL("PB_" + IntegerToString(state.pullbackSwingCount), state.pullbackLastPoint, swing, clrOrange); state.pullbackLastPoint = swing; state.pullbackSwingCount++; // Check if swing count exceeded dynamic maxSwingCount if(state.pullbackSwingCount > configs.momShiftConfigs.maxSwingCount) { state.pullbackActive = false; } // Check for target reach using MomShift tolerance else if(NearPrice(swing.y, state.pullbackTargetPrice, configs.momShiftConfigs.tolerance)) { state.pullbackActive = false; } // Check for invalidation: price broke above upper level or below lower level else if(swing.y > state.pullbackUpperLevel || swing.y < state.pullbackLowerLevel) { state.pullbackActive = false; } }/***/ // ====================================================== // 2. Structural pattern detection // ====================================================== int index = state.m_swings.Size() - 1; if(state.m_swings.Size() < 5) return; ZigzagSwing s1 = state.m_swings.At(index); ZigzagSwing s2 = state.m_swings.At(index - 1); ZigzagSwing s3 = state.m_swings.At(index - 2); ZigzagSwing s4 = state.m_swings.At(index - 3); ZigzagSwing s5 = state.m_swings.At(index - 4); double firstlegDiff = CalcLegPercent(s3.point.y, s2.point.y, s1.point.y); double seclegDiff = CalcLegPercent(s4.point.y, s3.point.y, s2.point.y); if(isHigh) { if((s5.point.y > s3.point.y && s1.point.y >= s3.point.y ) && (s4.point.y < s2.point.y)//lows && firstlegDiff > configs.momShiftConfigs.minPercent && seclegDiff < configs.momShiftConfigs.maxPercent) { // Draw structural legs CreateTrendL("MOM_s1", s1.point, s2.point, clrAqua); CreateTrendL("MOM_s2", s2.point, s3.point, clrAqua); CreateTrendL("MOM_s3", s3.point, s4.point, clrAqua); CreateTrendL("MOM_s4", s4.point, s5.point, clrAqua); // Activate pullback monitoring state.pullbackActive = true; state.pullbackTargetPrice = s4.point.y; // Replaced eqConfigs.tolerance with momShiftConfigs.tolerance state.pullbackUpperLevel = s1.point.y + configs.momShiftConfigs.tolerance; state.pullbackLowerLevel = s4.point.y - configs.momShiftConfigs.tolerance; state.pullbackSwingCount = 0; state.pullbackLastPoint = s4.point; MomentumShiftLiquidityEvent* e = new MomentumShiftLiquidityEvent(bar.symbol, bar.tf, BSL, s4.point.x, s4.point.y, bar.bar.LastBarOpen(), s4.point.y); eventBus.Push(e); } } // --- Bearish structural pattern (EQL / BOS) --- else { if((s5.point.y < s3.point.y && s1.point.y <= s3.point.y ) && (s4.point.y > s2.point.y)//lows && firstlegDiff > configs.momShiftConfigs.minPercent && seclegDiff < configs.momShiftConfigs.maxPercent) { // Draw structural legs CreateTrendL("MOM_s1m", s1.point, s2.point, clrAqua); CreateTrendL("MOM_s2m", s2.point, s3.point, clrAqua); CreateTrendL("MOM_s3m", s3.point, s4.point, clrAqua); CreateTrendL("MOM_s4m", s4.point, s5.point, clrAqua); // Activate pullback monitoring state.pullbackActive = true; state.pullbackTargetPrice = s4.point.y; // Replaced eqConfigs.tolerance with momShiftConfigs.tolerance state.pullbackLowerLevel = s1.point.y - configs.momShiftConfigs.tolerance; state.pullbackUpperLevel = s4.point.y + configs.momShiftConfigs.tolerance; state.pullbackSwingCount = 0; state.pullbackLastPoint = s4.point; MomentumShiftLiquidityEvent* e = new MomentumShiftLiquidityEvent(bar.symbol, bar.tf, SSL, s4.point.x, s4.point.y, bar.bar.LastBarOpen(), s4.point.y); eventBus.Push(e); } } } }; //+------------------------------------------------------------------+