Mt5Client

pdmt5.mt5

MetaTrader5 client wrapper class.

Mt5Client

Bases: BaseModel

MetaTrader5 client class.

This class provides a wrapper interface to all MetaTrader5 functions, delegating calls to the underlying MetaTrader5 module while providing error handling and logging capabilities.

logger class-attribute instance-attribute

logger: Logger = Field(
    default_factory=lambda: getLogger(__name__),
    description="Logger instance for MetaTrader5 operations",
)

model_config class-attribute instance-attribute

model_config = ConfigDict(arbitrary_types_allowed=True)

mt5 class-attribute instance-attribute

mt5: ModuleType = Field(
    default_factory=lambda: import_module("MetaTrader5"),
    description="MetaTrader5 module instance",
)

__enter__

__enter__() -> Self

Context manager entry.

Returns:

Name Type Description
Mt5Client Self

The client instance.

Source code in pdmt5/mt5.py
def __enter__(self) -> Self:
    """Context manager entry.

    Returns:
        Mt5Client: The client instance.
    """
    self.initialize()
    return self

__exit__

__exit__(
    exc_type: type[BaseException] | None,
    exc_val: BaseException | None,
    exc_tb: TracebackType | None,
) -> None

Context manager exit.

Source code in pdmt5/mt5.py
def __exit__(
    self,
    exc_type: type[BaseException] | None,
    exc_val: BaseException | None,
    exc_tb: TracebackType | None,
) -> None:
    """Context manager exit."""
    self.shutdown()

account_info

account_info() -> Any

Get info on the current trading account.

Returns:

Type Description
Any

AccountInfo structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def account_info(self) -> Any:
    """Get info on the current trading account.

    Returns:
        AccountInfo structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving account information.")
    response = self.mt5.account_info()
    self._validate_mt5_response_is_not_none(
        response=response, operation="account_info"
    )
    return response

copy_rates_from

copy_rates_from(
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    count: int,
) -> Any

Get bars from the terminal starting from the specified date.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
date_from datetime | int

Start date or timestamp.

required
count int

Number of bars to retrieve.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_from(
    self,
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    count: int,
) -> Any:
    """Get bars from the terminal starting from the specified date.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        date_from: Start date or timestamp.
        count: Number of bars to retrieve.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying rates from symbol: %s, timeframe: %d, date_from: %s, count: %d",
        symbol,
        timeframe,
        date_from,
        count,
    )
    response = self.mt5.copy_rates_from(symbol, timeframe, date_from, count)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_from",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" date_from={date_from}, count={count}"
        ),
    )
    return response

copy_rates_from_pos

copy_rates_from_pos(
    symbol: str, timeframe: int, start_pos: int, count: int
) -> Any

Get bars from the terminal starting from the specified index.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
start_pos int

Starting position.

required
count int

Number of bars to retrieve.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_from_pos(
    self,
    symbol: str,
    timeframe: int,
    start_pos: int,
    count: int,
) -> Any:
    """Get bars from the terminal starting from the specified index.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        start_pos: Starting position.
        count: Number of bars to retrieve.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        (
            "Copying rates from position:"
            " symbol=%s, timeframe=%d, start_pos=%d, count=%d"
        ),
        symbol,
        timeframe,
        start_pos,
        count,
    )
    response = self.mt5.copy_rates_from_pos(symbol, timeframe, start_pos, count)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_from_pos",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" start_pos={start_pos}, count={count}"
        ),
    )
    return response

copy_rates_range

copy_rates_range(
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    date_to: datetime | int,
) -> Any

Get bars in the specified date range from the terminal.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_range(
    self,
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    date_to: datetime | int,
) -> Any:
    """Get bars in the specified date range from the terminal.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying rates range: symbol=%s, timeframe=%d, date_from=%s, date_to=%s",
        symbol,
        timeframe,
        date_from,
        date_to,
    )
    response = self.mt5.copy_rates_range(symbol, timeframe, date_from, date_to)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_range",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" date_from={date_from}, date_to={date_to}"
        ),
    )
    return response

copy_ticks_from

copy_ticks_from(
    symbol: str,
    date_from: datetime | int,
    count: int,
    flags: int,
) -> Any

Get ticks from the terminal starting from the specified date.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
date_from datetime | int

Start date or timestamp.

required
count int

Number of ticks to retrieve.

required
flags int

Tick flags.

required

Returns:

Type Description
Any

Array of ticks or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_ticks_from(
    self,
    symbol: str,
    date_from: datetime | int,
    count: int,
    flags: int,
) -> Any:
    """Get ticks from the terminal starting from the specified date.

    Args:
        symbol: Symbol name.
        date_from: Start date or timestamp.
        count: Number of ticks to retrieve.
        flags: Tick flags.

    Returns:
        Array of ticks or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying ticks from symbol: %s, date_from: %s, count: %d, flags: %d",
        symbol,
        date_from,
        count,
        flags,
    )
    response = self.mt5.copy_ticks_from(symbol, date_from, count, flags)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_ticks_from",
        context=(
            f"symbol={symbol}, date_from={date_from}, count={count}, flags={flags}"
        ),
    )
    return response

copy_ticks_range

copy_ticks_range(
    symbol: str,
    date_from: datetime | int,
    date_to: datetime | int,
    flags: int,
) -> Any

Get ticks for the specified date range from the terminal.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required
flags int

Tick flags.

required

Returns:

Type Description
Any

Array of ticks or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_ticks_range(
    self,
    symbol: str,
    date_from: datetime | int,
    date_to: datetime | int,
    flags: int,
) -> Any:
    """Get ticks for the specified date range from the terminal.

    Args:
        symbol: Symbol name.
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        flags: Tick flags.

    Returns:
        Array of ticks or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying ticks range: symbol=%s, date_from=%s, date_to=%s, flags=%d",
        symbol,
        date_from,
        date_to,
        flags,
    )
    response = self.mt5.copy_ticks_range(symbol, date_from, date_to, flags)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_ticks_range",
        context=(
            f"symbol={symbol}, date_from={date_from},"
            f" date_to={date_to}, flags={flags}"
        ),
    )
    return response

history_deals_get

history_deals_get(
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]

Get deals from trading history within the specified interval with the ability to filter by ticket or position.

Parameters:

Name Type Description Default
date_from datetime | int | None

Start date or timestamp.

None
date_to datetime | int | None

