//+-------------------------------------------------------------------------------------+ //| NightBatAndZZ.mq4 | //| Scriptong | //| scriptong@mail.ru | //+-------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" extern string A1 = "Период ATR и множитель"; extern int ATRPeriod = 7; extern double Factor = 4; extern string A2 = "================================================="; extern string A3 = "Цена применения (0-Close, 1-Open, 2-High, 3-Low и т. д.)"; extern int Price = 0; extern string A4 = "=================================="; extern string A5 = "Объем первой сделки. Если Lots = 0, то считается в процентах"; extern double Lots = 0.1; extern double PercentOfDepo = 5; extern string A6 = "==============================================================="; extern string A7 = "Время начала торговли"; extern int BeginHour = 0; extern string A8 = "==============================================================="; extern string A9 = "Время окончания торговли"; extern int EndHour = 24; extern string A10 = "==============================================================="; extern string A11 = "Параметры ZigZag"; extern int ExtDepth = 12; extern int ExtDeviation = 5; extern int ExtBackStep = 3; extern string A12 = "==============================================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 11243; bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, FreezeLevel, MinLot, MaxLot, LotStep, BuyLevel, SellLevel, UpLevel, DnLevel; datetime LastBar = 0, // Последний бар, на котором были произведены все расчеты LastSignal = 0, // Время последнего расчета сигнала LastCountTime = 0, // Время последнего рассчитанного бара LastPierce = 0, // Время последнего бробития уровня в ту или иную сторону SellTime, BuyTime; // Время открытия последних сделок для каждого из типов int Dir, BuyTicket, SellTicket, BuyType, SellType, LastZZ; //+-------------------------------------------------------------------------------------+ //| expert initialization function | //+-------------------------------------------------------------------------------------+ int init() { FatalError = False; Activate = 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 - ==================== Проверка корректности входных параметров ================== if (ATRPeriod < 1) { Comment("Значение ATRPeriod не может быть меньше 1. Советник отключен!"); Print("Значение ATRPeriod не может быть меньше 1. Советник отключен!"); return(0); } if (Factor <= 0) { Comment("Значение Factor не может быть 0 и меньше. Советник отключен!"); Print("Значение Factor не может быть 0 и меньше. Советник отключен!"); return(0); } if (Price < 0 || Price > 6) { Comment("Значение Price может быть от 0 до 6. Советник отключен!"); Print("Значение Price может быть от 0 до 6. Советник отключен!"); return(0); } if (PercentOfDepo <= 0 || PercentOfDepo >= 100.0) { Comment("Значение PercentOfDepo должно быть больше 0 и меньше 100."+ " Советник отключен!"); Print("Значение PercentOfDepo должно быть больше 0 и меньше 100."+ " Советник отключен!"); return(0); } if (BeginHour < 0 || BeginHour > 23 || BeginHour >= EndHour) { Comment("Время начала торговли должно быть от 0 до 24 и меньше времени "+ "окончания торговли. Советник отключен!"); Print("Время начала торговли должно быть от 0 до 24 и меньше времени "+ "окончания торговли. Советник отключен!"); return(0); } if (EndHour < 1 || EndHour > 24) { Comment("Время окончания торговли должно быть от 1 до 24. Советник отключен!"); Print("Время окончания торговли должно быть от 1 до 24. Советник отключен!"); return(0); } if (ExtDepth < 1) { Comment("Значение ExtDepth не может быть меньше 1. Советник отключен!"); Print("Значение ExtDepth не может быть меньше 1. Советник отключен!"); return(0); } if (ExtDeviation < 1) { Comment("Значение ExtDeviation не может быть меньше 1. Советник отключен!"); Print("Значение ExtDeviation не может быть меньше 1. Советник отключен!"); return(0); } if (ExtBackStep < 1) { Comment("Значение ExtBackStep не может быть меньше 1. Советник отключен!"); Print("Значение ExtBackStep не может быть меньше 1. Советник отключен!"); return(0); } // - 2 - ================================= Окончание блока ============================== // - 3 - ===================== Нахождение последнего экстремума ZigZag ================== double ZZHigh = 0, ZZLow = 0; // По умолчанию экстремума ZZ нет int i = 0; // Поиск начинается с текущего бара // - 3.1 - ============================= Цикл поиска экстремума ====================== while (ZZHigh == 0 && ZZLow == 0 && i < Bars) // Поиск, пока не будет найден экстремум { // или не будет достигнут конец исторических данных ZZHigh = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 1, i); ZZLow = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 2, i); i++; } // - 3.1 - ============================= Окончание блока ============================= // - 3.2 - ====================== Достигнут ли успех в поиске экстремума ============= if (i == Bars) { Comment("Слишком мало исторических данных для текущих настроек ZigZag. "+ "Советник отключен!"); Print("Слишком мало исторических данных для текущих настроек ZigZag. "+ "Советник отключен!"); return(0); } // - 3.2 - ============================= Окончание блока ============================= // - 3.3 - =================== Определение типа найденного экстремума ================ if (ZZHigh != 0) // Найден верхний экстремум ZZ LastZZ = -1; // Ожидается движение вниз if (ZZLow != 0) // Найден нижний экстремум ZZ LastZZ = 1; // Ожидается движение вверх // - 3.3 - ============================= Окончание блока ============================= // - 3 - ================================= Окончание блока ============================== LastCountTime = Time[1000]; // Время открытия последнего посчитанного бара UpLevel = 1000; // Текущий верхний уровень (для открытия BUY) DnLevel = 0; // Текущий нижний уровень (для открытия SELL) Dir = 0; // Текущее направление движения цены (1 - вверх, -1 - вниз) Activate = True; //---- return(0); } //+-------------------------------------------------------------------------------------+ //| expert deinitialization function | //+-------------------------------------------------------------------------------------+ int deinit() { //---- if (ObjectFind("NB_Level") == 0) ObjectDelete("NB_Level"); Comment(""); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Проверка объема на корректность и округление | //+-------------------------------------------------------------------------------------+ double LotRound(double L) { return(MathRound(MathMin(MathMax(L, MinLot), MaxLot)/LotStep)*LotStep); } //+-------------------------------------------------------------------------------------+ //| Расчет объема сделки, исходя из свободных средств. | //+-------------------------------------------------------------------------------------+ double GetLots() { if (Lots == 0) { double lot = (PercentOfDepo/100)*AccountFreeMargin()/ MarketInfo(Symbol(), MODE_MARGINREQUIRED); return(LotRound(lot)); } else return(LotRound(Lots)); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double NP(double A) { return(MathRound(A/Tick)*Tick); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ 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 Lots, 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+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, 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 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Расчет цены свечи по значению поля Price | //+-------------------------------------------------------------------------------------+ double GetPrice(int i) { switch (Price) { case 0: return(Close[i]); case 1: return(Open[i]); case 2: return(High[i]); case 3: return(Low[i]); case 4: return((High[i]+Low[i])/2); case 5: return((High[i]+Low[i]+Close[i])/3); case 6: return((High[i]+Low[i]+2*Close[i])/4); } } //+-------------------------------------------------------------------------------------+ //| Отображение уровня поддержки/сопротивления | //+-------------------------------------------------------------------------------------+ void ShowLevel(double Price, color Color) { if (ObjectFind("NB_Level") < 0) { ObjectCreate("NB_Level", OBJ_HLINE, 0, 1, Price); ObjectSet("NB_Level", OBJPROP_STYLE, STYLE_DOT); ObjectSet("NB_Level", OBJPROP_COLOR, Color); } else { ObjectMove("NB_Level", 0, 1, Price); ObjectSet("NB_Level", OBJPROP_COLOR, Color); } } //+-------------------------------------------------------------------------------------+ //| Расчет уровней для каждого направления торговли | //+-------------------------------------------------------------------------------------+ void GetSignal() { // - 1 - ============================= Инициализация переменных ========================= BuyLevel = 0; SellLevel = 0; // - 1 - ================================== Окончание блока ============================= // - 2 - =========== Поиск последнего пробитого уровня ATR ============================== int i = iBarShift(Symbol(), 0, LastCountTime, false); // С последнего посчитанного бара while (i > 0) { double ApplyPrice = GetPrice(i); double ATRF = iATR(Symbol(), 0, ATRPeriod, i)*Factor; if (Dir == 0) // если направление не определено (первый подход к GetSignal), то { DnLevel = MathMax(ApplyPrice - ATRF, DnLevel); // рассчитываем оба уровня - нижний UpLevel = MathMin(ApplyPrice + ATRF, UpLevel); // и верхний } if (Dir >= 0) // При наличии восходящего движения следим за пробитием поддержки if (Low[i] <= DnLevel) // пробита ли поддержка? { Dir = -1; // если пробита, то меняем текущее направление движения на нисходящее DnLevel = 0; LastPierce = Time[i]; // запоминаем время пробития } else DnLevel = MathMax(ApplyPrice - ATRF, DnLevel); // или высчитываем новый уровень if (Dir <= 0) // При наличии нисходящего движения следим за пробитием сопротивления if (High[i] >= UpLevel) // пробито ли сопротивление { Dir = 1; // если пробито, то меняем направление движения на восходящее UpLevel = 1000; LastPierce = Time[i]; // запоминаем время пробития i++; } else UpLevel = MathMin(ApplyPrice + ATRF, UpLevel); // или рассчитываем новый уровень i--; } // - 2 - ================================== Окончание блока ============================= LastCountTime = Time[i]; // Последний посчитанный бар запоминаем // - 3 - ================= Отображение верхнего уровня ATR выше цены ==================== if (Dir < 0) // текущее направление нисходящее { ShowLevel(UpLevel, Red); // отображаем уровень выше цены BuyLevel = UpLevel; // это и будет уровнем открытия Buy Stop } // - 3 - ================================== Окончание блока ============================= // - 4 - ================== Отображение нижнего уровня ATR ============================== if (Dir > 0) // текущее направление восходящее { ShowLevel(DnLevel, Blue); // отображаем уровень ниже цены SellLevel = DnLevel; // это и будет уровнем открытия Sell Stop } // - 4 - ================================== Окончание блока ============================= // - 5 - ================== Отслеживаение новых экстремумов ZigZag ====================== double ZZHigh0 = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 1, 0); double ZZLow0 = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 2, 0); if (ZZHigh0 != 0) // Найден верхний экстремум ZZ { LastZZ = -1; // Ожидается движение вниз return; } if (ZZLow0 != 0) // Найден нижний экстремум ZZ { LastZZ = 1; // Ожидается движение вверх return; } double ZZHigh1 = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 1, 1); double ZZLow1 = iCustom(NULL, 0, "ZigZag", ExtDepth, ExtDeviation, ExtBackStep, 2, 1); if (ZZHigh1 != 0) // Найден верхний экстремум ZZ { LastZZ = -1; // Ожидается движение вниз return; } if (ZZLow1 != 0) // Найден нижний экстремум ZZ { LastZZ = 1; // Ожидается движение вверх return; } // - 5 - ================================== Окончание блока ============================= } //+-------------------------------------------------------------------------------------+ //| Функция поиска своих ордеров | //+-------------------------------------------------------------------------------------+ void FindOrders() { BuyTicket = -1; SellTicket = -1; // Пока не нашли, считаем, что ни одного ордера нет BuyType = -1; SellType = -1; for (int i = OrdersTotal()-1; i >= 0; i--) // Используется весь список ордеров if (OrderSelect(i, SELECT_BY_POS)) // Убедимся, что ордер выбран if (OrderMagicNumber() == MagicNumber && // Ордер открыт экспертом, OrderSymbol() == Symbol()) // который прикреплен к текущей валютной паре { if (MathMod(OrderType(), 2) == 0) // Ордер BUY-типа { BuyTicket = OrderTicket(); // Сохраняем тикет BuyType = OrderType(); // Сохраняем тип BuyTime = MathMax(OrderOpenTime(), BuyTime); // Отслеживаем время последнего } // открытия else // Ордер SELL-типа { SellTicket = OrderTicket(); // Сохраняем тикет SellType = OrderType(); // Сохраняем тип SellTime = MathMax(OrderOpenTime(), SellTime); // Отслеживаем время последнего } // открытия } } //+-------------------------------------------------------------------------------------+ //| Закрытие заданного рыночного ордера | //+-------------------------------------------------------------------------------------+ bool CloseOrder(int Ticket) { if (OrderSelect(Ticket, SELECT_BY_TICKET) && // Существует ордер с заданным тикетом и OrderCloseTime() == 0) // ордер не закрыт if (WaitForTradeContext()) // Свободен ли торговый поток? { if (OrderType() == OP_BUY) // Если следует закрыть длинную сделку, double Price = MarketInfo(Symbol(), MODE_BID); // то применяется цена BID else // Если следует закрыть короткую сделку, Price = MarketInfo(Symbol(), MODE_ASK); // то применяется цена ASK if (!OrderClose(OrderTicket(), OrderLots(), NP(Price), 3)) // Если сделку не return(False); // удалось закрыть, то результат функции - False } return(True); // Можно открывать сделку } //+-------------------------------------------------------------------------------------+ //| Анализ расположения ордеров и позиций (перемещение стопов, цен открытия) | //+-------------------------------------------------------------------------------------+ bool CheckOrders() { // - 1 - ==================== Активен сигнал открытия длинных позиций =================== if (SellLevel > 0) // Существует поддержка (ATR_the_Bat ниже цены) { // - 1.1 - ============== Если существует сделка Sell, то закрываем ================= if (SellType == OP_SELL) // Тип позиции - Sell if (!CloseOrder(SellTicket)) // Попытка закрытия позиции return(false); // Если закрыть позицию не удалось, то вернем False (ошибка) // - 1.1 - ============================= Окончание блока ============================ // - 1.2 - ============ Если существует сделка Buy, то подтягиваем стоп ============= if (BuyType == OP_BUY) // Тип позиции - Buy if (OrderSelect(BuyTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // Ордер // успешно выбран и не находится в списке закрытых if (MathAbs(OrderStopLoss() - (SellLevel - Tick)) >= Tick) // Стоп необходимо // изменить if (Bid - SellLevel + Tick > StopLevel) // Уровень нового стопа располагается // достаточно далеко от текущей цены if (!OrderModify(BuyTicket, 0, NP(SellLevel - Tick), // Попытка изменения OrderTakeProfit(), 0)) // уровня стоп-приказа return(False); // Если модификация не удалась, то вернем ошибку // - 1.2 - ============================= Окончание блока ============================ // - 1.3 - ============ Открытие позиции BUY, если ZZ дал подтверждение ============= if (LastZZ == 1) // Последний экстремум ZZ - нижний if (Hour() >= BeginHour && Hour() < EndHour) // Попадаем ли в рабочее время? if (BuyType < 0) // Если ордера Buy нет, то открываем if (OpenOrderCorrect(OP_BUY, GetLots(), NP(Ask), NP(SellLevel - Tick), 0) != 0) return(False); // Если открыть сделку не удалось, то вернем ошибку // - 1.3 - ============================= Окончание блока ============================ } // - 1 - ================================ Окончание блока =============================== // - 2 - =================== Активен сигнал открытия коротких позиций =================== if (BuyLevel > 0) // Существует сопротивление (ATR_the_Bat выше цены) { // - 2.1 - =============== Если существует сделка Buy, то закрываем ================= if (BuyType == OP_BUY) // Тип позиции - Buy if (!CloseOrder(BuyTicket)) // Попытка закрытия позиции return(false); // Если закрыть позицию не удалось, то вернем False (ошибка) // - 2.1 - ============================= Окончание блока ============================ // - 2.2 - ============ Если существует сделка Sell, то подтягиваем стоп ============ if (SellType == OP_SELL) // Тип позиции - Sell if (OrderSelect(SellTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // Ордер // успешно выбран и не находится в списке закрытых if (MathAbs(OrderStopLoss() - (BuyLevel + Spread + Tick)) >= Tick) // Стоп // необходимо изменить if (BuyLevel + Spread + Tick - Ask > StopLevel) // Уровень нового стопа // располагается достаточно далеко от текущей цены if (!OrderModify(SellTicket, 0, NP(BuyLevel + Spread + Tick), // Попытка OrderTakeProfit(), 0)) // изменения уровня стоп-приказа return(False); // Если модификация не удалась, то вернем ошибку // - 2.2 - ============================= Окончание блока ============================ // - 2.3 - ============ Открытие позиции Sell, если ZZ дал подтверждение ============ if (LastZZ == -1) // Последний экстремум ZZ - верхний if (Hour() >= BeginHour && Hour() < EndHour) // Попадаем ли в рабочее время? if (SellType < 0) // Если ордера Sell нет, то открываем if (OpenOrderCorrect(OP_SELL, GetLots(), NP(Bid), // Попытка открытия сделки NP(BuyLevel + Spread + Tick), 0) != 0) return(False); // Если открыть сделку не удалось, то вернем ошибку // - 2.3 - ============================= Окончание блока ============================ } // - 2 - ================================ Окончание блока =============================== return(True); } //+-------------------------------------------------------------------------------------+ //| Функция 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 - ================ Расчет уровней открытия длинных и коротких позиций ============ if (LastBar == Time[0]) // Если на текущей свече уже все действия выполнены, return(0); // то нет нужды их повторять if (LastSignal != Time[0]) // Если на текущей свече уже был произведен расчет данных { // индикаторов ZigZag и ATR_the_Bat GetSignal(); // Расчет значений индикаторов ZigZag и ATR_the_Bat LastSignal = Time[0]; // Отмечаем, что расчет произведен } // - 3 - ================================ Окончание блока ============================== // - 4 - =========== Изменение стопов позиций и цены открытия отложенных ордеров ======== FindOrders(); // Нахождение своих ордеров if (!CheckOrders()) // Открытие/закрытие сделок, подтяжка стопов return(0); // - 4 - ========================== Окончание блока ===================================== LastBar = Time[0]; // Отмечаем, что все действия на текущей свече успешно выполнены return(0); }