CFDs are complex instruments and come with a high risk of losing money rapidly due to leverage. 66 % of retail investor accounts lose money when trading CFDs with this provider. You should consider whether you understand how CFDs work and whether you can afford to take the high risk of losing your money.

Python, ZeroMQ & MetaTrader – Pricing, Trading & Transaction Reporting (ZMQ Series)

Hi Community,
Our Quants team @DarwinexLabs just released a new article!

In this third installment of our ZeroMQ series, we describe how to use ZeroMQ in non-MQL trading strategies to get the following information:

  • Account Information (e.g. equity, margin, balance, etc)
  • Trades at market (live or pending)
  • Historical Trades

https://blog.darwinex.com/zeromq-transaction-reporting-metatrader-zmq3/


For ease of reference, here’s the complete step-by-step guide :slight_smile:

https://blog.darwinex.com/zeromq-trade-execution-metatrader-zmq2/
https://blog.darwinex.com/zeromq-interface-python-r-metatrader4/


An the latest @DarwinexLabs’ webinar on the topic, in case you missed it!



Happy reading!!!

9 Likes

Just fyi, so those following this know that this project is very much an active effort :slight_smile:

We’ve been working on several improvements to the Bridge above, including:

  1. Support for Python 3.6+

  2. Asynchronous price feed (MetaTrader <-> Python)

  3. Order OPEN, MODIFY, CLOSE, CLOSE PARTIAL commands between Python and MetaTrader.

  4. Minor bug fixes / optimizations in general.

The objective as always, is to enable traders using Python to greatly (if not entirely) minimize any development on the MQL front, focusing instead on trading strategy development and using MetaTrader as an execution engine only.

Will keep you posted on release dates in the new year :thumbsup:

7 Likes

Function list for the ZeroMQ (Python 3.6+) -> MetaTrader implementation has also been expanded significantly:

As always, stay tuned :muscle:

2 Likes

Getting things ready… sneak peek:

This thread will be updated once the package is completely ready.

Stay tuned :muscle:

2 Likes

Latest version 2.0.1_RC8 code, dependencies and fairly detailed README have now been uploaded to GitHub :muscle:

Feedback, ideas, suggestions for improvement and anything in between most welcome.

2 Likes

But it’s also possible backtest?

1 Like

Hi @tradingest,

The current release does not support backtesting unfortunately.

It’s primary purpose is to serve as a bridge between Python (and in future releases: C#/C++, R and Java) environments and MetaTrader 4 to enable traders to focus on strategy development outside MetaTrader and use the latter for execution and trade management only.

Further information can be found here:

1 Like

Hi Many thanks for providing this code !

A suggestion from my side: make a simple EA that shows how to work with the class in PY:
for example: a simple trend following running on the 1M timeframe

Python logic:
#init
get last 200 bars of data for EURUSD 1M
stream 1 min bar from MT4
subscribe ticks for EURUSD, to get the bid and ask and the spread
get currency info from MT4 to know how much is the point value for EURUSD & point size

on each new bar:
if no open buy order, check for entries:
if EMA20>EMA200 place a buy order
SL=3*ATR200
order size = distance (last_ask-SL)*tick_value=100 euros
place BUY limit order

if order open:
        -check if MT4 has confirmed order hit SL if not
         -if last_bid-3*ATR200 > SL => move SL, so it is a trailing stop

the objective of this simple EA is not to make money, but just to have a simple example of the whole thing working

I am trying to build one myself,

I did

from DWX_ZeroMQ_Connector_v2_0_1_RC8 import DWX_ZeroMQ_Connector
dwx_connect=DWX_ZeroMQ_Connector()
startime=(dt.datetime.now()-dt.timedelta(minutes=500)).strftime(’%Y.%m.%d %H:%M:00’)
endtime=dt.datetime.now().strftime(’%Y.%m.%d %H:%M:00’)

dwx_connect.DWX_MTX_SEND_MARKETDATA_REQUEST(“EURUSD”,1,startime,endtime) => nothing happens I think it is because it is 500 bars I am requesting…if I request 50 bars it works

then
dwx_connect.DWX_ZMQ_Poll_Data() => I guess this method should not be called from outside the class

then the kernel dies
An error ocurred while starting the kernel
Assertion failed: nbytes == sizeof (dummy) (bundled\zeromq\src\signaler.cpp:303)

to get the data from MT4 I found out I should use instead: dwx_connect._thread_data_output

so sometimes having an example would be good

I also noticed in the MQ4 code the switches have mismatched numbers:

if(compArray[0] == “DATA”)
switch_action = 9;

and the cases dont go up to 9…

case 8: // DATA REQUEST

     zmq_ret = "{";
     
     DWX_GetData(compArray, zmq_ret);
     
     InformPullClient(pSocket, zmq_ret + "}");
     
     break;
     
  default: 
     break;

}

