Skip to content

Order Info

COrderInfo

Source code in strategytester5\trade_classes\OrderInfo.py
 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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
class COrderInfo:

    def __init__(self, order: TradeOrder, terminal: Union[OverLoadedMetaTrader5API|MetaTrader5]) -> None:

        """
        A lightweight Python wrapper that resembles the MQL5 Standard Library class
        `COrderInfo` and provides convenient, read-only access to the currently
        selected pending/open order properties in MetaTrader 5.

        This class acts like a cursor over one selected order stored in `self._order`.
        You may select an order directly with `select_order(order)`, by ticket using
        `select(ticket)`, or by index using `select_by_index(index)`.

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

        Args:
        order (TradeOrder):
            A tuple representing an order, typically obtained from `mt5.history_orders_get()` or `mt5.orders_get()`. This should be a structure compatible with the MetaTrader5 Python API's order representation.

        terminal (Any): Initialize native MetaTrader5 API or the simulated one from the StrategyTester instance

        Notes
        -----
        - If no order is selected, properties return `None`, `0`, `0.0`, empty string, or `"N/A"` depending on the property.
        - `time_setup`, `time_done`, and `time_expiration` are returned as timezone-aware UTC datetimes where possible.
        - Description methods intentionally preserve your original mapping logic/style.

        """

        self.terminal = terminal

        self._order = order

        if self._order is None:
            raise ValueError("Order cannot be None. Please provide a valid order tuple.")

    # --------- Integer / datetime properties -----------

    @property
    def ticket(self) -> int:
        """Gets the ticket of the selected order."""
        return int(self._order.ticket) if self._order else -1

    @property
    def time_setup(self) -> Optional[datetime]:
        """Gets the time of order placement."""
        return datetime.fromtimestamp(self._order.time_setup, tz=timezone.utc) if self._order else None

    @property
    def time_setup_msc(self) -> int:
        """Receives the time of placing an order in milliseconds since 01.01.1970."""
        return int(self._order.time_setup_msc) if self._order else 0

    @property
    def time_done(self) -> Optional[datetime]:
        """Gets the time of order execution or cancellation."""
        if not self._order or int(self._order.time_done) == 0:
            return None
        return datetime.fromtimestamp(self._order.time_done, tz=timezone.utc)

    @property
    def time_done_msc(self) -> int:
        """Receives order execution or cancellation time in milliseconds since 01.01.1970."""
        return int(self._order.time_done_msc) if self._order else 0

    @property
    def order_type(self) -> int:
        """Gets the order type."""
        return int(self._order.type) if self._order else -1

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

        order_type_map = {
            self.terminal.ORDER_TYPE_BUY: "Market Buy order",
            self.terminal.ORDER_TYPE_SELL: "Market Sell order",
            self.terminal.ORDER_TYPE_BUY_LIMIT: "Buy Limit pending order",
            self.terminal.ORDER_TYPE_SELL_LIMIT: "Sell Limit pending order",
            self.terminal.ORDER_TYPE_BUY_STOP: "Buy Stop pending order",
            self.terminal.ORDER_TYPE_SELL_STOP: "Sell Stop pending order",
            self.terminal.ORDER_TYPE_BUY_STOP_LIMIT: "Upon reaching the order price, a pending Buy Limit order is placed at the StopLimit price",
            self.terminal.ORDER_TYPE_SELL_STOP_LIMIT: "Upon reaching the order price, a pending Sell Limit order is placed at the StopLimit price",
            self.terminal.ORDER_TYPE_CLOSE_BY: "Order to close a position by an opposite one"
        }

        return order_type_map.get(self.order_type, "Unknown order type")

    @property
    def state(self) -> int:
        """Gets the order state."""
        return int(self._order.state) if self._order else -1

    @property
    def state_description(self) -> str:
        """Gets the order state as a string."""

        state_map = {
            self.terminal.ORDER_STATE_STARTED: "Order checked, but not yet accepted by broker",
            self.terminal.ORDER_STATE_PLACED: "Order accepted",
            self.terminal.ORDER_STATE_CANCELED: "Order canceled by client",
            self.terminal.ORDER_STATE_PARTIAL: "Order partially executed",
            self.terminal.ORDER_STATE_FILLED: "Order fully executed",
            self.terminal.ORDER_STATE_REJECTED: "Order rejected",
            self.terminal.ORDER_STATE_EXPIRED: "Order expired",
            self.terminal.ORDER_STATE_REQUEST_ADD: "Order is being registered (placing to the trading system)",
            self.terminal.ORDER_STATE_REQUEST_MODIFY: "Order is being modified (changing its parameters)",
            self.terminal.ORDER_STATE_REQUEST_CANCEL: "Order is being deleted (deleting from the trading system)"
        }

        return state_map.get(self.state, "Unknown order state")

    @property
    def time_expiration(self) -> Optional[datetime]:
        """Gets the time of order expiration."""
        if not self._order:
            return None

        if self._order.time_expiration == 0:
            return None

        try:
            return datetime.fromtimestamp(self._order.time_expiration, tz=timezone.utc)
        except (ValueError, OSError):
            return None

    @property
    def type_filling(self) -> int:
        """Gets the type of order execution by remainder."""
        return int(self._order.type_filling) if self._order else -1

    @property
    def type_filling_description(self) -> Optional[str]:
        """Gets the type of order execution by remainder as a string."""

        filling_map = {
            1: "FOK (Fill or Kill)",
            2: "IOC (Immediate or Cancel)",
            4: "BOC (Book or Cancel)",
            8: "RETURN"
        }

        return filling_map.get(self.type_filling)

    @property
    def type_time(self) -> int:
        """Gets the type of order at the time of the expiration."""
        return int(self._order.type_time) if self._order else -1

    @property
    def type_time_description(self) -> str:
        """Gets the order type by expiration time as a string."""

        if not self._order:
            return "unknown"

        type_time = self._order.type_time

        if type_time == self.terminal.ORDER_TIME_SPECIFIED:
            return "ORDER_TIME_SPECIFIED"
        elif type_time == self.terminal.ORDER_TIME_SPECIFIED_DAY:
            return "ORDER_TIME_SPECIFIED_DAY"
        elif type_time == self.terminal.ORDER_TIME_DAY:
            return "ORDER_TIME_DAY"
        elif type_time == self.terminal.ORDER_TIME_GTC:
            return "ORDER_TIME_GTC"
        else:
            return "unknown"

    @property
    def magic(self) -> int:
        """Gets the ID of expert that placed the order."""
        return int(self._order.magic) if self._order else -1

    @property
    def position_id(self) -> int:
        """Gets the ID of position."""
        return int(self._order.position_id) if self._order else -1

    # ---------- Double properties -----------

    @property
    def volume_initial(self) -> float:
        """Gets the initial volume of the order."""
        return float(self._order.volume_initial) if self._order else 0.0

    @property
    def volume_current(self) -> float:
        """Gets the unfilled volume of the order."""
        return float(self._order.volume_current) if self._order else 0.0

    @property
    def price_open(self) -> float:
        """Gets the order price."""
        return float(self._order.price_open) if self._order else 0.0

    @property
    def stop_loss(self) -> float:
        """Gets the order Stop Loss."""
        return float(self._order.sl) if self._order else 0.0

    @property
    def take_profit(self) -> float:
        """Gets the order Take Profit."""
        return float(self._order.tp) if self._order else 0.0

    @property
    def price_current(self) -> float:
        """Gets the current price by order symbol."""
        if not self._order:
            return 0.0

        tick = self.terminal.symbol_info_tick(self._order.symbol)
        if not tick:
            return 0.0

        return tick.bid if self._order.type in [
            self.terminal.ORDER_TYPE_BUY,
            self.terminal.ORDER_TYPE_BUY_LIMIT,
            self.terminal.ORDER_TYPE_BUY_STOP
        ] else tick.ask

    @property
    def price_stop_limit(self) -> float:
        """Gets the price of a Limit order."""
        return float(self._order.price_stoplimit) if self._order else 0.0

    # ---------- String properties ------------

    @property
    def symbol(self) -> str:
        """Gets the name of the order symbol."""
        return str(self._order.symbol) if self._order else ""

    @property
    def comment(self) -> str:
        """Gets the order comment."""
        return str(self._order.comment) if self._order else ""

    @property
    def external_id(self) -> str:
        """Gets the external ID."""
        value = getattr(self._order, "external_id", "")
        return str(value) if self._order else ""

    # --------- Generic Info* methods -----------

    def info_integer(self, prop_name: str) -> Optional[int]:
        """
        Gets the value of a specified integer type property.

        Parameters
        ----------
        prop_name : str
            Name of the order attribute.

        Returns
        -------
        Optional[int]
            Integer value if present, otherwise None.
        """
        if self._order is None or not hasattr(self._order, prop_name):
            return None
        value = getattr(self._order, prop_name)
        return None if value is None else int(value)

    def info_double(self, prop_name: str) -> Optional[float]:
        """
        Gets the value of a specified double type property.

        Parameters
        ----------
        prop_name : str
            Name of the order attribute.

        Returns
        -------
        Optional[float]
            Float value if present, otherwise None.
        """
        if self._order is None or not hasattr(self._order, prop_name):
            return None
        value = getattr(self._order, prop_name)
        return None if value is None else float(value)

    def info_string(self, prop_name: str) -> Optional[str]:
        """
        Gets the value of a specified string type property.

        Parameters
        ----------
        prop_name : str
            Name of the order attribute.

        Returns
        -------
        Optional[str]
            String value if present, otherwise None.
        """
        if self._order is None or not hasattr(self._order, prop_name):
            return None
        value = getattr(self._order, prop_name)
        return None if value is None else str(value)

    # --------- Debug / utility helpers ---------

    def to_dict(self) -> dict[str, Any]:
        """Return all @property values from the class and its parents."""
        data: dict[str, Any] = {}
        seen: set[str] = set()

        for cls in type(self).mro():
            for name, attr in vars(cls).items():
                if name in seen:
                    continue
                if isinstance(attr, property):
                    seen.add(name)
                    try:
                        data[name] = getattr(self, name)
                    except Exception as e:
                        data[name] = f"<error: {e}>"

        return data

    def print_all(self) -> None:
        """Print all @property values of the class."""
        for name, value in self.to_dict().items():
            print(f"{name:24} : {value}")

comment property

Gets the order comment.

external_id property

Gets the external ID.

magic property

Gets the ID of expert that placed the order.

order_type property

Gets the order type.

order_type_description property

Gets the order type as a string.

position_id property

Gets the ID of position.

price_current property

Gets the current price by order symbol.

price_open property

Gets the order price.

price_stop_limit property

Gets the price of a Limit order.

state property

Gets the order state.

state_description property

Gets the order state as a string.

stop_loss property

Gets the order Stop Loss.

symbol property

Gets the name of the order symbol.

take_profit property

Gets the order Take Profit.

ticket property

Gets the ticket of the selected order.

time_done property

Gets the time of order execution or cancellation.

time_done_msc property

Receives order execution or cancellation time in milliseconds since 01.01.1970.

time_expiration property

Gets the time of order expiration.

time_setup property

Gets the time of order placement.

time_setup_msc property

Receives the time of placing an order in milliseconds since 01.01.1970.

type_filling property

Gets the type of order execution by remainder.

type_filling_description property

Gets the type of order execution by remainder as a string.

type_time property

Gets the type of order at the time of the expiration.

type_time_description property

Gets the order type by expiration time as a string.

volume_current property

Gets the unfilled volume of the order.

volume_initial property

Gets the initial volume of the order.

__init__(order, terminal)

A lightweight Python wrapper that resembles the MQL5 Standard Library class COrderInfo and provides convenient, read-only access to the currently selected pending/open order properties in MetaTrader 5.

This class acts like a cursor over one selected order stored in self._order. You may select an order directly with select_order(order), by ticket using select(ticket), or by index using select_by_index(index).

MQL5 Reference

order (TradeOrder): A tuple representing an order, typically obtained from mt5.history_orders_get() or mt5.orders_get(). This should be a structure compatible with the MetaTrader5 Python API's order representation.

terminal (Any): Initialize native MetaTrader5 API or the simulated one from the StrategyTester instance

Notes
  • If no order is selected, properties return None, 0, 0.0, empty string, or "N/A" depending on the property.
  • time_setup, time_done, and time_expiration are returned as timezone-aware UTC datetimes where possible.
  • Description methods intentionally preserve your original mapping logic/style.
Source code in strategytester5\trade_classes\OrderInfo.py
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
def __init__(self, order: TradeOrder, terminal: Union[OverLoadedMetaTrader5API|MetaTrader5]) -> None:

    """
    A lightweight Python wrapper that resembles the MQL5 Standard Library class
    `COrderInfo` and provides convenient, read-only access to the currently
    selected pending/open order properties in MetaTrader 5.

    This class acts like a cursor over one selected order stored in `self._order`.
    You may select an order directly with `select_order(order)`, by ticket using
    `select(ticket)`, or by index using `select_by_index(index)`.

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

    Args:
    order (TradeOrder):
        A tuple representing an order, typically obtained from `mt5.history_orders_get()` or `mt5.orders_get()`. This should be a structure compatible with the MetaTrader5 Python API's order representation.

    terminal (Any): Initialize native MetaTrader5 API or the simulated one from the StrategyTester instance

    Notes
    -----
    - If no order is selected, properties return `None`, `0`, `0.0`, empty string, or `"N/A"` depending on the property.
    - `time_setup`, `time_done`, and `time_expiration` are returned as timezone-aware UTC datetimes where possible.
    - Description methods intentionally preserve your original mapping logic/style.

    """

    self.terminal = terminal

    self._order = order

    if self._order is None:
        raise ValueError("Order cannot be None. Please provide a valid order tuple.")

