MQL4 Script To Close All Trades

Forex trading needs to be fun, exciting emotionally and stress free as well as finanacial rewarding. If forex trading makes you stressed and emotionally drained, you have a wrong trading strategy that you are trading. You need a trading strategy that is rule based, easy to execute and emotionally stress free. You trading strategy should give you consistent results. You should be able to find the market direction on any timeframe anytime. Then you need an entry strategy that works right from when you enter the trade in your favor. Becoming a successful currency trading is a dream for millions of people around the world who want to achieve financial freedom. DId you read the post on USDJPY sell trade that made 160 pips with 16 pip stop loss?

MQL4 Script

One method that you can use to make your trading strategy less emotionally draining and more stress free is to use automation. You can automate certain things in your trading strategy. Suppose you have multiple trades open on MT4. You want to close all the open trades at once. One method is to close the open trades one by one manually with the risk of losing a percentage of the profit due to price moving fast. A better method is to code a script in MQL4 that will close all the open trades at once. Read the post on how to code custom indicator in MQL4.

What Is An MQL4 Script?

If you know coding, you know what is  script. But in MQL4, script has a specified meaning. An MQL4 script is a simplified expert advisor that performs a single task like placing a pending order or closing orders. We can customize the MQL4 script and tell it to close open trades for only a specific currency pair and more stuff like that. When you are trading, this Close Orders MQL4 script will be very handy and save you a  lot of trouble. It is always a good idea to learn some coding in MQL4 if you are trading on MT4. MT4 is a popular forex trading platform with many brokers. Just keep this in mind. MT4 is single threaded. If you wanted multi threading, you should take a look at MT5 which was introduced by the Meta Quotes Corporation a few years later to overcome the short comings of MT4. But this did not reduce the popularity of MT4. It is still more popular than MT5. I am writing this post for education. Did you take a look at my MQL4 coding course?

Learning MQL4 is a Good Idea

When you download the Close Orders MQL4 script, you can also learn some MQL4 while reading this post. Learning MQL4 will help you write your own expert advisors also known in popular jargon as forex robots. This is my piece of advice. Forex robots generally don’t work. Automated a trading strategy is easy conceptually but when you do automated trading, you will find that your account will suffer heavy drawdowns. So don’t expect miracles with automated trading. Your MQL4 coding knowledge can help you automate stuff like closing trades with one click, scaling into a position and stuff like that. You can even code an expert advisor that can add positions when the price is moving fast. These type of expert advisors are selling for $49-$99. You can code them yourself. Let’s start and learn some MQL4.

//+------------------------------------------------------------------+
//|                                                 Close Orders.mq4 |
//|                                                     Andrew Young |
//|                                 http://www.expertadvisorbook.com |
//+------------------------------------------------------------------+

#property copyright   "Andrew Young"     //A
#property link        "http://www.expertadvisorbook.com" //A
#property description "Close all orders of the specified type for the specified symbol." //A

/*
Creative Commons Attribution-NonCommercial 3.0 Unported
http://creativecommons.org/licenses/by-nc/3.0/

You may use this file in your own personal projects. You
may modify it if necessary. You may even share it, provided
the copyright above is present. No commercial use permitted. 
*/


#property script_show_inputs   //A

#include <Mql4Book\Trade.mqh>  //B
CTrade Trade;                  //C

enum CloseTypes                                  //D
{
	All,		// All Orders            //D
	Market,		// Market Orders         //D
	Pending,	// Pending Orders        //D
	Buy,		// Buy Market            //D
	Sell,		// Sell Market           //D
	BuyStop,	// Buy Stop              //D
	SellStop,	// Sell Stop             //D
	BuyLimit,	// Buy Limit             //D
	SellLimit,	// Sell Limit            //D
};

input CloseTypes CloseType = All;               //E
input string CloseSymbol = "";                  //E


void OnStart()
{
	for(int i = 0; i <= OrdersTotal() - 1; i++) { 
          // Select order 
            bool result = OrderSelect(i,SELECT_BY_POS); //F
            if(result == true) 
            { 
                 string orderSymbol = OrderSymbol();    //G
                 string closeSymbol = StringTrimRight(CloseSymbol);  //H
                 if(closeSymbol != "" && closeSymbol != orderSymbol) continue; //G
                 int orderType = OrderType(); 
                 int orderTicket = OrderTicket(); 
                 bool closeOrder = false; 
                 switch(CloseType) 
                 { 

                        case All: 
                             closeOrder = true; 
                             break; 

                        case Market: 
                             if(orderType == OP_BUY || orderType == OP_SELL) closeOrder = true; 
                             break; 

                        case Pending: 
                             if(orderType >= 2) closeOrder = true;		
			     break;
					
		        case Buy:
			     if(orderType == OP_BUY) closeOrder = true;
			     break;
					
			case Sell:
			      if(orderType == OP_SELL) closeOrder = true;
			      break;
					
			case BuyStop:
			      if(orderType == OP_BUYSTOP) closeOrder = true;
			      break;
				
			case SellStop:
			      if(orderType == OP_SELLSTOP) closeOrder = true;
			      break;
					
			case BuyLimit:
			      if(orderType == OP_BUYLIMIT) closeOrder = true;
			      break;
					
			case SellLimit:
			      if(orderType == OP_SELLLIMIT) closeOrder = true;
			      break;
			}
			
			if(closeOrder == true)
			{
				bool closed = false;
				
				if(orderType == OP_BUY || orderType == OP_SELL)
				{
					closed = Trade.CloseMarketOrder(orderTicket,0,clrNONE);
				}
				else
				{
					closed = Trade.DeletePendingOrder(orderTicket,clrNONE);
				}
				
				if(closed == true) i--;
			}
		}
	}
}

As you can see above. this Close Orders MQL4 script has been developed by Andrews Young. I was reading his book on MQL4 programming and copied it from his book. In the Close Orders MQL4 script you can see Andrew Young has given permission to share the script provided we include his copyright claim. So for the benefit of my Forex Robot 2.0 Blog readers, I am sharing this Close Orders MQL4 script. I will also explain the code in the script so that if you are new to MQL4 you can learn MQL4 also when you download this script. Learn how to invest in cryptocurrencies.

