Need Help - EA is working for fixed lot size but not for risk percentage

 

EA is working for fixed lot size but not for risk percentage. I get diffrent loss values for most currency pairs. On USD pairs risk works as close to accurate as possible. EX: Risk 1 % of 3500.00 USD  and i lose about 36 dollars. GBPJPY i lose 50 USD, EURNZD i lose 25 USD. 

I am fairly new to programming in MQL5 and i have been working on creating this EA with very minimal help for the last few months. I researched and worked tirelessly trying to figure this lot thing out. I would greatly appreciate it if anyone can point me in the right direction. 

Cheers!

 
//+------------------------------------------------------------------+
//|                          Time Range Break and Retest EA v1.0.mq5 |
//|                                     Copyright 2024, Bosco A Vega |
//|                                          quantumpips85@gmail.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Bosco A Vega"
#property link      "quantumpips85@gmail.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
#include <Trade/PositionInfo.mqh>
#include <Trade/SymbolInfo.mqh>

sinput group "GENERAL EA INPUTS"
input int EA_Magic = 12345;      //EA magic number
input int Slippage = 10;
input bool Buy = true;          //Allow Buying
input bool Sell = true;          //Allow Selling
input string InpTradeComment = "Trade has been placed";

sinput group "RANGE START INPUTS"
input int InpRangeStartHours = 0; // Range Start Hours (0-23)
input int InpRangeStartMinutes = 0; //Range Start Minutes (0-59)

sinput group "RANGE END INPUTS"
input int InpRangeEndHours = 2; // Range End Hours (0-23)
input int InpRangeEndMinutes = 0; //Range End Minutes (0-59)

sinput group "RANGE CLOSE INPUTS"
input int InpCloseHours = 23; // Close Hours (0-23)
input int InpCloseMinutes = 0; //Close Minutes (0-59)

sinput group "MONEY MANAGEMENT INPUTS"
input bool useMM = false;                      //Use Money Management
input double InpRisk = 1.0;                    //Risk in % of balance
input double InpOrderSize = 0.05;              //Lotsize used if useMM = false

sinput group "SL AND TP INPUTS"
input int Stoploss =25;                        //Stoploss in pips
input int TakeProfit = 25;                     //Takeprofit in pips

sinput group "BREAKEVEN INPUTS"
input bool UseBreakEven = true;                //Use breakeven
input int WhenToBreak = 20;                    //When to Breakeven in pips
input int BreakBy = 5;                         //Break even in pips

sinput group "TRAILING STOP INPUTS"
input bool UseTrailing = true;                 //Use trailing stop
input int WhenToTrail = 50;                    //When to Start Trailing in pips
input int TrailBy = 20;                        //TrailingStop in pips


//--- Global Values for the Range
bool InsideRange; // Gets set when the time is between start and end time
bool InsideClose; // Gets set when time is between end and close time

bool BreakoutHigh;
bool BreakinHigh;
bool BreakoutLow;
bool BreakinLow;

int RangeStartMinutes;
int RangeEndMinutes;
int CloseMinutes;

double STP,TKP;

ulong LastBars = 0;
double Ask,Bid,Lots;

//----
double m_whentobreak;
double m_breakby;
double m_whentotrail;
double m_trailby;

//---Creating some Objects
CTrade *Trade;
CPositionInfo PositionInfo;
CSymbolInfo m_symbol;
COrderInfo Order;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

//---Initializing the Trade Objects

   Trade = new CTrade;
   Trade.SetDeviationInPoints(Slippage);
   Trade.SetExpertMagicNumber(EA_Magic);
   m_symbol.Name(Symbol());
   
//--- Checking user inputs 

   if  (!CheckInput()) return (INIT_PARAMETERS_INCORRECT);
   
   InsideRange = IsInsideTime  (TimeCurrent() , RangeStartMinutes, RangeEndMinutes);
   InsideClose = IsInsideTime  (TimeCurrent() , RangeEndMinutes, CloseMinutes);


