From 3b85a93e979a7e256a670c3039e1a227997df6e9 Mon Sep 17 00:00:00 2001 From: Gunther Schulz Date: Sun, 8 Nov 2020 13:26:22 +0100 Subject: [PATCH] add support for indicator short name apply styler shortened indicator refresh. indicators draw much faster now --- Experts/JsonAPI.mq5 | 3436 +++++++++++++++++-------------- Indicators/JsonAPIIndicator.mq5 | 414 ++-- 2 files changed, 2175 insertions(+), 1675 deletions(-) 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(); } //+----------------------------------------------------