How To Do Object Oriented Programming In MQL5?

MQL5 is an object oriented programming that has been build from the ground up by the Meta Quotes Corporation. MQL4 is a simple procedural language that lacks object oriented programming. This short coming and many other short comings were removed by Meta Quotes Corporation with MQL5. MQL5 is very close to C++. If you know C++ then you know how powerful C++. It will be very easy for you to learn and master MQL5. This is an educational post in which I will discuss in detail how we can build class and objects in MQL5. All modern programing languages like C++, JAVA, C#, Python etc are object oriented programming (OOP) languages in which we define classes to model real life objects. For new programmers, OOP is a little difficult in the beginning. But with some practice OOP concepts become clear and they realize how easy and useful this can be. Did you read this post in which I explained how to build a simple Kalman Filter?

Classes are like templates that we design for creating objects that we can use in our coding. For example we can create a car class. In this car class we describe the cars that we will be creating with that class. For example, we can tell that class to have private variables and public variables plus private functions and public functions that are also known as methods. We can use this car class to create different car objects like the Toyota car, Honda car, ford car, Mercedes car etc. Similarly we define different indicators classes like the moving average indicator class, relative strength indicator class, stochastic class, MACD class etc. We can then use these classes to define moving average object, relative strength indicator object, stochastic object, MACD object in our code. We can also create trailing stop loss class to define a trailing stop loss object. It all depends on your imagination. Download this Engulfing Pattern Trading Robot FREE.

MQL5 Meta Editor

Classes are the templates that define our objects. Objects have data and methods. The object methods operate on the data to exhibit certain behavior. Each object has different data. Methods operate on that data. Class are the templates that define that data an object can have and what methods an object can use. Once I build a class things will start getting clear to you. Object Oriented Programming (OOP) is a concept that you should master even if you have spend some hours to master it. Learning OOP will become handy in the future. Days of retail trading are coming to an end. Today something like 80% of the trades are being placed by algorithms. Algorithmic Trading is the future. Price reacts very fast. It is physically impossible for a trader to react that fast. Only algorithms can react that fast. In order to master algorithmic trading, you will have to master programming. Read this post on how a 23 year old made $700K in 1 year of trading. Starting with MQL5 will help you code your own eas that you can test on the demo account.In order to understand OOP, you should understand the following concepts.

Encapsulation:: MQL5 borrows many things from C++. Encapsulation is an OOP concept that MQL5 borrows from C++. Encapsulation is built into classes. Classes create objects that have data that is hidden from outside world. Only way to access that data is through publicly available methods. These methods are used to modify the behavior of these objects. Encapsulation simply means we hide the data. Only way to modify that data is through publicly available methods.

Inheritance: Inheritance is a powerful property of OOP. Power of OOP lies in code reuse. Once we have defined a class and coded it and tested it thoroughly. We can then use that class to define more classes based on it by using the property of inheritance. The new class will inherit all the variables and methods of the parent class. We can further extend the new class by adding more variables and more methods. So the new class inherits the variables and methods from the parent class plus it has it’s own variables and methods.

Virtual Functions: Virtual functions allows us to change the way a function behaves in a derived class. Virtual functions are an extension of the polymorphism property.

Constructors: Constructors are integral part of any class definition. A constructor is used to initialize a new object. So when a new object is declared, the constructor creates that object by initializing its variables. If you don’t define a constructor in the class template, compiler will use the default constructor. A class can have multiple constructors apart from the default constructor. These constructors are defined using operator overloading so that the compiler can distinguish which constructor to call. THe default constructor has no parameters. With every constructor comes its destructor. Constructors and destructors are very important in C++ when we use pointers. Watch this 50 minute video on how to trade on daily and weekly charts.

Now I will create an order placement class that make the above concepts more clear. We will built a class that will place buy/sell orders. After placing the order, it will be able to modify, cancel, delete and close the order. First we define the class variables,

class cOrder
{
private:
MqlTradeRequest request;
public:
MqlTradeResult result;
};

Above you can see we have defined two variables based on MqlTradeRequest structure and MqlTradeResult structure. MqlTradeRequest variable request is private while MqlTradeResult is public.

class cOrder
{

private:
MqlTradeRequest request;
// decalre OpenOrderPosition function
bool OpenOrderPosition(string fSymbol, ENUM_ORDER_TYPE fType, double fVolume,
double fStop = 0, double fProfit = 0, string fComment = NULL);
// declare OpenOrderPending function
bool OpenOrderPendingPosition (string fSymbol, ENUM_ORDER_TYPE fType, double fVolume, 
double fPrice, double fStop = 0, double fProfit = 0, double fStopLimit = 0, 
datetime fExpiration = 0, string fComment = NULL);
public:
MqlTradeResult result;
};

In the above code we have declared OpenOrderPosition() function. Function is the same as method. Some people will call these functions as methods. It is upto you. OpenOrderPosition() is a boolean function. It will return true value when the order is opened/placed successfully. It will return false value if there is an error and no position was opened/placed. fSymbol is the symbol of the currency pair or financial security. fType is the order type is an enumeration. fVolume is the number of lots of the order. fStop is the stop loss order which is optional as we have already specified with the default value of 0.0. fProfit and fComment are also optional. MqlTradeResult is a structure. Structure is a set of variables that can be different data types. Structures are a little simpler than classes. Structures don’t have any methods. In the same manner enumberation is a list of integer variables. Below is a predefined MQ5 structure. Similarly we declare the OpenOrderPendingPosition() function.

struct MqlTick
{
datetime time; // Time of the last price update
double bid; // Current Bid price
double ask; // Current Ask price
double last; // Price of the last deal (Last)
ulong volume; // Volume for the current Last price
};

We can access the last tick price with the following commands.

MqlTick price;  // first define an MqlTick variable price
SymbolInfoTick(_Symbol,price);
Print(price.ask); // Returns the current ask price

Once we have defined the MqlTick price structure, we will use the SymbolInfoTick() function to fill the price structure with the present tick price that includes ask and bid price as well as volume. There are a number of predefined structures and enumerations in MQL5 Reference Manual. Returning to our Order class definitions we have used MqlTradeResult structure. Below is the MqlTradeResult structure.

struct MqlTradeResult
{
uint retcode; // Return code. This code tells whether the trade has been placed or not
ulong deal; // Deal ticket (this is for market orders)
ulong order; // Order ticket (this is for pending orders)
double volume; // Deal volume
double price; // Deal price
double bid; // Current Bid price
double ask; // Current Ask price
string comment; // Broker comment to operation
}

As you can see there are a number of variables in the MqlTradeResult. Returning to our class definition we need to defined the OrderOpenPosition function. We had declared the OpenOrderPosition function in the class definition. We define it below.

// Open Order position definition
bool cOrder::OpenOrderPosition(string fSymbol, 
ENUM_ORDER_TYPE fType, double fVolume, 
double fStop = 0, double fProfit = 0, string fComment = NULL)
{
	request.action = TRADE_ACTION_DEAL;
	request.symbol = fSymbol;
        request.volume=fVolume;
	request.type = fType;
	request.sl = fStop;
	request.tp = fProfit;
	request.comment = fComment;
// Order loop
int retryCount = 0;
int checkCode = 0;

do
{
if(fType == ORDER_TYPE_BUY) request.price = SymbolInfoDouble(pSymbol,SYMBOL_ASK);
else if(fType == ORDER_TYPE_SELL) request.price = SymbolInfoDouble(fSymbol,SYMBOL_BID);

OrderSend(request,result);

checkCode = CheckReturnCode(result.retcode);

if(checkCode == CHECK_RETCODE_OK) break;
else if(checkCode == CHECK_RETCODE_ERROR)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("Open market order: Error ",result.retcode," - ",errDesc);
break;
}
else
{
Print("Server error detected, retrying...");
Sleep(RETRY_DELAY);
retryCount++;
}
}
while(retryCount < MAX_RETRIES); if(retryCount >= MAX_RETRIES)
{
string errDesc = TradeServerReturnCodeDescription(result.retcode);
Alert("Max retries exceeded: Error ",result.retcode," - ",errDesc);
}

string orderType = CheckOrderType(pType);

string errDesc = TradeServerReturnCodeDescription(result.retcode);
Print("Open ",orderType," order #",result.deal,": ",result.retcode," - ",errDesc,", 
Volume: ",result.volume,", Price: ",result.price,", Bid: ",result.bid,", Ask: ",result.ask);

if(checkCode == CHECK_RETCODE_OK)
{
Comment(orderType," position opened at ",result.price," on ",fSymbol);
return(true);
}
else return(false);

In the above code cOrder :: OpenOrderPosition() is the scope resolution operator that tells the compiler that OpenOrderPosition has been declared in the class cOrder. TRADE_ACTION_DEAL means OrderSend() will place a market order. First initialize the MqlTradeRequest structure.This we do at the very beginning of the code. Once we have initializes the MqlTradeRequest. We need to check the market price. If we are placing a buy order we need bid price and if we are placing a sell order we need ask price. Once we have the market price we initialize it with request.price and then place the order with OrderSend(). Now we need to do error handling. Error can happen when the OrderSend() function fails to open an order successfully. When that happens, we need to notify the trader that order could not be placed. If the return code is 10008 (TRADE_RETCODE_PLACED) and 10009 (TRADE_RETCODE_DONE), it means trade order was succesfully placed. In this case we will notify the trader that position has been opened with price on symbol. In case other code is returned we have an error we need to notify the trader that trade was not placed. Now we need to define OpenOrderPendingPosition() function. Below is the code for OpenOrderPendingPosition(). Before you start reading the code below, read this post on how to use random forests in trading.

// Open pending order
bool cOrder::OpenOrderPendingPosition(string fSymbol,ENUM_ORDER_TYPE fType,double fVolume,
double fPrice,double fStop=0.000000,double fProfit=0.000000,double fStopLimit = 0,datetime 
fExpiration=0,string fComment=NULL)
{
	request.action = TRADE_ACTION_PENDING;
	request.symbol = fSymbol;
	request.type = fType;
	request.sl = fStop;
	request.tp = fProfit;
	request.comment = fComment;
	request.price = fPrice;
	request.volume = fVolume;
	request.stoplimit = fStopLimit;
	
	if(fExpiration > 0)
	{
		request.expiration = fExpiration;
		request.type_time = ORDER_TIME_SPECIFIED;
	}
	else request.type_time = ORDER_TIME_GTC;
	
	// Order loop
	int retryCount = 0;
	int checkCode = 0;
	
	do 
	{
		OrderSend(request,result);
		
		checkCode = CheckReturnCode(result.retcode);
		
		if(checkCode == CHECK_RETCODE_OK) break;
		else if(checkCode == CHECK_RETCODE_ERROR)
		{
			string errDesc = TradeServerReturnCodeDescription(result.retcode);
			Alert("Open pending order: Error ",result.retcode," - ",errDesc);
			break;
		}
		else
		{
			Print("Server error detected, retrying...");
			Sleep(RETRY_DELAY);
			retryCount++;
		}
	}
	while(retryCount < MAX_RETRIES); if(retryCount >= MAX_RETRIES)
	{
		string errDesc = TradeServerReturnCodeDescription(result.retcode);
		Alert("Max retries exceeded: Error ",result.retcode," - ",errDesc);
	}
	
	string orderType = CheckOrderType(fType);
	string errDesc = TradeServerReturnCodeDescription(result.retcode);
	
	Print("Open ",orderType," order #",result.order,": ",result.retcode," - ",errDesc,", 
Volume: ",result.volume,", Price: ",request.price,", 
Bid: ",SymbolInfoDouble(fSymbol,SYMBOL_BID),", 
Ask: ",SymbolInfoDouble(fSymbol,SYMBOL_ASK),", 
SL: ",request.sl,", TP: ",request.tp,", 
Stop Limit: ",request.stoplimit,", 
Expiration: ",request.expiration);
	
	if(checkCode == CHECK_RETCODE_OK) 
	{
		Comment(orderType," order opened at ",request.price," on ",fSymbol);
		return(true);
	}
	else return(false);
}

With practice you will see coding is easy. Read this post on how to predict the daily candle using Elman Neural Network. Now if you had read the code correctly you must have observed that OpenOrderPosition() is a private function. We define the following 2 helper function that are publicly available to palce the buy/sell orders.

bool cOrder::Buy(string fSymbol, double fVolume, double fStop = 0, double fProfit = 0,
string fComment = NULL)
{
bool Success = OpenOrderPosition(fSymbol,ORDER_TYPE_BUY,fVolume,fStop,fProfit,fComment);
return(Success);
}
bool cOrder::Sell(string fSymbol, double fVolume, double fStop = 0, double fProfit = 0,
string fComment = NULL)
{
bool Success = OpenOrderPosition(fSymbol,ORDER_TYPE_SELL,fVolume,fStop,fProfit,fComment);
return(Success);
}

Internally these buy/sell functions use the OpenOrderPositions() functions.

MQL5 Meta Editor Error Window

Once we have coded the class we need to compile it. Once we compile it we get the following errors. Now you can see above there are just 8 warnings and no error. So this code has been compiled and it will run. Warnings are coming because we didn’t check OrderSend() function which has a boolean value. Building classes will simplfy coding for you. Using the inheritance propery you can derive more classes from the parent classes without having to code everything from scratch. My next project is to build a kalman filter in MQL5. If you don’t know what a Kalman Filter is, you can take a look at this course on Kalman Filter. In this course, I teach you how to use a Kalman Filter in trading.

Leave A Response