The MQL4 Lot Size Functions I Use In My Algotrading Code

All the functions discussed here are part of the Common library available for purchase.




The goal of this post is to share with you some functions I am using to verify and manage the lot size I used when opening an order. As mentioned in my home page, I am using proprietary algorithm to trade the 25% cash I don't invest in the permanent portfolio. To achieve that, I programmed an Expert Advisor using MQL language which is running 24/5 and trade 5 currency pairs. In here, you can find the relevant darwin which can be traded as a normal financial product thanks to the Darwinex broker.

Managing Lot Size



As noted in another post about leverage, it is important to keep the leverage / lot size under control. Most common junior mistakes are trading massive lot sizes to gain quick wins, but as soon as the market turns against them, their account is completely wiped out without a chance to react (speaking from experience). So, in this post I will share three functions I am using to verify and manage lot sizes I am using in my own expert advisor. You may copy paste this code and use it on your own responsibility in your own code.

Verify Lot Size



Lot Size

Perhaps the simplest and most common function of all. I use this one whenever I am about to open a position, to verify the lot size is:


  1. Above the minimum lot size allowed

  2. Below the maximum lot size allowed

  3. Allows micro or mini lots as per the broker.



double VerifyLotSize(string argSymbol,double argLotSize) export
{
argLotSize=MarketInfo(argSymbol,MODE_LOTSTEP)==0.1?NormalizeDouble(argLotSize,1):NormalizeDouble(argLotSize,2);
return MathMax(MarketInfo(argSymbol,MODE_MINLOT),MathMin(MarketInfo(argSymbol,MODE_MAXLOT),argLotSize));
}


Starting from the declaration, you can the return value is the actual verified lot size. There are two arguments, the symbol you want to open the order for and the lot size you want to open. A typical call would look like:

double Lots=VerifyLotSize("EURUSD",0.02);

If the size provided is legitimate, the return value will be equal to the input, in this case to 0.02 lot size. On the other hand, there are a couple of checks happening which will influence the result:


  • First, we check in MarketInfo(argSymbol,MODE_LOTSTEP) how many digits the broker allows, whether mini lots are allowed (0.1) or micro as well (0.01). Based on the return value, we trim the lot size if needed. If for example, the broker only allows mini lots, 0.11 will turn into 0.1 lots and the 0.01 will get trimmed.

  • Then, MathMin(MarketInfo(argSymbol,MODE_MAXLOT),argLotSize) verifies that the requested lot size is smaller than the maximum for that currency, in my case, the maximum lot size I can open per trade is 1,000 which is 100,000,000 units.

  • Finally, MathMax is called on the result of the previous step to verify the lot size is larger than the minimum lot size offered by the broker.



Running this function on several examples for EURUSD will give the following output:

Print(VerifyLotSize(Symbol(),0.001)); --> 0.01
Print(VerifyLotSize(Symbol(),0.00)); --> 0.01
Print(VerifyLotSize(Symbol(),100000.001)); --> 1,000
Print(VerifyLotSize(Symbol(),0.123)); --> 0.12

Best place to use this function is right before opening an order, so you can be certain that the lot size you are using is legal. I normally use specific exposure per trade based on percentage from my equity so it looks like that:

double Lots = VerifyLotSize(TheSymbol,(Exposure/100)*AccountEquity()/100000);

Confirm Enough Margin



[caption id="attachment_176" align="alignnone" width="300"]Enough Margin photo by CafeCredit[/caption]

The next function verifies whether you have enough margin before opening the order. So, if you know how much lots you want to trade and verified it in the previous step, this step will check if you even have enough margin to open the order at all.