//---Standardise the currency digits for different pairs

   STP = Stoploss*_Point;
   TKP = TakeProfit*_Point;
   m_whentobreak = WhenToBreak*_Point;
   m_breakby= BreakBy*_Point;
   m_trailby = TrailBy*_Point;
   m_whentotrail = WhenToTrail*_Point;

   //if(_Digits==5||_Digits==3)
     {
      STP=STP*10;
      TKP=TKP*10;
      m_whentobreak=m_whentobreak*10;
      m_trailby=m_trailby*10;
      m_whentotrail=m_whentotrail*10;
     }

//---Checking the adequecy of the number of bars in history

   if(Bars(_Symbol,_Period)<500)
     {
      Alert("We have less than enough bars, EA will now exit");
      return(0);
     }

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
          
//---Checking if we are able to trade

   if((!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))||(!TerminalInfoInteger(TERMINAL_CONNECTED))||(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_MODE)!=SYMBOL_TRADE_MODE_FULL))
     {
      return;
     }

//---Defining MQL structures to be used for trading

   MqlTick latest_price;                  //To be used to get the latest information about prices

//---Checking if we have the latest price quote

   if(!SymbolInfoTick(_Symbol,latest_price))
     {
      Alert("Error getting the latest price quote - Error: ",GetLastError(),"!!");
      return;
     }
     
   
//--- Checking for the presence of an open position

   bool Tradeopened = false;

   if(PositionsTotal()>0)
     {
      Tradeopened = true;
      if(UseBreakEven)
        {
         BreakEven();
        }
      if(UseTrailing)
        {
         TrailingStopLoss();
        }
     }   

    
//--- Static values to track the range
   static double rangeHigh = 0;
   static double rangeLow = 0;
   
     
//--- Conditions for the range 
   
   bool nowOutsideClose = !IsInsideTime(TimeCurrent(), RangeEndMinutes, CloseMinutes);
   if (InsideClose && nowOutsideClose )
   {
    CloseAll();
    InsideClose = false;
    
    rangeHigh = 0;
    rangeLow = 0;
    
    BreakinHigh = false;
    BreakinLow = false;
    BreakoutHigh = false;
    BreakoutLow = false;
   }
   
   InsideClose = !nowOutsideClose;
   
   if(InsideClose && IsNewBar(true))
     {
      double close = iClose(Symbol(),Period(),1);
      long spread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD) + 50;
      double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT);
      double gap = spread * point;
      
//--- Getting the Lotsize
   if(useMM)
    {
     Lots = calclots(InpRisk,STP);
    }
          
   else
    {
     Lots = InpOrderSize;
    }
      
//--- Buy Condition

      if(!BreakinHigh)
        {
         BreakoutHigh = BreakoutHigh || (close > rangeHigh);
          if (BreakoutHigh && close<rangeHigh)
          {
           BreakinHigh = true;
           OpenTrade(ORDER_TYPE_BUY_STOP, rangeHigh+gap,rangeHigh+gap-STP,rangeHigh+gap+TKP);
          }
        }

//--- Sell Condition       
        if(!BreakinLow)
        {
         BreakoutLow = BreakoutLow || (close < rangeLow);
          if (BreakoutLow && close>rangeLow)
          {
           BreakinLow = true;
           OpenTrade(ORDER_TYPE_SELL_STOP, rangeLow-gap, rangeLow-gap+STP, rangeLow-gap-TKP);
          }
        }
     } 
      
//--- Exited the range and setting our price
   
   bool nowOutsideRange = !IsInsideTime(TimeCurrent(), RangeStartMinutes, RangeEndMinutes);
   if  (InsideRange && nowOutsideRange)
     {
      ShowRange(rangeHigh,rangeLow);
     
      InsideRange = false;
      InsideClose = true;
      
      BreakinHigh = false;
      BreakinLow = false;
      BreakoutHigh = false;
      BreakoutLow = false;
     }
     
    InsideRange = !nowOutsideRange;
 
    
    if  (InsideRange)
      {
       double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
       double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
       if (rangeHigh==0 || ask > rangeHigh) rangeHigh = ask;
       if (rangeLow==0 || bid < rangeLow) rangeLow = bid;
      } 

