Cheapest way to dicover the value of closed positions within a period

 

I might want to calculate the value of all closed positions within a given period.

/*
 * Pick up profit so far today for all deals that have completed, for all EA's
 * for a specific magic # & symbol.
 * 
 * Parameters: None
 *
 * Returns: profit as a double, 0 on none found or error.
 * 
 */
double day_profit_so_far(datetime start, datetime end, string symbol, ulong magic)
{
   int deals_total;
   double profit = 0.0;
   ulong ticket = 0;
   CDealInfo m_deal;
   int found = 0;

   HistorySelect(start, end); 
   deals_total = (int)HistoryDealsTotal();
   
   for( int i = 0 ; i < deals_total ; i++ ) {
      if ( (ticket = HistoryDealGetTicket(i)) == 0 )
         continue;
      m_deal.Ticket(ticket);
      if ( m_deal.Magic() != magic )
         continue;
      if ( m_deal.Symbol() != symbol )
         continue;
      if ( m_deal.DealType() != DEAL_TYPE_BUY && m_deal.DealType() != DEAL_TYPE_SELL )
         continue;
      if ( m_deal.Entry() != DEAL_ENTRY_OUT )
         continue;

      printf("%s[%d], %s: ticket %u profit %.2f",
         __FILE__, __LINE__, __FUNCTION__, ticket, m_deal.Profit());
      profit += m_deal.Profit();
      found++;
   }
   return(profit);
}

It might look something like the above. It seems an incredibly expensive way to calculate for instance, the value of trades so far today if I had restarted an EA.

I say this because my understanding is that just about every operation on an order/position market/pending order involvers a deal. If you are running broker side trailing stop loss, there might be a lot of deals.

I haven't seen a state diagram showing the relationships & flows between deals, orders & positions.

So is there a better way of doing this? I can see I can use CHistoryOrderInfo in cahoots with HistorySelect() and I could check the state to see if it is in state ORDER_STATE_FILLED, but I still only have access to PriceOpen() & PriceCurrent(), and their meaning/content is not extensively described (IMHO).

What am I missing? is it the case that I just parse every deal as above?

Yours a little frustrated, ESB.

 
Earthy Stag beetle:

I might want to calculate the value of all closed positions within a given period.

It might look something like the above. It seems an incredibly expensive way to calculate for instance, the value of trades so far today if I had restarted an EA.

I say this because my understanding is that just about every operation on an order/position market/pending order involvers a deal. If you are running broker side trailing stop loss, there might be a lot of deals.

I haven't seen a state diagram showing the relationships & flows between deals, orders & positions.

So is there a better way of doing this? I can see I can use CHistoryOrderInfo in cahoots with HistorySelect() and I could check the state to see if it is in state ORDER_STATE_FILLED, but I still only have access to PriceOpen() & PriceCurrent(), and their meaning/content is not extensively described (IMHO).

What am I missing? is it the case that I just parse every deal as above?

Yours a little frustrated, ESB.

Have a look at looping through positions, orders, and deals in the following indicator (utility). The code can be readily copied into an EA, and you merely have to insert your desired times therein... and tally up your deal history accordingly. It's deals loop is substantially the same as your code, but this utility shows positions and orders code for purposes of contrasting with deals.

Code Base

Show Positions on Custom Chart (or standard chart) for MT5

Ryan L Johnson, 2025.06.02 14:02

This indicator is a utility that shows labelled trade levels on any chart. If you want to replace your native trade levels on a native chart, then turn off "Show trade levels" in your F8 Chart Properties and attach this indicator. If you want to show trade levels on a Custom Chart (where native trade levels cannot be shown), then simply attach this indicator. BaseSymbol - specify the Symbol from which the trade level data will be pulled--handy for unique Custom Symbols. TextBarsBack - specify the number of bars back in history from the current bar where the level labels will be drawn. Note: Although magic number is referenced in the code, it is not presently included in the trade lines. If you're running multiple EA's on the same Symbol, you can edit the code to show magic numbers and then run multiple instances of the indicator on one chart. You can also edit the font sizes and text spacing in the object properties as needed for different display resolutions.

And a brief description of positions, orders, and deals:

MQL5 Book: Basic principles and concepts: order, deal, and position / Trading automation
MQL5 Book: Basic principles and concepts: order, deal, and position / Trading automation
  • www.mql5.com
Before starting to study the development of Expert Advisors in MQL5, let's recall the general architecture of the platform and the basic concepts...
 

Thank you Ryan for taking the trouble to read & reply;

I have had a look at your useful indicator Show Positions on Custom Chart (or standard chart) for MT5 and in terms of deals, order & positions, it's doing what I'd expect.

I think in essence, the nub of my question is:

Is there any way of discovering cumulative profit for a given period other than searching through every deal, looking for DEAL_ENTRY_OUT and accumulating the profit of those deals?

Your indicator contains the following code:
HistorySelect(0,TimeCurrent());
//--- obtain the total number of orders
int horders = HistoryOrdersTotal();
//--- scan the list of deals
for(int i=0; i<horders; i++)
     {
      //--- if the order is closed...
      if(historyOrderInfo.SelectByIndex(i))
  {
   // Read order out and get order state
   if((historyOrderInfo.Ticket()==ord_id)
  && (historyOrderInfo.State()==ORDER_STATE_CANCELED
  || historyOrderInfo.State()==ORDER_STATE_EXPIRED
  || historyOrderInfo.State()==ORDER_STATE_FILLED
  || historyOrderInfo.State()==ORDER_STATE_PARTIAL
  || historyOrderInfo.State()==ORDER_STATE_REJECTED))
{  
// delete the horizontal line  
} 

It occurred to me that it might be meaningful to look for history orders with a state of ORDER_STATE_FILLED rather than a list of all deals pertaining to an order. If it was meaningful, how would that be reconciled as the concomitant order closing a position. Lastly, what meaning can be attributed to the HistoryOrderInfo PriceCurrent() for?

I might be barking up the wrong tree and parsing all deals looking for DEAL_ENTRY_OUT might be the only way to do this, as in the code I posted earlier.

With my best regards, Paul.

Show Positions on Custom Chart (or standard chart) for MT5
Show Positions on Custom Chart (or standard chart) for MT5
  • 2025.06.02
  • www.mql5.com
This indicator is a utility that shows labelled trade levels on any chart. If you want to replace your native trade levels on a native chart, then turn off "Show trade levels" in your F8 Chart Properties and attach this indicator. If you want to show trade levels on a Custom Chart (where native trade levels cannot be shown), then simply attach this indicator. BaseSymbol - specify the Symbol from which the trade level data will be pulled--handy for unique Custom Symbols. TextBarsBack - specify the number of bars back in history from the current bar where the level labels will be drawn. Note: Although magic number is referenced in the code, it is not presently included in the trade lines. If you're running multiple EA's on the same Symbol, you can edit the code to show magic numbers and then run multiple instances of the indicator on one chart. You can also edit the font sizes and text spacing in the object properties as needed for different display resolutions.
 
Earthy Stag beetle #:
Is there any way of discovering cumulative profit for a given period other than searching through every deal, looking for DEAL_ENTRY_OUT and accumulating the profit of those deals?

The most efficient way that I've found is doing exactly that. I previously posted the indicator merely to illustrate the differences between positions, orders, and deals which you inquired about in your OP.

Having said that, see the following post if you want to filter by position ID:

Forum on trading, automated trading systems and testing trading strategies

[SOLVED] How get profit from position ticket in history tab?

J_128, 2020.06.15 04:40

Thanks all, I solved my problem...

My code:

string example(){
   ulong ticket = 131104675; // Ticket search 
   ulong deal_ticket = -1;

   datetime end_date_history = TimeTradeServer(); // Current Time
   datetime start_date_history = end_date_history - 432000; // Decrease 5 day = 432000 seconds
   
   // rage date
   HistorySelect(start_date_history, end_date_history);
   
   // Total deals
   int total_deals = HistoryDealsTotal(); 
   if(total_deals > 0){
      total_deals -= 1;
      
      for(int x = total_deals; x >= 0; x--){
         deal_ticket = HistoryDealGetTicket(x);
         if(deal_ticket > 0 && HistoryDealGetInteger(deal_ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT && HistoryDealGetInteger(deal_ticket, DEAL_POSITION_ID) == ticket){
            if(HistoryOrderSelect(ticket)){
               Print((string)HistoryDealGetDouble(deal_ticket, DEAL_PROFIT));
               /* Here other functions for example 
                  HistoryOrderGetDouble(ticket, ORDER_TP);
               */               
               return "";               
            }else{
               return "-1";
            }  
         }   
      }
      return "-1";  
   }else{
      return "-1";
   }              
}

Bye all ;)


 

Paul, to your follow-up in #2: scanning deals really is the only reliable route, because profit is a property of deals, not orders. A history order never carries P/L — one order can produce several deals via partial fills, and profit is booked per deal, so ORDER_STATE_FILLED only tells you the order executed, not what it earned. As for PriceCurrent() on a historical order: ORDER_PRICE_CURRENT is just the symbol price recorded at the order's last state change — occasionally useful for diagnostics, not for accounting.

On the cost concern: the expense is bounded by the HistorySelect() window, not the account's lifetime history. For "profit so far today", select from midnight server time (or iTime(_Symbol, PERIOD_D1, 0)) to TimeCurrent() and you will typically iterate a handful of deals. If you want it cheaper still, run the full scan once in OnInit() to seed a running total after a restart, then update it incrementally in OnTradeTransaction() whenever a TRADE_TRANSACTION_DEAL_ADD arrives with DEAL_ENTRY_OUT and your magic — no per-tick rescanning at all.

One accounting detail: DEAL_PROFIT excludes trading costs. Add DEAL_COMMISSION and DEAL_SWAP per deal if you want net figures that reconcile with the terminal's history tab.

 
Mobina Bayat #:
On the cost concern: the expense is bounded by the HistorySelect()

The historySelect comes with its own expense. It was a known issue that a large trading history (30k+ trades) caused a huge lag. Not sure if it is fixed today. 

Anayways, in order to do it fast regardless and deal with a ton of terminal nuances, use MT4Orders library https://www.mql5.com/ru/forum/93352

It allows for simple and clean MT4 style code:

int ticketNumber = 12345678; 
if(OrderSelect(ticketNumber, SELECT_BY_TICKET, MODE_HISTORY)) {
    double profit = OrderProfit() + OrderCommission() + OrderSwap();
    
    Print("Ticket #", ticketNumber, "Profit: ", profit );
} else {
    Print("Failed to select order. Error code: ", GetLastError());
}
 
Mobina Bayat #:
run the full scan once in OnInit()

Hi Mobina,

I think running the full scan once when I start, and looking for DEAL_ENTRY_OUT is a good idea.

void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{
   CDealInfo deal;

   switch ( trans.type ) {
      //case TRADE_TRANSACTION_ORDER_ADD:
      //case TRADE_TRANSACTION_ORDER_UPDATE:
      //case TRADE_TRANSACTION_ORDER_DELETE:
      //case TRADE_TRANSACTION_REQUEST:
      case TRADE_TRANSACTION_HISTORY_ADD: // Adding an order to the history as a result of execution or cancellation
      {
         /* Order ID in an external system - a ticket assigned by an Exchange
          * see: https://www.mql5.com/en/docs/event_handlers/ontradetransaction
          */
         ulong order_ticket, deal_ticket;
         if(trans.order_state==ORDER_STATE_FILLED) {
            if(HistoryOrderSelect(trans.order)) {
               order_ticket=HistoryOrderGetInteger(trans.order, ORDER_TICKET);
               printf("%s[%d], %s: History ORDER_STATE_FILLED: %s order #%I64u %s %s %s %ld",
                  __FILE__, __LINE__, __FUNCTION__, EnumToString(trans.type),
                  trans.order,EnumToString(trans.order_type),trans.symbol,EnumToString(trans.order_state), order_ticket);
            }
            deal.Ticket(trans.deal);
            if ( deal.DealType() != DEAL_TYPE_BUY && deal.DealType() != DEAL_TYPE_SELL )
               return;
            if ( deal.Entry() != DEAL_ENTRY_OUT )
               return;
            printf("%s[%d], %s: Deal profit=%.2f"
               __FILE__, __LINE__, __FUNCTION__, Deal.Profit());
         return;
      }
      default:
         return;
   }
}

This is kind of pseudo code, and I am not sure I am following the (unwritten) state model for transaction, orders, deals - but the idea is:

  • run the full deal scan  at start up
  • pick up extra information on receipt of OnTradeTransaction and update the profit piecemeal as it comes in.

I am stringing together rather hopefully that a transaction type of TRADE_TRANSACTION_HISTORY_ADD might have a transaction order_state of ORDER_STATE_FILLED, and a (concluding) deal entry of DEAL_ENTRY_OUT.

That would be handy! I might compile it and have a look.

WMBR, ESB.