#property copyright "Scritong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots=0.1; extern string A1 = "Периоды быстрой, медленной и сигнальной линий MACD"; extern int FastMACD = 12; extern int SlowMACD = 26; extern int SignalMACD = 9; extern string A2 = "==============================================="; extern string A3 = "Период, метод и цена применения средней скользящей"; extern int MAPeriod = 13; extern int MAMethod = MODE_EMA; extern int MAPrice = PRICE_CLOSE; extern string A4 = "==============================================="; extern string A5 = "\"Большой\" таймфрейм для определения тренда"; extern int LargeTF = 1440; extern string A6 = "==============================================="; extern string A7 = "Период, метод и цена применения средней скользящей большего ТФ"; extern int MALPeriod = 26; extern int MALMethod = MODE_EMA; extern int MALPrice = PRICE_CLOSE; extern string A8 = "==============================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 10014; int Signal; bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, MinLot, MaxLot, LotStep, FreezeLevel; datetime LastBar; //+-------------------------------------------------------------------------------------+ //| Функция инициализации эксперта | //+-------------------------------------------------------------------------------------+ int init() { FatalError = 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 - == Окончание блока ============================================================= // - 3 - ================= Проверка корректности входных параметров ===================== if (FastMACD < 1) { Comment("Период FastMACD должен быть больше нуля! Советник отключен!"); Print("Период FastMACD должен быть больше нуля! Советник отключен!"); return(0); } if (SignalMACD < 1) { Comment("Период SignalMACD должен быть больше нуля! Советник отключен!"); Print("Период SignalMACD должен быть больше нуля! Советник отключен!"); return(0); } if (SlowMACD < 1) { Comment("Период SlowMACD должен быть больше нуля! Советник отключен!"); Print("Период SlowMACD должен быть больше нуля! Советник отключен!"); return(0); } if (MAPeriod < 1) { Comment("Период средней должен быть больше нуля! Советник отключен!"); Print("Период средней должен быть больше нуля! Советник отключен!"); return(0); } if (MAMethod < 0 || MAMethod > 3) { Comment("Метод средней должен быть от 0 до 3! Советник отключен!"); Print("Метод средней должен быть от 0 до 3! Советник отключен!"); return(0); } if (MAPrice < 0 || MAPrice > 6) { Comment("Цена применения средней должна быть от 0 до 6! Советник отключен!"); Print("Цена применения средней должна быть от 0 до 6! Советник отключен!"); return(0); } if (FastMACD >= SlowMACD) { Comment("Период FastMACD должен быть меньше SlowMACD! Советник отключен!"); Print("Период FastMACD должен быть меньше SlowMACD! Советник отключен!"); return(0); } // - 3 - =========================== Окончание блока ==================================== LastBar = 0; Activate = True; // Все проверки успешно завершены, возводим флаг активизации эксперта //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Функция деинициализации эксперта | //+-------------------------------------------------------------------------------------+ int deinit() { Comment(""); return(0); } //+-------------------------------------------------------------------------------------+ //| Проверка объема на корректность и округление | //+-------------------------------------------------------------------------------------+ double LotRound(double L) { return(MathRound(MathMin(MathMax(L, MinLot), MaxLot)/LotStep)*LotStep); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного пункта | //+-------------------------------------------------------------------------------------+ 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 Lot, double Price, double SL, double TP, bool Redefinition = True) // Redefinition - при True доопределять параметры до минимально допустимых // при False - возвращать ошибку { // - 1 - == Проверка достаточности свободных средств ==================================== if(AccountFreeMarginCheck(Symbol(), OP_BUY, Lot) <= 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+Tick); else return(4); if (ND(Bid-SL) <= StopLevel) if (Redefinition) SL = ND(Bid-StopLevel-Tick); 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-Tick); else return(4); if (ND(SL-Ask) <= StopLevel && SL != 0) if (Redefinition) SL = ND(Ask+StopLevel+Tick); else return(3); break; case OP_BUYSTOP: S = "BUYSTOP"; if (ND(Price-Ask) <= StopLevel) if (Redefinition) Price = ND(Ask+StopLevel+Tick); else return(2); if (ND(TP-Price) <= StopLevel && TP != 0) if (Redefinition) TP = ND(Price+StopLevel+Tick); else return(4); if (ND(Price-SL) <= StopLevel) if (Redefinition) SL = ND(Price-StopLevel-Tick); else return(3); break; case OP_SELLSTOP: S = "SELLSTOP"; if (ND(Bid-Price) <= StopLevel) if (Redefinition) Price = ND(Bid-StopLevel-Tick); else return(2); if (ND(Price-TP) <= StopLevel) if (Redefinition) TP = ND(Price-StopLevel-Tick); else return(4); if (ND(SL-Price) <= StopLevel && SL != 0) if (Redefinition) SL = ND(Price+StopLevel+Tick); else return(3); break; case OP_BUYLIMIT: S = "BUYLIMIT"; if (ND(Ask-Price) <= StopLevel) if (Redefinition) Price = ND(Ask-StopLevel-Tick); else return(2); if (ND(TP-Price) <= StopLevel && TP != 0) if (Redefinition) TP = ND(Price+StopLevel+Tick); else return(4); if (ND(Price-SL) <= StopLevel) if (Redefinition) SL = ND(Price-StopLevel-Tick); else return(3); break; case OP_SELLLIMIT: S = "SELLLIMIT"; if (ND(Price - Bid) <= StopLevel) if (Redefinition) Price = ND(Bid+StopLevel+Tick); else return(2); if (ND(Price-TP) <= StopLevel) if (Redefinition) TP = ND(Price-StopLevel-Tick); else return(4); if (ND(SL-Price) <= StopLevel && SL != 0) if (Redefinition) SL = ND(Price+StopLevel+Tick); else return(3); break; } // - 2 - == Окончание блока ============================================================= // - 3 - == Открытие ордера с ожидание торгового потока ================================= if(WaitForTradeContext()) // ожидание освобождения торгового потока { Comment("Отправлен запрос на открытие ордера ", S, " ..."); int ticket=OrderSend(Symbol(), Type, Lot, 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 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double NP(double A) { return(MathRound(A/Tick)*Tick); } //+-------------------------------------------------------------------------------------+ //| Генерация сигналов покупки и продажи по значениям средней скользящей и MACD | //+-------------------------------------------------------------------------------------+ void GetSignal() { Signal = 0; // - 1 - ====== Значения MACD, средней скользящей на текущем ТФ и на "большом" ТФ ======= double MA1 = iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, 1); double MA2 = iMA(NULL, 0, MAPeriod, 0, MAMethod, MAPrice, 2); double MAL1 = iMA(NULL, LargeTF, MALPeriod, 0, MALMethod, MALPrice, 1); double MAL2 = iMA(NULL, LargeTF, MALPeriod, 0, MALMethod, MALPrice, 2); double MACD1 = iMACD(NULL, 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_MAIN,1); double MACD2 = iMACD(NULL, 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_MAIN,2); double SMACD = iMACD(NULL,0,FastMACD,SlowMACD, SignalMACD, PRICE_CLOSE, MODE_SIGNAL, 1); // - 1 - ========================== Окончание блока ===================================== // - 2 - ======================== Генерация сигнала покупки ============================= if (MAL1 > MAL2 && // рост средней на "большом" ТФ MA1 > MA2 && // рост средней на текущем ТФ MACD1 > MACD2 && // рост гистограммы МАСД MACD1 > SMACD) // гистограмма выше сигнальной линии Signal = 1; // Сигнал покупки // - 2 - ========================== Окончание блока ===================================== // - 3 - ======================== Генерация сигнала продажи ============================= if (MAL1 < MAL2 && // падение средней на "большом" ТФ MA1 < MA2 && // падение средней на текущем ТФ MACD1 < MACD2 && // падение гистограммы МАСД MACD1 < SMACD) // гистограмма ниже сигнальной линии Signal = -1; // Сигнал продажи // - 3 - ========================== Окончание блока ===================================== } //+-------------------------------------------------------------------------------------+ //| Поиск своих ордеров. Возвращает: | //| 0 - Своих позиций нет. Можно открывать новую позицию | //| 1 - Не удалось закрыть указанную позицию. Требуется еще попытка | //| 2 - Существует противоположная указанной поиция | //+-------------------------------------------------------------------------------------+ int CheckOrders(int Type) // Type - Тип позиции, которую нужно закрыть или -1, если тип { // позиции не имеет значения for (int i = OrdersTotal()-1; i >= 0; i--) if (OrderSelect(i, SELECT_BY_POS)) if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) if (OrderType() == Type || Type < 0) { if (WaitForTradeContext()) { if (Type == OP_BUY) double Price = MarketInfo(Symbol(), MODE_BID); else Price = MarketInfo(Symbol(), MODE_ASK); if (!OrderClose(OrderTicket(), OrderLots(), NP(Price), 3)) return(1); } } else return(2); return(0); } //+-------------------------------------------------------------------------------------+ //| Открытие позиций | //+-------------------------------------------------------------------------------------+ bool Trade() { // - 1 - ============== Закрытие позиций, если какой-либо сигнал отсутствует ============ if (Signal == 0) if (CheckOrders(-1) != 0) return(False); // - 1 - ============================== Окончание блока ================================= // - 2 - ==================== Открытие длинной позиции ================================== if (Signal > 0) { int Res = CheckOrders(OP_SELL); if (Res == 0) // Открытых позиций нет, можно открывать новую if (OpenOrderCorrect(OP_BUY, Lots, NP(Ask), 0, 0) != 0) return(False); if (Res == 1) return(False);//Существует короткая позиция, которую закрыть не удалось } // - 2 - ==================== Окончание блока =========================================== // - 3 - ==================== Открытие короткой позиции ================================= if (Signal < 0) { Res = CheckOrders(OP_BUY); if (Res == 0) // Открытых позиций нет, можно открывать новую if (OpenOrderCorrect(OP_SELL, Lots, NP(Bid), 0, 0) != 0) return(False); if (Res == 1) return(False);// Существует длинная позиция, которую закрыть не удалось } // - 3 - ==================== Окончание блока =========================================== return(True); } //+-------------------------------------------------------------------------------------+ //| Функция start эксперта | //+-------------------------------------------------------------------------------------+ int start() { // - 1 - ========================== Можно ли работать эксперту? ========================= if (!Activate || FatalError) return(0); // - 1 - ============================= Окончание блока ================================== // - 2 - ========================== Контроль открытия нового бара ======================= if (LastBar == Time[0]) return(0); // - 2 - ============================= Окончание блока ================================== // - 3 - ========================== Расчет сигналов открытия и закрытия ================= GetSignal(); // - 3 - ============================= Окончание блока ================================== // - 4 - ================== Выполнение операций открытия и закрытия позиций ============= if (!Trade()) return(0); // - 4 - ============================= Окончание блока ================================== LastBar = Time[0]; return(0); }