Алексей Боровков
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)

Конец ознакомительного фрагмента.

Текст предоставлен ООО «Литрес».

Прочитайте эту книгу целиком, купив полную легальную версию на Литрес.

Безопасно оплатить книгу можно банковской картой Visa, MasterCard, Maestro, со счета мобильного телефона, с платежного терминала, в салоне МТС или Связной, через PayPal, WebMoney, Яндекс.Деньги, QIWI Кошелек, бонусными картами или другим удобным Вам способом.