MetaTrader 5 Python User Group - the summary - page 12

To add comments, please log in or register
Sergey Golubev
Moderator
117549
Sergey Golubev  

Forum on trading, automated trading systems and testing trading strategies

MetaTrader 5 Python User Group - how to use Python in Metatrader

Rashid Umarov , 2020.03.28 09:11

Descriptions of 3 new functions are added to the help:

In addition, changes were made to the descriptions of many functions, as they were finalized. Almost all the examples were rewritten taking into account the new functionality. However, examples for the following functions on the site have not yet been updated, they will be a little later:


nicholish en
2692
nicholish en  

How important is it to call mt5.shutdown()?

I would imagine that it is rather important otherwise it wouldn't be part of the common practice. That being said then why is it never presented in a try/finally block? If the user code raises an exception then mt5.shutdown will not get called. Another issue is not having any custom MT5 python exceptions. I'd like to propose is adding a context manager to the official MT5 library as well as a unique exception to catch in a try block. Example:


This code sets up a MT5 connection context manager and initializes the MT5 connect when entered and shuts it down when exited, ensuring that the mt5.shutdown() function is always called.

if __name__ == "__main__":
    mt5_connection = mt5_connection_context(
        path=r"C:\Users\user\Desktop\MT5\terminal64.exe",
        portable=True,
        server="MetaQuotes-Demo",
        login=112878789,
        password="d183SD8",
        timeout=7_000,
        ensure_trade_enabled=True,
        logger=print,
    )

    with mt5_connection:
        x = 1 / 0  # raises exception
        print(x)

 Produces the following result:

Python <-> MT5 init: success
Traceback (most recent call last):
  File "C:/Users/user/AppData/Scripts/mt5py.py", line 69, in <module>
    x = 1 / 0  # raises exception
ZeroDivisionError: division by zero
Python <-> MT5 shutdown: success

Here is the context manager code:

import MetaTrader5 as mt5
from contextlib import contextmanager


class Mt5Error(Exception):
    pass


@contextmanager
def mt5_connection_context(*,
    path: str = None,
    portable: bool = None,
    server: str = None,
    login: int = None,
    password: str = None,
    timeout: int = None,
    ensure_trade_enabled: bool = False,
    logger: callable = None,
    message: callable = None
):
    logger = logger or (lambda m: None)
    message = message or (lambda m: "Python <-> MT5 {}: {}".format(*m.split()))
    try:
        mt5_keys = "path portable server login password timeout".split()
        mt5_kwargs = {k: v for k, v in locals().items() if v is not None and k in mt5_keys}
        if not mt5.initialize(**mt5_kwargs):
            reason = message("init failed") + " ({}) {}".format(*mt5.last_error())
            logger(reason)
            raise Mt5Error(reason)
        else:
            logger(message("init success"))
        if ensure_trade_enabled and not mt5.terminal_info().trade_allowed:
            logger(reason:="Terminal auto-trade is disabled")
            raise Mt5Error(reason)
        yield
    finally:
        mt5.shutdown()
        logger(message("shutdown success"))
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
Дмитрий Прокопьев
232
Дмитрий Прокопьев  
nicholi shen:


This code sets up a MT5 connection context manager and initializes the MT5 connect when entered and shuts it down when exited, ensuring that the mt5.shutdown() function is always called.

 Produces the following result:

Here is the context manager code:

A good example, I would suggest devops that it be included in the documentation.

Дмитрий Прокопьев
232
Дмитрий Прокопьев  
nicholi shen:

How important is it to call mt5.shutdown()?

MetaTrader5 - in the context of implementation limited resource.

Terminals may be running on the host several. To specify which is running - the path-variable is used.

initialize(
   path                      // path to the MetaTrader 5 terminal EXE file
   timeout=TIMEOUT,          // timeout
   login=LOGIN,              // account number
   password="PASSWORD",      // password
   server="SERVER"           // server name as it is specified in the terminal
   )

To be precise, the first, unnamed parameter.

If you need to reconnect - change account or terminal, needed to execute mt5.shutdown()

Дмитрий Прокопьев
232
Дмитрий Прокопьев  
nicholi shen:


Here is the context manager code:

import MetaTrader5 as mt5
from contextlib import contextmanager


class Mt5Error(Exception):
    pass

MetaTrader5 - Exception don`t processed in the classic python concept, nessesary to use last_error()

https://www.mql5.com/en/docs/integration/python_metatrader5/mt5lasterror_py

Documentation on MQL5: Integration / MetaTrader for Python / last_error
Documentation on MQL5: Integration / MetaTrader for Python / last_error
  • www.mql5.com
allows obtaining an error code in case of a failed execution of a MetaTrader 5 library function. It is similar to GetLastError(). However, it applies its own error codes. Possible values:
nicholish en
2692
nicholish en  
Дмитрий Прокопьев:

MetaTrader5 - in the context of implementation limited resource.

Terminals may be running on the host several. To specify which is running - the path-variable is used.

To be precise, the first, unnamed parameter.

If you need to reconnect - change account or terminal, needed to execute mt5.shutdown()

So if I understand you correctly, it is not possible to have more than one concurrent terminal connection?

nicholish en
2692
nicholish en  

I've discovered an issue with the handling of **kwargs in some of the functions that can be called with or without arguments. Please reference these pytest unit tests.  

Expected behavior:

All functions should be able to except **kwargs and return the equivalent of a call without args:

all_positions = mt5.positions_get()
#should return the same as
all_positions = mt5.positions_get(**{})

This is the undesirable workaround

positions_get = lambda **kwargs: mt5.positions_get(**kwargs) if kwargs else mt5.positions_get()

pytest

import MetaTrader5 as mt5
import pytest


@pytest.fixture(autouse=True)
def mt5_init_shutdown():
    try:
        mt5.initialize()
        yield
    finally:
        mt5.shutdown()


def make_kwargs_func(func):
    return lambda **kwargs: func(**kwargs)


def test_initialize(): #PASSED
    initialize = make_kwargs_func(mt5.initialize)
    assert isinstance(mt5.initialize(), bool)
    assert isinstance(initialize(), bool)


def test_symbols_get_without_args(): #PASSED
    symbols_get = make_kwargs_func(mt5.symbols_get)
    assert mt5.symbols_get() is not None
    assert symbols_get() is not None


def test_orders_get_without_args(): #FAILED
    orders_get = make_kwargs_func(mt5.orders_get)
    assert mt5.orders_get() is not None #PASSED
    assert orders_get() is not None #FAILED


def test_positions_get_without_args(): #FAILED
    positions_get = make_kwargs_func(mt5.positions_get)
    assert mt5.positions_get() is not None #PASSED
    assert positions_get() is not None #FAILED


if __name__ == "__main__":
    pass
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
jeanjacques88
5
jeanjacques88  

Hi,

I'm newbie in MetaTrader5. I decided to start programing in this area and I'm looking for a way to integrate Python3 to it so I can extract the historical data as the first HelloWorld program.

I'm also using Debian 10 Buster. I've prepared all the packages according to the instruction here, but unfortunately I can't import MetaTrader5 and I confront with this error:

In [1]: import MetaTrader5 as mt5
Error:

----> 1 import MetaTrader5

~/mt5/env/lib/python3.7/site-packages/MetaTrader5/__init__.py in <module>
    250
    251 # import C methods to our module
--> 252 from ._core import *
    253
    254 # internal order send

ModuleNotFoundError: No module named 'MetaTrader5._core'

Does anybody here know how to come over this error?

I also installed the package successfully:

(env) [mt5] pip3 install MetaTrader5                                           
Requirement already satisfied: MetaTrader5 in ./env/lib/python3.7/site-packages (5.0.29)
Requirement already satisfied: numpy>=1.7 in ./env/lib/python3.7/site-packages (from MetaTrader5) (1.18.2

I'd installed MetaTrader5 through pip3, but this error causes me to uninstall it and reinstall with the MetaTrader5 wheel file itself but same error. I've check MetaTrader5 .whl file in pypi.org and found out it has been named win_amd64 or win32 in filename. So this made me to rename the file according to my system architecture but after successfully installation (as before) again same error is being shown. Does this package has been developed only for Windows? If so, is there any other way to deploy this package in GNU/Linux.

Thank you
nicholish en
2692
nicholish en  
jeanjacques88:

Does this package has been developed only for Windows?


Yes. It requires a running MT5 terminal which only runs on windows. 

Дмитрий Прокопьев
232
Дмитрий Прокопьев  
nicholi shen:

So if I understand you correctly, it is not possible to have more than one concurrent terminal connection?

Yes, 1 Terminal - 1 connection.

In my task, needed using over 1 terminals connections and in code i using threading.RLock() as semafor :)

I didn't come up with anything better ...

To add comments, please log in or register