This project was developed to work as a server for the 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 programming language that has [ZeroMQ binding](http://zeromq.org/bindings:_start).
Backtrader Python client is located here: [Python Backtrader - Metaquotes MQL5 ](https://github.com/khramkov/Backtrader-MQL5-API)
- Support for multiple datastreams in parallel for any combination of symbols and timeframes independently of the timeframe and symbol of the attached chart
- Support for tick data
- Support for direct download as CSV files
- Automatic retry binding to sockets. When running under Wine in Linux, sockets will be blocked for 60 seconds if closed uncleanly. This can happen if the client is still connected while the EA gets reloaded.
- Skip re-initialization on chart timeframe change
The idea is to send requests via `System socket` and recieve results/errors via `Data socket`. Event handlers should be created for `Live socket` and `Streaming socket` because the server sends data to theese sockets automatically. See examples in [Live data and streaming events](#live-data-and-streaming-events) section.
First of all we should configure the script `symbol` and `timeframe`. Live data stream will be configured to the same params. You can use any number of `symbols` and `timeframes`. The server subscribes to these sembols and will transmit them through the `Live data` socket
Get historical data. `fromDate` should be in timestamp format. The data will be loaded to the last candle if `toDate` is `None`. Notice, that the script sends the last unclosed candle too. You should delete it manually.
There are some issues:
- MetaTrader keeps historical data in cache. But when you make a request for the first time, MetaTrader downloads the data from a broker. This operation can exceed `Data socket` timeout. It depends on your broker. Second request will be handeled quickly.
- It takes 6-7 seconds to process `50000` M1 candles. It was tested on Windows 10 in Parallels Desktop container with 4 cores and 4GB RAM. So if you need more data there are three ways to handle it. 1) Increase `Data socket` timeout. 2) You can load data partially using `fromDate` and `toDate`. 3) You can use more powerfull hardware.
All pending orders are set to `Good till cancel` by default. If you want to set an expiration date, pass the date in timestamp format to `expiration` param.
There are only two variants of `Live socket` data. When everything is ok, the script sends subscribed data on new even. You can divide streams by symbol and timeframe names:
If the terminal has lost connection to the market:
```
{"status":"DISCONNECTED"}
```
When the terminal reconnects to the market, it sends the last closed candle again. So you should update your historical data. Make the `action="HISTORY"` request with `fromDate` equal to your last candle timestamp before disconnect.
`OnTradeTransaction` function is called when a trade transaction event occurs. `Streaming socket` sends `TRADE_TRANSACTION_REQUEST` data every time it happens. Try to create and modify orders in the MQL5 terminal manually and check the expert logging tab for better understanding. Also see [MQL5 docs](https://www.mql5.com/en/docs/event_handlers/ontradetransaction).
A common scenario would be to stream vlaues calculated by the client indictor to be plotted in MT5. This is done by attaching the supplied MT5 indicator `JsonAPIIndicator` and passing values to be plotted to it.
Initialize a plot line object by attaching a new instance of `JsonAPIIndicator`, ready to recieve values to be plotted.
Parameters:
-`chartId` - id string of a previously opened chart.
-`indicatorChartId`: a unique id string to reference the new plot line object.
-`chartIndicatorSubWindow`: chart sub window to plot to (https://www.mql5.c.om/en/docs/chart_operations/chartindicatoradd)
-`style`: style settings for the plot. `shortname` and `linelabel` can be any string value. `linewidth` expects an int. All other paramters require constants supported by MQL5.
Supported are the following style paramers (with the corresponding MQL5 constants in braces): `color` (PLOT_LINE_COLOR), `linetype` (PLOT_DRAW_TYPE), `linestyle` (PLOT_LINE_STYLE).
Stream values to a plot line object (draw a line).
Parameters:
-`chartId` - id string of a previously opened chart.
-`indicatorChartId`: id string of a previously initialized plot line object.
-`data`: list of values to plot. The last value in a list (`values[-1]`) corresponds to the most recent candle. If the size of the list of values passsed is >= 1, and the number of historic candles to plot is `n` then `values[n-1]` is the most recent candle and `values[0]` is the oldest candle.
The supplied indicator `JsonAPIIndicator` does not do any calculations by itself. It simply plots
incoming data to a chart which can be passed by via JSON interface to the `Chart Data Socket`. The indicator is controlled by the expert script `JsonAPI.mq5` locally via port `15562`.
First of all, when you send a command via `System socket`, you should always receive back `"OK"` message via `System socket`. It means that your command was received and deserialized.
All data that come through `Data socket` have an `error` param. This param will have `true` key if somethng goes wrong. Also, there will be `description` and `function` params. They will hold information about error and the name of the function with error.
This information also applies to the trade commannds. See [MQL5 docs](https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes) for possible server answers.
## License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See `LICENSE` for more information.