#define MODE_SPREAD 13
#define SELECT_BY_POS 0
#define MODE_TRADES 0
#define OP_SELL 1
#define MODE_HISTORY 1
#define OP_SELLLIMIT 3
#define OP_SELLSTOP 5
#define MODE_BID 9
#define MODE_ASK 10
//+------------------------------------------------------------------+
//|                                                            1.mq4 |
//|                                                   Copyright 2021 |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright " "
#property link      " "
#property version   "2.00"
#property description "  "


input string __note__ = " "; // Info
string note = __note__;
input double __Lot_Size__ = 0.01;//Lot_Size
double Lot_Size = __Lot_Size__;
input double __Lot_Multiplier__ = 1.3 ;//Lot_Multiplier
double Lot_Multiplier = __Lot_Multiplier__;
input double __Take_Profit__ = 5.0;//Take_Profit
double Take_Profit = __Take_Profit__;
input double __Pip_Step__ = 5.0;//Pip_Step
double Pip_Step = __Pip_Step__;
input int __Max_Trades__ = 15;//Max_Trades
int Max_Trades = __Max_Trades__;

  string DD_Alert_Settings="**************************************"; // DrawDown alerts and settings
  double  DD_Alert= 10.0;// DrawDown Alert level 
  string Alert_After_Text= "10% Drawdown Reached";// DrawDown Alert Text
  double Close_After= 20.0;//Close All Trades After %
  string Alert_After_Close= "All trades Closed";//Text for DD close alert

input bool TestEmail=false;
input bool TestNotification=false;
string notitest= " ";
int Gi_76 = 1;
bool Gi_80 = false;
bool Gi_84 = true;

double G_slippage_96 = 1.0;

double Gd_112 = 2.0;

double G_pips_128 = 500.0;
double Gd_136 = 10.0;
double Gd_144 = 10.0;


bool Gi_164 = false;
double Gd_168 = 20.0;
bool Gi_176 = false;
bool Gi_180 = false;
double Gd_184 = 48.0;
int G_magic_192 = 543210;
double G_price_196;
double Gd_204;
double Gd_unused_212;
double G_price_220;
double G_bid_228;
double Gd_236;
double Gd_244;
bool Gi_252;
string Gs_sell_256 = "sell";
datetime G_time_264 = 0;
int Gi_268;
int Gi_272 = 0;
double Gd_276;
int G_pos_284 = 0;
int Gi_288;
double Gd_292 = 0.0;
bool Gi_300 = false;
bool Gi_unused_304 = false;
bool Gi_308 = false;
int Gi_312;
bool Gi_316 = false;
int G_datetime_320 = 0;
double Gd_324;
double Gd_332;

// E37F0136AA3FFAF149B351F6A4C948E9
void OnInit() {

if(TestEmail==true)
  {
   SendMail("Test", "This is the test email that EA sends when started , if you dont want it you can turn it off from EA settings ");

  }
  
  if(TestNotification==true)
  {
   SendNotification(notitest);

  }


   Gd_244 = CEBF::MarketInfo(Symbol(), MODE_SPREAD) * Point;
 
   return;
}

// 52D46093050F38C27267BCE42543EF60
void OnDeinit() {
   return;
}

// EA2B2676C28C0DB26D39331A336C6B92
int __OnTick__() {
   double order_Lot_Size_0;
   int Li_unused_8 = 377313;
   if (Gi_176) f0_12(Gd_136, Gd_144, G_price_220);
   if (Gi_180) {
      if (TimeCurrent() >= Gi_268) {
         f0_2();
         Print("Closed All due to TimeOut");
      }
   }
   if (G_time_264 == Time[0]) return (0);
   G_time_264 = Time[0];
   double Ld_12 = f0_4();
   if (Gi_164) {
      if (Ld_12 < 0.0 && MathAbs(Ld_12) > Gd_168 / 100.0 * f0_6()) {
         f0_2();
         Print("Closed All due to Stop Out");
         Gi_316 = false;
      }
   }
   Gi_288 = f0_11();
   if (Gi_288 == 0) Gi_252 = false;
   for (G_pos_284 = CEBF::OrdersTotal() - 1; G_pos_284 >= 0; G_pos_284--) {
      CEBF::OrderSelect(G_pos_284, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
      if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) {
         if (CEBF::OrderType() == OP_SELL) {
            Gi_308 = true;
            order_Lot_Size_0 = CEBF::OrderLots ();
            break;
         }
      }
   }
   if (Gi_288 > 0 && Gi_288 <= Max_Trades) {
      CEBF::RefreshRates();
      Gd_236 = f0_5();
      if (Gi_308 && Bid - Gd_236 >= Pip_Step * Point) Gi_300 = true;
   }
   if (Gi_288 < 1) {
      Gi_308 = false;
      Gi_300 = true;
      Gd_204 = CEBF::AccountEquity();
   }
   if (Gi_300) {
      Gd_236 = f0_5();
      if (Gi_308) {
         if (Gi_80) {
            f0_1(1, 0);
            Gd_276 = NormalizeDouble(Lot_Multiplier * order_Lot_Size_0, Gd_112);
         } else Gd_276 = f0_9(OP_SELL);
         if (Gi_84) {
            Gi_272 = Gi_288;
            if (Gd_276 > 0.0) {
               Gi_312 = f0_10(1, Gd_276, Bid, G_slippage_96, Ask, 0, 0, Gs_sell_256 + "-" + Gi_272, G_magic_192, 0, HotPink);
               if (Gi_312 < 0) {
                  Print("Error: ", CEBF::GetLastError());
                  return (0);
               }
               Gd_236 = f0_5();
               Gi_300 = false;
               Gi_316 = true;
            }
         }
      }
   }
   if (Gi_300 && Gi_288 < 1) {
      G_bid_228 = Bid;
      if (!Gi_308) {
         Gi_272 = Gi_288;
         Gd_276 = f0_9(OP_SELL);
         if (Gd_276 > 0.0) {
            Gi_312 = f0_10(1, Gd_276, G_bid_228, G_slippage_96, G_bid_228, 0, 0, Gs_sell_256 + "-" + Gi_272, G_magic_192, 0, HotPink);
            if (Gi_312 < 0) {
               Print(Gd_276, "Error: ", CEBF::GetLastError());
               return (0);
            }
            Gi_316 = true;
         }
      }
      if (Gi_312 > 0) Gi_268 = TimeCurrent() + 60.0 * (60.0 * Gd_184);
      Gi_300 = false;
   }
   Gi_288 = f0_11();
   G_price_220 = 0;
   double Ld_20 = 0;
   for (G_pos_284 = CEBF::OrdersTotal() - 1; G_pos_284 >= 0; G_pos_284--) {
      CEBF::OrderSelect(G_pos_284, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
      if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) {
         if (CEBF::OrderType() == OP_SELL) {
            G_price_220 += CEBF::OrderOpenPrice() * CEBF::OrderLots();
            Ld_20 += CEBF::OrderLots();
         }
      }
   }
   if (Gi_288 > 0) G_price_220 = NormalizeDouble(G_price_220 / Ld_20, Digits);
   if (Gi_316) {
      for (G_pos_284 = CEBF::OrdersTotal() - 1; G_pos_284 >= 0; G_pos_284--) {
         CEBF::OrderSelect(G_pos_284, SELECT_BY_POS, MODE_TRADES);
         if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
         if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) {
            if (CEBF::OrderType() == OP_SELL) {
               G_price_196 = G_price_220 - Take_Profit * Point;
               Gd_unused_212 = G_price_196;
               Gd_292 = G_price_220 + G_pips_128 * Point;
               Gi_252 = true;
            }
         }
      }
   }
   if (Gi_316) {
      if (Gi_252 == true) {
         for (G_pos_284 = CEBF::OrdersTotal() - 1; G_pos_284 >= 0; G_pos_284--) {
            CEBF::OrderSelect(G_pos_284, SELECT_BY_POS, MODE_TRADES);
            if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
            if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) CEBF::OrderModify(CEBF::OrderTicket(), G_price_220, CEBF::OrderStopLoss(), G_price_196, 0, Yellow);
            Gi_316 = false;
         }
      }
   }
   return (0);
}

// 9A116C50D133C8648404081885194300
double f0_8(double Ad_0) {
   return (NormalizeDouble(Ad_0, Digits));
}

// 169720DB8C7DA7F48F483E787B4A2725
int f0_1(bool Ai_unused_0 = true, bool Ai_4 = true) {
   int Li_ret_8 = 0;
   for (int pos_12 = CEBF::OrdersTotal() - 1; pos_12 >= 0; pos_12--) {
      if (CEBF::OrderSelect(pos_12, SELECT_BY_POS, MODE_TRADES)) {
         if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) {
            if (CEBF::OrderType() == OP_SELL && Ai_4) {
               CEBF::RefreshRates();
               if (!CEBF::IsTradeContextBusy()) {
                  if (!(!CEBF::OrderClose(CEBF::OrderTicket(), CEBF::OrderLots(), f0_8(Ask), 5, CLR_NONE))) continue;
                  Print("Error close SELL " + CEBF::OrderTicket());
                  Li_ret_8 = -1;
                  continue;
               }
               if (G_datetime_320 == CEBF::iTime(NULL, 0, 0)) return (-2);
               G_datetime_320 = CEBF::iTime(NULL, 0, 0);
               Print("Need close SELL " + CEBF::OrderTicket() + ". Trade Context Busy");
               return (-2);
            }
         }
      }
   }
   return (Li_ret_8);
}

// BD1F338B493E3233DF78411E167716E8
double f0_9(int A_cmd_0) {
   double Lot_Size_4;
   int datetime_12;
   switch (Gi_76) {
   case 0:
      Lot_Size_4 = Lot_Size;
      break;
   case 1:
      Lot_Size_4 = NormalizeDouble(Lot_Size * MathPow(Lot_Multiplier, Gi_272), Gd_112);
      break;
   case 2:
      datetime_12 = 0;
      Lot_Size_4 = Lot_Size;
      for (int pos_20 = CEBF::OrdersHistoryTotal() - 1; pos_20 >= 0; pos_20--) {
         if (CEBF::OrderSelect(pos_20, SELECT_BY_POS, MODE_HISTORY)) {
            if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192) {
               if (datetime_12 < CEBF::OrderCloseTime()) {
                  datetime_12 = CEBF::OrderCloseTime();
                  if (CEBF::OrderProfit() < 0.0) {
                     Lot_Size_4 = NormalizeDouble(CEBF::OrderLots() * Lot_Multiplier, Gd_112);
                     continue;
                  }
                  Lot_Size_4 = Lot_Size;
               }
            }
         } else return (-3);
      }
   }
   if (CEBF::AccountFreeMarginCheck(Symbol(), A_cmd_0, Lot_Size_4) <= 0.0) return (-1);
   if (CEBF::GetLastError() == 134/* NOT_ENOUGH_MONEY */) return (-2);
   return (Lot_Size_4);
}