//-----End of on tick function    
   } //---------------------->
//---Start of global functions

//+------------------------------------------------------------------+
//|Checking User Inputs                                              |
//+------------------------------------------------------------------+

bool CheckInput()
  {
   if(  (InpRangeStartHours<0 || InpRangeStartHours>23)
      ||(InpRangeStartMinutes<0 || InpRangeStartMinutes>59)
      ||(InpRangeEndHours<0 || InpRangeEndHours>23)
      ||(InpRangeEndMinutes<0 || InpRangeEndMinutes>59)
      ||(InpCloseHours<0 || InpCloseHours>23)
      ||(InpCloseMinutes<0 || InpCloseMinutes>59)  ) return false;
      
      RangeStartMinutes = InpRangeStartHours*60 + InpRangeStartMinutes;
      RangeEndMinutes = InpRangeEndHours*60 + InpRangeEndMinutes;
      CloseMinutes = InpCloseHours*60 + InpCloseMinutes;
      
      if(RangeStartMinutes==RangeEndMinutes) return false;
      if(RangeEndMinutes==CloseMinutes) return false;
      
      return true;
  }
  
//+------------------------------------------------------------------+
//|Is Inside Time Function                                           |
//+------------------------------------------------------------------+

bool IsInsideTime(datetime now, int startMinutes, int endMinutes)
  {
   MqlDateTime time;
   TimeToStruct(now, time);
   int nowMinutes = time.hour*60+time.min; // Currently ignoring seconds after the minute
   return (  (startMinutes<=nowMinutes && nowMinutes<endMinutes )
          || (  ( startMinutes>endMinutes) && (nowMinutes<endMinutes || nowMinutes>=startMinutes)  )
          ); 
  }
  
//+------------------------------------------------------------------+
//|Calculate lots function                                           |
//+------------------------------------------------------------------+
      
double calclots (double riskPercent, double sl)
  {
    double ticksize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE);
    double tickvalue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
    double lotstep = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
    
    if(ticksize == 0 || tickvalue == 0 || lotstep == 0)
      {
       Print(__FUNCTION__," > Lotsize cannot be calculated...");
       return 0;
      }
    
    double riskMoney = AccountInfoDouble(ACCOUNT_BALANCE) * riskPercent / 100;
    double moneyLotStep = (sl / ticksize) * tickvalue * lotstep;
    
    if(moneyLotStep==0)
      {
       Print(__FUNCTION__," > Lotsize cannot be calculated...");
       return 0;
      }
    double lots = MathFloor (riskMoney / moneyLotStep) * lotstep;
    
    return lots;
    
  }
  
//+------------------------------------------------------------------+
//|Open Order Function                                               |
//+------------------------------------------------------------------+
  
void OpenTrade( ENUM_ORDER_TYPE type, double price, double sl , double tp )
  {
   
   price = NormalizeDouble(price, Digits() );
   sl = NormalizeDouble(sl, Digits() );
   tp = NormalizeDouble(tp,Digits() );
   
   if(!Trade.OrderOpen(Symbol(), type, Lots, 0, price, sl, tp, ORDER_TIME_GTC, 0, InpTradeComment)  )
     {
      Print("Open failed for %s, %s, price=%f, tp=%f", Symbol(), EnumToString ( type ),price,sl,tp );
     }
  }
  
//+------------------------------------------------------------------+
//|Close All Function                                                |
//+------------------------------------------------------------------+

void CloseAll ()
  {
   for(int i=PositionsTotal()-1; i>=0; i--)
    {
      ulong ticket = PositionGetTicket(i);
      if (!PositionSelectByTicket(ticket)) continue;
      if (PositionInfo.Symbol() !=Symbol() || PositionInfo.Magic()!=EA_Magic) continue;
      if (!Trade.PositionClose(ticket))
      {
       PrintFormat("Failed to close position %i", ticket);
      }
    }

   for(int i=OrdersTotal()-1; i>=0; i--)
    {
      ulong ticket = OrderGetTicket(i);
      if (!OrderSelect(ticket)) continue;
      if (Order.Symbol() !=Symbol() || Order.Magic()!=EA_Magic) continue;
      if (!Trade.OrderDelete(ticket))
      {
       PrintFormat("Failed to delete order %i", ticket);
      }
    }    
   
  }
  
