116 lines
5.2 KiB
MQL5
116 lines
5.2 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| StructuralLiquidity.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 StructuralLiquidity : public AbstractLiquidity {
| |||
private:
| |||
double CalcPrevLegPercent(double pA, double pB, double pC, double pD) {
| |||
double leg = MathAbs(pA - pB);
| |||
if(leg <= 0.0)
| |||
return -1.0;
| |||
return (MathAbs(pC - pD) / leg) * 100.0;
| |||
}
| |||
| |||
public:
| |||
StructuralLiquidity() {}
| |||
~StructuralLiquidity() {}
| |||
| |||
virtual string GetAnalyserName() override {
| |||
return "StructuralLiquidity";
| |||
}
| |||
| |||
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 for target reach
| |||
if(NearPrice(swing.y, state.pullbackTargetPrice, configs.eqConfigs.tolerance)) {
| |||
// Print("Pullback to level completed after ", state.pullbackSwingCount, " swings");
| |||
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) {
| |||
// Print("Pullback invalidated. Swings = ", state.pullbackSwingCount);
| |||
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 legDiff = CalcPrevLegPercent(s5.point.y, s4.point.y, s3.point.y, s2.point.y);
| |||
| |||
// --- Bullish structural pattern (EQH / BOS) ---
| |||
if(isHigh) {
| |||
if((s5.point.y > s3.point.y && s1.point.y <= s3.point.y && s4.point.y > s2.point.y) &&
| |||
s5.isHigh == true && s3.isHigh == true && legDiff > configs.structConfigs.minPercent) {
| |||
// Draw structural legs
| |||
CreateTrendL("s1", s1.point, s2.point, clrAqua);
| |||
CreateTrendL("s2", s2.point, s3.point, clrAqua);
| |||
CreateTrendL("s3", s3.point, s4.point, clrAqua);
| |||
CreateTrendL("s4", s4.point, s5.point, clrAqua);
| |||
| |||
// Activate pullback monitoring
| |||
state.pullbackActive = true;
| |||
state.pullbackTargetPrice = s3.point.y;
| |||
state.pullbackUpperLevel = s3.point.y + configs.eqConfigs.tolerance;
| |||
state.pullbackLowerLevel = s1.point.y - configs.eqConfigs.tolerance;
| |||
state.pullbackSwingCount = 0;
| |||
state.pullbackLastPoint = s1.point;
| |||
| |||
StructuralLiquidityEvent* e = new StructuralLiquidityEvent(bar.symbol, bar.tf, BSL, s3.point.x, s3.point.y, bar.bar.LastBarOpen(), s3.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) &&
| |||
s5.isHigh == false && s3.isHigh == false && legDiff > configs.structConfigs.minPercent) {
| |||
// Draw structural legs
| |||
CreateTrendL("s1", s1.point, s2.point, clrAqua);
| |||
CreateTrendL("s2", s2.point, s3.point, clrAqua);
| |||
CreateTrendL("s3", s3.point, s4.point, clrAqua);
| |||
CreateTrendL("s4", s4.point, s5.point, clrAqua);
| |||
| |||
// Activate pullback monitoring
| |||
state.pullbackActive = true;
| |||
state.pullbackTargetPrice = s3.point.y;
| |||
state.pullbackUpperLevel = s3.point.y + configs.eqConfigs.tolerance;
| |||
state.pullbackLowerLevel = s1.point.y - configs.eqConfigs.tolerance;
| |||
state.pullbackSwingCount = 0;
| |||
state.pullbackLastPoint = s1.point;
| |||
StructuralLiquidityEvent* e = new StructuralLiquidityEvent(bar.symbol, bar.tf, SSL, s3.point.x, s3.point.y, bar.bar.LastBarOpen(), s3.point.y);
| |||
eventBus.Push(e);
| |||
}
| |||
}
| |||
}
| |||
};
| |||
//+------------------------------------------------------------------+
|