Lot calculation based on risk percentage does not work on indices

 
   loss = (SLpips / (MarketInfo(Symbol(),MODE_TICKSIZE)*MathPow(10,Digits)))*MarketInfo(Symbol(),MODE_TICKVALUE);

   risk = AccountEquity() * RiskPercentage/100;

   lots = NormalizeDouble(risk/loss,xx);

SLpips is the sl in pips. RiskPercentage can be equal to 2 for example. xx can either be 1 or 2 depending on the broker's lotstep.

The ideea behind the code goes like this:

I have a 200 pips sl. On a pair like EURUSD the price must move up 0.0001 200 times in order to hit my stop loss for a short order. Because the ticksize on EURUSD is 0.0001 the price will move 200 ticks against me before hitting my SL. I multiply that number, 200 with the TICKVALUE and get what I would expect to lose with my 200 pips sl if I'd open a lot right now. However I want to lose a set ammount which is represented by the risk variable. In order to obtain the number of lots I need in order to lose that exact amount I divide my ammount by the 1 lot ammount. On EURUSD i get the exact number and the calculation is fine. The same thing happens with all the pairs in which the ticksize actually represents the smallest value a price can move,

With indices such as ftse and others, the ticksize is not ending in 1. For example, on the ava fx platform, the ftse can only move in 0.5 incrementations. A pip is still 0.1, but the ticksize is 0.5 Therfore if I add a SL of 200 pips the price must move up against me 40 ticks before it will reach my SL. Remember that with each tick the price covers 0.5 and not 0.1 Therfore after 40 ticks the price wil have went up 0.1 200 times or 0.5 40 times. In order to find out how much I can lose when trading a full lot I multiply the number of ticks with the tickvalue and obtain the ammount I would lose if I would trade a full lot. 40 ticks * 50 (tick value per lot) = 2000$ In practice however, me oppening a trade of one lot and losing it does not result in a 2000$ loss but something else... This is what happens when the expert places its orders too... It thinks that it will lose 200$ (2 percent of 10000) but it actually loses 340 something....

I've tried some different code I found here on mql forums but I could not get it to work correctly on indices. Do you have any ideea about what the heck is going on? What am I missing? How can I calculate the lot value so that when I open trades on indices I lose a predefined sum of money (x% out of balance)? Please help. Thank you for your time.

 

This may help => https://www.mql5.com/en/code/8583

Notes:
1) "avd.VARLimit" is a value of risk for the single order;
2) "avi.VARPoints" is a stop-loss in points.

 

Thanks for your input. On the FTSE100 (on the ava fx platform), your code, just like mine, gives a lot output of 0.33 for a 60 points SL and a 200$ risk value. However, in practice the order with a SL of 60 points and a volume of 0.33 loses 320$ and not 200$.

Any other ideeas as to what am I missing?

 
Need to test on USD account.
And some symbols of some brokers may have obvious miscounts in definitions.
Need to check all "MarketInfo(...)" data.
 
