Hi,
So i'm trying to build a scalping system that watch the market in 5 minutes timeframe and execute trades based on simple algorithm, until here its all okay (I hope so), but when it comes to lot size its a bit tricky.
The formula i calculate lot size is:
willingToSpend = accountValue * .01 // IN THIS CASE I WANT TO RISK 1% OF MY TRADING ACCOUNT
stopLossDistance = willingToSpend / NUMBER_OF_PIPS
calculate = stopLossDistance / VALUE_PER_PIP // In this case my account is in euro and i do the math on what's the value per pip for EUR to USD // for example 0.88
And this calculates me lot size for example it prints 0.23.
But as a scalping strategy, this system sometimes executes trades even on distances lower than one pip for example .05 pip and this calculation return value of more then 1 lot. When it touches the TP the value of it is for example $3 profit that means 2 times lower or 3 times lower than 1% of the trading account, but when it touches SL it stops the SL of $20 or even higher that is 2 times to 3 times bigger that my account value.
But when the trade size more than one pip for example 4 pips (more than one pip SL), this calculation formula somehow it works well, not accurate but its close to the ammount.
So is there any other formula on how can i calculate this more accurately ?
P.S my formula of lot size is based on this: https://www.babypips.com/tools/positionsizecalculator
Show your code if you need coding help, not pseudo code.
How are you calculating the value per pip, most probably incorrectly ? If you need to convert using a cross you can't have exact value as the price of this cross when your position will be closed is unknown. You can also have slippage which will make your calculation inaccurate and also rounding. All in all don't expect to get the exact amount you want to risk.
Risk depends on your initial stop loss, lot size, and the value of the symbol. It does not depend on margin and leverage. No SL means you have infinite risk. Never risk more than a small percentage of your trading funds, certainly less than 2% per trade, 6% total.

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.

AccountBalance * percent/100 = RISK = OrderLots * (OrderOpenPrice  OrderStopLoss * DeltaPerLot + CommissionPerLot) (Note OOPOSL includes the spread, and DeltaPerLot is usually around $10/PIP but it takes account of the exchange rates of the pair vs. your account currency.)

Do NOT use TickValue by itself  DeltaPerLot and verify that MODE_TICKVALUE is returning a value in your deposit currency, as promised by the documentation, or whether it is returning a value in the instrument's base currency.
MODE_TICKVALUE is not reliable on nonfx instruments with many brokers  MQL4 programming forum (2017)
Is there an universal solution for Tick value?  Currency Pairs  General  MQL5 programming forum (2018)
Lot value calculation off by a factor of 100  MQL5 programming forum (2019) 
You must normalize lots properly and check against min and max.

You must also check FreeMargin to avoid stop out

For MT5, see 'Money Fixed Risk'  MQL5 Code Base (2017)
Most pairs are worth about $10 per PIP. A $5 risk with a (very small) 5 PIP SL is $5/$10/5 or 0.1 Lots maximum.
.
This is untested, uncompiled code, only to serve as a guide for you to further study and implement depending on your own requirements ...
// Calculate Max Lot Size based on Maximum Risk double dblLotsRisk( double dbStopLoss, double dbRiskRatio ) { double dbLotsMinimum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MIN ), dbLotsMaximum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MAX ), dbLotsStep = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP ), dbTickSize = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE ), dbTickValue = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_VALUE ), dbValueAccount = fmin( fmin( AccountInfoDouble( ACCOUNT_EQUITY ) , AccountInfoDouble( ACCOUNT_BALANCE ) ), AccountInfoDouble( ACCOUNT_MARGIN_FREE ) ), dbValueRisk = dbValueAccount * dbRiskRatio, dbLossOrder = dbStopLoss * dbTickValue / dbTickSize, dbCalcLot = fmin( dbLotsMaximum, // Prevent too greater volume fmax( dbLotsMinimum, // Prevent too smaller volume round( dbValueRisk / dbLossOrder // Calculate stop risk / dbLotsStep ) * dbLotsStep ) ); // Align to step value return ( dbCalcLot ); };
Show us your code. What is the value of your variables (#2.3 footnotes).
Hello William,
The code is already shown above by @ Fernando Carreiro. I used dRiskRatio form 5% to 50%.
My main problem was I couldn't understand what is going on when people added SL, Point, etc. to calculate the _volume_ of a trade.
In my opinion volume (in other word, Lots) has to account for margin and free equity, nothing else.
So I've come up with my own solution.
//++ // CalcLot.mq5  // Copyright 2023, MetaQuotes Ltd.  // https://www.mql5.com  //++ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property strict #property script_show_inputs input double dInpRisk = 5.0; // Risk percent //++ // Script program start function  //++ void OnStart() { double dLots; // Calculate Max Lot Size based on Maximum Risk //dLots = dLotsRisk( 50 * SymbolInfoDouble( Symbol(), SYMBOL_TRADE_TICK_SIZE ), 0.5 ); dLots = dGetLot( dInpRisk ); } //++ /*double dLotsRisk( double dStopLoss, double dRiskRatio ) { double dLotsMinimum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MIN ), dLotsMaximum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MAX ), dLotsStep = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP ), dTickSize = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE ), dTickValue = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_VALUE ), dValueAccount = fmin( fmin( AccountInfoDouble( ACCOUNT_EQUITY ), AccountInfoDouble( ACCOUNT_BALANCE ) ), AccountInfoDouble( ACCOUNT_MARGIN_FREE ) ), dValueRisk = dValueAccount * dRiskRatio, dLossOrder = dStopLoss * dTickValue / dTickSize, dCalcLot = fmin( dLotsMaximum, // Prevent too greater volume fmax( dLotsMinimum, // Prevent too smaller volume round( dValueRisk / dLossOrder // Calculate stop risk / dLotsStep ) * dLotsStep ) ); // Align to step value return ( dCalcLot ); };*/ double dGetLot( double dRisk ) { double dAccountValue, dAccountValueEffective, dLotMin, dLotMax, dLotStep, dCalcMargin, dLots, dFreeMargin; int i, iStepMax; bool bStat; string str; dAccountValue = MathMin( MathMin( AccountInfoDouble( ACCOUNT_EQUITY ), AccountInfoDouble( ACCOUNT_BALANCE ) ), AccountInfoDouble( ACCOUNT_MARGIN_FREE ) ); dAccountValueEffective = dRisk * dAccountValue / 100; dLotMin = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MIN ); dLotMax = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MAX ); dLotStep = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP ); dFreeMargin = AccountInfoDouble( ACCOUNT_MARGIN_FREE ); iStepMax = ( int ) MathRound ( ( dLotMax  dLotMin ) / dLotStep ); // FRA40: 999, EURUSD: 9999 ResetLastError(); for ( i = 0, dLots = dLotMin; i < iStepMax; i++, dLots += dLotStep ) { bStat = OrderCalcMargin( ORDER_TYPE_BUY, Symbol(), dLots, SymbolInfoDouble( Symbol(), SYMBOL_BID ), dCalcMargin); //free margin required for x lot! if ( bStat ) { str = "Calculated Margin = " + DoubleToString( dCalcMargin, 2 ); str += ", risk = " + DoubleToString( dRisk, 2 ); str += ", account value effective = " + DoubleToString( dAccountValueEffective, 2 ); str += ", current lot = " + DoubleToString( dLots, 2 ); if ( dFreeMargin < dCalcMargin  dCalcMargin > dAccountValueEffective ) { dLots = dLotStep; if ( dLots < dLotMin ) { dLots = dLotMin;str += ", minimum lot size used."; } if ( dLots > dLotMax ) { dLots = dLotMax;str += ", maximum lot size reached."; } Print( str, "\nOverstepping boundary, calculated lot size is ", DoubleToString( dLots, 2 ) ); return dLots; } else Print( str ); } else Print( "Margin calculation error, error code: ", IntegerToString( GetLastError() ) ); } return dLots; }
Initial testing looks promising.
Hello William,
The code is already shown above by @ Fernando Carreiro. I used dRiskRatio form 5% to 50%.
My main problem was I couldn't understand what is going on when people added SL, Point, etc. to calculate the _volume_ of a trade.
In my opinion volume (in other word, Lots) has to account for margin and free equity, nothing else.
So I've come up with my own solution.
Initial testing looks promising.
For further reference,
This worked for my pretty much flawlessly, I only tried it with the GBPJPY pair, but it should work for all/most of them.
I politely took some ideas from @Fernando Carreiro :)
double LotsToBuyPerLostPercentage( double entry_price, double stop_loss_price, double percentage_to_lose){ // Get Symbol Info double lots_maximum = SymbolInfoDouble( Symbol(), SYMBOL_VOLUME_MAX); double lots_minimum = SymbolInfoDouble( Symbol(), SYMBOL_VOLUME_MIN); double volume_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP); double tick_size = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE); double tick_value = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); // Get trade basic info double available_capital = fmin( fmin( AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE)), AccountInfoDouble(ACCOUNT_MARGIN_FREE)); double amount_to_risk = available_capital * percentage_to_lose / 100; double sl_distance = MathAbs(entry_price  stop_loss_price); // Get the Abs since it might be a short (EP < SL) // Calculate steps and lots double money_step = sl_distance / tick_size * tick_value * volume_step; double lots = fmin( lots_maximum, fmax(lots_minimum, NormalizeDouble(amount_to_risk / money_step, 2))); // The number 2 is due to my brokers volume step, depends on the currency pair return(lots); }
//++ // Calculate the appropriate volume for the trade operation planned. //  // ordertype : ORDER_TYPE_BUY or ORDER_TYPE_SELL only.  // symbol : Symbol name  // risk_money : Loss money when SL is hit, in account currency.  // price_open : Open price  // price_sl : Close price  // commission_lot : Comm. per lot per side, in account currency.  //++ double OrderCalcVolume(ENUM_ORDER_TYPE ordertype, string symbol, double risk_money, double price_open, double price_sl, double commission_lot = 0.0)
 www.mql5.com
double LotsToBuyPerLostPercentage( double entry_price, double stop_loss_price, double percentage_to_lose){ // Get Symbol Info double lots_maximum = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX); double lots_minimum = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN); double volume_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP); double tick_size = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_SIZE); double tick_value = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE); // Get trade basic info double available_capital = fmin( fmin( AccountInfoDouble(ACCOUNT_EQUITY), AccountInfoDouble(ACCOUNT_BALANCE)), AccountInfoDouble(ACCOUNT_MARGIN_FREE)); double amount_to_risk = available_capital * percentage_to_lose / 100; double sl_distance = MathAbs(entry_price  stop_loss_price); // Get the Abs since it might be a short (EP < SL) // Calculate steps and lots double money_step = sl_distance / tick_size * tick_value * volume_step; double lots = fmin( lots_maximum, fmax(lots_minimum, NormalizeDouble(amount_to_risk / money_step * volume_step, 2))); // The number 2 is due to my brokers volume step, depends on the currency pair return(lots); }
 Free trading apps
 Over 8,000 signals for copying
 Economic news for exploring financial markets
You agree to website policy and terms of use
Hi,
So i'm trying to build a scalping system that watch the market in 5 minutes timeframe and execute trades based on simple algorithm, until here its all okay (I hope so), but when it comes to lot size its a bit tricky.
The formula i calculate lot size is:
willingToSpend = accountValue * .01 // IN THIS CASE I WANT TO RISK 1% OF MY TRADING ACCOUNT
stopLossDistance = willingToSpend / NUMBER_OF_PIPS
calculate = stopLossDistance / VALUE_PER_PIP // In this case my account is in euro and i do the math on what's the value per pip for EUR to USD // for example 0.88
And this calculates me lot size for example it prints 0.23.
But as a scalping strategy, this system sometimes executes trades even on distances lower than one pip for example .05 pip and this calculation return value of more then 1 lot. When it touches the TP the value of it is for example $3 profit that means 2 times lower or 3 times lower than 1% of the trading account, but when it touches SL it stops the SL of $20 or even higher that is 2 times to 3 times bigger that my account value.
But when the trade size more than one pip for example 4 pips (more than one pip SL), this calculation formula somehow it works well, not accurate but its close to the ammount.
So is there any other formula on how can i calculate this more accurately ?
P.S my formula of lot size is based on this: https://www.babypips.com/tools/positionsizecalculator