bool ConfirmEnoughMargin(string argSymbol,int argOrderType,double argLotSize) export { if(AccountStopoutMode()==0 && (AccountMargin()+AccountFreeMargin()-AccountFreeMarginCheck(argSymbol,argOrderType,argLotSize))!=0 && (100*AccountEquity()/(AccountMargin()+AccountFreeMargin()-AccountFreeMarginCheck(argSymbol,argOrderType,argLotSize)))

As per the signature, this function returns true or false based on the check it performs. The inputs are the symbol you want to open the order on, the lots size you want to trade and order type which is either OP_BUY or OP_SELL.

As described in MQL reference, there are two modes to calculate whether you have enough margin to open the order:

0 - calculation of percentage ratio between margin and equity.
1 - comparison of the free margin level to the absolute value.

Based on that, I built the function to confirm there is enough margin to open the trade:


  • If your broker is using the percentage method. We need to check that the ratio between the account equity and the margin is less the the stop out level using the following code - (100*AccountEquity()/(AccountMargin()+AccountFreeMargin()-AccountFreeMarginCheck(argSymbol,argOrderType,argLotSize)))

  • On the other case, if you broker is using method number 1 to compare the margin to the absolute value, we use the following code - AccountFreeMarginCheck(argSymbol,argOrderType,argLotSize)



In both case, if the check fails, and opening the order will result with a situation you won`t have enough margin, error 134 will be thrown. In this case the function fails and a false value will return. Otherwise, if both checks passes, a true will return and you may proceed and open this position. Using this function will save you an error returned from the open order and check whether the order ticket is not equal to -1 upon failure.

Running this function on several examples for EURUSD will give the following output, assuming equity is 100,000:

Print(ConfirmEnoughMargin(Symbol(),OP_BUY,0.01)); --> true
Print(ConfirmEnoughMargin(Symbol(),OP_BUY,1)); --> true
Print(ConfirmEnoughMargin(Symbol(),OP_BUY,100)); --> true
Print(ConfirmEnoughMargin(Symbol(),OP_BUY,1000)); --> false

You can see in the last case it is failing, as I am trying to open a position to control 100,000,000 Units which requires a margin of 500,000 which is more than my equity. Otherwise, the other functions return true so it is safe from margin point of view to open them. Still, it doesn`t mean you need to ignore your effective leverage and make sure you are still nicely leverage, i.e. below 1:10 as explained here.

Calculate Lot Size Based On Risk



Risk

The last function in my arsenal is to calculate the lot size I want to open based on a risk parameter. In my case, I use the volatility to open an order which will loss at the worse case a certain percentage of my account over a specific timeframe.

double CalcRiskBasedLotSize(string argSymbol,double argPercentageRiskPerOrder,int argTimeframe,int argSTDFactor,int argSTDPeriod) export { double Risk=AccountBalance()*argPercentageRiskPerOrder/100; double STDPips=argSTDFactor*iStdDev(argSymbol,argTimeframe,argSTDPeriod,0,MODE_SMA,PRICE_CLOSE,0)/MarketInfo(argSymbol,MODE_POINT); return STDPips==0?MarketInfo(argSymbol,MODE_MINLOT):VerifyLotSize(argSymbol,Risk/(STDPips*MarketInfo(argSymbol,MODE_TICKVALUE))); }

This function return value is the calculated lot size based on the risk parameters you provide:


  • argSymbol - product the calculate the lot for.

  • argPercentageRiskPerOrder - how much you want to risk for this trade (1%, 2%...).

  • argTimeframe - timeframe to calculate the volatility (PERIOD_D1, PERIOD_H1...).

  • argSTDFactor - factor to multiply the volatility, in case you want to have double the amount, triple etc...

  • argSTDPeriod - period to test the volatility over



The first line of code calculate how much of your balance you would like to risk as per the first argument -  double Risk=AccountBalance()*argPercentageRiskPerOrder/100;

Then, using the next parameters we calculate how much volatility in pips we have in his timeframe - double STDPips=argSTDFactor*iStdDev(argSymbol,argTimeframe,argSTDPeriod,0,MODE_SMA,PRICE_CLOSE,0)/MarketInfo(argSymbol,MODE_POINT);

The division with MarketInfo(argSymbol, MODE_POINT) make sure we convert it from decimal value to pips value.

Finally, the last line calculate the lot size according to the risk parameters. The main part is Risk/(STDPips*MarketInfo(argSymbol,MODE_TICKVALUE)). Here, we divide the amount we would like to risk with the volatility. The value we get is the lot size, that over this volatility will lose the amount we calculated in the first stage.
For example, let's say you have an account with 100,000 USD and you want to risk 2% of it using the daily volatility. Using a daily volatility of 890 pips the calculated pips will be:

(2%*100,000) / 890 = 2.24.

Meaning, that if the order goes 890 pips against you as per the daily volatility, you will lost 2,000 USD which is 2% from your equity.

In my code, usually I run it with the following input - double Lots = CalcRiskBasedLotSize("EURUSD",2%,PERIOD_D1,1,20), which calculates the lot size based on 20 days volatility.

Running an example code with different values gives the following values:

Print(CalcRiskBasedLotSize("EURUSD",1,PERIOD_D1,1,20)); --> 1.69
Print(CalcRiskBasedLotSize("EURUSD",2,PERIOD_D1,1,20)); --> 3.38
Print(CalcRiskBasedLotSize("EURUSD",1,PERIOD_M1,1,20)); --> 140.98
Print(CalcRiskBasedLotSize("EURUSD",1,PERIOD_W1,1,20)); --> 0.63

If you look at the third line, you might be surprise we got 140.98 as lot size. But if you think about it, the volatility for one minute is really low, so to risk 1% of your balance, you must open a very large lot size position.

Summary



I presented these three functions I used almost always in my algotrading code. It make my code safe to use and run 24/5 a week, recognize errors and prevent over leveraging my portfolio. On top of these functions I have separate error handling logic I didn`t present when this functions return a negative value. One trick I usually do is setting a value to the AccountMargin() and "putting" the EA to sleep until the margin changes, but I will cover error handling in another post.

Comments

  1. thanks
    My name is saeed
    can i ask you
    what code can be done to make hedge trade use lots2 or lots3 in each stop loss trade ?
    please help me to solve this problem .....

    ReplyDelete
  2. i mean lot * 2 lot * 3 multiply

    ReplyDelete
  3. Hi Saeed,

    Thank you for this question. The code which will do it is as follows:
    OrderSend(OrderSymbol(),OrderType(),(int)MathMax(2,StringToInteger(OrderComment()))*OrderLots(),OrderType()==OP_BUY?Ask:Bid,1,0,0,IntegerToString((int)MathMax(2,StringToInteger(OrderComment()))+1));

    So, assuming an order hit the stop loss, this code will open another order with the same values for the symbol and type. But, the lots will be multiply by the recent number which is saved in the order comment. So, the first order to be opened will be 2 * Lots. Then, the comment will store the value 3, so in the next iteration, the lots size will be multiplied by 3 and so on.

    I hope that answers your question,
    Roy

    ReplyDelete

Post a Comment