Робот 1: «Следователь за трендом» (Trend Follower) – MQL5 Код
Вот полный код советника для MetaTrader 5, реализующий стратегию следования за трендом:
```mql5
//+–+
//| TrendFollower.mq5 |
//| Автор: Алготрейдинг Книга |
//| https://example.com |
//+–+
#property copyright "Алготрейдинг Книга"
#property link "https://example.com"
#property version "1.00"
//+–+
//| Входные параметры советника |
//+–+
input double LotSize = 0.1; // Размер лота
input int FastMAPeriod = 50; // Период быстрой MA
input int SlowMAPeriod = 200; // Период медленной MA
input int ADXPeriod = 14; // Период ADX
input double ADXThreshold = 25.0; // Пороговое значение ADX для силы тренда
input int StopLoss = 200; // Стоп-лосс в пунктах
input int TakeProfit = 400; // Тейк-профит в пунктах
input bool UseTrailingStop = false; // Использовать трейлинг-стоп
input int TrailingStop = 100; // Размер трейлинг-стопа в пунктах
input int MagicNumber = 123456; // Магический номер для идентификации ордеров
input string OrderComment = "TrendFollower"; // Комментарий к ордерам
//+–+
//| Глобальные переменные |
//+–+
int fastMAHandle; // Хэндл для быстрой MA
int slowMAHandle; // Хэндл для медленной MA
int adxHandle; // Хэндл для ADX
double prevFastMA = 0; // Значение быстрой MA на предыдущем баре
double prevSlowMA = 0; // Значение медленной MA на предыдущем баре
//+–+
//| Функция инициализации советника |
//+–+
int OnInit()
{
// Проверка входных параметров
if(FastMAPeriod >= SlowMAPeriod)
{
Alert("Ошибка: Период быстрой MA должен быть меньше периода медленной MA");
return INIT_PARAMETERS_INCORRECT;
}
if(LotSize <= 0 || LotSize > 100)
{
Alert("Ошибка: Неверный размер лота");
return INIT_PARAMETERS_INCORRECT;
}
// Создание хэндлов для индикаторов
fastMAHandle = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
slowMAHandle = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
adxHandle = iADX(_Symbol, _Period, ADXPeriod);
// Проверка создания хэндлов
if(fastMAHandle == INVALID_HANDLE || slowMAHandle == INVALID_HANDLE || adxHandle == INVALID_HANDLE)
{
Alert("Ошибка создания индикаторов");
return INIT_FAILED;
}
// Получение начальных значений индикаторов
double fastMA[1], slowMA[1];
if(CopyBuffer(fastMAHandle, 0, 1, 1, fastMA) < 1 || CopyBuffer(slowMAHandle, 0, 1, 1, slowMA) < 1)
{
Alert("Ошибка копирования данных индикаторов");
return INIT_FAILED;
}
prevFastMA = fastMA[0];
prevSlowMA = slowMA[0];
Print("Советник TrendFollower успешно инициализирован");
return INIT_SUCCEEDED;
}
//+–+
//| Функция деинициализации советника |
//+–+
void OnDeinit(const int reason)
{
// Освобождение хэндлов индикаторов
if(fastMAHandle != INVALID_HANDLE)
IndicatorRelease(fastMAHandle);
if(slowMAHandle != INVALID_HANDLE)
IndicatorRelease(slowMAHandle);
if(adxHandle != INVALID_HANDLE)
IndicatorRelease(adxHandle);
Print("Советник деинициализирован, причина: ", reason);
}
//+–+
//| Функция обработки тиков |
//+–+
void OnTick()
{
// Проверяем, есть ли уже открытые позиции этим советником
if(PositionsTotal() > 0)
{
CheckForClose(); // Проверяем условия для закрытия
ManageTrailingStop(); // Управляем трейлинг-стопом
return;
}
// Проверяем условия для открытия новой позиции
CheckForOpen();
}
//+–+
//| Проверка условий для открытия позиции |
//+–+
void CheckForOpen()
{
// Получаем значения индикаторов на текущем и предыдущем барах
double fastMA[2], slowMA[2], adxValue[2];
if(CopyBuffer(fastMAHandle, 0, 0, 2, fastMA) < 2) return;
if(CopyBuffer(slowMAHandle, 0, 0, 2, slowMA) < 2) return;
// Получаем значение линии ADX (индекс направленного движения)
if(CopyBuffer(adxHandle, 0, 0, 2, adxValue) < 2) return;
// Проверяем условия для BUY (покупки)
// 1. Быстрая MA пересекла медленную MA снизу вверх
// 2. ADX выше порогового значения (сильный тренд)
if(fastMA[1] <= slowMA[1] && fastMA[0] > slowMA[0] && adxValue[0] > ADXThreshold)
{
OpenPosition(ORDER_TYPE_BUY);
}
// Проверяем условия для SELL (продажи)
// 1. Быстрая MA пересекла медленную MA сверху вниз
// 2. ADX выше порогового значения (сильный тренд)
else if(fastMA[1] >= slowMA[1] && fastMA[0] < slowMA[0] && adxValue[0] > ADXThreshold)
{
OpenPosition(ORDER_TYPE_SELL);
}
// Сохраняем текущие значения для следующего сравнения
prevFastMA = fastMA[0];
prevSlowMA = slowMA[0];
}
//+–+
//| Открытие позиции |
//+–+
void OpenPosition(ENUM_ORDER_TYPE orderType)
{
// Подготовка данных для торгового запроса
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
// Установка символа
request.symbol = _Symbol;
request.volume = LotSize;
request.magic = MagicNumber;
request.comment = OrderComment;
// Установка типа ордера
request.type = orderType;
// Расчет цены входа
if(orderType == ORDER_TYPE_BUY)
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.sl = request.price – StopLoss * _Point;
request.tp = request.price + TakeProfit * _Point;
}
else if(orderType == ORDER_TYPE_SELL)
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.sl = request.price + StopLoss * _Point;
request.tp = request.price – TakeProfit * _Point;
}
// Установка отклонения от цены
request.deviation = 10;
request.type_filling = ORDER_FILLING_FOK;
// Отправка торгового запроса
if(OrderSend(request, result))
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("Позиция открыта успешно. Тикет: ", result.order);
}
else
{
Print("Ошибка открытия позиции. Код: ", result.retcode, " Комментарий: ", result.comment);
}
}
else
{
Print("Ошибка OrderSend. Код ошибки: ", GetLastError());
}
}
//+–+
//| Проверка условий для закрытия позиции |
//+–+
void CheckForClose()
{
// Получаем значения индикаторов на текущем баре
double fastMA[1], slowMA[1];
if(CopyBuffer(fastMAHandle, 0, 0, 1, fastMA) < 1) return;
if(CopyBuffer(slowMAHandle, 0, 0, 1, slowMA) < 1) return;
// Проверяем все открытые позиции
for(int i = PositionsTotal() – 1; i >= 0; i–)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
long positionType = PositionGetInteger(POSITION_TYPE);
// Закрываем BUY позицию если быстрая MA пересекла медленную сверху вниз
if(positionType == POSITION_TYPE_BUY && fastMA[0] < slowMA[0])
{
ClosePosition(i);
}
// Закрываем SELL позицию если быстрая MA пересекла медленную снизу вверх
else if(positionType == POSITION_TYPE_SELL && fastMA[0] > slowMA[0])
{
ClosePosition(i);
}
}
}
}
//+–+
//| Закрытие позиции |
//+–+
void ClosePosition(int positionIndex)
{
// Получаем информацию о позиции
ulong ticket = PositionGetTicket(positionIndex);
if(ticket <= 0) return;
// Подготовка торгового запроса
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.magic = MagicNumber;
request.comment = "Close by signal";
// Установка цены закрытия
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.type = ORDER_TYPE_SELL;
}
else
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.type = ORDER_TYPE_BUY;
}
request.deviation = 10;
request.type_filling = ORDER_FILLING_FOK;
// Отправка запроса на закрытие
if(OrderSend(request, result))
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("Позиция закрыта успешно. Тикет: ", result.order);
}
else
{
Print("Ошибка закрытия позиции. Код: ", result.retcode);
}
}
}
//+–+
//| Управление трейлинг-стопом |
//+–+
void ManageTrailingStop()
{
if(!UseTrailingStop) return;
for(int i = PositionsTotal() – 1; i >= 0; i–)
{
if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
ulong ticket = PositionGetTicket(i);
if(ticket <= 0) continue;
double currentSL = PositionGetDouble(POSITION_SL);
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
long positionType = PositionGetInteger(POSITION_TYPE);
// Для длинной позиции (BUY)
if(positionType == POSITION_TYPE_BUY)
{
double newSL = currentPrice – TrailingStop * _Point;
if(newSL > currentSL && newSL > openPrice)
{
ModifyStopLoss(ticket, newSL);
}
}
// Для короткой позиции (SELL)
else if(positionType == POSITION_TYPE_SELL)
{
double newSL = currentPrice + TrailingStop * _Point;
if(newSL < currentSL && newSL < openPrice)
{
ModifyStopLoss(ticket, newSL);
}
}
}
}
}
//+–+
//| Модификация стоп-лосса |
//+–+
void ModifyStopLoss(ulong ticket, double newStopLoss)
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
request.action = TRADE_ACTION_SLTP;
request.position = ticket;
request.symbol = _Symbol;
request.sl = newStopLoss;
request.magic = MagicNumber;
// Сохраняем текущий тейк-профит
request.tp = PositionGetDouble(POSITION_TP);
if(OrderSend(request, result))
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("Стоп-лосс модифицирован. Новый SL: ", newStopLoss);
}
}
}
//+–+
//| Функция для логов |
//+–+
void PrintStatus()
{
double fastMA[1], slowMA[1], adxValue[1];
if(CopyBuffer(fastMAHandle, 0, 0, 1, fastMA) < 1) return;
if(CopyBuffer(slowMAHandle, 0, 0, 1, slowMA) < 1) return;
if(CopyBuffer(adxHandle, 0, 0, 1, adxValue) < 1) return;
Print("Текущие значения: FastMA=", fastMA[0], " SlowMA=", slowMA[0], " ADX=", adxValue[0]);
}
```
Инструкция по установке и использованию:
1. Установка советника:
· Сохраните код в файл TrendFollower.mq5
· Поместите файл в папку MQL5/Experts/ вашего терминала MetaTrader 5
· Перезапустите MetaTrader 5 или обновите список экспертов (Навигатор -> Эксперты -> Обновить)
2. Настройка параметров:
Основные параметры:
· LotSize = 0.1 – Размер лота (рекомендуется начинать с 0.01)
· FastMAPeriod = 50 – Период быстрой скользящей средней
· SlowMAPeriod = 200 – Период медленной скользящей средней
· ADXPeriod = 14 – Период индикатора ADX
· ADXThreshold = 25.0 – Минимальное значение ADX для силы тренда
· StopLoss = 200 – Стоп-лосс в пунктах
· TakeProfit = 400 – Тейк-профит в пунктах
Дополнительные параметры:
· UseTrailingStop = false – Включить трейлинг-стоп
· TrailingStop = 100 – Размер трейлинг-стопа в пунктах
· MagicNumber = 123456 – Уникальный идентификатор ордеров
3. Рекомендации по использованию:
Оптимизация параметров:
```mql5
// Для разных таймфреймов рекомендуются разные настройки:
// Дневной график (D1):
FastMAPeriod = 20
SlowMAPeriod = 50
StopLoss = 300
TakeProfit = 600
// Четырехчасовой график (H4):
FastMAPeriod = 14
SlowMAPeriod = 50
StopLoss = 150
TakeProfit = 300
// Часовой график (H1):
FastMAPeriod = 10
SlowMAPeriod = 30
StopLoss = 100
TakeProfit = 200
```
Дополнительные улучшения стратегии:
1. Фильтр волатильности:
```mql5
// Добавить в CheckForOpen():
double atrValue = iATR(_Symbol, _Period, 14, 0);
if(atrValue > 0.005) // Пример фильтра по ATR
{
// Торговать только при достаточной волатильности
}
```
1. Фильтр по времени:
```mql5
// Не торговать во время выхода важных новостей
bool IsTradingTime()
{
MqlDateTime time;
TimeCurrent(time);
// Не торговать с 13:00 до 15:00 (пример)
if(time.hour >= 13 && time.hour < 15)
return false;
return true;
}
```
1. Управление капиталом:
```mql5
// Вместо фиксированного лота использовать процент от депозита
double riskPercent = 2.0; // Риск 2% от депозита
double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * riskPercent / 100;
double lotSize = riskAmount / (StopLoss * _Point * SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE));
```
4. Важные предупреждения:
1. Всегда тестируйте на демо-счете перед использованием на реальных деньгах
2. Адаптируйте параметры под конкретную валютную пару и таймфрейм
3. Мониторьте работу советника, особенно в первые недели торговли
4. Учитывайте спреды и свопы – они могут существенно повлиять на прибыльность
5. Используйте VPS для круглосуточной работы советника
5. Ограничения данной реализации:
1. Советник открывает только одну позицию на символ
2. Не учитывает корреляции между разными инструментами
3. Нет защиты от "зависаний" и сбоев связи
4. Требует постоянного мониторинга и периодической оптимизации параметров
Этот код представляет собой базовую реализацию стратегии следования за трендом. Для профессионального использования рекомендуется добавить дополнительные фильтры, улучшенное управление капиталом и систему мониторинга.
Робот 2: «Ловец отскоков» (Bounce Catcher)
Вот пример кода торгового робота "Bounce Catcher" для MetaTrader 5:
```mq5
//+–+
//| BounceCatcherRobot.mq5|
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+–+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+–+
//| Входные параметры эксперта |
//+–+
input double LotSize = 0.1; // Размер лота
input int BB_Period = 20; // Период Bollinger Bands
input double BB_Deviation = 2.0; // Отклонение Bollinger Bands
input int RSI_Period = 14; // Период RSI
input int RSI_OverSold = 30; // Уровень перепроданности
input int RSI_OverBought = 70; // Уровень перекупленности
input int StopLoss_Points = 200; // Стоп-лосс в пунктах
input int TakeProfit_Points = 400; // Тейк-профит в пунктах
input bool UseTrailingStop = false; // Использовать трейлинг-стоп
input int TrailingStop_Points = 100;// Уровень трейлинг-стопа
input int MagicNumber = 123456; // Магический номер
//+–+
//| Глобальные переменные |
//+–+
int handleBB, handleRSI;
double bbUpper[], bbMiddle[], bbLower[];
double rsiBuffer[];
datetime lastTradeTime = 0;
//+–+
//| Expert initialization function |
//+–+
int OnInit()
{
// Проверка входных параметров
if(LotSize <= 0 || LotSize > 100)
{
Print("Некорректный размер лота!");
return INIT_PARAMETERS_INCORRECT;
}
// Создание индикаторов
handleBB = iBands(_Symbol, _Period, BB_Period, 0, BB_Deviation, PRICE_CLOSE);
handleRSI = iRSI(_Symbol, _Period, RSI_Period, PRICE_CLOSE);
if(handleBB == INVALID_HANDLE || handleRSI == INVALID_HANDLE)
{
Print("Ошибка создания индикаторов!");
return INIT_FAILED;
}
// Установка массивов как таймсерии
ArraySetAsSeries(bbUpper, true);
ArraySetAsSeries(bbMiddle, true);
ArraySetAsSeries(bbLower, true);
ArraySetAsSeries(rsiBuffer, true);
return INIT_SUCCEEDED;
}
//+–+
//| Expert deinitialization function |
//+–+
void OnDeinit(const int reason)
{
if(handleBB != INVALID_HANDLE) IndicatorRelease(handleBB);
if(handleRSI != INVALID_HANDLE) IndicatorRelease(handleRSI);
}
//+–+
//| Expert tick function |
//+–+
void OnTick()
{
// Проверяем наличие открытых позиций по этому символу и магику
if(PositionSelect(_Symbol)) return;
// Получаем текущее время
datetime currentTime = iTime(_Symbol, _Period, 0);
if(lastTradeTime == currentTime) return; // Проверяем, чтобы не торговать несколько раз на одном баре
// Копируем данные индикаторов
if(CopyBuffer(handleBB, 0, 0, 3, bbUpper) <= 0 ||
CopyBuffer(handleBB, 1, 0, 3, bbMiddle) <= 0 ||
CopyBuffer(handleBB, 2, 0, 3, bbLower) <= 0 ||
CopyBuffer(handleRSI, 0, 0, 3, rsiBuffer) <= 0)
{
Print("Ошибка копирования данных индикаторов!");
return;
}
// Получаем текущие цены
MqlTick lastTick;
if(!SymbolInfoTick(_Symbol, lastTick)) return;
double ask = lastTick.ask;
double bid = lastTick.bid;
double close1 = iClose(_Symbol, _Period, 1); // Цена закрытия предыдущего бара
// Сигнал на покупку: цена около нижней полосы Боллинджера и RSI < 30
bool buySignal = (close1 <= bbLower[1] || bid <= bbLower[0]) &&
rsiBuffer[0] < RSI_OverSold;
// Сигнал на продажу: цена около верхней полосы Боллинджера и RSI > 70
bool sellSignal = (close1 >= bbUpper[1] || ask >= bbUpper[0]) &&
rsiBuffer[0] > RSI_OverBought;
// Проверка на боковой тренд (дополнительный фильтр)
bool isFlatMarket = MathAbs(bbUpper[0] – bbLower[0]) > 0;
// Открытие позиций
if(buySignal && isFlatMarket)
{
OpenPosition(ORDER_TYPE_BUY);
lastTradeTime = currentTime;
}
else if(sellSignal && isFlatMarket)
{
OpenPosition(ORDER_TYPE_SELL);
lastTradeTime = currentTime;
}
// Обработка трейлинг-стопа
if(UseTrailingStop && PositionSelect(_Symbol))
{
TrailingStop();
}
}
//+–+
//| Функция открытия позиции |
//+–+
void OpenPosition(ENUM_ORDER_TYPE orderType)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = orderType;
request.type_filling = ORDER_FILLING_FOK;
request.deviation = 10;
request.magic = MagicNumber;
// Установка цен
if(orderType == ORDER_TYPE_BUY)
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.sl = request.price – StopLoss_Points * _Point;
request.tp = request.price + TakeProfit_Points * _Point;
}
else // ORDER_TYPE_SELL
{
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.sl = request.price + StopLoss_Points * _Point;
request.tp = request.price – TakeProfit_Points * _Point;
}
// Отправка ордера
if(!OrderSend(request, result))
{
Print("Ошибка открытия позиции: ", GetLastError());
}
else
{
Print("Позиция успешно открыта. Тикет: ", result.order);
}
}
//+–+
//| Функция трейлинг-стопа |
//+–+
void TrailingStop()
{
ulong posTicket = PositionGetTicket(0);
if(!PositionSelectByTicket(posTicket)) return;
double currentSL = PositionGetDouble(POSITION_SL);
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double newSL = currentSL;
double trailingStep = TrailingStop_Points * _Point;
if(posType == POSITION_TYPE_BUY)
{
if(currentPrice – currentSL > trailingStep)
{
newSL = currentPrice – trailingStep;
if(newSL > currentSL)
{
ModifyPositionSL(newSL);
}
}
}
else if(posType == POSITION_TYPE_SELL)
{
if(currentSL – currentPrice > trailingStep)
{
newSL = currentPrice + trailingStep;
if(newSL < currentSL)
{
ModifyPositionSL(newSL);
}
}
}
}
//+–+
//| Функция модификации стоп-лосса |
//+–+
void ModifyPositionSL(double newSL)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_SLTP;
request.position = PositionGetTicket(0);
request.symbol = _Symbol;
request.sl = newSL;
request.magic = MagicNumber;
if(!OrderSend(request, result))
{
Print("Ошибка модификации стоп-лосса: ", GetLastError());
}
}
//+–+
```
Ключевые особенности робота:
1. Логика работы:
· Покупка при касании нижней полосы Боллинджера и RSI < 30
· Продажа при касании верхней полосы Боллинджера и RSI > 70
2. Управление рисками:
· Фиксированные Stop-Loss и Take-Profit
· Опциональный трейлинг-стоп
· Проверка размера лота
3. Защитные механизмы:
· Торговля только на новом баре
· Одна позиция на символ
· Проверка успешности выполнения ордеров
4. Настраиваемые параметры:
· Периоды индикаторов
· Уровни RSI
· Размеры стоп-лосса и тейк-профита
· Магический номер для идентификации
Рекомендации по использованию:
1. Тестируйте на истории с разными параметрами
2. Настройте размер лота под ваш депозит
3. Добавьте фильтр тренда (например, ADX) для лучшей работы во флете
4. Используйте на таймфреймах M15-H1 для меньшего шума
5. Регулярно оптимизируйте параметры под текущую рыночную волатильность
Внимание: Перед использованием на реальном счете обязательно протестируйте робота на демо-счете и оптимизируйте параметры под конкретный инструмент.
Робот 3: «Скальпер Пипсарь» (Scalper)
Скальпер Пипсарь для MetaTrader 5
```mq5
//+–+
//| ScalperPipsar.mq5|
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+–+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+–+
//| Входные параметры эксперта |
//+–+
input double LotSize = 0.1; // Размер лота
input int TakeProfit_Pips = 10; // Тейк-профит в пипсах
input int StopLoss_Pips = 5; // Стоп-лосс в пипсах
input int MaxDailyTrades = 100; // Максимум сделок в день
input double MaxSpread_Pips = 0.5; // Максимальный спред в пипсах
input bool UseEquityProtection = true;// Защита по эквити
input double EquityProtectionPercent = 5;// Макс. просадка эквити в %
input int MagicNumber = 789012; // Магический номер
input bool UseNewsFilter = true; // Фильтр новостей
input int NewsBeforeMinutes = 30; // Не торговать за N минут до новостей
input int NewsAfterMinutes = 30; // Не торговать N минут после новостей
// Входные параметры индикаторов
input int FastMA_Period = 5; // Период быстрой MA
input int SlowMA_Period = 10; // Период медленной MA
input ENUM_MA_METHOD MA_Method = MODE_EMA;// Метод MA
input int Volume_Threshold = 100; // Порог объема
input int Momentum_Period = 3; // Период момента
input double MinTickSpeed = 0.5; // Мин. скорость тиков (тиков/сек)
//+–+
//| Глобальные переменные |
//+–+
int handleFastMA, handleSlowMA, handleMomentum;
double fastMA[], slowMA[], momentum[];
datetime lastTradeTime = 0;
int todayTrades = 0;
datetime lastTradeDate = 0;
double initialEquity = 0;
MqlDateTime currentTime;
int tickCounter = 0;
datetime lastTickTime = 0;
double tickSpeed = 0;
// Структура для хранения информации о новостях
struct NewsEvent
{
datetime time;
string currency;
string event;
int impact; // 0=low, 1=medium, 2=high, 3=very high
};
//+–+
//| Expert initialization function |
//+–+
int OnInit()
{
// Проверка входных параметров
if(LotSize <= 0 || LotSize > 100)
{
Print("Некорректный размер лота!");
return INIT_PARAMETERS_INCORRECT;
}
if(TakeProfit_Pips <= 0 || StopLoss_Pips <= 0)
{
Print("Некорректные уровни TP/SL!");
return INIT_PARAMETERS_INCORRECT;
}
// Инициализация индикаторов
handleFastMA = iMA(_Symbol, PERIOD_M1, FastMA_Period, 0, MA_Method, PRICE_CLOSE);
handleSlowMA = iMA(_Symbol, PERIOD_M1, SlowMA_Period, 0, MA_Method, PRICE_CLOSE);
handleMomentum = iMomentum(_Symbol, PERIOD_M1, Momentum_Period, PRICE_CLOSE);
if(handleFastMA == INVALID_HANDLE || handleSlowMA == INVALID_HANDLE ||
handleMomentum == INVALID_HANDLE)
{
Print("Ошибка создания индикаторов!");
return INIT_FAILED;
}
// Установка массивов как таймсерии
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);
ArraySetAsSeries(momentum, true);
// Инициализация начального эквити
initialEquity = AccountInfoDouble(ACCOUNT_EQUITY);
// Сброс счетчика сделок при перезагрузке
ResetDailyTradesCounter();
// Создание таймера для мониторинга скорости тиков
EventSetTimer(1);
return INIT_SUCCEEDED;
}
//+–+
//| Expert deinitialization function |
//+–+
void OnDeinit(const int reason)
{
if(handleFastMA != INVALID_HANDLE) IndicatorRelease(handleFastMA);
if(handleSlowMA != INVALID_HANDLE) IndicatorRelease(handleSlowMA);
if(handleMomentum != INVALID_HANDLE) IndicatorRelease(handleMomentum);
EventKillTimer();
}
//+–+
//| Expert tick function |
//+–+
void OnTick()
{
// Подсчет скорости тиков
tickCounter++;
datetime currentTickTime = TimeCurrent();
if(lastTickTime == 0) lastTickTime = currentTickTime;
// Проверяем ежедневный лимит сделок
CheckDailyTradesLimit();
// Проверяем защиту по эквити
if(UseEquityProtection && !CheckEquityProtection()) return;
// Проверяем фильтр новостей
if(UseNewsFilter && IsNewsTime()) return;
// Проверяем спред
if(!CheckSpread()) return;
// Проверяем скорость тиков
if(!CheckTickSpeed()) return;
// Проверяем наличие открытых позиций
if(PositionSelect(_Symbol)) return;
// Получаем данные индикаторов
if(!UpdateIndicators()) return;
// Получаем тиковые данные
MqlTick lastTick;
if(!SymbolInfoTick(_Symbol, lastTick)) return;
// Получаем данные объемов
long volumeArray[];
ArraySetAsSeries(volumeArray, true);
if(CopyTickVolume(_Symbol, PERIOD_M1, 0, 3, volumeArray) <= 0) return;
// Генерируем сигналы
bool buySignal = GenerateBuySignal(lastTick, volumeArray);
bool sellSignal = GenerateSellSignal(lastTick, volumeArray);
// Открываем позиции
if(buySignal)
{
OpenPosition(ORDER_TYPE_BUY);
}
else if(sellSignal)
{
OpenPosition(ORDER_TYPE_SELL);
}
}
//+–+
//| Timer function для подсчета скорости тиков |
//+–+
void OnTimer()
{
datetime currentTime = TimeCurrent();
double timeDiff = currentTime – lastTickTime;
if(timeDiff > 0)
{
tickSpeed = tickCounter / timeDiff;
tickCounter = 0;
lastTickTime = currentTime;
}
}
//+–+
//| Функция генерации сигнала на покупку |
//+–+
bool GenerateBuySignal(MqlTick &tick, long &volumeArray[])
{
// Сигнал по скользящим средним
bool maSignal = fastMA[0] > slowMA[0] && fastMA[1] <= slowMA[1];
// Сигнал по моменту
bool momentumSignal = momentum[0] > 100 && momentum[1] <= 100;
// Проверка объема
bool volumeSignal = volumeArray[0] > Volume_Threshold;
// Проверка цены (микро-паттерны)
bool pricePattern = CheckBullishMicroPattern();
// Комбинированный сигнал
return (maSignal && momentumSignal && volumeSignal && pricePattern);
}
//+–+
//| Функция генерации сигнала на продажу |
//+–+
bool GenerateSellSignal(MqlTick &tick, long &volumeArray[])
{
// Сигнал по скользящим средним
bool maSignal = fastMA[0] < slowMA[0] && fastMA[1] >= slowMA[1];
// Сигнал по моменту
bool momentumSignal = momentum[0] < 100 && momentum[1] >= 100;
// Проверка объема
bool volumeSignal = volumeArray[0] > Volume_Threshold;
// Проверка цены (микро-паттерны)
bool pricePattern = CheckBearishMicroPattern();
// Комбинированный сигнал
return (maSignal && momentumSignal && volumeSignal && pricePattern);
}
//+–+
//| Проверка бычьего микро-паттерна |
//+–+
bool CheckBullishMicroPattern()
{
// Пример: проверка последовательности из 3 последних тиков
MqlRates rates[];
ArraySetAsSeries(rates, true);
if(CopyRates(_Symbol, PERIOD_M1, 0, 5, rates) < 5) return false;
// Паттерн: снижение-снижение-рост (поглощение)
bool pattern1 = rates[3].close < rates[3].open && // Медвежья свеча
rates[2].close < rates[2].open && // Медвежья свеча
rates[1].close > rates[1].open && // Бычья свеча
rates[1].close > rates[2].close; // Закрытие выше предыдущего закрытия
// Паттерн: молот или доджи после снижения
bool pattern2 = rates[2].close < rates[2].open && // Медвежья свеча
(rates[1].high – rates[1].low) > 3 * (rates[1].close – rates[1].open) && // Длинная тень
rates[1].close > rates[1].open; // Закрытие выше открытия
return pattern1 || pattern2;
}
//+–+
//| Проверка медвежьего микро-паттерна |
//+–+
bool CheckBearishMicroPattern()
{
MqlRates rates[];
ArraySetAsSeries(rates, true);
if(CopyRates(_Symbol, PERIOD_M1, 0, 5, rates) < 5) return false;
// Паттерн: рост-рост-снижение (поглощение)
bool pattern1 = rates[3].close > rates[3].open && // Бычья свеча
rates[2].close > rates[2].open && // Бычья свеча
rates[1].close < rates[1].open && // Медвежья свеча
rates[1].close < rates[2].close; // Закрытие ниже предыдущего закрытия
// Паттерн: повешенный или доджи после роста
bool pattern2 = rates[2].close > rates[2].open && // Бычья свеча
(rates[1].high – rates[1].low) > 3 * (rates[1].open – rates[1].close) && // Длинная тень
rates[1].close < rates[1].open; // Закрытие ниже открытия
return pattern1 || pattern2;
}
//+–+
//| Обновление данных индикаторов |
//+–+
bool UpdateIndicators()
{
if(CopyBuffer(handleFastMA, 0, 0, 3, fastMA) <= 0) return false;
if(CopyBuffer(handleSlowMA, 0, 0, 3, slowMA) <= 0) return false;
if(CopyBuffer(handleMomentum, 0, 0, 3, momentum) <= 0) return false;
return true;
}
//+–+
//| Проверка спреда |
//+–+
bool CheckSpread()
{
MqlTick lastTick;
if(!SymbolInfoTick(_Symbol, lastTick)) return false;
double currentSpread = (lastTick.ask – lastTick.bid) / _Point;
return currentSpread <= MaxSpread_Pips;
}
//+–+
//| Проверка скорости тиков |
//+–+
bool CheckTickSpeed()
{
return tickSpeed >= MinTickSpeed;
}
//+–+
//| Проверка времени новостей |
//+–+
bool IsNewsTime()
{
// В реальной реализации здесь должен быть доступ к календарю новостей
// Это примерная заглушка
TimeToStruct(TimeCurrent(), currentTime);
// Пример: не торговать в 8:30-9:00 и 13:30-14:00 (важные релизы)
bool newsTime1 = (currentTime.hour == 8 && currentTime.min >= 30) ||
(currentTime.hour == 9 && currentTime.min == 0);
bool newsTime2 = (currentTime.hour == 13 && currentTime.min >= 30) ||
(currentTime.hour == 14 && currentTime.min == 0);
return newsTime1 || newsTime2;
}
//+–+
//| Проверка защиты по эквити |
//+–+
bool CheckEquityProtection()
{
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
double drawdownPercent = ((initialEquity – currentEquity) / initialEquity) * 100;
return drawdownPercent < EquityProtectionPercent;
}
//+–+
//| Проверка дневного лимита сделок |
//+–+
void CheckDailyTradesLimit()
{
datetime currentDate = TimeCurrent();
MqlDateTime dateStruct;
TimeToStruct(currentDate, dateStruct);
// Если день сменился, сбрасываем счетчик
if(lastTradeDate != dateStruct.day)
{
todayTrades = 0;
lastTradeDate = dateStruct.day;
}
}
//+–+
//| Сброс счетчика дневных сделок |
//+–+
void ResetDailyTradesCounter()
{
datetime currentDate = TimeCurrent();
MqlDateTime dateStruct;
TimeToStruct(currentDate, dateStruct);
todayTrades = 0;
lastTradeDate = dateStruct.day;
}
//+–+
//| Открытие позиции |
//+–+
void OpenPosition(ENUM_ORDER_TYPE orderType)
{
// Проверяем лимит сделок
if(todayTrades >= MaxDailyTrades) return;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = orderType;
request.type_filling = ORDER_FILLING_IOC; // Немедленное исполнение или отмена
request.deviation = 1; // Минимальное отклонение
request.magic = MagicNumber;
// Установка цен
MqlTick lastTick;
SymbolInfoTick(_Symbol, lastTick);
if(orderType == ORDER_TYPE_BUY)
{
request.price = lastTick.ask;
request.sl = request.price – StopLoss_Pips * _Point;
request.tp = request.price + TakeProfit_Pips * _Point;
}
else // ORDER_TYPE_SELL
{
request.price = lastTick.bid;
request.sl = request.price + StopLoss_Pips * _Point;
request.tp = request.price – TakeProfit_Pips * _Point;
}
// Отправка ордера
if(!OrderSend(request, result))
{
Print("Ошибка открытия позиции: ", GetLastError());
}
else
{
todayTrades++;
Print("Позиция открыта. Сегодня сделок: ", todayTrades);
}
}
//+–+
//| Функция закрытия всех позиций |
//+–+
void CloseAllPositions()
{
for(int i = PositionsTotal()-1; i >= 0; i–)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
{
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.position = ticket;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.deviation = 1;
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
{
request.type = ORDER_TYPE_SELL;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
}
else
{
request.type = ORDER_TYPE_BUY;
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
}
OrderSend(request, result);
}
}
}
}
```
Дополнительные функции для реального скальпинга:
```mq5
//+–+
//| Функция мониторинга стакана цен (упрощенная) |
//+–+
void MonitorMarketDepth()
{
// В MT5 нет прямого доступа к Level II, но можно использовать
// символьные свойства для получения информации о спросе/предложении
MqlTick lastTick;
SymbolInfoTick(_Symbol, lastTick);
// Можно добавить логику анализа объема на текущих ценах
// Например, отслеживать крупные лимитные ордера
}
//+–+
//| Функция анализа кластеров объемов |
//+–+
void AnalyzeVolumeClusters()
{
// Использование индикатора Volume Profile или Cluster Charts
// для определения уровней с максимальным объемом
}
//+–+
//| Функция для работы со стаканом заявок (требует специальных API) |
//+–+
void ProcessMarketDepth()
{
// Для реального доступа к Level II потребуется:
// 1. API от брокера с доступом к стакану
// 2. Специальные библиотеки или плагины
// 3. Прямое подключение к биржевым данным
}
```
Ключевые особенности скальпера:
1. Сверхбыстрая торговля:
· Использование тиковых данных
· Мгновенное исполнение (IOC)
· Минимальные уровни TP/SL (5-15 пунктов)
2. Система защиты:
· Ограничение по количеству сделок в день
· Защита по эквити
· Фильтр по спреду
· Фильтр новостей
3. Мониторинг качества соединения:
· Контроль скорости тиков
· Проверка стабильности подключения
4. Анализ микро-паттернов:
· Свечные паттерны на M1
· Анализ объемов
· Мониторинг момента
Требования для работы скальпера:
1. Технические:
· VPS с низкой задержкой (менее 1 мс к серверу)
· Выделенный канал связи
· Стабильное электропитание
2. Торговые условия:
· ECN счет с сырыми спредами
· Минимальная комиссия
· Разрешение на скальпинг
3. Рыночные условия:
· Высокая ликвидность (мажорные пары)
· Низкая волатильность в азиатскую сессию
· Отсутствие важных новостей
Важно: Скальпинг – это высокочастотная торговля с высокими рисками. Тестируйте стратегию на демо-счете не менее 3 месяцев перед использованием на реальные деньги. Начните с минимального лота и постепенно увеличивайте объемы при стабильной прибыльности.
Робот 4: «Гармоничный паттерн» (Harmonic Pattern Scanner)
Гармоничный паттерн (Harmonic Pattern Scanner) для MetaTrader 5
```mq5
//+–+
//| HarmonicPatternScanner.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+–+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+–+
//| Входные параметры эксперта |
//+–+
input double LotSize = 0.1; // Размер лота
input int StopLoss_Points = 200; // Стоп-лосс в пунктах
input int TakeProfit_Points = 400; // Тейк-профит в пунктах
input int MagicNumber = 112233; // Магический номер
input double FiboTolerance = 0.05; // Допуск для уровней Фибо (5%)
input int MinPatternBars = 20; // Минимум баров в паттерне
input int MaxPatternBars = 300; // Максимум баров в паттерне
input bool ShowPatternLines = true; // Показывать линии паттернов
input color PatternColor = clrBlue; // Цвет линий паттернов
//+–+
//| Перечисление типов паттернов |
//+–+
enum PATTERN_TYPE
{
PATTERN_NONE = 0,
PATTERN_GARTLEY = 1,
PATTERN_BUTTERFLY = 2,
PATTERN_CRAB = 3,
PATTERN_BAT = 4,
PATTERN_SHARK = 5,
PATTERN_CYPHER = 6
};
//+–+
//| Структура для хранения точек паттерна |
//+–+
struct PatternPoints
{
double X, A, B, C, D;
datetime timeX, timeA, timeB, timeC, timeD;
PATTERN_TYPE type;
int direction; // 1 – бычий, -1 – медвежий
};
//+–+
//| Глобальные переменные |
//+–+
PatternPoints lastPattern;
bool patternFound = false;
int lastPatternBar = 0;
int zigzagHandle;
double zigzagBuffer[];
datetime timeBuffer[];
double highBuffer[], lowBuffer[];
int lastCalculated = 0;
//+–+
//| Expert initialization function |
//+–+
int OnInit()
{
// Проверка входных параметров
if(LotSize <= 0 || LotSize > 100)
{
Print("Некорректный размер лота!");
return INIT_PARAMETERS_INCORRECT;
}
// Создание индикатора ZigZag для поиска экстремумов
zigzagHandle = iCustom(_Symbol, _Period, "Examples\\ZigZag.ex5", 12, 5, 3);
if(zigzagHandle == INVALID_HANDLE)
{
Print("Ошибка создания индикатора ZigZag!");
return INIT_FAILED;
}
// Настройка массивов
ArraySetAsSeries(zigzagBuffer, true);
ArraySetAsSeries(timeBuffer, true);
ArraySetAsSeries(highBuffer, true);
ArraySetAsSeries(lowBuffer, true);
return INIT_SUCCEEDED;
}
//+–+
//| Expert deinitialization function |
//+–+
void OnDeinit(const int reason)
{
if(zigzagHandle != INVALID_HANDLE) IndicatorRelease(zigzagHandle);
DeletePatternLines();
}
//+–+
//| Expert tick function |
//+–+
void OnTick()
{
// Проверяем наличие открытых позиций по этому символу и магику
if(PositionSelect(_Symbol)) return;
// Получаем текущее время бара
datetime currentTime = iTime(_Symbol, _Period, 0);
// Ищем паттерны каждые N баров или при смене дня
static datetime lastScanTime = 0;
if(currentTime – lastScanTime < 3600) return; // Сканируем раз в час
// Обновляем данные ZigZag
if(!UpdateZigZagData()) return;
// Ищем гармонические паттерны
PatternPoints foundPattern = ScanForPatterns();
if(foundPattern.type != PATTERN_NONE)
{
patternFound = true;
lastPattern = foundPattern;
lastPatternBar = iBarShift(_Symbol, _Period, currentTime);
// Отображаем паттерн на графике
if(ShowPatternLines) DrawPattern(foundPattern);
// Открываем сделку в точке D
OpenPatternTrade(foundPattern);
lastScanTime = currentTime;
}
}
//+–+
//| Обновление данных ZigZag |
//+–+
bool UpdateZigZagData()
{
// Копируем данные ZigZag
if(CopyBuffer(zigzagHandle, 0, 0, 500, zigzagBuffer) <= 0)
{
Print("Ошибка копирования данных ZigZag!");
return false;
}
// Копируем временные метки
if(CopyTime(_Symbol, _Period, 0, 500, timeBuffer) <= 0) return false;
// Копируем High и Low
if(CopyHigh(_Symbol, _Period, 0, 500, highBuffer) <= 0) return false;
if(CopyLow(_Symbol, _Period, 0, 500, lowBuffer) <= 0) return false;
return true;
}
//+–+
//| Поиск гармонических паттернов |
//+–+
PatternPoints ScanForPatterns()
{
PatternPoints result;
result.type = PATTERN_NONE;
// Собираем экстремумы из ZigZag
double extremes[];
datetime extremeTimes[];
int extremeBars[];
CollectExtremes(extremes, extremeTimes, extremeBars);
int extremeCount = ArraySize(extremes);
if(extremeCount < 5) return result;
// Ищем паттерны среди экстремумов
for(int i = 4; i < extremeCount; i++)
{
// Проверяем XABCD паттерны
for(int x = i-4; x <= i-4; x++)
for(int a = x+1; a <= i-3; a++)
for(int b = a+1; b <= i-2; b++)
for(int c = b+1; c <= i-1; c++)
for(int d = c+1; d <= i; d++)
{
// Проверяем временные рамки паттерна
int patternBars = extremeBars[d] – extremeBars[x];
if(patternBars < MinPatternBars || patternBars > MaxPatternBars) continue;
// Проверяем бычий паттерн (X – low, A – high, B – low, C – high, D – low)
if(extremes[x] < extremes[a] && extremes[a] > extremes[b] &&
extremes[b] < extremes[c] && extremes[c] > extremes[d])
{
PatternPoints bullPattern;
bullPattern.X = extremes[x];
bullPattern.A = extremes[a];
bullPattern.B = extremes[b];
bullPattern.C = extremes[c];
bullPattern.D = extremes[d];
bullPattern.timeX = extremeTimes[x];
bullPattern.timeA = extremeTimes[a];
bullPattern.timeB = extremeTimes[b];
bullPattern.timeC = extremeTimes[c];
bullPattern.timeD = extremeTimes[d];
bullPattern.direction = 1;
// Проверяем тип паттерна
bullPattern.type = CheckPatternType(bullPattern);
if(bullPattern.type != PATTERN_NONE)
{
// Проверяем, что точка D – последняя (или почти последняя)
int barsSinceD = iBarShift(_Symbol, _Period, extremeTimes[d]);
if(barsSinceD <= 3) // Паттерн свежий
{
return bullPattern;
}
}
}
// Проверяем медвежий паттерн (X – high, A – low, B – high, C – low, D – high)
if(extremes[x] > extremes[a] && extremes[a] < extremes[b] &&
extremes[b] > extremes[c] && extremes[c] < extremes[d])
{
PatternPoints bearPattern;
bearPattern.X = extremes[x];
bearPattern.A = extremes[a];
bearPattern.B = extremes[b];
bearPattern.C = extremes[c];
bearPattern.D = extremes[d];
bearPattern.timeX = extremeTimes[x];
bearPattern.timeA = extremeTimes[a];
bearPattern.timeB = extremeTimes[b];
bearPattern.timeC = extremeTimes[c];
bearPattern.timeD = extremeTimes[d];
bearPattern.direction = -1;
// Проверяем тип паттерна
bearPattern.type = CheckPatternType(bearPattern);
if(bearPattern.type != PATTERN_NONE)
{
// Проверяем, что точка D – последняя (или почти последшая)
int barsSinceD = iBarShift(_Symbol, _Period, extremeTimes[d]);
if(barsSinceD <= 3) // Паттерн свежий
{
return bearPattern;
}
}
}
}
}
return result;
}
//+–+
//| Сбор экстремумов из ZigZag |
//+–+
void CollectExtremes(double &extremes[], datetime ×[], int &bars[])
{
ArrayResize(extremes, 0);
ArrayResize(times, 0);
ArrayResize(bars, 0);
for(int i = 100; i >= 0; i–)
{
if(zigzagBuffer[i] != 0 && zigzagBuffer[i] != EMPTY_VALUE)
{
int size = ArraySize(extremes);
ArrayResize(extremes, size + 1);
ArrayResize(times, size + 1);
ArrayResize(bars, size + 1);
extremes[size] = zigzagBuffer[i];
times[size] = timeBuffer[i];
bars[size] = i;
}
}
// Ограничиваем количество экстремумов
int count = ArraySize(extremes);
if(count > 20)
{
ArrayResize(extremes, 20);
ArrayResize(times, 20);
ArrayResize(bars, 20);
}
}
//+–+
//| Проверка типа паттерна |
//+–+
PATTERN_TYPE CheckPatternType(const PatternPoints &pattern)
{
// Вычисляем соотношения Фибоначчи
double XA = MathAbs(pattern.A – pattern.X);
double AB = MathAbs(pattern.B – pattern.A);
double BC = MathAbs(pattern.C – pattern.B);
double CD = MathAbs(pattern.D – pattern.C);
// Отношения
double AB_XA = (XA != 0) ? AB / XA : 0;
double BC_AB = (AB != 0) ? BC / AB : 0;
double CD_BC = (BC != 0) ? CD / BC : 0;
double XC_XA = (XA != 0) ? MathAbs(pattern.C – pattern.X) / XA : 0;
double XD_XA = (XA != 0) ? MathAbs(pattern.D – pattern.X) / XA : 0;
// Уровни Фибоначчи
double fib_0382 = 0.382;
double fib_0500 = 0.5;
double fib_0618 = 0.618;
double fib_0707 = 0.707;
double fib_0786 = 0.786;
double fib_0886 = 0.886;
double fib_1130 = 1.13;
double fib_1272 = 1.272;
double fib_1414 = 1.414;
double fib_1618 = 1.618;
double fib_2000 = 2.0;
double fib_2240 = 2.24;
double fib_2618 = 2.618;
// Проверяем паттерн Гартли (Gartley)
// AB = 0.618 XA, BC = 0.382-0.886 AB, CD = 1.272-1.618 BC, XD = 0.786 XA
if(MathAbs(AB_XA – fib_0618) < FiboTolerance &&
(MathAbs(BC_AB – fib_0382) < FiboTolerance ||
MathAbs(BC_AB – fib_0886) < FiboTolerance) &&
(MathAbs(CD_BC – fib_1272) < FiboTolerance ||
MathAbs(CD_BC – fib_1618) < FiboTolerance) &&
MathAbs(XD_XA – fib_0786) < FiboTolerance)
{
return PATTERN_GARTLEY;
}
// Проверяем паттерн Бабочка (Butterfly)
// AB = 0.786 XA, BC = 0.382-0.886 AB, CD = 1.618-2.24 BC, XD = 1.272-1.618 XA
if(MathAbs(AB_XA – fib_0786) < FiboTolerance &&
(MathAbs(BC_AB – fib_0382) < FiboTolerance ||
MathAbs(BC_AB – fib_0886) < FiboTolerance) &&
(MathAbs(CD_BC – fib_1618) < FiboTolerance ||
MathAbs(CD_BC – fib_2240) < FiboTolerance) &&
(MathAbs(XD_XA – fib_1272) < FiboTolerance ||
MathAbs(XD_XA – fib_1618) < FiboTolerance))
{
return PATTERN_BUTTERFLY;
}
// Проверяем паттерн Краб (Crab)
// AB = 0.382-0.618 XA, BC = 0.382-0.886 AB, CD = 2.618-3.618 BC, XD = 1.618 XA
if((MathAbs(AB_XA – fib_0382) < FiboTolerance ||
MathAbs(AB_XA – fib_0618) < FiboTolerance) &&
(MathAbs(BC_AB – fib_0382) < FiboTolerance ||
MathAbs(BC_AB – fib_0886) < FiboTolerance) &&
(MathAbs(CD_BC – fib_2618) < FiboTolerance ||
MathAbs(CD_BC – 3.618) < FiboTolerance) &&
MathAbs(XD_XA – fib_1618) < FiboTolerance)
{
return PATTERN_CRAB;
}
// Проверяем паттерн Летучая мышь (Bat)
// AB = 0.382-0.5 XA, BC = 0.382-0.886 AB, CD = 1.618-2.618 BC, XD = 0.886 XA
if((MathAbs(AB_XA – fib_0382) < FiboTolerance ||
MathAbs(AB_XA – fib_0500) < FiboTolerance) &&
(MathAbs(BC_AB – fib_0382) < FiboTolerance ||
MathAbs(BC_AB – fib_0886) < FiboTolerance) &&
(MathAbs(CD_BC – fib_1618) < FiboTolerance ||
MathAbs(CD_BC – fib_2618) < FiboTolerance) &&
MathAbs(XD_XA – fib_0886) < FiboTolerance)
{
return PATTERN_BAT;
}
// Проверяем паттерн Акула (Shark)
// 0X = 1.13-1.618 XA, AB = 1.13-1.618 0X, BC = 0.886-1.13 AB
// Специфический паттерн, требует особой логики
return PATTERN_NONE;
}
//+–+
//| Отображение паттерна на графике |
//+–+
void DrawPattern(const PatternPoints &pattern)
{
// Удаляем старые линии
DeletePatternLines();
// Создаем уникальные имена для объектов
string prefix = "HP_"+IntegerToString(MagicNumber)+"_";
// Рисуем линии паттерна
ObjectCreate(0, prefix+"X_A", OBJ_TREND, 0, pattern.timeX, pattern.X, pattern.timeA, pattern.A);
ObjectSetInteger(0, prefix+"X_A", OBJPROP_COLOR, PatternColor);
ObjectSetInteger(0, prefix+"X_A", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, prefix+"X_A", OBJPROP_RAY, false);
ObjectCreate(0, prefix+"A_B", OBJ_TREND, 0, pattern.timeA, pattern.A, pattern.timeB, pattern.B);
ObjectSetInteger(0, prefix+"A_B", OBJPROP_COLOR, PatternColor);
ObjectSetInteger(0, prefix+"A_B", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, prefix+"A_B", OBJPROP_RAY, false);
ObjectCreate(0, prefix+"B_C", OBJ_TREND, 0, pattern.timeB, pattern.B, pattern.timeC, pattern.C);
ObjectSetInteger(0, prefix+"B_C", OBJPROP_COLOR, PatternColor);
ObjectSetInteger(0, prefix+"B_C", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, prefix+"B_C", OBJPROP_RAY, false);
ObjectCreate(0, prefix+"C_D", OBJ_TREND, 0, pattern.timeC, pattern.C, pattern.timeD, pattern.D);
ObjectSetInteger(0, prefix+"C_D", OBJPROP_COLOR, PatternColor);
ObjectSetInteger(0, prefix+"C_D", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, prefix+"C_D", OBJPROP_RAY, false);
// Добавляем точки
CreatePoint(prefix+"X", pattern.timeX, pattern.X, 218);
CreatePoint(prefix+"A", pattern.timeA, pattern.A, 218);
CreatePoint(prefix+"B", pattern.timeB, pattern.B, 218);
CreatePoint(prefix+"C", pattern.timeC, pattern.C, 218);
CreatePoint(prefix+"D", pattern.timeD, pattern.D, 218);
// Добавляем метки
CreateLabel(prefix+"Label_X", "X", pattern.timeX, pattern.X);
CreateLabel(prefix+"Label_A", "A", pattern.timeA, pattern.A);
CreateLabel(prefix+"Label_B", "B", pattern.timeB, pattern.B);
CreateLabel(prefix+"Label_C", "C", pattern.timeC, pattern.C);
CreateLabel(prefix+"Label_D", "D", pattern.timeD, pattern.D);
// Добавляем название паттерна
string patternName = GetPatternName(pattern.type);
CreateLabel(prefix+"PatternName", patternName + " " + ((pattern.direction == 1) ? "Bullish" : "Bearish"),
pattern.timeD, pattern.D, 12, clrRed);
}
//+–+
//| Создание точки на графике |
//+–+
void CreatePoint(string name, datetime time, double price, int code)
{
ObjectCreate(0, name, OBJ_ARROW, 0, time, price);
ObjectSetInteger(0, name, OBJPROP_ARROWCODE, code);
ObjectSetInteger(0, name, OBJPROP_COLOR, PatternColor);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 3);
}
//+–+
//| Создание метки на графике |
//+–+
void CreateLabel(string name, string text, datetime time, double price, int fontSize = 8, color clr = clrBlack)
{
ObjectCreate(0, name, OBJ_TEXT, 0, time, price);
ObjectSetString(0, name, OBJPROP_TEXT, text);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_UPPER);
}
//+–+
//| Удаление линий паттерна |
//+–+
void DeletePatternLines()
{
string prefix = "HP_"+IntegerToString(MagicNumber)+"_";
for(int i = ObjectsTotal(0)-1; i >= 0; i–)
{
string name = ObjectName(0, i);
if(StringFind(name, prefix) == 0)
{
ObjectDelete(0, name);
}
}
}
//+–+
//| Получение названия паттерна |
//+–+
string GetPatternName(PATTERN_TYPE type)
{
switch(type)
{
case PATTERN_GARTLEY: return "Gartley";
case PATTERN_BUTTERFLY: return "Butterfly";
case PATTERN_CRAB: return "Crab";
case PATTERN_BAT: return "Bat";
case PATTERN_SHARK: return "Shark";
case PATTERN_CYPHER: return "Cypher";
default: return "Unknown";
}
}
//+–+
//| Открытие сделки по паттерну |
//+–+
void OpenPatternTrade(const PatternPoints &pattern)
{
// Получаем текущую цену
MqlTick lastTick;
if(!SymbolInfoTick(_Symbol, lastTick)) return;
// Определяем направление сделки
ENUM_ORDER_TYPE orderType;
double entryPrice;
double slPrice, tpPrice;
if(pattern.direction == 1) // Бычий паттерн – покупаем
{
orderType = ORDER_TYPE_BUY;
entryPrice = lastTick.ask;
// Стоп-лосс ниже точки D
slPrice = pattern.D – StopLoss_Points * _Point;
// Тейк-профит на уровне точки B или A (в зависимости от паттерна)
if(pattern.type == PATTERN_GARTLEY || pattern.type == PATTERN_BAT)
tpPrice = entryPrice + (pattern.B – pattern.D);
else
tpPrice = entryPrice + TakeProfit_Points * _Point;
}
else // Медвежий паттерн – продаем
{
orderType = ORDER_TYPE_SELL;
entryPrice = lastTick.bid;
// Стоп-лосс выше точки D
slPrice = pattern.D + StopLoss_Points * _Point;
// Тейк-профит на уровне точки B или A
if(pattern.type == PATTERN_GARTLEY || pattern.type == PATTERN_BAT)
tpPrice = entryPrice – (pattern.D – pattern.B);
else
tpPrice = entryPrice – TakeProfit_Points * _Point;
}
// Открываем сделку
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = orderType;
request.price = entryPrice;
request.sl = slPrice;
request.tp = tpPrice;
request.deviation = 10;
request.magic = MagicNumber;
request.comment = GetPatternName(pattern.type);
if(!OrderSend(request, result))
{
Print("Ошибка открытия позиции по паттерну: ", GetLastError());
}
else
{
Print("Позиция открыта по паттерну: ", GetPatternName(pattern.type),
" (", (pattern.direction == 1) ? "Bullish" : "Bearish", ")");
}
}
//+–+
//| Функция для ручного тестирования паттернов |
//+–+
void TestPatternRecognition()
{
// Эта функция может быть использована для тестирования
// алгоритма распознавания паттернов на исторических данных
Print("Начинаем тестирование распознавания паттернов…");
for(int i = 100; i < Bars(_Symbol, _Period) – 100; i += 10)
{
// Здесь можно добавить код для тестирования на разных участках истории
}
}
```
Дополнительные функции для расширенного распознавания:
```mq5
//+–+
//| Улучшенная функция распознавания паттернов (опционально) |
//+–+
PatternPoints AdvancedPatternScan()
{
PatternPoints result;
result.type = PATTERN_NONE;
// Используем алгоритм поиска экстремумов без ZigZag
// для более точного распознавания
// 1. Ищем swing highs и swing lows
double swingHighs[], swingLows[];
datetime swingHighTimes[], swingLowTimes[];
FindSwingPoints(swingHighs, swingHighTimes, swingLows, swingLowTimes);
// 2. Комбинируем экстремумы в правильном порядке
// 3. Проверяем больше типов паттернов
// 4. Добавляем фильтры по объему и времени
return result;
}
//+–+
//| Поиск точек разворота (swing points) |
//+–+
void FindSwingPoints(double &highs[], datetime &highTimes[],
double &lows[], datetime &lowTimes[],
int lookback = 5)
{
ArrayResize(highs, 0);
ArrayResize(highTimes, 0);
ArrayResize(lows, 0);
ArrayResize(lowTimes, 0);
for(int i = lookback; i < Bars(_Symbol, _Period) – lookback; i++)
{
// Проверяем swing high
bool isSwingHigh = true;
for(int j = 1; j <= lookback; j++)
{
if(iHigh(_Symbol, _Period, i) <= iHigh(_Symbol, _Period, i+j) ||
iHigh(_Symbol, _Period, i) <= iHigh(_Symbol, _Period, i-j))
{
isSwingHigh = false;
break;
}
}
if(isSwingHigh)
{
int size = ArraySize(highs);
ArrayResize(highs, size + 1);
ArrayResize(highTimes, size + 1);
highs[size] = iHigh(_Symbol, _Period, i);
highTimes[size] = iTime(_Symbol, _Period, i);
}
// Проверяем swing low
bool isSwingLow = true;
for(int j = 1; j <= lookback; j++)
{
if(iLow(_Symbol, _Period, i) >= iLow(_Symbol, _Period, i+j) ||
iLow(_Symbol, _Period, i) >= iLow(_Symbol, _Period, i-j))
{
isSwingLow = false;
break;
}
}
if(isSwingLow)
{
int size = ArraySize(lows);
ArrayResize(lows, size + 1);
ArrayResize(lowTimes, size + 1);
lows[size] = iLow(_Symbol, _Period, i);
lowTimes[size] = iTime(_Symbol, _Period, i);
}
}
}
//+–+
//| Фильтр паттернов по дополнительным критериям |
//+–+
bool ValidatePattern(const PatternPoints &pattern)
{
// 1. Проверяем объемы в точках разворота
// 2. Проверяем временные соотношения
// 3. Проверяем наличие дивергенций
// 4. Проверяем контекст рынка
// Пример: проверяем, что в точке D объем выше среднего
int barD = iBarShift(_Symbol, _Period, pattern.timeD);
long volumeD = iVolume(_Symbol, _Period, barD);
long avgVolume = iMA(_Symbol, _Period, 20, 0, MODE_SMA, VOLUME_TICK, barD);
if(volumeD < avgVolume * 0.8) return false;
// Проверяем временные соотношения
double timeAB = double(pattern.timeB – pattern.timeA);
double timeBC = double(pattern.timeC – pattern.timeB);
double timeCD = double(pattern.timeD – pattern.timeC);
// Время CD не должно быть меньше времени BC (для большинства паттернов)
if(timeCD < timeBC * 0.5) return false;
return true;
}
```
Ключевые особенности робота:
1. Алгоритм распознавания:
· Использует индикатор ZigZag для поиска экстремумов
· Проверяет соотношения Фибоначчи с заданным допуском
· Распознает 6 основных гармонических паттернов
2. Точность распознавания:
· Настраиваемый допуск для уровней Фибо
· Фильтры по времени и количеству баров
· Проверка чередования экстремумов
3. Визуализация:
· Отображение паттерна на графике
· Подписанные точки X, A, B, C, D
· Разные цвета для бычьих и медвежьих паттернов
4. Торговая логика:
· Вход в точке завершения паттерна (D)