//+-------------------------------------------------------------------------------------+ //| PrevDayEffect.mq4 | //| Scriptong | //| | //+-------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots = 0.1; // Объем открываемой позиции extern int TakeProfit = 20; extern int OffsetForStop = 15; extern string OpenOrderSound = "ok.wav"; // Звук для открытия позиции extern int MagicNumber = 17589 ; // Магик позиций советника bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, MinLot, MaxLot, LotStep, TP, SL; datetime LastDay, LastBar; int Signal, TypeOrder, LastType, TicketOrder; //+-------------------------------------------------------------------------------------+ //| Функция инициализации эксперта | //+-------------------------------------------------------------------------------------+ int init() { //---- Activate = False; // - 1 - == Сбор информации об условиях торговли ======================================== Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов MinLot = MarketInfo(Symbol(), MODE_MINLOT); // минимальный разрешенный объем сделки MaxLot = MarketInfo(Symbol(), MODE_MAXLOT); // максимальный разрешенный объем сделки LotStep = MarketInfo(Symbol(), MODE_LOTSTEP); // шаг приращения объема сделки // - 1 - == Окончание блока ============================================================= // - 2 - == Приведение объема сделки к допустимому и проверка корректности объема ======= Lots = MathRound(Lots/LotStep)*LotStep; // округление объема до ближайшего допустимого if(Lots < MinLot || Lots > MaxLot) // объем сделки не меньше MinLot и не больше MaxLot { Comment("Параметром Lots был задан неправильный объем сделки! Советник отключен!"); return(0); } // - 2 - == Окончание блока ============================================================= // - 3 - == Проверка корректности входных параметров ==================================== if (TakeProfit <= StopLevel/Point) { Comment("Слишком малое значение параметра TakeProfit. Советник отключен!"); return(0); } // - 3 - == Окончание блока ============================================================= // - 4 - == Обновление данных с дневного и минутного таймфреймов ======================= Comment("Подождите, идет оновление данных дневного таймфрейма..."); int P = 0; while (P < 120) { iTime(Symbol(), PERIOD_D1, 0); if (GetLastError() != 4066) break; Sleep(1000); P++; } if (P == 120) { Comment("Обновление данных завершилось с ошибкой. Советник отключен!"); return(0); } Comment("Подождите, идет оновление данных минутного таймфрейма..."); P = 0; while (P < 120) { iTime(Symbol(), PERIOD_M1, 0); if (GetLastError() != 4066) break; Sleep(1000); P++; } if (P == 120) { Comment("Обновление данных завершилось с ошибкой. Советник отключен!"); return(0); } Comment(""); LastDay = 0; LastBar = 0; // - 4 - == Окончание блока ============================================================= // - 5 - == Работали уже в этот день или нет? =========================================== for (int i = OrdersTotal()-1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS)) if (OrderSymbol() == Symbol()) if (MathFloor(OrderMagicNumber()/10) == MagicNumber && MathMod(OrderMagicNumber(), 10) == 0) { LastDay = iTime(Symbol(), PERIOD_D1, 0); break; } if (LastDay == 0) for (i = OrdersHistoryTotal()-1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) if (OrderSymbol() == Symbol()) if (MathFloor(OrderMagicNumber()/10) == MagicNumber && MathMod(OrderMagicNumber(), 10) == 0 && OrderOpenTime() >= iTime(Symbol(), PERIOD_D1, 0)) { LastDay = iTime(Symbol(), PERIOD_D1, 0); break; } // - 5 - == Окончание блока ============================================================= Activate = True; // Все проверки успешно завершены, возводим флаг активизации эксперта //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Функция деинициализации эксперта | //+-------------------------------------------------------------------------------------+ 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 OpenOrder(int Type, double Price, double SL, double TP, int Num) { // Блок проверки достаточности свободных средств if(AccountFreeMarginCheck(Symbol(), OP_BUY, Lots) <= 0 || GetLastError() == 134) { if(!FreeMarginAlert) { Print("Недостаточно средств для открытия позиции. Free Margin = ", AccountFreeMargin()); FreeMarginAlert = True; } return(False); } FreeMarginAlert = False; // --------------------------------------------- switch (Type) { case OP_BUY: string S = "BUY"; break; case OP_SELL: S = "SELL"; break; case OP_BUYSTOP: S = "BUYSTOP"; break; case OP_SELLSTOP: S = "SELLSTOP"; break; case OP_BUYLIMIT: S = "BUYLIMIT"; break; case OP_SELLLIMIT: S = "SELLLIMIT"; break; } if(WaitForTradeContext()) // ожидание освобождения торгового потока { Comment("Отправлен запрос на открытие ордера ", S, " ..."); int ticket=OrderSend(Symbol(), Type, Lots, Price, 0, SL, TP, NULL, MagicNumber*10+Num, 0, CLR_NONE); // открытие позиции // Попытка открытия позиции завершилась неудачей 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(False); } // --------------------------------------------- // Удачное открытие позиции Comment("Позиция ", S, " открыта успешно!"); PlaySound(OpenOrderSound); return(True); // ------------------------ } else { Comment("Время ожидания освобождения торгового потока истекло!"); return(False); } } //+-------------------------------------------------------------------------------------+ //| Ожидание торгового потока. Если поток свободен, то результат True, иначе - False | //+-------------------------------------------------------------------------------------+ bool WaitForTradeContext() { int P = 0; // цикл "пока" while(IsTradeContextBusy() && P < 5) { P++; Sleep(1000); } // ------------- if(P == 5) return(False); return(True); } //+-------------------------------------------------------------------------------------+ //| Расчет сигнала по предыдущему дню | //+-------------------------------------------------------------------------------------+ void GetSignal() { Signal = 0; // обнуление сигнала // - 1 - == Нахождение последнего пробития предыдущего дня ============================== double HighD = iHigh(Symbol(), PERIOD_D1, 1); double LowD = iLow(Symbol(), PERIOD_D1, 1); for (int i = 1; i <= iBarShift(Symbol(), PERIOD_M1, iTime(Symbol(), PERIOD_D1, 0)); i++) if (ND(iHigh(Symbol(), PERIOD_M1, i)) > HighD+Tick || ND(iLow(Symbol(), PERIOD_M1, i)) < LowD-Tick) break; // - 1 - == Окончание блока ============================================================= // - 2 - == Сигнал открытия BUY ========================================================= if (ND(iHigh(Symbol(), PERIOD_M1, i)) > HighD+Tick) // сигнал пробития дня вверх if (Close[1] < Low[2]) // Произошел откат с закрытием свечи ниже минимума предыдущей { SL = MathMin(iLow(Symbol(), PERIOD_D1, 0), iLow(Symbol(), PERIOD_D1, 1)) - OffsetForStop*Tick; Signal = 1; return; } // - 2 - == Окончание блока ============================================================= // - 3 - == Сигнал открытия SELL ======================================================== if (ND(iLow(Symbol(), PERIOD_M1, i)) < LowD-Tick) // сигнал пробития дня вниз if (Close[1] > High[2]) // Произошел откат с закрытием свечи выше максимума предыдущей { SL = MathMax(iHigh(Symbol(), PERIOD_D1, 0), iHigh(Symbol(), PERIOD_D1, 1)) + Spread + OffsetForStop*Tick; Signal = 2; return; } // - 3 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Закрывает все позиции типа 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() && MathFloor(OrderMagicNumber()/10) == 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 } //+-------------------------------------------------------------------------------------+ //| Добавление или удаление разворотного ордера | //+-------------------------------------------------------------------------------------+ void AddOrDeleteReverse() { int BaseTicket = -1, ReverseTicket = -1; double BaseSL = 0, BaseOpen = 0, ReverseOpen = 0, ReverseSL = 0; int BaseType = -1, ReverseType = -1; datetime BaseOOT = 0; // - 1 - == Поиск основного и разворотного ордеров ====================================== for (int i = OrdersTotal()-1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS)) if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/10) == MagicNumber) // поиск "своей" сделки if (MathMod(OrderMagicNumber(), 10) == 0) { BaseTicket = OrderTicket(); BaseSL = OrderStopLoss(); BaseOpen = OrderOpenPrice(); BaseType = OrderType(); BaseOOT = OrderOpenTime(); } else { ReverseTicket = OrderTicket(); ReverseSL = OrderStopLoss(); ReverseType = OrderType(); ReverseOpen = OrderOpenPrice(); } // - 1 - == Окончание блока ============================================================= // - 2 - == Закрытие основной позиции в начале следующих суток ========================== if (BaseTicket > 0 && BaseOOT < iTime(Symbol(), PERIOD_D1, 0)) { if (BaseType == OP_BUY) double price = ND(Bid); else price = ND(Ask); if (WaitForTradeContext()) OrderClose(BaseTicket, Lots, price, 3); return; } // - 2 - == Окончание блока ============================================================= // - 3 - == Добавление разворотного ордера ============================================== if (BaseTicket > 0 && ReverseTicket < 0) { if (BaseType == OP_BUY) { ReverseType = OP_SELLSTOP; double sl = BaseOpen;//ND(iHigh(Symbol(), PERIOD_D1, 0)+Spread+Tick); double tp = ND(BaseSL - (BaseOpen - BaseSL)); } else { ReverseType = OP_BUYSTOP; sl = BaseOpen;//ND(iLow(Symbol(), PERIOD_D1, 0)-Tick); tp = ND(BaseSL + (BaseSL - BaseOpen)); } OpenOrder(ReverseType, BaseSL, sl, tp, 1); } // - 3 - == Окончание блока ============================================================= // - 4 - == Удаление разворотного ордера ============================================== if (ReverseTicket > 0 && ReverseType > 1 && (BaseTicket < 0 || (BaseTicket > 0 && ND(ReverseOpen) != ND(BaseSL)))) if (WaitForTradeContext()) OrderDelete(ReverseTicket); // - 4 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Функция 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); // текущий уровень стопов // - 2 - == Окончание блока ============================================================ // - 3 - == Удаление или добавление отложенного ордера ================================== AddOrDeleteReverse(); // - 3 - == Окончание блока ============================================================ // - 4 - == Расчет текущего сигнала ===================================================== if (LastDay == iTime(Symbol(), PERIOD_D1, 0)) return(0); if (LastBar != Time[0]) { GetSignal(); LastBar = Time[0]; } // - 4 - == Окончание блока ============================================================ // - 5 - == Открытие длинной позиции =================================================== if (Signal == 1) { int Res = CheckOrdersReal(OP_SELL); // Противоположную позицию - закрыть if (Res == 0) // если нет открытых позиций { RefreshRates(); TP = Ask + TakeProfit*Tick; if (ND(Bid-SL) > StopLevel) if (!OpenOrder(OP_BUY, ND(Ask), ND(SL), ND(TP), 0)) // если не удалось открыть return(0); // то попробуем со следующим тиком else LastDay = iTime(Symbol(), PERIOD_D1, 0); // новый бар "посчитали" } if(Res == 1) return(0); //закрыть противоположную не вышло, ждем до следующего тика } // - 5 - == Окончание блока ============================================================ // - 6 - == Открытие короткой позиции =================================================== if (Signal == 2) { Res = CheckOrdersReal(OP_BUY); // Противоположную позицию - закрыть if (Res == 0) // если нет открытых позиций { RefreshRates(); TP = Bid - TakeProfit*Tick; if (ND(SL-Ask) > StopLevel) if (!OpenOrder(OP_SELL, ND(Bid), ND(SL), ND(TP), 0))// если не удалось открыть return(0); // то попробуем со следующим тиком else LastDay = iTime(Symbol(), PERIOD_D1, 0); // новый бар "посчитали" } if (Res == 1) return(0);//закрыть противоположную не вышло, ждем до следующего тика } // - 6 - == Окончание блока ============================================================ //---- return(0); } //+------------------------------------------------------------------+