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);
| |||
}
| |||
}
| |||
| |||
}
| |||
| |||
};
| |||
//+------------------------------------------------------------------+
|