//+------------------------------------------------------------------+
//| Lot size computation.                                            |
//+------------------------------------------------------------------+
void    OnInitLotSize(){        at.risk.equity = 0;             at.risk.chart = 0;      }
double  LotSize(double risk){
/*double    at.risk.new;                        // Export to init/start
//double    TEF.value,                          // Import from ComputeTEF
//          at.risk.equity                      // Import from ModifyStops
//double    at.risk.chart;                      // Import from ModifyStops
//int       op.code; // OP_BUY/OP_SELL          // Import from SetDIR */
    /* This function computes the lot size for a trade.
     * Explicit inputs are SL relative to bid/ask (E.G. SL=30*points,)
     * Implicit inputs are the MM mode, the MM multiplier, count currently
     * filled orders by all EA's vs this EA/pair/period count and history.
     * Implicit inputs are all used to reduce available balance the maximum
     * dollar risk allowed. StopLoss determines the maximum dollar risk possible
     * per lot. Lots=maxRisk/maxRiskPerLot
     **************************************************************************/
    /*++++ Compute lot size based on account balance and MM mode*/{
    double  ab  = AccountBalance() - at.risk.equity;
    switch(MM.F0M1G2){
    case MMMODE_FIXED:                                              double
        minRisk = MM.PerTrade,
        maxRisk = MM.MaxRisk;
        break;
    case MMMODE_MODERATE:
        // See https://www.mql5.com/en/articles/1526 Fallacies, Part 1: Money
        // Management is Secondary and Not Very Important.
        maxRisk = MathSqrt(MM.MaxRisk  * ab);
        minRisk = MathSqrt(MM.PerTrade * ab);
        break;
    case MMMODE_GEOMETRICAL:
        minRisk = MM.PerTrade * ab;
        maxRisk = MM.MaxRisk  * ab;
        break;
    }
        ComputeTEF();
    double  minLot  = MarketInfo(Symbol(), MODE_MINLOT),
            lotStep = MarketInfo(Symbol(), MODE_LOTSTEP),
            perLotPerPoint  = PointValuePerLot(),
            maxLossPerLot   = (risk+Slippage.Pips*pips2dbl) * perLotPerPoint,
            size = minRisk / maxLossPerLot; // Must still round to lotStep.
    /*---- Compute lot size based on account balance and MM mode*/}
    /* The broker doesn't care about the at.risk/account balance. They care
     * about margin. Margin used=lots used*marginPerLot and that must be less
     * than free margin available. Using the lesser of size vs
     * AccountFreeMargin / MODE_MARGINREQUIRED should have been sufficient, but
     * the tester was generating error 134 even when marginFree should have been
     * OK. So I also use AccountFreeMarginCheck < 0 which agrees with the
     * tester. Reported at https://forum.mql4.com/35056
     *
     * Second problem, after opening the new order, if free margin then drops to
     * zero we get a margin call. In the tester, the test stops with: "EA:
     * stopped because of Stop Out" So I make sure that the free margin
     * after is larger then the equity risk so I never get a margin call. */
    string status = "SL>AE";                            // Assume size < minLot
    while (true){   // Adjust for broker, test for margin, combine with TEF...
        size = MathFloor(MathMax(0.,size)/lotStep)*lotStep;
        at.risk.new = size * maxLossPerLot;             // Export for Comment
        if (size < minLot){ at.risk.new = 0;    EA.status = status; return(0); }

        double  AFMC    = AccountFreeMarginCheck(Symbol(), op.code, size),
                eRisk   = at.risk.equity + risk*size*perLotPerPoint;
                /* at.risk.equity += Direction( OrderType() )
                 *              * (OrderClosePrice()-OrderStopLoss())*perPoint;
                 * Summed for all open orders. */
        if (AFMC*0.99 <= eRisk){    size *= 0.95;   status = "Free Margin";
            continue;   }   // Prevent margin call if new trade goes against us.
        break;
    }
    return(size);   // We're good to go.
}   // LotSize
double  PointValuePerLot() { // Value in account currency of a Point of Symbol.
    /* In tester I had a sale: open=1.35883 close=1.35736 (0.00147)
     * gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
     * IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
     * IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
     *                                  $1.00/point or $10.00/pip.
     *
     * https://forum.mql4.com/33975 CB: MODE_TICKSIZE will usually return the
     * same value as MODE_POINT (or Point for the current symbol), however, an
     * example of where to use MODE_TICKSIZE would be as part of a ratio with
     * MODE_TICKVALUE when performing money management calculations which need
     * to take account of the pair and the account currency. The reason I use
     * this ratio is that although TV and TS may constantly be returned as
     * something like 7.00 and 0.00001 respectively, I've seen this
     * (intermittently) change to 14.00 and 0.00002 respectively (just example
     * tick values to illustrate). */
    return(  MarketInfo(Symbol(), MODE_TICKVALUE)
           / MarketInfo(Symbol(), MODE_TICKSIZE) ); // Not Point.
}
Reason: