mql5/Experts/_FrameWork/Analysers/Liquidity/AbstractLiquidity.mqh
younglubah-gmail c5aaa5e1e2
2026-10-26 06:27:09 +02:00

205 lines
6.2 KiB
MQL5

//+------------------------------------------------------------------+
//| AbstractLiquidity.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 "../AbstractAnalyser.mqh"
struct EqConfigs {
double tolerance;
int minSwingCount;
int lookBack;
bool allowAverage;
};
struct StructConfigs {
double maxPercent;
double minPercent;
int lookBack;
};
struct MomShiftConfigs {
double maxPercent;
double minPercent;
double tolerance; // Dedicated tolerance for MomShift
int maxSwingCount; // Dynamic swing limit for pullbacks
};
struct LiquidityLvl {
TimePrice a;
TimePrice b;
};
struct LiquidityConfigs {
EqConfigs eqConfigs;
StructConfigs structConfigs;
MomShiftConfigs momShiftConfigs;
};
struct ZigzagSwing {
TimePrice point;
bool isHigh;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class LiqState {
public:
string symbol;
ENUM_TIMEFRAMES tf;
CArrayList<TimePrice>* m_swingHighs;
CArrayList<TimePrice>* m_swingLows;
CArrayList<ZigzagSwing>* m_swings;
// Pullback tracking (per state)
double pullbackTargetPrice;
double pullbackUpperLevel; // s3.y + tolerance
double pullbackLowerLevel; // s1.y - tolerance
int pullbackSwingCount;
bool pullbackActive;
datetime lastMomShiftS1Time; // prevents duplicate fires
double momShiftInvalidationBuffer; // optional, or use configs
// Inside LiqState:
double protectedLowPrice;
double protectedHighPrice;
datetime protectedLowTime;
datetime protectedHighTime;
bool hasProtectedLow;
bool hasProtectedHigh;
TimePrice pullbackLastPoint;
LiqState() {
m_swingHighs = new CArrayList<TimePrice>();
m_swingLows = new CArrayList<TimePrice>();
m_swings = new CArrayList<ZigzagSwing>();
pullbackTargetPrice = 0.0;
pullbackUpperLevel = 0.0;
pullbackLowerLevel = 0.0;
pullbackSwingCount = 0;
pullbackActive = false;
protectedLowPrice = 0.0;
protectedHighPrice = 0.0;
protectedLowTime = 0;
protectedHighTime = 0;
hasProtectedLow = false;
hasProtectedHigh = false;
}
~LiqState() {
delete m_swingHighs;
delete m_swingLows;
delete m_swings;
}
bool HasSwingAt(datetime time, bool isHigh) {
if(isHigh) {
for(int i = 0; i < m_swingHighs.Size(); i++)
if(m_swingHighs.At(i).x == time)
return true;
} else {
for(int i = 0; i < m_swingLows.Size(); i++)
if(m_swingLows.At(i).x == time)
return true;
}
return false;
}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class AbstractLiquidity : public AbstractAnalyser {
protected:
Indicator* ind;
TimeFrameDataSeries* bar;
LiqState* state;
LiquidityConfigs configs;
bool NearPrice(double a, double b, double tol) {
return MathAbs(a - b) <= tol;
}
void CreateTrendL(string name, datetime t1, double p1, datetime t2, double p2, color clr) {
long chart_id = ChartID();
bool created = ObjectCreate(chart_id, name, OBJ_TREND, 0, t1, p1, t2, p2);
if(created) {
ObjectSetInteger(chart_id, name, OBJPROP_COLOR, clr);
ObjectSetInteger(chart_id, name, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(chart_id, name, OBJPROP_WIDTH, 2);
}
}
void CreateTrendL(string name, const TimePrice &p1, const TimePrice &p2, color clr) {
CreateTrendL(name, p1.x, p1.y, p2.x, p2.y, clr);
}
int CountSwingHighsBetween(datetime leftTime, datetime rightTime) {
int count = 0;
for(int i = 0; i < state.m_swingLows.Size(); i++) {
TimePrice sl = state.m_swingLows.At(i);
if(sl.x > leftTime && sl.x < rightTime)
count++;
}
return count;
}
//--- Checks intermediate swings using absolute datetime (bypasses 5-bar limit)
int CountSwingLowsBetween(datetime leftTime, datetime rightTime) {
int count = 0;
for(int i = 0; i < state.m_swingHighs.Size(); i++) {
TimePrice sh = state.m_swingHighs.At(i);
if(sh.x > leftTime && sh.x < rightTime)
count++;
}
return count ;
}
bool HasSwingAt(datetime time, bool isHigh) {
if(isHigh) {
for(int i = 0; i < state.m_swingHighs.Size(); i++) {
if(state.m_swingHighs.At(i).x == time) {
return true;
}
}
} else {
for(int i = 0; i < state.m_swingLows.Size(); i++) {
if(state.m_swingLows.At(i).x == time)
return true;
}
}
return false;
}
public:
AbstractLiquidity() {}
~AbstractLiquidity() {}
virtual void ProcessBar(TimeFrameDataSeries* series, int i) override { }
virtual void ProcessBar(LiqState* s, Indicator* _ind, TimeFrameDataSeries* series, int i) {
ind = _ind;
bar = series;
state = s;
}
void SetConfigs(LiquidityConfigs &c) {
configs = c;
}
virtual void OnSwing(TimePrice &swing, bool isHigh) = 0;
};
//+------------------------------------------------------------------+