2026-09-30 09:06:59 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| Chapter3.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 "Liquidity/EqualLiquidity.mqh"
|
| | | #include "Liquidity/StructuralLiquidity.mqh"
|
| | | #include "Liquidity/MomentumShiftLiquidity.mqh"
|
2026-10-26 06:27:09 +02:00 | | | #include "Liquidity/TrendlineLiquidity.mqh"
|
| | | #include "Liquidity/ImbalanceLiquidity.mqh"
|
| | | //#include "Liquidity/TrendlineLiquidity.mqh"
|
| | |
|
| | | // 1. Hyperparameters (Inputs)
|
| | | input double InpMomMaxPercent = 60.0; // MS: Max Percent
|
| | | input double InpMomMinPercent = 45.0; // MS: Min Percent
|
| | | input int InpMomTolerancePoints = 50; // MS: Tolerance (Points)
|
| | | input int InpMomMaxSwingCount = 10; // MS: Max Pullback Swings
|
| | |
|
| | |
|
2026-09-30 09:06:59 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class Chapter3: public AbstractAnalyser {
|
| | | private:
|
| | | Indicator* ind;
|
| | | TimeFrameDataSeries* bar;
|
| | | CArrayList<AbstractLiquidity*>* liquidityScanners;
|
| | |
|
| | | LiquidityConfigs configs;
|
| | |
|
| | | CArrayList<LiqState*>* states;
|
| | | LiqState* activeState;
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | TimePrice MakeSwingHigh(int i) {
|
| | | TimePrice tp;
|
| | | tp.i = i;
|
| | | tp.x = bar.Time(i);
|
| | | tp.y = bar.High(i);
|
| | | return tp;
|
| | | }
|
| | | //---
|
| | |
|
| | | TimePrice MakeSwingLow(int i) {
|
| | | TimePrice tp;
|
| | | tp.i = i;
|
| | | tp.x = bar.Time(i);
|
| | | tp.y = bar.Low(i);
|
| | | return tp;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | |
|
| | | int FindExist(string symbol, ENUM_TIMEFRAMES tf) {
|
| | | for(int i = 0; i < states.Size(); i++) {
|
| | | LiqState* data = states.At(i);
|
| | | if(data.symbol == symbol && data.tf == tf)
|
| | | return i;
|
| | | }
|
| | | return -1;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | |
|
| | | void DetectAndNotifySwings(int i) {
|
| | | if(IsSwingHigh(i, ind)) {
|
| | | TimePrice swing = MakeSwingHigh(i);
|
| | |
|
| | | if(!activeState.HasSwingAt(swing.x, true)) {
|
| | | ZigzagSwing s;
|
| | | s.point = swing;
|
| | | s.isHigh = true;
|
| | | activeState.m_swings.Add(s);
|
| | | activeState.m_swingHighs.Add(swing);
|
| | |
|
| | | for(int j = 0; j < liquidityScanners.Size(); j++)
|
| | | liquidityScanners.At(j).OnSwing(swing, true);
|
| | | }
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | |
|
| | | if(IsSwingLow(i, ind)) {
|
| | | TimePrice swing = MakeSwingLow(i);
|
| | | if(!activeState.HasSwingAt(swing.x, false)) {
|
| | | ZigzagSwing s;
|
| | | s.point = swing;
|
| | | s.isHigh = false;
|
| | | activeState.m_swings.Add(s);
|
| | | activeState.m_swingLows.Add(swing);
|
| | |
|
| | | for(int j = 0; j < liquidityScanners.Size(); j++)
|
| | | liquidityScanners.At(j).OnSwing(swing, false);
|
| | | }
|
| | | }
|
| | | }
|
| | | public:
|
| | | Chapter3() {
|
| | | liquidityScanners = new CArrayList<AbstractLiquidity*>();
|
| | |
|
| | | // AbstractLiquidity* eqLiq = new EqualLiquidity();
|
| | | // liquidityScanners.Add(eqLiq);
|
| | |
|
| | | //AbstractLiquidity* structLiq = new StructuralLiquidity();
|
| | | //liquidityScanners.Add(structLiq);
|
| | |
|
2026-10-26 06:27:09 +02:00 | | | //AbstractLiquidity* momShiftLiq = new MomentumShiftLiquidity();
|
| | | // liquidityScanners.Add(momShiftLiq);
|
| | |
|
| | | //AbstractLiquidity* trendLiq = new TrendlineLiquidity();
|
| | | // liquidityScanners.Add(trendLiq);
|
| | |
|
| | | AbstractLiquidity* imbLiq = new ImbalanceLiquidity();
|
| | | liquidityScanners.Add(imbLiq);
|
2026-09-30 09:06:59 +02:00 | | |
|
| | | configs.eqConfigs.tolerance = 150000 * _Point;
|
| | | configs.eqConfigs.minSwingCount = 0;
|
| | | configs.eqConfigs.lookBack = 75;
|
| | |
|
| | | configs.structConfigs.lookBack = 5;
|
| | | configs.structConfigs.maxPercent = 60;
|
| | | configs.structConfigs.minPercent = 45;
|
2026-10-26 06:27:09 +02:00 | | |
|
2026-09-30 09:06:59 +02:00 | | | //configs.momShiftConfigs.lookBack = 5;
|
2026-10-26 06:27:09 +02:00 | | | // 3. Configuration Initialization
|
| | | configs.momShiftConfigs.maxPercent = InpMomMaxPercent;
|
| | | configs.momShiftConfigs.minPercent = InpMomMinPercent;
|
| | | configs.momShiftConfigs.tolerance = InpMomTolerancePoints * _Point; // Converted to price format
|
| | | configs.momShiftConfigs.maxSwingCount = InpMomMaxSwingCount;
|
2026-09-30 09:06:59 +02:00 | | |
|
| | |
|
| | | states = new CArrayList<LiqState*>();
|
| | |
|
| | | }
|
| | | ~Chapter3() {
|
| | | for(int i = 0; i < liquidityScanners.Size(); i++) {
|
| | | AbstractLiquidity* liquidityScanner = liquidityScanners.At(i);
|
| | | delete liquidityScanner;
|
| | | }
|
| | |
|
| | | for(int i = 0; i < states.Size(); i++) {
|
| | | LiqState* state = states.At(i);
|
| | | delete state;
|
| | | }
|
| | |
|
| | | delete liquidityScanners;
|
| | | delete states;
|
| | | }
|
| | |
|
| | | virtual void Init(EventBus* bus) {
|
| | | AbstractAnalyser::Init(bus);
|
| | |
|
| | | for(int i = 0; i < liquidityScanners.Size(); i++) {
|
| | | AbstractLiquidity* liquidityScanner = liquidityScanners.At(i);
|
| | | liquidityScanner.Init(bus);
|
| | | liquidityScanner.SetConfigs(configs);
|
| | | }
|
| | |
|
| | | }
|
| | | void SetConfigs(LiquidityConfigs &c) {
|
| | | configs = c;
|
| | | for(int i = 0; i < liquidityScanners.Size(); i++) {
|
| | | liquidityScanners.At(i).SetConfigs(configs);
|
| | | }
|
| | | }
|
| | |
|
| | | virtual string GetAnalyserName() override {
|
| | | return "Chapter3";
|
| | | }
|
| | |
|
| | | virtual void ProcessBar(TimeFrameDataSeries* series, int i) override {
|
| | |
|
| | | ind = series.GetIndicator(0);
|
| | | bar = series;
|
| | |
|
| | | int stateIndex = FindExist(series.symbol, series.tf);
|
| | |
|
| | | if(stateIndex < 0) {
|
| | | LiqState* s = new LiqState();
|
| | | s.symbol = series.symbol;
|
| | |
|
| | | s.tf = series.tf;
|
| | | states.Add(s);
|
| | | activeState = s;
|
| | | } else {
|
| | | activeState = states.At(stateIndex);
|
| | | }
|
| | |
|
| | | for(int j = 0; j < liquidityScanners.Size(); j++) {
|
| | | AbstractLiquidity* liquidityScanner = liquidityScanners.At(j);
|
| | | liquidityScanner.ProcessBar(activeState, ind, series, i);
|
| | | }
|
| | |
|
| | | DetectAndNotifySwings(i);
|
| | | }
|
| | |
|
| | | };
|
| | | //+------------------------------------------------------------------+
|