Grupo de usuarios de MetaTrader 5 Python - cómo utilizar Python en Metatrader - página 60

 
Ya está disponible la versión 5.0.30
 
MetaQuotes:
Ya está disponible la versión 5.0.30

Gracias.

 
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...
 
Ya está disponible la versión 5.0.31
 
MetaQuotes:
Ya está disponible la versión 5.0.31
¿Algún cambio importante?
 
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:
¿Algún cambio importante?

No, sólo algunos arreglos para 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 :

Gracias, este ejemplo que vi, funciona.

Estoy un poco sobre otra cosa.


positions_get - se me devolverá la lista de TradePosition. En principio, se puede echar a los pandas y funcionar bien.

Pero no todo se limita a una pandas, y si necesitas conseguir algo como:

tienes que componer de alguna manera, pandas o para... de alguna manera un montón de movimientos corporales adicionales.

Se ha vuelto mucho más conveniente con _asdict (), si el que escribe no es un prog de MQL5, sino digamos un pythonista ... o un datasynetist, entonces la lista / dict es

Los elementos básicos de python, muchos están construyendo una transferencia de datos en la lista / dict.

Las tuplas se utilizan mucho y muy a menudo, pero sólo si se necesita un control estricto de los tipos de datos que se mueven en ellas.

y también cuelga un manejador de errores, si no se usa o se asigna correctamente. Bueno, en algún lugar ... :) Podría estar equivocado.

Ok estoy completamente de acuerdo con este sentimiento ahora, y también creo que devolver los datos como namedtuples en lugar de diccionarios es demasiado opinable para una API. Recientemente he tenido problemas con este diseño porque es imposible hacer un pickle de namedtuples. Considere el siguiente script de copiado de comercio concurrente. ¿Notaste lo complicado que es convertir todas las namedtuples en diccionarios para poder utilizar el 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
    }
  ]
}

Es especialmente difícil cuando hay namedtuples anidados dentro de namedtuple, como es el caso de OrderSendResult.request. Así que hay que crear funciones de conversión únicas para convertirlos de nuevo en tipos de datos seleccionables. Se podría pasar todo por una función recursiva para convertirlo de nuevo en tipos de datos nativos, pero esto es computacionalmente caro.

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
 

Fallo en la instalación

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