//+-------------------------------------------------------------------------------------+ //| SimpleMACross_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 = 8; extern int FastMAShift = 0; extern int FastMAMethod = 0; extern int FastMAPrice = 0; extern string A2 = "=================================="; extern string A3 = "Параметры медленной МА"; extern int SlowMAPeriod = 13; extern int SlowMAShift = 0; extern int SlowMAMethod = 0; extern int SlowMAPrice = 0; extern string A4 = "=================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 10012; bool Activate, FreeMarginAlert, FatalError, IsClose; double Tick, Spread, StopLevel, FreezeLevel, MinLot, MaxLot, LotStep; int Signal; datetime LastBar = 0; //+-------------------------------------------------------------------------------------+ //| 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) { Comment("FastМАPeriod должен быть меньше SlowМАPeriod. Советник отключен!"); Print("FastМАPeriod должен быть меньше SlowМАPeriod. Советник отключен!"); return(0); } Activate = True; //---- return(0); } //+-------------------------------------------------------------------------------------+ //| expert deinitialization function | //+-------------------------------------------------------------------------------------+ int deinit() { //---- Comment(""); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ 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, 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 - == Окончание блока ============================================================= // - 3 - == Открытие ордера с ожидание торгового потока ================================= if(WaitForTradeContext()) // ожидание освобождения торгового потока { Comment("Отправлен запрос на открытие ордера ", S, " ..."); int ticket=OrderSend(Symbol(), Type, Lots, Price, 3, SL, TP, NULL, MagicNumber, 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); // - 1 - == Окончание блока ============================================================= // - 2 - == Генерация сигнала =========================================================== if (FMA1 > SMA1 && FMA2 < SMA2) Signal = -1; // Открытие BUY if (FMA1 < SMA1 && FMA2 > SMA2) Signal = 1; // Открытие SELL // - 2 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Проверка объема на корректность и округление | //+-------------------------------------------------------------------------------------+ double LotRound(double L) { return(MathRound(MathMin(MathMax(L, MinLot), MaxLot)/LotStep)*LotStep); } //+-------------------------------------------------------------------------------------+ //| Закрывает все позиции типа Type. Если закрыть не удалось, то 1. | //| Если присутствует противоположная, то возвращает 2. В случае успеха 0. | //+-------------------------------------------------------------------------------------+ int CheckOrdersReal(int Type) { for (int i = OrdersTotal()-1; i >= 0; i--) if(OrderSelect(i, SELECT_BY_POS)) if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() < 2) // поиск "своей" сделки if(OrderType() == Type) // Если позиция типа Type { if (WaitForTradeContext()) { if(Type == OP_BUY) double Pr = ND(MarketInfo(Symbol(), MODE_BID)); else Pr = ND(MarketInfo(Symbol(), MODE_ASK)); if (!OrderClose(OrderTicket(), OrderLots(), Pr, 3))// то пытаемся закрыть ее return(1); // не удалось закрыть - вернем 1 } else return(1);//вернем 1, если не удалось дождаться освобождения торгового потока } else return(2); // вернем 2, если открыта позиция, противоположная указанной return(0); // если все ОК, то вернем 0 } //+-------------------------------------------------------------------------------------+ //| Функция 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 == 1) // Открытие BUY { int Res = CheckOrdersReal(OP_SELL); if (Res == 0) { RefreshRates(); if (OpenOrderCorrect(OP_BUY, ND(Ask), 0, 0) != 0) // открытие позиции return(0); // если не удалось открыть, то попытка переносится на следующий тик } if (Res == 1) return(0); } if (Signal == -1) // Открытие SELL { Res = CheckOrdersReal(OP_BUY); if (Res == 0) { RefreshRates(); if (OpenOrderCorrect(OP_SELL, ND(Bid), 0, 0) != 0) // открытие позиции return(0); // если не удалось открыть, то попытка переносится на следующий тик } if (Res == 1) return(0); } // - 5 - == Окончание блока ============================================================ LastBar = Time[0]; return(0); }