//+------------------------------------------------------------------+
//|                                             PendingMove_1.13.mq4 |
//|                                            Copyright 2024, drknn |
//|                                svbdaa@gmail.com    drknn@mail.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, drknn"
#property link      "drknn@mail.ru"
#property strict

// ----------- Пользовательские переменные ---------------------------
sinput string		C1="----------------------------";//-------------- StartOrders Settings --------------
input double		StartLot = 0.1;// Lot for StartOrder
input int      	StartStopLoss = 300;// StopLoss For StartOrders. If <= 0, Then None
input int      	StartTakeProfit = 0;// TakeProfit For StartOrders. If <= 0, Then None
input int      	OrdersStartStep = 100;// Step For StartOrders
sinput string		C2="----------------------------";//-------------- NetOrders Settings --------------
input int      	MaxOrders=10;// How Many Orders Maximum
input int      	NetStopLoss = 90;// StopLoss For NetOrders. If <= 0, Then None
input int      	NetTakeProfit = 0;// TakeProfit For NetOrders. If <= 0, Then None
input int      	OrdersNetStep = 65;// Step For NetOrders
sinput string		C3="----------------------------";//-------------- Time Settings --------------
input bool			TradeByTime = true;
input bool			UseOrdersDelete = true;
input string		StartTime_1 = "00:30";
input string		EndTime_1 = "00:35";
input string		StartTime_2 = "00:36";
input string		EndTime_2 = "00:40";
input string		StartTime_3 = "00:45";
input string		EndTime_3 = "00:55";
input string		StartTime_4 = "00:56";
input string		EndTime_4 = "00:58";
input string		StartTime_5 = "15:30";
input string		EndTime_5 = "15:40";
input string		C4="------ Трейлингстоп ------";
input bool			TralingStartPending=true;// Use Trailing For StartOrders
input int				TrailingStop = 50; //Size of TrailingStop. If = 0, Then None
input int				TrailingStep = 5; //Size of  TrailingStep
input bool			WaitProfit = false; // Wait Profit, Then Trail
sinput string		C5="----------------------------";//-------------- Other Settings --------------
input int      	MAGIC = 111;// MagicNumber
input int      	Slippage = 30;// Slippage

// ----------- Вспомогательные переменные ---------------------------
string		SMB;
int				SPR,DGS,MinLevel,TicketBuy=0,TicketSell=0,DGTlot;
double		PR,SL,TP,LOT;
bool      Dobro,LNG,b_Torg,b_PendidngTrailing,Rasstanovka;
double		PNT,MinLot,LotStep,LotLastOrdera,LastPrice;
int 			SchBuyLimit,SchSellLimit,SchBuyStop,SchSellStop,SchBuy,SchSell,SchRyn,SchOtl;


// ================================================================================================+
//             =============         БЛОК ИНИЦИАЛИЗАЦИИ СОВЕТНИКА          =============           |
// ================================================================================================+
int OnInit(){

	SMB=Symbol();
	PNT=MarketInfo(SMB,MODE_POINT);
	DGS=(int)MarketInfo(SMB,MODE_DIGITS);
	MinLot=MarketInfo(SMB,MODE_MINLOT);
	LNG=TerminalInfoString(TERMINAL_LANGUAGE)=="Russian";
	
	return(INIT_SUCCEEDED);
}
// ================================================================================================+
//             =============         ДЕИНИЦИАЛИЗАЦИЯ СОВЕТНИКА             =============           |
// ================================================================================================+
void OnDeinit(const int reason){
	DeinitComment(reason);
}
// ================================================================================================+
//             =============         СТАРТ РАБОТЫ СОВЕТНИКА            =============               |
// ================================================================================================+
void OnTick(){
	MinLevel=(int)MarketInfo(SMB,MODE_STOPLEVEL);
	SPR=(int)MarketInfo(SMB,MODE_SPREAD);
	// ===============================================================================================
	// =========================          Блок             ==========================================
	// =========================    Предустановки времени   ==========================================
	// ===============================================================================================
	CountOrders();
	if(TradeByTime && UseOrdersDelete && SchRyn+SchOtl>0){
		if(
			!isTradeTimeString(StartTime_1,EndTime_1) &&
			!isTradeTimeString(StartTime_2,EndTime_2) &&
			!isTradeTimeString(StartTime_3,EndTime_3) &&
			!isTradeTimeString(StartTime_4,EndTime_4) &&
			!isTradeTimeString(StartTime_5,EndTime_5)
		){// время вышло - закрываем все позиции
			Close_All(true,true);
			Print(Text(LNG,"Время работы вышло. Все ордера закрыты.","Working hours are over. All orders are closed."));
			Rasstanovka=true;
			return;
		}
	}
	b_Torg=false;
	if(TradeByTime){
		if(
			isTradeTimeString(StartTime_1,EndTime_1) ||
			isTradeTimeString(StartTime_2,EndTime_2) ||
			isTradeTimeString(StartTime_3,EndTime_3) ||
			isTradeTimeString(StartTime_4,EndTime_4) ||
			isTradeTimeString(StartTime_5,EndTime_5)
		){// время торга наступило
			b_Torg=true;
		}
	}
	else{
		b_Torg=true;
	}
	// ========================= Закрылись рыночные, остались отложки ================================
	if((SchBuy<=0 && SchBuyStop>0 && SchSell+SchSellStop<=0) || (SchSell<=0 && SchSellStop>0 && SchBuy+SchBuyStop<=0)){
		Close_All(true,true);
		Print(Text(LNG,"Торговая сессия закончилась. Старые отложенные ордера удалены.","Trading session ended. Old pending orders have been deleted."));
		Rasstanovka=true;
		return;
	}
	// ===============================================================================================
	// =========================          Блок 1            ==========================================
	// =========================    Стартовая расстановка   ==========================================
	// ===============================================================================================
	
	if(b_Torg && SchRyn+SchOtl<=0){
		Rasstanovka=true;
		b_PendidngTrailing=false;
		TicketBuy=0; TicketSell=0;
		// ----------- Ставим байстоп -----------------
		LOT=ProverkaLota(StartLot);
		PR=NormalizeDouble(Ask+OrdersStartStep*PNT,DGS);
		if(StartStopLoss>0){
			SL=NormalizeDouble(PR-StartStopLoss*PNT,DGS);
		}
		else{
			SL=0;
		}
		if(StartTakeProfit>0){
			TP=NormalizeDouble(PR+StartTakeProfit*PNT,DGS);
		}
		else{
			TP=0;
		}
		TicketBuy=OpenOrder(SMB,"BUYSTOP",LOT,PR,Slippage,SL,TP,MAGIC,1.0,false);
		// ----------- Ставим селлстоп -----------------
		LOT=ProverkaLota(StartLot);
		PR=NormalizeDouble(Bid-OrdersStartStep*PNT,DGS);
		if(StartStopLoss>0){
			SL=NormalizeDouble(PR+StartStopLoss*PNT,DGS);
		}
		else{
			SL=0;
		}
		if(StartTakeProfit>0){
			TP=NormalizeDouble(PR-StartTakeProfit*PNT,DGS);
		}
		else{
			TP=0;
		}
		TicketSell=OpenOrder(SMB,"SELLSTOP",LOT,PR,Slippage,SL,TP,MAGIC,1.1,false);
		if(TicketBuy>0 && TicketSell>0){
			b_PendidngTrailing=true;
		}
	}
	// ===============================================================================================
	// =========================          Блок 2            ==========================================
	// ================    Сработала отложка. Удаляем противоположную   ==============================
	// ===============================================================================================
	if(SchBuy==1 && SchSellStop==1){
		Close_All_Sell(true);
	}
	if(SchSell==1 && SchBuyStop==1){
		Close_All_Buy(true);
	}
	// ===============================================================================================
	// =========================          Блок 3            ==========================================
	// ================          Ставим сетку из стоповых ордеров       ==============================
	// ===============================================================================================
	CountOrders();
	if(Rasstanovka && ((SchBuy==1 && SchOtl<=0) || (SchBuy>0 && SchBuyStop<MaxOrders))){
		for(int i=MaxOrders;i>0;i--){
			TicketBuy=0;
			TicketBuy=TickHighBuy(MAGIC);
			if(TicketBuy>0){
				LotLastOrdera=ParamOrdera(TicketBuy,"LOT","REAL");
				LastPrice=ParamOrdera(TicketBuy,"OPENPRICE","REAL");
				LotStep=LotStep(LotLastOrdera);
				LOT=ProverkaLota(LotLastOrdera+LotStep);
				PR=NormalizeDouble(LastPrice+OrdersNetStep*PNT,DGS);
				if(NetStopLoss==0){
					SL=0;			
				}
				else{
					SL=NormalizeDouble(PR-NetStopLoss*PNT,DGS);
				}
				if(NetTakeProfit==0){
					TP=0;			
				}
				else{
					TP=NormalizeDouble(PR+NetTakeProfit*PNT,DGS);
				}
				TicketBuy=OpenOrder(SMB,"BUYSTOP",LOT,PR,Slippage,SL,TP,MAGIC,3.0,false);
			}
			Sleep(500);
		}
		CountOrders();
		if(SchRyn+SchOtl>=MaxOrders+1){
			Rasstanovka=false;
		}
	}
	if(Rasstanovka && ((SchSell==1 && SchOtl<=0) || (SchSell>0 && SchSellStop<MaxOrders))){
		for(int i=MaxOrders;i>0;i--){
			TicketSell=0;
			TicketSell=TickLowSell(MAGIC);
			if(TicketSell>0){
				LotLastOrdera=ParamOrdera(TicketSell,"LOT","REAL");
				LastPrice=ParamOrdera(TicketSell,"OPENPRICE","REAL");
				LotStep=LotStep(LotLastOrdera);
				LOT=ProverkaLota(LotLastOrdera+LotStep);
				PR=NormalizeDouble(LastPrice-OrdersNetStep*PNT,DGS);
				if(NetStopLoss==0){
					SL=0;			
				}
				else{
					SL=NormalizeDouble(PR+NetStopLoss*PNT,DGS);
				}
				if(NetTakeProfit==0){
					TP=0;			
				}
				else{
					TP=NormalizeDouble(PR-NetTakeProfit*PNT,DGS);
				}
				TicketSell=OpenOrder(SMB,"SELLSTOP",LOT,PR,Slippage,SL,TP,MAGIC,3.1,false);
			}
		}
		if(SchRyn+SchOtl>=MaxOrders+1){
			Rasstanovka=false;
		}
	}
	
	
	
	RefreshRates();
	// ----------------------------- Тралим рыночные ордера ------------------------------------
	if(TrailingStop>0){
		TrailingRyn_b(TrailingStop,TrailingStep,Slippage,WaitProfit);
	}
	// ========================= Трал отложек ========================================================
	if(TrailingStop>0 && TralingStartPending && SchBuyStop==1 && SchSellStop==1 && SchBuy<=0 && SchSell<=0){
		TrailBuyStop(StartTakeProfit,StartStopLoss,TrailingStop,TrailingStep,MAGIC);
		TrailSellStop(StartTakeProfit,StartStopLoss,TrailingStop,TrailingStep,MAGIC);
	}
}
// ================================================================================================+
//             =============         ПОЛЬЗОВАТЕЛЬСКИЕ ПОДПРОГРАММЫ          =============          |
// ================================================================================================+

