Unusual Position Sizing Glitch: Seeking Insights on Unexpected 100-Lot Size Error

 
I've been experiencing an unusual issue with my trading system related to position sizing. While the system generally operates smoothly, there's an intermittent occurrence, happening about once or twice a month, where it attempts to place an order with a 100-lot size. My position size is determined by a function based on relative account equity, and it's calculated just before the order is executed. Everything seems to work as intended, but occasionally, I encounter an order failure with a '[money not enough]' error. The system then retries with the supposed lot size and succeeds.

Journal Log


I've checked the journal to investigate, and it appears that a 100-lot size trade was attempted but failed. Despite troubleshooting, I haven't been able to pinpoint the source of this 100-lot size anomaly. Has anyone experienced a similar issue or have ideas on where I should focus my efforts to resolve this error? 

Size calculation functions

double GetTradeSize(ENUM_RISK_MANAGEMENT_METHOD pRiskManagementMethod,ENUM_POS_SIZE_METHOD pPositionSizingMethod,string pSymbol,double pFixedVolume,double pRiskPercent,int pStopLossPoints){
        double tradeSize;
        // if (UseMoneyManagement == true)
        if (pPositionSizingMethod == RELATIVE_LOT_SIZE)
                tradeSize = MoneyManagement(pSymbol, pFixedVolume, pRiskPercent, pStopLossPoints);
        else if (pPositionSizingMethod == FIXED_LOT_SIZE)
                tradeSize = VerifyVolume(pSymbol, pFixedVolume);
        else 
                tradeSize = SymbolInfoDouble(pSymbol, SYMBOL_VOLUME_MIN);
        
        return tradeSize;
}
// Risk-based money management
double MoneyManagement(string pSymbol,double pFixedVol,double pPercent,int pStopPoints)
{
        double tradeSize;
        if(pPercent > 0 && pStopPoints > 0)
        {
                if(pPercent > MAX_PERCENT) pPercent = MAX_PERCENT;
                
                double margin = AccountInfoDouble(ACCOUNT_BALANCE) * (pPercent / 100);
                double tickSize = SymbolInfoDouble(pSymbol,SYMBOL_TRADE_TICK_VALUE);
                
                tradeSize = (margin / pStopPoints) / tickSize;
                tradeSize = VerifyVolume(pSymbol,tradeSize);
                
                return(tradeSize);
        }
        else
        {
                // tradeSize = pFixedVol;
                tradeSize = VerifyVolume(pSymbol,pFixedVol);
                return(tradeSize);
        }
}


Calling Lot size function

   double tradeSize = GetTradeSize(RiskManagementMethod,PositionSizingMethod,CurrentSymbol,FixedVolume,RiskPercent,StopLossPoints);

// Open trade function
// Open Trade
 
Your topic has been moved to the section: Expert Advisors and Automated Trading
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 

That is not the correct way to calculate volume. You are mixing up the concepts, especially about tick size and tick value.

Here are the correct equations ...

Forum on trading, automated trading systems and testing trading strategies

How to calculate take profit from currency

Fernando Carreiro, 2022.09.05 17:00

These are all the same equation written in different ways ...

[Volume]      = [Money Value] * [Tick Size] / ( [Tick Value] * [Stop Size] )
[Stop Size]   = [Money Value] * [Tick Size] / ( [Tick Value] * [Volume]    )
[Money Value] = [Volume]      * [Stop Size] * [Tick Value]   / [Tick Size]

[Volume] in lots
[Stop Size] in quote price change
[Money Value] in account currency

Forum on trading, automated trading systems and testing trading strategies

Symbol Point Value

Fernando Carreiro, 2022.05.18 21:05

double
   dbTickSize   = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_SIZE  ), // Tick size
   dbTickValue  = SymbolInfoDouble( _Symbol, SYMBOL_TRADE_TICK_VALUE ), // Tick value
   dbPointSize  = SymbolInfoDouble( _Symbol, SYMBOL_POINT ),            // Point size
   dbPointValue = dbTickValue * dbPointSize / dbTickSize;               // Point value

Remember, it's best to use tick size and tick value in your calculations, instead of point size and its value.


However, there is no need to calculate it yourself. MQL5 already has a function that does the calculations and adjusts depending on the asset class of the symbol.

Forum on trading, automated trading systems and testing trading strategies

Confused about tickvalue

Fernando Carreiro, 2023.04.26 13:27

This site has something called "search" ... https://www.mql5.com/en/search#!keyword=OrderCalcProfit%20calculate%20volume&module=mql5_module_forum

To calculate the correct volume for your trade, you should ...

  1. Use the OrderCalcProfit to first obtain the correct volume based on your stop-loss size and percentage risk.
  2. Adjust the volume, based on the contract specifications
  3. Use the OrderCalcMargin to verify that the volume is within the margin limits and requirements, and if not, then either reduce the volume or abort the trade.
  4. And finally, before placing the order, use OrderCheck to make sure everything is in valid.

Forum on trading, automated trading systems and testing trading strategies

P&L calculation formula for different traded assets

Fernando Carreiro, 2023.05.04 14:53

I suggest reading up on the following two MQL5 trade functions ...

OrderCalcMargin

Calculates the margin required for the specified order type, in the deposit currency

OrderCalcProfit

Calculates the profit based on the parameters passed, in the deposit currency

They calculate the margin and the profit/loss respectively, adjusting automatically for the asset type, making it unnecessary to calculate it manually using the methods you have described.

They do however, not include Commission or Swaps. Those are only provided after the fact and are accessible via other functionality — Documentation on MQL5: Trade Functions

Forum on trading, automated trading systems and testing trading strategies

SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) sometimes zero

Fernando Carreiro, 2022.08.23 17:41

You can! These are the steps I take. I supply the function with a lot size equal to the “Max Lot Size” allowed for the symbol in question, then calculate the ratio needed to achieve the fractional risk that I wish to apply, to get the correct volume for the order. I then align that with the “Lot Step” and finally check it against both the maximum and minimum allowed lots for the symbol.

The reason I use the “maximum” lots instead of just “1.0” lots as a reference value is because there is no guarantee that the value of 1.0 is within the minimum and maximum values allowed. Given that using 1.0, or the maximum, gives equivalent results anyway (by using the ratio method), I choose to use the “max lots” as the reference point which also offers the most precision for the calculation.

Something like this ...

// This code will not compile. It is only a example reference

if( OrderCalcProfit( eOrderType, _Symbol, dbLotsMax, dbPriceOpen, dbPriceStopLoss, dbProfit ) )
{
   dbOrderLots = fmin( fmax( round( dbRiskMax * dbLotsMax / ( -dbProfit * dbLotsStep ) )
               * dbLotsStep, dbLotsMin ), dbLotsMax ); 
      
   // the rest of the code ...
};

Forum on trading, automated trading systems and testing trading strategies

Market Registration of EA Unable to Validate

Fernando Carreiro, 2022.08.30 14:20

For your screenshot with an Error 131 and it also has a link on "How to fix it". So follow up on it and fix your EA accordingly.

In regards to volume, you have to check the contract specification of the symbol and limit your volume to the minimum, maximum and step that is allowed for the symbol.

// Variables for symbol volume conditions
   double
      dbLotsMinimum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MIN  ),
      dbLotsMaximum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MAX  ),
      dbLotsStep    = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP );
       
// Adjust volume for allowable conditions
   dbLots = fmin(  dbLotsMaximum,                           // Prevent too greater volume
            fmax(  dbLotsMinimum,                           // Prevent too smaller volume
            round( dbLots / dbLotsStep ) * dbLotsStep ) );  // Align to step value
Reason: