MetaTrader 5 Python User Group - wie man Python in Metatrader verwendet - Seite 60

 
Version 5.0.30 ist erschienen
 
MetaQuotes:
Version 5.0.30 ist erschienen

Ich danke Ihnen!

 
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...
 
Version 5.0.31 ist erschienen
 
MetaQuotes:
Version 5.0.31 ist erschienen
Irgendwelche größeren Änderungen?
 
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:
Irgendwelche größeren Änderungen?

Nein, nur einige Korrekturen für 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 :

Danke, dieses Beispiel habe ich gesehen, es funktioniert.

Mir geht es um etwas anderes.


positions_get - die Liste der TradePosition wird an mich zurückgegeben. Im Prinzip kann man Pandas einbauen und gut arbeiten.

Aber alles ist nicht auf einen Panda beschränkt, und wenn Sie etwas wie:

Sie müssen irgendwie komponieren, Pandas oder für... irgendwie eine Menge zusätzlicher Körperbewegungen.

Mit _asdict () ist es viel bequemer geworden, wenn derjenige, der schreibt, kein MQL5-Prog ist, sondern, sagen wir, ein Pythonist ... oder ein Datennetzbetreiber, dann ist list / dict

Die grundlegenden Elemente von Python, viele bauen eine Datenübertragung auf Liste / dict.

Tupel werden zu oft und viel verwendet, aber nur, wenn Sie die Datentypen, die sich darin bewegen, genau kontrollieren müssen.

und auch einen Fehler-Handler aufhängen, wenn er nicht richtig verwendet oder zugewiesen wird. Nun, irgendwo ... :) Ich könnte mich irren.

Ok, ich stimme dieser Meinung jetzt völlig zu, und ich denke auch, dass die Rückgabe von Daten als Namedtupel anstelle von Wörterbüchern zu eigenwillig für eine API ist. Kürzlich hatte ich Probleme mit diesem Design, weil es unmöglich ist, namedtuples zu picken. Betrachten Sie das folgende Skript zum Kopieren von gleichzeitigem Handel. Haben Sie bemerkt, wie mühsam es ist, alle Namedtupel in Dictionaries umzuwandeln, um den ProcessPoolExectutor zu nutzen?


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
    }
  ]
}

Besonders schwierig ist es, wenn Namedtupel in Namedtupel verschachtelt sind, wie es bei OrderSendResult.request der Fall ist. Sie müssen also eigene Konvertierungsfunktionen erstellen, nur um sie wieder in abrufbare Datentypen umzuwandeln. Sie könnten alles durch eine rekursive Funktion laufen lassen, um es wieder in native Datentypen zu konvertieren, aber das ist sehr rechenintensiv.

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
 

Installation fehlgeschlagen

----- Установка "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 und WinPy3.7.7.