137 lines
5.6 KiB
MQL5
137 lines
5.6 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| EqualLiquidity.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 EqualLiquidity : public AbstractLiquidity {
| |
private:
| |
bool HasRequiredInternalSwingsForEqh(datetime leftIndex, datetime rightIndex) {
| |
return CountSwingHighsBetween(leftIndex, rightIndex) > configs.eqConfigs.minSwingCount;
| |
}
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool HasRequiredInternalSwingsForEql(datetime leftIndex, datetime rightIndex) {
| |
return CountSwingLowsBetween(leftIndex, rightIndex) > configs.eqConfigs.minSwingCount;
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
| |
bool IsCleanEQH(datetime leftTime, datetime rightTime, double pointAPrice, double tolerance) {
| |
if(leftTime >= rightTime)
| |
return false;
| |
| |
// If any historical swing high between the two points exceeded the threshold, invalidate EQH
| |
for(int i = 0; i < state.m_swingHighs.Size(); i++) {
| |
TimePrice sh = state.m_swingHighs.At(i);
| |
if(sh.x > leftTime && sh.x < rightTime) {
| |
if(sh.y > pointAPrice + tolerance)
| |
return false;
| |
}
| |
}
| |
return true;
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
bool IsCleanEQL(datetime leftTime, datetime rightTime, double pointAPrice, double tolerance) {
| |
if(leftTime >= rightTime)
| |
return false;
| |
| |
// If any historical swing low between the two points fell below the threshold, invalidate EQL
| |
for(int i = 0; i < state.m_swingLows.Size(); i++) {
| |
TimePrice sl = state.m_swingLows.At(i);
| |
if(sl.x > leftTime && sl.x < rightTime) {
| |
if(sl.y < pointAPrice - tolerance)
| |
return false;
| |
}
| |
}
| |
return true;
| |
}
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
public:
| |
EqualLiquidity() {}
| |
~EqualLiquidity() {}
| |
| |
virtual string GetAnalyserName() override {
| |
return "EqualLiquidity";
| |
}
| |
| |
| |
//+------------------------------------------------------------------+
| |
//| |
| |
//+------------------------------------------------------------------+
| |
virtual void OnSwing(TimePrice &swing, bool isHigh)override {
| |
double tolerance = configs.eqConfigs.tolerance;
| |
int maxTimeDiff = configs.eqConfigs.lookBack ;
| |
| |
if(isHigh) {
| |
for(int i = 0; i < state.m_swingHighs.Size() - 1; i++) {
| |
TimePrice oldSwing = state.m_swingHighs.At(i);
| |
if(oldSwing.x == swing.x)
| |
break;
| |
| |
int k = Bars(bar.symbol, bar.tf, oldSwing.x, swing.x);
| |
if(k > maxTimeDiff)
| |
continue;
| |
| |
if(!NearPrice(oldSwing.y, swing.y, tolerance))
| |
continue;
| |
| |
if(!HasRequiredInternalSwingsForEqh(oldSwing.x, swing.x))
| |
continue;
| |
| |
if(!IsCleanEQH(oldSwing.x, swing.x, oldSwing.y, tolerance))
| |
continue;
| |
| |
string name = "EQH_" + IntegerToString((int)oldSwing.x) + "_" + IntegerToString((int)swing.x);
| |
| |
// CreateTrendL(name, oldSwing.x, oldSwing.y, swing.x, swing.y, clrRed);
| |
EqualLiquidityEvent* e = new EqualLiquidityEvent(bar.symbol, bar.tf, BSL, oldSwing.x, oldSwing.y, swing.x, swing.y);
| |
eventBus.Push(e);
| |
| |
}
| |
} else {
| |
for(int i = 0; i < state.m_swingLows.Size() - 1; i++) {
| |
TimePrice oldSwing = state.m_swingLows.At(i);
| |
if(oldSwing.x == swing.x)
| |
break;
| |
| |
int k = Bars(bar.symbol, bar.tf, oldSwing.x, swing.x);
| |
if(k > maxTimeDiff)
| |
continue;
| |
| |
if(!NearPrice(oldSwing.y, swing.y, tolerance))
| |
continue;
| |
| |
if(!HasRequiredInternalSwingsForEql(oldSwing.x, swing.x))
| |
continue;
| |
| |
if(!IsCleanEQL(oldSwing.x, swing.x, oldSwing.y, tolerance))
| |
continue;
| |
| |
string name = "EQL_" + IntegerToString((int)oldSwing.x) + "_" + IntegerToString((int)swing.x);
| |
// CreateTrendL(name, oldSwing.x, oldSwing.y, swing.x, swing.y, clrDodgerBlue);
| |
| |
EqualLiquidityEvent* e = new EqualLiquidityEvent(bar.symbol, bar.tf, SSL, oldSwing.x, oldSwing.y, swing.x, swing.y);
| |
eventBus.Push(e);
| |
}
| |
}
| |
| |
}
| |
| |
};
| |
//+------------------------------------------------------------------+
|