MetaTrader 5 Python User Group - the summary - page 13

 
nicholi shen:

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:

This is the undesirable workaround

pytest

it should be written in the main thread ... i copied 

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

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 ...

Wrong. There can be many connections to one terminal (rather to a broker / account). Or did I misunderstand?

 

The examples for the following functions were updated:

Documentation on MQL5: Integration / MetaTrader for Python / order_calc_margin
Documentation on MQL5: Integration / MetaTrader for Python / order_calc_margin
  • www.mql5.com
The function allows estimating the margin necessary for a specified order type on the current account and in the current market environment without considering the current pending orders and open positions. The function is similar to OrderCalcMargin...
 
alkam_ai:
pip install MetaTrader5 does not work even after an upgrade to python 3.8

It does work. I'm using 3.82 and python and additional packages are running fine.

I'm not sure if you are into developing, if so please ignore my lack of knowledge about you. If not then take a look at https://www.mql5.com/en/docs/integration/python_metatrader5 and https://datatofish.com/upgrade-pip/

Notice that you must be using CMD as Administrator.  You have to find the CMD app and right click >Run as administrator

Pip is an absolute must prior to continuing with any of the steps.  You don't want to build the whl with outdated Pip

All these steps must be done every time you update Python.


I would recommend using PyCharm as your Python IDE outside of MT5 purposes


Nothing will install if you don't run CMD as Administrator.

1. Install the latest developer packages into the MT5 MetaEditor under options.

2. Ensure that the Python directory is the actual 3.8 path and not the MT5 python path. (you may have to copy and paste the path)

3. Did you ensure all boxes were checked during the 3.8 installation?

4. You will need quite a few gigabytes of storage in your hard drive for all the developer tools


The below test script is modified from the python_metatrader5 link above. This will run if you follow all the developer installation steps


# Copyright 2019, MetaQuotes Software Corp.

# https://www.mql5.com


from datetime import datetime

import matplotlib.pyplot as plt

import pandas as pd

from pandas.plotting import register_matplotlib_converters

register_matplotlib_converters()

import MetaTrader5 as mt5

# you code here


# connect to MetaTrader 5

if not mt5.initialize():

    print("initialize() failed")

    mt5.shutdown()

 

# request connection status and parameters

print(mt5.terminal_info())

# get data on MetaTrader 5 version

print(mt5.version())


# shut down connection to MetaTrader 5

mt5.shutdown()

Documentation on MQL5: Integration / MetaTrader for Python
Documentation on MQL5: Integration / MetaTrader for Python
  • www.mql5.com
Python is a modern high-level programming language for developing scripts and applications. It contains multiple libraries for machine learning, process automation, as well as data analysis and visualization. MetaTrader package for Python is designed...
 
Azeem Hussein:

Is it possible to send a request to set a stop loss on an existing order?

I have a code that works in my python ea, which can set and open trades. however I need to know the syntax for mt5.Buy(), mt5.Sell(), and what values they accept. for example how can i set a stop loss and take profit value when sending a buy? or a sell?

Buy(), Sell(), Close() just wrappers on oreder_send() in module __init__.py file:

# internal order send
def _RawOrder(order_type, symbol, volume, price, comment=None, ticket=None):
    order = {
      "action":    TRADE_ACTION_DEAL,
      "symbol":    symbol,
      "volume":    volume,
      "type":      order_type,
      "price":     price,
      "deviation": 10,
    }
    if comment != None:
        order["comment"] = comment
    if ticket != None:
        order["position"] = ticket
    r = order_send(order)
    return r

# Close all specific orders
def Close(symbol, *, comment=None, ticket=None):
    if ticket != None:
        positions = positions_get(ticket=ticket)
    else:
        positions = positions_get(symbol=symbol)

    tried = 0
    done = 0

    for pos in positions:
        # process only simple buy, sell
        if pos.type == ORDER_TYPE_BUY or pos.type == ORDER_TYPE_SELL:
            tried += 1
            for tries in range(10):
                info = symbol_info_tick(symbol)
                if pos.type == ORDER_TYPE_BUY:
                    r = _RawOrder(ORDER_TYPE_SELL, symbol, pos.volume, info.bid, comment, pos.ticket)
                else:
                    r = _RawOrder(ORDER_TYPE_BUY, symbol, pos.volume, info.ask, comment, pos.ticket)
                # check results
                if r.retcode != TRADE_RETCODE_REQUOTE and r.retcode != TRADE_RETCODE_PRICE_OFF:
                    if r.retcode == TRADE_RETCODE_DONE:
                        done += 1
                    break
    
    if done > 0:
        if done == tried:
            return True
        else:
            return "Partially"
    return False

# Buy order                
def Buy(symbol, volume, price=None, *, comment=None, ticket=None):
    # with direct call
    if price != None:
        return _RawOrder(ORDER_TYPE_BUY, symbol, volume, price, comment, ticket)
    # no price, we try several times with current price
    for tries in range(10):
        info = symbol_info_tick(symbol)
        r = _RawOrder(ORDER_TYPE_BUY, symbol, volume, info.ask, comment, ticket)
        if r.retcode != TRADE_RETCODE_REQUOTE and r.retcode != TRADE_RETCODE_PRICE_OFF:
            break
    return r

# Sell order
def Sell(symbol, volume, price=None, *, comment=None, ticket=None):
    # with direct call
    if price != None:
        return _RawOrder(ORDER_TYPE_SELL, symbol, volume, price, comment, ticket)
    # no price, we try several times with current price
    for tries in range(10):
        info = symbol_info_tick(symbol)
        r = _RawOrder(ORDER_TYPE_SELL, symbol, volume, info.bid, comment, ticket)
        if r.retcode != TRADE_RETCODE_REQUOTE and r.retcode != TRADE_RETCODE_PRICE_OFF:
            break
    return r
 
Vladimir Perervenko:

Wrong. There can be many connections to one terminal (rather to a broker / account). Or did I misunderstand?

MT5 can be used in portable mode

https://www.metatrader5.com/en/terminal/help/start_advanced/start

2 MT5 instance - 2 broker/accounts, but 1 MetaTrader5 library, 1 connection at a time ... 

Platform Start - For Advanced Users - MetaTrader 5 Help
Platform Start - For Advanced Users - MetaTrader 5 Help
  • www.metatrader5.com
After installation, a group of programs of the trading platform is added to the Start menu, and the program shortcut is created on the desktop. Use them to run the platform. Two copies of the platform cannot run from the same directory. If you need to run multiple copies at the same time, install the appropriate number of programs in different...
 

Bug report - package version 5.0.30


1. The functions [history_deals_get, history_deals_total, history_orders_get, history_orders_total, ...all of the copy_funcs] all have a fundamental flaw, and that is the parameter "from". From is a reserved keyword in python and cannot be used as a parameter name. This prevents the creation of pythonic adapter functions due to the naming conflict. The following will not even compile:

def my_history_orders_total(from:datetime, to:datetime):
    return mt5.history_orders_total(from=from, to=to)

The parameter names should be changed to something that doesn't conflict with python and is more descriptive. Example:

def my_history_orders_total(datetime_from:datetime, datetime_to:datetime, **kwargs):
    return mt5.history_orders_total(datetime_from=datetime_from, datetime_to=datetime_to)

2. The mt5.RES_* constants are assigned as tuples instead of <int>. Someone forgot to remove the commas after the expressions in the MetaTrader5.__init__.py module. This is how to fix the bug:

RES_S_OK                            =1, # <-- REMOVE COMMA
RES_E_FAIL                          =-1,# <-- REMOVE COMMA
...					# etc

Test

def test_last_error_res_codes():
    defined_error_codes = [getattr(mt5, name) for name in dir(mt5) if name.startswith('RES_')]
    for code in defined_error_codes:
        assert isinstance(code, int)


3. last_error() should return a tuple instead of a list in order to remain consistent with the API.

Test

def test_last_error():
    defined_error_codes = [getattr(mt5, name) for name in dir(mt5) if name.startswith('RES_')]
    error = mt5.last_error()
    assert isinstance(error, tuple)
    assert len(error) == 2
    code, description = error
    assert code in defined_error_codes
    assert isinstance(code, int)
    assert isinstance(description, str)

4. The documentation for version() needs to change the type for the "build-number" from type "string" to "int"


5. history_deals_get (and perhaps other functions) are inconsistent with their return type. Some functions return None when there is no data to return and other functions return an empty tuple. These functions all need to be consistent. They should all return the same object in the case of no data -- instead of some returning None and some returning an empty tuple. 

Test

def test_consistency_for_empty_data_returns():
    def all_same_return_types(results):
        g = itertools.groupby(results, key=lambda v: type(v))
        return next(g, True) and not next(g, False)

    funcs = (mt5.positions_get, mt5.orders_get, mt5.history_orders_get, mt5.history_deals_get,)
    results = [f(ticket=0) for f in funcs]
    assert all_same_return_types(results)


Please see all pytest unittests attached. 

Files:
 
version 5.0.31 released
 
Дмитрий Прокопьев:
version 5.0.31 released

Thanks for the rapid response! All tests passed with the exception of the one that checks for different return types. Any idea about change the keyword "from" in the C-functions?

Reason: