Re: fetching trade info when position opens/closes, editing csv to update info, matching closed position with its corresponding limit order

 

Hi all,

I want to do the following:

-Step 1- catch information about a trade when a  position (whether its direct market order or when price hits limit order) opens eg ticket, trade spread, slippage, price requested , price received attribute X value (eg X = 5, this is artificial attribute, not position related) and store it in a csv.

Step 2 - when position gets closed (either hits tp or SL), i want to get information about the position (eg spread, slippage, price requested, price received) and also fetch the row within the csv which corresponds to this closed position and add the closed position info in the same row as additional info.

Step 3 - Next time EA wants to open a new trade(limit order/market order), it will read the csv and find the count of rows with attribute X value = 5. If the number of rows with attribute X value = 5 is more than 3 then it will not open the trade. If it is below 3 then it will open the trade.

I browsed the forums a bit to solve a few challenges that I am not sure how to solve them in the best way possible .

The challenges:

- When my EA opens a limit order eg Buy limit, and then price hits it opening a buy position then I need to fetch the info about this position and ensure that it is corresponds to the limit order that EA opened and then fetch info about it.

    Q - I saw that we can use OnTrade or OnTradeTransaction to fetch trade info when some trade related event occurs. Which one of these would be appropriate to fetch the position open and position close event?

    Q - how do i ensure that position info that i receive in OnTrade/OntradeTransaction is the same one that the EA opened as limit order ?

    Q - How do i ensure that the position event info that i receive in OnTrade/OntradeTransaction is corresponding to that position closing?

    Q- How do i edit the opening of position info row in csv to add information for the closing of corresponding  position trade so that they are both on the same line?

Thanks

Documentation on MQL5: Language Basics / Functions / Event Handling Functions
Documentation on MQL5: Language Basics / Functions / Event Handling Functions
  • www.mql5.com
Event Handling Functions - Functions - Language Basics - MQL5 Reference - Reference on algorithmic/automated trading language for MetaTrader 5
 
  • Usually people who can't code don't receive free help on this forum.
  • If you show your attempts and describe your problem clearly, you will most probably receive an answer from the community. Use the CODE button (Alt-S) when inserting code.
  • To learn MQL programming, you can research the many available Articles on the subject, or examples in the Codebase, as well as reference the online Documentation.
  • If you do not want to learn to code, that is not a problem. You can either look at the Codebase if something free already exists, or in the Market for paid products (also sometimes free). However, recommendations or suggestions for Market products are not allowed on the forum, so you will have to do your own research.
  • Finally, you also have the option to hire a programmer in the Freelance section.
 
Fernando Carreiro #:
  • Usually people who can't code don't receive free help on this forum.
  • If you show your attempts and describe your problem clearly, you will most probably receive an answer from the community. Use the CODE button (Alt-S) when inserting code.
  • To learn MQL programming, you can research the many available Articles on the subject, or examples in the Codebase, as well as reference the online Documentation.
  • If you do not want to learn to code, that is not a problem. You can either look at the Codebase if something free already exists, or in the Market for paid products (also sometimes free). However, recommendations or suggestions for Market products are not allowed on the forum, so you will have to do your own research.
  • Finally, you also have the option to hire a programmer in the Freelance section.

I'll post my code attempt and elaborate the problem more clearly.

 

Hi, I am fairly new to coding with MQL5 but I use these functions to send me an email whenever a position is closed. You can use CheckHistoryPositionProperties() to populate your own values.

In summary the logic is the following:

1. on every TradeTransaction check if the position (related to the transaction) is closed --- simply by comparing the volume of the 1st deal to the volume in the last deal (to account for partial closing of the position along the way), also only taking into account when an actual DEAL is added to the history ie. ignoring orders.2. if position is closed call email function

2a. within email function declare the variables corresponding to the info i want to get

2b. call a function to populate all those variables from the deal history related to the position that was closed

2c. send email.


Not sure if it is the best way but it has been working for me. NB: instead of using my ToPNLString() function you can simply use DoubleToString(closePnl...or closeSwp or closeCom, 2).


This is how the email looks like:

Symbol: BTCUSD

Position Type: POSITION_TYPE_BUY

Open Price: 43882.30

Close Price: 43868.05

Close Reason: DEAL_REASON_CLIENT (or DEAL_REASON_SL / DEAL_REASON_TP if sl or tp was the reason for the closing of the position)

P/L ($): -0.57$ | P/L (R): -0.057R

Comm ($): 0.00$ | Comm (R): 0.000R

Swap ($): 0.00$ | Swap (R): 0.000R

Open Time: 2024.01.05 14:55:45

Close Time: 2024.01.05 14:56:02


