diff --git a/Experts/JsonAPI.mq5 b/Experts/JsonAPI.mq5 index 5b7af78..bc1576c 100644 --- a/Experts/JsonAPI.mq5 +++ b/Experts/JsonAPI.mq5 @@ -41,7 +41,7 @@ int LIVE_PORT=15557; int STR_PORT=15558; int INDICATOR_DATA_PORT=15559; int CHART_DATA_PORT=15560; -int CHART_INDICATOR_PORT=15562; +int CHART_INDICATOR_DATA_PORT=15562; // ZeroMQ Cnnections Context context("MQL5 JSON API"); @@ -51,7 +51,7 @@ Socket liveSocket(context,ZMQ_PUSH); Socket streamSocket(context,ZMQ_PUSH); Socket indicatorDataSocket(context,ZMQ_PUSH); Socket chartDataSocket(context,ZMQ_PULL); -Socket chartIndicatorSocket(context,ZMQ_PUB); +Socket chartIndicatorDataSocket(context,ZMQ_PUB); // Global variables \\ bool debug = false; @@ -84,12 +84,19 @@ int indicatorCount = 0; struct ChartWindow { long id; // Internal id string chartId; // UUID - string indicatorId; // UUID - int indicatorHandle; // Internal id/handle }; 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 @@ -114,8 +121,8 @@ bool BindSockets(){ 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 = chartIndicatorSocket.bind(StringFormat("tcp://%s:%d", HOST,CHART_INDICATOR_PORT)); - if (result == false) { return result; } else {Print("Bound 'JsonAPIIndicator Data' socket on port ", CHART_INDICATOR_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); @@ -123,7 +130,7 @@ bool BindSockets(){ streamSocket.setLinger(1000); indicatorDataSocket.setLinger(1000); chartDataSocket.setLinger(1000); - chartIndicatorSocket.setLinger(1000); + chartIndicatorDataSocket.setLinger(1000); // Number of messages to buffer in RAM. sysSocket.setSendHighWaterMark(1); @@ -132,7 +139,7 @@ bool BindSockets(){ streamSocket.setSendHighWaterMark(50); indicatorDataSocket.setSendHighWaterMark(5); chartDataSocket.setReceiveHighWaterMark(1); // TODO confirm settings - chartIndicatorSocket.setReceiveHighWaterMark(1); + chartIndicatorDataSocket.setReceiveHighWaterMark(1); return result; } @@ -201,7 +208,7 @@ void OnDeinit(const int reason){ Print("Unbinding 'Chart Data' socket on port ", STR_PORT, ".."); streamSocket.unbind(StringFormat("tcp://%s:%d", HOST, CHART_DATA_PORT)); Print("Unbinding 'JsonAPIIndicator Data' socket on port ", STR_PORT, ".."); - streamSocket.unbind(StringFormat("tcp://%s:%d", HOST, CHART_INDICATOR_PORT)); + streamSocket.unbind(StringFormat("tcp://%s:%d", HOST, CHART_INDICATOR_DATA_PORT)); // Shutdown ZeroMQ Context context.shutdown(); @@ -256,6 +263,21 @@ int GetChartWindowIdxByChartWindowId(string chartWindowId) return -1; } +//+------------------------------------------------------------------+ +//| Get index of chart indicator handler array by indicator id string | +//+------------------------------------------------------------------+ +int GetChartIndicatorIdxByChartIndicatorId(string indicatorId) + { + for(int i=0;i0){ - if(debug) Print(chartMsg.getData()); - chartIndicatorSocket.send(chartMsg,true); + double values[]; + // Ensure that all indicators have finished intitailisation + for(int i=0;i= chartWindowTimerInterval) { for(int i=0;i +#include #include #include @@ -21,24 +21,34 @@ Context context("MQL5 JSON API"); Socket chartSubscriptionSocket(context,ZMQ_SUB); //--- input parameters +#property indicator_buffers 21 +#property indicator_plots 20 +#property indicator_label1 "JsonAPI" +#property indicator_type1 DRAW_NONE +#property indicator_type2 DRAW_NONE +#property indicator_type3 DRAW_NONE +//#property indicator_color3 CLR_NONE +#property indicator_type4 DRAW_NONE +#property indicator_type5 DRAW_NONE + input string IndicatorId=""; input string ShortName="JsonAPI"; -input string LineLabel="Value"; -input string ColorSyle = "clrRed"; -input string LineType = "DRAW_LINE"; -input string LineStyle = "STYLE_SOLID"; -input int LineWidth = 1; //--- indicator settings -double Buffer[]; -bool debug = false; -bool first = false; +double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[], B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], alive[]; +bool debug = true; +bool first = false; +int activeBufferCount = 0; + +int activeBufferCount = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() + { + bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT)); if (result == false) {Print("Failed to subscrbe on port ", CHART_SUB_PORT);} else { @@ -46,32 +56,72 @@ int OnInit() // TODO subscribe only to own IndicatorId topic // Subscribe to all topics chartSubscriptionSocket.setSubscribe(""); - chartSubscriptionSocket.setLinger(1000); + //chartSubscriptionSocket.setLinger(1000); + chartSubscriptionSocket.setLinger(10000); // Number of messages to buffer in RAM. chartSubscriptionSocket.setReceiveHighWaterMark(5); // TODO confirm settings } + //--- indicator buffers mapping; - ArraySetAsSeries(Buffer,true); - SetIndexBuffer(0,Buffer,INDICATOR_DATA); - SetIndexBuffer(1,Buffer,INDICATOR_CALCULATIONS); - - color colorstyle = StringToColor(ColorSyle); - int linetype = StringToEnumInt(LineType); - int linestyle = StringToEnumInt(LineStyle); - SetStyle(ShortName, LineLabel, colorstyle, linetype, linestyle, LineWidth); + ArraySetAsSeries(B0,true); + ArraySetAsSeries(B1,true); + ArraySetAsSeries(B2,true); + ArraySetAsSeries(B3,true); + ArraySetAsSeries(B4,true); + ArraySetAsSeries(B5,true); + ArraySetAsSeries(B6,true); + ArraySetAsSeries(B7,true); + ArraySetAsSeries(B8,true); + ArraySetAsSeries(B9,true); + ArraySetAsSeries(B10,true); + ArraySetAsSeries(B11,true); + ArraySetAsSeries(B12,true); + ArraySetAsSeries(B13,true); + ArraySetAsSeries(B14,true); + ArraySetAsSeries(B15,true); + ArraySetAsSeries(B16,true); + ArraySetAsSeries(B17,true); + ArraySetAsSeries(B18,true); + ArraySetAsSeries(B19,true); + ArraySetAsSeries(alive,true); + + SetIndexBuffer(0,B0,INDICATOR_DATA); + SetIndexBuffer(1,B1,INDICATOR_DATA); + SetIndexBuffer(2,B2,INDICATOR_DATA); + SetIndexBuffer(3,B3,INDICATOR_DATA); + SetIndexBuffer(4,B4,INDICATOR_DATA); + SetIndexBuffer(5,B5,INDICATOR_DATA); + SetIndexBuffer(6,B6,INDICATOR_DATA); + SetIndexBuffer(7,B7,INDICATOR_DATA); + SetIndexBuffer(8,B8,INDICATOR_DATA); + SetIndexBuffer(9,B9,INDICATOR_DATA); + SetIndexBuffer(10,B10,INDICATOR_DATA); + SetIndexBuffer(11,B11,INDICATOR_DATA); + SetIndexBuffer(12,B12,INDICATOR_DATA); + SetIndexBuffer(13,B13,INDICATOR_DATA); + SetIndexBuffer(14,B14,INDICATOR_DATA); + SetIndexBuffer(15,B15,INDICATOR_DATA); + SetIndexBuffer(16,B16,INDICATOR_DATA); + SetIndexBuffer(17,B17,INDICATOR_DATA); + SetIndexBuffer(18,B18,INDICATOR_DATA); + SetIndexBuffer(19,B19,INDICATOR_DATA); + SetIndexBuffer(20,alive,INDICATOR_CALCULATIONS); // If the buffer index changes, the line starting with "CopyBuffer(chartWindowIndicators[i].indicatorHandle," in JsonAPI.mq5 has to be updated + + //--- + IndicatorSetString(INDICATOR_SHORTNAME,ShortName); + return(INIT_SUCCEEDED); } -void SetStyle(string shortname, string linelabel, color colorstyle, int linetype, int linestyle, int linewidth) { - IndicatorSetString(INDICATOR_SHORTNAME,shortname); - PlotIndexSetString(0,PLOT_LABEL,linelabel); - PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,colorstyle); - PlotIndexSetInteger(0,PLOT_DRAW_TYPE,linetype); - PlotIndexSetInteger(0,PLOT_LINE_STYLE,linestyle); - PlotIndexSetInteger(0,PLOT_LINE_WIDTH,linewidth); +void SetStyle(int bufferIdx, string linelabel, color colorstyle, int linetype, int linestyle, int linewidth) { + PlotIndexSetString(bufferIdx,PLOT_LABEL,linelabel); + PlotIndexSetInteger(bufferIdx,PLOT_LINE_COLOR,0,colorstyle); + PlotIndexSetInteger(bufferIdx,PLOT_DRAW_TYPE,linetype); + PlotIndexSetInteger(bufferIdx,PLOT_LINE_STYLE,linestyle); + PlotIndexSetInteger(bufferIdx,PLOT_LINE_WIDTH,linewidth); } //+------------------------------------------------------------------+ @@ -89,9 +139,31 @@ int OnCalculate(const int rates_total, const int &spread[]) { // While a new candle is forming, set the current value to be empty + if(rates_total>prev_calculated){ - Buffer[0] = EMPTY_VALUE; + 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); //--- return value of prev_calculated for next call return(rates_total); @@ -99,19 +171,65 @@ int OnCalculate(const int rates_total, void SubscriptionHandler(ZmqMsg &chartMsg){ CJAVal message; - - // Get data from reguest + // 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") { - WriteToBuffer(message); + 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);;} + + //aa = true;} + */ + + SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth); + activeBufferCount = activeBufferCount + 1; } } } @@ -119,11 +237,17 @@ void SubscriptionHandler(ZmqMsg &chartMsg){ //+------------------------------------------------------------------+ //| Update indicator buffer function | //+------------------------------------------------------------------+ -void WriteToBuffer(CJAVal &message) { - int bufferSize = ArraySize(Buffer); +void WriteToBuffer(CJAVal &message, double &buffer[]) { + + int bufferSize = ArraySize(buffer); + int messageDataSize = message["data"].Size(); + // TODO check if this is working as expected. Seems to if(first==false) { - PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,bufferSize-messageDataSize); + for(int i=0;i