Need moneymanagement LOT size formula based on SL and Account Risk! - page 3

 

OK guys! This code was written by me and it is what I use in my own EA's. It is quite complex because, besides the Risk% and StopLoss, it also takes into account the Margin Risk% as well as correct the Lot Size based on Minimum, Maximum and Step Size. It also always uses the minimum value of Current Balance and Equity instead of just using one of them. I feel it is safer that way.

Please note, however, that it does not use the spread in the calculation, because I calculate that separately when calculating the StopLoss to be used. The below function, thus uses a relative stop loss size. In my EA's the argument dblStopLossPips is calculated beforehand depending on various factors such as the strategy, spread, ATR, etc.; so the final value passed on to the dblLotsRisk() function is already a final value in order to calculate the Lot size to be used.

// Function to Determine Tick Point Value in Account Currency

        double dblTickValue( string strSymbol )
        {
                return( MarketInfo( strSymbol, MODE_TICKVALUE ) );
        }
        

// Function to Determine Pip Point Value in Account Currency

        double dblPipValue( string strSymbol )
        {
                double dblCalcPipValue = dblTickValue( strSymbol );
                switch ( MarketInfo( strSymbol, MODE_DIGITS ) )
                {
                        case 3:
                        case 5:
                                dblCalcPipValue *= 10;
                                break;
                }
                
                return( dblCalcPipValue );
        }
        

// Calculate Lot Size based on Maximum Risk & Margin

        double dblLotsRisk( string strSymbol, double dblStopLossPips,
                double dblRiskMaxPercent, double dblMarginMaxPercent,
                double dblLotsMin, double dblLotsMax, double dblLotsStep )
        {
                double
                        dblValueAccount = MathMin( AccountEquity(), AccountBalance() )
                ,       dblValueRisk    = dblValueAccount * dblRiskMaxPercent / 100.0
                ,       dblValueMargin  = AccountFreeMargin() * dblMarginMaxPercent / 100.0
                ,       dblLossOrder    = dblStopLossPips * dblPipValue( strSymbol )
                ,       dblMarginOrder  = MarketInfo( strSymbol, MODE_MARGINREQUIRED )
                ,       dblCalcLotMin
                                = MathMax( dblLotsMin, MarketInfo( strSymbol, MODE_MINLOT ) )
                ,       dblCalcLotMax
                                = MathMin( dblLotsMax, MarketInfo( strSymbol, MODE_MAXLOT ) )
                ,       dblModeLotStep  = MarketInfo( strSymbol, MODE_LOTSTEP )
                ,       dblCalcLotStep  = MathCeil( dblLotsStep / dblModeLotStep ) * dblModeLotStep
                ,       dblCalcLotLoss
                                = MathFloor( dblValueRisk / dblLossOrder / dblCalcLotStep ) * dblCalcLotStep
                ,       dblCalcLotMargin
                                = MathFloor( dblValueMargin / dblMarginOrder / dblCalcLotStep ) * dblCalcLotStep
                ,       dblCalcLot = MathMin( dblCalcLotLoss, dblCalcLotMargin )
                ;
                
                if ( dblCalcLot < dblCalcLotMin ) dblCalcLot = dblCalcLotMin;
                if ( dblCalcLot > dblCalcLotMax ) dblCalcLot = dblCalcLotMax;

                return ( dblCalcLot );
        }
 
GumRai:

This gives me a headache just trying to work out the brackets!

To be honest, I have absolutely no idea what it is that you are trying to achieve here.

I can't see how MODE_STOPLEVEL or SPREAD are relevant, surely you should be basing your calculations on the stop-loss distance from current price?

It should make no difference what the account currency is, calculation should be the same because TICKVALUE is in the account currency.

Please note, by putting your line of code on 2 lines, the post is not so wide and makes it easier to read without scrolling right and left :)

I posted a few pages back, a picture in which i illustrated my formula how to calculate the lot.But the pipvalue or tickvalue or whatever is always messing around.Quote->base currency and other things which are confusing, but so far my formula did a good job, although i`m not sure its correct.

The SPREAD may be irrelevant, but the stoplevel is necessary. I put the SL as closest possible to the orderopenprice which is the stoplevel, but due to fluctuations and spikes, i need to manually adjust it sometimes,that is why i put a STOPSLIP variable with which i can adjust the SL to the volatility or whatever.

FMIC:

OK guys! This code was written by me and it is what I use in my own EA's. It is quite complex because, besides the Risk% and StopLoss, it also takes into account the Margin Risk% as well as correct the Lot Size based on Minimum, Maximum and Step Size. It also always uses the minimum value of Current Balance and Equity instead of just using one of them. I feel it is safer that way.

Please note, however, that it does not use the spread in the calculation, because I calculate that separately when calculating the StopLoss to be used. The below function, thus uses a relative stop loss size. In my EA's the argument dblStopLossPips is calculated beforehand depending on various factors such as the strategy, spread, ATR, etc.; so the final value passed on to the dblLotsRisk() function is already a final value in order to calculate the Lot size to be used.

Thanks, i will test it and tell my feedback!

Although i dont understand why you put so many variables there, the entire code can be fitted into 1 line :)

 
Proximus:

I posted a few pages back, a picture in which i illustrated my formula how to calculate the lot.But the pipvalue or tickvalue or whatever is always messing around.Quote->base currency and other things which are confusing, but so far my formula did a good job, although i`m not sure its correct.

The SPREAD may be irrelevant, but the stoplevel is necessary. I put the SL as closest possible to the orderopenprice which is the stoplevel, but due to fluctuations and spikes, i need to manually adjust it sometimes,that is why i put a STOPSLIP variable with which i can adjust the SL to the volatility or whatever.

Thanks, i will test it and tell my feedback!

Although i dont understand why you put so many variables there, the entire code can be fitted into 1 line :)


Yes the code could all be put into one line, but trust me, it is NEVER a good way to code, unless you are trying to squeeze every last CPU cycle out of your code to be the fastest on the planet.

That is why "GumRai" complained about getting a headache trying to make head or tail of the other code. It simply was not very readable or easily understood and that makes it very difficult to debug.

My way may be more verbose but it is easier to debug and maintain as well as more readable and easier to understand by others such as yourself.

But feel free to compact it all into one line. Just don't complain if it does not quite give the same results. I will leave it up to you to debug THAT.

 

Sorry for reopening this thread but its crucial to confirm something, so this is the function that i came up with (i`m putting it public you can thank me later):

double LOTUNITSTORISK()
{
double LOTS=((AccountBalance()*RISKPERCENT/100) / (  MarketInfo(Symbol(), MODE_TICKVALUE)*MarketInfo(Symbol(), MODE_TICKSIZE)*STOPSIZE     ));
return LOTS;
}


This function should return the lot units based on account risk, and calculated via an EUR account, since the EUR is always base currency.

Lot unit means = the actual money size of a position so for a 100 € account of 1% risk it should return 1€ which based on the STOPLOSS for example a 100 pipette stoploss should be 1000 lot units ( 0.01 LOT IN MT4 EQUIVALENT)

It critical that the account currency is EURO, nothing else.

Once we call the LOTUNITTORISK(), we shall divide the results by 100.000 to get the actual lot size in MT4 format (1000 cash unit 0.01 LOT in MT4)

RISKPERCENT =is an int and it can be 1,2,3,4 the risk % that we risk

STOPSIZE = is an int and its the number of pipettes (pips/10 on 5 digit broker) that our stoploss size is, so for example 60 pipette SL is a 6 pip SL

I want to know if the function does calculate the LOT UNITS properly, please test it and if you find any mistake please help me :)

A thousand thanks!

 
Proximus:
MarketInfo(Symbol(), MODE_TICKVALUE)*MarketInfo(Symbol(), MODE_TICKSIZE)*STOPSIZE

Risk  = lotsize * StopSize * TickValue / TickSize
         1      *  0.0100  *  $10.00   / 0.0001
$1000 = one lot * 100 pips *  $10.00   / pip
  1. You place the stop where it needs to be - where the reason for the trade is no longer valid. E.g. trading a support bounce the stop goes below the support.
  2. Account Balance * percent = RISK = (OrderOpenPrice - OrderStopLoss)*DIR * OrderLots * DeltaPerlot (Note OOP-OSL includes the SPREAD)
  3. Do NOT use TickValue by itself - DeltaPerlot
  4. You must also check FreeMargin to avoid stop out
 
WHRoeder:
  1. You place the stop where it needs to be - where the reason for the trade is no longer valid. E.g. trading a support bounce the stop goes below the support.
  2. Account Balance * percent = RISK = (OrderOpenPrice - OrderStopLoss)*DIR * OrderLots * DeltaPerlot (Note OOP-OSL includes the SPREAD)
  3. Do NOT use TickValue by itself - DeltaPerlot
  4. You must also check FreeMargin to avoid stop out

1) The function only returns the LOT SIZE in money unit not MT4 unit nothing else, when i put the orders then respectively the STOPSIZE it will be added /sustracted from Bid in case of BUY and Ask in case of sell.It is just as MT4 handles the TP and SL.

BUY opened at ASK, closed at BID

SELL opened at BID, closed at ASK

2) I cannot use OrderOpenprice man because no order is opened before this function is calculated.Spreads not included, spreads will be handled when i add/substract the STOPSIZE after the order is opened.

But before that we need to determine the lot size, thats logical.

3) I dont understand this.

4) Obviously, but i emphasize again the order placement function is ran after this, and has little to do with this function.The only purpose this function has is to determine the lot size, nothing else.


TickValue / TickSize

Incorrect, if i divide them then i get the wrong number, maybe for USD accounts should be done so, but its an EUR account.They must be multiplied.

 
Proximus:

BUY opened at ASK, closed at BID SELL opened at BID, closed at ASK

2) I cannot use OrderOpenprice

3) I dont understand this.

4)t, if i divide them then i get the wrong number, maybe for USD accounts should be done so, but its an EUR account.They must be multiplied.

  1. The Ask is the OrderOpenPrice for a buy
  2. The Bid is the OrderOpenPrice for a sell. Why can't you use it, you have to know it to pass it to OrderSend?
  3. You MUST use tickvalue/ticksize. Tickvalue by itself is meaningless.
  4. You MUST divide to get the units correct (Change in price) * (tickValue) /(change in price) gives you a value. $10 per pip = $1 per point = value/change. Remember the result in is account currency so when you divide it by your risk you get lots a pure number, again the units cancel $risk(BAL%)/$risk(SL). If you have to multiple you're doing something wrong or the brokers values are messed up.
 
WHRoeder:
Proximus:

BUY opened at ASK, closed at BID SELL opened at BID, closed at ASK

2) I cannot use OrderOpenprice

3) I dont understand this.

4)t, if i divide them then i get the wrong number, maybe for USD accounts should be done so, but its an EUR account.They must be multiplied.

  1. The Ask is the OrderOpenPrice for a buy
  2. The Bid is the OrderOpenPrice for a sell. Why can't you use it, you have to know it to pass it to OrderSend?
  3. You MUST use tickvalue/ticksize. Tickvalue by itself is meaningless.
  4. You MUST divide to get the units correct (Change in price) * (tickValue) /(change in price) gives you a value. $10 per pip = $1 per point = value/change. Remember the result in is account currency so when you divide it by your risk you get lots a pure number, again the units cancel $risk(BAL%)/$risk(SL). If you have to multiple you're doing something wrong or the brokers values are messed up.


1,2 I know that, but understand me that that is handled by another function it has nothing to do with this one

3) As i understand the tickvalue is the value of 1 pip in the base currency, so depending on what pair i use it will either have to divide or multiply by it.In case of an EUR account it seems like we have to multiply not divide.

Here is a pic which ilustrates it better:


On the EUR/USD for a  3% risk trade we need to open 1798 units, rounded 0.02 LOTS in MT4 units to achieve that.

The STOPLOSS size is determined by another function.

It seems to be correct as i tested it but i`m not sure if the formula is really precise, that is what i am trying to determine here, so please help on that.

 

I too have been trying to figure out this lot size calculation based on SL, account risk AND Margin Call Level especially when the Margin Call Level is not 100% but is for example, 120%. The best answer I've found is what WHRoeder shared here in his whrea.mq4 code.  The whrea.mq4 code needed some correction but WHRoeder already gaves that correction here in his answer to RaptorUK's comment. So the complete answer to calculating lot size is there but some effort is required to fully understand what WHRoeder has shared.

I attached the code I extracted and modified code from WHRoeder's whrea.mq4 to compile with the latest new MT4 build to calculate lot size for a long trade where the Margin Call Level is more than 100%.

However, I'm not sure if multiplying by the MarginCallLevel % is correct to take the Margin Call Level % into account for avoiding a margin call. If the MarginCallLevel is 100% then both lines of code would be correct, but if the MarginCallLevel is 120%, would multiplying by the MarginCallLevel % be a correct Margin Call test? If not, then what is the correct way to do this? WHRoeder, can you help with this? William, I tried my best.

Here is the code from that Margin Test section for a Long trade:

extern double MarginCallLevel = 120; //As a percentage

double MarginCallLevel1 = MarginCallLevel * 0.01; 

        double  AFMC    = AccountFreeMarginCheck(Symbol(), OP_BUY, tradesize),
                        eRisk   = equityatrisk + atrisknew;

        //Test for margin
        //Note: Not sure if multiplying by the MarginCallLevel % here is correct to 
        //take the Margin Call Level % into account for avoiding a margin call.
        //If the MarginCallLevel is 100% then both lines of code would be correct
        //but if the MarginCallLevel is 120% would multiplying by the MarginCallLevel %
        //be a correct Margin Call test? If not, then what is the correct way to do this?

        //if (AFMC*0.99 <= eRisk){
        if (AFMC*0.99 <= eRisk*MarginCallLevel1){
            tradesize *= 0.95;    // Must still round to lotStep.
            continue;   }   // Prevent margin call if new trade goes against us.
Files:
 

... in this part of code is a problem with new compilation (error ---> 'MarketInfo' - illegal switch expression type) perhaps it was all OK until the update to MT4 build 600+ ... but since then it doesn't work any longer.

// Function to Determine Pip Point Value in Account Currency

        double dblPipValue( string strSymbol )
        {
                double dblCalcPipValue = dblTickValue( strSymbol );
                switch ( MarketInfo( strSymbol, MODE_DIGITS ) )
                {
                        case 3:
                        case 5:
                                dblCalcPipValue *= 10;
                                break;
                }
                
                return( dblCalcPipValue );
        }
        

 So, could you please post some newer version ... if  of course you're still around.


Reason: