Ind_Aleks_ICT_Entry_V2_TS_I.../CLiquidityLevels.mqh

413 lines
18 KiB
MQL5
Raw Permalink Normal View History

Реализация модуля CLiquidityLevels завершена и успешно скомпилирована. Вот краткое изложение того, что было сделано: Создано: CLiquidityLevels.mqh — новый модуль с кольцевым буферным хранилищем для уровней спроса/предложения, обнаружение развертки (каскадный время-loop), условия con_buy/con_sell с фильтрацией трендов Изменено: CSwingDetector.mqh — форвардное объявление, расширенный Calculate() с 8 новыми параметрами (время[], 6 буферов ликвидности, указатель CLiquidityLevels), обратный вызов в основном цикле после равновесия Ind_Aleks_ICT_Entry_V2_TS_Indie.mq5 — 24 буфера / 16 участков, 4 новых буфера DRAW_LINE (Вверх2/Вверх3/Dn2/Dn3), INDICATOR_CALCULATIONS смещены на индексы 16-23, g_liquidity init с параметром inp_show_lid Сборник: 0 ошибок, 0 предупреждений. Индикатор готов к визуальному тестированию на графике — вы должны увидеть до 6 зеленых горизонтальных линий (3 ближайших уровня предложения выше цены, 3 ближайших уровня спроса ниже). Когда уровень подметается, линии перескакивают на следующие доступные уровни.
2026-02-18 00:00:02 +03:00
//+------------------------------------------------------------------+
//| CLiquidityLevels.mqh |
//| Модуль уровней ликвидности (Liquidity Levels) |
//| Sweep detection + con_buy/con_sell для ICT Entry |
//+------------------------------------------------------------------+
#ifndef CLIQUIDITY_LEVELS_MQH
#define CLIQUIDITY_LEVELS_MQH
//--- Требует SLiquiditySwingState и SStructureSwingState из CSwingDetector.mqh
//--- Подключать ПОСЛЕ CSwingDetector.mqh
//+------------------------------------------------------------------+
//| Структура состояния уровней ликвидности |
//+------------------------------------------------------------------+
struct SLiquidityLevelsState
{
bool break_dem; // Sweep Demand на этом баре
bool break_sup; // Sweep Supply на этом баре
bool con_buy; // Условие Buy активно (persistent)
bool con_sell; // Условие Sell активно (persistent)
double value_dem_lid; // Значение последнего swept Demand уровня
double value_sup_lid; // Значение последнего swept Supply уровня
datetime pre_bar_Dlid_left; // Время создания swept Demand
datetime pre_bar_Dlid_right; // Время sweep Demand
datetime pre_bar_Slid_left; // Время создания swept Supply
datetime pre_bar_Slid_right; // Время sweep Supply
//--- Копии для Entry Signal (сохраняются при активации con_buy/con_sell)
double pre_dem_lid;
double pre_sup_lid;
datetime pre2_bar_Dlid_left;
datetime pre2_bar_Dlid_right;
datetime pre2_bar_Slid_left;
datetime pre2_bar_Slid_right;
};
//+------------------------------------------------------------------+
//| Класс CLiquidityLevels — уровни ликвидности и sweep |
//+------------------------------------------------------------------+
class CLiquidityLevels
{
public:
CLiquidityLevels();
~CLiquidityLevels();
//--- Инициализация — вызывать из OnInit()
bool Init(int len, int max_levels, bool show_lid);
//--- Per-bar расчёт — вызывается из цикла CSwingDetector.Calculate
void Calculate(int bar,
const SLiquiditySwingState &liq,
const SStructureSwingState &str,
const double &high[],
const double &low[],
const double &open[],
const double &close[],
const datetime &time[],
double &buf_liq_up1[],
double &buf_liq_up2[],
double &buf_liq_up3[],
double &buf_liq_dn1[],
double &buf_liq_dn2[],
double &buf_liq_dn3[],
int rates_total);
//--- Полный сброс — вызывать при prev_calculated == 0
void FullReset();
//--- Геттеры
SLiquidityLevelsState GetState() const { return m_state; }
bool GetConBuy() const { return m_state.con_buy; }
bool GetConSell() const { return m_state.con_sell; }
bool GetBreakDem() const { return m_state.break_dem; }
bool GetBreakSup() const { return m_state.break_sup; }
private:
//--- Параметры
int m_len; // Сила пивота Liquidity Swings (Len=5)
int m_max_levels; // Максимум уровней в массиве
bool m_show_lid; // Заполнять буферы отрисовки
//--- Массивы уровней (ring buffer: [0] = самый новый)
double m_lid_sup[]; // Supply уровни (Swing Highs)
double m_lid_dem[]; // Demand уровни (Swing Lows)
datetime m_lid_bar_sup[]; // Время создания Supply уровней
datetime m_lid_bar_dem[]; // Время создания Demand уровней
int m_count_sup; // Количество активных Supply
int m_count_dem; // Количество активных Demand
//--- Состояние
SLiquidityLevelsState m_state;
//--- Внутренние методы
void AddSupplyLevel(double value, datetime time_created);
void AddDemandLevel(double value, datetime time_created);
void RemoveSupplyLevel(int index);
void RemoveDemandLevel(int index);
void CheckSweepDemand(double bar_low, datetime bar_time);
void CheckSweepSupply(double bar_high, datetime bar_time);
void UpdateConditions(double bar_close, double bar_open,
bool up_trend, bool down_trend);
void FillBuffers(int bar,
double &buf_liq_up1[],
double &buf_liq_up2[],
double &buf_liq_up3[],
double &buf_liq_dn1[],
double &buf_liq_dn2[],
double &buf_liq_dn3[]);
void ResetState();
};
//+------------------------------------------------------------------+
//| Конструктор |
//+------------------------------------------------------------------+
CLiquidityLevels::CLiquidityLevels()
{
m_len = 5;
m_max_levels = 200;
m_show_lid = true;
m_count_sup = 0;
m_count_dem = 0;
ZeroMemory(m_state);
}
//+------------------------------------------------------------------+
//| Деструктор |
//+------------------------------------------------------------------+
CLiquidityLevels::~CLiquidityLevels()
{
}
//+------------------------------------------------------------------+
//| Инициализация параметров |
//+------------------------------------------------------------------+
bool CLiquidityLevels::Init(int len, int max_levels, bool show_lid)
{
m_len = len;
m_max_levels = max_levels;
m_show_lid = show_lid;
//--- Выделяем массивы фиксированного размера
ArrayResize(m_lid_sup, m_max_levels);
ArrayResize(m_lid_dem, m_max_levels);
ArrayResize(m_lid_bar_sup, m_max_levels);
ArrayResize(m_lid_bar_dem, m_max_levels);
ResetState();
return true;
}
//+------------------------------------------------------------------+
//| Полный сброс — при prev_calculated == 0 |
//+------------------------------------------------------------------+
void CLiquidityLevels::FullReset()
{
ResetState();
}
//+------------------------------------------------------------------+
//| Сброс всего состояния |
//+------------------------------------------------------------------+
void CLiquidityLevels::ResetState()
{
m_count_sup = 0;
m_count_dem = 0;
ArrayInitialize(m_lid_sup, 0);
ArrayInitialize(m_lid_dem, 0);
ArrayInitialize(m_lid_bar_sup, 0);
ArrayInitialize(m_lid_bar_dem, 0);
ZeroMemory(m_state);
}
//+------------------------------------------------------------------+
//| Добавить Supply уровень (Swing High → ликвидность сверху) |
//| Ring buffer: вставка в начало, последний элемент теряется |
//+------------------------------------------------------------------+
void CLiquidityLevels::AddSupplyLevel(double value, datetime time_created)
{
//--- Сдвиг вправо на 1 позицию (от конца к началу)
int last = MathMin(m_count_sup, m_max_levels - 1);
for(int i = last; i > 0; i--)
{
m_lid_sup[i] = m_lid_sup[i - 1];
m_lid_bar_sup[i] = m_lid_bar_sup[i - 1];
}
//--- Новый уровень в [0]
m_lid_sup[0] = value;
m_lid_bar_sup[0] = time_created;
m_count_sup = MathMin(m_count_sup + 1, m_max_levels);
}
//+------------------------------------------------------------------+
//| Добавить Demand уровень (Swing Low → ликвидность снизу) |
//+------------------------------------------------------------------+
void CLiquidityLevels::AddDemandLevel(double value, datetime time_created)
{
int last = MathMin(m_count_dem, m_max_levels - 1);
for(int i = last; i > 0; i--)
{
m_lid_dem[i] = m_lid_dem[i - 1];
m_lid_bar_dem[i] = m_lid_bar_dem[i - 1];
}
m_lid_dem[0] = value;
m_lid_bar_dem[0] = time_created;
m_count_dem = MathMin(m_count_dem + 1, m_max_levels);
}
//+------------------------------------------------------------------+
//| Удалить Supply уровень по индексу (сдвиг влево) |
//+------------------------------------------------------------------+
void CLiquidityLevels::RemoveSupplyLevel(int index)
{
for(int j = index; j < m_count_sup - 1; j++)
{
m_lid_sup[j] = m_lid_sup[j + 1];
m_lid_bar_sup[j] = m_lid_bar_sup[j + 1];
}
m_count_sup--;
}
//+------------------------------------------------------------------+
//| Удалить Demand уровень по индексу (сдвиг влево) |
//+------------------------------------------------------------------+
void CLiquidityLevels::RemoveDemandLevel(int index)
{
for(int j = index; j < m_count_dem - 1; j++)
{
m_lid_dem[j] = m_lid_dem[j + 1];
m_lid_bar_dem[j] = m_lid_bar_dem[j + 1];
}
m_count_dem--;
}
//+------------------------------------------------------------------+
//| Проверка sweep Demand уровней (tz.md строки 608-620) |
//| Sweep: цена Low пробивает уровень поддержки |
//| Множественный sweep: while-loop пока low <= lid_dem[0] |
//+------------------------------------------------------------------+
void CLiquidityLevels::CheckSweepDemand(double bar_low, datetime bar_time)
{
if(m_count_dem == 0)
return;
if(bar_low > m_lid_dem[0])
return;
//--- Минимум один уровень пробит
while(m_count_dem > 0 && bar_low <= m_lid_dem[0])
{
//--- Сохраняем данные swept уровня
m_state.value_dem_lid = m_lid_dem[0];
m_state.pre_bar_Dlid_left = m_lid_bar_dem[0];
m_state.pre_bar_Dlid_right = bar_time;
//--- Удаляем уровень из массива
RemoveDemandLevel(0);
}
m_state.break_dem = true;
}
//+------------------------------------------------------------------+
//| Проверка sweep Supply уровней (tz.md строки 622-634) |
//| Sweep: цена High пробивает уровень сопротивления |
//+------------------------------------------------------------------+
void CLiquidityLevels::CheckSweepSupply(double bar_high, datetime bar_time)
{
if(m_count_sup == 0)
return;
if(bar_high < m_lid_sup[0])
return;
//--- Минимум один уровень пробит
while(m_count_sup > 0 && bar_high >= m_lid_sup[0])
{
//--- Сохраняем данные swept уровня
m_state.value_sup_lid = m_lid_sup[0];
m_state.pre_bar_Slid_left = m_lid_bar_sup[0];
m_state.pre_bar_Slid_right = bar_time;
//--- Удаляем уровень из массива
RemoveSupplyLevel(0);
}
m_state.break_sup = true;
}
//+------------------------------------------------------------------+
//| Обновление торговых условий con_buy/con_sell |
//| (tz.md строки 921-933, 965-977) |
//+------------------------------------------------------------------+
void CLiquidityLevels::UpdateConditions(double bar_close, double bar_open,
bool up_trend, bool down_trend)
{
//=== Активация con_buy: Demand swept + цена выше swept уровня ===
if(m_state.break_dem
&& bar_close > m_state.value_dem_lid
&& bar_open > m_state.value_dem_lid
&& up_trend)
{
m_state.con_buy = true;
m_state.pre_dem_lid = m_state.value_dem_lid;
m_state.pre2_bar_Dlid_left = m_state.pre_bar_Dlid_left;
m_state.pre2_bar_Dlid_right = m_state.pre_bar_Dlid_right;
m_state.con_sell = false; // Деактивация противоположного
}
//=== Активация con_sell: Supply swept + цена ниже swept уровня ===
if(m_state.break_sup
&& bar_close < m_state.value_sup_lid
&& bar_open < m_state.value_sup_lid
&& down_trend)
{
m_state.con_sell = true;
m_state.pre_sup_lid = m_state.value_sup_lid;
m_state.pre2_bar_Slid_left = m_state.pre_bar_Slid_left;
m_state.pre2_bar_Slid_right = m_state.pre_bar_Slid_right;
m_state.con_buy = false; // Деактивация противоположного
}
//=== Деактивация con_buy: цена вернулась ниже swept уровня ===
if(m_state.con_buy && bar_close < m_state.value_dem_lid)
m_state.con_buy = false;
//=== Деактивация con_sell: цена вернулась выше swept уровня ===
if(m_state.con_sell && bar_close > m_state.value_sup_lid)
m_state.con_sell = false;
}
//+------------------------------------------------------------------+
//| Заполнение буферов: 3 ближайших уровня на сторону |
//+------------------------------------------------------------------+
void CLiquidityLevels::FillBuffers(int bar,
double &buf_liq_up1[],
double &buf_liq_up2[],
double &buf_liq_up3[],
double &buf_liq_dn1[],
double &buf_liq_dn2[],
double &buf_liq_dn3[])
{
if(m_show_lid)
{
buf_liq_up1[bar] = (m_count_sup > 0) ? m_lid_sup[0] : EMPTY_VALUE;
buf_liq_up2[bar] = (m_count_sup > 1) ? m_lid_sup[1] : EMPTY_VALUE;
buf_liq_up3[bar] = (m_count_sup > 2) ? m_lid_sup[2] : EMPTY_VALUE;
buf_liq_dn1[bar] = (m_count_dem > 0) ? m_lid_dem[0] : EMPTY_VALUE;
buf_liq_dn2[bar] = (m_count_dem > 1) ? m_lid_dem[1] : EMPTY_VALUE;
buf_liq_dn3[bar] = (m_count_dem > 2) ? m_lid_dem[2] : EMPTY_VALUE;
}
else
{
buf_liq_up1[bar] = EMPTY_VALUE;
buf_liq_up2[bar] = EMPTY_VALUE;
buf_liq_up3[bar] = EMPTY_VALUE;
buf_liq_dn1[bar] = EMPTY_VALUE;
buf_liq_dn2[bar] = EMPTY_VALUE;
buf_liq_dn3[bar] = EMPTY_VALUE;
}
}
//+------------------------------------------------------------------+
//| Главный per-bar расчёт |
//| Порядок: добавление → sweep → conditions → буферы |
//+------------------------------------------------------------------+
void CLiquidityLevels::Calculate(int bar,
const SLiquiditySwingState &liq,
const SStructureSwingState &str,
const double &high[],
const double &low[],
const double &open[],
const double &close[],
const datetime &time[],
double &buf_liq_up1[],
double &buf_liq_up2[],
double &buf_liq_up3[],
double &buf_liq_dn1[],
double &buf_liq_dn2[],
double &buf_liq_dn3[],
int rates_total)
{
//--- 1. Сброс per-bar флагов
m_state.break_dem = false;
m_state.break_sup = false;
//--- 2. Добавление уровней при подтверждении свинга
//--- Supply: Ch_swh AND sw_high >= ph (ss_high = ph для текущего бара)
if(liq.ch_swh && liq.sw_high >= liq.ss_high)
{
//--- Время создания уровня = время бара свинга
int bar_idx = liq.bar_sw_high;
if(bar_idx >= 0 && bar_idx < rates_total)
AddSupplyLevel(liq.sw_high, time[bar_idx]);
}
//--- Demand: Ch_swl AND sw_low <= pl (ss_low = pl для текущего бара)
if(liq.ch_swl && liq.sw_low <= liq.ss_low)
{
int bar_idx = liq.bar_sw_low;
if(bar_idx >= 0 && bar_idx < rates_total)
AddDemandLevel(liq.sw_low, time[bar_idx]);
}
//--- 3. Sweep detection
CheckSweepDemand(low[bar], time[bar]);
CheckSweepSupply(high[bar], time[bar]);
//--- 4. Обновление торговых условий
UpdateConditions(close[bar], open[bar], str.up_trend, str.down_trend);
//--- 5. Заполнение буферов
FillBuffers(bar, buf_liq_up1, buf_liq_up2, buf_liq_up3,
buf_liq_dn1, buf_liq_dn2, buf_liq_dn3);
}
#endif // CLIQUIDITY_LEVELS_MQH