Topic: Help needed! Position sizing relative to SL code

Hi Popov,

I have been reading all over the interent as well on the forum on how to code a particular function. I notice that you have provided a code to set the entry amount relative to the account size as a percentage. I have added this code into my EA's with much appreciation  for providing us with it.

However I really want to be able to set my position size relative to the Stop Loss of the strategy. For example if I want to risk 2% of my available margin per trade with a strategy that has a SL of 50 pips:
So as an example:

Pip value X 50 = 2% of account margin

How can I add this function in the MQL code to automate this process?

All of my EA's run SL's and never TSL's.

Thanks!

Re: Help needed! Position sizing relative to SL code

Hi Popov if I could please get a hand with this it would be much appreciated I’ve spent 5 days trying to make it work with no success

Re: Help needed! Position sizing relative to SL code

Hi Michael1,

I haven't test this code, but it seems to be logically correct...

https://mql4tradingautomation.com/mql4-calculate-position-size/

Let me know how it goes!

Re: Help needed! Position sizing relative to SL code

Thanks traderaw,
Ive been trying and trying all night to get it to work however cannot seem to get it working\

Popov! can i please get hand with this im desperate!

Attached is a file I have modified however I cannot get it to work. The EA constantly opens trades at the maximum_Lots value not the MaxRiskPerTrade and I cannot work out why.

//
// EA Studio Expert Advisor
//
// Created with: Expert Advisor Studio
// Website: https://forexsb.com/expert-advisor-studio-app
//
// Copyright 2019, Forex Software Ltd.
//

#property copyright "Forex Software Ltd."
#property version   "2.10"
#property strict

static input string StrategyProperties__ = "------------"; // ------ Expert Properties ------
extern double MaxRiskPerTrade=1; //% of balance to risk in one trade
static input double Maximum_Lots = 0.01; // Maximum entry lots
input int Stop_Loss   = 10; // Stop Loss (pips)
input int Take_Profit = 0; // Take Profit (pips)
static input string Ind1 = "------------";// ----- Entry Time -----
input int Ind1Param0 = 0; // From hour
input int Ind1Param1 = 0; // From minute
input int Ind1Param2 = 0; // Until hour
input int Ind1Param3 = 59; // Until minute
static input string Ind2 = "------------";// ----- Money Flow Index -----
input int Ind2Param0 = 11; // Period
input int Ind2Param1 = 20; // Level

static input string ExpertSettings__ = "------------"; // ------ Expert Settings ------
static input int Magic_Number = 98261191; // Magic Number

#define TRADE_RETRY_COUNT 4
#define TRADE_RETRY_WAIT  100
#define OP_FLAT           -1

// Session time is set in seconds from 00:00
int sessionSundayOpen           = 0;     // 00:00
int sessionSundayClose          = 86400; // 24:00
int sessionMondayThursdayOpen   = 0;     // 00:00
int sessionMondayThursdayClose  = 86400; // 24:00
int sessionFridayOpen           = 0;     // 00:00
int sessionFridayClose          = 60;    // 00:01
bool sessionIgnoreSunday        = true;
bool sessionCloseAtSessionClose = false;
bool sessionCloseAtFridayClose  = true;

const double sigma   = 0.000001;

double posType       = OP_FLAT;
int    posTicket     = 0;
double posLots       = 0;
double posStopLoss   = 0;
double posTakeProfit = 0;

datetime barTime;
int      digits;
double   pip;
double   stopLevel;
bool     isTrailingStop=false;
bool     setProtectionSeparately=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   barTime        = Time[0];
   digits         = (int) MarketInfo(_Symbol, MODE_DIGITS);
   pip            = GetPipValue(digits);
   stopLevel      = MarketInfo(_Symbol, MODE_STOPLEVEL);
   isTrailingStop = isTrailingStop && Stop_Loss > 0;

   const ENUM_INIT_RETCODE initRetcode = ValidateInit();

   return (initRetcode);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(Time[0]>barTime)
     {
      barTime=Time[0];
      OnBar();
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnBar()
  {
   UpdatePosition();

   if(posType!=OP_FLAT && IsForceSessionClose())
     {
      ClosePosition();
      return;
     }

   if(IsOutOfSession())
      return;

   if(posType!=OP_FLAT)
     {
      ManageClose();
      UpdatePosition();
     }

   if(posType!=OP_FLAT && isTrailingStop)
     {
      double trailingStop=GetTrailingStop();
      ManageTrailingStop(trailingStop);
      UpdatePosition();
     }

   if(posType==OP_FLAT)
     {
      ManageOpen();
      UpdatePosition();
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void UpdatePosition()
  {
   posType   = OP_FLAT;
   posTicket = 0;
   posLots   = 0;
   int total = OrdersTotal();

   for(int pos=total-1; pos>=0; pos--)
     {
      if(OrderSelect(pos,SELECT_BY_POS) &&
         OrderSymbol()==_Symbol &&
         OrderMagicNumber()==Magic_Number)
        {
         posType       = OrderType();
         posLots       = OrderLots();
         posTicket     = OrderTicket();
         posStopLoss   = OrderStopLoss();
         posTakeProfit = OrderTakeProfit();
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ManageOpen()
  {
   bool ind0long  = true;
   bool ind0short = false;


   int fromTime1  = Ind1Param0*3600 + Ind1Param1*60;
   int untilTime1 = Ind1Param2*3600 + Ind1Param3*60;

   MqlDateTime mqlTime1; TimeToStruct(Time(0), mqlTime1);
   int barMinutes1 = mqlTime1.hour*3600 + mqlTime1.min*60;

   bool isOnTime1 = fromTime1 < untilTime1
      ? barMinutes1 >= fromTime1 && barMinutes1 <= untilTime1
      : barMinutes1 >= fromTime1 || barMinutes1 <= untilTime1;

   bool ind1long  = isOnTime1;
   bool ind1short = isOnTime1;

   const bool canOpenLong  = ind0long && ind1long;
   const bool canOpenShort = ind0short && ind1short;

   if(canOpenLong && canOpenShort)
      return;

   if(canOpenLong)
      OpenPosition(OP_BUY);
   else if(canOpenShort)
      OpenPosition(OP_SELL);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ManageClose()
  {
   double ind2val1 = iMFI(NULL,0,Ind2Param0,1);
   double ind2val2 = iMFI(NULL,0,Ind2Param0,2);
   double ind2val3 = iMFI(NULL,0,Ind2Param0,3);
   bool ind2long  = ind2val1 > ind2val2 + sigma && ind2val2 < ind2val3 - sigma;
   bool ind2short = ind2val1 < ind2val2 - sigma && ind2val2 > ind2val3 + sigma;

   if(posType==OP_BUY && ind2long)
      ClosePosition();
   else if(posType==OP_SELL && ind2short)
      ClosePosition();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OpenPosition(int command)
  {
  int margin=(int) MarketInfo(_Symbol,MODE_MARGINREQUIRED);
   double Entry_Amount=(AccountBalance()*MaxRiskPerTrade/100)/(Stop_Loss*pip);
   Entry_Amount=MathMin(Entry_Amount,Maximum_Lots);
   Entry_Amount=MathMax(Entry_Amount,0.01);
   Entry_Amount=NormalizeDouble(Entry_Amount,2);
   for(int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
     {
      int    ticket     = 0;
      int    lastError  = 0;
      bool   modified   = false;
      double stopLoss   = GetStopLoss(command);
      double takeProfit = GetTakeProfit(command);
      string comment    = IntegerToString(Magic_Number);
      color  arrowColor = command==OP_BUY ? clrGreen : clrRed;

      if(IsTradeContextFree())
        {
         double price=MarketInfo(_Symbol,command==OP_BUY ? MODE_ASK : MODE_BID);
         if(setProtectionSeparately)
           {
            ticket=OrderSend(_Symbol,command,Entry_Amount,price,10,0,0,comment,Magic_Number,0,arrowColor);
            if(ticket>0 && (Stop_Loss>0 || Take_Profit>0))
              {
               modified=OrderModify(ticket,0,stopLoss,takeProfit,0,clrBlue);
              }
           }
         else
           {
            ticket=OrderSend(_Symbol,command,Entry_Amount,price,10,stopLoss,takeProfit,comment,Magic_Number,0,arrowColor);
            lastError=GetLastError();
            if(ticket<=0 && lastError==130)
              {
               ticket=OrderSend(_Symbol,command,Entry_Amount,price,10,0,0,comment,Magic_Number,0,arrowColor);
               if(ticket>0 && (Stop_Loss>0 || Take_Profit>0))
                 {
                  modified=OrderModify(ticket,0,stopLoss,takeProfit,0,clrBlue);
                 }
               if(ticket>0 && modified)
                 {
                  setProtectionSeparately=true;
                  Print("Detected ECN type position protection.");
                 }
              }
           }
        }

      if(ticket>0)
         break;

      lastError=GetLastError();
      if(lastError!=135 && lastError!=136 && lastError!=137 && lastError!=138)
         break;

      Sleep(TRADE_RETRY_WAIT);
      Print("Open Position retry no: "+IntegerToString(attempt+2));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ClosePosition()
  {
   for(int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
     {
      bool closed;
      int lastError=0;

      if(IsTradeContextFree())
        {
         double price=MarketInfo(_Symbol,posType==OP_BUY ? MODE_BID : MODE_ASK);
         closed=OrderClose(posTicket,posLots,price,10,clrYellow);
         lastError=GetLastError();
        }

      if(closed)
         break;

      if(lastError==4108)
         break;

      Sleep(TRADE_RETRY_WAIT);
      Print("Close Position retry no: "+IntegerToString(attempt+2));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ModifyPosition()
  {
   for(int attempt=0; attempt<TRADE_RETRY_COUNT; attempt++)
     {
      bool modified;
      int lastError=0;

      if(IsTradeContextFree())
        {
         modified=OrderModify(posTicket,0,posStopLoss,posTakeProfit,0,clrBlue);
         lastError=GetLastError();
        }

      if(modified)
         break;

      if(lastError==4108)
         break;

      Sleep(TRADE_RETRY_WAIT);
      Print("Modify Position retry no: "+IntegerToString(attempt+2));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetStopLoss(int command)
  {
   if(Stop_Loss==0)
      return (0);

   double delta    = MathMax(pip*Stop_Loss, _Point*stopLevel);
   double price    = MarketInfo(_Symbol, command==OP_BUY ? MODE_BID : MODE_ASK);
   double stopLoss = command==OP_BUY ? price-delta : price+delta;
   return (NormalizeDouble(stopLoss, digits));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetTakeProfit(int command)
  {
   if(Take_Profit==0)
      return (0);

   double delta      = MathMax(pip*Take_Profit, _Point*stopLevel);
   double price      = MarketInfo(_Symbol, command==OP_BUY ? MODE_BID : MODE_ASK);
   double takeProfit = command==OP_BUY ? price+delta : price-delta;
   return (NormalizeDouble(takeProfit, digits));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetTrailingStop()
  {
   double bid=MarketInfo(_Symbol,MODE_BID);
   double ask=MarketInfo(_Symbol,MODE_ASK);
   double stopLevelPoints=_Point*stopLevel;
   double stopLossPoints=pip*Stop_Loss;

   if(posType==OP_BUY)
     {
      double stopLossPrice=High[1]-stopLossPoints;
      if(posStopLoss<stopLossPrice-pip)
        {
         if(stopLossPrice<bid)
           {
            if(stopLossPrice>=bid-stopLevelPoints)
               return (bid - stopLevelPoints);
            else
               return (stopLossPrice);
           }
         else
           {
            return (bid);
           }
        }
     }

   else if(posType==OP_SELL)
     {
      double stopLossPrice=Low[1]+stopLossPoints;
      if(posStopLoss>stopLossPrice+pip)
        {
         if(stopLossPrice>ask)
           {
            if(stopLossPrice<=ask+stopLevelPoints)
               return (ask + stopLevelPoints);
            else
               return (stopLossPrice);
           }
         else
           {
            return (ask);
           }
        }
     }

   return (posStopLoss);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ManageTrailingStop(double trailingStop)
  {
   double bid=MarketInfo(_Symbol,MODE_BID);
   double ask=MarketInfo(_Symbol,MODE_ASK);

   if(posType==OP_BUY && MathAbs(trailingStop-bid)<_Point)
     {
      ClosePosition();
     }

   else if(posType==OP_SELL && MathAbs(trailingStop-ask)<_Point)
     {
      ClosePosition();
     }

   else if(MathAbs(trailingStop-posStopLoss)>_Point)
     {
      posStopLoss=NormalizeDouble(trailingStop,digits);
      ModifyPosition();
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime Time(int bar)
  {
   return Time[bar];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Open(int bar)
  {
   return Open[bar];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double High(int bar)
  {
   return High[bar];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Low(int bar)
  {
   return Low[bar];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Close(int bar)
  {
   return Close[bar];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetPipValue(int digit)
  {
   if(digit==4 || digit==5)
      return (0.0001);
   if(digit==2 || digit==3)
      return (0.01);
   if(digit==1)
      return (0.1);
   return (1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsTradeContextFree()
  {
   if(IsTradeAllowed())
      return (true);

   uint startWait=GetTickCount();
   Print("Trade context is busy! Waiting...");

   while(true)
     {
      if(IsStopped())
         return (false);

      uint diff=GetTickCount()-startWait;
      if(diff>30*1000)
        {
         Print("The waiting limit exceeded!");
         return (false);
        }

      if(IsTradeAllowed())
        {
         RefreshRates();
         return (true);
        }
      Sleep(TRADE_RETRY_WAIT);
     }
   return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsOutOfSession()
  {
   MqlDateTime time0; TimeToStruct(Time[0],time0);
   int weekDay           = time0.day_of_week;
   long timeFromMidnight = Time[0]%86400;
   int periodLength      = PeriodSeconds(_Period);
   bool skipTrade        = false;

   if(weekDay==0)
     {
      if(sessionIgnoreSunday) return true;
      int lastBarFix=sessionCloseAtSessionClose ? periodLength : 0;
      skipTrade=timeFromMidnight<sessionSundayOpen || timeFromMidnight+lastBarFix>sessionSundayClose;
     }
   else if(weekDay<5)
     {
      int lastBarFix=sessionCloseAtSessionClose ? periodLength : 0;
      skipTrade=timeFromMidnight<sessionMondayThursdayOpen || timeFromMidnight+lastBarFix>sessionMondayThursdayClose;
     }
   else
     {
      int lastBarFix=sessionCloseAtFridayClose || sessionCloseAtSessionClose ? periodLength : 0;
      skipTrade=timeFromMidnight<sessionFridayOpen || timeFromMidnight+lastBarFix>sessionFridayClose;
     }

   return (skipTrade);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsForceSessionClose()
  {
   if(!sessionCloseAtFridayClose && !sessionCloseAtSessionClose)
      return (false);

   MqlDateTime time0; TimeToStruct(Time[0],time0);
   int weekDay           = time0.day_of_week;
   long timeFromMidnight = Time[0]%86400;
   int periodLength      = PeriodSeconds(_Period);
   int lastBarFix        = sessionCloseAtSessionClose ? periodLength : 0;

   bool forceExit=false;
   if(weekDay==0)
     {
      forceExit=timeFromMidnight+lastBarFix>sessionSundayClose;
     }
   else if(weekDay<5)
     {
      forceExit=timeFromMidnight+lastBarFix>sessionMondayThursdayClose;
     }
   else
     {
      int fridayBarFix=sessionCloseAtFridayClose || sessionCloseAtSessionClose ? periodLength : 0;
      forceExit=timeFromMidnight+fridayBarFix>sessionFridayClose;
     }

   return (forceExit);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ENUM_INIT_RETCODE ValidateInit()
  {
   return (INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
/*STRATEGY MARKET Dukascopy-DEMO-1; EURNZD; H1 */
/*STRATEGY CODE {"properties":{"entryLots":0.05,"stopLoss":54,"takeProfit":33,"useStopLoss":false,"useTakeProfit":false,"isTrailingStop":false},"openFilters":[{"name":"Long or Short","listIndexes":[0,0,0,0,0],"numValues":[0,0,0,0,0,0]},{"name":"Entry Time","listIndexes":[0,0,0,0,0],"numValues":[0,0,0,59,0,0]}],"closeFilters":[{"name":"Money Flow Index","listIndexes":[6,0,0,0,0],"numValues":[11,20,0,0,0,0]}]} */

Re: Help needed! Position sizing relative to SL code

Ive just being trying again tonight after 3hours I still cannot get it to work.

Can I please get some assistance from someone please? Im desperate haha

6 (edited by footon 2019-04-04 15:19:15)

Re: Help needed! Position sizing relative to SL code

I'm illiterate in mql, but I can pitch some ideas as a by-stander.

Firstly, what are your modifications? It would especially great to see them side by side, I mean the original code and your mod.

/// edited out

Re: Help needed! Position sizing relative to SL code

Are you using the same parameters as in your pasted code? If so, raise max lot value.

And check this line:

double Entry_Amount=(AccountBalance()*MaxRiskPerTrade/100)/(Stop_Loss*pip);

Re: Help needed! Position sizing relative to SL code

Try this.

make Entry_Amount as global variable.

datetime barTime;
int      digits;
double   pip;
double   stopLevel;
bool     isTrailingStop=false;
bool     setProtectionSeparately=false;
[b]double   Entry_Amount;[/b]

Than put your code in OnTick.

void OnTick()
  {
      int margin=(int) MarketInfo(_Symbol,MODE_MARGINREQUIRED);
      Entry_Amount=(AccountBalance()*MaxRiskPerTrade/100)/(Stop_Loss*pip);
      Entry_Amount = NormalizeEntrySize(Entry_Amount);

ADD THIS FUNCTION OUTSIDE ONTICK

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double NormalizeEntrySize(double size) {
   double minlot  = MarketInfo(_Symbol, MODE_MINLOT);
   double maxlot  = MarketInfo(_Symbol, MODE_MAXLOT);
   double lotstep = MarketInfo(_Symbol, MODE_LOTSTEP);

   if (size <= minlot)
       return (minlot);

   int steps = (int) MathRound((size - minlot) / lotstep);
   size = minlot + steps * lotstep;

   if (size >= maxlot)
       size = maxlot;
   if (size >=Maximum_Lots)
       size = Maximum_Lots;
       
   size = NormalizeDouble(size, digits);   

   return (size);
}  

Re: Help needed! Position sizing relative to SL code

Roughey your a legend I had a lay around with that code and got it work.

Thank you very much!!!

Re: Help needed! Position sizing relative to SL code

No Problem. ;-)