Skip to content

Deal Info

CDealInfo

A lightweight Python wrapper that resembles the MQL5 Standard Library class CDealInfo and provides convenient, read-only access to MetaTrader 5 deal properties.

Reference (MQL5)

Source code in strategytester5\trade_classes\DealInfo.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
class CDealInfo:
    """
        A lightweight Python wrapper that resembles the MQL5 Standard Library class
        `CDealInfo` and provides convenient, read-only access to MetaTrader 5 deal
        properties.

        [Reference (MQL5)](https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo)
    """

    def __init__(self, deal: TradeDeal):
        """
        Instantiates the CDealInfo object

        Args:
            deal: A deal object (e.g., from `mt5.history_deals_get()`) to wrap and provide access to.

        Notes:
            - Many getters return `None` if no deal is selected.
            - Times:
                * `time` returns a timezone-aware UTC datetime (recommended for MT5 history).
                * `time_msc` returns milliseconds since 1970-01-01 (UTC) when available.
            - This wrapper does not modify terminal state; it only reads/derives properties.
        """

        if self.deal is None:
            raise ValueError("Deal cannot be None. Please provide a valid deal tuple.")

        self._deal = deal

    @property
    def deal_type_description(self):
        """Gets the deal type as a string"""

        if not self._deal:
            return "N/A"

        deal_type_map = {
            mt5_constants.DEAL_TYPE_BUY: "BUY",
            mt5_constants.DEAL_TYPE_SELL: "SELL",
            mt5_constants.DEAL_TYPE_BALANCE: "BALANCE",
            mt5_constants.DEAL_TYPE_CREDIT: "CREDIT",
            mt5_constants.DEAL_TYPE_CHARGE: "CHARGE",
            mt5_constants.DEAL_TYPE_CORRECTION: "CORRECTION",
            mt5_constants.DEAL_TYPE_BONUS: "BONUS",
            mt5_constants.DEAL_TYPE_COMMISSION: "COMMISSION",
            mt5_constants.DEAL_TYPE_COMMISSION_DAILY: "COMMISSION DAILY",
            mt5_constants.DEAL_TYPE_COMMISSION_MONTHLY: "COMMISSION MONTHLY",
            mt5_constants.DEAL_TYPE_COMMISSION_AGENT_DAILY: "AGENT COMMISSION DAILY",
            mt5_constants.DEAL_TYPE_COMMISSION_AGENT_MONTHLY: "AGENT COMMISSION MONTHLY",
            mt5_constants.DEAL_TYPE_INTEREST: "INTEREST",
            mt5_constants.DEAL_TYPE_BUY_CANCELED: "BUY CANCELED",
            mt5_constants.DEAL_TYPE_SELL_CANCELED: "SELL CANCELED"
        }

        return deal_type_map.get(self._deal.type, f"UNKNOWN({self._deal.type})")

    @property
    def entry_description(self):
        """Gets the deal direction as a string"""

        if not self._deal:
            return "N/A"

        entry_map = {
            mt5_constants.DEAL_ENTRY_IN: "IN",
            mt5_constants.DEAL_ENTRY_OUT: "OUT",
            mt5_constants.DEAL_ENTRY_INOUT: "INOUT"
        }

        return entry_map.get(self._deal.entry, "UNKNOWN")

    # --- Integer, datetime & properties

    @property
    def ticket(self) -> Optional[int]:
        """Gets ticket/selects the deal ticket."""
        return None if self._deal is None else int(self._deal.ticket)

    @property
    def order(self) -> Optional[int]:
        """Gets the order by which the deal was executed."""
        return None if self._deal is None else int(self._deal.order)

    @property
    def time(self) -> Optional[datetime]:
        """
        Gets the time of deal execution as a timezone-aware UTC datetime.

        Returns:
            UTC datetime, or None if no deal is selected.
        """
        if self._deal is None:
            return None
        # MT5 history times are effectively UTC; keep it explicit.
        return datetime.fromtimestamp(int(self._deal.time), tz=timezone.utc)

    @property
    def time_msc(self) -> Optional[int]:
        """Receives the time of a deal execution in milliseconds since 1970-01-01 (UTC)."""
        return None if self._deal is None else int(self._deal.time_msc)

    @property
    def deal_type(self) -> Optional[int]:
        """Gets the deal type (DEAL_TYPE_*)."""
        return None if self._deal is None else int(self._deal.type)

    @property
    def type_description(self) -> str:
        """Gets the deal type as a string."""

        if self._deal is None:
            return "N/A"

        deal_type_map ={
            mt5_constants.DEAL_TYPE_BUY: "BUY",
            mt5_constants.DEAL_TYPE_SELL: "SELL",
            mt5_constants.DEAL_TYPE_BALANCE: "BALANCE",
            mt5_constants.DEAL_TYPE_CREDIT: "CREDIT",
            mt5_constants.DEAL_TYPE_CHARGE: "CHARGE",
            mt5_constants.DEAL_TYPE_CORRECTION: "CORRECTION",
            mt5_constants.DEAL_TYPE_BONUS: "BONUS",
            mt5_constants.DEAL_TYPE_COMMISSION: "COMMISSION",
            mt5_constants.DEAL_TYPE_COMMISSION_DAILY: "COMMISSION DAILY",
            mt5_constants.DEAL_TYPE_COMMISSION_MONTHLY: "COMMISSION MONTHLY",
            mt5_constants.DEAL_TYPE_COMMISSION_AGENT_DAILY: "AGENT COMMISSION DAILY",
            mt5_constants.DEAL_TYPE_COMMISSION_AGENT_MONTHLY: "AGENT COMMISSION MONTHLY",
            mt5_constants.DEAL_TYPE_INTEREST: "INTEREST",
            mt5_constants.DEAL_TYPE_BUY_CANCELED: "BUY CANCELED",
            mt5_constants.DEAL_TYPE_SELL_CANCELED: "SELL CANCELED",
        }

        return deal_type_map.get(self._deal.type, f"UNKNOWN({self._deal.type})")

    @property
    def entry(self) -> Optional[int]:
        """Gets the deal direction/entry (DEAL_ENTRY_*)."""
        return None if self._deal is None else int(self._deal.entry)

    @property
    def magic(self) -> Optional[int]:
        """Gets the ID of the expert (magic number) that executed the deal."""
        return None if self._deal is None else int(self._deal.magic)

    @property
    def position_id(self) -> Optional[int]:
        """Gets the ID of the position in which the deal was involved."""
        return None if self._deal is None else int(self._deal.position_id)

    # Double properties

    @property
    def volume(self) -> Optional[float]:
        """Gets the volume of the deal."""
        return None if self._deal is None else float(self._deal.volume)

    @property
    def price(self) -> Optional[float]:
        """Gets the deal price."""
        return None if self._deal is None else float(self._deal.price)

    @property
    def commission(self) -> Optional[float]:
        """Gets the amount of commission for the deal."""
        return None if self._deal is None else float(self._deal.commission)

    @property
    def swap(self) -> Optional[float]:
        """Gets the amount of swap when the position is closed."""
        return None if self._deal is None else float(self._deal.swap)

    @property
    def profit(self) -> Optional[float]:
        """Gets the financial result of the deal."""
        return None if self._deal is None else float(self._deal.profit)

    # Text properties

    @property
    def symbol(self) -> Optional[str]:
        """Gets the symbol name."""
        return None if self._deal is None else str(self._deal.symbol)

    @property
    def comment(self) -> Optional[str]:
        """Gets the deal comment."""
        return None if self._deal is None else str(self._deal.comment)

    @property
    def external_id(self) -> Optional[str]:
        """Gets the external ID (if provided by the broker)."""
        return None if self._deal is None else str(self._deal.external_id)

    # -------------------------
    # Generic "Info*" methods (MQL5-like)
    # -------------------------

    def info_integer(self, prop_name: str) -> Optional[int]:
        """
        Gets an integer property value by attribute name.

        This is a Pythonic approximation of MQL5's InfoInteger/HistoryDealGetInteger.
        In Python MT5, deal objects expose fields as attributes.

        Args:
            prop_name: Attribute name on the deal object (e.g., "ticket", "order", "magic").

        Returns:
             The integer value, or None if no deal is selected or attribute missing.
        """

        if self._deal is None or not hasattr(self._deal, prop_name):
            return None
        value = getattr(self._deal, prop_name)
        return None if value is None else int(value)

    def info_double(self, prop_name: str) -> Optional[float]:
        """
        Gets a float property value by attribute name.

        Args:
            prop_name : Attribute name on the deal object (e.g., "price", "profit", "volume").

        Returns:
            The float value, or None if no deal is selected or attribute missing.
        """
        if self._deal is None or not hasattr(self._deal, prop_name):
            return None
        value = getattr(self._deal, prop_name)
        return None if value is None else float(value)

    def info_string(self, prop_name: str) -> Optional[str]:
        """
        Gets a string property value by attribute name.

        Args:
            prop_name: Attribute name on the deal object (e.g., "symbol", "comment", "external_id").

        Returns:
            The string value, or None if no deal is selected or attribute missing.
        """
        if self._deal is None or not hasattr(self._deal, prop_name):
            return None
        value = getattr(self._deal, prop_name)
        return None if value is None else str(value)

    def print_all(self) -> None:
        """Print all @property values of the class."""

        for name, attr in vars(type(self)).items():
            if isinstance(attr, property):
                try:
                    value = getattr(self, name)
                except Exception as e:
                    value = f"<error: {e}>"

                print(f"{name:20} : {value}")

comment property

Gets the deal comment.

commission property

Gets the amount of commission for the deal.

deal_type property

Gets the deal type (DEAL_TYPE_*).

deal_type_description property

Gets the deal type as a string

entry property

Gets the deal direction/entry (DEAL_ENTRY_*).

entry_description property

Gets the deal direction as a string

external_id property

Gets the external ID (if provided by the broker).

magic property

Gets the ID of the expert (magic number) that executed the deal.

order property

Gets the order by which the deal was executed.

position_id property

Gets the ID of the position in which the deal was involved.

price property

Gets the deal price.

profit property

Gets the financial result of the deal.

swap property

Gets the amount of swap when the position is closed.

symbol property

Gets the symbol name.

ticket property

Gets ticket/selects the deal ticket.

time property

Gets the time of deal execution as a timezone-aware UTC datetime.

Returns:

Type Description
Optional[datetime]

UTC datetime, or None if no deal is selected.

time_msc property

Receives the time of a deal execution in milliseconds since 1970-01-01 (UTC).

type_description property

Gets the deal type as a string.

volume property

Gets the volume of the deal.

__init__(deal)

Instantiates the CDealInfo object

Parameters:

Name Type Description Default
deal TradeDeal

A deal object (e.g., from mt5.history_deals_get()) to wrap and provide access to.

required
Notes
  • Many getters return None if no deal is selected.
  • Times:
    • time returns a timezone-aware UTC datetime (recommended for MT5 history).
    • time_msc returns milliseconds since 1970-01-01 (UTC) when available.
  • This wrapper does not modify terminal state; it only reads/derives properties.
Source code in strategytester5\trade_classes\DealInfo.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def __init__(self, deal: TradeDeal):
    """
    Instantiates the CDealInfo object

    Args:
        deal: A deal object (e.g., from `mt5.history_deals_get()`) to wrap and provide access to.

    Notes:
        - Many getters return `None` if no deal is selected.
        - Times:
            * `time` returns a timezone-aware UTC datetime (recommended for MT5 history).
            * `time_msc` returns milliseconds since 1970-01-01 (UTC) when available.
        - This wrapper does not modify terminal state; it only reads/derives properties.
    """

    if self.deal is None:
        raise ValueError("Deal cannot be None. Please provide a valid deal tuple.")

    self._deal = deal

info_double(prop_name)

Gets a float property value by attribute name.

Parameters:

Name Type Description Default
prop_name

Attribute name on the deal object (e.g., "price", "profit", "volume").

required

Returns:

Type Description
Optional[float]

The float value, or None if no deal is selected or attribute missing.

Source code in strategytester5\trade_classes\DealInfo.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
def info_double(self, prop_name: str) -> Optional[float]:
    """
    Gets a float property value by attribute name.

    Args:
        prop_name : Attribute name on the deal object (e.g., "price", "profit", "volume").

    Returns:
        The float value, or None if no deal is selected or attribute missing.
    """
    if self._deal is None or not hasattr(self._deal, prop_name):
        return None
    value = getattr(self._deal, prop_name)
    return None if value is None else float(value)

info_integer(prop_name)

Gets an integer property value by attribute name.

This is a Pythonic approximation of MQL5's InfoInteger/HistoryDealGetInteger. In Python MT5, deal objects expose fields as attributes.

Parameters:

Name Type Description Default
prop_name str

Attribute name on the deal object (e.g., "ticket", "order", "magic").

required

Returns:

Type Description
Optional[int]

The integer value, or None if no deal is selected or attribute missing.

Source code in strategytester5\trade_classes\DealInfo.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
def info_integer(self, prop_name: str) -> Optional[int]:
    """
    Gets an integer property value by attribute name.

    This is a Pythonic approximation of MQL5's InfoInteger/HistoryDealGetInteger.
    In Python MT5, deal objects expose fields as attributes.

    Args:
        prop_name: Attribute name on the deal object (e.g., "ticket", "order", "magic").

    Returns:
         The integer value, or None if no deal is selected or attribute missing.
    """

    if self._deal is None or not hasattr(self._deal, prop_name):
        return None
    value = getattr(self._deal, prop_name)
    return None if value is None else int(value)

info_string(prop_name)

Gets a string property value by attribute name.

Parameters:

Name Type Description Default
prop_name str

Attribute name on the deal object (e.g., "symbol", "comment", "external_id").

required

Returns:

Type Description
Optional[str]

The string value, or None if no deal is selected or attribute missing.

Source code in strategytester5\trade_classes\DealInfo.py
238
239
240
241
242
243
244
245
246
247
248
249
250
251
def info_string(self, prop_name: str) -> Optional[str]:
    """
    Gets a string property value by attribute name.

    Args:
        prop_name: Attribute name on the deal object (e.g., "symbol", "comment", "external_id").

    Returns:
        The string value, or None if no deal is selected or attribute missing.
    """
    if self._deal is None or not hasattr(self._deal, prop_name):
        return None
    value = getattr(self._deal, prop_name)
    return None if value is None else str(value)

print_all()

Print all @property values of the class.

Source code in strategytester5\trade_classes\DealInfo.py
253
254
255
256
257
258
259
260
261
262
263
def print_all(self) -> None:
    """Print all @property values of the class."""

    for name, attr in vars(type(self)).items():
        if isinstance(attr, property):
            try:
                value = getattr(self, name)
            except Exception as e:
                value = f"<error: {e}>"

            print(f"{name:20} : {value}")