//+------------------------------------------------------------------+ // // 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