What Are Preprocessor Directives?

Preprocessor directives are the first thing you notice in the above code. Preprocessor directive is proceeded with a # sign. Now #property copyright is a preprocessor directive that informs you of the copyright owner of the code. The second #property link gives the website address of the author of this code. This is a good practice to use these two property directives and tell the user of the code that you own the code and whether you give the user permission to use the code or not. The property directives are marked A in the above code.are the property directives. The #propert description directive gives a brief text decscription of the MQL4 program After that we have the #property script_show_input directive. This #property script_show_input ensures that a window showing the properties above is always shown before the script is run.

It is always a good idea to use comments judiciously in your code. Comments help you later in future when you again look your code that you had written months or years back. Comments tell you what you wanted to do with your code below the comment. In MQL4, a comment line starts with //. If you want multiple lines in a comment you should enclose the comment in /* ….comment spanning multiple lines…*/.You can see in the above code multiple line comment where Andrew Young gives copyright information and the permission to share the code with others but forbids commercial use of the code.

We can also use #property version directive if we plan to update the code in the future. There is another preprocessor directive used in the code below that is #property strict that tells the compiler for strict complation mode. There are many preprocessor directives provided in MQL4 Reference. Comment B gives the #include preprocessor directive #include <Mql4Book\Trade.mqh>. This #include preprocessor directive tells the compiler to include the functions and class definitions in the flie provided in include folder file Mql4Book\Trade.mqh. This #include preprocessor directive makes the code of the main program look simple and more elegant as we have define all the functions and classes in the include file which is in a separate folder.

Object Oriented Programming in MQL4

MQL4 allows use to define your own classes just like in C++. Object Oriented Programming is a paradym that makes your code more robust and reusable. You define a class once and then you can use it repeated in many programs. This helps especially when you are coding a very complex program. You divide your complex program into parts  and code each part separately as objects which can interact with each other. Before comment C, you declare a Trade object from class CTrade which has been defined in the Trade.mqh file. We discuss the CTrade class below when we discuss the Trade.mqh file. Now Trade.mqh is the work done by Andrew Young. All modern programming languages like C++, JAVA, C#, Python and R are object oriented languages. MQL5 is an object oriented programming language. MQL4 is an object oriented programming language as an after thought. MT4 was the first trading software developed by Meta Quotes corporation. As it was there first attempt you will find many short comings in MT4 like it is single threaded. Later on with experience they developed the next trading software MT5 which is more powerful and has object oriented programming inbuilt into it from the very start. MT5 is also multithreaded and much faster than MT4.  But still brokers love MT4.

What is an ENUM Enumeration?

ENUM is just the names of integer constants. ENUM short for Enumeration is  a special integer type that defines a list of constants representing integer values. ENUM is used in almost all modern languages that includes C/C++/JAVA/C#/Python etc. MQL4 also has ENUM. You can see the ENUM in the above code in D where we define the enum CloseTypes that includes All, Market, Pending, Buy,Sell, BuyStop, SellStop, BuyLimit and SellLimit. All will have a value of 0, Market will have the integer value of 1, Pending will have the integer value of 2, Buy 3, Sell 4, BuyStop 5, SellStop 6, BuyLimit 7 and SellLimit 8. Learn how to code Donchian Channel. Close All Trades script can close market, stop and limit orders. When we create an enumeration, the name of the enumeration becomes a data type just like double and int. Enumerations provide a set of values that we choose from just like the CloseType enumeration. |There are a number of predefined enumerations in both MQL4 and MQL5.

What is Input Variable?

Input variable is the external variable defined by the user like you and me. Input variables are the only variables that can be changed by the user. An imput variable always is proceeded with the keyword input. In the above code before comment E, you can see the input variables CloseType that has been defined be defaut as All. When you run the Close All Trades script, the CloseType by default is all and the CloseSymbol is blank so the script will automatically close all open orders. If you change the CloseType on the properties window that appears when you first run the script to say Buy, it will close all the open buy orders. If in addition, you specify the CloseSymbol as EURUSD, Close All Trades script will only close all open EURUSD buy orders. So you see we have a pretty flexiable MQL4 script that first asks you what type of order to close when you click on it. If you don’t specify anything, it will close all orders on all symbols by default. In short the input variables specify the input parameters of the script and are availble on the Properties Window when you first run the script. Learn how to calculate Keltner Channels.

What is OnStart()?

OnStart() is in an MQL4 inbuilt function that is invoked when the script is run first time. Once the conditions in the script code are fullfilled the OnStart() function execute them and then the script is done and no more work is required. OnStart() is where the code for the script is run after initialization. in OnStart() we start off with a for statement that checks for the number of orders open with the OrdersTotal() predefined function. SELECT_BY_POSITION is an enum. OrderSelect() is a predefined MQL function. We use i as an index and and iterate over the order pool. We use an if statement to check if we have an open position.

What is a Switch Statement?

A switch statement compares an expression to a list of constants like the ones in an ENUM using a case operator. When there is a match, the swtich expression is executed. First we define the variable closeOrder as false. Then we use a Swtich statement to check for the order types that we had defined in the enum closeTypes. We check for each order type in the switch statement and then use that information to close the order types using a CTrade class that is defined in Trade.mqh file. OrderType() is a predefined function that returns the order type of the currently selected order. Defining the CTrade class makes the code elegent and sleak. We can use an if else statement instead of a switch statement. Using a switch statement makes the code more elegant, concise and precise.If  the expression in the switch statement matches, we use a break statement to get out of the loop. We also use a continue statement in case

What Is MQH File?

Below is the Trade.mqh file. Files with .mqh are include files that include user created functions and classes that you can reference in your main .mq4 file. Using an include file can help in making your code organized. Instead of littering the main .mq4 file with all the functions and class definitions you can do that in the .mqh file.

//+------------------------------------------------------------------+
//|                                                        Trade.mqh |
//|                                                  Andrew R. Young |
//|                                 http://www.expertadvisorbook.com |
//+------------------------------------------------------------------+

#property copyright   "Andrew R. Young"
#property link        "http://www.expertadvisorbook.com"
#property description "Trading classes and functions"
#property strict


