182 lines
7.8 KiB
MQL5
#property copyright "Lonely Wolf & AI"
| |||
#property version "3.00"
| |||
#property description "SMC MTF EA: Контекст H4 (BOS/Тренд) + Вход по QML на M5"
| |||
#property strict
| |||
| |||
// Подключаем стандартный торговый класс MT5
| |||
#include <Trade\Trade.mqh>
| |||
CTrade trade;
| |||
| |||
//============================== НАСТРОЙКИ СТРАТЕГИИ ==================
| |||
input string _core_ = "--- Торговые Настройки ---";
| |||
input ulong InpMagic = 999111; // Магический номер
| |||
input double InpLotSize = 0.1; // Объём сделки
| |||
input int InpStopLoss = 250; // Стоп-лосс в пипсах (для Gold на M5)
| |||
input int InpTakeProfit = 1000; // Тейк-профит в пипсах (Соотношение 1:4)
| |||
| |||
input string _mtf_ = "--- Настройки Мультитаймфрейма ---";
| |||
input ENUM_TIMEFRAMES InpHTF = PERIOD_H4; // Старший таймфрейм для тренда
| |||
input ENUM_TIMEFRAMES InpLTF = PERIOD_M5; // Младший таймфрейм для входа
| |||
| |||
input string _ind_ = "--- Настройки Индикатора ---";
| |||
input string InpIndName = "LW_Market_Structure_Buffers"; // Имя файла индикатора без .mq5
| |||
input int InpSwingN_HTF = 7; // Настройка SwingN для H4 (крупная структура)
| |||
input int InpSwingN_LTF = 5; // Настройка SwingN для M5 (быстрый вход)
| |||
| |||
// Внутренние хэндлы индикаторов
| |||
int g_htf_handle = INVALID_HANDLE;
| |||
int g_ltf_handle = INVALID_HANDLE;
| |||
| |||
// Защита от повторных входов на одном баре
| |||
datetime g_last_trade_bar = 0;
| |||
| |||
//============================== ИНИЦИАЛИЗАЦИЯ =========================
| |||
int OnInit()
| |||
{
| |||
trade.SetExpertMagicNumber(InpMagic);
| |||
| |||
// 1. Создаем хэндл индикатора для Старшего ТФ (H4)
| |||
g_htf_handle = iCustom(_Symbol, InpHTF, InpIndName, InpSwingN_HTF);
| |||
| |||
// 2. Создаем хэндл индикатора для Младшего ТФ (M5)
| |||
g_ltf_handle = iCustom(_Symbol, InpLTF, InpIndName, InpSwingN_LTF);
| |||
| |||
if(g_htf_handle == INVALID_HANDLE || g_ltf_handle == INVALID_HANDLE)
| |||
{
| |||
Print("КРИТИЧЕСКАЯ ОШИБКА: Не удалось инициализировать индикаторы структуры.");
| |||
return(INIT_FAILED);
| |||
}
| |||
| |||
g_last_trade_bar = 0;
| |||
return(INIT_SUCCEEDED);
| |||
}
| |||
| |||
void OnDeinit(const int reason)
| |||
{
| |||
if(g_htf_handle != INVALID_HANDLE) IndicatorRelease(g_htf_handle);
| |||
if(g_ltf_handle != INVALID_HANDLE) IndicatorRelease(g_ltf_handle);
| |||
}
| |||
| |||
//============================== ОСНОВНОЙ ТИКЛ =========================
| |||
void OnTick()
| |||
{
| |||
// Если позиция уже открыта, отдыхаем (согласно стратегии — один точный вход)
| |||
if(CountPositions() > 0) return;
| |||
| |||
// Контролируем вход строго по закрытию текущей свечи младшего ТФ
| |||
datetime current_ltf_time = iTime(_Symbol, InpLTF, 0);
| |||
if(current_ltf_time == g_last_trade_bar) return;
| |||
| |||
// ----------------------------------------------------------------
| |||
// ШАГ 1: ОПРЕДЕЛЯЕМ ГЛОБАЛЬНЫЙ ТРЕНД НА H4 (Через буферы фракталов)
| |||
// ----------------------------------------------------------------
| |||
double h4_highs[], h4_lows[];
| |||
ArraySetAsSeries(h4_highs, true);
| |||
ArraySetAsSeries(h4_lows, true);
| |||
| |||
if(CopyBuffer(g_htf_handle, 0, 0, 50, h4_highs) < 50 ||
| |||
CopyBuffer(g_htf_handle, 1, 0, 50, h4_lows) < 50) return;
| |||
| |||
int htf_trend = GetCurrentTrend(h4_highs, h4_lows);
| |||
if(htf_trend == 0) return; // Нет четкого тренда на H4 — пропускаем торги
| |||
| |||
// ----------------------------------------------------------------
| |||
// ШАГ 2: ИЩЕМ СИГНАЛЫ И УРОВНИ QML НА МЛАДШЕМ ТФ (M5)
| |||
// ----------------------------------------------------------------
| |||
double m5_qml_buy[], m5_qml_sell[];
| |||
ArraySetAsSeries(m5_qml_buy, true);
| |||
ArraySetAsSeries(m5_qml_sell, true);
| |||
| |||
if(CopyBuffer(g_ltf_handle, 2, 0, 2, m5_qml_buy) < 2 ||
| |||
CopyBuffer(g_ltf_handle, 3, 0, 2, m5_qml_sell) < 2) return;
| |||
| |||
double qml_buy_level = m5_qml_buy[1];
| |||
double qml_sell_level = m5_qml_sell[1];
| |||
| |||
double close_ltf_1 = iClose(_Symbol, InpLTF, 1);
| |||
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
| |||
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
| |||
| |||
// ----------------------------------------------------------------
| |||
// ШАГ 3: СОВМЕЩАЕМ СИГНАЛЫ И ТОРГУЕМ
| |||
// ----------------------------------------------------------------
| |||
| |||
// Условия для BUY: На H4 восходящий тренд + на M5 цена скорректировалась к QML Buy
| |||
if(htf_trend == 1 && qml_buy_level > 0.0)
| |||
{
| |||
if(close_ltf_1 <= qml_buy_level && close_ltf_1 > qml_buy_level - (InpStopLoss * _Point))
| |||
{
| |||
double sl = qml_buy_level - (InpStopLoss * _Point);
| |||
double tp = qml_buy_level + (InpTakeProfit * _Point);
| |||
| |||
if(trade.Buy(InpLotSize, _Symbol, ask, sl, tp, "SMC MTF Buy (H4+M5)"))
| |||
{
| |||
if(trade.ResultRetcode() == TRADE_RETCODE_DONE) g_last_trade_bar = current_ltf_time;
| |||
}
| |||
}
| |||
}
| |||
| |||
// Условия для SELL: На H4 нисходящий тренд + на M5 цена поднялась к QML Sell
| |||
if(htf_trend == -1 && qml_sell_level > 0.0)
| |||
{
| |||
if(close_ltf_1 >= qml_sell_level && close_ltf_1 < qml_sell_level + (InpStopLoss * _Point))
| |||
{
| |||
double sl = qml_sell_level + (InpStopLoss * _Point);
| |||
double tp = qml_sell_level - (InpTakeProfit * _Point);
| |||
| |||
if(trade.Sell(InpLotSize, _Symbol, bid, sl, tp, "SMC MTF Sell (H4+M5)"))
| |||
{
| |||
if(trade.ResultRetcode() == TRADE_RETCODE_DONE) g_last_trade_bar = current_ltf_time;
| |||
}
| |||
}
| |||
}
| |||
}
| |||
| |||
//============================== ОПРЕДЕЛЕНИЕ ТРЕНДА ПО СВИНГАМ ========
| |||
// Логика: если последний сформированный свинг-хай выше предыдущего хая — тренд UP.
| |||
// Если последний свинг-лоу ниже предыдущего лоу — тренд DOWN.
| |||
int GetCurrentTrend(const double &highs[], const double &lows[])
| |||
{
| |||
double last_high = 0, prev_high = 0;
| |||
double last_low = 0, prev_low = 0;
| |||
| |||
// Ищем два последних фрактальных High на истории
| |||
for(int i=0; i<ArraySize(highs); i++)
| |||
{
| |||
if(highs[i] > 0.0)
| |||
{
| |||
if(last_high == 0.0) last_high = highs[i];
| |||
else if(prev_high == 0.0) { prev_high = highs[i]; break; }
| |||
}
| |||
}
| |||
| |||
// Ищем два последних фрактальных Low на истории
| |||
for(int i=0; i<ArraySize(lows); i++)
| |||
{
| |||
if(lows[i] > 0.0)
| |||
{
| |||
if(last_low == 0.0) last_low = lows[i];
| |||
else if(prev_low == 0.0) { prev_low = lows[i]; break; }
| |||
}
| |||
}
| |||
| |||
if(last_high > prev_high && prev_high > 0) return 1; // Тренд вверх (Повышающиеся максимумы)
| |||
if(last_low < prev_low && prev_low > 0) return -1; // Тренд вниз (Понижающиеся минимумы)
| |||
| |||
return 0; // Неопределенность
| |||
}
| |||
| |||
//============================== ПОДГРУЗКА ДАННЫХ И ПОЗИЦИЙ ===========
| |||
int CountPositions()
| |||
{
| |||
int count = 0;
| |||
for(int i = PositionsTotal() - 1; i >= 0; i--)
| |||
{
| |||
if(PositionGetSymbol(i) == _Symbol)
| |||
{
| |||
if(PositionGetInteger(POSITION_MAGIC) == InpMagic)
| |||
count++;
| |||
}
| |||
}
| |||
return count;
| |||
}
|