//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
{
//---
   if (trans.symbol == _Symbol)
      {
         Print("Position Closed?: #", trans.position, " Result: ", CheckIfPositionClosed(trans.position, trans.type));
         bool send_message = CheckIfPositionClosed(trans.position, trans.type) ? EmailPositionClosed(trans.position) : false;
        }
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool EmailPositionClosed(ulong ticket)
{
   string closeReason = "", dealType = "";
   double closePnl = 0.0, closeSwp = 0.0, closeCom = 0.0, openPrice = 0.0, closePrice = 0.0, original_tp = 0.0, original_sl = 0.0;;
   datetime openTime = 0, closeTime = 0;
   CheckHistoryPositionProperties(ticket, dealType, closePnl, closeCom, closeSwp, openPrice, closePrice, openTime, closeTime, original_tp, original_sl, closeReason);
   string sbj = "Position Closed: #" + ticket + " (" + _Symbol + ")";
   string msg = "Symbol: " + _Symbol + "\n";
   msg += "Position Type: " + dealType + "\n";
   msg += "Open Price: " + DoubleToString(openPrice, _Digits) + "\n";
   msg += "Close Price: " + DoubleToString(closePrice, _Digits) + "\n";
   msg += "Close Reason: " + closeReason + "\n";
   msg += "P/L ($): " + ToPNLString(closePnl, inp_DollarRisk, false) + " | P/L (R): " + ToPNLString(closePnl, inp_DollarRisk, true) + "\n";
   msg += "Comm ($): " + ToPNLString(closeCom, inp_DollarRisk, false) + " | Comm (R): " + ToPNLString(closeCom, inp_DollarRisk, true) + "\n";
   msg += "Swap ($): " + ToPNLString(closeSwp, inp_DollarRisk, false) + " | Swap (R): " + ToPNLString(closeSwp, inp_DollarRisk, true) + "\n";
   msg += "Open Time: " + TimeToString(openTime, TIME_DATE | TIME_SECONDS) + "\n";
   msg += "Close Time: " + TimeToString(closeTime, TIME_DATE | TIME_SECONDS);
   return SendMail(sbj, msg);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CheckHistoryPositionProperties(ulong ticket, string& dealType, double& closePl, double& closeCom, double& closeSwp, double& openPrice, double& closePrice, datetime& openTime, datetime& closeTime, double& origTP, double& origSL, string& reason)
{
   HistorySelectByPosition(ticket);
   for (int i = 0; i < HistoryDealsTotal(); i++)
      {
         closePl += HistoryDealGetDouble(HistoryDealGetTicket(i), DEAL_PROFIT);
         closeSwp += HistoryDealGetDouble(HistoryDealGetTicket(i), DEAL_SWAP);
         closeCom += HistoryDealGetDouble(HistoryDealGetTicket(i), DEAL_COMMISSION);
      }
   dealType = EnumToString(ENUM_POSITION_TYPE(HistoryDealGetInteger(HistoryDealGetTicket(0), DEAL_TYPE)));
   origTP = HistoryDealGetDouble(HistoryDealGetTicket(0), DEAL_TP);
   origSL = HistoryDealGetDouble(HistoryDealGetTicket(0), DEAL_SL);
   reason = EnumToString(ENUM_DEAL_REASON(HistoryDealGetInteger(HistoryDealGetTicket(HistoryDealsTotal() - 1), DEAL_REASON)));
   openTime = HistoryDealGetInteger(HistoryDealGetTicket(0), DEAL_TIME);
   openPrice = HistoryDealGetDouble(HistoryDealGetTicket(0), DEAL_PRICE);
   closeTime = HistoryDealGetInteger(HistoryDealGetTicket(HistoryDealsTotal() - 1), DEAL_TIME);
   closePrice = HistoryDealGetDouble(HistoryDealGetTicket(HistoryDealsTotal() - 1), DEAL_PRICE);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CheckIfPositionClosed(ulong ticket, long type)
{
   if (type != TRADE_TRANSACTION_DEAL_ADD) return false;
   
   HistorySelectByPosition(ticket);
   double closedVolume = 0.0;
   for (int i = 1; i < HistoryDealsTotal(); i++)
      {
         closedVolume += HistoryDealGetDouble(HistoryDealGetTicket(i), DEAL_VOLUME);
      }
   return closedVolume == HistoryDealGetDouble(HistoryDealGetTicket(0), DEAL_VOLUME);
}
 
metph86 #:

Hi, I am fairly new to coding with MQL5 but I use these functions to send me an email whenever a position is closed. You can use CheckHistoryPositionProperties() to populate your own values.

In summary the logic is the following:

1. on every TradeTransaction check if the position (related to the transaction) is closed --- simply by comparing the volume of the 1st deal to the volume in the last deal (to account for partial closing of the position along the way), also only taking into account when an actual DEAL is added to the history ie. ignoring orders.2. if position is closed call email function

2a. within email function declare the variables corresponding to the info i want to get

2b. call a function to populate all those variables from the deal history related to the position that was closed

2c. send email.


Not sure if it is the best way but it has been working for me. NB: instead of using my ToPNLString() function you can simply use DoubleToString(closePnl...or closeSwp or closeCom, 2).


This is how the email looks like:

Symbol: BTCUSD

Position Type: POSITION_TYPE_BUY

Open Price: 43882.30

Close Price: 43868.05

Close Reason: DEAL_REASON_CLIENT (or DEAL_REASON_SL / DEAL_REASON_TP if sl or tp was the reason for the closing of the position)

P/L ($): -0.57$ | P/L (R): -0.057R

Comm ($): 0.00$ | Comm (R): 0.000R

Swap ($): 0.00$ | Swap (R): 0.000R

Open Time: 2024.01.05 14:55:45

Close Time: 2024.01.05 14:56:02


@metph86

It has been quite some time since i posted this topic.  Thanks for your solution.
After exploring many things, I have managed to put to rest the first 2 questions. I just wanted to share my approach in case others research this as well.

I found that using using handler that has been contributed to our community has helped immensely in simplifying my handling of Trade open/SL/TP handling. 


https://www.mql5.com/en/code/24901 

It has worked like a charm.


Regarding question 3  - i havent finished testing it. 

I havnt explored CSV editing either yet.  I will probably update again in future.
Cheers!



TradeTransaction Class
TradeTransaction Class
  • www.mql5.com
A base class to simplify analyzing trade transactions in MQL5.
Reason: