#property copyright "Scritong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots=0.1; extern string A1 = "Параметры быстрого стохастика"; extern int FastK = 5; extern int FastD = 3; extern int FastSlowing = 3; extern string A2 = "==============================================="; extern string A3 = "Параметры медленного стохастика"; extern int SlowK = 20; extern int SlowD = 10; extern int SlowSlowing = 20; extern string A4 = "==============================================="; extern string A5 = "Множитель для уровня профита"; extern double Factor = 5; extern string A6 = "==============================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 10015; int Signal; bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, MinLot, MaxLot, LotStep, FreezeLevel, StopLoss, LastLot; 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 (FastK < 1) { Comment("Период FastK должен быть больше нуля! Советник отключен!"); Print("Период FastK должен быть больше нуля! Советник отключен!"); return(0); } if (FastD < 1) { Comment("Период FastD должен быть больше нуля! Советник отключен!"); Print("Период FastD должен быть больше нуля! Советник отключен!"); return(0); } if (FastSlowing < 1) { Comment("Период FastSlowing должен быть больше нуля! Советник отключен!"); Print("Период FastSlowing должен быть больше нуля! Советник отключен!"); return(0); } if (SlowK < 1) { Comment("Период SlowK должен быть больше нуля! Советник отключен!"); Print("Период SlowK должен быть больше нуля! Советник отключен!"); return(0); } if (SlowD < 1) { Comment("Период SlowD должен быть больше нуля! Советник отключен!"); Print("Период SlowD должен быть больше нуля! Советник отключен!"); return(0); } if (SlowSlowing < 1) { Comment("Период SlowSlowing должен быть больше нуля! Советник отключен!"); Print("Период SlowSlowing должен быть больше нуля! Советник отключен!"); 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); } //+-------------------------------------------------------------------------------------+ //| Генерация сигналов покупки и продажи по значениям двух стохастиков | //+-------------------------------------------------------------------------------------+ void GetSignal() { Signal = 0; // - 1 - ====== Определение значений главной и сигнальной линий обоих стохастиков ======= double FastM1 = iStochastic(NULL,0,FastK,FastD,FastSlowing,MODE_SMA,0,MODE_MAIN,1); double FastS1 = iStochastic(NULL,0,FastK,FastD,FastSlowing,MODE_SMA,0,MODE_SIGNAL,1); double SlowM1 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_MAIN,1); double SlowS1 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_SIGNAL,1); double SlowM2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_MAIN,2); double SlowS2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_SIGNAL,2); // - 1 - ========================== Окончание блока ===================================== // - 2 - ======================== Генерация сигнала покупки ============================= if (FastM1 > FastS1 && SlowM1 > SlowS1 && SlowM2 < SlowS2) { // - 2.1 - ===== Поиск предпоследнего пересечения главной и сигнальной линий ======== // ============================ медленного стохастика =============================== int i = 2; while (SlowM2 < SlowS2 && i < Bars) { SlowM2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_MAIN,i); SlowS2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_SIGNAL,i); i++; } // - 2.1 - ========================= Окончание блока ================================ // - 2.2 - ============= Определение уровня стопа и генерация сигнала =============== StopLoss = Low[iLowest(NULL, 0, MODE_LOW, i - 2, 2)] - Tick; Signal = 1; // Сигнал покупки // - 2.2 - ========================= Окончание блока ================================ } // - 2 - ========================== Окончание блока ===================================== // - 3 - ======================== Генерация сигнала продажи ============================= if (FastM1 < FastS1 && SlowM1 < SlowS1 && SlowM2 > SlowS2) { // - 3.1 - ===== Поиск предпоследнего пересечения главной и сигнальной линий ======== // ============================ медленного стохастика =============================== i = 2; while (SlowM2 > SlowS2 && i < Bars) { SlowM2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_MAIN,i); SlowS2 = iStochastic(NULL,0,SlowK,SlowD,SlowSlowing,MODE_SMA,0,MODE_SIGNAL,i); i++; } // - 3.1 - ========================= Окончание блока ================================ StopLoss = High[iHighest(NULL, 0, MODE_HIGH, i - 2, 2)] + Spread + Tick; 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) { int Res = CheckOrders(OP_SELL); if (Res == 0) // Открытых позиций нет, можно открывать новую { double TP = Ask + iATR(NULL, 0, 24, 1)*Factor;//Уровень профита - 5 волатильностей if (OpenOrderCorrect(OP_BUY, Lots, NP(Ask), NP(StopLoss), NP(TP)) != 0) return(False); } if (Res == 1) return(False);//Существует короткая позиция, которую закрыть не удалось } // - 1 - ==================== Окончание блока =========================================== // - 2 - ==================== Открытие короткой позиции ================================= if (Signal < 0) { Res = CheckOrders(OP_BUY); if (Res == 0) // Открытых позиций нет, можно открывать новую { TP = Bid - iATR(NULL, 0, 24, 1)*Factor;// Уровень профита - 5 сред. волатильностей if (OpenOrderCorrect(OP_SELL, Lots, NP(Bid), NP(StopLoss), NP(TP)) != 0) return(False); } if (Res == 1) return(False);// Существует длинная позиция, которую закрыть не удалось } // - 2 - ==================== Окончание блока =========================================== 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); }