//+------------------------------------------------------------------+
//|Is New Bar Function                                               |
//+------------------------------------------------------------------+
  
  bool   IsNewBar( bool first_call = false ) {

   static bool result = false;
   if ( !first_call ) return ( result );

   static datetime previous_time = 0;
   datetime        current_time  = iTime( Symbol(), Period(), 0 );
   result                        = false;
   if ( previous_time != current_time ) {
      previous_time = current_time;
      result        = true;
   }
   return ( result );
}


//+------------------------------------------------------------------+
//|Breaking Even Function                                            |
//+------------------------------------------------------------------+
void BreakEven()
  {
//---Loop through all open positions
   for(int i = PositionsTotal()-1; i>=0; i--)
     {
      if(!PositionInfo.SelectByIndex(i))
        {
         continue;
        }
      if(PositionInfo.Magic() != EA_Magic)
        {
         continue;
        }
      if(PositionInfo.Symbol() != m_symbol.Name())
        {
         continue;
        }

      //---Checking if SL is in profit

      double current_sl = PositionInfo.StopLoss();
      double openingPrice = PositionInfo.PriceOpen();
      if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
        {
         if(current_sl>=openingPrice)
           {
            continue;
           }
        }
      if(PositionInfo.PositionType()==POSITION_TYPE_SELL)
        {
         if(current_sl!=0 && current_sl<=openingPrice)
           {
            continue;
           }
        }

      //---Checking if price has arrived at BE point
      double breakevenprice = PositionInfo.PositionType()==POSITION_TYPE_BUY ? openingPrice+m_whentobreak : openingPrice-m_whentobreak;
      double current_price = PositionInfo.PriceCurrent();

      if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
        {
         if(current_price<breakevenprice)
           {
            continue;
           }
        }
      else
        {
         if(current_price>breakevenprice)
           {
            continue;
           }
        }

      //---Breaking even
      double new_sl=PositionInfo.PositionType() == POSITION_TYPE_BUY ? openingPrice + m_breakby : openingPrice - m_breakby;

      //---Modify position
      if(!Trade.PositionModify(PositionInfo.Ticket(),new_sl,PositionInfo.TakeProfit()))
        {
         Alert("Error Modifying position [%d]",GetLastError());
        }

     }
  }
//+------------------------------------------------------------------+
//|Trailing Stop Function                                            |
//+------------------------------------------------------------------+

void TrailingStopLoss()
  {
//---Loop through all open positions
   for(int i = PositionsTotal()-1; i>=0; i--)
     {
      if(!PositionInfo.SelectByIndex(i))
        {
         continue;
        }
      if(PositionInfo.Magic() != EA_Magic)
        {
         continue;
        }
      if(PositionInfo.Symbol() != m_symbol.Name())
        {
         continue;
        }
      //---Getting the Stoploss and OpenPrice
      double current_sl = PositionInfo.StopLoss();
      double opening_price = PositionInfo.PriceOpen();
      double current_price = PositionInfo.PriceCurrent();

      //---Checking if Price Has reached the trailmark
      double trailprice = PositionInfo.PositionType()==POSITION_TYPE_BUY ? opening_price + m_whentotrail : opening_price - m_whentotrail;

      if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
        {
         if(current_price < trailprice)
           {
            continue;
           }
        }
      else
        {
         if(current_price > trailprice)
           {
            continue;
           }
        }

      //---Getting the new sl and checking if position sl has moved
      double new_sl = PositionInfo.PositionType()==POSITION_TYPE_BUY ? current_price - m_trailby : current_price + m_trailby;

      //---Checking if new SL is valid
      if(PositionInfo.PositionType()==POSITION_TYPE_BUY && new_sl < current_sl)
        {
         continue;
        }
      if(PositionInfo.PositionType()==POSITION_TYPE_SELL && new_sl > current_sl)
        {
         continue;
        }

      ulong m_ticket = PositionInfo.Ticket();
      double TP = PositionInfo.TakeProfit();

      if(!Trade.PositionModify(m_ticket,new_sl,TP))
        {
         Alert("Error Modifying position [%d]",GetLastError());
        }
     }
}

