Position Sizing with Stop Loss and Take Profit calculations

 

I keep getting error 10014 and/or 10016 related to the correct volume and/stop. Pls assist, i have read almost all blogs pertaining this :D

//+------------------------------------------------------------------+
//| Calculate Stop Loss                                              |
//+------------------------------------------------------------------+
double CalculateStopLoss()
{
    int orderDirection  = DetermineOrderDirection();
    double highestHigh  = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, slLengthA, 0));
    double lowestLow    = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, slLengthB, 0));
    long stopLevel      = (int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
    int symbolDigits    = (int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
    double priceLevel   = stopLevel * SymbolInfoDouble(_Symbol,SYMBOL_POINT);
    double askPrice     = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
    double bidPrice     = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    long spreadPoints   = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    double spreadPrice  = spreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double closePrice   = iClose(_Symbol, _Period, 0);

    if (orderDirection == Long)
    {
        double stopLoss = highestHigh + MathAbs(closePrice - highestHigh - spreadPrice) * slMultiplierA - stopLossTicks;

        if (stopLoss == EMPTY_VALUE)
        {
            PrintFormat("Failed to calculate Long stop loss. Check conditions or function implementation.");
        }
        else
        {
            PrintFormat("Long stop loss calculated.");
        }

        return stopLoss;
    }

    if (orderDirection == Short)
    {
        double stopLoss = lowestLow - MathAbs(closePrice - lowestLow + spreadPrice) * slMultiplierB + stopLossTicks;

        if (stopLoss == EMPTY_VALUE)
        {
            PrintFormat("Failed to calculate Short stop loss. Check conditions or function implementation.");
        }
        else
        {
            PrintFormat("Short stop loss calculated.");
        }
            
        return stopLoss;
    }

    PrintFormat("Invalid order direction. Check conditions or function implementation.");
    return EMPTY_VALUE;
}
//+------------------------------------------------------------------+
//| Calculate Take Profit                                            |
//+------------------------------------------------------------------+
double CalculateTakeProfit()
{
    double takeProfit;
    int orderDirection  = DetermineOrderDirection();
    int priceType       = takeProfitPriceType; 
    double highestHigh  = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, tpLengthA, 0));
    double lowestLow    = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, tpLengthB, 0)); 
    double closePrice   = iClose(_Symbol, _Period, 0);
    long spreadPoints   = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    double spreadPrice  = spreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT);

    if (orderDirection == Long)
    {
        // Calculate takeProfit
        takeProfit = closePrice + MathAbs(closePrice - highestHigh) * tpMultiplierLong + tpTicks + spreadPrice;
        PrintFormat("Long take profit calculated.");
    }
    else if (orderDirection == Short)
    {
        // Calculate takeProfit
        takeProfit = closePrice - MathAbs(closePrice - lowestLow) * tpMultiplierShort - tpTicks - spreadPrice;
        PrintFormat("Short take profit calculated.");
    }
    else
    {
        PrintFormat("Invalid order direction. Check conditions or function implementation.");
        return EMPTY_VALUE;
    }

    return takeProfit;
}
//+------------------------------------------------------------------+
//| Calculate Position Size                                          |
//+------------------------------------------------------------------+
double CalculatePositionSize()
{
    // Calculate Position & Volume
    double stopLoss      = CalculateStopLoss();
    double accBalance    = AccountInfoDouble(ACCOUNT_BALANCE);
    double tickValue     = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);        
    double riskAmount    = (riskPercentage / 100.0) * accBalance;
    double lotSizeStep   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
    double minVolume     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    double maxVolume     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double positionSize  = MathRound(riskAmount / stopLoss / tickValue) * lotSizeStep;    
    int stepRatio        = (int)MathRound(positionSize/lotSizeStep);

    // Validate positionSize against min and max allowed volumes
    if (positionSize < minVolume)
    {
        PrintFormat("Position size is less than the minimum allowed SYMBOL_VOLUME_MIN=%.2f", minVolume);
        return false;
    }
    if (MathAbs(stepRatio * lotSizeStep - positionSize) > 0.0000001)
    {
        PrintFormat("Position size is greater than the maximum allowed SYMBOL_VOLUME_MAX=%.2f", maxVolume);
        return false;
    }

    return positionSize;
}
 

10014

TRADE_RETCODE_INVALID_VOLUME

Invalid volume in the request

10015

TRADE_RETCODE_INVALID_PRICE

Invalid price in the request


Even if it is not for market product, the following still applies. Please read it and implement it in your code ...

Articles

The checks a trading robot must pass before publication in the Market

MetaQuotes, 2016.08.01 09:30

Before any product is published in the Market, it must undergo compulsory preliminary checks in order to ensure a uniform quality standard. This article considers the most frequent errors made by developers in their technical indicators and trading robots. An also shows how to self-test a product before sending it to the Market.

Also see the following ...


 
Hello!
I think that you set stop loss above open price for long and below open price for short.
Also volume size should be normalized.
Your method CalculatePositionSize() returns double values, don't return false value.
 
Thanks Anton Ohurtsov, i dont know how that missed my eyes. Helped allot!
Anton Ohurtsov
Anton Ohurtsov
  • 2024.01.30
  • www.mql5.com
Trader's profile
 
K Maniam #:
Thanks Anton Ohurtsov, i dont know how that missed my eyes. Helped allot!
You're welcome
 

i simplified it to this and im still getting 10016 : invalid stops


//+------------------------------------------------------------------+
//| Calculate Stop Loss                                              |
//+------------------------------------------------------------------+
double CalculateStopLoss()
{
    double stopLoss     = 0.0;
    int orderDirection  = DetermineOrderDirection();
    double highestHigh  = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, slLengthB, 0));
    double lowestLow    = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, slLengthA, 0));
    long stopLevel      = SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
    long symbolDigits   = SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
    double priceLevel   = stopLevel * SymbolInfoDouble(_Symbol,SYMBOL_POINT);
    double askPrice     = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
    double bidPrice     = SymbolInfoDouble(_Symbol, SYMBOL_BID);
    long spreadPoints   = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    double spreadPrice  = spreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double closePrice   = iClose(_Symbol, _Period, 0);

      if (orderDirection == Long)
    {
        stopLoss = closePrice - MathAbs(((closePrice - lowestLow) * slMultiplierA) - stopLossTicks + spreadPrice);
    }
    else if (orderDirection == Short)
    {
        stopLoss = closePrice + MathAbs(((closePrice - highestHigh) * slMultiplierB) + stopLossTicks - spreadPrice);
    }

    if (stopLoss == 0.0)
    {
        PrintFormat("Failed to calculate stop loss. Check conditions or function implementation. OrderDirection: %d", orderDirection);
    }

    return NormalizeDouble(stopLoss,_Digits);
}
//+------------------------------------------------------------------+
//| Calculate Take Profit                                            |
//+------------------------------------------------------------------+
double CalculateTakeProfit()
{
    double takeProfit   = 0.0;
    int orderDirection  = DetermineOrderDirection();
    double highestHigh  = iHigh(_Symbol, _Period, iHighest(_Symbol, _Period, MODE_HIGH, tpLengthA, 0));
    double lowestLow    = iLow(_Symbol, _Period, iLowest(_Symbol, _Period, MODE_LOW, tpLengthB, 0)); 
    double closePrice   = iClose(_Symbol, _Period, 0);
    long spreadPoints   = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    double spreadPrice  = spreadPoints * SymbolInfoDouble(_Symbol, SYMBOL_POINT);

    if (orderDirection == Long)
    {
        // Calculate takeProfit
        takeProfit = closePrice + MathAbs((closePrice - highestHigh) * tpMultiplierLong) + tpTicks + spreadPrice;
    }
    else if (orderDirection == Short)
    {
        // Calculate takeProfit
        takeProfit = closePrice - MathAbs((closePrice - lowestLow) * tpMultiplierShort) - tpTicks - spreadPrice;
    }
    else
    {
        PrintFormat("Invalid order direction. Check conditions or function implementation.");
        return 0.0;
    }
    
    return NormalizeDouble(takeProfit,_Digits);
}
//+------------------------------------------------------------------+
//| Calculate Position Size                                          |
//+------------------------------------------------------------------+
double CalculatePositionSize()
{
     double accBalance = AccountInfoDouble(ACCOUNT_BALANCE);
     double riskAmount = accBalance * riskPercentage / 100;

     if(riskAmount == 0)
     {
         PrintFormat("ERROR: Get data from broker's server failed. (0)");
         return 0;
     }

     return riskLots(riskAmount);

}
//+------------------------------------------------------------------+
//| Get distance between stop loss and open price                    |
//+------------------------------------------------------------------+
double GetDistance()
{
     // Function return variable
     double askPrice                = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double lotStep                 = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
     double stopLossPrice           = CalculateStopLoss();
     double normalizedOpenPrice     = NormalizeDouble(askPrice, _Digits);
     double normalizedStopLossPrice = NormalizeDouble(stopLossPrice, _Digits);   
     double distance                = MathAbs(normalizedOpenPrice - normalizedStopLossPrice);

     return distance;
}
//+------------------------------------------------------------------+
//| Calculate Max Lot Size based on Maximum Risk                     |
//+------------------------------------------------------------------+
double riskLots(double riskAmount)
{
   double riskRatio    = riskPercentage / 100;
   double minLots      = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLots      = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep      = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double tickSize     = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue    = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); 
   double accountValue = fmin(fmin(AccountInfoDouble(ACCOUNT_EQUITY),AccountInfoDouble(ACCOUNT_BALANCE)),AccountInfoDouble(ACCOUNT_MARGIN_FREE));
   double riskValue    = accountValue * riskRatio;
   double orderRisk    = riskAmount * tickValue / tickSize;
   double calculateLot = fmin(maxLots,fmax(minLots,round(riskValue / orderRisk / lotStep) * lotStep));       

   return NormaliseLots(calculateLot);
}
//+------------------------------------------------------------------+
//| Lot size normalizer, round (floating point) numbers.             |                            |
//+------------------------------------------------------------------+
double NormaliseLots(double lots)
{
     double lotsMinimum = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
     double lotsMaximum = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
     double lotStep     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   
     // Prevent too greater volume. Prevent too smaller volume. Align to Step value
     return fmin(lotsMaximum, fmax(lotsMinimum, round(lots / lotStep) * lotStep));
}