// CBBD1151F6D49BC6C817A0B96D15036D
int f0_11() {
   int count_0 = 0;
   for (int pos_4 = CEBF::OrdersTotal() - 1; pos_4 >= 0; pos_4--) {
      CEBF::OrderSelect(pos_4, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
      if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192)
         if (CEBF::OrderType() == OP_SELL) count_0++;
   }
   return (count_0);
}

// 41BB59E8D36C416E4C62910D9E765220
void f0_2() {
   for (int pos_0 = CEBF::OrdersTotal() - 1; pos_0 >= 0; pos_0--) {
      CEBF::OrderSelect(pos_0, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() == Symbol()) {
         if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192)
            if (CEBF::OrderType() == OP_SELL) CEBF::OrderClose(CEBF::OrderTicket(), CEBF::OrderLots(), Ask, G_slippage_96, Red);
         Sleep(1000);
      }
   }
}

// C159FD8BED695B6E6A109D3B72C199C3
int f0_10(int Ai_0, double A_Lot_Size_4, double A_price_12, int A_slippage_20, double Ad_24, int Ai_32, int Ai_36, string A_comment_40, int A_magic_48, int A_datetime_52, color A_color_56) {
   int ticket_60 = 0;
   int error_64 = 0;
   int count_68 = 0;
   int Li_72 = 100;
   switch (Ai_0) {
   case 3:
      for (count_68 = 0; count_68 < Li_72; count_68++) {
         ticket_60 = CEBF::OrderSend(Symbol(), OP_SELLLIMIT, A_Lot_Size_4, A_price_12, A_slippage_20, f0_0(Ad_24, Ai_32), f0_3(A_price_12, Ai_36), A_comment_40, A_magic_48, A_datetime_52,
            A_color_56);
         error_64 = CEBF::GetLastError();
         if (error_64 == 0/* NO_ERROR */) break;
         if (!((error_64 == 4/* SERVER_BUSY */ || error_64 == 137/* BROKER_BUSY */ || error_64 == 146/* TRADE_CONTEXT_BUSY */ || error_64 == 136/* OFF_QUOTES */))) break;
         Sleep(1000);
      }
      break;
   case 5:
      for (count_68 = 0; count_68 < Li_72; count_68++) {
         ticket_60 = CEBF::OrderSend(Symbol(), OP_SELLSTOP, A_Lot_Size_4, A_price_12, A_slippage_20, f0_0(Ad_24, Ai_32), f0_3(A_price_12, Ai_36), A_comment_40, A_magic_48, A_datetime_52,
            A_color_56);
         error_64 = CEBF::GetLastError();
         if (error_64 == 0/* NO_ERROR */) break;
         if (!((error_64 == 4/* SERVER_BUSY */ || error_64 == 137/* BROKER_BUSY */ || error_64 == 146/* TRADE_CONTEXT_BUSY */ || error_64 == 136/* OFF_QUOTES */))) break;
         Sleep(5000);
      }
      break;
   case 1:
      for (count_68 = 0; count_68 < Li_72; count_68++) {
         CEBF::RefreshRates();
         ticket_60 = CEBF::OrderSend(Symbol(), OP_SELL, A_Lot_Size_4, Bid, A_slippage_20, f0_0(Ask, Ai_32), f0_3(Bid, Ai_36), A_comment_40, A_magic_48, A_datetime_52, A_color_56);
         error_64 = CEBF::GetLastError();
         if (error_64 == 0/* NO_ERROR */) break;
         if (!((error_64 == 4/* SERVER_BUSY */ || error_64 == 137/* BROKER_BUSY */ || error_64 == 146/* TRADE_CONTEXT_BUSY */ || error_64 == 136/* OFF_QUOTES */))) break;
         Sleep(5000);
      }
   }
   return (ticket_60);
}

// 0D578CA46072792DE50D5B9F5F5F8784
double f0_0(double Ad_0, int Ai_8) {
   if (Ai_8 == 0) return (0);
   return (Ad_0 + Ai_8 * Point);
}

// 4347D7B92E8469B198EAA742F66BBE62
double f0_3(double Ad_0, int Ai_8) {
   if (Ai_8 == 0) return (0);
   return (Ad_0 - Ai_8 * Point);
}

// 4A186EA1A04A05E39FD2E7A94BB28576
double f0_4() {
   double Ld_ret_0 = 0;
   for (G_pos_284 = CEBF::OrdersTotal() - 1; G_pos_284 >= 0; G_pos_284--) {
      CEBF::OrderSelect(G_pos_284, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
      if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192)
         if (CEBF::OrderType() == OP_SELL) Ld_ret_0 += CEBF::OrderProfit();
   }
   return (Ld_ret_0);
}

// FDD5E0C68EEEAC73C07299767285F173
void f0_12(int Ai_0, int Ai_4, double A_price_8) {
   int Li_16;
   double order_stoploss_20;
   double price_28;
   if (Ai_4 != 0) {
      for (int pos_36 = CEBF::OrdersTotal() - 1; pos_36 >= 0; pos_36--) {
         if (CEBF::OrderSelect(pos_36, SELECT_BY_POS, MODE_TRADES)) {
            if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
            if (CEBF::OrderSymbol() == Symbol() || CEBF::OrderMagicNumber() == G_magic_192) {
               if (CEBF::OrderType() == OP_SELL) {
                  Li_16 = NormalizeDouble((A_price_8 - Ask) / Point, 0);
                  if (Li_16 < Ai_0) continue;
                  order_stoploss_20 = CEBF::OrderStopLoss();
                  price_28 = Ask + Ai_4 * Point;
                  if (order_stoploss_20 == 0.0 || (order_stoploss_20 != 0.0 && price_28 > order_stoploss_20)) CEBF::OrderModify(CEBF::OrderTicket(), A_price_8, price_28, CEBF::OrderTakeProfit(), 0, Red);
               }
            }
            Sleep(1000);
         }
      }
   }
}

// 91C97865111C4DD6B44C584F4B9358BB
double f0_6() {
   if (f0_11() == 0) Gd_324 = CEBF::AccountEquity();
   if (Gd_324 < Gd_332) Gd_324 = Gd_332;
   else Gd_324 = CEBF::AccountEquity();
   Gd_332 = CEBF::AccountEquity();
   return (Gd_324);
}

// 599A26C25DF2561FBAA884F47E1B315C
double f0_5() {
   double order_open_price_0;
   int ticket_8;
   double Ld_unused_12 = 0;
   int ticket_20 = 0;
   for (int pos_24 = CEBF::OrdersTotal() - 1; pos_24 >= 0; pos_24--) {
      CEBF::OrderSelect(pos_24, SELECT_BY_POS, MODE_TRADES);
      if (CEBF::OrderSymbol() != Symbol() || CEBF::OrderMagicNumber() != G_magic_192) continue;
      if (CEBF::OrderSymbol() == Symbol() && CEBF::OrderMagicNumber() == G_magic_192 && CEBF::OrderType() == OP_SELL) {
         ticket_8 = CEBF::OrderTicket();
         if (ticket_8 > ticket_20) {
            order_open_price_0 = CEBF::OrderOpenPrice();
            Ld_unused_12 = order_open_price_0;
            ticket_20 = ticket_8;
         }
      }
   }
   return (order_open_price_0);
}








int ___OnTick___()
      {
       
       double acctb= CEBF::AccountBalance();
       double accteq= CEBF::AccountEquity();
       double ddd=   accteq-acctb;
       double fddd= ddd*100;
       
       
       
       if(fddd <0 && fddd<= DD_Alert)
         { 
                              datetime LastActionTime; 
                              if ((LastActionTime != Time[0]) )
                              {
                              Alert (Alert_After_Text);
                              SendNotification(Alert_After_Text);
                              SendMail(Alert_After_Text,Alert_After_Text);
                              LastActionTime = Time[0];
                              } 
         }
         
               
    if(fddd <0 && fddd<= Close_After)
    {
         
             for(int i=CEBF::OrdersTotal()-1; i>=0; i--)        
    { 
     if (CEBF::OrderSelect(i,SELECT_BY_POS)==true) 
       {  
         double ExPrice;
         int Tck=CEBF::OrderTicket();                                        
         CEBF::RefreshRates();    
         if (CEBF::OrderType()==0)  {   
              ExPrice=CEBF::MarketInfo(CEBF::OrderSymbol(),MODE_BID);  
              CEBF::OrderClose(Tck,CEBF::OrderLots(),ExPrice,3);   
          } else if (CEBF::OrderType()==1) {                                                            
              ExPrice=CEBF::MarketInfo(CEBF::OrderSymbol(),MODE_ASK);
              CEBF::OrderClose(Tck,CEBF::OrderLots(),ExPrice,3);             
          }  
          int Err=CEBF::GetLastError();
          if (Err>0) Print("Error closing position. Ticket: ", Tck, "  Err: #",Err);                            
       }
    }
                                          datetime LastActionTime; 
                                          if ((LastActionTime != Time[0]) )
                                          {
                                          Alert (Alert_After_Close);
                                          SendNotification(Alert_After_Close);
                                          SendMail(Alert_After_Close,Alert_After_Close);
                                          LastActionTime = Time[0];
                                          }
    
    } 
    
       return NULL;
}

// 938363B042E987609BD8B876255B9679
 

//== fxDreema MQL4 to MQL5 Converter ==//

//-- Global Variables
int FXD_SELECTED_TYPE = 0;// Indicates what is selected by OrderSelect, 1 for trade, 2 for pending order, 3 for history trade
ulong FXD_SELECTED_TICKET = 0;// The ticket number selected by OrderSelect

// Set the missing predefined variables, which are controlled by RefreshRates
int Bars     = Bars(_Symbol, PERIOD_CURRENT);
int Digits   = _Digits;
double Point = _Point;
double Ask, Bid, Close[], High[], Low[], Open[];
long Volume[];
datetime Time[];

void OnTick()
{
	CEBF::RefreshRates();
	__OnTick__();
	___OnTick___();
}



class CEBF
{
private:
	/**
	* _LastError is used to set custom errors that could be returned by the custom GetLastError method
	* The initial value should be -1 and everything >= 0 should be valid error code
	* When setting an error code in it, it should be the MQL5 value,
	* because then in GetLastError it will be converted to MQL4 value
	*/
	static int _LastError;
public:
	CEBF() {
		
	};
	
	static double AccountBalance()
	{
		return ::AccountInfoDouble(ACCOUNT_BALANCE);
	}
	
	static double AccountEquity()
	{
		return ::AccountInfoDouble(ACCOUNT_EQUITY);
	}
	
