What is using all my memory?

 

I am backtesting my algo on MT5 Version 5.00 Build 4153 22 Jan 24 on OSX Sonoma 14.3 M1 Max (10 Cores) 64 GB Ram. 

When I do it uses a lot of memory and even runs out of application memory space. 



I am only using 1 core in this example because when I use more than 1 agent it runs out of space quicker. 

Memory Usage

I get no errors in Journal when running locally, I just run out of memory with the above errors:

When I run an optimisation with 7896 steps using MQL Cloud Network I get the following errors:

 

 I tried to detect an issue with: `checkForMemLeak.mqh` but nothing was found. Each time I create a new Object I am deleting the object with new and delete. I create all my arrays with a fixed size, and I a believe I only initialise my indicators once and I release my indicator  handles via the  destructor.

2024.02.12 15:26:01.700 MQL5 Cloud Europe 2     pass 5956 tested with error "critical runtime error 0 in OnInit function (error code 0, module Experts\AsianRange\AsianRangeBackTest.ex5, file Trend.mqh, line 370, col 19)" in 0:00:00.528 (PR 207)

2024.02.12 15:26:01.700 MQL5 Cloud Europe 2     pass 3266 tested with error "critical runtime error 505 in global initialization function (out of memory)" in 0:00:00.002 (PR 207)

...

2024.02.12 15:26:02.930 MQL5 Cloud Europe 2     stop using of cloud servers because of 65 critical errors

2024.02.12 15:26:02.930 Tester  Cloud servers switched off

The 65 critical errors are just reporting: ` error "critical runtime error 505 in global initialization function (out of memory)"` below error might a symptom of running out of memory and maybe not the cause but I can't be sure. 
OnInit function (error code 0, module Experts\AsianRange\AsianRangeBackTest.ex5, file Trend.mqh, line 370, col 19
I can't seem to find this file: Trend.mqh in MT5 to view it. I can see it referenced here (which is not mine) and line 370 is: `      ((CIndicatorBuffer*)At(1)).Offset(ma_shift);`

Function From ` Trend.mqh`

//+------------------------------------------------------------------+
//| Initialize indicator with the special parameters.                |
//+------------------------------------------------------------------+
bool CiBands::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                         const int ma_period,const int ma_shift,
                         const double deviation,const int applied)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- string of status of drawing
      m_name  ="Bands";
      m_status="("+symbol+","+PeriodDescription()+","+
                IntegerToString(ma_period)+","+IntegerToString(ma_shift)+","+
                DoubleToString(deviation)+","+PriceDescription(applied)+") H="+IntegerToString(m_handle);
      //--- save settings
      m_ma_period=ma_period;
      m_ma_shift =ma_shift;
      m_deviation=deviation;
      m_applied  =applied;
      //--- create buffers
      ((CIndicatorBuffer*)At(0)).Name("BASE_LINE");
      ((CIndicatorBuffer*)At(0)).Offset(ma_shift);
      ((CIndicatorBuffer*)At(1)).Name("UPPER_BAND");
      ((CIndicatorBuffer*)At(1)).Offset(ma_shift);
      ((CIndicatorBuffer*)At(2)).Name("LOWER_BAND");
      ((CIndicatorBuffer*)At(2)).Offset(ma_shift);
      //--- ok
      return(true);
     }
//--- error
   return(false);
  }

  • How can I see what is using all this memory?
  • Is it just the candles/tick data being read from disk? Still seems excessive. If so is there a more efficient way to handle this data? only read chunks of it at a time? 


The algo is pretty large so not easy to upload.. here is the some code from it: 

void OnTick()
  {

// Check if we have a new x Minute bar. if we do, call OnNewBar() in our AsianRangeStrategy
   if(asianRangeStrategy != NULL)
     {
      asianRangeStrategy.CheckNewBar();
     }
   else
     {
      DPrint("Error with asianRangeStrategy ",ERROR);
     }
  }

.... 
// From Breakout Class

