2026-09-30 09:06:59 +02:00 | | | //+------------------------------------------------------------------+
|
2026-10-26 06:27:09 +02:00 | | | //| MomentumShiftLiquidity.mqh |
|
2026-09-30 09:06:59 +02:00 | | | //| Copyright 2026, Concrete Goonies |
|
| | | //| https://concrete-goonies.web.app |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Concrete Goonies"
|
| | | #property link "https://concrete-goonies.web.app"
|
2026-10-26 06:27:09 +02:00 | | | #property version "1.00"
|
2026-09-30 09:06:59 +02:00 | | |
|
| | | #include "AbstractLiquidity.mqh"
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class MomentumShiftLiquidity : public AbstractLiquidity {
|
2026-09-30 09:06:59 +02:00 | | | private:
|
2026-10-26 06:27:09 +02:00 | | | double CalcLegPercent(double firstLiquidityPrice, double legExtremePrice, double secondLiquidityPrice) {
|
2026-09-30 09:06:59 +02:00 | | | double leg = MathAbs(legExtremePrice - firstLiquidityPrice);
|
| | | if(leg <= 0.0)
|
| | | return -1.0;
|
2026-10-26 06:27:09 +02:00 | | |
|
2026-09-30 09:06:59 +02:00 | | | return (MathAbs(secondLiquidityPrice - firstLiquidityPrice) / leg) * 100.0;
|
| | | }
|
| | |
|
| | | public:
|
2026-10-26 06:27:09 +02:00 | | | MomentumShiftLiquidity() {}
|
| | | ~MomentumShiftLiquidity() {}
|
2026-09-30 09:06:59 +02:00 | | |
|
2026-10-26 06:27:09 +02:00 | | | virtual string GetAnalyserName() override {
|
2026-09-30 09:06:59 +02:00 | | | return "MomentumShiftLiquidity";
|
| | | }
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | virtual void OnSwing(TimePrice &swing, bool isHigh) override {
|
| | | // ======================================================
|
| | | // 1. Pullback monitoring (if active)
|
| | | // ======================================================
|
| | | if(state.pullbackActive) {
|
| | | // Draw pullback leg
|
2026-09-30 09:06:59 +02:00 | | | CreateTrendL("PB_" + IntegerToString(state.pullbackSwingCount),
|
| | | state.pullbackLastPoint, swing, clrOrange);
|
| | | state.pullbackLastPoint = swing;
|
| | | state.pullbackSwingCount++;
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | // Check if swing count exceeded dynamic maxSwingCount
|
| | | if(state.pullbackSwingCount > configs.momShiftConfigs.maxSwingCount) {
|
2026-09-30 09:06:59 +02:00 | | | state.pullbackActive = false;
|
| | | }
|
2026-10-26 06:27:09 +02:00 | | | // Check for target reach using MomShift tolerance
|
| | | else if(NearPrice(swing.y, state.pullbackTargetPrice, configs.momShiftConfigs.tolerance)) {
|
2026-09-30 09:06:59 +02:00 | | | state.pullbackActive = false;
|
| | | }
|
2026-10-26 06:27:09 +02:00 | | | // 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;
|
| | | }
|
| | | }/***/
|
2026-09-30 09:06:59 +02:00 | | |
|
2026-10-26 06:27:09 +02:00 | | | // ======================================================
|
| | | // 2. Structural pattern detection
|
| | | // ======================================================
|
2026-09-30 09:06:59 +02:00 | | | int index = state.m_swings.Size() - 1;
|
2026-10-26 06:27:09 +02:00 | | |
|
2026-09-30 09:06:59 +02:00 | | | if(state.m_swings.Size() < 5)
|
| | | return;
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | ZigzagSwing s1 = state.m_swings.At(index);
|
2026-09-30 09:06:59 +02:00 | | | ZigzagSwing s2 = state.m_swings.At(index - 1);
|
| | | ZigzagSwing s3 = state.m_swings.At(index - 2);
|
| | | ZigzagSwing s4 = state.m_swings.At(index - 3);
|
2026-10-26 06:27:09 +02:00 | | | 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
|
2026-09-30 09:06:59 +02:00 | | | 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);
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | // 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;
|
2026-09-30 09:06:59 +02:00 | | |
|
2026-10-26 06:27:09 +02:00 | | | 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);
|
2026-09-30 09:06:59 +02:00 | | | }
|
| | | }
|
2026-10-26 06:27:09 +02:00 | | | // --- 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
|
2026-09-30 09:06:59 +02:00 | | | 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);
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | // 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);
|
2026-09-30 09:06:59 +02:00 | | | eventBus.Push(e);
|
| | | }
|
| | | }
|
| | | }
|
| | | };
|
| | | //+------------------------------------------------------------------+
|