End date or timestamp.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None
position int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of historical deal info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_deals_get(
    self,
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]:
    """Get deals from trading history within the specified interval with the ability to filter by ticket or position.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        group: Group filter.
        ticket: Order ticket filter.
        position: Position ticket filter.

    Returns:
        Tuple of historical deal info structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving deal with ticket: %d", ticket)
        response = self.mt5.history_deals_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif position is not None:
        self.logger.info("Retrieving deal for position: %d", position)
        response = self.mt5.history_deals_get(position=position)
        context = f"position={position}"
    elif group is not None:
        self.logger.info(
            "Retrieving deals for group: %s, date_from: %s, date_to: %s",
            group,
            date_from,
            date_to,
        )
        response = self.mt5.history_deals_get(date_from, date_to, group=group)
        context = f"date_from={date_from}, date_to={date_to}, group={group}"
    else:
        self.logger.info(
            "Retrieving all historical deals from %s to %s",
            date_from,
            date_to,
        )
        response = self.mt5.history_deals_get(date_from, date_to)
        context = f"date_from={date_from}, date_to={date_to}"
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="history_deals_get",
        context=context,
    )
    return response

history_deals_total

history_deals_total(
    date_from: datetime | int, date_to: datetime | int
) -> int

Get the number of deals in trading history within the specified interval.

Parameters:

Name Type Description Default
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
int

Number of historical deals.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_deals_total(
    self,
    date_from: datetime | int,
    date_to: datetime | int,
) -> int:
    """Get the number of deals in trading history within the specified interval.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Number of historical deals.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Retrieving total number of historical deals from %s to %s",
        date_from,
        date_to,
    )
    return self.mt5.history_deals_total(date_from, date_to)

history_orders_get

history_orders_get(
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]

Get orders from trading history with the ability to filter by ticket or position.

Parameters:

Name Type Description Default
date_from datetime | int | None

Start date or timestamp.

None
date_to datetime | int | None

End date or timestamp.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None
position int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of historical order info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_orders_get(
    self,
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]:
    """Get orders from trading history with the ability to filter by ticket or position.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        group: Group filter.
        ticket: Order ticket filter.
        position: Position ticket filter.

    Returns:
        Tuple of historical order info structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving order with ticket: %d", ticket)
        response = self.mt5.history_orders_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif position is not None:
        self.logger.info("Retrieving order for position: %d", position)
        response = self.mt5.history_orders_get(position=position)
        context = f"position={position}"
    elif group is not None:
        self.logger.info(
            "Retrieving orders for group: %s, date_from: %s, date_to: %s",
            group,
            date_from,
            date_to,
        )
        response = self.mt5.history_orders_get(date_from, date_to, group=group)
        context = f"date_from={date_from}, date_to={date_to}, group={group}"
    else:
        self.logger.info(
            "Retrieving all historical orders from %s to %s",
            date_from,
            date_to,
        )
        response = self.mt5.history_orders_get(date_from, date_to)
        context = f"date_from={date_from}, date_to={date_to}"
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="history_orders_get",
        context=context,
    )
    return response

history_orders_total

history_orders_total(
    date_from: datetime | int, date_to: datetime | int
) -> int

Get the number of orders in trading history within the specified interval.

Parameters:

Name Type Description Default
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
int

Number of historical orders.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_orders_total(
    self,
    date_from: datetime | int,
    date_to: datetime | int,
) -> int:
    """Get the number of orders in trading history within the specified interval.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Number of historical orders.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Retrieving total number of historical orders from %s to %s",
        date_from,
        date_to,
    )
    return self.mt5.history_orders_total(date_from, date_to)

initialize

initialize(
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool

Establish a connection with the MetaTrader 5 terminal.

Parameters:

Name Type Description Default
path str | None

Path to the MetaTrader 5 terminal EXE file.

None
login int | None

Trading account number.

None
password str | None

Trading account password.

None
server str | None

Trade server address.

None
timeout int | None

Connection timeout in milliseconds.

None

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def initialize(
    self,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool:
    """Establish a connection with the MetaTrader 5 terminal.

    Args:
        path: Path to the MetaTrader 5 terminal EXE file.
        login: Trading account number.
        password: Trading account password.
        server: Trade server address.
        timeout: Connection timeout in milliseconds.

    Returns:
        True if successful, False otherwise.
    """
    if path is not None:
        self.logger.info(
            "Initializing MT5 connection with path: %s",
            path,
        )
        self._is_initialized = self.mt5.initialize(
            path,
            **{
                k: v
                for k, v in {
                    "login": login,
                    "password": password,
                    "server": server,
                    "timeout": timeout,
                }.items()
                if v is not None
            },
        )
    else:
        self.logger.info("Initializing MT5 connection.")
        self._is_initialized = self.mt5.initialize()
    return self._is_initialized

last_error

last_error() -> tuple[int, str]

Return data on the last error.

Returns:

Type Description
tuple[int, str]

Tuple of (error_code, error_description).

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def last_error(self) -> tuple[int, str]:
    """Return data on the last error.

    Returns:
        Tuple of (error_code, error_description).
    """
    self.logger.info("Retrieving last MT5 error")
    return self.mt5.last_error()

login

login(
    login: int,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool

Connect to a trading account using specified parameters.

Parameters:

Name Type Description Default
login int

Trading account number.

required
password str | None

Trading account password.

None
server str | None

Trade server address.

None
timeout int | None

Connection timeout in milliseconds.

None

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def login(
    self,
    login: int,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool:
    """Connect to a trading account using specified parameters.

    Args:
        login: Trading account number.
        password: Trading account password.
        server: Trade server address.
        timeout: Connection timeout in milliseconds.

    Returns:
        True if successful, False otherwise.
    """
    self._initialize_if_needed()
    self.logger.info("Logging in to MT5 account: %d", login)
    return self.mt5.login(
        login,
        **{
            k: v
            for k, v in {
                "password": password,
                "server": server,
                "timeout": timeout,
            }.items()
            if v is not None
        },
    )

market_book_add

market_book_add(symbol: str) -> bool

Subscribe the terminal to the Market Depth change events for a specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_add(self, symbol: str) -> bool:
    """Subscribe the terminal to the Market Depth change events for a specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        True if successful, False otherwise.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Adding market book for symbol: %s", symbol)
    response = self.mt5.market_book_add(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_add",
        context=f"symbol={symbol}",
    )
    return response

market_book_get

market_book_get(symbol: str) -> tuple[Any, ...]

Return a tuple from BookInfo featuring Market Depth entries for the specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
tuple[Any, ...]

Tuple of BookInfo structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_get(self, symbol: str) -> tuple[Any, ...]:
    """Return a tuple from BookInfo featuring Market Depth entries for the specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        Tuple of BookInfo structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Retrieving market book for symbol: %s", symbol)
    response = self.mt5.market_book_get(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_get",
        context=f"symbol={symbol}",
    )
    return response

market_book_release

market_book_release(symbol: str) -> bool

Cancels subscription of the terminal to the Market Depth change events for a specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_release(self, symbol: str) -> bool:
    """Cancels subscription of the terminal to the Market Depth change events for a specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        True if successful, False otherwise.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Releasing market book for symbol: %s", symbol)
    response = self.mt5.market_book_release(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_release",
        context=f"symbol={symbol}",
    )
    return response

order_calc_margin

order_calc_margin(
    action: int, symbol: str, volume: float, price: float
) -> float

Return margin in the account currency to perform a specified trading operation.

Parameters:

Name Type Description Default
action int

Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).

required
symbol str

Symbol name.

required
volume float

Volume in lots.

required
price float

Open price.

required

Returns:

Type Description
float

Required margin amount or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_calc_margin(
    self,
    action: int,
    symbol: str,
    volume: float,
    price: float,
) -> float:
    """Return margin in the account currency to perform a specified trading operation.

    Args:
        action: Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).
        symbol: Symbol name.
        volume: Volume in lots.
        price: Open price.

    Returns:
        Required margin amount or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info(
        "Calculating margin: action=%d, symbol=%s, volume=%.2f, price=%.5f",
        action,
        symbol,
        volume,
        price,
    )
    response = self.mt5.order_calc_margin(action, symbol, volume, price)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_calc_margin",
        context=f"action={action}, symbol={symbol}, volume={volume}, price={price}",
    )
    return response

order_calc_profit

order_calc_profit(
    action: int,
    symbol: str,
    volume: float,
    price_open: float,
    price_close: float,
) -> float

Return profit in the account currency for a specified trading operation.

Parameters:

Name Type Description Default
action int

Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).

required
symbol str

Symbol name.

required
volume float

Volume in lots.

required
price_open float

Open price.

required
price_close float

Close price.

required

Returns:

Type Description
float

Calculated profit or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_calc_profit(
    self,
    action: int,
    symbol: str,
    volume: float,
    price_open: float,
    price_close: float,
) -> float:
    """Return profit in the account currency for a specified trading operation.

    Args:
        action: Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).
        symbol: Symbol name.
        volume: Volume in lots.
        price_open: Open price.
        price_close: Close price.

    Returns:
        Calculated profit or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        (
            "Calculating profit: action=%d, symbol=%s, volume=%.2f,"
            " price_open=%.5f, price_close=%.5f"
        ),
        action,
        symbol,
        volume,
        price_open,
        price_close,
    )
    response = self.mt5.order_calc_profit(
        action, symbol, volume, price_open, price_close
    )
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_calc_profit",
        context=(
            f"action={action}, symbol={symbol}, volume={volume},"
            f" price_open={price_open}, price_close={price_close}"
        ),
    )
    return response

order_check

order_check(request: dict[str, Any]) -> Any

Check funds sufficiency for performing a required trading operation.

Parameters:

Name Type Description Default
request dict[str, Any]

Trade request dictionary.

required

Returns:

Type Description
Any

OrderCheckResult structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_check(self, request: dict[str, Any]) -> Any:
    """Check funds sufficiency for performing a required trading operation.

    Args:
        request: Trade request dictionary.

    Returns:
        OrderCheckResult structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Checking order with request: %s", request)
    response = self.mt5.order_check(request)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_check",
        context=f"request={request}",
    )
    return response

order_send

order_send(request: dict[str, Any]) -> Any

Send a request to perform a trading operation from the terminal to the trade server.

Parameters:

Name Type Description Default
request dict[str, Any]

Trade request dictionary.

required

Returns:

Type Description
Any

OrderSendResult structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_send(self, request: dict[str, Any]) -> Any:
    """Send a request to perform a trading operation from the terminal to the trade server.

    Args:
        request: Trade request dictionary.

    Returns:
        OrderSendResult structure or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Sending order with request: %s", request)
    response = self.mt5.order_send(request)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_send",
        context=f"request={request}",
    )
    return response

orders_get

orders_get(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]

Get active orders with the ability to filter by symbol or ticket.

Parameters:

Name Type Description Default
symbol str | None

Symbol name filter.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of order info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def orders_get(
    self,
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]:
    """Get active orders with the ability to filter by symbol or ticket.

    Args:
        symbol: Symbol name filter.
        group: Group filter.
        ticket: Order ticket filter.

    Returns:
        Tuple of order info structures or None.
    """
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving order with ticket: %d", ticket)
        response = self.mt5.orders_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif group is not None:
        self.logger.info("Retrieving orders for group: %s", group)
        response = self.mt5.orders_get(group=group)
        context = f"group={group}"
    elif symbol is not None:
        self.logger.info("Retrieving orders for symbol: %s", symbol)
        response = self.mt5.orders_get(symbol=symbol)
        context = f"symbol={symbol}"
    else:
        self.logger.info("Retrieving all active orders.")
        response = self.mt5.orders_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="orders_get",
        context=context,
    )
    return response

orders_total

orders_total() -> int

Get the number of active orders.

Returns:

Type Description
int

Number of active orders.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def orders_total(self) -> int:
    """Get the number of active orders.

    Returns:
        Number of active orders.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of active orders.")
    return self.mt5.orders_total()

positions_get

positions_get(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]

Get open positions with the ability to filter by symbol or ticket.

Parameters:

Name Type Description Default
symbol str | None

Symbol name filter.

None
group str | None

Group filter.

None
ticket int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of position info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def positions_get(
    self,
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]:
    """Get open positions with the ability to filter by symbol or ticket.

    Args:
        symbol: Symbol name filter.
        group: Group filter.
        ticket: Position ticket filter.

    Returns:
        Tuple of position info structures or None.
    """
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving position with ticket: %d", ticket)
        response = self.mt5.positions_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif group is not None:
        self.logger.info("Retrieving positions for group: %s", group)
        response = self.mt5.positions_get(group=group)
        context = f"group={group}"
    elif symbol is not None:
        self.logger.info("Retrieving positions for symbol: %s", symbol)
        response = self.mt5.positions_get(symbol=symbol)
        context = f"symbol={symbol}"
    else:
        self.logger.info("Retrieving all open positions.")
        response = self.mt5.positions_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="positions_get",
        context=context,
    )
    return response

positions_total

positions_total() -> int

Get the number of open positions.

Returns:

Type Description
int

Number of open positions.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def positions_total(self) -> int:
    """Get the number of open positions.

    Returns:
        Number of open positions.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of open positions.")
    return self.mt5.positions_total()

shutdown

shutdown() -> None

Close the previously established connection to the MetaTrader 5 terminal.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def shutdown(self) -> None:
    """Close the previously established connection to the MetaTrader 5 terminal."""
    self.logger.info("Shutting down MT5 connection.")
    response = self.mt5.shutdown()
    self._is_initialized = False
    return response

symbol_info

symbol_info(symbol: str) -> Any

Get data on the specified financial instrument.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
Any

Symbol info structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_info(self, symbol: str) -> Any:
    """Get data on the specified financial instrument.

    Args:
        symbol: Symbol name.

    Returns:
        Symbol info structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving information for symbol: %s", symbol)
    response = self.mt5.symbol_info(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_info",
        context=f"symbol={symbol}",
    )
    return response

symbol_info_tick

symbol_info_tick(symbol: str) -> Any

Get the last tick for the specified financial instrument.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
Any

