TradeTransaction/TradeTransaction.mqh
2025-09-19 20:26:58 +00:00

169 lines
20 KiB
MQL5

//+------------------------------------------------------------------+
//| TradeTransaction.mqh |
//| Copyright © 2018, Amr Ali |
//| https://www.mql5.com/en/users/amrali |
//+------------------------------------------------------------------+
#property version "1.10"
// Updates:
// 2019.03.06 - v.1.00 : Initial release.
// 2025.03.05 - v.1.10 : Fixed issue with STOP LIMIT orders not being captured. Added 'SetLogging' public method to control printing verbose information to 'Experts' logs.
//+------------------------------------------------------------------+
//| Macro definitions. |
//+------------------------------------------------------------------+
//--- check the expectation of transaction
#define IS_TRANSACTION_ORDER_PLACED (trans.type == TRADE_TRANSACTION_REQUEST && request.action == TRADE_ACTION_PENDING && OrderSelect(result.order) && (ENUM_ORDER_STATE)OrderGetInteger(ORDER_STATE) == ORDER_STATE_PLACED)
#define IS_TRANSACTION_ORDER_MODIFIED (trans.type == TRADE_TRANSACTION_REQUEST && request.action == TRADE_ACTION_MODIFY && OrderSelect(result.order) && (ENUM_ORDER_STATE)OrderGetInteger(ORDER_STATE) == ORDER_STATE_PLACED)
#define IS_TRANSACTION_ORDER_DELETED (trans.type == TRADE_TRANSACTION_HISTORY_ADD && (trans.order_type >= 2 && trans.order_type < 8) && trans.order_state == ORDER_STATE_CANCELED)
#define IS_TRANSACTION_ORDER_EXPIRED (trans.type == TRADE_TRANSACTION_HISTORY_ADD && (trans.order_type >= 2 && trans.order_type < 8) && trans.order_state == ORDER_STATE_EXPIRED)
#define IS_TRANSACTION_ORDER_TRIGGERED (trans.type == TRADE_TRANSACTION_HISTORY_ADD && (trans.order_type >= 2 && trans.order_type < 8) && trans.order_state == ORDER_STATE_FILLED)
#define IS_TRANSACTION_POSITION_OPENED (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_IN)
#define IS_TRANSACTION_POSITION_STOP_TAKE (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_OUT && ((ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) == DEAL_REASON_SL || (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) == DEAL_REASON_TP))
#define IS_TRANSACTION_POSITION_CLOSED (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_OUT && ((ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) != DEAL_REASON_SL && (ENUM_DEAL_REASON)HistoryDealGetInteger(trans.deal, DEAL_REASON) != DEAL_REASON_TP))
#define IS_TRANSACTION_POSITION_CLOSEBY (trans.type == TRADE_TRANSACTION_DEAL_ADD && HistoryDealSelect(trans.deal) && (ENUM_DEAL_ENTRY)HistoryDealGetInteger(trans.deal, DEAL_ENTRY) == DEAL_ENTRY_OUT_BY)
#define IS_TRANSACTION_POSITION_MODIFIED (trans.type == TRADE_TRANSACTION_REQUEST && request.action == TRADE_ACTION_SLTP)
//+------------------------------------------------------------------+
//| Class CTradeTransaction. |
//| Purpose: Base class for trade transactions. |
//+------------------------------------------------------------------+
class CTradeTransaction
{
public:
CTradeTransaction(void) { }
~CTradeTransaction(void) { }
//--- printing verbose information
void SetLogging(bool state) { m_logging = state; }
//--- event handler
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result);
protected:
//--- trade transactions
//--- these methods should be overridden in the derived class
virtual void TradeTransactionOrderPlaced(ulong order) { }
virtual void TradeTransactionOrderModified(ulong order) { }
virtual void TradeTransactionOrderDeleted(ulong order) { }
virtual void TradeTransactionOrderExpired(ulong order) { }
virtual void TradeTransactionOrderTriggered(ulong order) { }
virtual void TradeTransactionPositionOpened(ulong position, ulong deal) { }
virtual void TradeTransactionPositionStopTake(ulong position, ulong deal) { }
virtual void TradeTransactionPositionClosed(ulong position, ulong deal) { }
virtual void TradeTransactionPositionCloseBy(ulong position, ulong deal) { }
virtual void TradeTransactionPositionModified(ulong position) { }
private:
bool m_logging;
};
//+------------------------------------------------------------------+
//| Method of verification of trade transactions. |
//+------------------------------------------------------------------+
void CTradeTransaction::OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
//---
if(m_logging)
{
if(trans.type!=TRADE_TRANSACTION_REQUEST)
{
//--- displays information on transactions
Print("---===Transaction===---");
string desc="Type: "+EnumToString(trans.type)+"\n";
desc += "Symbol: " + trans.symbol + "\n";
desc += "Deal ticket: " + (string)trans.deal + "\n";
desc += "Deal type: " + EnumToString(trans.deal_type) + "\n";
desc += "Order ticket: " + (string)trans.order + "\n";
desc += "Order type: " + EnumToString(trans.order_type) + "\n";
desc += "Order state: " + EnumToString(trans.order_state) + "\n";
desc += "Order time type: " + EnumToString(trans.time_type) + "\n";
desc += "Order expiration: " + TimeToString(trans.time_expiration) + "\n";
desc += "Price: " + StringFormat("%G", trans.price) + "\n";
desc += "Price trigger: " + StringFormat("%G", trans.price_trigger) + "\n";
desc += "Stop Loss: " + StringFormat("%G", trans.price_sl) + "\n";
desc += "Take Profit: " + StringFormat("%G", trans.price_tp) + "\n";
desc += "Volume: " + StringFormat("%G", trans.volume) + "\n";
desc += "Position: " + (string)trans.position + "\n";
desc += "Position by: " + (string)trans.position_by + "\n";
Print(desc);
}
//--- if a request has been processed by server
if(trans.type==TRADE_TRANSACTION_REQUEST)
{
//--- displays type of transaction
Print("---===Transaction===---");
string desc="Type: "+EnumToString(trans.type)+"\n";
Print(desc);
//--- displays information on the request
Print("---===Request===---");
desc="Action: "+EnumToString(request.action)+"\n";
desc += "Symbol: " + request.symbol + "\n";
desc += "Magic Number: " + StringFormat("%d", request.magic) + "\n";
desc += "Order ticket: " + (string)request.order + "\n";
desc += "Order type: " + EnumToString(request.type) + "\n";
desc += "Order filling: " + EnumToString(request.type_filling) + "\n";
desc += "Order time type: " + EnumToString(request.type_time) + "\n";
desc += "Order expiration: " + TimeToString(request.expiration) + "\n";
desc += "Price: " + StringFormat("%G", request.price) + "\n";
desc += "Deviation points: " + StringFormat("%G", request.deviation) + "\n";
desc += "Stop Loss: " + StringFormat("%G", request.sl) + "\n";
desc += "Take Profit: " + StringFormat("%G", request.tp) + "\n";
desc += "Stop Limit: " + StringFormat("%G", request.stoplimit) + "\n";
desc += "Volume: " + StringFormat("%G", request.volume) + "\n";
desc += "Comment: " + request.comment + "\n";
desc += "Position: " + (string)request.position + "\n";
desc += "Position by: " + (string)request.position_by + "\n";
Print(desc);
//--- displays information about result
Print("---===Result===---");
desc="Retcode: "+(string)result.retcode+"\n";
desc += "Order ticket: " + (string)result.order + "\n";
desc += "Deal ticket: " + (string)result.deal + "\n";
desc += "Volume: " + StringFormat("%G", result.volume) + "\n";
desc += "Price: " + StringFormat("%G", result.price) + "\n";
desc += "Bid: " + StringFormat("%G", result.bid) + "\n";
desc += "Ask: " + StringFormat("%G", result.ask) + "\n";
desc += "Comment: " + result.comment + "\n";
desc += "Request ID: " + StringFormat("%d", result.request_id) + "\n";
desc += "Retcode external: " + (string)result.retcode_external + "\n";
Print(desc);
}
}
//---
if(IS_TRANSACTION_ORDER_PLACED)
TradeTransactionOrderPlaced(result.order);
else if(IS_TRANSACTION_ORDER_MODIFIED)
TradeTransactionOrderModified(result.order);
else if(IS_TRANSACTION_ORDER_DELETED)
TradeTransactionOrderDeleted(trans.order);
else if(IS_TRANSACTION_ORDER_EXPIRED)
TradeTransactionOrderExpired(trans.order);
else if(IS_TRANSACTION_ORDER_TRIGGERED)
TradeTransactionOrderTriggered(trans.order);
else if(IS_TRANSACTION_POSITION_OPENED)
TradeTransactionPositionOpened(trans.position,trans.deal);
else if(IS_TRANSACTION_POSITION_STOP_TAKE)
TradeTransactionPositionStopTake(trans.position,trans.deal);
else if(IS_TRANSACTION_POSITION_CLOSED)
TradeTransactionPositionClosed(trans.position,trans.deal);
else if(IS_TRANSACTION_POSITION_CLOSEBY)
TradeTransactionPositionCloseBy(trans.position,trans.deal);
else if(IS_TRANSACTION_POSITION_MODIFIED)
TradeTransactionPositionModified(request.position);
}
//+------------------------------------------------------------------+