MetaTrader 5 Python User Group - Comment utiliser Python dans Metatrader - page 60

 
La version 5.0.30 est sortie
 
MetaQuotes:
La version 5.0.30 est sortie

Merci !

 
MetaTrader 5 Python User Group - the summary
MetaTrader 5 Python User Group - the summary
  • 2020.03.30
  • www.mql5.com
The Main Study MetaTrader Python online documentation Python Releases for Windows - website MetaTrader5 : Python Package - website...
 
La version 5.0.31 est sortie
 
MetaQuotes:
La version 5.0.31 est sortie
Des changements majeurs ?
 
MetaTrader 5 Python User Group - the summary
MetaTrader 5 Python User Group - the summary
  • 2020.04.02
  • www.mql5.com
The Main Study MetaTrader Python online documentation Python Releases for Windows - website MetaTrader5 : Python Package - website...
 
Kiran Sawant:
Des changements majeurs ?

Non, juste quelques corrections pour https://www.mql5.com/en/forum/306742/page13#comment_15699363

MetaTrader 5 Python User Group - the summary
MetaTrader 5 Python User Group - the summary
  • 2020.03.30
  • www.mql5.com
The Main Study MetaTrader Python online documentation Python Releases for Windows - website MetaTrader5 : Python Package - website...
 
pymt5adapter
pymt5adapter
  • 2020.04.02
  • pypi.org
is a wrapper and drop-in replacement for the python package by MetaQuotes. The API functions return the same values from the functions, but adds the following functionality: Typing hinting has been added to all functions and return objects for linting and IDE integration. Intellisense will now work now matter how nested the objects are...
 
Dmitry Prokopyev :

Merci, cet exemple que j'ai vu, il fonctionne.

Je suis un peu sur autre chose.


positions_get - la liste des positions commerciales me sera retournée. En principe, vous pouvez ajouter des pandas et travailler sans problème.

Mais tout n'est pas limité à un seul pandas, et si vous avez besoin d'obtenir quelque chose comme :

vous devez composer d'une manière ou d'une autre, pandas ou pour... en quelque sorte beaucoup de mouvements corporels supplémentaires.

C'est devenu beaucoup plus pratique avec _asdict (), si celui qui écrit n'est pas un prog MQL5, mais disons un pythoniste ... ou un datasynetist, alors la liste / dict est

Les éléments de base de python, beaucoup construisent un transfert de données sur liste / dict.

Les tuples sont utilisés, trop souvent et beaucoup, mais seulement si vous avez besoin de contrôler étroitement les types de données qui y circulent.

et suspend également un gestionnaire d'erreur, s'il n'est pas utilisé ou assigné correctement. Eh bien, quelque part... :) Je peux me tromper.

Ok, je suis tout à fait d'accord avec ce sentiment maintenant, et je pense aussi que renvoyer des données sous forme de tuples nommés au lieu de dictionnaires est trop subjectif pour une API. J'ai récemment eu des problèmes avec cette conception parce qu'il est impossible de récupérer les namedtuples. Considérons le script de copie de commerce simultané suivant. Remarquez combien il est fastidieux de convertir tous les namedtuples en dictionnaires afin d'utiliser le ProcessPoolExectutor ?


trade_copier.py

import json
import time
from concurrent.futures.process import ProcessPoolExecutor
from typing import List

import pymt5adapter as mt5
from pymt5adapter.order import Order
from pymt5adapter.symbol import Symbol


def result_to_dict(result):
    res = result._asdict()
    res['request'] = res['request']._asdict()
    return res


def p2d(positions):
    return [p._asdict() for p in positions]


def get_position_map(positions: List[dict]):
    position_map = {}
    for p in positions:
        position_map.setdefault(p['symbol'], {}).setdefault('positions', []).append(p)
        v = -p['volume'] if p['type'] else p['volume']
        inner = position_map[p['symbol']]
        inner['net_volume'] = inner.get('net_volume', 0.0) + v
    return position_map


def match_positions(terminal, positions):
    result_positions = []
    incoming = get_position_map(positions)
    with mt5.connected(**terminal):
        my_pos_map = get_position_map(p2d(mt5.positions_get()))
        for symbol, d in incoming.items():
            if symbol not in my_pos_map:
                volume = d['net_volume']
            else:
                volume = d['net_volume'] - my_pos_map[symbol]['net_volume']
            if volume == 0.0:
                continue
            symbol = Symbol(symbol)
            order = Order.as_buy() if volume > 0.0 else Order.as_sell()
            order(volume=abs(volume), symbol=symbol.name)
            for _ in range(5):
                symbol.refresh_rates()
                price = symbol.ask if volume > 0.0 else symbol.bid
                res = order(price=price).send()
                if res.retcode == mt5.TRADE_RETCODE_DONE:
                    result_positions.append(result_to_dict(res))
                    break
    return result_positions


def main():
    with open('terminal_config.json') as f:
        terminals = json.load(f)
    master = terminals['master']
    slaves = terminals['slaves']
    with mt5.connected(**master), ProcessPoolExecutor() as pool:
        while True:
            positions = [p2d(mt5.positions_get())] * len(slaves)
            results = list(pool.map(match_positions, slaves, positions))
            for result in results:
                for sub in result:
                    if sub:
                        print(sub)
            time.sleep(0.01)


if __name__ == "__main__":
    main()

terminal_config.json

{
  "master": {
    "path":"C:\\Users\\nicho\\Desktop\\terminal1\\terminal64.exe",
    "portable": true
  },
  "slaves": [
    {
      "path": "C:\\Users\\nicho\\Desktop\\terminal2\\terminal64.exe",
      "portable": true
    },{
      "path": "C:\\Users\\nicho\\Desktop\\terminal3\\terminal64.exe",
      "portable": true
    }
  ]
}

C'est particulièrement difficile lorsqu'il y a des namedtuples imbriqués à l'intérieur de namedtuple, comme c'est le cas avec OrderSendResult.request. Il faut donc créer des fonctions de conversion uniques pour les reconvertir en types de données exploitables. Vous pourriez faire passer le tout par une fonction récursive pour le reconvertir en types de données natives, mais cela est coûteux en calcul.

def as_dict(data: Any):
    try:
        return as_dict(data._asdict())
    except AttributeError:
        T = type(data)
        if T is list or T is tuple:
            return T(as_dict(i) for i in data)
        if T is dict:
            return {k: as_dict(v) for k, v in data.items()}
        return data
 

Échec de l'installation

----- Установка "pymt5adapter" -----
ERROR: Could not find a version that satisfies the requirement pymt5adapter (from versions: none)
ERROR: No matching distribution found for pymt5adapter
----- Не удалось установить "pymt5adapter". -----

----- Установка "pymt5adapter==0.1.11" -----
ERROR: Could not find a version that satisfies the requirement pymt5adapter==0.1.11 (from versions: none)
ERROR: No matching distribution found for pymt5adapter==0.1.11
----- Не удалось установить "pymt5adapter==0.1.11". -----

----- Установка "pymt5adapter" -----
ERROR: Could not find a version that satisfies the requirement pymt5adapter (from versions: none)
ERROR: No matching distribution found for pymt5adapter
----- Не удалось установить "pymt5adapter". -----

Win10, Py3.6.10 et WinPy3.7.7.