info_double(prop_name)

Gets the value of a specified double type property.

Parameters

prop_name : str Name of the order attribute.

Returns

Optional[float] Float value if present, otherwise None.

Source code in strategytester5\trade_classes\OrderInfo.py
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
def info_double(self, prop_name: str) -> Optional[float]:
    """
    Gets the value of a specified double type property.

    Parameters
    ----------
    prop_name : str
        Name of the order attribute.

    Returns
    -------
    Optional[float]
        Float value if present, otherwise None.
    """
    if self._order is None or not hasattr(self._order, prop_name):
        return None
    value = getattr(self._order, prop_name)
    return None if value is None else float(value)

info_integer(prop_name)

Gets the value of a specified integer type property.

Parameters

prop_name : str Name of the order attribute.

Returns

Optional[int] Integer value if present, otherwise None.

Source code in strategytester5\trade_classes\OrderInfo.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def info_integer(self, prop_name: str) -> Optional[int]:
    """
    Gets the value of a specified integer type property.

    Parameters
    ----------
    prop_name : str
        Name of the order attribute.

    Returns
    -------
    Optional[int]
        Integer value if present, otherwise None.
    """
    if self._order is None or not hasattr(self._order, prop_name):
        return None
    value = getattr(self._order, prop_name)
    return None if value is None else int(value)

info_string(prop_name)

Gets the value of a specified string type property.

Parameters

prop_name : str Name of the order attribute.

Returns

Optional[str] String value if present, otherwise None.

Source code in strategytester5\trade_classes\OrderInfo.py
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def info_string(self, prop_name: str) -> Optional[str]:
    """
    Gets the value of a specified string type property.

    Parameters
    ----------
    prop_name : str
        Name of the order attribute.

    Returns
    -------
    Optional[str]
        String value if present, otherwise None.
    """
    if self._order is None or not hasattr(self._order, prop_name):
        return None
    value = getattr(self._order, 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\OrderInfo.py
334
335
336
337
def print_all(self) -> None:
    """Print all @property values of the class."""
    for name, value in self.to_dict().items():
        print(f"{name:24} : {value}")

to_dict()

Return all @property values from the class and its parents.

Source code in strategytester5\trade_classes\OrderInfo.py
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def to_dict(self) -> dict[str, Any]:
    """Return all @property values from the class and its parents."""
    data: dict[str, Any] = {}
    seen: set[str] = set()

    for cls in type(self).mro():
        for name, attr in vars(cls).items():
            if name in seen:
                continue
            if isinstance(attr, property):
                seen.add(name)
                try:
                    data[name] = getattr(self, name)
                except Exception as e:
                    data[name] = f"<error: {e}>"

    return data