// ====================== LotStep(LotLastOrdera) ===================================================
// функция возвращает корректный шаг лота
// --------------------------------------
double LotStep(double LastLot){
	double Step=0;
	if(LastLot>=0.01 && LastLot<=0.09){
		Step=0.01;
	}
	if(LastLot>=0.1 && LastLot<=0.9){
		Step=0.1;
	}
	if(LastLot>=1.0){
		Step=1.0;
	}
	return(Step);
}

// =================================================================================================
// ------------------------ Трейлинг отложенных ордеров --------------------------------------------
// =================================================================================================

//======================= TrailBuyStop  =====================================================
// Функция подтягивает отложенный BuyStop-ордер вслед за ценой
// Этот ордер всегда выше рынка и едет вниз
//------------------------------------------------------------

void TrailBuyStop(int st_TakeProfit,int st_StopLoss,int st_TrStop,int st_TrStep,int Magic){  
	double		Pr,NewPrice,sl,tp;
	for(int i=OrdersTotal()-1;i>=0;i--){
		RefreshRates();
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderSymbol()!=SMB || OrderMagicNumber()!=Magic){continue;} 
			if(OrderType()==OP_BUYSTOP){ 
				Pr=OrderOpenPrice();// тут стоит байстоп сейчас
				NewPrice=Ask+(st_TrStop+st_TrStep)*PNT;// вычисляем, куда он должен встать
				NewPrice=NormalizeDouble(NewPrice,DGS);
				if(Pr-NewPrice>=st_TrStep*PNT && NewPrice-Ask>=MinLevel*PNT){
					if(st_StopLoss==0){sl=0;}
					else{sl=NewPrice-st_StopLoss*PNT;}
					if(st_TakeProfit==0){tp=0;}
					else{tp=NewPrice+st_TakeProfit*PNT;}
					sl=NormalizeDouble(sl,DGS);
					tp=NormalizeDouble(tp,DGS);
					if(!OrderModify(OrderTicket(),NewPrice,sl,tp,0,CLR_NONE)){
						Print(__FUNCTION__,Text(LNG,"(): Ошибка № ","(): Error No. "),GetLastError(),Text(LNG," модификации БайСтоп-ордера №"," of BuyStop-order modification No. "),OrderTicket()," NewPrice = ",NewPrice," sl = ",sl," tp = ",tp);
					}
				}
			}       
		}
	}
}     
// ============================================================================================

//======================= TrailSellStop  =====================================================
// Функция подтягивает отложенный SellStop-ордер вслед за ценой
// Этот ордер всегда ниже рынка и едет вверх
//-------------------------------------------------------------

void TrailSellStop(int st_TakeProfit,int st_StopLoss,int st_TrStop,int st_TrStep,int Magic){  
	double		Pr,NewPrice,sl,tp;
	for(int i=OrdersTotal()-1;i>=0;i--){//Начало цикла
		RefreshRates();
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderSymbol()!=SMB || OrderMagicNumber()!=Magic){continue;} 
			if(OrderType()==OP_SELLSTOP){
				Pr=OrderOpenPrice();// тут стоит селлстоп сейчас
				NewPrice=Bid-(st_TrStop+st_TrStep)*PNT;// вычисляем, куда он должен встать
				NewPrice=NormalizeDouble(NewPrice,DGS);
				if(NewPrice-Pr>=st_TrStep*PNT && Bid-NewPrice>=MinLevel*PNT){
					if(st_StopLoss==0){sl=0;}
					else{sl=NewPrice+st_StopLoss*PNT;}
					if(st_TakeProfit==0){tp=0;}
					else{tp=NewPrice-st_TakeProfit*PNT;}
					sl=NormalizeDouble(sl,DGS);
					tp=NormalizeDouble(tp,DGS);
					if(!OrderModify(OrderTicket(),NewPrice,sl,tp,0,CLR_NONE)){
						Print(__FUNCTION__,Text(LNG,"(): Ошибка № ","(): Error No. "),GetLastError(),Text(LNG," модификации СеллСтоп-ордера №"," of SellStop-order modification No. "),OrderTicket()," NewPrice = ",NewPrice," sl = ",sl," tp = ",tp);
					}
				}
			}     
		}
	}
}     
// ============================================================================================ 


// =================  TrailingRyn() =============================================================
// функция осуществляет трейлинг рыночных ордеров 
// ----------------------------------------------
void TrailingRyn_b(int ryn_TrStop,int ryn_TrStep,int Proskalz,bool Waitprofit) {
  int i;
  if(ryn_TrStop>=MinLevel && ryn_TrStep>0 && (SchBuy>0 || SchSell>0)){    
    for (i=OrdersTotal()-1;i>=0;i--){
      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
				Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
			}
      else {
        if (OrderSymbol()==SMB && OrderMagicNumber()==MAGIC){
          TrailingPositions_b(ryn_TrStop,ryn_TrStep,Proskalz,Waitprofit);
        }
      }
    }
  }
 if(ryn_TrStop>=MinLevel && ryn_TrStep==0)
 Alert("Трейлинг невозможен - ryn_TrStep==0");
} 
// =================================================================================================

//+------------------------------------------------------------------+
//| Сопровождение позиции простым тралом                             |
//+------------------------------------------------------------------+
void TrailingPositions_b(int ryn_TrStop, int ryn_TrStep, int Proskalz, bool Waitprofit){
  if(OrderType()==OP_BUY){
    if(!Waitprofit || (Bid-OrderOpenPrice())>ryn_TrStop*Point){
      if (OrderStopLoss()<Bid-(ryn_TrStop+ryn_TrStep-1)*Point){
        ModifyStopLoss_b(Bid-ryn_TrStop*Point);
      }
    }
  }
  if(OrderType()==OP_SELL){
    if(!Waitprofit || OrderOpenPrice()-Ask>ryn_TrStop*Point) {
      if(OrderStopLoss()>Ask+(ryn_TrStop+ryn_TrStep-1)*Point || OrderStopLoss()==0){
        ModifyStopLoss_b(Ask+ryn_TrStop*Point);
      }
    }
  }
}

//+------------------------------------------------------------------+
//| Перенос уровня StopLoss                                          |
//| Параметры:                                                       |
//|   ldStopLoss - уровень StopLoss                                  |
//+------------------------------------------------------------------+
void ModifyStopLoss_b(double ldStopLoss){
  bool fm=false;
  fm=OrderModify(OrderTicket(),OrderOpenPrice(),ldStopLoss,OrderTakeProfit(),0,CLR_NONE);
  if(!fm){
		Print(__FUNCTION__,Text(LNG,"() Ошибка № ","() Error No "),GetLastError());
	}
}

// ================ Деинициализация ================================================================
void DeinitComment(int Prichina){
	if(!IsTesting()){
		string s_Deint;
		switch (Prichina){
			case 0: s_Deint=Text(LNG,"Эксперт вызвал функцию ExpertRemove()","The expert called the ExpertRemove() function"); break;
			case 1: s_Deint=Text(LNG,"Или советник удалён с графика, или график получил нового эксперта","Either the advisor has been removed from the chart, or the chart has received a new expert"); break;
			case 2: s_Deint=Text(LNG,"Советник перекомпилирован","The advisor has been recompiled"); break;
			case 3: s_Deint=Text(LNG,"Символ или период графика был изменен","The chart symbol or period has been changed"); break;
			case 4: s_Deint=Text(LNG,"График закрыт, либо трейдер сменил шаблон графика","The chart is closed, or the trader has changed the chart template"); break;
			case 5: s_Deint=Text(LNG,"Пользователь изменил входные параметры","The user changed the input parameters"); break;
			case 6: s_Deint=Text(LNG,"Активирован другой счет либо произошло переподключение к торговому серверу вследствие изменения настроек счета","Another account has been activated or a reconnection to the trading server has occurred due to a change in account settings"); break;
			case 7: s_Deint=Text(LNG,"Применён другой шаблон графика","A different chart template has been applied"); break;
			case 8: s_Deint=Text(LNG,"Обработчик OnInit() вернул ненулевое значение","The OnInit() handler returned a non-zero value"); break;
			case 9: s_Deint=Text(LNG,"Терминал был закрыт","The terminal was closed"); break;
			default: s_Deint=Text(LNG,"Причина деинициализации не ясна","The reason for deinitialization is not clear"); break;
   	}
		Print(Text(LNG,"Советник деинициализирован. Причина: ","The advisor has been deinitialized. Cause: "),s_Deint);
  }
}
// =================================================================================================
// =================           Работа с ордерами           =========================================
// =================================================================================================

// ======================= CountOrders() =============================================================
void CountOrders(){
	SchBuyLimit=0; SchSellLimit=0; SchBuyStop=0; SchSellStop=0; SchBuy=0; SchSell=0; SchRyn=0; SchOtl=0;
  for(int i=OrdersTotal()-1;i>=0;i--){
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderSymbol()!=SMB || OrderMagicNumber()!=MAGIC) {continue;}
			if(OrderType()==OP_BUY){SchBuy++;}
			if(OrderType()==OP_SELL){SchSell++;}
			if(OrderType()==OP_BUYSTOP){SchBuyStop++;}
			if(OrderType()==OP_SELLSTOP){SchSellStop++;}
			if(OrderType()==OP_BUYLIMIT){SchBuyLimit++;}
			if(OrderType()==OP_SELLLIMIT){SchSellLimit++;}
		}
  }
  SchRyn = SchBuy+SchSell;
  SchOtl = SchBuyStop+SchSellStop+SchBuyLimit+SchSellLimit;
  return;
}

// =================== ParamOrdera() ===============================================================
// Функция возвращает цену стопа, тейка, открытия, закрытия и лот указанного ордера
// Параметры переменных:
// - Ticket - тикет ордера. Его нужно предварительно узнать с помощью функции TicketOrdera()
// - Param может принимать значения: "OPENPRICE", "CLOSEPRICE", "STOPLOSS", "TAKEPROFIT", "LOT","PROFIT"
//   значение "CLOSEPRICE" может указываться только для закрытых ордеров
// - Type  может принимать значения: "REAL", "HISTORY"
// - Magic - магикнумбер ордера
// ---------
//  Если на вход функции будет подано значение Param=="CLOSEPRICE" и при этом указан тип ордера, ещё
//  не закрытого, то функция выдаст сообщение об ошибке и вернёт значение = (-1), так как ордера,
//  которые ещё не находятся в истории, не имеют цены закрытия
// -------------------------------------------------------------------------------------------------
double ParamOrdera(int Ticket,string Param,string Type){
	// ------------- обработка ошибок ------------------
	if(Type!="REAL" && Type!="HISTORY"){
		Print(__FUNCTION__,Text(LNG,"(): Некорректное значение переменной Type = ","(): Incorrect variable value Type ="),Type);
		return(-1);
	}
	if(Param=="CLOSEPRICE" && Type=="REAL"){
		Print(__FUNCTION__,Text(LNG,"(): На вход функции подано значение CLOSEPRICE, а тип ордера - не ордер истории. Type = ","(): The function input is CLOSEPRICE, and the order type is not a history order. Type = "),Type);
		return(-1);
	}
	if(Param!="OPENPRICE" && Param!="CLOSEPRICE" && Param!="STOPLOSS" && Param!="TAKEPROFIT" && Param!="LOT" && Param!="PROFIT"){
		Print(__FUNCTION__,Text(LNG,"(): некорректное значение переменной Param = ","(): incorrect value of the Param variable = "),Param);
		return(-1);
	}
	// ----------------------------------------------------------------------
	if(!OrderSelect(Ticket,SELECT_BY_TICKET)){
		Print(__FUNCTION__,"(): не удалось выбрать ордер № ",Ticket," Код ошибки = ",GetLastError());
		return(-1);
	}
	else{
		if(Param=="LOT")				{return(OrderLots());}
		if(Param=="OPENPRICE")	{return(NormalizeDouble(OrderOpenPrice(),DGS));}
		if(Param=="CLOSEPRICE")	{return(NormalizeDouble(OrderClosePrice(),DGS));}
		if(Param=="STOPLOSS")		{return(NormalizeDouble(OrderStopLoss(),DGS));}
		if(Param=="TAKEPROFIT")	{return(NormalizeDouble(OrderTakeProfit(),DGS));}
		if(Param=="PROFIT")			{return(NormalizeDouble(OrderProfit(),2));}
	}
	return(-1);
}

// ========================================================================================
// ====================== Тикеты ордеров    ===============================================
// ========================================================================================

// ========== Тикет верхнего Buy-ордера ============================================================
int TickHighBuy(int Magic){
	int TICK=(-1);
	double Pr=0.0;
	for(int i=OrdersTotal()-1;i>=0;i--){
    if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
    else{
      if(OrderSymbol()!=SMB || OrderMagicNumber()!=Magic){continue;}
      if(OrderType()==OP_BUY || OrderType()==OP_BUYSTOP){
        if(OrderOpenPrice()>Pr){
					Pr=OrderOpenPrice();
					TICK=OrderTicket();
				}
			}
    }
  }
	return(TICK);
}
// ========== Тикет нижнего Sell-ордера ============================================================
int TickLowSell(int Magic){
	int TICK=(-1);
	double Pr=10000000;
	for(int i=OrdersTotal()-1;i>=0;i--){
    if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());	
		}
    else{
      if(OrderSymbol()!=SMB || OrderMagicNumber()!=Magic){continue;}
      if(OrderType()==OP_SELL || OrderType()==OP_SELLSTOP){
        if(OrderOpenPrice()<Pr || Pr==10000000){
					Pr=OrderOpenPrice();
					TICK=OrderTicket();
				}
			}
    }
  }
	return(TICK);
}
// ========================================================================================
// ====================== Закрытие ордеров    =============================================
// ========================================================================================

// =================== Close_All_Pending() =======================
// функция закрывает все рыночные и отложенные ордера
// ===========================================================
void Close_All_Pending(){
  int			Ticket=0;
	for(int i=OrdersTotal()-1;i>=0;i--){
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderMagicNumber()!=MAGIC || OrderSymbol()!=SMB){continue;}
			Ticket=OrderTicket();
			if(OrderType()==OP_BUYLIMIT || OrderType()==OP_SELLLIMIT || OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP){
				if(!OrderDelete(Ticket,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось удалить ордер № ","(): failed to delete order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
				else{
					RefreshRates();
				}
			}  
		}
	}
}

// =================== Close_All() =======================
// функция закрывает все рыночные и отложенные ордера
// ===========================================================
void Close_All(bool Delete_Otlozh,bool OnlyOneTool){
  int			Ticket=0;
	double	PriseAsk=0,PriseBid=0;
	double	Lot=0;
	
	for(int i=OrdersTotal()-1;i>=0;i--){
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OnlyOneTool){
				if(OrderSymbol()!=SMB){continue;}
			}
			if(OrderMagicNumber()!=MAGIC){continue;}
			PriseAsk=MarketInfo(SMB,MODE_ASK);
			PriseAsk=NormalizeDouble(PriseAsk,Digits); 
			PriseBid=MarketInfo(SMB,MODE_BID);
			PriseBid=NormalizeDouble(PriseBid,Digits); 
			Ticket=OrderTicket();
			Lot=OrderLots();
			if(OrderType()==OP_BUY){
				if(!OrderClose(Ticket,Lot,PriseBid,Slippage,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось закрыть ордер № ","(): failed to close order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
				else{
					RefreshRates();
				}
			}
			if(OrderType()==OP_SELL){
				if(!OrderClose(Ticket,Lot,PriseAsk,Slippage,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось закрыть ордер № ","(): failed to close order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
				else{
					RefreshRates();
				}
			}  
			if(Delete_Otlozh && (OrderType()==OP_BUYLIMIT || OrderType()==OP_SELLLIMIT || OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP)){
				if(!OrderDelete(Ticket,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось удалить ордер № ","(): failed to delete order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
				else{
					RefreshRates();
				}
			}  
		}
	}
}

// =================== Close_All_Buy() =======================
// функция закрывает все рыночные и отложенные ордера
// ===========================================================
void Close_All_Buy(bool Delete_Otlozh){
	int			Ticket=0;
	double	PriseBid=0;
	double	Lot=0;
	for(int i=OrdersTotal()-1;i>=0;i--){
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderSymbol()!=SMB){continue;}
			if(OrderMagicNumber()!=MAGIC){continue;}
			RefreshRates();
			PriseBid=NormalizeDouble(Bid,Digits); 
			Ticket=OrderTicket();
			Lot=OrderLots();
			if(OrderType()==OP_BUY){
				if(!OrderClose(Ticket,Lot,PriseBid,Slippage,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось закрыть ордер № ","(): failed to close order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
			}  
			if(Delete_Otlozh && (OrderType()==OP_BUYLIMIT || OrderType()==OP_BUYSTOP)){
				if(!OrderDelete(Ticket,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось удалить ордер № ","(): failed to delete order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError()); 
				}
			}  
		}
	}
}
// =================== Close_All_Sell() =======================
// функция закрывает все рыночные и отложенные ордера
// ===========================================================
void Close_All_Sell(bool Delete_Otlozh){
	int			Ticket=0;
	double	PriseAsk=0;
	double	Lot=0;
	
	for(int i=OrdersTotal()-1;i>=0;i--){
		if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)){
			Print(__FUNCTION__,"(): ",Text(LNG,"Ошибка выбора ордера № ","Failed to select order No. "),i,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
		}
		else{
			if(OrderSymbol()!=SMB){continue;}
			if(OrderMagicNumber()!=MAGIC){continue;}
			RefreshRates();
			PriseAsk=NormalizeDouble(Ask,Digits); 
			Ticket=OrderTicket();
			Lot=OrderLots();
			if(OrderType()==OP_SELL){
				if(!OrderClose(Ticket,Lot,PriseAsk,Slippage,CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось закрыть ордер № ","(): failed to close order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError());
				}
			}  
			if(Delete_Otlozh && (OrderType()==OP_SELLLIMIT || OrderType()==OP_SELLSTOP)){
				if(!OrderDelete(OrderTicket(),CLR_NONE)){
					Print(__FUNCTION__,Text(LNG,"(): не удалось удалить ордер № ","(): failed to delete order No. "),Ticket,Text(LNG," Код ошибки = "," Error code = "),GetLastError()); 
				}
			}  
		}
	}
}
// ============== OpenOrder() ====================================
// Функция открывает ордер заданного типа.
// Возвращает тикет ордера или (-1) в случае неудачи
// -------------------------------------------------
int OpenOrder(string Symbl,string Type,double Lot,double Prr,int Prosk,double StLoss,double TkProfit,int Magic,double Blok,bool UseComment){
	int Ticket=(-1);
	if(Type!="BUY" && Type!="SELL" && Type!="BUYSTOP" && Type!="SELLSTOP" && Type!="BUYLIMIT" && Type!="SELLLIMIT"){
		Print(__FUNCTION__"(): ",Text(LNG,"Ошибка! На вход подан неверный тип ордера = ","Error! Invalid order type entered ="),Type,Text(LNG,". Блок ",". Block "),Blok);
		return (Ticket);
	}
	// ------------- Нормализуем цены --------------------
	Prr=NormalizeDouble(Prr,DGS);
	StLoss=NormalizeDouble(StLoss,DGS);
	TkProfit=NormalizeDouble(TkProfit,DGS);
	int MinLVL=(int)MarketInfo(Symbl,MODE_STOPLEVEL);
	// ------------- Инициализируем тип ордера -----------
	int Tip=(-1);
	if(Type=="BUY"){Tip=OP_BUY;}
	if(Type=="SELL"){Tip=OP_SELL;}
	if(Type=="BUYLIMIT"){Tip=OP_BUYLIMIT;}
	if(Type=="SELLLIMIT"){Tip=OP_SELLLIMIT;}
	if(Type=="BUYSTOP"){Tip=OP_BUYSTOP;}
	if(Type=="SELLSTOP"){Tip=OP_SELLSTOP;}
	Ticket=OrderSend(Symbl,Tip,Lot,Prr,Prosk,StLoss,TkProfit,NULL,Magic,0,CLR_NONE);
	if(Ticket<0){
		int Error=GetLastError();
		Print(__FUNCTION__"(): Ошибка № ",Error," при открытии ",Type,"-ордера. Блок ",Blok);
		if(Error==129 || Error==130 || Error==131){
			string Stroka;
			if(Error==129){
				
				Stroka=Text(LNG,"Описание: Неправильная цена (PR) ","Description: Incorrect price (PR)");
			}
			if(Error==130){
				Stroka=Text(LNG,"Описание: Неправильные стопы (SL,TP) ","Description: Irregular feet (SL,TP) ");
			}
			if(Error==131){
				Stroka=Text(LNG,"Описание: Неправильный Lot ","Description: Irregular Lot ");
			}
			Print(Stroka,"Lot = ",Lot," Ask = ",Ask," Bid = ",Bid," PR = ",Prr," SL = ",StLoss," TP = ",TkProfit);
		}
		if(Error==4){
			Print(Text(LNG,"Описание ошибки: Торговый сервер занят","Error description: Trading server is busy"));
		}
		if(Error==6){
			Print(Text(LNG,"Описание ошибки: Нет связи с торговым сервером","Error description: No connection to the trading server"));
		}
		if(Error==8){
			Print(Text(LNG,"Описание ошибки: Слишком частые запросы. Попробуйте Sleep()","Error description: Requests are too frequent. Try Sleep()"));
		}
		if(Error==132){
			Print(Text(LNG,"Описание ошибки: Рынок закрыт","Error description: Market closed"));
		}
		if(Error==133){
			Print(Text(LNG,"Описание ошибки: Торговля запрещена в настройках терминала","Error description: Trading is prohibited in the terminal settings"));
		}
		if(Error==134){
			Print(Text(LNG,"Описание ошибки: Недостаточно денег для открытия ордера","Error description: There is not enough money to open an order"));
		}
		if(Error==135 || Error==138){
			Print(Text(LNG,"Описание ошибки: Нет цен или новая цена. Увеличьте проскальзывание","Error description: No prices or new price. Increase slippage"));
		}
		if(Error==135){
			Print(Text(LNG,"Описание ошибки: Неправильный параметр цены (PR) для торговой функции","Error description: Incorrect price parameter (PR) for the trading function"));
		}
	}
	else{
		if(UseComment){
			Print(Type,Text(LNG,"-ордер № ","-order No. "),Ticket,Text(LNG," установлен из блока "," installed from block "),Blok);
		}
	}
	return (Ticket);
}

// ========================================================================================
// ====================== Лоты ордеров    =================================================
// ========================================================================================

// ============ ProverkaLota() =====================================================================
// функция принимает и нормализует лот ордера
//-----------------------------------------------------
double ProverkaLota(double LotOrdera){
  string Tmp;
  double MinLots=(MarketInfo(SMB,MODE_MINLOT));
  double MaxLots=MarketInfo(SMB,MODE_MAXLOT);
  double CorrectLot=0;
  int    diglots=0;
  if(MinLots==1 || MinLots==0.1 || MinLots==0.01){
		if(MinLots==1){
			diglots=0;
		}
		if(MinLots==0.1){
			diglots=1;
		}
		if(MinLots==0.01){
			diglots=2;
		}
	}
	Tmp=DoubleToString(LotOrdera,diglots);// отбрасываем лишние числа
	CorrectLot=StringToDouble(Tmp);
  if(CorrectLot<MinLots){
    CorrectLot=MinLots;
  }
  if(CorrectLot>MaxLots){
    CorrectLot=MaxLots;
  }
  return(CorrectLot);
}

// =================================================================================================
// ======================   Прочие подпрограммы    =================================================
// =================================================================================================

// =================== Text ========================================================================
// Функция возвращает текст на выбраном языке терминала.
// Если терминал русскоязычный, то возвращается строка на русском. В противном случае на английском.
// -------------------------------------------------------------------------------------------------
string Text(bool Lang,string Russ,string Engl){
   if(Lang){
		return(Russ);
	}
  else return(Engl);
}

// ==================== CompareDoubles_n() =========================================================
// Функция сравнивает 2 числа типа double до указанной n-точности после запятой
// Если равны, возвращает true. Если не равны, возвращает false
// ----------------------------------------------------------------------------
bool CompareDoubles_n(int n, double number1, double number2){
  if(NormalizeDouble(number1-number2,n)==0) return(true);
  else return(false);
}

/*
Функция isTradeTimeString().

Данная функция возвращает флаг разрешения торговли по времени. Вообще-то, на самом деле проверяется расположение текущего времени торгового сервера внутри некоего временного отрезка. Если внутри, то функция isTradeTimeString() возвращает истину, иначе - ложь. Особенностью данной функции является возможность задания временного отрезка как внутри суток, так и за пределами одних суток. Функция isTradeTimeString() принимает следующие необязательные параметры:

TimeBegin - Строка в формате "ЧЧ:ММ", задаёт время начала торговли. Значение по умолчанию - "00:00".
TimeEnd - Строка в формате "ЧЧ:ММ", задаёт время окончания торговли. Значение по умолчанию - "00:00".
*/
//+----------------------------------------------------------------------------+

//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |

//+----------------------------------------------------------------------------+

//|  Версия   : 29.04.2009                                                     |

//|  Описание : Возвращает флаг разрешения торговли по времени.                |

//+----------------------------------------------------------------------------+

//|  Параметры:                                                                |

//|    TimeBegin - время начала торговли         (ЧЧ:ММ)                       |

//|    TimeEnd   - время окончания торговли      (ЧЧ:ММ)                       |

//+----------------------------------------------------------------------------+

bool isTradeTimeString(string TimeBegin="00:00", string TimeEnd="00:00") {
	datetime dtBegin, dtEnd;        // Время начала и окончания работы
	int      hc, he;                // Часы текущего времени и окончания работы
	dtBegin=StrToTime(TimeToStr(TimeCurrent(), TIME_DATE)+" "+TimeBegin);
	dtEnd  =StrToTime(TimeToStr(TimeCurrent(), TIME_DATE)+" "+TimeEnd);
	hc     =TimeHour(TimeCurrent());
	he     =TimeHour(dtEnd);
	if (dtBegin>=dtEnd) {
		if (hc>=he) dtEnd+=24*60*60; else dtBegin-=24*60*60;
	}
	if(TimeCurrent()>=dtBegin && TimeCurrent()<=dtEnd){
		return(true);
	}
  else{
		return(false);
	}
}