Читать книгу 10 роботов для автоматической торговли на Форекс - - Страница 3
Робот 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 месяцев перед использованием на реальные деньги. Начните с минимального лота и постепенно увеличивайте объемы при стабильной прибыльности.