Little help to correct code for a simple trade counter indicator (almost working)

 

Hello al,


I have this code for an indicator that should display the number of manually opened trades during a particular time span, however it gets stuck to 0.


I'm using hedging mode and the orders are opened manually. The script compiles without errors however, the totalTrades is always 0. I'm not sure what is wrong.


Any help to correctly count the number of trades opened during the specified period would be greatly appreciated!


Thank you!


//+------------------------------------------------------------------+
//|                                      TradeCounterIndicator.mq5   |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

#include <Trade\Trade.mqh>
CTrade trade;

//--- input parameters
input int TimePeriodStart = 800;  // Start time in HHMM format
input int TimePeriodEnd = 1700;   // End time in HHMM format
input int X_Position = 10;        // X coordinate for text position
input int Y_Position = 10;        // Y coordinate for text position
input int RefreshInterval = 60;   // Refresh interval in seconds

int totalTrades = 0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Set the timer to call OnTimer function every RefreshInterval seconds
   EventSetTimer(RefreshInterval);
   // Initialization done
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Kill the timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Custom indicator calculation function                           |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   // Update the chart display
   UpdateChartDisplay();
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function to count trades                                  |
//+------------------------------------------------------------------+
void OnTimer()
  {
   // Reset the totalTrades counter
   totalTrades = 0;

   // Convert input times to datetime format
   datetime startTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodStart / 100, TimePeriodStart % 100));
   datetime endTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodEnd / 100, TimePeriodEnd % 100));

   // Loop through the order history
   for(int i = 0; i < HistoryOrdersTotal(); i++)
     {
      ulong ticket = HistoryOrderGetTicket(i);
      if(HistoryOrderSelect(ticket))
        {
         datetime orderOpenTime = (datetime)HistoryOrderGetInteger(ticket, ORDER_TIME_SETUP);
         int orderType = (int)HistoryOrderGetInteger(ticket, ORDER_TYPE);
         // Check if the order was opened within the specified time period
         if(orderOpenTime >= startTime && orderOpenTime <= endTime &&
            (orderType == ORDER_TYPE_BUY || orderType == ORDER_TYPE_SELL))
           {
            totalTrades++;
           }
        }
     }

   // Update the chart display
   UpdateChartDisplay();
  }
//+------------------------------------------------------------------+
//| Update chart display function                                   |
//+------------------------------------------------------------------+
void UpdateChartDisplay()
  {
   // Print the total number of trades
   string resultText = "Total trades executed during the specified period: " + IntegerToString(totalTrades);

   // Create or update a text object to display the result on the chart
   string textName = "TradeCountText";
   if(ObjectFind(0, textName) != 0)
     {
      ObjectCreate(0, textName, OBJ_LABEL, 0, 0, 0);
     }
   ObjectSetInteger(0, textName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, textName, OBJPROP_XDISTANCE, X_Position);
   ObjectSetInteger(0, textName, OBJPROP_YDISTANCE, Y_Position);
   ObjectSetString(0, textName, OBJPROP_TEXT, resultText);
   ObjectSetInteger(0, textName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, textName, OBJPROP_FONTSIZE, 12);
  }
//+------------------------------------------------------------------+
 

You don't need to use OnTimer at all here as you're dealing with positions that are already closed. You have to use HistorySelect, because HistoryOrdersTotal won't return anything without using HistorySelect. I believe HistoryOrderSelect() is the wrong function to use, that's for selecting one order from history to do further processing on it. 


#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

#include <Trade\Trade.mqh>
CTrade trade;

//--- input parameters
input int TimePeriodStart = 800;  // Start time in HHMM format
input int TimePeriodEnd = 1700;   // End time in HHMM format
input int X_Position = 10;        // X coordinate for text position
input int Y_Position = 10;        // Y coordinate for text position
input int RefreshInterval = 60;   // Refresh interval in seconds

int totalTrades = 0;

// Create or update a text object to display the result on the chart
string textName = "TradeCountText";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int OnInit()
  {
   datetime yesterday = TimeCurrent()-86400;
    
   datetime startTime = yesterday;
   datetime endTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE));
   
    // Convert input times to datetime format
 //  datetime startTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodStart / 100, TimePeriodStart % 100));
 //  datetime endTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodEnd / 100, TimePeriodEnd % 100));
   
    HistorySelect(yesterday, TimeCurrent());
    
   // Loop through the order history
   for(int i = 0; i < HistoryOrdersTotal(); i++)
     {
      ulong ticket = HistoryOrderGetTicket(i);
      if(ticket > 0)
        {       
         //Print("FOUND.... ", ticket);   
         totalTrades++;
         
         if(i == HistoryOrdersTotal()-1){
             break;
         }
        }
     }

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   
   ObjectDelete(0, textName);
  }
  

