f5db7b13fe223453c6b2950ab4e5cddea7a80e19
Metaquotes MQL5 - JSON - API
Development state: stable beta (code is stable)
Table of Contents
About the Project
This project was developed to work as a server for Backtrader Python trading framework. It is based on ZeroMQ sockets and uses JSON format to communicate. But now it has grown to the independent project. You can use it with any language that has ZeroMQ binding.
Backtrader Python client located here: Python Backtrader - Metaquotes MQL5
In development:
- Historical data load speed
- Trades info
- Experation
- Devitation
Installation
- Install ZeroMQ for MQL5 https://github.com/dingmaotu/mql-zmq
- Put 'include/Json.mqh' from this repo to your MetaEditor 'include' directoty.
- Download and compile JsonAPI script.
- Check if automatic trading is allowed.
- Attach the script to a chart in Metatrader 5.
- Allow DLL import in dialog window.
- Check if the ports are free to use. (default: 15555, 15556, 15557, 15558)
Tested on macOS Mojave and Windows 10 in Parallels Desktop container.
Documentation
The script uses 4 ZeroMQ sockets:
- System socket - recives requests from client and replies 'OK'
- Data socket - pushes data to client depending on request via System socket.
- Live socket - pushes last candle when it closes.
- Streaming socket - pushes last transaction info when it happens.
Configure the script:
{
"action": None,
"actionType": None,
"symbol": None,
"chartTF": None,
"fromDate": None,
"toDate": None,
"id": None,
"magic": None,
"volume": None,
"price": None,
"stoploss": None,
"takeprofit": None,
"expiration": None,
"deviation": None,
"comment": None
}
| action | actionType | Description |
|---|---|---|
| CONFIG | null | Set script configuration |
| ACCOUNT | null | Get account settings |
| BALANCE | null | Get current balance |
| HISTORY | null | Get symbol history |
| POSITIONS | null | Get current open positions |
| ORDERS | null | Get current open orders |
| ----------- | ---------------------- | ---------------------------- |
| TRADE | ORDER_TYPE_BUY | Buy market |
| TRADE | ORDER_TYPE_SELL | Sell market |
| TRADE | ORDER_TYPE_BUY_LIMIT | Buy limit |
| TRADE | ORDER_TYPE_SELL_LIMIT | Sell limit |
| TRADE | ORDER_TYPE_BUY_STOP | Buy stop |
| TRADE | ORDER_TYPE_SELL_STOP | Sell stop |
| TRADE | POSITION_MODIFY | Position modify |
| TRADE | POSITION_PARTIAL | Position close partial |
| TRADE | POSITION_ID | Position close by id |
| TRADE | POSITION_CLOSE | Position close |
| TRADE | ORDER_MODIFY | Order modify |
| TRADE | ORDER_CANCEL | Order cancel |
import zmq
class MTraderAPI:
HOST = 'localhost'
SYS_PORT = 15555 # REP/REQ port
DATA_PORT = 15556 # PUSH/PULL port
LIVE_PORT = 15557 # PUSH/PULL port
EVENTS_PORT = 15558 # PUSH/PULL port
# ZeroMQ timeout in seconds
sys_sock_tmout = 1
data_sock_tmout = 10
# initialise ZMQ context
context = zmq.Context()
# connect to server sockets
try:
sys_socket = context.socket(zmq.REQ)
sys_socket.RCVTIMEO = sys_sock_tmout * 1000
sys_socket.connect('tcp://{}:{}'.format(HOST, SYS_PORT))
data_socket = context.socket(zmq.PULL)
data_socket.RCVTIMEO = data_sock_tmout * 1000
data_socket.connect('tcp://{}:{}'.format(HOST, DATA_PORT))
live_socket = context.socket(zmq.PULL)
live_socket.connect('tcp://{}:{}'.format(HOST, LIVE_PORT))
events_socket = context.socket(zmq.PULL)
events_socket.connect('tcp://{}:{}'.format(HOST, EVENTS_PORT))
except zmq.ZMQError:
raise zmq.ZMQBindError("Binding ports ERROR")
def _send_request(self, data: dict) -> None:
""" Send request to server via ZeroMQ System socket """
try:
self.sys_socket.send_json(data)
msg = self.sys_socket.recv_string()
# terminal received the request
assert msg == 'OK', 'Something wrong on server side'
except AssertionError as err:
raise zmq.NotDone(err)
except zmq.ZMQError:
raise zmq.NotDone("Sending request ERROR")
def _pull_reply(self):
""" Get reply from server via Data socket with timeout """
try:
msg = self.data_socket.recv_json()
except zmq.ZMQError:
raise zmq.NotDone('Data socket timeout ERROR')
return msg
def live_data(self):
""" Catch live data from server """
try:
candle = self.live_socket.recv_json()
except zmq.ZMQError:
raise zmq.NotDone("Live data ERROR")
return candle
def streaming_events(self):
""" Catch events from server """
try:
candle = self.events_socket.recv_json()
except zmq.ZMQError:
raise zmq.NotDone("Streaming events ERROR")
return candle
def construct_and_send(self, **kwargs) -> dict:
""" Construct request dictionary from default """
# default dictionary
request = {
"action": None,
"actionType": None,
"symbol": None,
"chartTF": None,
"fromDate": None,
"toDate": None,
"id": None,
"magic": None,
"volume": None,
"price": None,
"stoploss": None,
"takeprofit": None,
"expiration": None,
"deviation": None,
"comment": None
}
# update dict values if exist
for key, value in kwargs.items():
if key in request:
request[key] = value
else:
raise KeyError('Unknown key in **kwargs ERROR')
# send dict to server
self._send_request(request)
# return server reply
return self._pull_reply()
License
Distributed under the GNU v3 License. See LICENSE for more information.
Languages
MQL5
98.9%
Shell
1.1%