//+------------------------------------------------------------------+
//|Function for creating range objects                               |
//+------------------------------------------------------------------+

void ShowRange( double hi, double lo ) 
   {
    ShowRangeLine( "hi", OBJ_HLINE, hi );
    ShowRangeLine( "lo", OBJ_HLINE, lo );
    ShowRangeLine( "now", OBJ_VLINE, lo );
   }

void ShowRangeLine( string name, ENUM_OBJECT type, double value ) {

   ObjectDelete( 0, name );
   ObjectCreate( 0, name, type, 0, iTime( Symbol(), Period(), 1 ), value );
   ObjectSetInteger( 0, name, OBJPROP_COLOR, clrCyan );
   ObjectSetInteger( 0, name, OBJPROP_STYLE, STYLE_DASHDOTDOT);
   } 
//+------------------------------------------------------------------+
   

 
Bosco Antonio Vega #:

To calculate the lot size based on the risk percentage, you need to use a formula that takes into account the balance, the stop loss, the symbol price, and the symbol properties. The formula is:

AccountBalance * InpRisk / 100 = LotSize * (|OrderOpenPrice - OrderStopLoss| * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE) + SymbolInfoDouble(Symbol(), SYMBOL_TRADE_COMMISSION) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))

This formula will give you the lot size that corresponds to the risk percentage that you want to use. You can then use this lot size in your trade request structure. For example, if you want to risk 1% of your balance, you can use:

    double LotSize = AccountBalance * 0.01 / ((|OrderOpenPrice - OrderStopLoss| * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE) + SymbolInfoDouble(Symbol(), SYMBOL_TRADE_COMMISSION) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE)));

You can also use a function to calculate the lot size based on the risk percentage, and then call it in your code. For example, you can use:

double CalculateLotSize(double risk) { double LotSize = AccountBalance * risk / ((|OrderOpenPrice - OrderStopLoss| * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE) + SymbolInfoDouble(Symbol(), SYMBOL_TRADE_COMMISSION) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))); return LotSize; }

And then call it in your code like this:

    double LotSize = CalculateLotSize(0.01); // Risk 1% of balance 

i hope this helps 

 
Amos Tsopotsa #:
double LotSize = CalculateLotSize(0.01); // Risk 1% of balance

Hello my friend, i appreciate your kind help. I tried to figure it out but i am getting errors. Im not sure how i can exactly use the code you provided in my code. I attempted. Any other suggestion would be appreciated. 

 
Amos Tsopotsa #:

To calculate the lot size based on the risk percentage, you need to use a formula that takes into account the balance, the stop loss, the symbol price, and the symbol properties. The formula is:

AccountBalance * InpRisk / 100 = LotSize * (|OrderOpenPrice - OrderStopLoss| * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE) + SymbolInfoDouble(Symbol(), SYMBOL_TRADE_COMMISSION) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))

This formula will give you the lot size that corresponds to the risk percentage that you want to use. You can then use this lot size in your trade request structure. For example, if you want to risk 1% of your balance, you can use:

You can also use a function to calculate the lot size based on the risk percentage, and then call it in your code. For example, you can use:

double CalculateLotSize(double risk) { double LotSize = AccountBalance * risk / ((|OrderOpenPrice - OrderStopLoss| * SymbolInfoDouble(Symbol(), SYMBOL_POINT) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE) + SymbolInfoDouble(Symbol(), SYMBOL_TRADE_COMMISSION) * SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))); return LotSize; }

And then call it in your code like this:

i hope this helps 

Stop using AI to sort out other peoples problems.....What you describe here is not the problem he is having. ChatGPT will not find solutions to problems, we told you that already