//+------------------------------------------------------------------+
//| Custom indicator calculation function                           |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {


     
   // Update the chart display
   UpdateChartDisplay();

   return(rates_total);
  }


//+------------------------------------------------------------------+
//| Update chart display function                                   |
//+------------------------------------------------------------------+
void UpdateChartDisplay()
  {
   // Print the total number of trades
   string resultText = "Total trades executed during the specified period: " + IntegerToString(totalTrades);


   if(ObjectFind(0, textName) != 0)
     {
      ObjectCreate(0, textName, OBJ_LABEL, 0, 0, 0);
     }
   ObjectSetInteger(0, textName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, textName, OBJPROP_XDISTANCE, X_Position);
   ObjectSetInteger(0, textName, OBJPROP_YDISTANCE, Y_Position);
   ObjectSetString(0, textName, OBJPROP_TEXT, resultText);
   ObjectSetInteger(0, textName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, textName, OBJPROP_FONTSIZE, 12);
  }
  

I ignored your startTime and endTime variable for the convenience of a working example

 
Change to HistorySelect(startTime, endTime); and use those variables like how you had them already.
 

Hello sir, 


Thank you very much for your help, however what you are plotting with this code is the number of orders, not the number of trades. For example, opening and closing the trade will make 2 orders, or also opening the trades, closing half and then closing completely will plot 3 orders whereas I just want 1 to be plotted. I precise I'm using hedging mode in case it is of significance.


And with your code not using Ontimer, the number of orders do not get updated when new orders are done. The indicator will just plot the number of orders at the time the indicator was added to the chart. 


Somehow this trade counter indicator is a bit tricky :/

 

looks like my posts got deleted during the server maintenance. I wrote that what you want to do is not difficult, and you can cut out a lot of overthinking:


//+------------------------------------------------------------------+
//|                                      TradeCounterIndicator.mq5   |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

#include <Trade\Trade.mqh>
CTrade trade;

//--- input parameters
input int TimePeriodStart = 800;  // Start time in HHMM format
input int TimePeriodEnd = 1700;   // End time in HHMM format
input int X_Position = 10;        // X coordinate for text position
input int Y_Position = 10;        // Y coordinate for text position
input int RefreshInterval = 60;   // Refresh interval in seconds

int totalTrades = 0;

// Create or update a text object to display the result on the chart
string textName = "TradeCountText";

datetime startTime, endTime;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int OnInit()
  {

   // Convert input times to datetime format
   startTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodStart / 100, TimePeriodStart % 100));
   endTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodEnd / 100, TimePeriodEnd % 100));
   
   return(INIT_SUCCEEDED);
  }
  
  
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectDelete(0, textName);
}

//+------------------------------------------------------------------+
//| Custom indicator calculation function                           |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

   HistorySelect(startTime, endTime);
       
   totalTrades = HistoryDealsTotal();
  
   // Update the chart display
   UpdateChartDisplay();

   return(rates_total);
  }


//+------------------------------------------------------------------+
//| Update chart display function                                   |
//+------------------------------------------------------------------+
void UpdateChartDisplay()
  {
   // Print the total number of trades
   string resultText = "Total trades executed during the specified period: " + IntegerToString(totalTrades);


   if(ObjectFind(0, textName) != 0)
     {
      ObjectCreate(0, textName, OBJ_LABEL, 0, 0, 0);
     }
   ObjectSetInteger(0, textName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, textName, OBJPROP_XDISTANCE, X_Position);
   ObjectSetInteger(0, textName, OBJPROP_YDISTANCE, Y_Position);
   ObjectSetString(0, textName, OBJPROP_TEXT, resultText);
   ObjectSetInteger(0, textName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, textName, OBJPROP_FONTSIZE, 12);
  }
  
 

Hello sir, thank you very much for your answer


It works fine for the number of orders/deals, but is there a way to count only the number of orders with different ticket numbers ?  


Actually if i open a trade (+1  deal), close half of the trade (+1 deal), and then close it completely (+1 deal) it will plot 3, whereas I wanted it to plot 1 because all deals refer to the same ticket number. Do you know if there is a simple function to call for that ?


Best regards 

 

this is the best solution I can come up with:


//+------------------------------------------------------------------+
//|                                      TradeCounterIndicator.mq5   |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

#include <Trade\Trade.mqh>
CTrade trade;

//--- input parameters
input int TimePeriodStart = 800;  // Start time in HHMM format
input int TimePeriodEnd = 1700;   // End time in HHMM format
input int X_Position = 10;        // X coordinate for text position
input int Y_Position = 10;        // Y coordinate for text position

int totalTrades = 0;

// Create or update a text object to display the result on the chart
string textName = "TradeCountText";

datetime startTime, endTime;

ulong ticketsArray[]; // Array to store unique ticket numbers

//+------------------------------------------------------------------+
//| Custom indicator initialization function                        |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Convert input times to datetime format
   startTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodStart / 100, TimePeriodStart % 100));
   endTime = StringToTime(TimeToString(TimeCurrent(), TIME_DATE) + " " + StringFormat("%02d:%02d", TimePeriodEnd / 100, TimePeriodEnd % 100));
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectDelete(0, textName);
}

//+------------------------------------------------------------------+
//| Custom indicator calculation function                           |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
 
   HistorySelect(startTime, endTime);

   int uniqueTrades = 0;
   int totalDeals = HistoryDealsTotal();
   ulong ticket;
   
  ArrayResize(ticketsArray, 0);
            
   for(int i = 0; i < totalDeals; i++)
     {
      // Get deal ticket
      ticket = HistoryDealGetTicket(i);

 
      if(ArrayBsearch(ticketsArray, ticket) == -1) // Check if this ticket is already counted
        {
         ulong dealType = HistoryDealGetInteger(ticket, DEAL_TYPE);
         int count = (int)HistoryDealGetInteger(ticket, DEAL_ENTRY);

         if(dealType == DEAL_TYPE_BUY || dealType == DEAL_TYPE_SELL)
           {
            uniqueTrades += count; 
           }
        }
     }

   totalTrades = uniqueTrades; // totalTrades gets the count of unique trades (by only adding the deal entry and ignoring the other parts of the deal)

   // Update the chart display
   UpdateChartDisplay();

   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Update chart display function                                   |
//+------------------------------------------------------------------+
void UpdateChartDisplay()
  {
   // Print the total number of unique trades
   string resultText = "Total trades executed during the specified period: " + IntegerToString(totalTrades);

   if(ObjectFind(0, textName) != 0)
     {
      ObjectCreate(0, textName, OBJ_LABEL, 0, 0, 0);
     }
   ObjectSetInteger(0, textName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, textName, OBJPROP_XDISTANCE, X_Position);
   ObjectSetInteger(0, textName, OBJPROP_YDISTANCE, Y_Position);
   ObjectSetString(0, textName, OBJPROP_TEXT, resultText);
   ObjectSetInteger(0, textName, OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(0, textName, OBJPROP_FONTSIZE, 12);
  }


if there are 4 trades made in the period but there are 8 deals in this manner:

1 deal open + 1 deal close

1 deal open + 1 deal close

1 deal open + 1 deal close

1 deal open + 1 deal close


it will now just count the 4 trades, because it counts the deal entry and ignores the other parts of the deal


 

Hello sir,


Thank you very much, we are really close of making it works, however actually your code counts the number of closing deals, not entry. When I open a trade the count remain 0, when i partially close the trade (+1), when I fully close the trade (+1), for a total of 2.


Maybe using the DEAL_TICKET can make the trick to count the number of different ticket used ?


Best

 
Ostinato #:

Hello sir,


Thank you very much, we are really close of making it works, however actually your code counts the number of closing deals, not entry. When I open a trade the count remain 0, when i partially close the trade (+1), when I fully close the trade (+1), for a total of 2.


Maybe using the DEAL_TICKET can make the trick to count the number of different ticket used ?


Best

This is because a deal isn't a deal until it is historic. Positions on the other hand are the active trades.

I thought this is what you wanted though, a simple trade counter. This is pretty much counting the finished trades.

DEAL_TICKET is already counted, and only unique (new) tickets are counted with ArrayBsearch. So you only have 2 options:  count all deals, or count only DEAL_ENTRY (like it is now)

Just add PositionsTotal() to the variable if you want to add the current opened positions:

totalTrades = uniqueTrades + PositionsTotal();
 

Thanks for the answer, yes you are correct, what I want is a simple trade counter, and I have no problem counting the historic finished trades.


But for some reason, when I open a trade (in hedging mode in case it is relevant) and close half of it, it counts as 1 deal, then I close it completely it adds 1 count, for a final count of 2, whereas I wanted to plot 1. 


Are you sure that "only unique (new) tickets are counted with ArrayBsearch." ?


Anyway, thanks a lot for the help

 
Ostinato #:

Thanks for the answer, yes you are correct, what I want is a simple trade counter, and I have no problem counting the historic finished trades.


But for some reason, when I open a trade (in hedging mode in case it is relevant) and close half of it, it counts as 1 deal, then I close it completely it adds 1 count, for a final count of 2, whereas I wanted to plot 1. 


Are you sure that "only unique (new) tickets are counted with ArrayBsearch." ?


Anyway, thanks a lot for the help

Yes. I tested it. It counts finished trades perfectly as long as you don't modify a position, so I don't know what you can do about that...you'll have to do some check to see if a trade was modified and if so, subtract 1 from the variable