//+--------------------------------------------------------------------------------------+ //| NB_Channel_MQLabs.mq4 | //| Scriptong | //| | //+--------------------------------------------------------------------------------------+ #property copyright "Scriptong" #property link "scriptong@mail.ru" //---- input parameters extern double Lots = 0.1; extern string C1 = "Расчет стопа и профита: пункты (True), %(False) от ширины канала"; extern bool UsePipsStop = False; extern string C2 = "================================================================"; extern string C3 = "Отступ, стоп и профит в пунктах при UsePipsStop = True"; extern int Delta = 25; // Расстояние от линии до ордера в пунктах extern int TakeProfit = 50; extern int StopLoss = 50; extern string C4 = "================================================================"; extern string C5 = "Отступ, стоп и профит в % ширины канала при UsePipsStop = False"; extern double PercentDelta = 59; extern double PercentTP = 65; extern double PercentSL = 59; extern string C6 = "==============================================================="; extern string C7 = "Использовать среднюю линию канала (True) при установке ордеров"; extern bool UseMedianLine = False;//Если False - откладывать ордера при пересечении //верхней или нижней границы канала, если True - //добавляется средняя линия канала extern string C8 = "==============================================================="; extern string C9 = "TrailingStop1 - безубыток, TrailingStop2 - стандартный трейлинг"; extern int TrailingStop1 = 20000; extern int TrailingStop2 = 50; extern string C10 = "=============================================================="; extern string C11 = "Сколько баров участвуют в формировании фрактала"; extern int BarsForFract = 0; // Сколько баров участвуют в определении фрактала // (0 - будут предустановки) extern string C12 = "=============================================================="; extern string C13 = "Цвет стрелок, обозначающих цену открытия ордера"; extern color clBuy = Blue; extern color clSell = Red; extern string C14 = "=============================================================="; extern string C15 = "Тип используемых ордеров: True - стоповые, False - лимитные"; extern bool UseStopOrders = True; extern string C16 = "==========================================================="; extern string OpenOrderSound = "ok.wav"; extern int MagicNumber = 17589 ; bool Activate, FreeMarginAlert, FatalError; double Tick, Spread, StopLevel, MinLot, MaxLot, LotStep; double LowV, HighV, Middle, NewBid, SignalLine; datetime LastBar; int BFF, BuyTicket, SellTicket, BLTicket, SLTicket, BSTicket, SSTicket; //+-------------------------------------------------------------------------------------+ //| expert initialization function | //+-------------------------------------------------------------------------------------+ int init() { // - 1 - == Сбор информации об условиях торговли ======================================== Activate = False; FatalError = False; 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 = LotRound(Lots); // округление объема до ближайшего допустимого // - 2 - == Окончание блока ============================================================= // - 3 - == Проверка корректности входных параметров ==================================== if (ND(TakeProfit*Tick - StopLevel) <= 0 && TakeProfit != 0) { Comment("Значение TakeProfit должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); Print("Значение TakeProfit должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); return(0); } if (ND(StopLoss*Tick - StopLevel) <= 0 && StopLoss != 0) { Comment("Значение StopLoss должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); Print("Значение StopLoss должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); return(0); } if (ND(TrailingStop1*Tick - StopLevel) <= 0) { Comment("Значение TrailingStop1 должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); Print("Значение TrailingStop1 должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); return(0); } if (ND(TrailingStop2*Tick - StopLevel) <= 0) { Comment("Значение TrailingStop2 должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); Print("Значение TrailingStop2 должно быть больше ", MathCeil(StopLevel/Point), " пунктов."); return(0); } if (BarsForFract < 0) { Comment("Значение BarsForFract должно быть больше или равно нулю!"); Print("Значение BarsForFract должно быть больше или равно нулю!"); return(0); } // - 3 - == Окончание блока ============================================================= // - 4 - == Определение количества баров, участвующих в одном фрактале ================== if (BarsForFract>0) BFF=BarsForFract; else switch (Period()) { case 1: BFF=12; break; case 5: BFF=48; break; case 15: BFF=24; break; case 30: BFF=24; break; case 60: BFF=12; break; case 240: BFF=15; break; case 1440: BFF=10; break; case 10080: BFF=6; break; default: Comment("Не определен таймфрейм!"); return(-1); break; } // - 4 - == Окончание блока ============================================================= GetLastLevels(); LastBar = 0; Activate = True; //---- return(0); } //+-------------------------------------------------------------------------------------+ //| expert deinitialization function | //+-------------------------------------------------------------------------------------+ int deinit() { //---- if (ObjectFind("NB-TL_1") == 0) ObjectDelete("NB-TL_1"); if (ObjectFind("NB-TL_2") == 0) ObjectDelete("NB-TL_2"); if (ObjectFind("NB-MIDDLE") == 0) ObjectDelete("NB-MIDDLE"); Comment(""); //---- return(0); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double ND(double A) { return(NormalizeDouble(A, Digits)); } //+-------------------------------------------------------------------------------------+ //| Приведение значений к точности одного тика | //+-------------------------------------------------------------------------------------+ double NP(double A) { return(MathFloor(A/Tick)*Tick); } //+-------------------------------------------------------------------------------------+ //| Проверка объема на корректность и округление | //+-------------------------------------------------------------------------------------+ double LotRound(double L) { return(MathRound(MathMin(MathMax(L, MinLot), MaxLot)/LotStep)*LotStep); } //+-------------------------------------------------------------------------------------+ //| Расшифровка сообщения об ошибке | //+-------------------------------------------------------------------------------------+ 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 - Ошибка значения Lots | //+-------------------------------------------------------------------------------------+ int OpenOrderCorrect(int Type, double Price, double Lot, 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 = NP(Ask); else return(2); if (ND(TP-Bid) <= StopLevel && TP != 0) if (Redefinition) TP = NP(Bid+StopLevel+Tick); else return(4); if (ND(Bid-SL) <= StopLevel) if (Redefinition) SL = NP(Bid-StopLevel-Tick); else return(3); break; case OP_SELL: S = "SELL"; if (MathAbs(Price-Bid)/Point > 3) if (Redefinition) Price = NP(Bid); else return(2); if (NP(Ask-TP) <= StopLevel) if (Redefinition) TP = NP(Ask-StopLevel-Tick); else return(4); if (ND(SL-Ask) <= StopLevel && SL != 0) if (Redefinition) SL = NP(Ask+StopLevel+Tick); else return(3); break; case OP_BUYSTOP: S = "BUYSTOP"; if (ND(Price-Ask) <= StopLevel) if (Redefinition) Price = NP(Ask+StopLevel+Tick); else return(2); if (ND(TP-Price) <= StopLevel && TP != 0) if (Redefinition) TP = NP(Price+StopLevel+Tick); else return(4); if (ND(Price-SL) <= StopLevel) if (Redefinition) SL = NP(Price-StopLevel-Tick); else return(3); break; case OP_SELLSTOP: S = "SELLSTOP"; if (ND(Bid-Price) <= StopLevel) if (Redefinition) Price = NP(Bid-StopLevel-Tick); else return(2); if (ND(Price-TP) <= StopLevel) if (Redefinition) TP = NP(Price-StopLevel-Tick); else return(4); if (ND(SL-Price) <= StopLevel && SL != 0) if (Redefinition) SL = NP(Price+StopLevel+Tick); else return(3); break; case OP_BUYLIMIT: S = "BUYLIMIT"; if (ND(Ask-Price) <= StopLevel) if (Redefinition) Price = NP(Ask-StopLevel-Tick); else return(2); if (ND(TP-Price) <= StopLevel && TP != 0) if (Redefinition) TP = NP(Price+StopLevel+Tick); else return(4); if (ND(Price-SL) <= StopLevel) if (Redefinition) SL = NP(Price-StopLevel-Tick); else return(3); break; case OP_SELLLIMIT: S = "SELLLIMIT"; if (ND(Price - Bid) <= StopLevel) if (Redefinition) Price = NP(Bid+StopLevel+Tick); else return(2); if (ND(Price-TP) <= StopLevel) if (Redefinition) TP = NP(Price-StopLevel-Tick); else return(4); if (ND(SL-Price) <= StopLevel && SL != 0) if (Redefinition) SL = NP(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(MathMod(Type, 2) == 0, clBuy, clSell)); // Попытка открытия позиции завершилась неудачей 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 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Замена стандартного блока "if-else" | //+-------------------------------------------------------------------------------------+ double IF(bool Condition, double IfTrue, double IfFalse) { if (Condition) return(IfTrue); else return(IfFalse); } //+-------------------------------------------------------------------------------------+ //| Отображение канала | //+-------------------------------------------------------------------------------------+ void ShowChannel(datetime T1, double P1, datetime T2, double P2, double P3, double P4) { // - 1 - ======================== Отображение нижней линии канала ======================= if (ObjectFind("NB-TL_1") < 0) { ObjectCreate("NB-TL_1", OBJ_TREND, 0, T2, P4, T1, P3); ObjectSet("NB-TL_1", OBJPROP_COLOR, Lime); ObjectSet("NB-TL_1", OBJPROP_WIDTH, 2); ObjectSet("NB-TL_1", OBJPROP_STYLE, STYLE_SOLID); } else { ObjectMove("NB-TL_1", 0, T2, P4); ObjectMove("NB-TL_1", 1, T1, P3); } // - 1 - ================================ Окончание блока =============================== // - 2 - ======================== Отображение верхней линии канала ====================== if (ObjectFind("NB-TL_2") < 0) { ObjectCreate("NB-TL_2", OBJ_TREND, 0, T2, P2, T1, P1); ObjectSet("NB-TL_2", OBJPROP_COLOR, Lime); ObjectSet("NB-TL_2", OBJPROP_WIDTH, 2); ObjectSet("NB-TL_2", OBJPROP_STYLE, STYLE_SOLID); } else { ObjectMove("NB-TL_2", 1, T1, P1); ObjectMove("NB-TL_2", 0, T2, P2); } // - 2 - ================================ Окончание блока =============================== // - 3 - ======================== Отображение средней линии канала ====================== if (ObjectFind("NB-MIDDLE") < 0) { ObjectCreate("NB-MIDDLE", OBJ_TREND, 0, T2, (P2+P4)/2, T1, (P1+P3)/2); ObjectSet("NB-MIDDLE", OBJPROP_COLOR, Lime); ObjectSet("NB-MIDDLE", OBJPROP_WIDTH, 1); ObjectSet("NB-MIDDLE", OBJPROP_STYLE, STYLE_DOT); } else { ObjectMove("NB-MIDDLE", 1, T1, (P1 + P3)/2); ObjectMove("NB-MIDDLE", 0, T2, (P2 + P4)/2); } // - 3 - ================================ Окончание блока =============================== WindowRedraw(); } //+-------------------------------------------------------------------------------------+ //| Нахождение трех последних экстремумов | //+-------------------------------------------------------------------------------------+ void GetLastLevels() { // - 1 - ================================= Инициализация переменных ===================== LowV = 0; // Одна из границ канала HighV = 0; // Одна из границ канала int CurrentBar = 2; // Поиск фракталов начинается со второго бара int B1=-1, B2=-1, UpDown=0; // Номера фрактальных баров и флаг типа последнего фрактала // - 1 - ====================================== Окончание блока ========================= // - 2 - ======== Поиск двух последних фракталов - двух верхних или двух нижних ========= while((B1 == -1 || B2 == -1) && CurrentBar < Bars) { if (UpDown < 1 && // если еще не был найден верхний фрактал CurrentBar == iLowest(Symbol(), Period(), MODE_LOW, BFF*2+1, CurrentBar-BFF)) { if (UpDown == 0) // Еще ни один из экстремумов найден не был { UpDown = -1; // Следующий фрактал ожидается верхний B1 = CurrentBar; // Сохраняется номер бара, на котором найден фрактал double P1=Low[B1]; // Сохраняется значение фрактала } else // уже был найден один фрактал { B2=CurrentBar; // Поэтому найденный верхний сохраняется в B2 double P2=Low[B2]; // Сохраняется значение фрактала } } if (UpDown > -1 && // если еще не был найден нижний фрактал CurrentBar == iHighest(Symbol(), Period(), MODE_HIGH, BFF*2+1, CurrentBar-BFF)) { if (UpDown == 0) // Еще ни один из экстремумов найден не был { UpDown = 1; // Следующий фрактал ожидается нижний B1=CurrentBar; // Сохраняется номер бара, на котором найден фрактал P1=High[B1]; // Сохраняется значение фрактала } else // уже был найден нижний фрактал { B2=CurrentBar; // Поэтому найденный нижний сохраняется в B2 P2=High[B2]; // Сохраняется значение фрактала } } CurrentBar++; // Переход к следующему бару } if(B1 == -1 || B2 == -1) return; // - 2 - ====================================== Окончание блока ========================= // - 3 - ==== Расчет прямой по найденным точкам и расчет второй параллельной прямой ===== double Step = (P2-P1)/(B2-B1); // К - коэффициент наклона прямой P1 = P1-B1*Step; // B - коэффициент сдвига прямой по оси абсцисс if (UpDown == 1) // если была найдена пара верхних фракталов { // необходимо найти одну нижнюю точку, через которую будет // проведена прямая, параллельная найденной double PP = Low[2]-2*Step; // попытка провести линию через минимум второго бара for (int i = 3; i <= B2; i++) // Поиск до второго фрактального бара if (Low[i] < PP+Step*i) // если минимум этого бара ниже прямой, то PP=Low[i]-i*Step; // прямая проводится через минимум текущего бара } else // Была найдена пара нижних фракталов { // производится поиск верхней точки, через которую будет проведена прямая, PP = High[2]-2*Step; // параллельная найденной for(i = 3; i <= B2; i++) // Поиск до вторго фрактального бара if (High[i] > PP+Step*i) // Если максимум этого бара выше прямой, то PP=High[i]-i*Step; // прямая проводится через максимум текущего бара } // - 3 - ====================================== Окончание блока ========================= // - 4 - ========================= Формирование границ канала и отображение канала ====== LowV = PP; // Одна граница (не обязательно нижняя) HighV = P1; // Вторая граница (не обязательно верхняя) Middle = (P1 + PP)/2; // Средняя ShowChannel(Time[0], P1, Time[B2], P2, PP, PP+Step*B2); // - 4 - ====================================== Окончание блока ========================= } //+-------------------------------------------------------------------------------------+ //| Начало торговой сессии | //+-------------------------------------------------------------------------------------+ void Trade(double WorkLine) { // - 1 - ========= Преобразование размеров стопа и профита в единицы инструмента ======== if (UsePipsStop) { double sl = StopLoss*Point; // Уровень стопа, отложенный от цены открытия double tp = TakeProfit*Point; // Уровень профита, отложенный от цены открытия double delta = Delta*Point; // Цена открытия, отложенная от пробитой границы канала } else { double CW = MathAbs(HighV- LowV); // ширина канала sl = CW*(PercentSL/100.0); // Уровень стопа, отложенный от цены открытия tp = CW*(PercentTP/100.0); // Уровень профита, отложенный от цены открытия delta = CW*(PercentDelta/100.0);//Цена открытия,отложенная от пробитой границы канала } // - 1 - =================================== Окончание блока ============================ // - 2 - ====== Перемещение ордера Buy Stop/Limit при возникновении нового пробития ===== if (BSTicket > 0 || BLTicket > 0) { if (BSTicket > 0) // найден ордер Buy Stop { double Price = NP(WorkLine + delta + Spread); // Расчет новой цены открытия int ticket = BSTicket; } else // найден ордер Buy Limit { Price = NP(WorkLine - delta + Spread); // Расчет новой цены открытия ticket = BLTicket; } double TP = NP(Price+tp); // Профит в пунктах от цены открытия double SL = NP(Price-sl); // Стоп в пунктах от цены открытия if (OrderSelect(ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // выбор ордера if (MathAbs(Price - OrderOpenPrice()) >= Tick) // Если цена отличается от имеющейся if (WaitForTradeContext()) if (!OrderModify(OrderTicket(), Price, SL, TP, 0)) // Изменение параметров { // если операция прошла неудачно, то необходимо пробовать еще раз SignalLine = WorkLine; // для этого значение текущей линии сохраняется Print("BUY-ордер# ", OrderTicket(), ", WorkLine = ", WorkLine, ", delta = ", delta, ", Price = ", Price, ", SL = ", SL, ", TP = ", TP, ", Bid = ", Bid); return; } } // - 2 - =================================== Окончание блока ============================ // - 3 - ====== Перемещение ордера Sell Stop/Limit при возникновении нового пробития ==== if (SSTicket > 0 || SLTicket > 0) { if (SSTicket > 0) // найден ордер Sell Stop { Price = NP(WorkLine - delta); // Расчет новой цены открытия ticket = SSTicket; } else // найден ордер Sell Limit { Price = NP(WorkLine + delta); ticket = SLTicket; } TP = NP(Price-tp); // Профит в пунктах от цены открытия SL = NP(Price+sl); // Стоп в пунктах от цены открытия if (OrderSelect(ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) // выбор ордера if (MathAbs(Price - OrderOpenPrice()) >= Tick) // Если цена отличается от имеющейся if (WaitForTradeContext()) if (!OrderModify(OrderTicket(), Price, SL, TP, 0))// Изменение параметров { // если операция прошла неудачно, то необходимо пробовать еще раз SignalLine = WorkLine; // для этого значение текущей линии сохраняется Print("SELL-ордер# ", OrderTicket(), ", Price = ", Price, ", SL = ", SL, ", TP = ", TP, ", Bid = ", Bid); return; } } // - 3 - =================================== Окончание блока ============================ // - 4 - ====== Установка ордера Buy Stop или Buy Limit, если не найдены таковые ======== if (BSTicket < 0 && BLTicket < 0 && BuyTicket < 0 && SellTicket < 0) { if (UseStopOrders)//Если нужно использовать стоповые ордера, устанавливается Buy Stop { Price = NP(WorkLine + delta + Spread); int Type = OP_BUYSTOP; } else // Если нужно использовать лимитные ордера, устанавливается Buy Limit { Price = NP(WorkLine - delta + Spread); Type = OP_BUYLIMIT; } TP = NP(Price+tp); // Профит в пунктах от цены открытия SL = NP(Price-sl); // Стоп в пунктах от цены открытия if (OpenOrderCorrect(Type, Price, Lots, SL, TP) != 0) // Установка ордера { // При не состоявшейся установке откладывается до следующего тика SignalLine = WorkLine; return; } } // - 4 - =================================== Окончание блока ============================ // - 5 - ====== Установка ордера Sell Stop или Sell Limit, если таковые не найдены ====== if (SSTicket < 0 && SLTicket < 0 && SellTicket < 0 && BuyTicket < 0) { if (UseStopOrders)//Если нужно использовать стоповые ордера,устанавливается Sell Stop { Price = NP(WorkLine - delta); Type = OP_SELLSTOP; } else // Если нужно использовать лимитные ордера, устанавливается Sell Limit { Price = NP(WorkLine + delta); Type = OP_SELLLIMIT; } TP = NP(Price-tp); // Профит в пунктах от цены открытия SL = NP(Price+sl); // Стоп в пунктах от цены открытия if (OpenOrderCorrect(Type, Price, Lots, SL, TP) != 0) // Установка ордера { // При не состоявшейся установке откладывается до следующего тика SignalLine = WorkLine; return; } } // - 5 - =================================== Окончание блока ============================ SignalLine = 0; // Все операции завершены успешно, значение линии не сохраняется } //+-------------------------------------------------------------------------------------+ //| Поиск своих ордеров | //+-------------------------------------------------------------------------------------+ bool FindOwnOrder() { BuyTicket = -1; SellTicket = -1; BSTicket = -1; SSTicket = -1; BLTicket = -1; SLTicket = -1; for (int i = 0; i < OrdersTotal(); i++) if (OrderSelect(i, SELECT_BY_POS)) if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) switch (OrderType()) { case OP_BUY: BuyTicket = OrderTicket(); break; case OP_SELL: SellTicket = OrderTicket(); break; case OP_BUYSTOP: BSTicket = OrderTicket(); break; case OP_SELLSTOP: SSTicket = OrderTicket(); break; case OP_BUYLIMIT: BLTicket = OrderTicket(); break; case OP_SELLLIMIT: SLTicket = OrderTicket(); break; } return(True); return(False); } //+--------------------------------------------------------------------------------------+ //| Двухуровневый трейлинг-стоп | //| TrailingStop1 - выставляется один раз после достижения нужного кол-ва пунктов прибыли| //| TrailingStop2 - движущийся. Включается после отработки трейлинг-стопа первого уровня | //+--------------------------------------------------------------------------------------+ void TrailingStopDoubleLevel() { if (BuyTicket > 0) int ticket = BuyTicket; else ticket = SellTicket; if (OrderSelect(ticket, SELECT_BY_TICKET) && OrderCloseTime() == 0) { if (!WaitForTradeContext()) return; // Блок 1. Нормализация основных характеристик позиции ----------------------------------- RefreshRates(); double OpPrice = ND(OrderOpenPrice()); // Приведение цены открытия к нужной точности double SL = ND(OrderStopLoss()); // Приведение стоп-приказа к нужной точности double NBid = ND(Bid); double NAsk = ND(Ask); // Блок 1. ------------------------------------------------------------------------------- // Блок 2. Классический трейлинг длинной позиции ----------------------------------------- if(OrderType() == OP_BUY) if(ND(SL-OpPrice) >= 0) // Если стоп выше или равен цене открытия позиции { if(ND(NBid-Point*TrailingStop2-SL) > 0) // Если BID больше стопа на TrailingStop2 if(WaitForTradeContext()) // Ждем освобождение торгового потока if(!OrderModify(OrderTicket(), 0, ND(NBid-TrailingStop2*Point), OrderTakeProfit(), 0)) // Модификация Print("Не удалось изменить ордер BUY. Второй трал. Ошибка №", GetLastError(), ", Старый: ", SL, ", Новый: ", NBid-TrailingStop2*Point); // Развернутое сообщение об ошибке } // Блок 2. ------------------------------------------------------------------------------- // Блок 3. Перенос стопа в безубыток длинной позиции ------------------------------------- else { if(ND(NBid-OpPrice-TrailingStop1*Point) > 0 && // Если BID больше цены открытия ND(NBid-OpPrice-StopLevel) > 0) // на TrailingStop1 пунктов и дальше, чем if(WaitForTradeContext()) // уровень стопов if(!OrderModify(OrderTicket(), 0, OpPrice, OrderTakeProfit(), 0)) // модификация Print("Не удалось изменить ордер BUY. Первый трал. Ошибка №", // сообщение GetLastError(), ", Старый: ", SL, ", Новый: ", OpPrice);// в журнал } // Блок 3. ------------------------------------------------------------------------------- // Блок 4. Классический трейлинг короткой позиции ---------------------------------------- if(OrderType()==OP_SELL) // Для короткой позиции if(ND(OpPrice-SL) >= 0 && SL != 0) // Стоп ниже цены открытия и не равен нулю { if(ND(OpPrice-NAsk-StopLevel) > 0 && // ASK ниже цены открытия на StopLevel ND(SL-Point*TrailingStop2-NAsk) > 0) // и ниже стопа на TrailingStop2 пунктов if(WaitForTradeContext()) // Ожидаем освобождения торгового потока if(!OrderModify(OrderTicket(), 0, ND(NAsk+TrailingStop2*Point), OrderTakeProfit(), 0)) // модификация Print("Не удалось изменить ордер SELL. Второй трал. Ошибка №", GetLastError(), ", Старый: ", SL, ", Новый: ", NAsk+TrailingStop2*Point); } // Блок 4. ------------------------------------------------------------------------------- // Блок 5. Перенос стопа в безубыток короткой позиции ------------------------------------ else { if(ND(OpPrice-NAsk-Point*TrailingStop1) > 0 &&//ASK ниже открытия на TrailingStop1 ND(OpPrice-NAsk-StopLevel) > 0) // и на StopLevel пунктов if(WaitForTradeContext()) // Ожидаем торговый поток if(!OrderModify(OrderTicket(), 0, OpPrice, OrderTakeProfit(), 0))//модификация Print("Не удалось изменить ордер SELL. Первый трал. Ошибка №", GetLastError(), ", Старый: ", SL, ", Новый: ", OpPrice); } // Блок 5. ------------------------------------------------------------------------------- } return(0); } //+-------------------------------------------------------------------------------------+ //| Удаление отложенного ордера при открытии позиции | //+-------------------------------------------------------------------------------------+ void DeletePending() { int DelTicket = -1; if (BSTicket > 0) DelTicket = BSTicket; if (SSTicket > 0) DelTicket = SSTicket; if (BLTicket > 0) DelTicket = BLTicket; if (SLTicket > 0) DelTicket = SLTicket; if (DelTicket > 0 && OrderSelect(DelTicket, SELECT_BY_TICKET) && OrderCloseTime() == 0) if (WaitForTradeContext()) OrderDelete(DelTicket, Goldenrod); } //+-------------------------------------------------------------------------------------+ //| expert start function | //+-------------------------------------------------------------------------------------+ 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 - ======================= Поиск своих ордеров и трейлинг позиции ================= FindOwnOrder(); if (BuyTicket > 0 || SellTicket > 0) TrailingStopDoubleLevel(); // - 3 - =================================== Окончание блока ============================ // - 4 - =============== Удаление ордера, противоположного текущей позиции ============== if (BuyTicket > 0 || SellTicket > 0) // Если обнаружена позиция, то DeletePending(); // удаляются все ордера // - 4 - =================================== Окончание блока ============================ // - 5 - ============================ Получение значений границ канала ================== if (LastBar != Time[0]) { GetLastLevels(); LastBar = Time[0]; } // - 5 - =================================== Окончание блока ============================ // - 6 - ============= Установка ордеров при пробитии одной из границ канала ============ NewBid = ND(MarketInfo(Symbol(), MODE_BID)); // Установка ордеров, если достигнута одна из линий if (SignalLine != 0) Trade(SignalLine); else if (MathAbs(NewBid - HighV) < Tick) Trade(HighV); else if (MathAbs(NewBid - LowV) < Tick) Trade(LowV); else if (UseMedianLine && MathAbs(NewBid - Middle) < Tick) Trade(Middle); // - 6 - =================================== Окончание блока ============================ return(0); }