// Call this method in OnTick of each strategy
    void CheckNewBar() {
      datetime currentBarTime = iTime(_Symbol, _Period, 0); // iTime(_Symbol, _Period, 0) gets the time of the most recently completed bar.
      if (currentBarTime != lastBarTime) {
        lastBarTime = currentBarTime;
        OnNewBar();
      }
    }

// From RangeBreakout Class
virtual void OnNewBar() override {

        ResetBreakoutStrategy(); // If we move passed our breakout duration time, cancel all pending orders, reset our variables for the next window.
        CalculateUserBreakoutTimes(); // There will likley be some down time before our next window builds... need to notice that. 
        CheckBreakoutZone(currentTime); // Check if we are still in the breakout zone or not. 
        rlxdEntry.UpdateRlxdIndicators(); // Update our indicator values.

        // If we are past the breakout zone period and the zone is defined, lets check if we hit a high or low to trigger an entry:
        if (currentTime > GetBreakoutEnd() && !IsBreakoutZoneActive() && IsBreakoutZoneDefined()) {
            
            // WaitForTrigger
            DPrint("Checking if Zone is Triggered",DEV);
            if (IsBreakoutTriggered(lastBarHigh,lastBarLow)) { // Check if we have a break above or below the asian range line. 
                DPrint("Breakout Triggered",DEV);
            }
         if (GetBreakoutHighTriggered()){
                // Check Entry Critia Met
        }

        if (GetBreakoutLowTriggered()){
                // Check Entry Criteria Met
        }
}


The entry logic is where the Indicators are initialised: 

class RlxdEntry
  {
    CiBands bbands; // Bollinger Bands instance as a member variable
    bool isBBandsInitialized; // Flag to check if bands are initialized

         protected:
                double upper_band, lower_band, middle_band;
                double linRegValue, prev_linRegValue, prev_lower_band, prev_upper_band;
                bool isLSMAInitialized;
                int linRegHandle;  // Store the handle at class level

        RlxdEntry()
      {
        dragon_bands_period = 10;
        dragon_deviation = 0.5;
        EMA30Period = 30;
        prev_linRegValue = prev_lower_band = prev_upper_band = 0;
        rlxdLongState = CRITERIA_NOT_MET;
        rlxdShortState = CRITERIA_MET;
        symbolDigits = SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
        direction = NA;
        isBBandsInitialized = false;
        isLSMAInitialized = false;
        linRegHandle = INVALID_HANDLE;  // Store the handle at class level
        pipettePadding = 0;
        InitializeBBandsIndicators();
        pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
      }

      // Destructor
      virtual ~RlxdEntry() {
        IndicatorRelease(linRegHandle);
      }

      double GetATR(int atrPeriod) {
          int ATRHandle = iATR(_Symbol, _Period, atrPeriod); // Returns a handle for ATR. Use _Period for the current chart's timeframe
          double ATRValue[1]; // Array to store the ATR value

          if(ATRHandle != INVALID_HANDLE) {
              ArraySetAsSeries(ATRValue, true); // Set the ATRValue to timeseries, 0 is the current bar

              // Attempt to copy the latest ATR value
              if(CopyBuffer(ATRHandle, 0, 0, 1, ATRValue) > 0) {
                  // Successfully copied the ATR value
                  DPrint("ATR Value: "+ RoundToDigits(ATRValue[0],symbolDigits),DEBUG_DEBUG); // Print the value of the ATR
                  IndicatorRelease(ATRHandle); // Release the handle now that we're done with it
                  return RoundToDigits(ATRValue[0],symbolDigits); // Return the ATR value
              } else {
                  // Failed to copy the ATR value
                  Print("Error copying ATR buffer: ", GetLastError());
              }
              IndicatorRelease(ATRHandle); // Release the handle here, inside the check for INVALID_HANDLE
          } else {
              // Failed to obtain the ATR handle
              Print("Failed to obtain ATR handle: ", GetLastError());
          }

          return 0; // Return 0 or an appropriate error value if unable to obtain/copy the ATR value
      }

     void InitializeLSMA() {
        if(linRegHandle != INVALID_HANDLE) IndicatorRelease(linRegHandle); // Release existing handle if valid
        linRegHandle = iCustom(symbol, timeframe, "Examples\\LSMA", 10, PRICE_CLOSE, 0, 0);
        isLSMAInitialized = linRegHandle != INVALID_HANDLE;
    }

      void UpdateLSMA() {
          if (!isLSMAInitialized) {
              InitializeLSMA(); // Initialize LSMA if not done yet
          }

          if (isLSMAInitialized) {
              double linRegArray[1];
              //if (CopyBuffer(linRegHandle, 0, 1, 1, linRegArray) > 0) {
              if (CopyBuffer(linRegHandle, 0, 1, 1, linRegArray) > 0) {
                  DPrint("UpdateLSMA():", DEBUG_TRACE);
                  prev_linRegValue = linRegValue;  // Save the old value
                  linRegValue = RoundToDigits(linRegArray[0], symbolDigits);  // Update with the new value
                  DPrint("UpdateLSMA() prev_linRegValue linRegValue:"+" "+prev_linRegValue+" "+linRegValue, DEBUG_DEBUG);
              } else {
                  DPrint("Error copying buffer for LSMA: "+ GetLastError(),ERROR);
              }
          }
      }

      void InitializeBBandsIndicators() {
        DPrint("InitializeIndicators(): Initialize Indicators", DEBUG_TRACE);
        if(!isBBandsInitialized) {
          if(bbands.Create(_Symbol, _Period, dragon_bands_period, 0, dragon_deviation, PRICE_CLOSE)) {
            DPrint("InitializeIndicators(): Initialize Indicators: isBBandsInitialized: true", DEBUG_TRACE);
            isBBandsInitialized = true;
          } else {
            DPrint("Error creating Bollinger Bands indicator!", ERROR);
          }
        }
      }

      void UpdateDragonLevels(){
        DPrint("UpdateDragonLevels()",DEBUG_DEBUG);
        if(isBBandsInitialized) {
            // Store current values into previous values before updating
            DPrint("UpdateDragonLevels(): Store current dragon values into previous values before updating", DEBUG_DEBUG);
            bbands.Refresh(OBJ_ALL_PERIODS);
            double tempUpper = bbands.Upper(1);  // Temporarily store the value
            double tempLower = bbands.Lower(1);  // Temporarily store the value
            
            // Check if the values are valid before updating
            if (!IsInvalidPrice(tempUpper) && !IsInvalidPrice(tempLower)) {
              DPrint("UpdateDragonLevels(): Get current dragon levels", DEBUG_DEBUG);
              prev_upper_band = upper_band;
              prev_lower_band = lower_band;

              upper_band = RoundToDigits(bbands.Upper(1), symbolDigits);  // Value of the upper band for the most recent bar
              middle_band = RoundToDigits(bbands.Base(1), symbolDigits);  // Value of the middle band for the most recent bar
              lower_band = RoundToDigits(bbands.Lower(1), symbolDigits);  // Value of the lower band for the most recent bar
              DPrint("p_upper_band p_lower_band:  "+" "+prev_upper_band+" "+prev_lower_band, DEBUG_DEBUG);
              DPrint("upper_band lower_band:      "+" "+upper_band+" "+lower_band, DEBUG_DEBUG);
            }else{
               DPrint("UpdateDragonLevels(): IsInvalidPrice levels: tempUpper tempLower"+tempLower +" "+tempLower, DEBUG_DEBUG);
            }
        } else {            
            DPrint("UpdateDragonLevels(): Initialize Indicators", DEBUG_DEBUG);
            InitializeBBandsIndicators(); // Attempt to initialize if not yet done
        }
      }

    void UpdateRlxdIndicators()
    {
      UpdateDragonLevels();
      UpdateLSMA();
    }


Hoping someone can point me in the right direction to try find what is using all the memory?

 
John M:

I am backtesting my algo on MT5 Version 5.00 Build 4153 22 Jan 24 on OSX Sonoma 14.3 M1 Max (10 Cores) 64 GB Ram. 

When I do it uses a lot of memory and even runs out of application memory space. 



I am only using 1 core in this example because when I use more than 1 agent it runs out of space quicker. 



I get no errors in Journal when running locally, I just run out of memory with the above errors:

When I run an optimisation with 7896 steps using MQL Cloud Network I get the following errors:

 

 I tried to detect an issue with: `checkForMemLeak.mqh` but nothing was found. Each time I create a new Object I am deleting the object. I create all my arrays with a fixed size, and I a believe I only initialise my indicators once and I release my indicator  handles via the  destructor.


The 65 critical errors are just reporting: ` error "critical runtime error 505 in global initialization function (out of memory)"` below error might a symptom of running out of memory and maybe not the cause but I can't be sure.  I can't seem to find this file: Trend.mqh in MT5 to view it. I can see it referenced here (which is not mine) and line 370 is: `      ((CIndicatorBuffer*)At(1)).Offset(ma_shift);`

Function From ` Trend.mqh`


  • How can I see what is using all this memory?
  • Is it just the candles/tick data being read from disk? Still seems excessive. If so is there a more efficient way to handle this data? only read chunks of it at a time? 


The algo is pretty large so not easy to upload.. here is the some code from it: 


The entry logic is where the Indicators are initialised: 


Hoping someone can point me in the right direction to try find what is using all the memory?

Difficult to say from the code you have shown.

But you can insert some debug code to check what is eating all your memory.

Take a look here:

Use one of these to track your memory usage:

TERMINAL_MEMORY_PHYSICAL

Physical memory in the system, MB

int

TERMINAL_MEMORY_TOTAL

Memory available to the process of the terminal (agent), MB

int

TERMINAL_MEMORY_AVAILABLE

Free memory of the terminal (agent) process, MB

int

TERMINAL_MEMORY_USED

Memory used by the terminal (agent), MB

int

 
Thanks @ Dominik Egert I added this to the script.

I think it has something to do we how I am managing orders, the Used Memory: 412 MB seems to be growing after I create positions

2024.02.12 20:49:09.498 2024.02.09 10:00:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.498 2024.02.09 10:00:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.498 2024.02.09 10:00:00   Available Memory: 142948 MB
2024.02.12 20:49:09.498 2024.02.09 10:00:00   Used Memory: 412 MB
2024.02.12 20:49:09.502 2024.02.09 10:05:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.502 2024.02.09 10:05:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.502 2024.02.09 10:05:00   Available Memory: 142948 MB
2024.02.12 20:49:09.502 2024.02.09 10:05:00   Used Memory: 412 MB
2024.02.12 20:49:09.508 2024.02.09 10:10:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.509 2024.02.09 10:10:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.509 2024.02.09 10:10:00   Available Memory: 142948 MB
2024.02.12 20:49:09.509 2024.02.09 10:10:00   Used Memory: 412 MB
... 
2024.02.12 20:49:09.517 2024.02.09 10:20:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.517 2024.02.09 10:20:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.517 2024.02.09 10:20:00   Available Memory: 142948 MB
2024.02.12 20:49:09.517 2024.02.09 10:20:00   Used Memory: 412 MB
2024.02.12 20:49:09.519 2024.02.09 10:20:00   Placing order: Symbol = EURUSD.i, Volume = 0.79, Price = 1.07729, SL = 1.07792, TP = 1.07527
2024.02.12 20:49:09.521 2024.02.09 10:20:00   sell stop 0.79 EURUSD.i at 1.07729 sl: 1.07792 tp: 1.07527 (1.07761 / 1.07762 / 1.07761)
2024.02.12 20:49:09.523 2024.02.09 10:20:00   Sell Stop Order Order placed successfully, Ticket: 2
2024.02.12 20:49:09.531 2024.02.09 10:25:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.531 2024.02.09 10:25:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.531 2024.02.09 10:25:00   Available Memory: 142930 MB
2024.02.12 20:49:09.531 2024.02.09 10:25:00   Used Memory: 430 MB
...
2024.02.12 20:49:09.551 2024.02.09 10:45:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.551 2024.02.09 10:45:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.551 2024.02.09 10:45:00   Available Memory: 142930 MB
2024.02.12 20:49:09.551 2024.02.09 10:45:00   Used Memory: 430 MB
2024.02.12 20:49:09.551 2024.02.09 10:49:03   order [#2 sell stop 0.79 EURUSD.i at 1.07729] triggered
2024.02.12 20:49:09.552 2024.02.09 10:49:03   deal #2 sell 0.79 EURUSD.i at 1.07729 done (based on order #2)
2024.02.12 20:49:09.552 2024.02.09 10:49:03   deal performed [#2 sell 0.79 EURUSD.i at 1.07729]
2024.02.12 20:49:09.552 2024.02.09 10:49:03   order performed sell 0.79 at 1.07729 [#2 sell stop 0.79 EURUSD.i at 1.07729]
2024.02.12 20:49:09.555 2024.02.09 10:49:03   Alert: OnTradeTransaction() DEAL_TYPE: 1
2024.02.12 20:49:09.555 2024.02.09 10:49:03   New Short Position executed. Total Short Trades: 1
2024.02.12 20:49:09.562 2024.02.09 10:50:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.562 2024.02.09 10:50:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.562 2024.02.09 10:50:00   Available Memory: 142912 MB
2024.02.12 20:49:09.562 2024.02.09 10:50:00   Used Memory: 448 MB
...
2024.02.12 20:49:09.948 2024.02.09 15:31:05   stop loss triggered #2 sell 0.79 EURUSD.i 1.07729 sl: 1.07792 tp: 1.07527 [#3 buy 0.79 EURUSD.i at 1.07792]
2024.02.12 20:49:09.949 2024.02.09 15:31:05   deal #3 buy 0.79 EURUSD.i at 1.07793 done (based on order #3)
2024.02.12 20:49:09.949 2024.02.09 15:31:05   deal performed [#3 buy 0.79 EURUSD.i at 1.07793]
2024.02.12 20:49:09.949 2024.02.09 15:31:05   order performed buy 0.79 at 1.07793 [#3 buy 0.79 EURUSD.i at 1.07792]
2024.02.12 20:49:09.949 2024.02.09 15:31:05   Alert: OnTradeTransaction() DEAL_TYPE: 0
2024.02.12 20:49:09.949 2024.02.09 15:31:05   Alert: Stop Loss activation
2024.02.12 20:49:09.949 2024.02.09 15:31:05   Alert: BUY: Stop Loss activation
2024.02.12 20:49:09.957 2024.02.09 15:35:00   Physical Memory: 71680 MB
2024.02.12 20:49:09.957 2024.02.09 15:35:00   Total Memory Available to Process: 143360 MB
2024.02.12 20:49:09.957 2024.02.09 15:35:00   Available Memory: 142912 MB
2024.02.12 20:49:09.957 2024.02.09 15:35:00   Used Memory: 448 MB




ulong OrderTicket;
trade.PlaceSellStopOrder(_Symbol, RoundToDigits(positionSize,2), entryPrice, stopLossPrice, takeProfitPrice,OrderTicket);



// Utility function to place a sell stop order and capture order placement information
    void PlaceSellStopOrder(string symbol, double volume, double price, double sl, double tp, ulong &orderTicket) {
        string comment = "Sell Stop Order";
        ENUM_ORDER_TYPE orderType = ORDER_TYPE_SELL_STOP;
        
        if (!AreTradingConditionsValid(symbol, price, false)) {
            Print("Trading conditions are not valid for placing a sell stop order.");
            comment = "Sell Limit Order, Instead of Stop";
            orderType = ORDER_TYPE_SELL_LIMIT;
            //return;
        }

        MqlTradeRequest request = {};
        MqlTradeResult result = {};
        Print("Placing order: Symbol = ", symbol, ", Volume = ", volume, ", Price = ", price, ", SL = ", sl, ", TP = ", tp);

        request.action = TRADE_ACTION_PENDING;   // Pending order
        request.symbol = symbol;                 // Trading symbol
        request.volume = volume;                 // Volume in lots
        request.type = orderType;     // Order type
        request.price = price;                   // Price at which to sell
        request.sl = sl;                         // Stop loss
        request.tp = tp;                         // Take profit
        request.deviation = 10;                  // Deviation in points
        request.magic = 0;                       // Magic number
        request.comment = comment;     // Comment

        int attempts = 3; // Number of attempts to send the order
        bool orderPlaced = false;

        for (int i = 0; i < attempts && !orderPlaced; i++) {
            if (OrderSend(request, result)) {
                orderPlaced = true;
                orderTicket = result.order;
                Print(comment," Order placed successfully, Ticket: ", result.order);
                datetime startTime = TimeCurrent(); // Start time (current time)
                datetime endTime = TimeCurrent() + PeriodSeconds(PERIOD_M5) * 3; // End time (3 bars ahead)
                string objectName = "EntryPriceLine" + StringFormat("%d", TimeCurrent());
                // ObjectCreate(0, objectName, OBJ_TREND, 0, startTime, price, endTime, price);
                // ObjectSetInteger(0, objectName, OBJPROP_COLOR, clrRed); // Set color to red (optional)
                //return true;
            } else {
                Print("Attempt ", i + 1, " failed to place Sell Stop Order, Error code: ", GetLastError());
                Sleep(1000); // Wait for 1 second before retrying
            }
        }

        if (!orderPlaced) {
            Print("Failed to place Sell Stop Order after ", attempts, " attempts.");
            //return false;
        }
    }
bool AreTradingConditionsValid(string symbol, double price, bool isBuyOrder) {
        double currentPrice = isBuyOrder ? SymbolInfoDouble(symbol, SYMBOL_ASK) : SymbolInfoDouble(symbol, SYMBOL_BID);
        // For a buy stop order, the entry price should be above the current ask price
        if (isBuyOrder && price <= currentPrice) {
            Print("Current ask price: ", currentPrice, " is too low for a buy stop order. Entry price: ", price);
            return false;
        }
        // For a sell stop order, the entry price should be below the current bid price
        if (!isBuyOrder && price >= currentPrice) {
            Print("Current bid price: ", currentPrice, " is too high for a sell stop order. Entry price: ", price);
            return false;
        }
        // Additional checks can be added here (e.g., market hours, symbol trade status)
        return true;
    }

This is where I manage some of the order events: 

void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
   if(type==TRADE_TRANSACTION_DEAL_ADD)
     {
      if(HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
        {
         Print(__FILE__," ",__FUNCTION__,", ERROR: HistoryDealSelect(",trans.deal,")");
         return;
        }
      //---
      long reason=-1;
      if(!m_deal.InfoInteger(DEAL_REASON,reason))
        {
         Print(__FILE__," ",__FUNCTION__,", ERROR: InfoInteger(DEAL_REASON,reason)");
         return;
        }
      ENUM_DEAL_TYPE dt = m_deal.DealType(); // Directly use DealType() method

      Alert("OnTradeTransaction() DEAL_TYPE: ", dt);

      if((ENUM_DEAL_REASON)reason==DEAL_REASON_SL)
        {
         Alert("Stop Loss activation");
         if(dt == DEAL_TYPE_BUY)
           {
            Alert("BUY: Stop Loss activation"); // We had a short order originally
            asianRangeStrategy.SetEntryStrategyState(SHORT_STOP_LOSS_TRIGGERED);
           }
         else
            if(dt == DEAL_TYPE_SELL)
              {
               Alert("SELL: Stop Loss activation");  // We had a long order originally
               asianRangeStrategy.SetEntryStrategyState(LONG_STOP_LOSS_TRIGGERED);
              }
         // Reset the Entry Criteria so we can go long on the next RLxD

        }
      else
        {
         if((ENUM_DEAL_REASON)reason==DEAL_REASON_TP)
           {
            Alert("Take Profit activation");
            if(dt == DEAL_TYPE_BUY)
              {
               Alert("BUY: Stop Loss activation"); // We had a short order originally
               asianRangeStrategy.SetEntryStrategyState(SHORT_TAKE_PROFIT_TRIGGERED);
              }
            else
               if(dt == DEAL_TYPE_SELL)
                 {
                  Alert("SELL: Stop Loss activation"); // We had a long order originally
                  asianRangeStrategy.SetEntryStrategyState(LONG_TAKE_PROFIT_TRIGGERED);
                 }
           }
        }
      // Check if the deal is for entry (opening a position)
      if(HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_IN)
        {
         // Now determine if the deal is a buy or sell to increment the correct counter
         ENUM_DEAL_TYPE dealType = (ENUM_DEAL_TYPE)HistoryDealGetInteger(trans.deal, DEAL_TYPE);
         if(dealType == DEAL_TYPE_BUY)
           {
            // Increment long trades counter for a new long position
            asianRangeStrategy.longTrades++;
            Print("New Long Position executed. Total Long Trades: ", asianRangeStrategy.longTrades);
           }
         else
            if(dealType == DEAL_TYPE_SELL)
              {
               // This would be for short trades, in case you want to track those separately
               asianRangeStrategy.shortTrades++;
               Print("New Short Position executed. Total Short Trades: ", asianRangeStrategy.shortTrades);
              }
        }
     }
  }

I am going to keep trying to narrow down what is increasing the memory usage, but if you can see anything obvious in what I am doing above please let me know. 

Dominik Egert
Dominik Egert
  • 2024.01.28
  • www.mql5.com
Trader's profile
 

Found the culprit. Will work out why

double atr =GetATR(14) * 100000;
double stoploss = atr* rm.GetAtrMultiplier();

 
John M:
double GetATR(int atrPeriod) {
          int ATRHandle = iATR(_Symbol, _Period, atrPeriod); // Returns a handle for ATR. Use _Period for the current chart's timeframe
          double ATRValue[1]; // Array to store the ATR value

          if(ATRHandle != INVALID_HANDLE) {
              ArraySetAsSeries(ATRValue, true); // Set the ATRValue to timeseries, 0 is the current bar

              // Attempt to copy the latest ATR value
              if(CopyBuffer(ATRHandle, 0, 0, 1, ATRValue) > 0) {
                  // Successfully copied the ATR value
                  DPrint("ATR Value: "+ RoundToDigits(ATRValue[0],symbolDigits),DEBUG_DEBUG); // Print the value of the ATR
                  IndicatorRelease(ATRHandle); // Release the handle now that we're done with it
                  return RoundToDigits(ATRValue[0],symbolDigits); // Return the ATR value
              } else {
                  // Failed to copy the ATR value
                  Print("Error copying ATR buffer: ", GetLastError());
              }
              IndicatorRelease(ATRHandle); // Release the handle here, inside the check for INVALID_HANDLE
          } else {
              // Failed to obtain the ATR handle
              Print("Failed to obtain ATR handle: ", GetLastError());
          }

          return 0; // Return 0 or an appropriate error value if unable to obtain/copy the ATR value
      }

I'm not an expert in MQL5, but maybe it's worth trying to do this only from OnInit, and do this only from OnDeinit?

After all, you most likely call GetATR() from OnTick/OnCalculate, creating and deleting an indicator each time
 
Thanks @Vladislav Boyko, that is similar to what I did, I broke up that function into separate functions that took care of the initialisation, calling and releasing separately which has solved the issue. 
Reason: