//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж // AG_AT.mq4 // Пользовательская функция Автоматической Торговли. // Используется при построении функции автоматической торговли для приложения AutoGraf 4 // реализация стратегии "Сессионная торговля" (SessionTrade_Expert) // Игорь Герасько, Днепродзержинск, scriptong@mail.ru //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж 0 жж #property library #import "AG_Lib.ex4" int AG_Message(string& Message[], string _Text);// Запись сообщений в массив Message[] #import int AzianFlatStart = 0; int AzianFlatEnd = 8; int EuropeanFlatStart = 8; int EuropeanFlatEnd = 16; int AmericanFlatStart = 16; int AmericanFlatEnd = 24; string OpenOrderSound = "ok.wav"; double Spread, StopLevel, Tick, Lots, LowV, HighV, SessionLow, SessionHigh; bool FreeMarginAlert = False, FatalError = False, FirstStart = True; datetime LastBar, NowDay, LastOpen[3]; int Start[3], Finish[3], CurSession, Delta; int MagicNumber = 38540; //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж 1 жж int AG_AT(int Parol_AT, double Order[][], string Object[], double Instrument[][][][], int Ddraw_Object[][], double& Tuning[], double& Manager[][], string& Message[]) { if (FirstStart) { // - 1 - === Функция инициализации эксперта ============================================= if (!ToArray(Message, 0, AzianFlatStart, AzianFlatEnd) || !ToArray(Message, 1, EuropeanFlatStart, EuropeanFlatEnd) || !ToArray(Message, 2, AmericanFlatStart, AmericanFlatEnd)) return(0); ArrayInitialize(LastOpen, 0); for (int i = OrdersHistoryTotal() - 1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) // поиск в истории счета if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/10) == MagicNumber) { int ID = MathMod(OrderMagicNumber(), 10); LastOpen[ID] = MathMax(LastOpen[ID], OrderOpenTime()); } for (i = OrdersTotal() - 1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS)) // поиск в окне терминала if (OrderSymbol() == Symbol() && MathFloor(OrderMagicNumber()/10) == MagicNumber) { ID = MathMod(OrderMagicNumber(), 10); LastOpen[ID] = MathMax(LastOpen[ID], OrderOpenTime()); } FirstStart = False; // - 1 - === Окончание блока ============================================================ } if (FatalError) return(0); string Comm = "AG_AT"; // Комментарий (рекомендуется "AG_AT") // - 1 - == Получение настроек AutoGraf ================================================= Lots = NormalizeDouble(Tuning[1],2); // Значение лотов Delta = NormalizeDouble(Tuning[6], 2); // значение Delta // - 1 - == Окончание блока ============================================================= // - 2 - == Сбор информации об условиях торговли ======================================== Tick = MarketInfo(Symbol(), MODE_TICKSIZE); // минимальный тик Spread = ND(MarketInfo(Symbol(), MODE_SPREAD)*Point); // текщий спрэд StopLevel = ND(MarketInfo(Symbol(), MODE_STOPLEVEL)*Point); // текущий уровень стопов // - 2 - == Окончание блока ============================================================ // - 3 - == Контроль образования нового бара для ускорения работы эксперта ============== if (LastBar == Time[0]) return(1); // - 3 - === Окончание блока ============================================================ // - 4 - == Определение времени начала текущего дня и расчет уровней ==================== NowDay = iTime(Symbol(), PERIOD_D1, 0); GetSignal(); // - 4 - === Окончание блока ============================================================ // - 5 - == Установка отложенного ордера, если определены уровни ======================== if (LowV != 0 && HighV != 0 && CurSession != -1) DoTransactions(Message); // - 5 - === Окончание блока ============================================================ return(1); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Перекомпоновка входных параметров в массив | //+-------------------------------------------------------------------------------------+ bool ToArray(string& Message[], int Num, int St, int End) { if (St < 0 || End < 0 || St > 24 || End > 24 || St >= End) { AG_Message(Message, "Значения времени Start и End должны лежать в диапазоне от 0 до 24 и Start < End."); return(False); } int i = Num-1; while (i >= 0) { if (Start[i] >= St || Finish[i] >= End || Finish[i] > St) { AG_Message(Message, "Обнаружено пересечение сессий. Советник отключен."); return(False); } i--; } Start[Num] = St; Finish[Num] = End; return(True); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ 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(string& Message[], 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) { AG_Message(Message, "Недостаточно средств для открытия позиции. Free Margin = "+ DoubleToStr(AccountFreeMargin(), 2)); 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()) // ожидание освобождения торгового потока { AG_Message(Message, "Отправлен запрос на открытие ордера "+S+" ..."); int ticket=OrderSend(Symbol(), Type, Lots, Price, 3, SL, TP, "AG_AT", MagicNumber, 0);// открытие позиции // Попытка открытия позиции завершилась неудачей if(ticket<0) { int Error = GetLastError(); if(Error == 2 || Error == 5 || Error == 6 || Error == 64 || Error == 132 || Error == 133 || Error == 149) // список фатальных ошибок { AG_Message(Message, "Фатальная ошибка при открытии позиции т. к. "+ ErrorToString(Error)+" Советник отключен!"); FatalError = True; } else AG_Message(Message, "Ошибка открытия позиции "+S+": "+Error); // нефатальная ошибка return(1); } // --------------------------------------------- // Удачное открытие позиции AG_Message(Message, "Позиция "+S+" открыта успешно!"); return(0); // ------------------------ } else { AG_Message(Message, "Время ожидания освобождения торгового потока истекло!"); return(1); } // - 3 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Замена стандартного блока "if-else" | //+-------------------------------------------------------------------------------------+ double IF(bool Condition, double IfTrue, double IfFalse) { if (Condition) return(IfTrue); // Если условие истинно, то возвращаем значение IfTrue else return(IfFalse); // Если условие ложно, то возвращаем значение IfFalse } //+-------------------------------------------------------------------------------------+ //| Расчет границ канала | //+-------------------------------------------------------------------------------------+ void GetSignal() { // - 1 - ==== Если канал не будет рассчитан, то все значения останутся нулевыми ========= LowV = 0; HighV = 0; CurSession = -1; int DayBar = 0; int k = 0; // - 1 - ============================= Окончание блока ================================== // - 2 - ==== Определение текущей торговой сесиии ======================================= for (k = 0; k < 3; k++) if (Hour() >= Start[k] && Hour() < Finish[k]) { if (k == 0) { DayBar++; int j = 2; } else j = k - 1; // - 2 - ============================= Окончание блока ================================== // - 3 - ==== Расчет уровней ============================================================ datetime BeginDay = iTime(Symbol(), PERIOD_D1, DayBar); // Время начала дня if (!(TimeDayOfWeek(BeginDay) == 5 && k == 0)) // Исключаем азиатскую сессию { // понедельника // Бар, соответствующий началу предыдущей сесии int StartBar = iBarShift(Symbol(), 0, BeginDay+Start[j]*3600); // Бар, соответствующий окончанию предыдущей сесии int FinishBar = iBarShift(Symbol(), 0, BeginDay+Finish[j]*3600)+1; // Нижняя граница LowV = Low[iLowest(Symbol(), 0, MODE_LOW, StartBar-FinishBar+1, FinishBar)]; // Верхняя граница HighV = High[iHighest(Symbol(), 0, MODE_HIGH, StartBar-FinishBar+1, FinishBar)]; // Минимум текущей сессии SessionLow = Low[iLowest(Symbol(), 0, MODE_LOW, FinishBar+1)]; // Максимум текущей сессии SessionHigh = High[iHighest(Symbol(), 0, MODE_HIGH, FinishBar+1)]; } CurSession = k;// номер текущей сессии (0-азиатская, 1-европейская, 2-американская) break; } // - 3 - ============================= Окончание блока ================================== } //+-------------------------------------------------------------------------------------+ //| Установка отложенных ордеров | //+-------------------------------------------------------------------------------------+ void DoTransactions(string& Message[]) { // - 1 - == Установка ордера Buy Stop =================================================== if (LastOpen[CurSession] < NowDay) // Устанавливался ли ордер за время текущей сессии? if (Close[1] < LowV && Open[1] < LowV) // Цена закрепилась за нижней границей канала { RefreshRates(); double Price = ND(LowV + Spread + Delta*Tick); // Цена открытия Buy Stop - нижняя // граница канала double SL = ND(SessionLow - (HighV - LowV) - Tick); // Стоп для Buy Stop double TP = ND(HighV); // профит для Buy Stop - противоположная граница канала if (OpenOrderCorrect(Message, OP_BUYSTOP, Price, SL, TP, False) == 0) LastOpen[CurSession] = TimeCurrent(); // Ордер успешно открыт, записываем время else return; } // - 1 - === Окончание блока ============================================================ // - 2 - === Установка ордера Sell Stop ================================================= if (LastOpen[CurSession] < NowDay) // Устанавливался ли ордер за время текущей сессии? if (Close[1] > HighV && Open[1] > HighV)// Цена закрепилась за верхней границей канала { RefreshRates(); Price = ND(HighV - Delta*Tick); // Цена открытия Sell Stop - верхняя граница канала SL = ND(SessionHigh + (HighV - LowV) + Spread + Tick); // Стоп для Sell Stop TP = ND(LowV + Spread); // профит для Sell Stop - противоположная граница канала if (OpenOrderCorrect(Message, OP_SELLSTOP, Price, SL, TP, False) == 0) LastOpen[CurSession] = TimeCurrent(); // Ордер успешно открыт, записываем время else return; } // - 2 - === Окончание блока ============================================================ LastBar = Time[0]; // Больше на текущем баре не работаем }