//+------------------------------------------------------------------+
//
// Copyright (C) 2019 Nikolai Khramkov
//
// 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 the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
//+------------------------------------------------------------------+
// TODO: Deviation
#property copyright "Copyright 2019, Nikolai Khramkov."
#property link "https://github.com/khramkov"
#property version "2.00"
#property description "MQL5 JSON API"
#property description "See github link for documentation"
#include
#include
#include
#include
#include
#include
#include
// Set ports and host for ZeroMQ
string HOST="*";
int SYS_PORT=15555;
int DATA_PORT=15556;
int LIVE_PORT=15557;
int STR_PORT=15558;
// ZeroMQ Connections
Context context("MQL5 JSON API");
Socket sysSocket(context,ZMQ_REP);
Socket dataSocket(context,ZMQ_PUSH);
Socket liveSocket(context,ZMQ_PUSH);
Socket streamSocket(context,ZMQ_PUSH);
// Load MQL5-JSON-API includes
// Required:
#include
#include
// Optional:
#include
#include
// Global variables \\
bool debug = false;
bool liveStream = true;
bool connectedFlag = true;
int deInitReason = -1;
double chartAttached = ChartID(); // Chart id where the expert is attached to
// Variables for handling price data stream
struct SymbolSubscription
{
string symbol;
string chartTf;
datetime lastBar;
};
SymbolSubscription symbolSubscriptions[];
int symbolSubscriptionCount = 0;
// Error handling
ControlErrors mControl;
//+------------------------------------------------------------------+
//| Bind ZMQ sockets to ports |
//+------------------------------------------------------------------+
bool BindSockets()
{
sysSocket.setLinger(1000);
dataSocket.setLinger(1000);
liveSocket.setLinger(1000);
streamSocket.setLinger(1000);
#ifdef START_INDICATOR
indicatorDataSocket.setLinger(1000);
#endif
#ifdef CHART_CONTROL
chartDataSocket.setLinger(1000);
chartIndicatorDataSocket.setLinger(1000);
#endif
// Number of messages to buffer in RAM.
sysSocket.setSendHighWaterMark(1000);
dataSocket.setSendHighWaterMark(1000);
liveSocket.setSendHighWaterMark(1000);
streamSocket.setSendHighWaterMark(1000);
#ifdef START_INDICATOR
indicatorDataSocket.setSendHighWaterMark(1000);
#endif
#ifdef CHART_CONTROL
chartDataSocket.setReceiveHighWaterMark(1000); // TODO confirm settings
chartIndicatorDataSocket.setReceiveHighWaterMark(1000);
#endif
bool result = false;
result = sysSocket.bind(StringFormat("tcp://%s:%d", HOST,SYS_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'System' socket on port ", SYS_PORT);
}
result = dataSocket.bind(StringFormat("tcp://%s:%d", HOST,DATA_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'Data' socket on port ", DATA_PORT);
}
result = liveSocket.bind(StringFormat("tcp://%s:%d", HOST,LIVE_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'Live' socket on port ", LIVE_PORT);
}
result = streamSocket.bind(StringFormat("tcp://%s:%d", HOST,STR_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'Streaming' socket on port ", STR_PORT);
}
#ifdef START_INDICATOR
result = indicatorDataSocket.bind(StringFormat("tcp://%s:%d", HOST,INDICATOR_DATA_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'Indicator Data' socket on port ", INDICATOR_DATA_PORT);
}
#endif
#ifdef CHART_CONTROL
result = chartDataSocket.bind(StringFormat("tcp://%s:%d", HOST,CHART_DATA_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'Chart Data' socket on port ", CHART_DATA_PORT);
}
result = chartIndicatorDataSocket.bind(StringFormat("tcp://%s:%d", HOST,CHART_INDICATOR_DATA_PORT));
if(result == false)
{
return result;
}
else
{
Print("Bound 'JsonAPIIndicator Data' socket on port ", CHART_INDICATOR_DATA_PORT);
}
#endif
return result;
}
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Setting up error reporting
mControl.SetAlert(true);
mControl.SetSound(false);
mControl.SetWriteFlag(false);
/* Bindinig ZMQ ports on init */
// Skip reloading of the EA script when the reason to reload is a chart timeframe change
if(deInitReason != REASON_CHARTCHANGE)
{
EventSetMillisecondTimer(1);
int bindSocketsDelay = 65; // Seconds to wait if binding of sockets fails.
int bindAttemtps = 2; // Number of binding attemtps
Print("Binding sockets...");
for(int i=0; i0)
{
// Pull request to RequestHandler().
RequestHandler(request);
}
#ifdef CHART_CONTROL
// Publish indicator values for the JsonAPIIndicator indicator
ZmqMsg chartMsg;
chartDataSocket.recv(chartMsg, true);
if(chartMsg.size()>0)
{
double values[];
// Ensure that all indicators have finished intitailisation
for(int i=0; i