diff --git a/Experts/JsonAPI.mq5 b/Experts/JsonAPI.mq5
index bc1576c..fec1d70 100644
--- a/Experts/JsonAPI.mq5
+++ b/Experts/JsonAPI.mq5
@@ -1,1515 +1,1921 @@
-//+------------------------------------------------------------------+
-//
-// 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;
-int INDICATOR_DATA_PORT=15559;
-int CHART_DATA_PORT=15560;
-int CHART_INDICATOR_DATA_PORT=15562;
-
-// ZeroMQ Cnnections
-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);
-Socket indicatorDataSocket(context,ZMQ_PUSH);
-Socket chartDataSocket(context,ZMQ_PULL);
-Socket chartIndicatorDataSocket(context,ZMQ_PUB);
-
-// 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;
-
-// Variables for controlling indicators
-struct Indicator {
- long id; // Internal id
- string indicatorId; // UUID
- int indicatorHandle; // Internal id/handle
- int indicatorParamCount; // Number of parameters to be passed to the indicator
- int indicatorBufferCount; // Numnber of buffers to be returned bythe indicator
-};
-Indicator indicators[];
-int indicatorCount = 0;
-
-// Variables for controlling chart
-struct ChartWindow {
- long id; // Internal id
- string chartId; // UUID
-};
-ChartWindow chartWindows[];
-int chartWindowCount = 0;
-
-struct ChartWindowIndicator {
- long id; // Internal id
- string indicatorId; // UUID
- int indicatorHandle; // Internal id/handle
-};
-
-ChartWindowIndicator chartWindowIndicators[];
-int chartWindowIndicatorCount = 0;
-
-// Refresh chart window interval for JsonAPIIndicator
-int chartWindowTimerInterval = 100; // Cycles of the globally set EventSetMillisecondTimer interval
-int chartWindowTimerCounter = 0; // Keeps track of the current cycle
-
-// Error handling
-ControlErrors mControl;
-
-//+------------------------------------------------------------------+
-//| Bind ZMQ sockets to ports |
-//+------------------------------------------------------------------+
-bool BindSockets(){
- 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);}
- 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);}
- 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);}
-
- sysSocket.setLinger(1000);
- dataSocket.setLinger(1000);
- liveSocket.setLinger(1000);
- streamSocket.setLinger(1000);
- indicatorDataSocket.setLinger(1000);
- chartDataSocket.setLinger(1000);
- chartIndicatorDataSocket.setLinger(1000);
-
- // Number of messages to buffer in RAM.
- sysSocket.setSendHighWaterMark(1);
- dataSocket.setSendHighWaterMark(5);
- liveSocket.setSendHighWaterMark(1);
- streamSocket.setSendHighWaterMark(50);
- indicatorDataSocket.setSendHighWaterMark(5);
- chartDataSocket.setReceiveHighWaterMark(1); // TODO confirm settings
- chartIndicatorDataSocket.setReceiveHighWaterMark(1);
-
- 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);
- }
-
- // 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= chartWindowTimerInterval) {
- for(int i=0;i= 0) {
- if(CopyBuffer(indicators[idx].indicatorHandle, i, fromDate, 1, values) < 0) {
- if(mControl.mGetLastError())
- {
- CJAVal message;
- int lastError = mControl.mGetLastError();
- string desc = mControl.mGetDesc();
- mControl.Check();
-
- message["error"]=(bool) true;
- message["lastError"]=(string) lastError;
- message["description"]=desc;
- message["function"]=(string) __FUNCTION__;
- string t=message.Serialize();
- if(debug) Print(t);
- InformClientSocket(indicatorDataSocket,t);
- }
- }
- results[i] = DoubleToString(values[0]);
- }
- }
-
- CJAVal message;
- message["error"]=(bool) false;
- message["id"] = (string) id;
- message["data"].Set(results);
-
- string t=message.Serialize();
- if(debug) Print(t);
- InformClientSocket(indicatorDataSocket,t);
-
-}
-
-//+------------------------------------------------------------------+
-//| Open new chart or add indicator to chart |
-//+------------------------------------------------------------------+
-
-void ChartControl(CJAVal &dataObject){
-
- string actionType=dataObject["actionType"].ToStr();
-
- if(actionType=="ADDINDICATOR") {
- AddChartIndicator(dataObject);
- }
- else if(actionType=="OPEN") {
- OpenChart(dataObject);
- }
-}
-
-//+------------------------------------------------------------------+
-//| Open new chart |
-//+------------------------------------------------------------------+
-void OpenChart(CJAVal &dataObject){
-
- string chartId=dataObject["chartId"].ToStr();
- string symbol=dataObject["symbol"].ToStr();
- string chartTF=dataObject["chartTF"].ToStr();
-
- chartWindowCount++;
- ArrayResize(chartWindows,chartWindowCount);
-
- int idx = chartWindowCount-1;
-
- chartWindows[idx].chartId = chartId;
-
- ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
- chartWindows[idx].id = ChartOpen(symbol, period);
- ChartSetInteger(chartWindows[idx].id, CHART_AUTOSCROLL, false);
-
- CJAVal message;
- message["error"]=(bool) false;
- message["chartId"] = (string) chartId;
-
- string t=message.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
-}
-
-//+------------------------------------------------------------------+
-//| Add JsonAPIIndicator indicator to chart |
-//+------------------------------------------------------------------+
-void AddChartIndicator(CJAVal &dataObject){
-
- string chartIdStr=dataObject["chartId"].ToStr();
- string chartIndicatorId=dataObject["indicatorChartId"].ToStr();
- int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt();
- //string shortname = dataObject["style"]["shortname"].ToStr();
-
- int chartIdx = GetChartWindowIdxByChartWindowId(chartIdStr);
- long ChartId = chartWindows[chartIdx].id;
-
- double chartIndicatorHandle = iCustom(ChartSymbol(ChartId),ChartPeriod(ChartId),"JsonAPIIndicator",chartIndicatorId,"JsonAPI"); //linelabel,colorstyle,linetype,linestyle,linewidth);
-
- if(ChartIndicatorAdd(ChartId, chartIndicatorSubWindow, chartIndicatorHandle)) {
- chartWindowIndicatorCount++;
- ArrayResize(chartWindowIndicators,chartWindowIndicatorCount);
- int indicatorIdx = chartWindowIndicatorCount-1;
- chartWindowIndicators[indicatorIdx].indicatorId = chartIndicatorId;
- chartWindowIndicators[indicatorIdx].indicatorHandle = chartIndicatorHandle;
- }
- if(!CheckError(__FUNCTION__)) {
- CJAVal message;
- message["error"]=(bool) false;
- message["chartId"] = (string) chartIdStr;
-
- string t=message.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
- }
-}
-
-//+------------------------------------------------------------------+
-//| Account information |
-//+------------------------------------------------------------------+
-void GetAccountInfo(){
-
- CJAVal info;
-
- info["error"] = false;
- info["broker"] = AccountInfoString(ACCOUNT_COMPANY);
- info["currency"] = AccountInfoString(ACCOUNT_CURRENCY);
- info["server"] = AccountInfoString(ACCOUNT_SERVER);
- info["trading_allowed"] = TerminalInfoInteger(TERMINAL_TRADE_ALLOWED);
- info["bot_trading"] = AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
- info["balance"] = AccountInfoDouble(ACCOUNT_BALANCE);
- info["equity"] = AccountInfoDouble(ACCOUNT_EQUITY);
- info["margin"] = AccountInfoDouble(ACCOUNT_MARGIN);
- info["margin_free"] = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
- info["margin_level"] = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
-
- string t=info.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
-}
-
-//+------------------------------------------------------------------+
-//| Balance information |
-//+------------------------------------------------------------------+
-void GetBalanceInfo(){
-
- CJAVal info;
- info["balance"] = AccountInfoDouble(ACCOUNT_BALANCE);
- info["equity"] = AccountInfoDouble(ACCOUNT_EQUITY);
- info["margin"] = AccountInfoDouble(ACCOUNT_MARGIN);
- info["margin_free"] = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
-
- string t=info.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
-}
-
-//+------------------------------------------------------------------+
-//| Push historical data to ZMQ socket |
-//+------------------------------------------------------------------+
-bool PushHistoricalData(CJAVal &data){
- string t=data.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
- return true;
-}
-
-//+------------------------------------------------------------------+
-//| Get historical data |
-//+------------------------------------------------------------------+
-void HistoryInfo(CJAVal &dataObject){
-
- string actionType = dataObject["actionType"].ToStr();
- string chartTF = dataObject["chartTF"].ToStr();
- string symbol=dataObject["symbol"].ToStr();
-
- // Write CVS fle to local directory
- if(actionType=="WRITE" && chartTF=="TICK"){
-
- CJAVal data, d, msg;
- MqlTick tickArray[];
- string fileName=symbol + "-" + chartTF + ".csv"; // file name
- string directoryName="Data"; // directory name
- string outputFile=directoryName+"\\"+fileName;
-
- ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
- datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
- datetime toDate=TimeCurrent();
- if(dataObject["toDate"].ToInt()!=NULL) toDate=(datetime)dataObject["toDate"].ToInt();
-
- Print("Fetching HISTORY");
- Print("1) Symbol: "+symbol);
- Print("2) Timeframe: Ticks");
- Print("3) Date from: "+TimeToString(fromDate));
- if(dataObject["toDate"].ToInt()!=NULL)Print("4) Date to:"+TimeToString(toDate));
-
- int tickCount = 0;
- ulong fromDateM = StringToTime(fromDate);
- ulong toDateM = StringToTime(toDate);
-
- tickCount=CopyTicksRange(symbol,tickArray,COPY_TICKS_ALL,1000*(ulong)fromDateM,1000*(ulong)toDateM);
- if(tickCount < 0) {
- mControl.mSetUserError(65541, GetErrorID(65541));
- }
- CheckError(__FUNCTION__);
-
- Print("Preparing data of ", tickCount, " ticks for ", symbol);
- int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV);
- if(file_handle!=INVALID_HANDLE){
- msg["status"] = (string) "CONNECTED";
- msg["type"] = (string) "NORMAL";
- msg["data"] = (string) StringFormat("Writing to: %s\\%s", TerminalInfoString(TERMINAL_DATA_PATH), outputFile);
- if(liveStream) InformClientSocket(liveSocket, msg.Serialize());
- ActionDoneOrError(ERR_SUCCESS , __FUNCTION__, "ERR_SUCCESS");
- //ActionDoneOrError(ERR_SUCCESS , __FUNCTION__, dataSocket);
- // Inform client that file is avalable for writing
-
- PrintFormat("%s file is available for writing",fileName);
- PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
- //--- write the time and values of signals to the file
- for(int i=0;i0) {
- tradeInfo.Ticket(ticket);
- data["ticket"]=(long) tradeInfo.Ticket();
- data["time"]=(long) tradeInfo.Time();
- data["price"]=(double) tradeInfo.Price();
- data["volume"]=(double) tradeInfo.Volume();
- data["symbol"]=(string) tradeInfo.Symbol();
- data["type"]=(string) tradeInfo.TypeDescription();
- data["entry"]=(long) tradeInfo.Entry();
- data["profit"]=(double) tradeInfo.Profit();
-
- trades["trades"].Add(data);
- }
- }
- }
- else {trades["trades"].Add(data);}
-
- string t=trades.Serialize();
- if(debug) Print(t);
- InformClientSocket(dataSocket,t);
- }
- else {
- mControl.mSetUserError(65538, GetErrorID(65538));
- CheckError(__FUNCTION__);
- }
-}
-
-//+------------------------------------------------------------------+
-//| Fetch positions information |
-//+------------------------------------------------------------------+
-void GetPositions(CJAVal &dataObject){
- CPositionInfo myposition;
- CJAVal data, position;
-
- // Get positions
- int positionsTotal=PositionsTotal();
- // Create empty array if no positions
- if(!positionsTotal) data["positions"].Add(position);
- // Go through positions in a loop
- for(int i=0;i.
+//
+//+------------------------------------------------------------------+
+
+// 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;
+int INDICATOR_DATA_PORT=15559;
+int CHART_DATA_PORT=15560;
+int CHART_INDICATOR_DATA_PORT=15562;
+
+// ZeroMQ Cnnections
+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);
+Socket indicatorDataSocket(context,ZMQ_PUSH);
+Socket chartDataSocket(context,ZMQ_PULL);
+Socket chartIndicatorDataSocket(context,ZMQ_PUB);
+
+// 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;
+
+// Variables for controlling indicators
+struct Indicator
+ {
+ long id; // Internal id
+ string indicatorId; // UUID
+ int indicatorHandle; // Internal id/handle
+ int indicatorParamCount; // Number of parameters to be passed to the indicator
+ int indicatorBufferCount; // Numnber of buffers to be returned bythe indicator
+ };
+Indicator indicators[];
+int indicatorCount = 0;
+
+// Variables for controlling chart
+struct ChartWindow
+ {
+ long id; // Internal id
+ string chartId; // UUID
+ };
+ChartWindow chartWindows[];
+int chartWindowCount = 0;
+
+struct ChartWindowIndicator
+ {
+ long id; // Internal id
+ string indicatorId; // UUID
+ int indicatorHandle; // Internal id/handle
+ };
+
+ChartWindowIndicator chartWindowIndicators[];
+int chartWindowIndicatorCount = 0;
+
+// Refresh chart window interval for JsonAPIIndicator
+int chartWindowTimerInterval = 1; // Cycles of the globally set EventSetMillisecondTimer interval
+int chartWindowTimerCounter = 0; // Keeps track of the current cycle
+
+// Error handling
+ControlErrors mControl;
+
+//+------------------------------------------------------------------+
+//| Bind ZMQ sockets to ports |
+//+------------------------------------------------------------------+
+bool BindSockets()
+ {
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+
+ sysSocket.setLinger(1000);
+ dataSocket.setLinger(1000);
+ liveSocket.setLinger(1000);
+ streamSocket.setLinger(1000);
+ indicatorDataSocket.setLinger(1000);
+ chartDataSocket.setLinger(1000);
+ chartIndicatorDataSocket.setLinger(1000);
+
+// Number of messages to buffer in RAM.
+ sysSocket.setSendHighWaterMark(1);
+ dataSocket.setSendHighWaterMark(5);
+ liveSocket.setSendHighWaterMark(1);
+ streamSocket.setSendHighWaterMark(50);
+ indicatorDataSocket.setSendHighWaterMark(5);
+ chartDataSocket.setReceiveHighWaterMark(1); // TODO confirm settings
+ chartIndicatorDataSocket.setReceiveHighWaterMark(1);
+
+ 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);
+ }
+
+// 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= chartWindowTimerInterval)
+ {
+ for(int i=0; i= 0)
+ {
+ if(CopyBuffer(indicators[idx].indicatorHandle, i, fromDate, 1, values) < 0)
+ {
+ if(mControl.mGetLastError())
+ {
+ CJAVal message;
+ int lastError = mControl.mGetLastError();
+ string desc = mControl.mGetDesc();
+ mControl.Check();
+
+ message["error"]=(bool) true;
+ message["lastError"]=(string) lastError;
+ message["description"]=desc;
+ message["function"]=(string) __FUNCTION__;
+ string t=message.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(indicatorDataSocket,t);
+ }
+ }
+ results[i] = DoubleToString(values[0]);
+ }
+ }
+
+ CJAVal message;
+ message["error"]=(bool) false;
+ message["id"] = (string) id;
+ message["data"].Set(results);
+
+ string t=message.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(indicatorDataSocket,t);
+
+ }
+
+//+------------------------------------------------------------------+
+//| Open new chart or add indicator to chart |
+//+------------------------------------------------------------------+
+
+//+------------------------------------------------------------------+
+//| |
+//+------------------------------------------------------------------+
+void ChartControl(CJAVal &dataObject)
+ {
+
+ string actionType=dataObject["actionType"].ToStr();
+
+ if(actionType=="ADDINDICATOR")
+ {
+ AddChartIndicator(dataObject);
+ }
+ else
+ if(actionType=="OPEN")
+ {
+ OpenChart(dataObject);
+ }
+ }
+
+//+------------------------------------------------------------------+
+//| Open new chart |
+//+------------------------------------------------------------------+
+void OpenChart(CJAVal &dataObject)
+ {
+
+ string chartId=dataObject["chartId"].ToStr();
+ string symbol=dataObject["symbol"].ToStr();
+ string chartTF=dataObject["chartTF"].ToStr();
+
+ chartWindowCount++;
+ ArrayResize(chartWindows,chartWindowCount);
+
+ int idx = chartWindowCount-1;
+
+ chartWindows[idx].chartId = chartId;
+
+ ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
+ chartWindows[idx].id = ChartOpen(symbol, period);
+ ChartSetInteger(chartWindows[idx].id, CHART_AUTOSCROLL, false);
+
+ CJAVal message;
+ message["error"]=(bool) false;
+ message["chartId"] = (string) chartId;
+
+ string t=message.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ }
+
+//+------------------------------------------------------------------+
+//| Add JsonAPIIndicator indicator to chart |
+//+------------------------------------------------------------------+
+void AddChartIndicator(CJAVal &dataObject)
+ {
+
+ string chartIdStr=dataObject["chartId"].ToStr();
+ string chartIndicatorId=dataObject["indicatorChartId"].ToStr();
+ int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt();
+ string shortName = dataObject["shortName"].ToStr();
+
+ int chartIdx = GetChartWindowIdxByChartWindowId(chartIdStr);
+ long ChartId = chartWindows[chartIdx].id;
+
+ double chartIndicatorHandle = iCustom(ChartSymbol(ChartId),ChartPeriod(ChartId),"JsonAPIIndicator",chartIndicatorId,shortName); //linelabel,colorstyle,linetype,linestyle,linewidth);
+
+ if(ChartIndicatorAdd(ChartId, chartIndicatorSubWindow, chartIndicatorHandle))
+ {
+ chartWindowIndicatorCount++;
+ ArrayResize(chartWindowIndicators,chartWindowIndicatorCount);
+ int indicatorIdx = chartWindowIndicatorCount-1;
+ chartWindowIndicators[indicatorIdx].indicatorId = chartIndicatorId;
+ chartWindowIndicators[indicatorIdx].indicatorHandle = chartIndicatorHandle;
+ }
+ if(!CheckError(__FUNCTION__))
+ {
+ CJAVal message;
+ message["error"]=(bool) false;
+ message["chartId"] = (string) chartIdStr;
+
+ string t=message.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ }
+ }
+
+//+------------------------------------------------------------------+
+//| Account information |
+//+------------------------------------------------------------------+
+void GetAccountInfo()
+ {
+
+ CJAVal info;
+
+ info["error"] = false;
+ info["broker"] = AccountInfoString(ACCOUNT_COMPANY);
+ info["currency"] = AccountInfoString(ACCOUNT_CURRENCY);
+ info["server"] = AccountInfoString(ACCOUNT_SERVER);
+ info["trading_allowed"] = TerminalInfoInteger(TERMINAL_TRADE_ALLOWED);
+ info["bot_trading"] = AccountInfoInteger(ACCOUNT_TRADE_EXPERT);
+ info["balance"] = AccountInfoDouble(ACCOUNT_BALANCE);
+ info["equity"] = AccountInfoDouble(ACCOUNT_EQUITY);
+ info["margin"] = AccountInfoDouble(ACCOUNT_MARGIN);
+ info["margin_free"] = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
+ info["margin_level"] = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
+
+ string t=info.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ }
+
+//+------------------------------------------------------------------+
+//| Balance information |
+//+------------------------------------------------------------------+
+void GetBalanceInfo()
+ {
+
+ CJAVal info;
+ info["balance"] = AccountInfoDouble(ACCOUNT_BALANCE);
+ info["equity"] = AccountInfoDouble(ACCOUNT_EQUITY);
+ info["margin"] = AccountInfoDouble(ACCOUNT_MARGIN);
+ info["margin_free"] = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
+
+ string t=info.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ }
+
+//+------------------------------------------------------------------+
+//| Push historical data to ZMQ socket |
+//+------------------------------------------------------------------+
+bool PushHistoricalData(CJAVal &data)
+ {
+ string t=data.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ return true;
+ }
+
+//+------------------------------------------------------------------+
+//| Get historical data |
+//+------------------------------------------------------------------+
+void HistoryInfo(CJAVal &dataObject)
+ {
+
+ string actionType = dataObject["actionType"].ToStr();
+ string chartTF = dataObject["chartTF"].ToStr();
+ string symbol=dataObject["symbol"].ToStr();
+
+// Write CVS fle to local directory
+ if(actionType=="WRITE" && chartTF=="TICK")
+ {
+
+ CJAVal data, d, msg;
+ MqlTick tickArray[];
+ string fileName=symbol + "-" + chartTF + ".csv"; // file name
+ string directoryName="Data"; // directory name
+ string outputFile=directoryName+"\\"+fileName;
+
+ ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
+ datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
+ datetime toDate=TimeCurrent();
+ if(dataObject["toDate"].ToInt()!=NULL)
+ toDate=(datetime)dataObject["toDate"].ToInt();
+
+ Print("Fetching HISTORY");
+ Print("1) Symbol: "+symbol);
+ Print("2) Timeframe: Ticks");
+ Print("3) Date from: "+TimeToString(fromDate));
+ if(dataObject["toDate"].ToInt()!=NULL)
+ Print("4) Date to:"+TimeToString(toDate));
+
+ int tickCount = 0;
+ ulong fromDateM = StringToTime(fromDate);
+ ulong toDateM = StringToTime(toDate);
+
+ tickCount=CopyTicksRange(symbol,tickArray,COPY_TICKS_ALL,1000*(ulong)fromDateM,1000*(ulong)toDateM);
+ if(tickCount < 0)
+ {
+ mControl.mSetUserError(65541, GetErrorID(65541));
+ }
+ CheckError(__FUNCTION__);
+
+ Print("Preparing data of ", tickCount, " ticks for ", symbol);
+ int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV);
+ if(file_handle!=INVALID_HANDLE)
+ {
+ msg["status"] = (string) "CONNECTED";
+ msg["type"] = (string) "NORMAL";
+ msg["data"] = (string) StringFormat("Writing to: %s\\%s", TerminalInfoString(TERMINAL_DATA_PATH), outputFile);
+ if(liveStream)
+ InformClientSocket(liveSocket, msg.Serialize());
+ ActionDoneOrError(ERR_SUCCESS, __FUNCTION__, "ERR_SUCCESS");
+ //ActionDoneOrError(ERR_SUCCESS , __FUNCTION__, dataSocket);
+ // Inform client that file is avalable for writing
+
+ PrintFormat("%s file is available for writing",fileName);
+ PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
+ //--- write the time and values of signals to the file
+ for(int i=0; i0)
+ {
+ tradeInfo.Ticket(ticket);
+ data["ticket"]=(long) tradeInfo.Ticket();
+ data["time"]=(long) tradeInfo.Time();
+ data["price"]=(double) tradeInfo.Price();
+ data["volume"]=(double) tradeInfo.Volume();
+ data["symbol"]=(string) tradeInfo.Symbol();
+ data["type"]=(string) tradeInfo.TypeDescription();
+ data["entry"]=(long) tradeInfo.Entry();
+ data["profit"]=(double) tradeInfo.Profit();
+
+ trades["trades"].Add(data);
+ }
+ }
+ }
+ else
+ {
+ trades["trades"].Add(data);
+ }
+
+ string t=trades.Serialize();
+ if(debug)
+ Print(t);
+ InformClientSocket(dataSocket,t);
+ }
+ else
+ {
+ mControl.mSetUserError(65538, GetErrorID(65538));
+ CheckError(__FUNCTION__);
+ }
+ }
+
+//+------------------------------------------------------------------+
+//| Fetch positions information |
+//+------------------------------------------------------------------+
+void GetPositions(CJAVal &dataObject)
+ {
+ CPositionInfo myposition;
+ CJAVal data, position;
+
+// Get positions
+ int positionsTotal=PositionsTotal();
+// Create empty array if no positions
+ if(!positionsTotal)
+ data["positions"].Add(position);
+// Go through positions in a loop
+ for(int i=0; iprev_calculated){
- B0[0] = EMPTY_VALUE;
- B1[0] = EMPTY_VALUE;
- B2[0] = EMPTY_VALUE;
- B3[0] = EMPTY_VALUE;
- B4[0] = EMPTY_VALUE;
- B5[0] = EMPTY_VALUE;
- B6[0] = EMPTY_VALUE;
- B7[0] = EMPTY_VALUE;
- B8[0] = EMPTY_VALUE;
- B9[0] = EMPTY_VALUE;
- B10[0] = EMPTY_VALUE;
- B11[0] = EMPTY_VALUE;
- B12[0] = EMPTY_VALUE;
- B13[0] = EMPTY_VALUE;
- B14[0] = EMPTY_VALUE;
- B15[0] = EMPTY_VALUE;
- B16[0] = EMPTY_VALUE;
- B17[0] = EMPTY_VALUE;
- B18[0] = EMPTY_VALUE;
- B19[0] = EMPTY_VALUE;
- }
- if(first==false) alive[0] = 1;
- // ChartRedraw(0);
-
+// While a new candle is forming, set the current value to be empty
+ if(rates_total>prev_calculated)
+ {
+ B0[0] = EMPTY_VALUE;
+ B1[0] = EMPTY_VALUE;
+ B2[0] = EMPTY_VALUE;
+ B3[0] = EMPTY_VALUE;
+ B4[0] = EMPTY_VALUE;
+ B5[0] = EMPTY_VALUE;
+ B6[0] = EMPTY_VALUE;
+ B7[0] = EMPTY_VALUE;
+ B8[0] = EMPTY_VALUE;
+ B9[0] = EMPTY_VALUE;
+ B10[0] = EMPTY_VALUE;
+ B11[0] = EMPTY_VALUE;
+ B12[0] = EMPTY_VALUE;
+ B13[0] = EMPTY_VALUE;
+ B14[0] = EMPTY_VALUE;
+ B15[0] = EMPTY_VALUE;
+ B16[0] = EMPTY_VALUE;
+ B17[0] = EMPTY_VALUE;
+ B18[0] = EMPTY_VALUE;
+ B19[0] = EMPTY_VALUE;
+ B20[0] = EMPTY_VALUE;
+ B21[0] = EMPTY_VALUE;
+ B22[0] = EMPTY_VALUE;
+ B23[0] = EMPTY_VALUE;
+ B24[0] = EMPTY_VALUE;
+ B25[0] = EMPTY_VALUE;
+ B26[0] = EMPTY_VALUE;
+ B27[0] = EMPTY_VALUE;
+ B28[0] = EMPTY_VALUE;
+ B29[0] = EMPTY_VALUE;
+ }
+ if(first==false)
+ alive[0] = 1;
+// ChartRedraw(0);
+
//--- return value of prev_calculated for next call
return(rates_total);
}
-void SubscriptionHandler(ZmqMsg &chartMsg){
- CJAVal message;
- // Get data from request
- string msg=chartMsg.getData();
- if(debug) Print("Processing:"+msg);
- // Deserialize msg to CJAVal array
- if(!message.Deserialize(msg)){
- Alert("Deserialization Error");
- ExpertRemove();
- }
- if(message["indicatorChartId"]==IndicatorId) {
+//+------------------------------------------------------------------+
+//| |
+//+------------------------------------------------------------------+
+void SubscriptionHandler(ZmqMsg &chartMsg)
+ {
+ CJAVal message;
+// Get data from request
+ string msg=chartMsg.getData();
+ if(debug)
+ Print("Processing:"+msg);
+// Deserialize msg to CJAVal array
+ if(!message.Deserialize(msg))
+ {
+ Alert("Deserialization Error");
+ ExpertRemove();
+ }
+ if(message["indicatorChartId"]==IndicatorId)
+ {
- if(message["action"]=="PLOT" && message["actionType"]=="DATA") {
- int bufferIdx = message["indicatorBufferId"].ToInt();
- if (bufferIdx == 0) WriteToBuffer(message, B0);
- if (bufferIdx == 1) WriteToBuffer(message, B1);
- if (bufferIdx == 2) WriteToBuffer(message, B2);
- if (bufferIdx == 3) WriteToBuffer(message, B3);
- if (bufferIdx == 4) WriteToBuffer(message, B4);
- if (bufferIdx == 5) WriteToBuffer(message, B5);
- if (bufferIdx == 6) WriteToBuffer(message, B6);
- if (bufferIdx == 7) WriteToBuffer(message, B7);
- if (bufferIdx == 8) WriteToBuffer(message, B8);
- if (bufferIdx == 9) WriteToBuffer(message, B9);
- if (bufferIdx == 10) WriteToBuffer(message, B10);
- if (bufferIdx == 11) WriteToBuffer(message, B11);
- if (bufferIdx == 12) WriteToBuffer(message, B12);
- if (bufferIdx == 13) WriteToBuffer(message, B13);
- if (bufferIdx == 14) WriteToBuffer(message, B14);
- if (bufferIdx == 15) WriteToBuffer(message, B15);
- if (bufferIdx == 16) WriteToBuffer(message, B16);
- if (bufferIdx == 17) WriteToBuffer(message, B17);
- if (bufferIdx == 18) WriteToBuffer(message, B18);
- if (bufferIdx == 19) WriteToBuffer(message, B19);
- }
- else if(message["action"]=="PLOT" && message["actionType"]=="ADDBUFFER") {
- string linelabel = message["style"]["linelabel"].ToStr();
- string colorstyleStr = message["style"]["color"].ToStr();
- string linetypeStr = message["style"]["linetype"].ToStr();
- string linestyleStr = message["style"]["linestyle"].ToStr();
- int linewidth = message["style"]["linewidth"].ToInt();
-
- color colorstyle = StringToColor(colorstyleStr);
- int linetype = StringToEnumInt(linetypeStr);
- int linestyle = StringToEnumInt(linestyleStr);
-
- /*
- //if (aa == false) {
- Print("SETBUFF ActCount ",activeBufferCount);
- if (activeBufferCount == 0) {SetIndexBuffer(0,B1,INDICATOR_DATA);} // Two semicolons ar required! No idea why. Seems to be a timing problem, better to keep it in init()
-
- if (activeBufferCount == 1) {SetIndexBuffer(1,B2,INDICATOR_DATA);;}
- if (activeBufferCount == 2) {SetIndexBuffer(2,B3,INDICATOR_DATA);;}
- if (activeBufferCount == 3) {SetIndexBuffer(3,B4,INDICATOR_DATA);;}
- if (activeBufferCount == 4) {SetIndexBuffer(4,B5,INDICATOR_DATA);;}
+ if(message["action"]=="PLOT" && message["actionType"]=="DATA")
+ {
+ int bufferIdx = message["indicatorBufferId"].ToInt();
+ if(bufferIdx == 0)
+ WriteToBuffer(message, B0);
+ if(bufferIdx == 1)
+ WriteToBuffer(message, B1);
+ if(bufferIdx == 2)
+ WriteToBuffer(message, B2);
+ if(bufferIdx == 3)
+ WriteToBuffer(message, B3);
+ if(bufferIdx == 4)
+ WriteToBuffer(message, B4);
+ if(bufferIdx == 5)
+ WriteToBuffer(message, B5);
+ if(bufferIdx == 6)
+ WriteToBuffer(message, B6);
+ if(bufferIdx == 7)
+ WriteToBuffer(message, B7);
+ if(bufferIdx == 8)
+ WriteToBuffer(message, B8);
+ if(bufferIdx == 9)
+ WriteToBuffer(message, B9);
+ if(bufferIdx == 10)
+ WriteToBuffer(message, B10);
+ if(bufferIdx == 11)
+ WriteToBuffer(message, B11);
+ if(bufferIdx == 12)
+ WriteToBuffer(message, B12);
+ if(bufferIdx == 13)
+ WriteToBuffer(message, B13);
+ if(bufferIdx == 14)
+ WriteToBuffer(message, B14);
+ if(bufferIdx == 15)
+ WriteToBuffer(message, B15);
+ if(bufferIdx == 16)
+ WriteToBuffer(message, B16);
+ if(bufferIdx == 17)
+ WriteToBuffer(message, B17);
+ if(bufferIdx == 18)
+ WriteToBuffer(message, B18);
+ if(bufferIdx == 19)
+ WriteToBuffer(message, B19);
+ if(bufferIdx == 20)
+ WriteToBuffer(message, B20);
+ if(bufferIdx == 21)
+ WriteToBuffer(message, B21);
+ if(bufferIdx == 22)
+ WriteToBuffer(message, B22);
+ if(bufferIdx == 23)
+ WriteToBuffer(message, B23);
+ if(bufferIdx == 24)
+ WriteToBuffer(message, B24);
+ if(bufferIdx == 25)
+ WriteToBuffer(message, B25);
+ if(bufferIdx == 26)
+ WriteToBuffer(message, B26);
+ if(bufferIdx == 27)
+ WriteToBuffer(message, B27);
+ if(bufferIdx == 28)
+ WriteToBuffer(message, B28);
+ if(bufferIdx == 29)
+ WriteToBuffer(message, B29);
+ }
+ else
+ if(message["action"]=="PLOT" && message["actionType"]=="ADDBUFFER")
+ {
+ string linelabel = message["style"]["linelabel"].ToStr();
+ string colorstyleStr = message["style"]["color"].ToStr();
+ string linetypeStr = message["style"]["linetype"].ToStr();
+ string linestyleStr = message["style"]["linestyle"].ToStr();
+ int linewidth = message["style"]["linewidth"].ToInt();
- //aa = true;}
- */
-
- SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
- activeBufferCount = activeBufferCount + 1;
- }
+ color colorstyle = StringToColor(colorstyleStr);
+ int linetype = StringToEnumInt(linetypeStr);
+ int linestyle = StringToEnumInt(linestyleStr);
+
+ /*
+ //if (aa == false) {
+ Print("SETBUFF ActCount ",activeBufferCount);
+ if (activeBufferCount == 0) {SetIndexBuffer(0,B1,INDICATOR_DATA);} // Two semicolons ar required! No idea why. Seems to be a timing problem, better to keep it in init()
+
+ if (activeBufferCount == 1) {SetIndexBuffer(1,B2,INDICATOR_DATA);;}
+ if (activeBufferCount == 2) {SetIndexBuffer(2,B3,INDICATOR_DATA);;}
+ if (activeBufferCount == 3) {SetIndexBuffer(3,B4,INDICATOR_DATA);;}
+ if (activeBufferCount == 4) {SetIndexBuffer(4,B5,INDICATOR_DATA);;}
+
+ //aa = true;}
+ */
+
+ SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
+ activeBufferCount = activeBufferCount + 1;
+ }
+ }
}
-}
//+------------------------------------------------------------------+
//| Update indicator buffer function |
//+------------------------------------------------------------------+
-void WriteToBuffer(CJAVal &message, double &buffer[]) {
-
- int bufferSize = ArraySize(buffer);
+void WriteToBuffer(CJAVal &message, double &buffer[])
+ {
- int messageDataSize = message["data"].Size();
- // TODO check if this is working as expected. Seems to
- if(first==false) {
- for(int i=0;i0){
- // Handle subscription SubscriptionHandler()
- SubscriptionHandler(chartMsg);
- ChartRedraw(ChartID());
+// Request recieved
+ if(chartMsg.size()>0)
+ {
+ // Handle subscription SubscriptionHandler()
+ SubscriptionHandler(chartMsg);
+ ChartRedraw(ChartID());
+ }
}
-}
//+------------------------------------------------------------------+
//| OnTimer() workaround function |
@@ -293,6 +386,7 @@ void OnChartEvent(const int id,
const double &dparam,
const string &sparam)
{
- if(id==CHARTEVENT_CUSTOM+222) CheckMessages();
+ if(id==CHARTEVENT_CUSTOM+222)
+ CheckMessages();
}
//+----------------------------------------------------