	static double  AccountFreeMarginCheck(string symbol, int cmd, double volume)
	{
		MqlTick last_tick;
	
		if (::SymbolInfoTick(symbol, last_tick))
		{
			double freeMargin = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE);
			double margin = 0.0;
	
			if (::OrderCalcMargin((ENUM_ORDER_TYPE)cmd, symbol, volume, ((cmd==0) ? last_tick.ask : last_tick.bid), margin))
			{
				return (freeMargin - margin);
			}
		}
	
		return 0;
	}
	
	static string AccountName()
	{
		return ::AccountInfoString(ACCOUNT_NAME);
	}
	
	static int AccountNumber()
	{
		return (int)::AccountInfoInteger(ACCOUNT_LOGIN);
	}
	
	/**
	* In MQL4's documentation errors are also shown as numeric values and sometimes people use these numbers, because they are shorter to write.
	* This means that GetLastError shoud return such MQL4 numeric values instead of the MQL5 values.
	* Supports custom error codes that can be set with CEBF -> _LastError
	*/
	static int GetLastError()
	{
		int errorCode = 0;
	
		if (CEBF::_LastError >= 0)
		{
			errorCode = CEBF::_LastError;
			CEBF::_LastError = -1;
		}
		else
		{
			errorCode = ::GetLastError();
		}
	
		switch (errorCode)
		{
			//--- errors returned from trade server
			case ERR_SUCCESS                       : return 0; /* ERR_NO_ERROR */
			//case ERR_NO_RESULT                   : return 1; /* ERR_NO_RESULT */
			//case ERR_COMMON_ERROR                : return 2; /* ERR_COMMON_ERROR */
			case TRADE_RETCODE_INVALID             : return 3; /* ERR_INVALID_TRADE_PARAMETERS */
			case ERR_TRADE_SEND_FAILED             : return 4; /* ERR_SERVER_BUSY */
			//case ERR_OLD_VERSION                 : return 5; /* ERR_OLD_VERSION */
			case TRADE_RETCODE_CONNECTION          : return 6; /* ERR_NO_CONNECTION */
			case TRADE_RETCODE_REJECT              : return 7; /* ERR_NOT_ENOUGH_RIGHTS */
			//case TRADE_RETCODE_TOO_MANY_REQUESTS : return 8; /* ERR_TOO_FREQUENT_REQUESTS */
			case TRADE_RETCODE_ERROR               : return 9; /* ERR_MALFUNCTIONAL_TRADE */
			//case ERR_ACCOUNT_DISABLED            : return 64; /* ERR_ACCOUNT_DISABLED */
			//case ERR_INVALID_ACCOUNT             : return 65; /* ERR_INVALID_ACCOUNT */
			case TRADE_RETCODE_TIMEOUT             : return 128; /* ERR_TRADE_TIMEOUT */
			case TRADE_RETCODE_INVALID_PRICE       : return 129; /* ERR_INVALID_PRICE */
			case TRADE_RETCODE_INVALID_STOPS       : return 130; /* ERR_INVALID_STOPS */
			case TRADE_RETCODE_INVALID_VOLUME      : return 131; /* ERR_INVALID_TRADE_VOLUME */
			case TRADE_RETCODE_MARKET_CLOSED       : return 132; /* ERR_MARKET_CLOSED */
			case TRADE_RETCODE_TRADE_DISABLED      : return 133; /* ERR_TRADE_DISABLED */
			case TRADE_RETCODE_NO_MONEY            : return 134; /* ERR_NOT_ENOUGH_MONEY */
			case TRADE_RETCODE_PRICE_CHANGED       : return 135; /* ERR_PRICE_CHANGED */
			case TRADE_RETCODE_PRICE_OFF           : return 136; /* ERR_OFF_QUOTES */
			//case ERR_TRADE_SEND_FAILED           : return 137; /* ERR_BROKER_BUSY */
			case TRADE_RETCODE_REQUOTE             : return 138; /* ERR_REQUOTE */
			case TRADE_RETCODE_LOCKED              : return 139; /* ERR_ORDER_LOCKED */
			//case TRADE_RETCODE_LONG_ONLY         : return 140; /* ERR_LONG_POSITIONS_ONLY_ALLOWED */
			case TRADE_RETCODE_TOO_MANY_REQUESTS   : return 141; /* ERR_TOO_MANY_REQUESTS */
			//case ERR_TRADE_MODIFY_DENIED         : return 145; /* ERR_TRADE_MODIFY_DENIED */
			//case ERR_TRADE_CONTEXT_BUSY          : return 146; /* ERR_TRADE_CONTEXT_BUSY */
			case TRADE_RETCODE_INVALID_EXPIRATION  : return 147; /* ERR_TRADE_EXPIRATION_DENIED */
			case TRADE_RETCODE_LIMIT_ORDERS        : return 148; /* ERR_TRADE_TOO_MANY_ORDERS */
			// TRADE_RETCODE_HEDGE_PROHIBITED is listed in MQL5's documentation as a value, but it's not defined as a constant
			case 10046                             : return 149; /* ERR_TRADE_HEDGE_PROHIBITED */
			case TRADE_RETCODE_FIFO_CLOSE          : return 150; /* ERR_TRADE_PROHIBITED_BY_FIFO */
	
			//--- mql4 run time errors
			//case ERR_NO_MQLERROR                 : return 4000; /* ERR_NO_MQLERROR */
			case ERR_INVALID_POINTER_TYPE          : return 4001; /* ERR_WRONG_FUNCTION_POINTER */
			case ERR_SMALL_ARRAY                   : return 4002; /* ERR_ARRAY_INDEX_OUT_OF_RANGE */
			//case ERR_NOT_ENOUGH_MEMORY           : return 4003; /* ERR_NO_MEMORY_FOR_CALL_STACK */
			case ERR_MATH_OVERFLOW                 : return 4004; /* ERR_RECURSIVE_STACK_OVERFLOW */
			//case ERR_NOT_ENOUGH_STACK_FOR_PARAM  : return 4005; /* ERR_NOT_ENOUGH_STACK_FOR_PARAM */
			case ERR_STRING_OUT_OF_MEMORY          : return 4006; /* ERR_NO_MEMORY_FOR_PARAM_STRING */
			//case ERR_NO_MEMORY_FOR_TEMP_STRING   : return 4007; /* ERR_NO_MEMORY_FOR_TEMP_STRING */
			case ERR_NOTINITIALIZED_STRING         : return 4008; /* ERR_NOT_INITIALIZED_STRING */
			//case ERR_NOT_INITIALIZED_ARRAYSTRING : return 4009; /* ERR_NOT_INITIALIZED_ARRAYSTRING */
			//case ERR_NO_MEMORY_FOR_ARRAYSTRING   : return 4010; /* ERR_NO_MEMORY_FOR_ARRAYSTRING */
			case ERR_STRING_TOO_BIGNUMBER          : return 4011; /* ERR_TOO_LONG_STRING */
			//case ERR_REMAINDER_FROM_ZERO_DIVIDE  : return 4012; /* ERR_REMAINDER_FROM_ZERO_DIVIDE */
			//case ERR_ZERO_DIVIDE                 : return 4013; /* ERR_ZERO_DIVIDE */
			//case ERR_UNKNOWN_COMMAND             : return 4014; /* ERR_UNKNOWN_COMMAND */
			//case ERR_WRONG_JUMP                  : return 4015; /* ERR_WRONG_JUMP */
			case ERR_ZEROSIZE_ARRAY                : return 4016; /* ERR_NOT_INITIALIZED_ARRAY */
			//case ERR_DLL_CALLS_NOT_ALLOWED       : return 4017; /* ERR_DLL_CALLS_NOT_ALLOWED */
			//case ERR_CANNOT_LOAD_LIBRARY         : return 4018; /* ERR_CANNOT_LOAD_LIBRARY */
			//case ERR_CANNOT_CALL_FUNCTION        : return 4019; /* ERR_CANNOT_CALL_FUNCTION */
			//case ERR_EXTERNAL_CALLS_NOT_ALLOWED  : return 4020; /* ERR_EXTERNAL_CALLS_NOT_ALLOWED */
			//case ERR_NO_MEMORY_FOR_RETURNED_STR  : return 4021; /* ERR_NO_MEMORY_FOR_RETURNED_STR */
			//case ERR_SYSTEM_BUSY                 : return 4022; /* ERR_SYSTEM_BUSY */
			//case ERR_DLLFUNC_CRITICALERROR       : return 4023; /* ERR_DLLFUNC_CRITICALERROR */
			case ERR_INTERNAL_ERROR                : return 4024; /* ERR_INTERNAL_ERROR */
			case ERR_NOT_ENOUGH_MEMORY             : return 4025; /* ERR_OUT_OF_MEMORY */
			case ERR_INVALID_POINTER               : return 4026; /* ERR_INVALID_POINTER */
			case ERR_TOO_MANY_FORMATTERS           : return 4027; /* ERR_FORMAT_TOO_MANY_FORMATTERS */
			case ERR_TOO_MANY_PARAMETERS           : return 4028; /* ERR_FORMAT_TOO_MANY_PARAMETERS */
			case ERR_INVALID_ARRAY                 : return 4029; /* ERR_ARRAY_INVALID */
			case ERR_CHART_NO_REPLY                : return 4030; /* ERR_CHART_NOREPLY */
			//case ERR_INVALID_FUNCTION_PARAMSCNT  : return 4050; /* ERR_INVALID_FUNCTION_PARAMSCNT */
			//case ERR_INVALID_FUNCTION_PARAMVALUE : return 4051; /* ERR_INVALID_FUNCTION_PARAMVALUE */
			case ERR_WRONG_INTERNAL_PARAMETER      : return 4052; /* ERR_STRING_FUNCTION_INTERNAL */
			//case ERR_SOME_ARRAY_ERROR            : return 4053; /* ERR_SOME_ARRAY_ERROR */
			case ERR_SERIES_ARRAY                  : return 4054; /* ERR_INCORRECT_SERIESARRAY_USING */
			//case ERR_CUSTOM_INDICATOR_ERROR      : return 4055; /* ERR_CUSTOM_INDICATOR_ERROR */
			case ERR_INCOMPATIBLE_ARRAYS           : return 4056; /* ERR_INCOMPATIBLE_ARRAYS */
			case ERR_GLOBALVARIABLE_EXISTS         :
			case ERR_GLOBALVARIABLE_NOT_MODIFIED   :
			case ERR_GLOBALVARIABLE_CANNOTREAD     :
			case ERR_GLOBALVARIABLE_CANNOTWRITE    : return 4057; /* ERR_GLOBAL_VARIABLES_PROCESSING */
			case ERR_GLOBALVARIABLE_NOT_FOUND      : return 4058; /* ERR_GLOBAL_VARIABLE_NOT_FOUND */
			//case ERR_FUNC_NOT_ALLOWED_IN_TESTING : return 4059; /* ERR_FUNC_NOT_ALLOWED_IN_TESTING */
			case ERR_FUNCTION_NOT_ALLOWED          : return 4060; /* ERR_FUNCTION_NOT_CONFIRMED */
			case ERR_MAIL_SEND_FAILED              : return 4061; /* ERR_SEND_MAIL_ERROR */
			//case ERR_STRING_PARAMETER_EXPECTED   : return 4062; /* ERR_STRING_PARAMETER_EXPECTED */
			//case ERR_INTEGER_PARAMETER_EXPECTED  : return 4063; /* ERR_INTEGER_PARAMETER_EXPECTED */
			//case ERR_DOUBLE_PARAMETER_EXPECTED   : return 4064; /* ERR_DOUBLE_PARAMETER_EXPECTED */
			//case ERR_ARRAY_AS_PARAMETER_EXPECTED : return 4065; /* ERR_ARRAY_AS_PARAMETER_EXPECTED */
			//case ERR_HISTORY_WILL_UPDATED        : return 4066; /* ERR_HISTORY_WILL_UPDATED */
			//case ERR_TRADE_ERROR                 : return 4067; /* ERR_TRADE_ERROR */
			case ERR_RESOURCE_NOT_FOUND            : return 4068; /* ERR_RESOURCE_NOT_FOUND */
			case ERR_RESOURCE_UNSUPPOTED_TYPE      : return 4069; /* ERR_RESOURCE_NOT_SUPPORTED */
			case ERR_RESOURCE_NAME_DUPLICATED      : return 4070; /* ERR_RESOURCE_DUPLICATED */
			case ERR_INDICATOR_CANNOT_CREATE       : return 4071; /* ERR_INDICATOR_CANNOT_INIT */
			case ERR_INDICATOR_CANNOT_ADD          :
			case ERR_CHART_INDICATOR_CANNOT_ADD    : return 4072; /* ERR_INDICATOR_CANNOT_LOAD */
			case ERR_HISTORY_NOT_FOUND             : return 4073; /* ERR_NO_HISTORY_DATA */
			case ERR_HISTORY_LOAD_ERRORS           : return 4074; /* ERR_NO_MEMORY_FOR_HISTORY */
			case ERR_BUFFERS_NO_MEMORY             : return 4075; /* ERR_NO_MEMORY_FOR_INDICATOR */
			case ERR_FILE_ENDOFFILE                : return 4099; /* ERR_END_OF_FILE */
			// The file errors below have duplicate errors below around code 5010
			//case ERR_SOME_FILE_ERROR             : return 4100; /* ERR_SOME_FILE_ERROR */
			//case ERR_WRONG_FILENAME              : return 4101; /* ERR_WRONG_FILE_NAME */
			//case ERR_TOO_MANY_FILES              : return 4102; /* ERR_TOO_MANY_OPENED_FILES */
			//case ERR_CANNOT_OPEN_FILE            : return 4103; /* ERR_CANNOT_OPEN_FILE */
			//case ERR_INCOMPATIBLE_FILE           : return 4104; /* ERR_INCOMPATIBLE_FILEACCESS */
			case ERR_TRADE_POSITION_NOT_FOUND      :
			case ERR_TRADE_ORDER_NOT_FOUND         :
			case ERR_TRADE_DEAL_NOT_FOUND          : return 4105; /* ERR_NO_ORDER_SELECTED */
			case ERR_MARKET_UNKNOWN_SYMBOL         :
			case ERR_INDICATOR_UNKNOWN_SYMBOL      : return 4106; /* ERR_UNKNOWN_SYMBOL */
			//case ERR_INVALID_PRICE_PARAM         : return 4107; /* ERR_INVALID_PRICE_PARAM */
			//case ERR_INVALID_TICKET              : return 4108; /* ERR_INVALID_TICKET */
			case ERR_TRADE_DISABLED                :
			case TRADE_RETCODE_CLIENT_DISABLES_AT  : return 4109; /* ERR_TRADE_NOT_ALLOWED */
			case TRADE_RETCODE_SHORT_ONLY          : return 4110; /* ERR_LONGS_NOT_ALLOWED */
			case TRADE_RETCODE_LONG_ONLY           : return 4111; /* ERR_SHORTS_NOT_ALLOWED */
			case TRADE_RETCODE_SERVER_DISABLES_AT  : return 4112; /* ERR_TRADE_EXPERT_DISABLED_BY_SERVER */
			//case ERR_OBJECT_ALREADY_EXISTS       : return 4200; /* ERR_OBJECT_ALREADY_EXISTS */ // MQL5 doesn't give error when an object with the same name is created
			case ERR_OBJECT_WRONG_PROPERTY         : return 4201; /* ERR_UNKNOWN_OBJECT_PROPERTY */
			case ERR_OBJECT_NOT_FOUND              : return 4202; /* ERR_OBJECT_DOES_NOT_EXIST */
			//case ERR_INVALID_PARAMETER           : return 4203; /* ERR_UNKNOWN_OBJECT_TYPE */ // Value found after testing
			//case ERR_WRONG_STRING_PARAMETER      : return 4204; /* ERR_NO_OBJECT_NAME */ // Value found after testing
			//case ERR_OBJECT_COORDINATES_ERROR    : return 4205; /* ERR_OBJECT_COORDINATES_ERROR */
			//case ERR_INVALID_PARAMETER           : return 4206; /* ERR_NO_SPECIFIED_SUBWINDOW */ // Value found after testing
			case ERR_OBJECT_ERROR                  : return 4207; /* ERR_SOME_OBJECT_ERROR */
			case ERR_CHART_WRONG_PROPERTY          : return 4210; /* ERR_CHART_PROP_INVALID */
			case ERR_CHART_NOT_FOUND               : return 4211; /* ERR_CHART_NOT_FOUND */
			case ERR_CHART_WINDOW_NOT_FOUND        : return 4212; /* ERR_CHARTWINDOW_NOT_FOUND */
			case ERR_CHART_INDICATOR_NOT_FOUND     : return 4213; /* ERR_CHARTINDICATOR_NOT_FOUND */
			case ERR_MARKET_NOT_SELECTED           : return 4220; /* ERR_SYMBOL_SELECT */
			case ERR_NOTIFICATION_SEND_FAILED      : return 4250; /* ERR_NOTIFICATION_ERROR */
			case ERR_NOTIFICATION_WRONG_PARAMETER  : return 4251; /* ERR_NOTIFICATION_PARAMETER */
			case ERR_NOTIFICATION_WRONG_SETTINGS   : return 4252; /* ERR_NOTIFICATION_SETTINGS */
			case ERR_NOTIFICATION_TOO_FREQUENT     : return 4253; /* ERR_NOTIFICATION_TOO_FREQUENT */
			case ERR_FTP_NOSERVER                  : return 4260; /* ERR_FTP_NOSERVER */
			case ERR_FTP_NOLOGIN                   : return 4261; /* ERR_FTP_NOLOGIN */
			case ERR_FTP_CONNECT_FAILED            : return 4262; /* ERR_FTP_CONNECT_FAILED  */
			// ERR_FTP_CLOSED is listed in MQL5's documentation as a value, but it's not defined as a constant
			case 4524                              : return 4263; /* ERR_FTP_CLOSED */
			case ERR_FTP_CHANGEDIR                 : return 4264; /* ERR_FTP_CHANGEDIR */
			case ERR_FTP_FILE_ERROR                : return 4265; /* ERR_FTP_FILE_ERROR */
			case ERR_FTP_SEND_FAILED               : return 4266; /* ERR_FTP_ERROR */
			case ERR_TOO_MANY_FILES                : return 5001; /* ERR_FILE_TOO_MANY_OPENED */
			case ERR_WRONG_FILENAME                : return 5002; /* ERR_FILE_WRONG_FILENAME */
			case ERR_TOO_LONG_FILENAME             : return 5003; /* ERR_FILE_TOO_LONG_FILENAME */
			case ERR_CANNOT_OPEN_FILE              : return 5004; /* ERR_FILE_CANNOT_OPEN */
			case ERR_FILE_CACHEBUFFER_ERROR        : return 5005; /* ERR_FILE_BUFFER_ALLOCATION_ERROR */
			case ERR_CANNOT_DELETE_FILE            : return 5006; /* ERR_FILE_CANNOT_DELETE */
			case ERR_INVALID_FILEHANDLE            : return 5007; /* ERR_FILE_INVALID_HANDLE */
			case ERR_WRONG_FILEHANDLE              : return 5008; /* ERR_FILE_WRONG_HANDLE */
			case ERR_FILE_NOTTOWRITE               : return 5009; /* ERR_FILE_NOT_TOWRITE */
			case ERR_FILE_NOTTOREAD                : return 5010; /* ERR_FILE_NOT_TOREAD */
			case ERR_FILE_NOTBIN                   : return 5011; /* ERR_FILE_NOT_BIN */
			case ERR_FILE_NOTTXT                   : return 5012; /* ERR_FILE_NOT_TXT */
			case ERR_FILE_NOTTXTORCSV              : return 5013; /* ERR_FILE_NOT_TXTORCSV */
			case ERR_FILE_NOTCSV                   : return 5014; /* ERR_FILE_NOT_CSV */
			case ERR_FILE_READERROR                : return 5015; /* ERR_FILE_READ_ERROR */
			case ERR_FILE_WRITEERROR               : return 5016; /* ERR_FILE_WRITE_ERROR */
			case ERR_FILE_BINSTRINGSIZE            : return 5017; /* ERR_FILE_BIN_STRINGSIZE */
			case ERR_INCOMPATIBLE_FILE             : return 5018; /* ERR_FILE_INCOMPATIBLE */
			case ERR_FILE_IS_DIRECTORY             : return 5019; /* ERR_FILE_IS_DIRECTORY */
			case ERR_FILE_NOT_EXIST                : return 5020; /* ERR_FILE_NOT_EXIST */
			case ERR_FILE_CANNOT_REWRITE           : return 5021; /* ERR_FILE_CANNOT_REWRITE */
			case ERR_WRONG_DIRECTORYNAME           : return 5022; /* ERR_FILE_WRONG_DIRECTORYNAME */
			case ERR_DIRECTORY_NOT_EXIST           : return 5023; /* ERR_FILE_DIRECTORY_NOT_EXIST */
			case ERR_FILE_ISNOT_DIRECTORY          : return 5024; /* ERR_FILE_NOT_DIRECTORY */
			case ERR_CANNOT_DELETE_DIRECTORY       : return 5025; /* ERR_FILE_CANNOT_DELETE_DIRECTORY */
			case ERR_CANNOT_CLEAN_DIRECTORY        : return 5026; /* ERR_FILE_CANNOT_CLEAN_DIRECTORY */
			case ERR_ARRAY_RESIZE_ERROR            : return 5027; /* ERR_FILE_ARRAYRESIZE_ERROR */
			case ERR_STRING_RESIZE_ERROR           : return 5028; /* ERR_FILE_STRINGRESIZE_ERROR */
			case ERR_STRUCT_WITHOBJECTS_ORCLASS    : return 5029; /* ERR_FILE_STRUCT_WITH_OBJECTS */
			case ERR_WEBREQUEST_INVALID_ADDRESS    : return 5200; /* ERR_WEBREQUEST_INVALID_ADDRESS */
			case ERR_WEBREQUEST_CONNECT_FAILED     : return 5201; /* ERR_WEBREQUEST_CONNECT_FAILED */
			case ERR_WEBREQUEST_TIMEOUT            : return 5202; /* ERR_WEBREQUEST_TIMEOUT */
			case ERR_WEBREQUEST_REQUEST_FAILED     : return 5203; /* ERR_WEBREQUEST_REQUEST_FAILED */
			case ERR_USER_ERROR_FIRST              : return 65536; /* ERR_USER_ERROR_FIRST */
	
			// There is no something like ERR_COMMON_ERROR in MQL5, but for example ERR_INVALID_PARAMETER is returned
			// for what should be ERR_UNKNOWN_OBJECT_TYPE or ERR_NO_SPECIFIED_SUBWINDOW. Instead of deciding which one
			// to return, return ERR_COMMON_ERROR
			default : return 2; /* ERR_COMMON_ERROR */
		}
	}
	
	static bool IsTesting()
	{
		return (bool)::MQLInfoInteger(MQL_TESTER);
	}
	
	/**
	* Can't find such functionality in MQL5, but I think TERMINAL_CONNECTED should be here
	*/
	static bool IsTradeContextBusy()
	{
		if (!::TerminalInfoInteger(TERMINAL_CONNECTED)) return true;
	
		return false;
	}
	
	static double MarketInfo(string symbol, int type)
	{
		// For most cases below this is not needed, but OrderCalcMargin() returns error 5040 (Damaged parameter of string type) if the symbol is NULL
		if (symbol == NULL) symbol = ::Symbol();
	
		switch(type)
		{
			case 1 /* MODE_LOW                */ : return ::SymbolInfoDouble(symbol, SYMBOL_LASTLOW);
			case 2 /* MODE_HIGH               */ : return ::SymbolInfoDouble(symbol, SYMBOL_LASTHIGH);
			case 5 /* MODE_TIME               */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_TIME);
			case 9 /* MODE_BID                */ : return ::SymbolInfoDouble(symbol, SYMBOL_BID);
			case 10 /* MODE_ASK               */ : return ::SymbolInfoDouble(symbol, SYMBOL_ASK);
			case 11 /* MODE_POINT             */ : return ::SymbolInfoDouble(symbol, SYMBOL_POINT);
			case 12 /* MODE_DIGITS            */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_DIGITS);
			case 13 /* MODE_SPREAD            */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_SPREAD);
			case 14 /* MODE_STOPLEVEL         */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL);
			case 15 /* MODE_LOTSIZE           */ : return ::SymbolInfoDouble(symbol, SYMBOL_TRADE_CONTRACT_SIZE);
			case 16 /* MODE_TICKVALUE         */ : return ::SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
			case 17 /* MODE_TICKSIZE          */ : return ::SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
			case 18 /* MODE_SWAPLONG          */ : return ::SymbolInfoDouble(symbol, SYMBOL_SWAP_LONG);
			case 19 /* MODE_SWAPSHORT         */ : return ::SymbolInfoDouble(symbol, SYMBOL_SWAP_SHORT);
			case 20 /* MODE_STARTING          */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_START_TIME);
			case 21 /* MODE_EXPIRATION        */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_EXPIRATION_TIME);
			case 22 /* MODE_TRADEALLOWED      */ : return (::SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED);
			case 23 /* MODE_MINLOT            */ : return ::SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
			case 24 /* MODE_LOTSTEP           */ : return ::SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
			case 25 /* MODE_MAXLOT            */ : return ::SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
			case 26 /* MODE_SWAPTYPE          */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_SWAP_MODE);
			case 27 /* MODE_PROFITCALCMODE    */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
			case 28 /* MODE_MARGINCALCMODE    */ : return (double)::SymbolInfoInteger(symbol, SYMBOL_TRADE_CALC_MODE);
			case 29 /* MODE_MARGININIT        */ : return (double)::SymbolInfoDouble(symbol, SYMBOL_MARGIN_INITIAL);
			case 30 /* MODE_MARGINMAINTENANCE */ : return (double)::SymbolInfoDouble(symbol, SYMBOL_MARGIN_MAINTENANCE);
			case 31 /* MODE_MARGINHEDGED      */ : return (double)::SymbolInfoDouble(symbol, SYMBOL_MARGIN_HEDGED);
			case 32 /* MODE_MARGINREQUIRED    */ :
			{
				// Free margin required to open 1 lot for buying
			   double margin = 0.0;
	
				if (::OrderCalcMargin(ORDER_TYPE_BUY, symbol, 1, ::SymbolInfoDouble(symbol, SYMBOL_ASK), margin))
					return margin;
				else
					return 0.0;
			}
			case 33 /* MODE_FREEZELEVEL */     : return (double)::SymbolInfoInteger(symbol, SYMBOL_TRADE_FREEZE_LEVEL);
			case 34 /* MODE_CLOSEBY_ALLOWED */ : return 0.0;
		}
	
		return 0.0;
	}
	
	static bool OrderClose(long ticket, double lots, double price, int slippage, color arrow_color = clrNONE)
	{
		// ticket is actually position id, so find the position by its id
		int positionsTotal = ::PositionsTotal();
		bool found = false;
		long positionID = ticket;
	
		// try to find the position by position ID
		for (int index = positionsTotal-1; index >= 0; index--)
		{
			ticket = (long)::PositionGetTicket(index);
			if (::PositionGetInteger(POSITION_IDENTIFIER) == positionID)
			{
				found = true;
				break;
			}
		}
	
		/*
		// try to find the position by deal ticket
		if (!found) {
			if (::HistoryDealSelect(ticket))
			{
				long posID = ::HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
	
				for (int index = positionsTotal-1; index >= 0; index--)
				{
					ticket = (long)::PositionGetTicket(index);
					
					if (::PositionGetInteger(POSITION_IDENTIFIER) == posID)
					{
						found = true;
						break;
					}
				}
			}
		}
		*/
	
		if (!found) return false;
	
		double lots0   = ::NormalizeDouble(PositionGetDouble(POSITION_VOLUME), 5);
		string symbol  = ::PositionGetString(POSITION_SYMBOL);
		double lotstep = ::SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
	
		while (true)
	   {
			//-- fixing -------------------------------------------------------
			lots = ::MathFloor(lots/lotstep)*lotstep;
	
			//-- close --------------------------------------------------------
			MqlTradeRequest request;
			MqlTradeResult result;
			::ZeroMemory(request);
			::ZeroMemory(result);
	
			request.action    = TRADE_ACTION_DEAL;
			request.price     = price;
			request.type      = (::PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY ;
			request.position  = ::PositionGetInteger(POSITION_TICKET);
			request.symbol    = symbol;
			request.volume    = lots;
			request.magic     = ::PositionGetInteger(POSITION_MAGIC);
			request.deviation = (ulong)slippage;
			request.comment   = "from #" + ::IntegerToString(ticket);
	
			// filling type
			if (CEBF_TRADES::IsFillingTypeAllowed(symbol, SYMBOL_FILLING_FOK))
				request.type_filling = ORDER_FILLING_FOK;
			else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, SYMBOL_FILLING_IOC))
				request.type_filling = ORDER_FILLING_IOC;
			else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, ORDER_FILLING_RETURN)) // just in case
				request.type_filling = ORDER_FILLING_RETURN;
	
			int success = ::OrderSend(request, result);
	
			//-- error check --------------------------------------------------
			if (!success || (result.retcode!=TRADE_RETCODE_DONE && result.retcode!=TRADE_RETCODE_PLACED && result.retcode!=TRADE_RETCODE_DONE_PARTIAL))
			{
				string errmsgpfx = "Closing trade error";
	
				int erraction = CEBF_TRADES::CheckForTradingError(result.retcode, errmsgpfx);
				switch(erraction)
				{
					case 0: break;    // no error
					case 1: continue; // overcomable error
					case 2: break;    // fatal error
				}
				return false;
			}
	
			//-- finish work --------------------------------------------------
			if (result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED || result.retcode == TRADE_RETCODE_DONE_PARTIAL)
			{
				//- closing: full
				if (lots0 == ::NormalizeDouble(result.volume, 5))
				{
					while (true)
					{
						if (!::PositionSelectByTicket(ticket)) {break;}
						::Sleep(10);
					}
				}
				//- closing: partial
				else if (lots0 > ::NormalizeDouble(result.volume, 5))
				{
					while (true)
					{
						if (::PositionSelectByTicket(ticket) && (lots0 != ::NormalizeDouble(PositionGetDouble(POSITION_VOLUME), 5))) {break;}
						::Sleep(10);
					}
				}
			}
	
			break;
		}
	
		::ResetLastError();
	
		return true;
	}
	
	static datetime OrderCloseTime()
	{
		if (CEBF_TRADES::LoadedType() == 1) return (datetime)::PositionGetInteger(POSITION_TIME);
		if (CEBF_TRADES::LoadedType() == 2) return (datetime)::OrderGetInteger(ORDER_TIME_DONE);
		if (CEBF_TRADES::LoadedType() == 3)
		{
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_OUT)
				{
					return (datetime)::HistoryDealGetInteger(ticket, DEAL_TIME);
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return (datetime)::HistoryOrderGetInteger(CEBF::OrderTicket(), ORDER_TIME_DONE);
	
		return 0;
	}
	
	static double OrderLots()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetDouble(POSITION_VOLUME);
		if (CEBF_TRADES::LoadedType() == 2) return ::OrderGetDouble(ORDER_VOLUME_CURRENT);
		if (CEBF_TRADES::LoadedType() == 3)
		{
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_OUT)
				{
					return ::HistoryDealGetDouble(ticket, DEAL_VOLUME);
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return ::HistoryOrderGetDouble(CEBF::OrderTicket(), ORDER_VOLUME_CURRENT);
	
		return 0.0;
	}
	
	static long OrderMagicNumber()
	{
		if (CEBF_TRADES::LoadedType() == 1) return (long)::PositionGetInteger(POSITION_MAGIC);
		if (CEBF_TRADES::LoadedType() == 2) return (long)::OrderGetInteger(ORDER_MAGIC);
		if (CEBF_TRADES::LoadedType() == 3) {
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_OUT)
				{
					return (long)::HistoryDealGetInteger(ticket, DEAL_MAGIC);
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return (long)::HistoryOrderGetInteger(CEBF::OrderTicket(), ORDER_MAGIC);
		
		return 0;
	}
	
	static bool OrderModify(long ticket, double price, double sl, double tp, datetime expiration, color arrow_color = clrNONE)
	{
		bool isTrade = true;
	
		string symbol = "";
		long magic    = 0;
	
		if (::PositionSelectByTicket(ticket))
		{
			symbol = ::PositionGetString(POSITION_SYMBOL);
		}
		else if (::OrderSelect(ticket))
		{
			isTrade = false;
	
			symbol = ::OrderGetString(ORDER_SYMBOL);
		}
		else
		{
			return false;
		}
	
		::ResetLastError();
	
		//-- pre-fixing ---------------------------------------------------
		int digits = (int)::SymbolInfoInteger(symbol, SYMBOL_DIGITS);
	
		sl = ::NormalizeDouble(sl, digits);
		tp = ::NormalizeDouble(tp, digits);
		price = ::NormalizeDouble(price, digits);
	
		while (true)
		{
			//-- close --------------------------------------------------------
			MqlTradeRequest request;
			MqlTradeResult result;
			::ZeroMemory(request);
			::ZeroMemory(result);
	
			if (isTrade)
			{
				if (
					   sl == ::NormalizeDouble(PositionGetDouble(POSITION_SL), digits)
					&& tp == ::NormalizeDouble(PositionGetDouble(POSITION_TP), digits)
				) {
					return true;
				}
	
				request.action   = TRADE_ACTION_SLTP;
				request.symbol   = symbol;
				request.position = ::PositionGetInteger(POSITION_TICKET);
				request.magic    = ::PositionGetInteger(POSITION_MAGIC);
				request.comment  = ::PositionGetString(POSITION_COMMENT);
			}
			else
			{
				//-- check if needed to modify ------------------------------------
				if (
					   price == ::NormalizeDouble(OrderGetDouble(ORDER_PRICE_OPEN), digits)
					&& sl == ::NormalizeDouble(OrderGetDouble(ORDER_SL), digits)
					&& tp == ::NormalizeDouble(OrderGetDouble(ORDER_TP), digits)
					&& expiration == ::OrderGetInteger(ORDER_TIME_EXPIRATION)
				) {
					return true;
				}
	
				request.action   = TRADE_ACTION_MODIFY;
				request.order    = ::OrderGetInteger(ORDER_TICKET);
				request.price    = price;
				request.volume   = ::OrderGetDouble(ORDER_VOLUME_CURRENT);
				request.magic    = ::OrderGetInteger(ORDER_MAGIC);
				request.type_time  = ORDER_TIME_SPECIFIED;
				request.expiration = expiration;
				request.comment    = ::OrderGetString(ORDER_COMMENT);
	
				//-- filling type
				uint filling=(uint)::SymbolInfoInteger(request.symbol,SYMBOL_FILLING_MODE);
				if (filling==SYMBOL_FILLING_FOK) {
					request.type_filling=ORDER_FILLING_FOK;
				}
				else if (filling==SYMBOL_FILLING_IOC) {
					request.type_filling=ORDER_FILLING_IOC;
				}
			}
	
			request.sl = sl;
			request.tp = tp;
		
			int success = ::OrderSend(request, result);
			
			//-- error check --------------------------------------------------
			if (!success || (result.retcode!=TRADE_RETCODE_DONE && result.retcode!=TRADE_RETCODE_PLACED && result.retcode!=TRADE_RETCODE_DONE_PARTIAL))
			{
				string errmsgpfx="Modify error";
				int erraction = CEBF_TRADES::CheckForTradingError(result.retcode, errmsgpfx);
				switch(erraction)
				{
					case 0: break;    // no error
					case 1: continue; // overcomable error
					case 2: break;    // fatal error
				}
				return false;
			}
			
			//-- finish work --------------------------------------------------
			if (result.retcode==TRADE_RETCODE_DONE || result.retcode==TRADE_RETCODE_PLACED || result.retcode==TRADE_RETCODE_DONE_PARTIAL)
			{
				while (true)
				{
					if (isTrade)
					{
						if (!::PositionSelectByTicket(ticket)) {break;}
					}
					else {
						if (!::OrderSelect(ticket)) {break;}
				  	}
					::Sleep(10);
				}
			}
			
			break;
		}
	
		::ResetLastError();
	
		return true;
	}
	
	static double OrderOpenPrice()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetDouble(POSITION_PRICE_OPEN);
		if (CEBF_TRADES::LoadedType() == 2) return ::OrderGetDouble(ORDER_PRICE_OPEN);
		if (CEBF_TRADES::LoadedType() == 3) {
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = 0; index < total; index++)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_IN)
				{
					return ::HistoryDealGetDouble(ticket, DEAL_PRICE); 
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return ::HistoryOrderGetDouble(CEBF::OrderTicket(), ORDER_PRICE_OPEN);
	
		return 0.0;
	}
	
	static double OrderProfit()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetDouble(POSITION_PROFIT);
		if (CEBF_TRADES::LoadedType() == 3)
		{
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_OUT)
				{
					return ::HistoryDealGetDouble(ticket, DEAL_PROFIT);
				}
			}
		}
	
		return 0.0;
	}
	
	static bool OrderSelect(long index, int select, int pool = 0)
	{
		// SELECT_BY_POS is 0, SELECT_BY_TICKET is 1. If any other value is used, it defaults to SELECT_BY_TICKET
		// MODE_TRADES is 0, MODE_HISTORY is 1
	
		if (pool < 0 || pool > 1) pool = 0;
		if (select != 0) select = 1;
	
		bool selected = false;
		int loadedTypeTrade = 1;
		int loadedTypeOrder = 2;
	
		CEBF::OrderTicket(0);
		CEBF_TRADES::LoadedType(0);
	
		// SELECT_BY_POS
		if (select == 0)
		{
			// MODE_TRADES (running trades + pending orders)
			int totalTrades = 0;
			int totalOrders = 0;
	
			if (pool == 1)
			{
				::HistorySelect(0, ::TimeCurrent() + 1);
				
				totalTrades = ::HistoryDealsTotal();
				totalOrders = ::HistoryOrdersTotal();
				
				loadedTypeTrade = 3;
				loadedTypeOrder = 4;
			}
			else
			{
				totalTrades = ::PositionsTotal();
				totalOrders = ::OrdersTotal();
				
				loadedTypeTrade = 1;
				loadedTypeOrder = 2;
			}
	
			if (totalTrades == 0 && totalOrders == 0)
			{
				// nothing to select
				CEBF::_LastError_(ERR_INVALID_PARAMETER);
			}
			else {
				// mixed trades and orders
				int total = ::MathMax(totalTrades, totalOrders);
				int tradeIndex = 0;
				int orderIndex = 0;
				int iterationIndex = 0;
	
				while (true)
				{
					ulong tradeTicket = 0;
					ulong orderTicket = 0;
	
					if (tradeIndex < totalTrades)
					{
						if (pool == 1) {
							tradeTicket = ::HistoryDealGetTicket(tradeIndex);
	
							if (
								(tradeTicket == 0) // something is wrong
								|| (::HistoryDealGetInteger(tradeTicket, DEAL_ENTRY) != DEAL_ENTRY_OUT) // not that kind of a deal
							) {
								tradeIndex++;
								continue;
							}
	
							// However, after the OUT deal was just found, the ticket needs to be the position's ID
							if (tradeTicket > 0)
							{
								tradeTicket = ::HistoryDealGetInteger(tradeTicket, DEAL_POSITION_ID);
							}
						}
						else {
							tradeTicket = ::PositionGetTicket(tradeIndex);
						}
					}
	
					if (orderIndex < totalOrders)
					{
						if (pool == 1) {
							orderTicket            = ::HistoryOrderGetTicket(orderIndex);
							ENUM_ORDER_STATE state = (ENUM_ORDER_STATE)::HistoryOrderGetInteger(orderTicket, ORDER_STATE);
	
							if (
								(orderTicket == 0) // something is wrong
								|| (state != ORDER_STATE_CANCELED && state != ORDER_STATE_EXPIRED) // not that kind of state
							) {
								orderIndex++;
								continue;
							}
						}
						else {
							orderTicket = ::OrderGetTicket(orderIndex);
						}
					}
	
					iterationIndex++;
	
					// finished checking
					if (tradeTicket == 0 && orderTicket == 0)
					{
						break;
					}
					else if (tradeTicket > 0 && orderTicket == 0)
					{
						tradeIndex++;
						
						if (iterationIndex > index)
						{
							CEBF::OrderTicket(tradeTicket);
							CEBF_TRADES::LoadedType(loadedTypeTrade);
							selected = true;
							
							break;
						}
					}
					else if (tradeTicket == 0 && orderTicket > 0)
					{
						orderIndex++;
						
						if (iterationIndex > index)
						{
							CEBF::OrderTicket(orderTicket);
							CEBF_TRADES::LoadedType(loadedTypeOrder);
							selected = true;
							
							break;
						}
					}
					else if (tradeTicket <= orderTicket)
					{
						tradeIndex++;
						
						if (iterationIndex > index)
						{
							CEBF::OrderTicket(tradeTicket);
							CEBF_TRADES::LoadedType(loadedTypeTrade);
							selected = true;
							
							break;
						}
					}
					else if (tradeTicket > orderTicket)
					{
						orderIndex++;
						
						if (iterationIndex > index)
						{
							CEBF::OrderTicket(orderTicket);
							CEBF_TRADES::LoadedType(loadedTypeOrder);
							selected = true;
							
							break;
						}
					}
				}
			}
		}
		// SELECT_BY_TICKET
		else {
			long ticket = index;
	
			// Select whatever has the ticket here, the pool doesn't matter
			if (::PositionSelectByTicket(ticket))
			{
				CEBF::OrderTicket(::PositionGetInteger(POSITION_IDENTIFIER));
				CEBF_TRADES::LoadedType(1);
				selected = true;
			}
			else if (::OrderSelect(ticket))
			{
				CEBF::OrderTicket(ticket);
				CEBF_TRADES::LoadedType(2);
				selected = true;
			}
			else
			{
				::HistorySelect(0, ::TimeCurrent() + 1);
				long posID = ::HistoryDealGetInteger(ticket, DEAL_POSITION_ID);
	
				if (posID)
				{
					CEBF::OrderTicket(posID);
					CEBF_TRADES::LoadedType(3);
					selected = true;
				}
	
				if (selected == false)
				{
					long orderTicket = ::HistoryOrderGetInteger(ticket, ORDER_TICKET);
					
					if (orderTicket)
					{
						CEBF::OrderTicket(ticket);
						CEBF_TRADES::LoadedType(4);
						selected = true;
					}
				}
			}
		}
	
		if (selected) ::ResetLastError();
		
		return selected;
	}
	
	static int OrderSend(
		string   symbol,              // symbol 
		int      cmd,                 // operation 
		double   volume,              // volume 
		double   price,               // price 
		int      slippage,            // slippage 
		double   sl,                  // stop loss 
		double   tp,                  // take profit 
		string   comment=NULL,        // comment 
		long      magic=0,             // magic number 
		datetime expiration=0,        // pending order expiration 
		color    arrow_color=clrNONE  // color
		)
	{
		int type                       = cmd;
		ulong ticket                   = -1;
		bool successed                 = false;
		bool isPendingOrder            = (cmd > 1);
		ENUM_ORDER_TYPE_TIME type_time = ORDER_TIME_GTC;
	
		symbol = (symbol == NULL || symbol == "") ? ::Symbol() : symbol;
	
		if (isPendingOrder)
		{
			if (expiration <= 0)
			{
				expiration = 0;
	
				if (CEBF_TRADES::IsExpirationTypeAllowed(symbol, SYMBOL_EXPIRATION_GTC))
					type_time = ORDER_TIME_GTC;
				else
					type_time = ORDER_TIME_DAY;
			}
			else {
				type_time = ORDER_TIME_SPECIFIED;
			}
		}
		else {
			expiration = 0;
		}
	
		//-- we need this to prevent false-synchronous behaviour of MQL5 -----
		bool closing = false;
		double lots0 = 0;
		long type0   = type;
	
		if (
			   (::AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
			&& (type == POSITION_TYPE_BUY || type == POSITION_TYPE_SELL)
		) {
			if (::PositionSelect(symbol))
			{
				if ((int)::PositionGetInteger(POSITION_TYPE) != type)
				{
					closing = true;
				}
	
				lots0 = ::NormalizeDouble(PositionGetDouble(POSITION_VOLUME), 5);
				type0 = ::PositionGetInteger(POSITION_TYPE);
			}
		}
	
		while (true)
		{
			// fixing
			int digits     = (int)::SymbolInfoInteger(symbol, SYMBOL_DIGITS);
			double ask     = ::SymbolInfoDouble(symbol, SYMBOL_ASK);
			double bid     = ::SymbolInfoDouble(symbol, SYMBOL_BID);
			double lotstep = ::SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
	
			sl     = ::NormalizeDouble(sl, digits);
			tp     = ::NormalizeDouble(tp, digits);
			price  = ::NormalizeDouble(price, digits);
			volume = ::MathFloor(volume/lotstep) * lotstep; // MQL4's OrderSend rounds to floor
	
			// MQL4 gives error 130 and doesn't make pending order when outside of the requirements listed here: https://book.mql4.com/appendix/limits
			// MQL5 seems to don't have such and instead it would make a pending order or a trade. That's why these checks are needed here.
			if (isPendingOrder)
			{
				if (
					(type == ORDER_TYPE_BUY_LIMIT && price >= ask)
					|| (type == ORDER_TYPE_SELL_LIMIT && price <= bid)
					|| (type == ORDER_TYPE_BUY_STOP && price <= ask)
					|| (type == ORDER_TYPE_SELL_STOP && price >= bid)
				) {
					CEBF::_LastError_(TRADE_RETCODE_INVALID_STOPS);
	
					return -1;
				}
			}
	
			// Give error 130 when the stops are wrong right away
			if (
				   ((type == POSITION_TYPE_BUY || type == ORDER_TYPE_BUY_LIMIT || type == ORDER_TYPE_BUY_STOP) && ((sl > 0 && sl >= price) || (tp > 0 && tp <= price)))
				|| ((type == POSITION_TYPE_SELL || type == ORDER_TYPE_SELL_LIMIT || type == ORDER_TYPE_SELL_STOP) && ((sl > 0 && sl <= price) || (tp > 0 && tp >= price)))
			) {
					CEBF::_LastError_(TRADE_RETCODE_INVALID_STOPS);
					return -1;
			}
	
			// send
			MqlTradeRequest request;
			MqlTradeResult result;
			MqlTradeCheckResult check_result;
			::ZeroMemory(request);
			::ZeroMemory(result);
			::ZeroMemory(check_result);
	
			request.action     = (type < 2) ? TRADE_ACTION_DEAL : TRADE_ACTION_PENDING;
			request.symbol     = symbol;
			request.volume     = volume;
			request.type       = (ENUM_ORDER_TYPE)type;
			request.price      = price;
			request.deviation  = slippage;
			request.sl         = sl;
			request.tp         = tp;
			request.comment    = comment;
			request.magic      = magic;
			request.type_time  = type_time;
			request.expiration = expiration;
	
			//-- filling type
			if (isPendingOrder)
			{
				if (CEBF_TRADES::IsFillingTypeAllowed(symbol, ORDER_FILLING_RETURN))
					request.type_filling = ORDER_FILLING_RETURN;
				else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, ORDER_FILLING_FOK))
					request.type_filling = ORDER_FILLING_FOK;
				else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, ORDER_FILLING_IOC))
					request.type_filling = ORDER_FILLING_IOC;
			}
			else
			{
				// in case of positions I would check for SYMBOL_FILLING_ and then set ORDER_FILLING_
				// this is because it appears that CEBF_TRADES::IsFillingTypeAllowed() works correct with SYMBOL_FILLING_, but then the position works correctly with ORDER_FILLING_
				// FOK and IOC integer values are not the same for ORDER and SYMBOL
	
				if (CEBF_TRADES::IsFillingTypeAllowed(symbol, SYMBOL_FILLING_FOK))
					request.type_filling = ORDER_FILLING_FOK;
				else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, SYMBOL_FILLING_IOC))
					request.type_filling = ORDER_FILLING_IOC;
				else if (CEBF_TRADES::IsFillingTypeAllowed(symbol, ORDER_FILLING_RETURN)) // just in case
					request.type_filling = ORDER_FILLING_RETURN;
			}
	
			bool success = ::OrderSend(request, result);
	
			//-- check security flag ------------------------------------------
			if (successed == true)
			{
				::Print("The program will be removed because of suspicious attempt to create new positions");
				::ExpertRemove();
				::Sleep(10000);
	
				break;
			}
	
			if (success) {successed = true;}
	
			//-- error check --------------------------------------------------
			if (
				   success == false
				|| (
					   result.retcode != TRADE_RETCODE_DONE
					&& result.retcode != TRADE_RETCODE_PLACED
					&& result.retcode != TRADE_RETCODE_DONE_PARTIAL
				)
			)
			{
				string errmsgpfx = (type > ORDER_TYPE_SELL) ? "New pending order error" : "New position error";
	
				int erraction = CEBF_TRADES::CheckForTradingError(result.retcode, errmsgpfx);
	
				switch (erraction)
				{
					case 0: break;    // no error
					case 1: continue; // overcomable error
					case 2: break;    // fatal error
				}
	
				// MQL5 does not put the trading error into GetLastError, but I need it for later use in GetLastError
				CEBF::_LastError_(result.retcode);
	
				return -1;
			}
	
			//-- finish work --------------------------------------------------
			if (
				   result.retcode==TRADE_RETCODE_DONE
				|| result.retcode==TRADE_RETCODE_PLACED
				|| result.retcode==TRADE_RETCODE_DONE_PARTIAL
			) {
				ticket = result.order;
				//== Whatever was created, we need to wait until MT5 updates it's cache
	
				//-- Synchronize: Position
				if (type <= ORDER_TYPE_SELL)
				{
					if (::AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_NETTING)
					{
						if (closing == false)
						{
							//- new position: 2 situations here - new position or add to position
							//- ... because of that we will check the lot size instead of PositionSelect
							while (true)
							{
								if (::PositionSelect(symbol) && (lots0 != ::NormalizeDouble(PositionGetDouble(POSITION_VOLUME), 5))) {break;}
								Sleep(10);
							}
						}
						else
						{
							//- closing position: full
							if (lots0 == ::NormalizeDouble(result.volume, 5))
							{
								while (true)
								{
									if (!::PositionSelect(symbol)) {break;}
									::Sleep(10);
								}
							}
							//- closing position: partial
							else if (lots0 > ::NormalizeDouble(result.volume, 5))
							{
								while (true)
								{
									if (::PositionSelect(symbol) && (lots0 != ::NormalizeDouble(PositionGetDouble(POSITION_VOLUME), 5))) {break;}
									::Sleep(10);
								}
							}
							else if (lots0 < ::NormalizeDouble(result.volume, 5))
							{
							//-- position reverse
								while (true)
								{
									if (::PositionSelect(symbol) && (type0 != ::PositionGetInteger(POSITION_TYPE))) {break;}
									::Sleep(10);
								}
							}
						}
					}
					else if (::AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
					{
						if (closing == false)
						{
							while (true)
							{
								if (::PositionSelectByTicket(ticket)) {break;}
								::Sleep(10);
							}
						}
					}
				}
				//-- Synchronize: Order
				else
				{
					while (true)
					{
						if (CEBF_TRADES::LoadPendingOrder(result.order)) {break;}
						::Sleep(10);
					}
				}
			}
	
			break;
		}
	
		if (ticket > 0) {
			// In MQL4 OrderSend() selects the order
			int loadedType = (isPendingOrder) ? 2 : 1; // 1 for trade, 2 for pending order
			CEBF::OrderTicket(ticket);
			CEBF_TRADES::LoadedType(loadedType);
			::ResetLastError();
		}
	
		return (int)ticket;
	}
	
	static double OrderStopLoss()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetDouble(POSITION_SL);
		if (CEBF_TRADES::LoadedType() == 2) return ::OrderGetDouble(ORDER_SL);
		if (CEBF_TRADES::LoadedType() == 3) {
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_IN)
				{
					ulong orderTicket = ::HistoryDealGetInteger(ticket, DEAL_ORDER);
					return ::HistoryOrderGetDouble(orderTicket, ORDER_SL); 
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return ::HistoryOrderGetDouble(CEBF::OrderTicket(), ORDER_SL);
		
		return 0.0;
	}
	
	static string OrderSymbol()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetString(POSITION_SYMBOL);
		if (CEBF_TRADES::LoadedType() == 2) return ::OrderGetString(ORDER_SYMBOL);
		if (CEBF_TRADES::LoadedType() == 3)
		{
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
			
			for (int index = 0; index < total; index++)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_IN)
				{
					return ::HistoryDealGetString(ticket, DEAL_SYMBOL); 
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return ::HistoryOrderGetString(CEBF::OrderTicket(), ORDER_SYMBOL);
		
		return _Symbol;
	}
	
	static double OrderTakeProfit()
	{
		if (CEBF_TRADES::LoadedType() == 1) return ::PositionGetDouble(POSITION_TP);
		if (CEBF_TRADES::LoadedType() == 2) return ::OrderGetDouble(ORDER_TP);
		if (CEBF_TRADES::LoadedType() == 3) {
			::HistorySelectByPosition(CEBF::OrderTicket());
			int total = ::HistoryDealsTotal();
	
			for (int index = total -1; index >= 0; index--)
			{
				ulong ticket = ::HistoryDealGetTicket(index);
				ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY);
	
				if (entry == DEAL_ENTRY_IN)
				{
					ulong orderTicket = ::HistoryDealGetInteger(ticket, DEAL_ORDER);
					return ::HistoryOrderGetDouble(orderTicket, ORDER_TP); 
				}
			}
		}
		if (CEBF_TRADES::LoadedType() == 4) return ::HistoryOrderGetDouble(CEBF::OrderTicket(), ORDER_TP);
		
		return 0.0;
	}
	
	static int OrderTicket(long ticket = 0)
	{
		static int memory = 0;
	
		if (ticket > 0) {memory = (int)ticket;}
	
		return memory;
	}
	
	static int OrderType()
	{
		if (CEBF_TRADES::LoadedType() == 1) return (int)::PositionGetInteger(POSITION_TYPE);
		if (CEBF_TRADES::LoadedType() == 2) return (int)::OrderGetInteger(ORDER_TYPE);
		if (CEBF_TRADES::LoadedType() == 3) return (int)::HistoryDealGetInteger(CEBF::OrderTicket(), DEAL_TYPE);
		if (CEBF_TRADES::LoadedType() == 4) return (int)::HistoryOrderGetInteger(CEBF::OrderTicket(), ORDER_TYPE);
		
		return 0; // MQL4 returns 0 if there is nothing loaded
	}
	
	static int OrdersHistoryTotal()
	{
		int total = 0;
	
		::HistorySelect(0, ::TimeCurrent() + 1);
	
		int totalDeals  = ::HistoryDealsTotal();
		int totalOrders = ::HistoryOrdersTotal();
	
		for (int index = 0; index < totalDeals; index++)
		{
			ulong ticket = ::HistoryDealGetTicket(index);
			
			if (ticket == 0) continue;
	
			if (::HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT) total++;
		}
	
		for (int index = 0; index < totalOrders; index++)
		{
			ulong ticket = ::HistoryOrderGetTicket(index);
	
			if (ticket == 0) continue;
	
			ENUM_ORDER_STATE state = (ENUM_ORDER_STATE)::HistoryOrderGetInteger(ticket, ORDER_STATE);
	
			if (state == ORDER_STATE_CANCELED || state == ORDER_STATE_EXPIRED) total++;
		}
	
		return total;
	}
	
	static int OrdersTotal()
	{
		return ::PositionsTotal() + ::OrdersTotal();
	}
	
	/**
	* Refresh the data in the predefined variables and series arrays
	* In MQL5 this function should run on every tick or calculate
	*
	* Note that when Symbol or Timeframe is changed,
	* the global arrays (Ask, Bid...) are reset to size 0,
	* and also the static variables are reset to initial values.
	*/
	static bool RefreshRates()
	{
		static bool initialized = false;
		static double prevAsk   = 0.0;
		static double prevBid   = 0.0;
		static int prevBars     = 0;
		static MqlRates ratesArray[1];
	
		bool isDataUpdated = false;
	
		if (initialized == false)
		{
			::ArraySetAsSeries(::Close, true);
			::ArraySetAsSeries(::High, true);
			::ArraySetAsSeries(::Low, true);
			::ArraySetAsSeries(::Open, true);
			::ArraySetAsSeries(::Volume, true);
	
			initialized = true;
		}
	
		// For Bars below, if the symbol parameter is provided through a string variable, the function returns 0 immediately when the terminal is started
		::Bars = ::Bars(::_Symbol, PERIOD_CURRENT);
		::Ask  = ::SymbolInfoDouble(::_Symbol, SYMBOL_ASK);
		::Bid  = ::SymbolInfoDouble(::_Symbol, SYMBOL_BID);
	
		if ((::Bars > 0) && (::Bars > prevBars))
		{
			// Tried to resize these arrays below on every successful single result, but turns out that this is veeeery slow
			::ArrayResize(::Time, ::Bars);
			::ArrayResize(::Open, ::Bars);
			::ArrayResize(::High, ::Bars);
			::ArrayResize(::Low, ::Bars);
			::ArrayResize(::Close, ::Bars);
			::ArrayResize(::Volume, ::Bars);
	
			// Fill the missing data
			for (int i = prevBars; i < ::Bars; i++)
			{
				int success = ::CopyRates(::_Symbol, PERIOD_CURRENT, i, 1, ratesArray);
	
				if (success == 1)
				{
					::Time[i]   = ratesArray[0].time;
					::Open[i]   = ratesArray[0].open;
					::High[i]   = ratesArray[0].high;
					::Low[i]    = ratesArray[0].low;
					::Close[i]  = ratesArray[0].close;
					::Volume[i] = ratesArray[0].tick_volume;
				}
			}
		}
		else
		{
			// Update the current bar only
			int success = ::CopyRates(::_Symbol, PERIOD_CURRENT, 0, 1, ratesArray);
	
			if (success == 1)
			{
				::Time[0]   = ratesArray[0].time;
				::Open[0]   = ratesArray[0].open;
				::High[0]   = ratesArray[0].high;
				::Low[0]    = ratesArray[0].low;
				::Close[0]  = ratesArray[0].close;
				::Volume[0] = ratesArray[0].tick_volume;
			}
		}
	
		if (::Bars != prevBars || ::Ask != prevAsk || ::Bid != prevBid)
		{
			isDataUpdated = true;
		}
	
		prevBars = ::Bars;
		prevAsk  = ::Ask;
		prevBid  = ::Bid;
	
		return isDataUpdated;
	}
	
	/**
	* In MQL4 the values are the number of minutes in the period
	* In MQL5 the values are the minutes up to M30, then it's the number of seconds in the period
	* This function converts all values that exist in MQL4, but not in MQL5
	* There are no conflict values otherwise
	*/
	static ENUM_TIMEFRAMES _ConvertTimeframe_(int timeframe)
	{
		switch (timeframe)
		{
			case 60    : return PERIOD_H1;
			case 120   : return PERIOD_H2;
			case 180   : return PERIOD_H3;
			case 240   : return PERIOD_H4;
			case 360   : return PERIOD_H6;
			case 480   : return PERIOD_H8;
			case 720   : return PERIOD_H12;
			case 1440  : return PERIOD_D1;
			case 10080 : return PERIOD_W1;
			case 43200 : return PERIOD_MN1;
		}
	
		return (ENUM_TIMEFRAMES)timeframe;
	}
	static ENUM_TIMEFRAMES _ConvertTimeframe_(ENUM_TIMEFRAMES timeframe)
	{
		return timeframe;
	}
	
	/**
	* Getter
	*/
	static int _LastError_()
	{
		return _LastError;
	}
	/**
	* Setter
	*/
	static void _LastError_(int error)
	{
		_LastError = error;
	}
	
	/**
	* Overload for the case when numeric value is used for timeframe
	*/
	static datetime iTime(const string symbol, int timeframe, int shift)
	{
		return ::iTime(symbol, CEBF::_ConvertTimeframe_(timeframe), shift);
	}
};
int CEBF::_LastError = -1;

