10 роботов для автоматической торговли на Форекс

Размер шрифта:   13
10 роботов для автоматической торговли на Форекс

Робот 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 &times[], 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)

Продолжить чтение