//+-------------------------------------------------------------------------------------+ //| SimpleMACrossDouble_Expert.mq4 | //| Scriptong | //| scriptong@mail.ru | //+-------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots = 0.1; extern string A1 = "Параметры быстрой МА для прямой системы"; extern int FastMAPeriod = 110; extern int FastMAShift = 0; extern int FastMAMethod = 0; extern int FastMAPrice = 0; extern string A2 = "=================================="; extern string A3 = "Параметры медленной МА для прямой системы"; extern int SlowMAPeriod = 124; extern int SlowMAShift = 0; extern int SlowMAMethod = 0; extern int SlowMAPrice = 0; extern string A4 = "=================================="; extern string A5 = "Параметры быстрой МА для реверсной системы"; extern int FastMAPeriod_Rev = 265; extern int FastMAShift_Rev = 0; extern int FastMAMethod_Rev = 0; extern int FastMAPrice_Rev = 0; extern string A6 = "=================================="; extern string A7 = "Параметры медленной МА для реверсной системы"; extern int SlowMAPeriod_Rev = 284; extern int SlowMAShift_Rev = 0; extern int SlowMAMethod_Rev = 0; extern int SlowMAPrice_Rev = 0; extern string A8 = "=================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 10014; // Сам магик умножаем на 10, в младшем разряде - // идентификатор системы. Для прямой системы ID - 0, для обратной - 1. bool Activate, FreeMarginAlert, FatalError, IsClose; double Tick, Spread, StopLevel, FreezeLevel, MinLot, MaxLot, LotStep; int Signal; datetime LastBar = 0; int BuyTicket[2], // Тикеты BUY по прямой (элемент 0) и обратной (элемент 1) системам SellTicket[2]; // Тикеты SELL по прямой (элемент 0) и обратной (элемент 1) системам //+-------------------------------------------------------------------------------------+ //| expert initialization function | //+-------------------------------------------------------------------------------------+ int init() { FatalError = False; Activate = False; IsClose = False; // - 1 - == Сбор информации об условиях торговли ======================================== Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текущий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов FreezeLevel = ND(MarketInfo(Symbol(), MODE_FREEZELEVEL)*Point); // уровень заморозки MinLot = MarketInfo(Symbol(), MODE_MINLOT); // минимальный разрешенный объем сделки MaxLot = MarketInfo(Symbol(), MODE_MAXLOT); // максимальный разрешенный объем сделки LotStep = MarketInfo(Symbol(), MODE_LOTSTEP); // шаг приращения объема сделки // - 1 - == Окончание блока ============================================================= // - 2 - == Приведение объема сделки к допустимому и проверка корректности объема ======= Lots = LotRound(Lots); // округление объема до ближайшего допустимого // - 2 - == Окончание блока ============================================================= if ((FastMAPeriod == SlowMAPeriod && FastMAShift == SlowMAShift && FastMAMethod == SlowMAMethod && FastMAPrice == SlowMAPrice) || SlowMAPeriod < FastMAPeriod) return(0); Activate = True; //---- return(0); } //+-------------------------------------------------------------------------------------+ //| expert deinitialization function | //+-------------------------------------------------------------------------------------+ int deinit() { //---- Comment(""); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного пункта | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double NP(double A) { return(MathRound(A/Tick)*Tick); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ string ErrorToString(int Error) { switch(Error) { case 2: return("зафиксирована общая ошибка, обратитесь в техподдержку."); case 5: return("у вас старая версия терминала, обновите ее."); case 6: return("нет связи с сервером, попробуйте перезагрузить терминал."); case 64: return("счет заблокирован, обратитесь в техподдержку."); case 132: return("рынок закрыт."); case 133: return("торговля запрещена."); case 149: return("запрещено локирование."); } } //+-------------------------------------------------------------------------------------+ //| Ожидание торгового потока. Если поток свободен, то результат True, иначе - False | //+-------------------------------------------------------------------------------------+ bool WaitForTradeContext() { int P = 0; // цикл "пока" while(IsTradeContextBusy() && P < 5) { P++; Sleep(1000); } // ------------- if(P == 5) return(False); return(True); } //+-------------------------------------------------------------------------------------+ //| "Правильное" открытие позиции | //| В отличие от OpenOrder проверяет соотношение текущих уровней и устанавливаемых | //| Возвращает: | //| 0 - нет ошибок | //| 1 - Ошибка открытия | //| 2 - Ошибка значения Price | //| 3 - Ошибка значения SL | //| 4 - Ошибка значения TP | //| 5 - Ошибка значения Lot | //+-------------------------------------------------------------------------------------+ int OpenOrderCorrect(int Type, double Price, double SL, double TP, int Num, bool Redefinition = True) // Redefinition - при True доопределять параметры до минимально допустимых // при False - возвращать ошибку { // - 1 - == Проверка достаточности свободных средств ==================================== if(AccountFreeMarginCheck(Symbol(), OP_BUY, Lots) <= 0 || GetLastError() == 134) { if(!FreeMarginAlert) { Print("Недостаточно средств для открытия позиции. Free Margin = ", AccountFreeMargin()); FreeMarginAlert = True; } return(5); } FreeMarginAlert = False; // - 1 - == Окончание блока ============================================================= // - 2 - == Корректировка значений Price, SL и TP или возврат ошибки ==================== RefreshRates(); switch (Type) { case OP_BUY: string S = "BUY"; if (MathAbs(Price-Ask)/Point > 3) if (Redefinition) Price = ND(Ask); else return(2); if (ND(TP-Bid) < StopLevel && TP != 0) if (Redefinition) TP = ND(Bid+StopLevel); else return(4); if (ND(Bid-SL) < StopLevel) if (Redefinition) SL = ND(Bid-StopLevel); else return(3); break; case OP_SELL: S = "SELL"; if (MathAbs(Price-Bid)/Point > 3) if (Redefinition) Price = ND(Bid); else return(2); if (ND(Ask-TP) < StopLevel) if (Redefinition) TP = ND(Ask-StopLevel); else return(4); if (ND(SL-Ask) < StopLevel && SL != 0) if (Redefinition) SL = ND(Ask+StopLevel); else return(3); break; case OP_BUYSTOP: S = "BUYSTOP"; if (ND(Price-Ask) < StopLevel) if (Redefinition) Price = ND(Ask+StopLevel); else return(2); if (ND(TP-Price) < StopLevel && TP != 0) if (Redefinition) TP = ND(Price+StopLevel); else return(4); if (ND(Price-SL) < StopLevel) if (Redefinition) SL = ND(Price-StopLevel); else return(3); break; case OP_SELLSTOP: S = "SELLSTOP"; if (ND(Bid-Price) < StopLevel) if (Redefinition) Price = ND(Bid-StopLevel); else return(2); if (ND(Price-TP) < StopLevel) if (Redefinition) TP = ND(Price-StopLevel); else return(4); if (ND(SL-Price) < StopLevel && SL != 0) if (Redefinition) SL = ND(Price+StopLevel); else return(3); break; case OP_BUYLIMIT: S = "BUYLIMIT"; if (ND(Ask-Price) < StopLevel) if (Redefinition) Price = ND(Ask-StopLevel); else return(2); if (ND(TP-Price) < StopLevel && TP != 0) if (Redefinition) TP = ND(Price+StopLevel); else return(4); if (ND(Price-SL) < StopLevel) if (Redefinition) SL = ND(Price-StopLevel); else return(3); break; case OP_SELLLIMIT: S = "SELLLIMIT"; if (ND(Price - Bid) < StopLevel) if (Redefinition) Price = ND(Bid+StopLevel); else return(2); if (ND(Price-TP) < StopLevel) if (Redefinition) TP = ND(Price-StopLevel); else return(4); if (ND(SL-Price) < StopLevel && SL != 0) if (Redefinition) SL = ND(Price+StopLevel); else return(3); break; } // - 2 - == Окончание блока ============================================================= int MN = MagicNumber*10 + Num; // - 3 - == Открытие ордера с ожидание торгового потока ================================= if(WaitForTradeContext()) // ожидание освобождения торгового потока { Comment("Отправлен запрос на открытие ордера ", S, " ..."); int ticket=OrderSend(Symbol(), Type, Lots, Price, 3, SL, TP, NULL, MN, 0);// открытие позиции // Попытка открытия позиции завершилась неудачей if(ticket<0) { int Error = GetLastError(); if(Error == 2 || Error == 5 || Error == 6 || Error == 64 || Error == 132 || Error == 133 || Error == 149) // список фатальных ошибок { Comment("Фатальная ошибка при открытии позиции т. к. "+ ErrorToString(Error)+" Советник отключен!"); FatalError = True; } else Comment("Ошибка открытия позиции ", S, ": ", Error); // нефатальная ошибка return(1); } // --------------------------------------------- // Удачное открытие позиции Comment("Позиция ", S, " открыта успешно!"); PlaySound(OpenOrderSound); return(0); // ------------------------ } else { Comment("Время ожидания освобождения торгового потока истекло!"); return(1); } // - 3 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Расчет значений средней с формированием сигналов для открытия позиций | //+-------------------------------------------------------------------------------------+ void GetSignal() { Signal = 0; // - 1 - == Получение значений индикаторов ============================================== double FMA1 = iMA(Symbol(), 0, FastMAPeriod, FastMAShift, FastMAMethod, FastMAPrice, 1); double FMA2 = iMA(Symbol(), 0, FastMAPeriod, FastMAShift, FastMAMethod, FastMAPrice, 2); double SMA1 = iMA(Symbol(), 0, SlowMAPeriod, SlowMAShift, SlowMAMethod, SlowMAPrice, 1); double SMA2 = iMA(Symbol(), 0, SlowMAPeriod, SlowMAShift, SlowMAMethod, SlowMAPrice, 2); double FMAR1 = iMA(Symbol(), 0, FastMAPeriod_Rev, FastMAShift_Rev, FastMAMethod_Rev, FastMAPrice_Rev, 1); double FMAR2 = iMA(Symbol(), 0, FastMAPeriod_Rev, FastMAShift_Rev, FastMAMethod_Rev, FastMAPrice_Rev, 2); double SMAR1 = iMA(Symbol(), 0, SlowMAPeriod_Rev, SlowMAShift_Rev, SlowMAMethod_Rev, SlowMAPrice_Rev, 1); double SMAR2 = iMA(Symbol(), 0, SlowMAPeriod_Rev, SlowMAShift_Rev, SlowMAMethod_Rev, SlowMAPrice_Rev, 2); // - 1 - == Окончание блока ============================================================= // - 2 - == Генерация сигнала для прямой системы ======================================== if (FMA1 > SMA1 && FMA2 < SMA2) Signal = 1; // Открытие BUY if (FMA1 < SMA1 && FMA2 > SMA2) Signal = -1; // Открытие SELL // - 2 - == Окончание блока ============================================================= // - 3 - == Генерация сигнала для обратной системы ====================================== if (FMAR1 > SMAR1 && FMAR2 < SMAR2) Signal = Signal - 2; // Открытие BUY if (FMAR1 < SMAR1 && FMAR2 > SMAR2) Signal = Signal + 2; // Открытие SELL // - 3 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Проверка объема на корректность и округление | //+-------------------------------------------------------------------------------------+ double LotRound(double L) { return(MathRound(MathMin(MathMax(L, MinLot), MaxLot)/LotStep)*LotStep); } //+-------------------------------------------------------------------------------------+ //| Закрывает выбранную позицию. Если закрыть не удалось, то False, иначе True. | //+-------------------------------------------------------------------------------------+ bool ClosePos(int Ticket) { if (OrderSelect(Ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) if (WaitForTradeContext()) { if (OrderType() == OP_BUY) double Pr = ND(MarketInfo(Symbol(), MODE_BID)); else Pr = ND(MarketInfo(Symbol(), MODE_ASK)); if (OrderClose(OrderTicket(), OrderLots(), Pr, 3)) return(True); } return(False); } //+-------------------------------------------------------------------------------------+ //| Поиск позиций с заполнением массивов тикетов BuyTicket и SellTicket | //+-------------------------------------------------------------------------------------+ void OrdersFind() { ArrayInitialize(BuyTicket, -1); ArrayInitialize(SellTicket, -1); for (int i = OrdersTotal()-1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS)) if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/10) == MagicNumber && OrderType() < 2) { int ID = MathMod(OrderMagicNumber(), 10); if (OrderType() == OP_BUY) BuyTicket[ID] = OrderTicket(); else SellTicket[ID] = OrderTicket(); } } //+-------------------------------------------------------------------------------------+ //| Поиск закрытия позиции нужного типа на текущей свече. Если найдено закрытие, то True| //| В противном случае результат False | //+-------------------------------------------------------------------------------------+ bool IsCloseOnThisCandle(int Type, int ID) { // - 1 - ============== Блок проверки для режима тестирования =========================== if (IsTesting()) { if (OrderSelect(OrdersHistoryTotal()-1, SELECT_BY_POS, MODE_HISTORY)) if (OrderCloseTime() >= Time[0]) if (OrderType() == Type) if (MathMod(OrderMagicNumber(), 10) == ID) return(True); } // - 1 - =========================== Окончание блока ==================================== else // - 2 - ==================== Блок проверки для режима онлайн =========================== { for (int i = 0; i < OrdersHistoryTotal(); i++) if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) if (OrderSymbol() == Symbol()) if (OrderCloseTime() >= Time[0]) if (OrderType() == Type && MathFloor(OrderMagicNumber()/10) == MagicNumber) if (MathMod(OrderMagicNumber(), 10) == ID) return(True); } // - 2 - =========================== Окончание блока ==================================== return(False); } //+-------------------------------------------------------------------------------------+ //| Открытие и закрытие позиций | //+-------------------------------------------------------------------------------------+ bool Trades() { // - 1 - ============================ Инициализация "рабочих" переменных ================ int i = MathAbs(Signal); // Количество итераций цикла 0, 1 или 2 while (i > 0) { int ID = MathFloor(i/2); // Идентификатор системы 0 - прямая, 1 - обратная int Rev = MathAbs(ID-1); // Идентификатор противоположной системы // - 1 - ===================================== Окончание блока ========================== // - 2 - ==================== Действия при сигнале открытия длинных позиций ============= if (Signal > 0) if (SellTicket[ID] > 0) // найден SELL текущей системы { // нужно закрыть его и открыть BUY if (!ClosePos(SellTicket[ID])) // Попытка закрытия SELL return(False); if (SellTicket[Rev] > 0) // найден SELL противоположной системы { // закрываем его, но новый BUY не открываем if (!ClosePos(SellTicket[Rev])) return(False); } else // не найден SELL противоположной системы, открываем BUY if (OpenOrderCorrect(OP_BUY, NP(Ask), 0, 0, ID) != 0) return(False); } else if (BuyTicket[ID] < 0) // не найден BUY текущей системы, т. е. вообще нет позиций // текущей системы. Проверяем существование SELL противоположной системы if (SellTicket[Rev] > 0) // Если найден SELL, то закрываем его, но не { // открываем BUY if (!ClosePos(SellTicket[Rev])) return(False); } else // Если не было закрытия SELL на текущей свече или существует BUY // противоположной системы, то открываем новый BUY if (BuyTicket[Rev] > 0 || !IsCloseOnThisCandle(OP_SELL, Rev)) if (OpenOrderCorrect(OP_BUY, NP(Ask), 0, 0, ID) != 0) return(False); // - 2 - ===================================== Окончание блока ========================== // - 3 - ==================== Действия при сигнале открытия коротких позиций ============ if (Signal < 0) if (BuyTicket[ID] > 0) // найден BUY текущей системы { // нужно закрыть его и открыть SELL if (!ClosePos(BuyTicket[ID])) // Попытка закрытия BUY текущей системы return(False); if (BuyTicket[Rev] > 0) // найден BUY противоположной системы { // закрываем его, но новый SELL не открываем if (!ClosePos(BuyTicket[Rev]))// Попытка закрытия BUY противоположной системы return(False); } else // Нет позиции BUY противоположной системы, можно открывать SELL if (OpenOrderCorrect(OP_SELL, NP(Bid), 0, 0, ID) != 0) return(False); } else // Нет позиции BUY текущей системы if (SellTicket[ID] < 0) // не найден SELL текущей системы, т. е. вообще нет // текущей системы. Проверяем существование SELL противоположной системы if (BuyTicket[Rev] > 0) // Если найден BUY противоположной системы, { // то закрываем его, но SELL не открываем if (!ClosePos(BuyTicket[Rev])) return(False); } else // Если не было закрытия BUY на текущей свече или существует SELL // противоположной системы, то открываем новый SELL if (SellTicket[Rev] > 0 || !IsCloseOnThisCandle(OP_BUY, Rev)) if (OpenOrderCorrect(OP_SELL, NP(Bid), 0, 0, ID) != 0) return(False); // - 3 - ===================================== Окончание блока ========================== i = i - 2; // Учитываем, что сигнал мог быть по обратной системе с весом 2 } return(True); } //+-------------------------------------------------------------------------------------+ //| Функция START эксперта | //+-------------------------------------------------------------------------------------+ int start() { // - 1 - == Разрешено ли советнику работать? =========================================== if (!Activate || FatalError) // Отключается работа советника, если функция return(0); // init завершилась с ошибкой или имела место фатальная ошибка // - 1 - == Окончание блока ============================================================ // - 2 - == Сбор информации об условиях торговли ======================================== Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов FreezeLevel = ND(MarketInfo(Symbol(), MODE_FREEZELEVEL)*Point); // уровень заморозки // - 2 - == Окончание блока ============================================================ // - 3 - ======== Обработка существующей позиции и контроль открытия нового бара ======== if (LastBar == Time[0]) return(0); // - 3 - == Окончание блока ============================================================ // - 4 - ======================== Расчет сигнала ======================================== GetSignal(); // - 4 - == Окончание блока ============================================================ // - 5 - == Открытие позиций ============================================================ if (Signal != 0) { OrdersFind(); // Подсчет своих позиций if (!Trades()) // Открытие/закрытие сделок return(0); } // - 5 - == Окончание блока ============================================================ LastBar = Time[0]; return(0); }