class CEBF_TRADES
{
public:
	/**
	* Constructor
	*/
	CEBF_TRADES() {};
	
		static int CheckForTradingError(int error_code = -1, string msg_prefix = "")
		{
			// return 0 -> no error
			// return 1 -> overcomable error
			// return 2 -> fatal error
	
			static int tryout = 0;
			int tryouts = 5;   // How many times to retry
			int delay   = 1000; // Time delay between retries, in milliseconds
			int retval  = 0;
	
			//-- error check -----------------------------------------------------
			switch(error_code)
			{
				//-- no error
				case 0:
					retval = 0;
					break;
				//-- overcomable errors
				case TRADE_RETCODE_REQUOTE:
				case TRADE_RETCODE_REJECT:
				case TRADE_RETCODE_ERROR:
				case TRADE_RETCODE_TIMEOUT:
				case TRADE_RETCODE_INVALID_VOLUME:
				case TRADE_RETCODE_INVALID_PRICE:
				case TRADE_RETCODE_INVALID_STOPS:
				case TRADE_RETCODE_INVALID_EXPIRATION:
				case TRADE_RETCODE_PRICE_CHANGED:
				case TRADE_RETCODE_PRICE_OFF:
				case TRADE_RETCODE_TOO_MANY_REQUESTS:
				case TRADE_RETCODE_NO_CHANGES:
				case TRADE_RETCODE_CONNECTION:
					retval = 1;
					break;
				//-- critical errors
				default:
					retval = 2;
					break;
			}
	
			if (error_code > 0)
			{
				if (retval == 1)
				{
					Print(msg_prefix,": ",(error_code),". Retrying in ",(delay)," milliseconds..");
					Sleep(delay); 
				}
				else if (retval == 2)
				{
					Print(msg_prefix,": ",(error_code));
				}
			}
	
			if (retval == 0)
			{
				tryout = 0;
			}
			else if (retval == 1)
			{
				tryout++;
	
				if (tryout > tryouts)
				{
					tryout = 0;
					retval  = 2;
				}
				else
				{
					Print("retry #", tryout, " of ", tryouts);
				}
			}
	
			return retval;
		}
	
		static bool IsExpirationTypeAllowed(string symbol, int exp_type)
		{
			int expiration = (int)SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_MODE);
			return ((expiration&exp_type) == exp_type);
		}
	
		static bool IsFillingTypeAllowed(string symbol,int fill_type)
		{
			int filling=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE);
			return((filling & fill_type)==fill_type);
		}
	
	static bool LoadPendingOrder(long ticket)
	{
		bool success = false;
	
	   if (::OrderSelect(ticket))
		{
			// The order could be from any type, so check the type
			// and allow only true pending orders.
			ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)::OrderGetInteger(ORDER_TYPE);
	
			if (
				   type == ORDER_TYPE_BUY_LIMIT
				|| type == ORDER_TYPE_SELL_LIMIT
				|| type == ORDER_TYPE_BUY_STOP
				|| type == ORDER_TYPE_SELL_STOP
			) {
				CEBF_TRADES::LoadedType(2);
				CEBF::OrderTicket(ticket);
				success = true;
			}
		}
	
	   return success;
	}
	
	static int LoadedType(int type = 0)
	{
		// 1 - position
		// 2 - pending order
		// 3 - history position
		// 4 - history pending order
	
		static int memory;
	
		if (type > 0) {memory = type;}
	
		return memory;
	}
};
bool ___RefreshRates___ = CEBF::RefreshRates();

//== fxDreema MQL4 to MQL5 Converter ==//