/*
 Creative Commons Attribution-NonCommercial 3.0 Unported
 http://creativecommons.org/licenses/by-nc/3.0/

 You may use this file in your own personal projects. You may 
 modify it if necessary. You may even share it, provided the 
 copyright above is present. No commercial use is permitted! 
*/


#include <stdlib.mqh>

#define MAX_RETRIES 3		// Max retries on error
#define RETRY_DELAY 3000	// Retry delay in ms


//+------------------------------------------------------------------+
//| Trading class                                                    |
//+------------------------------------------------------------------+

class CTrade
{
   private:
      static int _magicNumber;
      static int _slippage;
      
      enum CLOSE_MARKET_TYPE
      {
         CLOSE_BUY,
         CLOSE_SELL,
         CLOSE_ALL_MARKET
      };
      
      enum CLOSE_PENDING_TYPE
      {
         CLOSE_BUY_LIMIT,
         CLOSE_SELL_LIMIT,
         CLOSE_BUY_STOP,
         CLOSE_SELL_STOP,
         CLOSE_ALL_PENDING
      };
      
      int OpenMarketOrder(string pSymbol, int pType, double pVolume, string pComment, color pArrow);
      int OpenPendingOrder(string pSymbol, int pType, double pVolume, 
double pPrice, double pStop, double pProfit, string pComment, datetime pExpiration, color pArrow);
      
      bool CloseMultipleOrders(CLOSE_MARKET_TYPE pCloseType);
      bool DeleteMultipleOrders(CLOSE_PENDING_TYPE pDeleteType);

   
   public:
      int OpenBuyOrder(string pSymbol, double pVolume, 
string pComment = "Buy order", color pArrow = clrGreen);
      int OpenSellOrder(string pSymbol, double pVolume, 
string pComment = "Sell order", color pArrow = clrRed);
      
      int OpenBuyStopOrder(string pSymbol, double pVolume, 
double pPrice, double pStop, double pProfit, string pComment = "Buy stop order", 
datetime pExpiration = 0, color pArrow = clrBlue);
      int OpenSellStopOrder(string pSymbol, double pVolume, double pPrice, 
double pStop, double pProfit, string pComment = "Sell stop order", 
datetime pExpiration = 0, color pArrow = clrIndigo);
      int OpenBuyLimitOrder(string pSymbol, double pVolume, 
double pPrice, double pStop, double pProfit, string pComment = "Buy limit order", 
datetime pExpiration = 0, color pArrow = clrCornflowerBlue);
      int OpenSellLimitOrder(string pSymbol, double pVolume, double pPrice, 
double pStop, double pProfit, string pComment = "Sell limit order", 
datetime pExpiration = 0, color pArrow = clrMediumSlateBlue);
      
      bool CloseMarketOrder(int pTicket, double pVolume = 0, color pArrow = clrRed);
      bool CloseAllBuyOrders();
      bool CloseAllSellOrders();
      bool CloseAllMarketOrders();
      
      bool DeletePendingOrder(int pTicket, color pArrow = clrRed);
      bool DeleteAllBuyStopOrders();
      bool DeleteAllSellStopOrders();
      bool DeleteAllBuyLimitOrders();
      bool DeleteAllSellLimitOrders();
      bool DeleteAllPendingOrders();
      
      static void SetMagicNumber(int pMagic);
      static int GetMagicNumber();
      
      static void SetSlippage(int pSlippage);     
};

int CTrade::_magicNumber = 0;
int CTrade::_slippage = 10;


//+------------------------------------------------------------------+
//| Market order functions                                           |
//+------------------------------------------------------------------+

int CTrade::OpenMarketOrder(string pSymbol, int pType, double pVolume, string pComment, color pArrow)
{
	int retryCount = 0;
	int ticket = 0;
	int errorCode = 0;
	
	double orderPrice = 0;
	
	string orderType;
	string errDesc;
	
	// Order retry loop
	while(retryCount <= MAX_RETRIES) { 
while(IsTradeContextBusy()) Sleep(10); 
// Get current bid/ask price 
if(pType == OP_BUY) orderPrice = MarketInfo(pSymbol,MODE_ASK); 
else if(pType == OP_SELL) orderPrice = MarketInfo(pSymbol,MODE_BID); 
// Place market order 
ticket = OrderSend(pSymbol,pType,pVolume,orderPrice,_slippage,0,0,
pComment,_magicNumber,0,pArrow); 
// Error handling if(ticket == -1) { 
errorCode = GetLastError(); errDesc = ErrorDescription(errorCode); 
bool checkError = RetryOnError(errorCode); orderType = OrderTypeToString(pType); 
// Unrecoverable error if(checkError == false) { 
Alert("Open ",orderType," order: Error ",errorCode," - ",errDesc); 
Print("Symbol: ",pSymbol,", Volume: ",pVolume,", Price: ",orderPrice); break; } 
// Retry on error else { 
Print("Server error detected, retrying..."); Sleep(RETRY_DELAY); retryCount++; } } 
// Order successful else { orderType = OrderTypeToString(pType); 
Comment(orderType," order #",ticket," opened on ",pSymbol); Print(orderType," 
order #",ticket," opened on ",pSymbol); break; } } 
// Failed after retry 
if(retryCount > MAX_RETRIES)
	{
		Alert("Open ",orderType," order: Max retries exceeded. Error ",errorCode," - ",errDesc);
		Print("Symbol: ",pSymbol,", Volume: ",pVolume,", Price: ",orderPrice);
	}
   
   return(ticket);
}  


int CTrade::OpenBuyOrder(string pSymbol,double pVolume,string pComment="Buy order",color pArrow=32768)
{
   int ticket = OpenMarketOrder(pSymbol, OP_BUY, pVolume, pComment, pArrow);
   return(ticket);
}


int CTrade::OpenSellOrder(string pSymbol,double pVolume,string pComment="Sell order",color pArrow=255)
{
   int ticket = OpenMarketOrder(pSymbol, OP_SELL, pVolume, pComment, pArrow);
   return(ticket);
}


//+------------------------------------------------------------------+
//| Pending order functions                                          |
//+------------------------------------------------------------------+