many thanks!

2 Likes

I am a newby ot EA’s/ MT4.

I have a complicated EA that uses multiple trade sinarios , but also implements sets of trades , so if already in a trade, the EA can start another sequence of trades if conditions allow.
Problem is , I cant keep visual track of whats happening [30 trades opening and closing] . What I want to do is send information to the chart via a single indicator using zeromq as the ‘feed’. [I have tried plotting values via the EA directly to screen but cant keep track as bars change/move, and I don’t want to write an indicators for all my custom signals and confirmations as this will be a lot of work , plus the screen will be full of false signals not ready to be considered by the EA]

Example…
So I get a ready signal in my customea.ex4 , send a ready signal to zeromq , customind.ex4 reads zeromq plots the signal ‘ready’ on the bar.

Next I get a confirm signal in my customea.ex4 , send a confirm signal to zeromq , customind.ex4 reads zeromq and plots the ‘confirm’ on the bar.

Next I send an order in my customea.ex4 , send a order signal to zeromq , customind.ex4 reads zeromq and plots the ‘order arrow’ on the bar.

I seem to be able to read the zeromq via ZMQ_SUB , in the indicator code, but cant find how to make it robust. Opening the MT4 platform , it freezes , it maybe looking fro the ZMQ_PUB which isn’t started. So how do I make it robust.

Q1 Is this even possible or is there some limitation I am going to encounter like handles/memory/objects to many/robustness/delay/ etc.?

Q2 where do I put the connection command, How do I check the connection is ready/working. [I was thinking of only reading on every new bar , 1min timeframe , so do I connect/reconnect every minute? [ I need it not crash if the ZMQ_PUB stops.]

Dodgy print code below is of the indicator.mq4

//+------------------------------------------------------------------+
//| plottest.mq4 |
//| Copyright 2018, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+

property copyright "Copyright 2018, MetaQuotes Software Corp."
property link "https://www.mql5.com"
property version "1.00"
property strict
property indicator_chart_window
property indicator_buffers 1
property indicator_plots 1
//--- plot Label1

property indicator_label1 "Label1"
property indicator_type1 DRAW_LINE
property indicator_color1 clrRed
property indicator_style1 STYLE_SOLID
property indicator_width1 1
//--- indicator buffers
double Label1Buffer[];

include
Context context;
Socket subscriber(context,ZMQ_SUB);

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{

//--- indicator buffers mapping
SetIndexBuffer(0,Label1Buffer);
EventSetMillisecondTimer(10);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
//---

//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
Read0MQ1();
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---

}
//+------------------------------------------------------------------+

void Read0MQ1()
{

int rc = subscriber.connect("tcp://localhost:5556");
if (rc != -1) {
subscriber.subscribe("");

// Do 10 requests, waiting each time for a response
for(int request_nbr=0; request_nbr!=10 && !IsStopped(); request_nbr++)
{
// ZmqMsg request("Hello");
// PrintFormat("Sending Hello %d...",request_nbr);
// socket.send(request);

  // Get the reply.
  ZmqMsg update;
  subscriber.recv(update);
  string replystring=update.getData();
  if (replystring != "") {
  Print(replystring+"- Received on try no "+request_nbr);
  }
 }
}else{
//error no connection
}

subscriber.disconnect("tcp://localhost:5556");
}

Cheers
CJ

1 Like

Hi @camjo,

I’m not sure I understand your workflow - from what I understand, it appears the chart object is a conduit of some sort in your execution path.

Perhaps the following implementation may prove useful?

Hi @rickinvestor :slight_smile:

Sorry I totally missed responding to your post… this is an excellent suggestion!

Thank you - I’ll cook something up along these lines for a future publication, code + tutorial most likely :thumbsup:

1 Like

A glimpse of what’s to come :wink:

https://twitter.com/darwinexlabs/status/1103342118079217667

3 Likes