Tick info structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_info_tick(self, symbol: str) -> Any:
    """Get the last tick for the specified financial instrument.

    Args:
        symbol: Symbol name.

    Returns:
        Tick info structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving last tick for symbol: %s", symbol)
    response = self.mt5.symbol_info_tick(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_info_tick",
        context=f"symbol={symbol}",
    )
    return response

symbol_select

symbol_select(symbol: str, enable: bool = True) -> bool

Select a symbol in the MarketWatch window or remove a symbol from the window.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
enable bool

True to show, False to hide.

True

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_select(self, symbol: str, enable: bool = True) -> bool:
    """Select a symbol in the MarketWatch window or remove a symbol from the window.

    Args:
        symbol: Symbol name.
        enable: True to show, False to hide.

    Returns:
        True if successful, False otherwise.
    """
    self._initialize_if_needed()
    self.logger.info("Selecting symbol: %s, enable=%s", symbol, enable)
    response = self.mt5.symbol_select(symbol, enable)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_select",
        context=f"symbol={symbol}, enable={enable}",
    )
    return response

symbols_get

symbols_get(group: str | None = None) -> tuple[Any, ...]

Get all financial instruments from the terminal.

Parameters:

Name Type Description Default
group str | None

Symbol group filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of symbol info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbols_get(self, group: str | None = None) -> tuple[Any, ...]:
    """Get all financial instruments from the terminal.

    Args:
        group: Symbol group filter.

    Returns:
        Tuple of symbol info structures or None.
    """
    self._initialize_if_needed()
    if group is not None:
        self.logger.info("Retrieving symbols for group: %s", group)
        response = self.mt5.symbols_get(group=group)
        context = f"group={group}"
    else:
        self.logger.info("Retrieving all symbols.")
        response = self.mt5.symbols_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbols_get",
        context=context,
    )
    return response

symbols_total

symbols_total() -> int

Get the number of all financial instruments in the terminal.

Returns:

Type Description
int

Total number of symbols.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbols_total(self) -> int:
    """Get the number of all financial instruments in the terminal.

    Returns:
        Total number of symbols.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of symbols.")
    return self.mt5.symbols_total()

terminal_info

terminal_info() -> Any

Get the connected MetaTrader 5 client terminal status and settings.

Returns:

Type Description
Any

TerminalInfo structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def terminal_info(self) -> Any:
    """Get the connected MetaTrader 5 client terminal status and settings.

    Returns:
        TerminalInfo structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving terminal information.")
    response = self.mt5.terminal_info()
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="terminal_info",
    )
    return response

version

version() -> tuple[int, int, str]

Return the MetaTrader 5 terminal version.

Returns:

Type Description
tuple[int, int, str]

Tuple of (terminal_version, build, release_date).

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def version(self) -> tuple[int, int, str]:
    """Return the MetaTrader 5 terminal version.

    Returns:
        Tuple of (terminal_version, build, release_date).
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving MT5 version information.")
    return self.mt5.version()

Mt5RuntimeError

Bases: RuntimeError

MetaTrader5 specific runtime error.

Raised when MetaTrader5 operations fail or when the client is used incorrectly (e.g., calling methods before initialization).

Overview

The Mt5Client module provides the base client class for connecting to MetaTrader 5 and performing core operations. This is the foundation class that handles the low-level MT5 API interactions and provides basic error handling and connection management.

Classes

Mt5Client

pdmt5.mt5.Mt5Client

Bases: BaseModel

MetaTrader5 client class.

This class provides a wrapper interface to all MetaTrader5 functions, delegating calls to the underlying MetaTrader5 module while providing error handling and logging capabilities.

logger class-attribute instance-attribute

logger: Logger = Field(
    default_factory=lambda: getLogger(__name__),
    description="Logger instance for MetaTrader5 operations",
)

model_config class-attribute instance-attribute

model_config = ConfigDict(arbitrary_types_allowed=True)

mt5 class-attribute instance-attribute

mt5: ModuleType = Field(
    default_factory=lambda: import_module("MetaTrader5"),
    description="MetaTrader5 module instance",
)

__enter__

__enter__() -> Self

Context manager entry.

Returns:

Name Type Description
Mt5Client Self

The client instance.

Source code in pdmt5/mt5.py
def __enter__(self) -> Self:
    """Context manager entry.

    Returns:
        Mt5Client: The client instance.
    """
    self.initialize()
    return self

__exit__

__exit__(
    exc_type: type[BaseException] | None,
    exc_val: BaseException | None,
    exc_tb: TracebackType | None,
) -> None

Context manager exit.

Source code in pdmt5/mt5.py
def __exit__(
    self,
    exc_type: type[BaseException] | None,
    exc_val: BaseException | None,
    exc_tb: TracebackType | None,
) -> None:
    """Context manager exit."""
    self.shutdown()

account_info

account_info() -> Any

Get info on the current trading account.

Returns:

Type Description
Any

AccountInfo structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def account_info(self) -> Any:
    """Get info on the current trading account.

    Returns:
        AccountInfo structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving account information.")
    response = self.mt5.account_info()
    self._validate_mt5_response_is_not_none(
        response=response, operation="account_info"
    )
    return response

copy_rates_from

copy_rates_from(
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    count: int,
) -> Any

Get bars from the terminal starting from the specified date.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
date_from datetime | int

Start date or timestamp.

required
count int

Number of bars to retrieve.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_from(
    self,
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    count: int,
) -> Any:
    """Get bars from the terminal starting from the specified date.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        date_from: Start date or timestamp.
        count: Number of bars to retrieve.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying rates from symbol: %s, timeframe: %d, date_from: %s, count: %d",
        symbol,
        timeframe,
        date_from,
        count,
    )
    response = self.mt5.copy_rates_from(symbol, timeframe, date_from, count)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_from",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" date_from={date_from}, count={count}"
        ),
    )
    return response

copy_rates_from_pos

copy_rates_from_pos(
    symbol: str, timeframe: int, start_pos: int, count: int
) -> Any

Get bars from the terminal starting from the specified index.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
start_pos int

Starting position.

required
count int

Number of bars to retrieve.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_from_pos(
    self,
    symbol: str,
    timeframe: int,
    start_pos: int,
    count: int,
) -> Any:
    """Get bars from the terminal starting from the specified index.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        start_pos: Starting position.
        count: Number of bars to retrieve.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        (
            "Copying rates from position:"
            " symbol=%s, timeframe=%d, start_pos=%d, count=%d"
        ),
        symbol,
        timeframe,
        start_pos,
        count,
    )
    response = self.mt5.copy_rates_from_pos(symbol, timeframe, start_pos, count)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_from_pos",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" start_pos={start_pos}, count={count}"
        ),
    )
    return response

copy_rates_range

copy_rates_range(
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    date_to: datetime | int,
) -> Any

Get bars in the specified date range from the terminal.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
timeframe int

Timeframe constant.

required
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
Any

Array of rates or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_rates_range(
    self,
    symbol: str,
    timeframe: int,
    date_from: datetime | int,
    date_to: datetime | int,
) -> Any:
    """Get bars in the specified date range from the terminal.

    Args:
        symbol: Symbol name.
        timeframe: Timeframe constant.
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Array of rates or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying rates range: symbol=%s, timeframe=%d, date_from=%s, date_to=%s",
        symbol,
        timeframe,
        date_from,
        date_to,
    )
    response = self.mt5.copy_rates_range(symbol, timeframe, date_from, date_to)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_rates_range",
        context=(
            f"symbol={symbol}, timeframe={timeframe},"
            f" date_from={date_from}, date_to={date_to}"
        ),
    )
    return response

copy_ticks_from

copy_ticks_from(
    symbol: str,
    date_from: datetime | int,
    count: int,
    flags: int,
) -> Any

Get ticks from the terminal starting from the specified date.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
date_from datetime | int

Start date or timestamp.

required
count int

Number of ticks to retrieve.

required
flags int

Tick flags.

required

Returns:

Type Description
Any

Array of ticks or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_ticks_from(
    self,
    symbol: str,
    date_from: datetime | int,
    count: int,
    flags: int,
) -> Any:
    """Get ticks from the terminal starting from the specified date.

    Args:
        symbol: Symbol name.
        date_from: Start date or timestamp.
        count: Number of ticks to retrieve.
        flags: Tick flags.

    Returns:
        Array of ticks or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying ticks from symbol: %s, date_from: %s, count: %d, flags: %d",
        symbol,
        date_from,
        count,
        flags,
    )
    response = self.mt5.copy_ticks_from(symbol, date_from, count, flags)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_ticks_from",
        context=(
            f"symbol={symbol}, date_from={date_from}, count={count}, flags={flags}"
        ),
    )
    return response

copy_ticks_range

copy_ticks_range(
    symbol: str,
    date_from: datetime | int,
    date_to: datetime | int,
    flags: int,
) -> Any

Get ticks for the specified date range from the terminal.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required
flags int

Tick flags.

required

Returns:

Type Description
Any

Array of ticks or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def copy_ticks_range(
    self,
    symbol: str,
    date_from: datetime | int,
    date_to: datetime | int,
    flags: int,
) -> Any:
    """Get ticks for the specified date range from the terminal.

    Args:
        symbol: Symbol name.
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        flags: Tick flags.

    Returns:
        Array of ticks or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Copying ticks range: symbol=%s, date_from=%s, date_to=%s, flags=%d",
        symbol,
        date_from,
        date_to,
        flags,
    )
    response = self.mt5.copy_ticks_range(symbol, date_from, date_to, flags)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="copy_ticks_range",
        context=(
            f"symbol={symbol}, date_from={date_from},"
            f" date_to={date_to}, flags={flags}"
        ),
    )
    return response

history_deals_get

history_deals_get(
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]

Get deals from trading history within the specified interval with the ability to filter by ticket or position.

Parameters:

Name Type Description Default
date_from datetime | int | None

Start date or timestamp.

None
date_to datetime | int | None

End date or timestamp.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None
position int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of historical deal info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_deals_get(
    self,
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]:
    """Get deals from trading history within the specified interval with the ability to filter by ticket or position.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        group: Group filter.
        ticket: Order ticket filter.
        position: Position ticket filter.

    Returns:
        Tuple of historical deal info structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving deal with ticket: %d", ticket)
        response = self.mt5.history_deals_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif position is not None:
        self.logger.info("Retrieving deal for position: %d", position)
        response = self.mt5.history_deals_get(position=position)
        context = f"position={position}"
    elif group is not None:
        self.logger.info(
            "Retrieving deals for group: %s, date_from: %s, date_to: %s",
            group,
            date_from,
            date_to,
        )
        response = self.mt5.history_deals_get(date_from, date_to, group=group)
        context = f"date_from={date_from}, date_to={date_to}, group={group}"
    else:
        self.logger.info(
            "Retrieving all historical deals from %s to %s",
            date_from,
            date_to,
        )
        response = self.mt5.history_deals_get(date_from, date_to)
        context = f"date_from={date_from}, date_to={date_to}"
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="history_deals_get",
        context=context,
    )
    return response

history_deals_total

history_deals_total(
    date_from: datetime | int, date_to: datetime | int
) -> int

Get the number of deals in trading history within the specified interval.

Parameters:

Name Type Description Default
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
int

Number of historical deals.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_deals_total(
    self,
    date_from: datetime | int,
    date_to: datetime | int,
) -> int:
    """Get the number of deals in trading history within the specified interval.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Number of historical deals.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Retrieving total number of historical deals from %s to %s",
        date_from,
        date_to,
    )
    return self.mt5.history_deals_total(date_from, date_to)

history_orders_get

history_orders_get(
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]

Get orders from trading history with the ability to filter by ticket or position.

Parameters:

Name Type Description Default
date_from datetime | int | None

Start date or timestamp.

None
date_to datetime | int | None

End date or timestamp.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None
position int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of historical order info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_orders_get(
    self,
    date_from: datetime | int | None = None,
    date_to: datetime | int | None = None,
    group: str | None = None,
    ticket: int | None = None,
    position: int | None = None,
) -> tuple[Any, ...]:
    """Get orders from trading history with the ability to filter by ticket or position.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.
        group: Group filter.
        ticket: Order ticket filter.
        position: Position ticket filter.

    Returns:
        Tuple of historical order info structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving order with ticket: %d", ticket)
        response = self.mt5.history_orders_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif position is not None:
        self.logger.info("Retrieving order for position: %d", position)
        response = self.mt5.history_orders_get(position=position)
        context = f"position={position}"
    elif group is not None:
        self.logger.info(
            "Retrieving orders for group: %s, date_from: %s, date_to: %s",
            group,
            date_from,
            date_to,
        )
        response = self.mt5.history_orders_get(date_from, date_to, group=group)
        context = f"date_from={date_from}, date_to={date_to}, group={group}"
    else:
        self.logger.info(
            "Retrieving all historical orders from %s to %s",
            date_from,
            date_to,
        )
        response = self.mt5.history_orders_get(date_from, date_to)
        context = f"date_from={date_from}, date_to={date_to}"
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="history_orders_get",
        context=context,
    )
    return response

history_orders_total

history_orders_total(
    date_from: datetime | int, date_to: datetime | int
) -> int

Get the number of orders in trading history within the specified interval.

Parameters:

Name Type Description Default
date_from datetime | int

Start date or timestamp.

required
date_to datetime | int

End date or timestamp.

required

Returns:

Type Description
int

Number of historical orders.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def history_orders_total(
    self,
    date_from: datetime | int,
    date_to: datetime | int,
) -> int:
    """Get the number of orders in trading history within the specified interval.

    Args:
        date_from: Start date or timestamp.
        date_to: End date or timestamp.

    Returns:
        Number of historical orders.
    """
    self._initialize_if_needed()
    self.logger.info(
        "Retrieving total number of historical orders from %s to %s",
        date_from,
        date_to,
    )
    return self.mt5.history_orders_total(date_from, date_to)

initialize

initialize(
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool

Establish a connection with the MetaTrader 5 terminal.

Parameters:

Name Type Description Default
path str | None

Path to the MetaTrader 5 terminal EXE file.

None
login int | None

Trading account number.

None
password str | None

Trading account password.

None
server str | None

Trade server address.

None
timeout int | None

Connection timeout in milliseconds.

None

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def initialize(
    self,
    path: str | None = None,
    login: int | None = None,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool:
    """Establish a connection with the MetaTrader 5 terminal.

    Args:
        path: Path to the MetaTrader 5 terminal EXE file.
        login: Trading account number.
        password: Trading account password.
        server: Trade server address.
        timeout: Connection timeout in milliseconds.

    Returns:
        True if successful, False otherwise.
    """
    if path is not None:
        self.logger.info(
            "Initializing MT5 connection with path: %s",
            path,
        )
        self._is_initialized = self.mt5.initialize(
            path,
            **{
                k: v
                for k, v in {
                    "login": login,
                    "password": password,
                    "server": server,
                    "timeout": timeout,
                }.items()
                if v is not None
            },
        )
    else:
        self.logger.info("Initializing MT5 connection.")
        self._is_initialized = self.mt5.initialize()
    return self._is_initialized

last_error

last_error() -> tuple[int, str]

Return data on the last error.

Returns:

Type Description
tuple[int, str]

Tuple of (error_code, error_description).

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def last_error(self) -> tuple[int, str]:
    """Return data on the last error.

    Returns:
        Tuple of (error_code, error_description).
    """
    self.logger.info("Retrieving last MT5 error")
    return self.mt5.last_error()

login

login(
    login: int,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool

Connect to a trading account using specified parameters.

Parameters:

Name Type Description Default
login int

Trading account number.

required
password str | None

Trading account password.

None
server str | None

Trade server address.

None
timeout int | None

Connection timeout in milliseconds.

None

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def login(
    self,
    login: int,
    password: str | None = None,
    server: str | None = None,
    timeout: int | None = None,
) -> bool:
    """Connect to a trading account using specified parameters.

    Args:
        login: Trading account number.
        password: Trading account password.
        server: Trade server address.
        timeout: Connection timeout in milliseconds.

    Returns:
        True if successful, False otherwise.
    """
    self._initialize_if_needed()
    self.logger.info("Logging in to MT5 account: %d", login)
    return self.mt5.login(
        login,
        **{
            k: v
            for k, v in {
                "password": password,
                "server": server,
                "timeout": timeout,
            }.items()
            if v is not None
        },
    )

market_book_add

market_book_add(symbol: str) -> bool

Subscribe the terminal to the Market Depth change events for a specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_add(self, symbol: str) -> bool:
    """Subscribe the terminal to the Market Depth change events for a specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        True if successful, False otherwise.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Adding market book for symbol: %s", symbol)
    response = self.mt5.market_book_add(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_add",
        context=f"symbol={symbol}",
    )
    return response

market_book_get

market_book_get(symbol: str) -> tuple[Any, ...]

Return a tuple from BookInfo featuring Market Depth entries for the specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
tuple[Any, ...]

Tuple of BookInfo structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_get(self, symbol: str) -> tuple[Any, ...]:
    """Return a tuple from BookInfo featuring Market Depth entries for the specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        Tuple of BookInfo structures or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Retrieving market book for symbol: %s", symbol)
    response = self.mt5.market_book_get(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_get",
        context=f"symbol={symbol}",
    )
    return response

market_book_release

market_book_release(symbol: str) -> bool

Cancels subscription of the terminal to the Market Depth change events for a specified symbol.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def market_book_release(self, symbol: str) -> bool:
    """Cancels subscription of the terminal to the Market Depth change events for a specified symbol.

    Args:
        symbol: Symbol name.

    Returns:
        True if successful, False otherwise.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Releasing market book for symbol: %s", symbol)
    response = self.mt5.market_book_release(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="market_book_release",
        context=f"symbol={symbol}",
    )
    return response

order_calc_margin

order_calc_margin(
    action: int, symbol: str, volume: float, price: float
) -> float

Return margin in the account currency to perform a specified trading operation.

Parameters:

Name Type Description Default
action int

Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).

required
symbol str

Symbol name.

required
volume float

Volume in lots.

required
price float

Open price.

required

Returns:

Type Description
float

Required margin amount or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_calc_margin(
    self,
    action: int,
    symbol: str,
    volume: float,
    price: float,
) -> float:
    """Return margin in the account currency to perform a specified trading operation.

    Args:
        action: Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).
        symbol: Symbol name.
        volume: Volume in lots.
        price: Open price.

    Returns:
        Required margin amount or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info(
        "Calculating margin: action=%d, symbol=%s, volume=%.2f, price=%.5f",
        action,
        symbol,
        volume,
        price,
    )
    response = self.mt5.order_calc_margin(action, symbol, volume, price)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_calc_margin",
        context=f"action={action}, symbol={symbol}, volume={volume}, price={price}",
    )
    return response

order_calc_profit

order_calc_profit(
    action: int,
    symbol: str,
    volume: float,
    price_open: float,
    price_close: float,
) -> float

Return profit in the account currency for a specified trading operation.

Parameters:

Name Type Description Default
action int

Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).

required
symbol str

Symbol name.

required
volume float

Volume in lots.

required
price_open float

Open price.

required
price_close float

Close price.

required

Returns:

Type Description
float

Calculated profit or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_calc_profit(
    self,
    action: int,
    symbol: str,
    volume: float,
    price_open: float,
    price_close: float,
) -> float:
    """Return profit in the account currency for a specified trading operation.

    Args:
        action: Order type (ORDER_TYPE_BUY or ORDER_TYPE_SELL).
        symbol: Symbol name.
        volume: Volume in lots.
        price_open: Open price.
        price_close: Close price.

    Returns:
        Calculated profit or None.
    """
    self._initialize_if_needed()
    self.logger.info(
        (
            "Calculating profit: action=%d, symbol=%s, volume=%.2f,"
            " price_open=%.5f, price_close=%.5f"
        ),
        action,
        symbol,
        volume,
        price_open,
        price_close,
    )
    response = self.mt5.order_calc_profit(
        action, symbol, volume, price_open, price_close
    )
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_calc_profit",
        context=(
            f"action={action}, symbol={symbol}, volume={volume},"
            f" price_open={price_open}, price_close={price_close}"
        ),
    )
    return response

order_check

order_check(request: dict[str, Any]) -> Any

Check funds sufficiency for performing a required trading operation.

Parameters:

Name Type Description Default
request dict[str, Any]

Trade request dictionary.

required

Returns:

Type Description
Any

OrderCheckResult structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_check(self, request: dict[str, Any]) -> Any:
    """Check funds sufficiency for performing a required trading operation.

    Args:
        request: Trade request dictionary.

    Returns:
        OrderCheckResult structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Checking order with request: %s", request)
    response = self.mt5.order_check(request)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_check",
        context=f"request={request}",
    )
    return response

order_send

order_send(request: dict[str, Any]) -> Any

Send a request to perform a trading operation from the terminal to the trade server.

Parameters:

Name Type Description Default
request dict[str, Any]

Trade request dictionary.

required

Returns:

Type Description
Any

OrderSendResult structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def order_send(self, request: dict[str, Any]) -> Any:
    """Send a request to perform a trading operation from the terminal to the trade server.

    Args:
        request: Trade request dictionary.

    Returns:
        OrderSendResult structure or None.
    """  # noqa: E501
    self._initialize_if_needed()
    self.logger.info("Sending order with request: %s", request)
    response = self.mt5.order_send(request)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="order_send",
        context=f"request={request}",
    )
    return response

orders_get

orders_get(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]

Get active orders with the ability to filter by symbol or ticket.

Parameters:

Name Type Description Default
symbol str | None

Symbol name filter.

None
group str | None

Group filter.

None
ticket int | None

Order ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of order info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def orders_get(
    self,
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]:
    """Get active orders with the ability to filter by symbol or ticket.

    Args:
        symbol: Symbol name filter.
        group: Group filter.
        ticket: Order ticket filter.

    Returns:
        Tuple of order info structures or None.
    """
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving order with ticket: %d", ticket)
        response = self.mt5.orders_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif group is not None:
        self.logger.info("Retrieving orders for group: %s", group)
        response = self.mt5.orders_get(group=group)
        context = f"group={group}"
    elif symbol is not None:
        self.logger.info("Retrieving orders for symbol: %s", symbol)
        response = self.mt5.orders_get(symbol=symbol)
        context = f"symbol={symbol}"
    else:
        self.logger.info("Retrieving all active orders.")
        response = self.mt5.orders_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="orders_get",
        context=context,
    )
    return response

orders_total

orders_total() -> int

Get the number of active orders.

Returns:

Type Description
int

Number of active orders.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def orders_total(self) -> int:
    """Get the number of active orders.

    Returns:
        Number of active orders.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of active orders.")
    return self.mt5.orders_total()

positions_get

positions_get(
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]

Get open positions with the ability to filter by symbol or ticket.

Parameters:

Name Type Description Default
symbol str | None

Symbol name filter.

None
group str | None

Group filter.

None
ticket int | None

Position ticket filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of position info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def positions_get(
    self,
    symbol: str | None = None,
    group: str | None = None,
    ticket: int | None = None,
) -> tuple[Any, ...]:
    """Get open positions with the ability to filter by symbol or ticket.

    Args:
        symbol: Symbol name filter.
        group: Group filter.
        ticket: Position ticket filter.

    Returns:
        Tuple of position info structures or None.
    """
    self._initialize_if_needed()
    if ticket is not None:
        self.logger.info("Retrieving position with ticket: %d", ticket)
        response = self.mt5.positions_get(ticket=ticket)
        context = f"ticket={ticket}"
    elif group is not None:
        self.logger.info("Retrieving positions for group: %s", group)
        response = self.mt5.positions_get(group=group)
        context = f"group={group}"
    elif symbol is not None:
        self.logger.info("Retrieving positions for symbol: %s", symbol)
        response = self.mt5.positions_get(symbol=symbol)
        context = f"symbol={symbol}"
    else:
        self.logger.info("Retrieving all open positions.")
        response = self.mt5.positions_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="positions_get",
        context=context,
    )
    return response

positions_total

positions_total() -> int

Get the number of open positions.

Returns:

Type Description
int

Number of open positions.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def positions_total(self) -> int:
    """Get the number of open positions.

    Returns:
        Number of open positions.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of open positions.")
    return self.mt5.positions_total()

shutdown

shutdown() -> None

Close the previously established connection to the MetaTrader 5 terminal.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def shutdown(self) -> None:
    """Close the previously established connection to the MetaTrader 5 terminal."""
    self.logger.info("Shutting down MT5 connection.")
    response = self.mt5.shutdown()
    self._is_initialized = False
    return response

symbol_info

symbol_info(symbol: str) -> Any

Get data on the specified financial instrument.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
Any

Symbol info structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_info(self, symbol: str) -> Any:
    """Get data on the specified financial instrument.

    Args:
        symbol: Symbol name.

    Returns:
        Symbol info structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving information for symbol: %s", symbol)
    response = self.mt5.symbol_info(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_info",
        context=f"symbol={symbol}",
    )
    return response

symbol_info_tick

symbol_info_tick(symbol: str) -> Any

Get the last tick for the specified financial instrument.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required

Returns:

Type Description
Any

Tick info structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_info_tick(self, symbol: str) -> Any:
    """Get the last tick for the specified financial instrument.

    Args:
        symbol: Symbol name.

    Returns:
        Tick info structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving last tick for symbol: %s", symbol)
    response = self.mt5.symbol_info_tick(symbol)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_info_tick",
        context=f"symbol={symbol}",
    )
    return response

symbol_select

symbol_select(symbol: str, enable: bool = True) -> bool

Select a symbol in the MarketWatch window or remove a symbol from the window.

Parameters:

Name Type Description Default
symbol str

Symbol name.

required
enable bool

True to show, False to hide.

True

Returns:

Type Description
bool

True if successful, False otherwise.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbol_select(self, symbol: str, enable: bool = True) -> bool:
    """Select a symbol in the MarketWatch window or remove a symbol from the window.

    Args:
        symbol: Symbol name.
        enable: True to show, False to hide.

    Returns:
        True if successful, False otherwise.
    """
    self._initialize_if_needed()
    self.logger.info("Selecting symbol: %s, enable=%s", symbol, enable)
    response = self.mt5.symbol_select(symbol, enable)
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbol_select",
        context=f"symbol={symbol}, enable={enable}",
    )
    return response

symbols_get

symbols_get(group: str | None = None) -> tuple[Any, ...]

Get all financial instruments from the terminal.

Parameters:

Name Type Description Default
group str | None

Symbol group filter.

None

Returns:

Type Description
tuple[Any, ...]

Tuple of symbol info structures or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbols_get(self, group: str | None = None) -> tuple[Any, ...]:
    """Get all financial instruments from the terminal.

    Args:
        group: Symbol group filter.

    Returns:
        Tuple of symbol info structures or None.
    """
    self._initialize_if_needed()
    if group is not None:
        self.logger.info("Retrieving symbols for group: %s", group)
        response = self.mt5.symbols_get(group=group)
        context = f"group={group}"
    else:
        self.logger.info("Retrieving all symbols.")
        response = self.mt5.symbols_get()
        context = None
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="symbols_get",
        context=context,
    )
    return response

symbols_total

symbols_total() -> int

Get the number of all financial instruments in the terminal.

Returns:

Type Description
int

Total number of symbols.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def symbols_total(self) -> int:
    """Get the number of all financial instruments in the terminal.

    Returns:
        Total number of symbols.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving total number of symbols.")
    return self.mt5.symbols_total()

terminal_info

terminal_info() -> Any

Get the connected MetaTrader 5 client terminal status and settings.

Returns:

Type Description
Any

TerminalInfo structure or None.

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def terminal_info(self) -> Any:
    """Get the connected MetaTrader 5 client terminal status and settings.

    Returns:
        TerminalInfo structure or None.
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving terminal information.")
    response = self.mt5.terminal_info()
    self._validate_mt5_response_is_not_none(
        response=response,
        operation="terminal_info",
    )
    return response

version

version() -> tuple[int, int, str]

Return the MetaTrader 5 terminal version.

Returns:

Type Description
tuple[int, int, str]

Tuple of (terminal_version, build, release_date).

Source code in pdmt5/mt5.py
@_log_mt5_last_status_code
def version(self) -> tuple[int, int, str]:
    """Return the MetaTrader 5 terminal version.

    Returns:
        Tuple of (terminal_version, build, release_date).
    """
    self._initialize_if_needed()
    self.logger.info("Retrieving MT5 version information.")
    return self.mt5.version()

options: show_bases: false

Base client class for MetaTrader 5 operations with connection management and error handling.

Mt5RuntimeError

pdmt5.mt5.Mt5RuntimeError

Bases: RuntimeError

MetaTrader5 specific runtime error.

Raised when MetaTrader5 operations fail or when the client is used incorrectly (e.g., calling methods before initialization).

options: show_bases: false

Custom runtime exception for MetaTrader 5 specific errors.

Usage Examples

Basic Connection

import MetaTrader5 as mt5
from pdmt5.mt5 import Mt5Client

# Create client
client = Mt5Client(mt5=mt5)

# Use as context manager
with client:
    # Initialize connection
    success = client.initialize()
    if success:
        print("Connected to MetaTrader 5")

        # Get version info
        version = client.version()
        print(f"MT5 Version: {version}")

        # Get account info
        account = client.account_info()
        print(f"Account: {account}")

Connection with Login

with client:
    # Initialize with path
    client.initialize(path="C:\\Program Files\\MetaTrader 5\\terminal64.exe")

    # Login to specific account
    success = client.login(
        login=12345,
        password="your_password",
        server="broker_server"
    )

    if success:
        print("Logged in successfully")

Symbol Operations

with client:
    client.initialize()

    # Get total number of symbols
    total = client.symbols_total()
    print(f"Total symbols: {total}")

    # Get all symbols
    symbols = client.symbols_get()
    print(f"First 5 symbols: {symbols[:5]}")

    # Get symbols by group
    forex_symbols = client.symbols_get(group="*USD*")

    # Get specific symbol info
    symbol_info = client.symbol_info("EURUSD")
    print(f"EURUSD info: {symbol_info}")

    # Get current tick
    tick = client.symbol_info_tick("EURUSD")
    print(f"Current EURUSD tick: {tick}")

Market Data Retrieval

from datetime import datetime
import MetaTrader5 as mt5

with client:
    client.initialize()

    # Get OHLCV rates from specific date
    rates = client.copy_rates_from(
        symbol="EURUSD",
        timeframe=mt5.TIMEFRAME_H1,
        date_from=datetime(2024, 1, 1),
        count=100
    )

    # Get rates within date range
    rates_range = client.copy_rates_range(
        symbol="EURUSD",
        timeframe=mt5.TIMEFRAME_D1,
        date_from=datetime(2024, 1, 1),
        date_to=datetime(2024, 1, 31)
    )

    # Get tick data
    ticks = client.copy_ticks_from(
        symbol="EURUSD",
        date_from=datetime(2024, 1, 1),
        count=1000,
        flags=mt5.COPY_TICKS_ALL
    )

Trading Operations

with client:
    client.initialize()
    client.login(12345, "password", "server")

    # Get current positions
    positions = client.positions_get()
    print(f"Open positions: {len(positions) if positions else 0}")

    # Get current orders
    orders = client.orders_get()
    print(f"Pending orders: {len(orders) if orders else 0}")

    # Calculate margin requirement
    margin = client.order_calc_margin(
        action=mt5.ORDER_TYPE_BUY,
        symbol="EURUSD",
        volume=1.0,
        price=1.1000
    )
    print(f"Required margin: {margin}")

    # Calculate profit
    profit = client.order_calc_profit(
        action=mt5.ORDER_TYPE_BUY,
        symbol="EURUSD",
        volume=1.0,
        price_open=1.1000,
        price_close=1.1050
    )
    print(f"Calculated profit: {profit}")

Historical Data

from datetime import datetime

with client:
    client.initialize()

    # Get historical orders
    history_orders = client.history_orders_get(
        date_from=datetime(2024, 1, 1),
        date_to=datetime(2024, 1, 31)
    )

    # Get historical deals
    history_deals = client.history_deals_get(
        date_from=datetime(2024, 1, 1),
        date_to=datetime(2024, 1, 31)
    )

    # Get specific order by ticket
    order = client.history_orders_get(ticket=123456)

Market Book Operations

with client:
    client.initialize()

    # Subscribe to market depth
    success = client.market_book_add("EURUSD")
    if success:
        print("Subscribed to EURUSD market depth")

        # Get market book
        book = client.market_book_get("EURUSD")
        print(f"Market book: {book}")

        # Unsubscribe
        client.market_book_release("EURUSD")

Connection Management

The Mt5Client supports both explicit and context manager usage:

# Explicit initialization
client = Mt5Client(mt5=mt5)
client.initialize()
try:
    # Your trading operations
    account = client.account_info()
finally:
    client.shutdown()

# Context manager (recommended)
with Mt5Client(mt5=mt5) as client:
    client.initialize()
    # Your trading operations
    account = client.account_info()

Error Handling

All methods include proper error handling and raise Mt5RuntimeError with detailed information when operations fail:

from pdmt5.mt5 import Mt5RuntimeError

try:
    with client:
        client.initialize()
        rates = client.copy_rates_from("INVALID", mt5.TIMEFRAME_H1, datetime.now(), 100)
except Mt5RuntimeError as e:
    print(f"MetaTrader 5 error: {e}")

Logging

The client includes comprehensive logging for all operations:

import logging

# Enable debug logging to see all MT5 operations
logging.basicConfig(level=logging.DEBUG)

with client:
    client.initialize()  # Will log initialization details
    account = client.account_info()  # Will log account retrieval

Method Categories

Connection Management

  • initialize() - Initialize MT5 connection
  • login() - Login to trading account
  • shutdown() - Close connection
  • version() - Get MT5 version
  • last_error() - Get last error details

Account & Terminal

  • account_info() - Get account information
  • terminal_info() - Get terminal status and settings

Symbol Management

  • symbols_total() - Get total number of symbols
  • symbols_get() - Get symbol list
  • symbol_info() - Get symbol information
  • symbol_info_tick() - Get current tick
  • symbol_select() - Add/remove symbol from Market Watch

Market Data

  • copy_rates_from() - Get OHLCV rates from date
  • copy_rates_from_pos() - Get OHLCV rates from position
  • copy_rates_range() - Get OHLCV rates in date range
  • copy_ticks_from() - Get ticks from date
  • copy_ticks_range() - Get ticks in date range

Market Book

  • market_book_add() - Subscribe to market depth
  • market_book_release() - Unsubscribe from market depth
  • market_book_get() - Get market book data

Trading

  • orders_total() - Get number of pending orders
  • orders_get() - Get pending orders
  • positions_total() - Get number of open positions
  • positions_get() - Get open positions
  • order_calc_margin() - Calculate required margin
  • order_calc_profit() - Calculate profit
  • order_check() - Validate order request
  • order_send() - Send trading order

History

  • history_orders_total() - Get historical orders count
  • history_orders_get() - Get historical orders
  • history_deals_total() - Get historical deals count
  • history_deals_get() - Get historical deals

Best Practices

  1. Always use context manager for automatic connection management
  2. Handle errors gracefully with try-except blocks
  3. Initialize before operations - call initialize() after creating the client
  4. Use logging to debug connection and operation issues
  5. Check return values - many methods return None on failure
  6. Use appropriate timeframes and date ranges for data requests
  7. Subscribe/unsubscribe to market book properly to avoid resource leaks