int CTrade::OpenPendingOrder(string pSymbol,int pType,double pVolume,double pPrice,
double pStop,double pProfit,string pComment,datetime pExpiration,color pArrow)
{
   int retryCount = 0;
	int ticket = 0;
	int errorCode = 0;

	string orderType;
	string errDesc;
	
	// Order retry loop
	while(retryCount <= MAX_RETRIES) { while(IsTradeContextBusy()) Sleep(10); 
ticket = OrderSend(pSymbol, pType, pVolume, pPrice, _slippage, pStop, pProfit, 
pComment, _magicNumber, pExpiration, pArrow); 
// Error handling 
if(ticket == -1) { errorCode = GetLastError(); 
errDesc = ErrorDescription(errorCode); 
bool checkError = RetryOnError(errorCode); 
orderType = OrderTypeToString(pType); 
// Unrecoverable error 
if(checkError == false) { 
Alert("Open ",orderType," order: Error ",errorCode," - ",errDesc); 
Print("Symbol: ",pSymbol,", Volume: ",pVolume,", Price: ",pPrice,", 
SL: ",pStop,", TP: ",pProfit,", Expiration: ",pExpiration); break; } 
// Retry on error else { Print("Server error detected, retrying..."); 
Sleep(RETRY_DELAY); retryCount++; } } 
// Order successful else { orderType = OrderTypeToString(pType); 
Comment(orderType," order #",ticket," opened on ",pSymbol); 
Print(orderType," order #",ticket," opened on ",pSymbol); 
break; } } // Failed after retry if(retryCount > MAX_RETRIES)
	{
		Alert("Open ",orderType," order: Max retries exceeded. Error ",errorCode," - ",errDesc);
		Print("Symbol: ",pSymbol,", Volume: ",pVolume,", Price: ",
pPrice,", SL: ",pStop,", TP: ",pProfit,", Expiration: ",pExpiration);
	}

	return(ticket);
}


int CTrade::OpenBuyStopOrder(string pSymbol,double pVolume,double pPrice,
double pStop,double pProfit,string pComment="Buy stop order",datetime pExpiration=0,color pArrow=16711680)
{
   int ticket = OpenPendingOrder(pSymbol, OP_BUYSTOP, pVolume, pPrice, 
pStop, pProfit, pComment, pExpiration, pArrow);
   return(ticket);
}


int CTrade::OpenSellStopOrder(string pSymbol,double pVolume,double pPrice,
double pStop,double pProfit,string pComment="Sell stop order",datetime pExpiration=0,color pArrow=8519755)
{
   int ticket = OpenPendingOrder(pSymbol, OP_SELLSTOP, pVolume, pPrice, 
pStop, pProfit, pComment, pExpiration, pArrow);
   return(ticket);
}


int CTrade::OpenBuyLimitOrder(string pSymbol,double pVolume,double pPrice,
double pStop,double pProfit,string pComment="Buy limit order",datetime pExpiration=0,color pArrow=15570276)
{
   int ticket = OpenPendingOrder(pSymbol, OP_BUYLIMIT, pVolume, pPrice, pStop, 
pProfit, pComment, pExpiration, pArrow);
   return(ticket);
}


int CTrade::OpenSellLimitOrder(string pSymbol,double pVolume,double pPrice,
double pStop,double pProfit,string pComment="Sell limit order",datetime pExpiration=0,color pArrow=15624315)
{
   int ticket = OpenPendingOrder(pSymbol, OP_SELLLIMIT, pVolume, pPrice, 
pStop, pProfit, pComment, pExpiration, pArrow);
   return(ticket);
}


//+------------------------------------------------------------------+
//| Close market orders                                              |
//+------------------------------------------------------------------+

bool CTrade::CloseMarketOrder(int pTicket,double pVolume=0.000000,color pArrow=255)
{
   int retryCount = 0;
   int errorCode = 0;
   
   double closePrice = 0;
   double closeVolume = 0;
   
   bool result;
   
   string errDesc;
   
   // Select ticket
   result = OrderSelect(pTicket,SELECT_BY_TICKET);
   
   // Exit with error if order select fails
   if(result == false)
   {
      errorCode = GetLastError();
      errDesc = ErrorDescription(errorCode);
      
      Alert("Close order: Error selecting order #",pTicket,". Error ",errorCode," - ",errDesc);
      return(result);
   }
   
   // Close entire order if pVolume not specified, or if pVolume is greater than order volume
   if(pVolume == 0 || pVolume > OrderLots()) closeVolume = OrderLots();
   else closeVolume = pVolume;
   
   // Order retry loop
	while(retryCount <= MAX_RETRIES) { while(IsTradeContextBusy()) Sleep(10); 
// Get current bid/ask price 
if(OrderType() == OP_BUY) closePrice = MarketInfo(OrderSymbol(),MODE_BID); 
else if(OrderType() == OP_SELL) closePrice = MarketInfo(OrderSymbol(),MODE_ASK); 
result = OrderClose(pTicket,closeVolume,closePrice,_slippage,pArrow); 
if(result == false) { 
errorCode = GetLastError(); 
errDesc = ErrorDescription(errorCode); 
bool checkError = RetryOnError(errorCode); 
// Unrecoverable error 
if(checkError == false) { 
Alert("Close order #",pTicket,": Error ",errorCode," - ",errDesc); 
Print("Price: ",closePrice,", Volume: ",closeVolume); break; } 
// Retry on error else { Print("Server error detected, retrying..."); 
Sleep(RETRY_DELAY); retryCount++; } } 
// Order successful 
else { Comment("Order #",pTicket," closed"); 
Print("Order #",pTicket," closed"); break; } } 
// Failed after retry if(retryCount > MAX_RETRIES)
	{
		Alert("Close order #",pTicket,": Max retries exceeded. Error ",errorCode," - ",errDesc);
		Print("Price: ",closePrice,", Volume: ",closeVolume);
	}
	
	return(result);
}


bool CTrade::CloseMultipleOrders(CLOSE_MARKET_TYPE pCloseType)
{
   bool error = false;
   bool closeOrder = false;
   
   // Loop through open order pool from oldest to newest
   for(int order = 0; order <= OrdersTotal() - 1; order++)
   {
      // Select order
      bool result = OrderSelect(order,SELECT_BY_POS);
      
      int orderType = OrderType();
      int orderMagicNumber = OrderMagicNumber();
      int orderTicket = OrderTicket();
      double orderVolume = OrderLots();
      
      // Determine if order type matches pCloseType
      if( (pCloseType == CLOSE_ALL_MARKET && (orderType == OP_BUY || orderType == OP_SELL)) 
         || (pCloseType == CLOSE_BUY && orderType == OP_BUY) 
         || (pCloseType == CLOSE_SELL && orderType == OP_SELL) )
      {
         closeOrder = true;
      }
      else closeOrder = false;
      
      // Close order if pCloseType and magic number match currently selected order
      if(closeOrder == true && orderMagicNumber == _magicNumber)
      {
         result = CloseMarketOrder(orderTicket,orderVolume);
         
         if(result == false)
         {
            Print("Close multiple orders: ",OrderTypeToString(orderType)," #",orderTicket," not closed");
            error = true;
         }
         else order--;
      }
   }
   
   return(error);
}


bool CTrade::CloseAllBuyOrders(void)
{
   bool result = CloseMultipleOrders(CLOSE_BUY);
   return(result);
}


bool CTrade::CloseAllSellOrders(void)
{
   bool result = CloseMultipleOrders(CLOSE_SELL);
   return(result);
}


bool CTrade::CloseAllMarketOrders(void)
{
   bool result = CloseMultipleOrders(CLOSE_ALL_MARKET);
   return(result);
}


//+------------------------------------------------------------------+
//| Delete pending orders                                            |
//+------------------------------------------------------------------+

bool CTrade::DeletePendingOrder(int pTicket,color pArrow=255)
{
   int retryCount = 0;
   int errorCode = 0;
   
   bool result = false;
   
   string errDesc;
  
   // Order retry loop
	while(retryCount <= MAX_RETRIES) { 
while(IsTradeContextBusy()) Sleep(10); 
result = OrderDelete(pTicket,pArrow); 
if(result == false) { errorCode = GetLastError(); errDesc = ErrorDescription(errorCode); 
bool checkError = RetryOnError(errorCode); 
// Unrecoverable error 
if(checkError == false) { 
Alert("Delete pending order #",pTicket,": Error ",errorCode," - ",errDesc); break; } 
// Retry on error 
else { Print("Server error detected, retrying..."); 
Sleep(RETRY_DELAY); retryCount++; } } 
// Order successful 
else { Comment("Pending order #",pTicket," deleted"); 
Print("Pending order #",pTicket," deleted"); break; } } 
// Failed after retry if(retryCount > MAX_RETRIES)
	{
		Alert("Delete pending order #",pTicket,": Max retries exceeded. 
Error ",errorCode," - ",errDesc);
	}
	
	return(result);
}


bool CTrade::DeleteMultipleOrders(CLOSE_PENDING_TYPE pDeleteType)
{
   bool error = false;
   bool deleteOrder = false;
   
   // Loop through open order pool from oldest to newest
   for(int order = 0; order <= OrdersTotal() - 1; order++)
   {
      // Select order
      bool result = OrderSelect(order,SELECT_BY_POS);
      
      int orderType = OrderType();
      int orderMagicNumber = OrderMagicNumber();
      int orderTicket = OrderTicket();
      double orderVolume = OrderLots();
      
      // Determine if order type matches pCloseType
      if( (pDeleteType == CLOSE_ALL_PENDING && orderType != OP_BUY && orderType != OP_SELL)
         || (pDeleteType == CLOSE_BUY_LIMIT && orderType == OP_BUYLIMIT) 
         || (pDeleteType == CLOSE_SELL_LIMIT && orderType == OP_SELLLIMIT) 
         || (pDeleteType == CLOSE_BUY_STOP && orderType == OP_BUYSTOP)
         || (pDeleteType == CLOSE_SELL_STOP && orderType == OP_SELLSTOP) )
      {
         deleteOrder = true;
      }
      else deleteOrder = false;
      
      // Close order if pCloseType and magic number match currently selected order
      if(deleteOrder == true && orderMagicNumber == _magicNumber)
      {
         result = DeletePendingOrder(orderTicket);
         
         if(result == false)
         {
            Print("Delete multiple orders: ",OrderTypeToString(orderType)," #",orderTicket," not deleted");
            error = true;
         }
         else order--;
      }
   }
   
   return(error);
}


bool CTrade::DeleteAllBuyLimitOrders(void)
{
   bool result = DeleteMultipleOrders(CLOSE_BUY_LIMIT);
   return(result);
}


bool CTrade::DeleteAllBuyStopOrders(void)
{
   bool result = DeleteMultipleOrders(CLOSE_BUY_STOP);
   return(result);
}


bool CTrade::DeleteAllSellLimitOrders(void)
{
   bool result = DeleteMultipleOrders(CLOSE_SELL_LIMIT);
   return(result);
}


bool CTrade::DeleteAllSellStopOrders(void)
{
   bool result = DeleteMultipleOrders(CLOSE_SELL_STOP);
   return(result);
}


bool CTrade::DeleteAllPendingOrders(void)
{
   bool result = DeleteMultipleOrders(CLOSE_ALL_PENDING);
   return(result);
}


//+------------------------------------------------------------------+
//| Set trade properties                                             |
//+------------------------------------------------------------------+

static void CTrade::SetMagicNumber(int pMagic)
{
   if(_magicNumber != 0)
   {
      Alert("Magic number changed! Any orders previously opened by this 
expert advisor will no longer be handled!");
   }
   
   _magicNumber = pMagic;
}

static int CTrade::GetMagicNumber(void)
{
   return(_magicNumber);
}


static void CTrade::SetSlippage(int pSlippage)
{
   _slippage = pSlippage;
}


//+------------------------------------------------------------------+
//| Internal functions                                               |
//+------------------------------------------------------------------+

bool RetryOnError(int pErrorCode)
{
	// Retry on these error codes
	switch(pErrorCode)
	{
		case ERR_BROKER_BUSY:
		case ERR_COMMON_ERROR:
		case ERR_NO_ERROR:
		case ERR_NO_CONNECTION:
		case ERR_NO_RESULT:
		case ERR_SERVER_BUSY:
		case ERR_NOT_ENOUGH_RIGHTS:
      case ERR_MALFUNCTIONAL_TRADE:
      case ERR_TRADE_CONTEXT_BUSY:
      case ERR_TRADE_TIMEOUT:
      case ERR_REQUOTE:
      case ERR_TOO_MANY_REQUESTS:
      case ERR_OFF_QUOTES:
      case ERR_PRICE_CHANGED:
      case ERR_TOO_FREQUENT_REQUESTS:
		
		return(true);
	}
	
	return(false);
}


string OrderTypeToString(int pType)
{
	string orderType;
	if(pType == OP_BUY) orderType = "Buy";
	else if(pType == OP_SELL) orderType = "Sell";
	else if(pType == OP_BUYSTOP) orderType = "Buy stop";
	else if(pType == OP_BUYLIMIT) orderType = "Buy limit";
	else if(pType == OP_SELLSTOP) orderType = "Sell stop";
	else if(pType == OP_SELLLIMIT) orderType = "Sell limit";
	else orderType = "Invalid order type";
	return(orderType);
}


//+------------------------------------------------------------------+
//| Modify orders                                                    |
//+------------------------------------------------------------------+

bool ModifyOrder(int pTicket, double pPrice, double pStop = 0, double pProfit = 0, 
datetime pExpiration = 0, color pArrow = clrOrange)
{
   int retryCount = 0;
   int errorCode = 0;
   
	bool result = false;
	
	string errDesc;
	
	// Order retry loop
	while(retryCount <= MAX_RETRIES) { while(IsTradeContextBusy()) Sleep(10); 
result = OrderModify(pTicket, pPrice, pStop, pProfit, pExpiration, pArrow); 
errorCode = GetLastError(); 
// Error handling - Ignore error code 1 
if(result == false && errorCode != ERR_NO_RESULT) { 
errDesc = ErrorDescription(errorCode); bool checkError = RetryOnError(errorCode); 
// Unrecoverable error 
if(checkError == false) { Alert("Modify order #",pTicket,": Error ",errorCode," - ",errDesc); 
Print("Price: ",pPrice,", SL: ",pStop,", TP: ",pProfit,", Expiration: ",pExpiration); break; } 
// Retry on error 
else { Print("Server error detected, retrying..."); 
Sleep(RETRY_DELAY); retryCount++; } } 
// Order successful 
else { Comment("Order #",pTicket," modified"); Print("Order #",pTicket," modified"); break; } } 
// Failed after retry if(retryCount > MAX_RETRIES)
	{
		Alert("Modify order #",pTicket,": Max retries exceeded. Error ",errorCode," - ",errDesc);
		Print("Price: ",pPrice,", SL: ",pStop,", TP: ",pProfit,", Expiration: ",pExpiration);
	}

	return(result);
}


bool ModifyStopsByPoints(int pTicket, int pStopPoints, int pProfitPoints = 0, int pMinPoints = 10)
{
   if(pStopPoints == 0 && pProfitPoints == 0) return false;
   
   bool result = OrderSelect(pTicket,SELECT_BY_TICKET);
   
   if(result == false)
   {
      Print("Modify stops: #",pTicket," not found!");
      return false;
   }
   
   double orderType = OrderType();
   double orderOpenPrice = OrderOpenPrice();
   string orderSymbol = OrderSymbol();
   
   double stopLoss = 0;
   double takeProfit = 0;
   
   if(orderType == OP_BUY)
   {
      stopLoss = BuyStopLoss(orderSymbol,pStopPoints,orderOpenPrice);
      if(stopLoss != 0) stopLoss = AdjustBelowStopLevel(orderSymbol,stopLoss,pMinPoints);
      
      takeProfit = BuyTakeProfit(orderSymbol,pProfitPoints,orderOpenPrice);
      if(takeProfit != 0) takeProfit = AdjustAboveStopLevel(orderSymbol,takeProfit,pMinPoints);
   }
   else if(orderType == OP_SELL)
   {
      stopLoss = SellStopLoss(orderSymbol,pStopPoints,orderOpenPrice);
      if(stopLoss != 0) stopLoss = AdjustAboveStopLevel(orderSymbol,stopLoss,pMinPoints);
      
      takeProfit = SellTakeProfit(orderSymbol,pProfitPoints,orderOpenPrice);
      if(takeProfit != 0) takeProfit = AdjustBelowStopLevel(orderSymbol,takeProfit,pMinPoints);
   }
   
   result = ModifyOrder(pTicket,0,stopLoss,takeProfit);
   return(result);
}


bool ModifyStopsByPrice(int pTicket, double pStopPrice, double pProfitPrice = 0, int pMinPoints = 10)
{
   if(pStopPrice == 0 && pProfitPrice == 0) return false;
   
   bool result = OrderSelect(pTicket,SELECT_BY_TICKET);
   
   if(result == false)
   {
      Print("Modify stops: #",pTicket," not found!");
      return false;
   }
   
   double orderType = OrderType();
   string orderSymbol = OrderSymbol();
   
   double stopLoss = 0;
   double takeProfit = 0;
   
   if(orderType == OP_BUY)
   {
      if(pStopPrice != 0) stopLoss = AdjustBelowStopLevel(orderSymbol,pStopPrice,pMinPoints);
      if(pProfitPrice != 0) takeProfit = AdjustAboveStopLevel(orderSymbol,pProfitPrice,pMinPoints);
   }
   else if(orderType == OP_SELL)
   {
      if(pStopPrice != 0) stopLoss = AdjustAboveStopLevel(orderSymbol,pStopPrice,pMinPoints);
      if(pProfitPrice != 0) takeProfit = AdjustBelowStopLevel(orderSymbol,pProfitPrice,pMinPoints);
   }
   
   result = ModifyOrder(pTicket,0,stopLoss,takeProfit);
   return(result);
}


//+------------------------------------------------------------------+
//| Stop loss & take profit calculation                              |
//+------------------------------------------------------------------+

double BuyStopLoss(string pSymbol,int pStopPoints, double pOpenPrice = 0)
{
	if(pStopPoints <= 0) return(0); double openPrice; if(pOpenPrice > 0) openPrice = pOpenPrice;
	else openPrice = SymbolInfoDouble(pSymbol,SYMBOL_ASK);
	
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double stopLoss = openPrice - (pStopPoints * point);
	
	long digits = SymbolInfoInteger(pSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}


double SellStopLoss(string pSymbol,int pStopPoints, double pOpenPrice = 0)
{
	if(pStopPoints <= 0) return(0); double openPrice; if(pOpenPrice > 0) openPrice = pOpenPrice;
	else openPrice = SymbolInfoDouble(pSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double stopLoss = openPrice + (pStopPoints * point);
	
	long digits = SymbolInfoInteger(pSymbol,SYMBOL_DIGITS);
	stopLoss = NormalizeDouble(stopLoss,(int)digits);
	
	return(stopLoss);
}


double BuyTakeProfit(string pSymbol,int pProfitPoints, double pOpenPrice = 0)
{
	if(pProfitPoints <= 0) return(0); double openPrice; if(pOpenPrice > 0) openPrice = pOpenPrice;
	else openPrice = SymbolInfoDouble(pSymbol,SYMBOL_ASK);
	
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double takeProfit = openPrice + (pProfitPoints * point);
	
	long digits = SymbolInfoInteger(pSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}


double SellTakeProfit(string pSymbol,int pProfitPoints, double pOpenPrice = 0)
{
	if(pProfitPoints <= 0) return(0); double openPrice; if(pOpenPrice > 0) openPrice = pOpenPrice;
	else openPrice = SymbolInfoDouble(pSymbol,SYMBOL_BID);
	
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double takeProfit = openPrice - (pProfitPoints * point);
	
	long digits = SymbolInfoInteger(pSymbol,SYMBOL_DIGITS);
	takeProfit = NormalizeDouble(takeProfit,(int)digits);
	return(takeProfit);
}


//+------------------------------------------------------------------+
//| Stop level verification                                         |
//+------------------------------------------------------------------+

// Check stop level
bool CheckAboveStopLevel(string pSymbol, double pPrice, int pPoints = 10)
{
	double currPrice = SymbolInfoDouble(pSymbol,SYMBOL_ASK);
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double stopLevel = SymbolInfoInteger(pSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
	double stopPrice = currPrice + stopLevel;
	double addPoints = pPoints * point;
	
	if(pPrice >= stopPrice + addPoints) return(true);
	else return(false);
}


bool CheckBelowStopLevel(string pSymbol, double pPrice, int pPoints = 10)
{
	double currPrice = SymbolInfoDouble(pSymbol,SYMBOL_BID);
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double stopLevel = SymbolInfoInteger(pSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
	double stopPrice = currPrice - stopLevel;
	double addPoints = pPoints * point;
	
	if(pPrice <= stopPrice - addPoints) return(true); else return(false); } 
// Adjust price to stop level 
double AdjustAboveStopLevel(string pSymbol, double pPrice, int pPoints = 10) { 
double currPrice = SymbolInfoDouble(pSymbol,SYMBOL_ASK); 
double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT); 
double stopLevel = SymbolInfoInteger(pSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point; 
double stopPrice = currPrice + stopLevel; 
double addPoints = pPoints * point; 
if(pPrice > stopPrice + addPoints) return(pPrice);
	else
	{
		double newPrice = stopPrice + addPoints;
		Print("Price adjusted above stop level to "+DoubleToString(newPrice));
		return(newPrice);
	}
}


double AdjustBelowStopLevel(string pSymbol, double pPrice, int pPoints = 10)
{
	double currPrice = SymbolInfoDouble(pSymbol,SYMBOL_BID);
	double point = SymbolInfoDouble(pSymbol,SYMBOL_POINT);
	double stopLevel = SymbolInfoInteger(pSymbol,SYMBOL_TRADE_STOPS_LEVEL) * point;
	double stopPrice = currPrice - stopLevel;
	double addPoints = pPoints * point;
	
	if(pPrice < stopPrice - addPoints) return(pPrice);
	else
	{
		double newPrice = stopPrice - addPoints;
		Print("Price adjusted below stop level to "+DoubleToString(newPrice));
		return(newPrice);
	}
}


//+------------------------------------------------------------------+
//| Order counts                                                     |
//+------------------------------------------------------------------+

class CCount
{
   private:  
      enum COUNT_ORDER_TYPE
      {
         COUNT_BUY,
         COUNT_SELL,
         COUNT_BUY_STOP,
         COUNT_SELL_STOP,
         COUNT_BUY_LIMIT,
         COUNT_SELL_LIMIT,
         COUNT_MARKET,
         COUNT_PENDING,
         COUNT_ALL
      };
      
      int CountOrders(COUNT_ORDER_TYPE pType);
 
      
   public:
      int Buy();
      int Sell();
      int BuyStop();
      int SellStop();
      int BuyLimit();
      int SellLimit();
      int TotalMarket();
      int TotalPending();
      int TotalOrders();
};


int CCount::CountOrders(COUNT_ORDER_TYPE pType)
{
   // Order counts
   int buy = 0, sell = 0, buyStop = 0, sellStop = 0, 
      buyLimit = 0, sellLimit = 0, totalOrders = 0;
   
   // Loop through open order pool from oldest to newest
   for(int order = 0; order <= OrdersTotal() - 1; order++)
   {
      // Select order
      bool result = OrderSelect(order,SELECT_BY_POS);
      
      int orderType = OrderType();
      int orderMagicNumber = OrderMagicNumber();
      
      // Add to order count if magic number matches
      if(orderMagicNumber == CTrade::GetMagicNumber())
      {
         switch(orderType)
         {
            case OP_BUY:
               buy++;
               break;
               
            case OP_SELL:
               sell++;
               break;
               
            case OP_BUYLIMIT:
               buyLimit++;
               break;
               
            case OP_SELLLIMIT:
               sellLimit++;
               break;   
               
            case OP_BUYSTOP:
               buyStop++;
               break;
               
            case OP_SELLSTOP:
               sellStop++;
               break;          
         }
         
         totalOrders++;
      }
   }
   
   // Return order count based on pType
   int returnTotal = 0;
   switch(pType)
   {
      case COUNT_BUY:
         returnTotal = buy;
         break;
         
      case COUNT_SELL:
         returnTotal = sell;
         break;
         
      case COUNT_BUY_LIMIT:
         returnTotal = buyLimit;
         break;
         
      case COUNT_SELL_LIMIT:
         returnTotal = sellLimit;
         break;
         
      case COUNT_BUY_STOP:
         returnTotal = buyStop;
         break;
         
      case COUNT_SELL_STOP:
         returnTotal = sellStop;
         break;
         
      case COUNT_MARKET:
         returnTotal = buy + sell;
         break;
         
      case COUNT_PENDING:
         returnTotal = buyLimit + sellLimit + buyStop + sellStop;
         break;   
         
      case COUNT_ALL:
         returnTotal = totalOrders; 
         break;        
   }
   
   return(returnTotal);
}


int CCount::Buy(void)
{
   int total = CountOrders(COUNT_BUY);
   return(total);
}

int CCount::Sell(void)
{
   int total = CountOrders(COUNT_SELL);
   return(total);
}

int CCount::BuyLimit(void)
{
   int total = CountOrders(COUNT_BUY_LIMIT);
   return(total);
}

int CCount::SellLimit(void)
{
   int total = CountOrders(COUNT_SELL_LIMIT);
   return(total);
}

int CCount::BuyStop(void)
{
   int total = CountOrders(COUNT_BUY_STOP);
   return(total);
}

int CCount::SellStop(void)
{
   int total = CountOrders(COUNT_SELL_STOP);
   return(total);
}

int CCount::TotalMarket(void)
{
   int total = CountOrders(COUNT_MARKET);
   return(total);
}

int CCount::TotalPending(void)
{
   int total = CountOrders(COUNT_PENDING);
   return(total);
}

int CCount::TotalOrders(void)
{
   int total = CountOrders(COUNT_ALL);
   return(total);
}

In the above Trade.mqh code, you will learn many new coding concepts. Trade.mqh is a pretty long file. It is very comprehensive. Since Andrew Young has given permission to share this code if the copy right attributed to him is also provided. I am sharing this Trade.mqh file code for eduction purposes without any commercial intent. You are free to download it  and use it in your trading. Did you take a look at my C++ for Traders course. Now as you can see above Trade.mqh is a pretty big file with morre than 2000 lines of code. Once you have code this Trade.mqh file, you can use it again and again in your EAs and indicators. So you only need to work on it once and later use it again and again. In the above Trade.mqh code we first have the #property preprocessor directives than we have the #define preprocessor directive.The #define directive allows us to assign mnemonic names to constants which in this case is the MAX_RETRIES which is 3 but we have named it as MAX_RETRIES when executing an order. Then we have RETRY_DELAY which is 3000 ms. This is the time between two consecutive retries. As a rule we always use captial latters in defining the constants. But it is not a must. However this is a good practice. This time we have used the #include directive to include the standard library stdlib.mqh.

Defining the CTrade Class

In the above Trade.mqh include Andrew defined the CTrade class that can manage the open order positions. A class is basically a template that we use to define objects. Each class has got data and methods. Methods are just functions which are blocks of code that perform a specific task. We define the class functions once and then use them again and again. Code once and use again is what prompted the development of object oriented programming. So basically classes and functions are designed to be flexible and reusable. As we saw above, object oriented programming encourages code reuse and hides unnessary implementation details as we saw above this allows much more flexible and compact stype of programming. Object oriented programming is based on the concept of classes and objects. A class is a collection of variables and functions that perform tasks on the variables. The variables and functions in a class are known as the members of the class.

As said above a  classis like a blueprint. An object is created using class as the blueprint. Each object has a unique name and we can create as many objects as we want. For example you can define a moving average indicator class and then use it to define a number of moving averages with different periods. When we define a moving average indicator class, we don’t need to define a dynamic array to hold the moving average indicator values. We also don’t need to worry about initializing the moving average indicator object and copying the indicator values from the buffer to the array. All the fine details are handled in the class implementation like when we create an object the class constructor initialized the object.

Classes are defined on the global scope. A class can be defined in the main program as well as in the include file like that done above. A class declaration starts with the class keyword like that above. We define the CTrade class by proceeding it with the class keyword. First we define the private members static int _magicNumber and static int _slippage. After that we define  two enums one is CLOSE_MARKET_TYPE and the other is CLOSE_PENDING_TYPE. CLOSE_MARKET_TYPE closes market orders and CLOSE_PENDING_TYPE closes all pending orders. After that we define two private functions that are OpenMarketOrder and OpenPendingOrder. We also define two private functions CloseMultipleOrders and DeleteMultipleOrders. After that we define a number of public functions like OpenBuyOrder, OpenSellOrder, OpenBuyStopOrder, OpenSellStopOrder, OpenBuyLImitOrder and OpenSellLimiteOrder. Learn what is the difference between the professional trader and the retail trader.

What is Public, Private and Protected?

The keywords public, private and protected tell you what type of access is allowed for the class variables outside the class. Public members of a class can be used from outside the class.Public functions are used to access and modify the private and protected members of a class. Private members cannot be accessed from outside the class. Only the public members of the class can access the private members  of the class. This is done to make sure no un authorized user can access and modify the private members of the class.Protected members are the private members of a class that can be inherited in the child class. Keep this in mind the most important thing when opening and closing orders is to check whether the order has been entered successfully without any error. If you go through the class CTrade public function definitions most of the time they are checking for the errors and reporting if the order has been placed without any error. if you check at the top we have the stdlib.mqh included in our file. This stdlib.mqh file contains the error codes that have been predefined in the MQL4 language.

Defining CCount class

Then we have the CCount class that counts the number of open orders using a private enum. You should go through the code of CCount class. It will be a learning experience. MQL4 initially lacked object oriented programming features. However, now you can also use OOP in MQL4 just like in MQL5. Watch this video documentary on the impact of automated trading systems on the markets.

Algorithmic trading is now very popular. You should learn how to code your own algorithmic trading strategies. Markets move very fast and only way to deal with fast moving price action is to code your own algorithmic trading system. Take a look at my course Algorithmic Trading with C++. With Interactive Brokers, you can code your trading strategy in C++.