From 7099ac1cacec6a376fb3046564784f6efcb02b02 Mon Sep 17 00:00:00 2001 From: Gunther Schulz Date: Sun, 1 Mar 2020 18:06:24 +0100 Subject: [PATCH] add chart control open and draw indicator lines on chart --- Experts/JsonAPI.mq5 | 591 ++++++++++++++++++++++---------- Include/EnumStringToInt.mqh | 382 +++++++++++++++++++++ Indicators/JsonAPIIndicator.mq5 | 200 +++++++++++ clean.sh | 11 + 4 files changed, 1003 insertions(+), 181 deletions(-) create mode 100644 Include/EnumStringToInt.mqh create mode 100644 Indicators/JsonAPIIndicator.mq5 diff --git a/Experts/JsonAPI.mq5 b/Experts/JsonAPI.mq5 index 36f8f44..2aae593 100644 --- a/Experts/JsonAPI.mq5 +++ b/Experts/JsonAPI.mq5 @@ -1,4 +1,4 @@ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ // // Copyright (C) 2019 Nikolai Khramkov // @@ -30,7 +30,12 @@ #include #include #include -#include +#include +//#include +//#include +//#include +// Starts an Expert Advisor with specified parameters +//#include // Set ports and host for ZeroMQ string HOST="*"; @@ -39,6 +44,8 @@ int DATA_PORT=15556; int LIVE_PORT=15557; int STR_PORT=15558; int IND_DATA_PORT=15559; +int CHART_LIVE_PORT=15560; +int PUB_CHART_LIVE_PORT=15562; // ZeroMQ Cnnections Context context("MQL5 JSON API"); @@ -47,24 +54,65 @@ Socket dataSocket(context,ZMQ_PUSH); Socket liveSocket(context,ZMQ_PUSH); Socket streamSocket(context,ZMQ_PUSH); Socket indicatorDataSocket(context,ZMQ_PUSH); +Socket chartLiveSocket(context,ZMQ_PULL); +Socket pubChartLiveSocket(context,ZMQ_PUB); // Global variables bool debug = false; bool liveStream = true; bool connectedFlag= true; int deInitReason = -1; +double chartAttached = ChartID(); // Variables for handling price data stream -string chartSymbols[]; -int chartSymbolCount = 0; -string chartSymbolSettings[][3]; +struct SymbolSubscription { + string symbol; + string chartTf; + datetime lastBar; +}; + +SymbolSubscription symbolSubscriptions[]; +//string chartSymbols[]; +int symbolSubscriptionCount = 0; +//string chartSymbolSettings[][3]; // Variables for controlling indicators + +struct Indicator { + long id; + string indicatorId; + int indicatorHandle; + int indicatorParamCount; + int indicatorBufferCount; +}; +Indicator indicators[]; int indicatorCount = 0; +/* double indicators[]; string indicatorIds[]; int indicatorParamCount[]; int indicatorBufferCount[]; +*/ + +// Variables for controlling chart +struct ChartWindow { + long id; + string chartId; + string indicatorId; + int indicatorHandle; +}; +ChartWindow chartWindows[]; +int chartWindowCount = 0; + +// Refresh chart windows interval. OnTimer function of indicatore JsonAPIIndicator gets triggered on each interval +int chartWindowTimerInterval = 100; +int chartWindowTimerCounter = 0; + + +//string chartWindowObjects[]; + +//double chartCurvePositions[][3]; + //+------------------------------------------------------------------+ //| Bind ZMQ sockets to ports | @@ -82,17 +130,26 @@ bool BindSockets(){ result = indicatorDataSocket.bind(StringFormat("tcp://%s:%d", HOST,IND_DATA_PORT)); if (result == false) return result; + result = chartLiveSocket.bind(StringFormat("tcp://%s:%d", HOST,CHART_LIVE_PORT)); + if (result == false) { return result; } else {Print("Bound 'Chart Live' socket on port ", CHART_LIVE_PORT);} + + result = pubChartLiveSocket.bind(StringFormat("tcp://%s:%d", HOST,PUB_CHART_LIVE_PORT)); + if (result == false) { return result; } else {Print("Bound 'PUB Chart Live' socket on port ", PUB_CHART_LIVE_PORT);} + Print("Bound 'System' socket on port ", SYS_PORT); Print("Bound 'Data' socket on port ", DATA_PORT); Print("Bound 'Live' socket on port ", LIVE_PORT); Print("Bound 'Streaming' socket on port ", STR_PORT); Print("Bound 'Indicator Data' socket on port ", IND_DATA_PORT); + sysSocket.setLinger(1000); dataSocket.setLinger(1000); liveSocket.setLinger(1000); streamSocket.setLinger(1000); indicatorDataSocket.setLinger(1000); + chartLiveSocket.setLinger(1000); + //pubChartLiveSocket.setLinger(1000); // Number of messages to buffer in RAM. sysSocket.setSendHighWaterMark(1); @@ -100,6 +157,8 @@ bool BindSockets(){ liveSocket.setSendHighWaterMark(1); streamSocket.setSendHighWaterMark(50); indicatorDataSocket.setSendHighWaterMark(5); + chartLiveSocket.setReceiveHighWaterMark(1); // TODO confirm settings + //pubChartLiveSocket.setReceiveHighWaterMark(1); return result; } @@ -109,10 +168,10 @@ bool BindSockets(){ //+------------------------------------------------------------------+ int OnInit(){ /* Bindinig ZMQ ports on init */ -Print(GetIndicatorConstantValue("VOLUME_TICK"), " ",VOLUME_TICK); + // 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. @@ -136,50 +195,6 @@ Print(GetIndicatorConstantValue("VOLUME_TICK"), " ",VOLUME_TICK); return(INIT_SUCCEEDED); } -void testDraw() { -// ChartSetSymbolPeriod(ChartID(), Symbol(),PERIOD_M1); - - // long chart_id; - // chart_id = ChartOpen("EURUSD",PERIOD_M1); - // Print(chart_id); - -long chart_id = 0; - int window = 0; - - datetime time1 = 1581891300; - double price1 = 1.08346; - datetime time2 = 1581891600; - double price2 = 1.08354; - chart_id = ChartOpen("EURUSD",PERIOD_M5); - Print(chart_id); - /* - bool CChartObjectTrend::Create(long chart_id,string name,int window, - datetime time1,double price1,datetime time2,double price2) - { - bool result=ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2); - if(result) result&=Attach(chart_id,name,window,2); -//--- - return(result); - } - */ - CChartObject object; - //ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1,price1,time2,price2,time2,price2+0.00005); - //ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1-100,price1,time1,price1+0.00010,time1+200,price1); - //ObjectCreate(chart_id,"trend",OBJ_TREND,window,time1,price1,time2,price2); - ObjectCreate(chart_id,"reactangle",OBJ_TREND,window,time1,price1+0.00010,time2,price2+0.00020); - - - //--- attach chart object - /* - if(!object.Attach(ChartID(),"MyObject",0,2)) - { - printf("Object attach error"); - - } - */ - //ChartSetSymbolPeriod(ChartID(), Symbol(),PERIOD_M5); - ChartRedraw(chart_id); -} //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ @@ -204,12 +219,22 @@ void OnDeinit(const int reason){ liveSocket.unbind(StringFormat("tcp://%s:%d", HOST,LIVE_PORT)); Print("Unbinding 'Streaming' socket on port ", STR_PORT, ".."); streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,STR_PORT)); + Print("Unbinding 'CHart' socket on port ", STR_PORT, ".."); + streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,CHART_LIVE_PORT)); + Print("Unbinding 'pub chart' socket on port ", STR_PORT, ".."); + streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,PUB_CHART_LIVE_PORT)); // Shutdown ZeroMQ Context context.shutdown(); context.destroy(0); + // Reset + ResetSubscriptionsAndIndicators(); + EventKillTimer(); + for(int i=0;i0){ + Print(chartMsg.getData()); + pubChartLiveSocket.send(chartMsg,true); + ResetLastError(); } -*/ + + // Trigger the indicator JsonAPIIndicator to check for new Messages + if(chartWindowTimerCounter >= chartWindowTimerInterval) { + for(int i=0;i= 0) { - if(CopyBuffer(indicators[idx], i, fromDate, 1, values) < 0) {/* Error handling */} + if(CopyBuffer(indicators[idx].indicatorHandle, i, fromDate, 1, values) < 0) {/* Error handling */} results[i] = DoubleToString(values[0]); } else { @@ -577,6 +628,237 @@ void GetIndicatorResult(CJAVal &dataObject) { //else ActionDoneOrError(ERR_MARKET_UNKNOWN_SYMBOL, __FUNCTION__); } +//+------------------------------------------------------------------+ +//| Open new chart or add indicator to chart | +//+------------------------------------------------------------------+ + +void ChartControl(CJAVal &dataObject){ + + string actionType=dataObject["actionType"].ToStr(); + + if(actionType=="ADDINDICATOR") { + AddIndicatorChartToChart(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); + //ArrayResize(chartWindowIds,chartWindowCount); + //ArrayResize(chartWindowPeriods,chartWindowCount); + // ArrayResize(chartWindowObjects,chartWindowCount); + + int idx = chartWindowCount-1; + + chartWindows[idx].chartId = chartId; + + ENUM_TIMEFRAMES period = GetTimeframe(chartTF); + chartWindows[idx].id = ChartOpen(symbol, period); + //chartWindowPeriods[idx] = period; + + CJAVal message; + message["chartId"] = (string) chartId; + + string t=message.Serialize(); + if(debug) Print(t); + InformClientSocket(dataSocket,t); +} + +//+------------------------------------------------------------------+ +//| Add JsonAPIIndicator indicator chart to chart | +//+------------------------------------------------------------------+ +void AddIndicatorChartToChart(CJAVal &dataObject){ + + string chartIdStr=dataObject["chartId"].ToStr(); + string chartIndicatorId=dataObject["indicatorChartId"].ToStr(); + int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt(); + string shortname = dataObject["style"]["shortname"].ToStr(); + string colorstyle = dataObject["style"]["color"].ToStr(); + string linetype = dataObject["style"]["linetype"].ToStr(); + string linestyle = dataObject["style"]["linestyle"].ToStr(); + int linewidth = dataObject["style"]["linewidth"].ToInt(); + + int idx = GetChartWindowIdxByChartWindowId(chartIdStr); + long ChartId = chartWindows[idx].id; + + double chartIndicatorHandle = iCustom(ChartSymbol(ChartId),ChartPeriod(ChartId),"JsonAPIIndicator",chartIndicatorId,shortname,colorstyle,linetype,linestyle,linewidth); + + ChartIndicatorAdd(ChartId, chartIndicatorSubWindow, chartIndicatorHandle); + + chartWindows[idx].indicatorId = chartIndicatorId; + chartWindows[idx].indicatorHandle = chartIndicatorHandle; + + CJAVal message; + message["chartId"] = (string) chartIdStr; + + string t=message.Serialize(); + if(debug) Print(t); + InformClientSocket(dataSocket,t); +} + +//+------------------------------------------------------------------+ +//| Draw on chart | +//+------------------------------------------------------------------+ +void ChartDraw(CJAVal &dataObject){ +/* + Print("drawchart"); + + string id=dataObject["id"].ToStr(); + //int windowIdx = GetChartWindowIdxByChartWindowId(id); + + int datesSize = dataObject["data"][0].Size(); + int x[]; + int y[]; + double x_dbl[]; + double y_dbl[]; + ArrayResize(chartCurvePositions, datesSize); + ArrayResize(x,datesSize); + ArrayResize(y,datesSize); + ArrayResize(x_dbl,datesSize); + ArrayResize(y_dbl,datesSize); + for(int i=0;i=0)return r; - - ENUM_APPLIED_VOLUME av; - r = StringToEnum(indicatorConstantString,av); - if(r>=0)return r; - - ENUM_STO_PRICE sp; - r = StringToEnum(indicatorConstantString,sp); - if(r>=0)return r; - - ENUM_MA_METHOD mm; - r = StringToEnum(indicatorConstantString,mm); - if(r>=0)return r; - - return(-1); -} - -#define MIN_ENUM_VALUES 0 -#define MAX_ENUM_VALUES 255 -//+------------------------------------------------------------------+ -//| StringToEnum : Convert a string to an ENUM value, | -//| it loop between min(0) and max(255), adjustable if needed. | -//| Non existing enum value defined as -1. If -1 is used as an | -//| enum value, code need to be adjusted to an other default. | -//| Parameters : | -//| in - string to convert | -//| out - ENUM value | -//| @return - int if conversion succeed, false otherwise | -//| | -//| Based on: | -//| https://www.mql5.com/en/forum/61741/page3#comment_5491344 | -//+------------------------------------------------------------------+ -template -int StringToEnum(string in,ENUM &out) - { - out=-1; -//--- - for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++) - { - ENUM enumValue=(ENUM)i; - if(in==EnumToString(enumValue)) - { - out=enumValue; - break; - } - } -//--- - return(out); - } - - //+------------------------------------------------------------------+ //| Trade confirmation | //+------------------------------------------------------------------+ @@ -1386,4 +1614,5 @@ string getUninitReasonText(int reasonCode) } //--- return text; - } \ No newline at end of file + } + \ No newline at end of file diff --git a/Include/EnumStringToInt.mqh b/Include/EnumStringToInt.mqh new file mode 100644 index 0000000..f26d640 --- /dev/null +++ b/Include/EnumStringToInt.mqh @@ -0,0 +1,382 @@ + +#define MIN_ENUM_VALUES 0 +#define MAX_ENUM_VALUES 255 +//+------------------------------------------------------------------+ +//| StringToEnum : Convert a string to an ENUM value, | +//| it loops between min(0) and max(255), adjustable if needed. | +//| Non existing enum value defined as -1. If -1 is used as an | +//| enum value, code need to be adjusted to an other default. | +//| Parameters : | +//| in - string to convert | +//| out - ENUM value | +//| @return - int if conversion succeeded, false otherwise | +//| | +//| Based on: | +//| https://www.mql5.com/en/forum/61741/page3#comment_5491344 | +//+------------------------------------------------------------------+ +template +int StringToEnum(string in,ENUM &out) + { + out=-1; +//--- + for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++) + { + ENUM enumValue=(ENUM)i; + if(in==EnumToString(enumValue)) + { + out=enumValue; + break; + } + } +//--- + return(out); + } + + +int StringToEnumInt(string indicatorConstantString, bool debug=1){ + + int r = -1; + + ENUM_ACCOUNT_INFO_DOUBLE a1; + r = StringToEnum(indicatorConstantString,a1); + //if(debug) Print("ENUM type: ENUM_ACCOUNT_INFO_DOUBLE"); + if(r>=0)return r; + ENUM_ACCOUNT_INFO_INTEGER a2; + r = StringToEnum(indicatorConstantString,a2); + if(r>=0)return r; + ENUM_ACCOUNT_INFO_STRING a3; + r = StringToEnum(indicatorConstantString,a3); + if(r>=0)return r; + ENUM_ACCOUNT_MARGIN_MODE a4; + r = StringToEnum(indicatorConstantString,a4); + if(r>=0)return r; + ENUM_ACCOUNT_STOPOUT_MODE a5; + r = StringToEnum(indicatorConstantString,a5); + if(r>=0)return r; + ENUM_ACCOUNT_TRADE_MODE a6; + r = StringToEnum(indicatorConstantString,a6); + if(r>=0)return r; + ENUM_ALIGN_MODE a7; + r = StringToEnum(indicatorConstantString,a7); + if(r>=0)return r; + ENUM_ANCHOR_POINT a8; + r = StringToEnum(indicatorConstantString,a8); + if(r>=0)return r; + ENUM_APPLIED_PRICE a9; + r = StringToEnum(indicatorConstantString,a9); + if(r>=0)return r; + ENUM_APPLIED_PRICE a10; + r = StringToEnum(indicatorConstantString,a10); + if(r>=0)return r; + ENUM_APPLIED_VOLUME a11; + r = StringToEnum(indicatorConstantString,a11); + if(r>=0)return r; + ENUM_ARROW_ANCHOR a12; + r = StringToEnum(indicatorConstantString,a12); + if(r>=0)return r; + ENUM_BASE_CORNER a13; + r = StringToEnum(indicatorConstantString,a13); + if(r>=0)return r; + ENUM_BOOK_TYPE a14; + r = StringToEnum(indicatorConstantString,a14); + if(r>=0)return r; + ENUM_BORDER_TYPE a15; + r = StringToEnum(indicatorConstantString,a15); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_FREQUENCY a16; + r = StringToEnum(indicatorConstantString,a16); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_IMPACT a17; + r = StringToEnum(indicatorConstantString,a17); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_IMPORTANCE a18; + r = StringToEnum(indicatorConstantString,a18); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_MULTIPLIER a19; + r = StringToEnum(indicatorConstantString,a19); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_SECTOR a20; + r = StringToEnum(indicatorConstantString,a20); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_TIMEMODE a21; + r = StringToEnum(indicatorConstantString,a21); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_TYPE a22; + r = StringToEnum(indicatorConstantString,a22); + if(r>=0)return r; + ENUM_CALENDAR_EVENT_UNIT a23; + r = StringToEnum(indicatorConstantString,a23); + if(r>=0)return r; + ENUM_CHART_EVENT a24; + r = StringToEnum(indicatorConstantString,a24); + if(r>=0)return r; + ENUM_CHART_MODE a25; + r = StringToEnum(indicatorConstantString,a25); + if(r>=0)return r; + ENUM_CHART_POSITION a26; + r = StringToEnum(indicatorConstantString,a26); + if(r>=0)return r; + ENUM_CHART_PROPERTY_DOUBLE a27; + r = StringToEnum(indicatorConstantString,a27); + if(r>=0)return r; + ENUM_CHART_PROPERTY_INTEGER a28; + r = StringToEnum(indicatorConstantString,a28); + if(r>=0)return r; + ENUM_CHART_PROPERTY_STRING a29; + r = StringToEnum(indicatorConstantString,a29); + if(r>=0)return r; + ENUM_CHART_VOLUME_MODE a30; + r = StringToEnum(indicatorConstantString,a30); + if(r>=0)return r; + ENUM_CL_DEVICE_TYPE a31; + r = StringToEnum(indicatorConstantString,a31); + if(r>=0)return r; + ENUM_COLOR_FORMAT a32; + r = StringToEnum(indicatorConstantString,a32); + if(r>=0)return r; + ENUM_CRYPT_METHOD a33; + r = StringToEnum(indicatorConstantString,a33); + if(r>=0)return r; + ENUM_CUSTOMIND_PROPERTY_DOUBLE a34; + r = StringToEnum(indicatorConstantString,a34); + if(r>=0)return r; + ENUM_CHART_PROPERTY_INTEGER a35; + r = StringToEnum(indicatorConstantString,a35); + if(r>=0)return r; + ENUM_CUSTOMIND_PROPERTY_STRING a36; + r = StringToEnum(indicatorConstantString,a36); + if(r>=0)return r; + ENUM_DATABASE_EXPORT_FLAGS a37; + r = StringToEnum(indicatorConstantString,a37); + if(r>=0)return r; + ENUM_DATABASE_FIELD_TYPE a38; + r = StringToEnum(indicatorConstantString,a38); + if(r>=0)return r; + ENUM_DATABASE_OPEN_FLAGS a39; + r = StringToEnum(indicatorConstantString,a39); + if(r>=0)return r; + ENUM_DATABASE_PRINT_FLAGS a40; + r = StringToEnum(indicatorConstantString,a40); + if(r>=0)return r; + ENUM_DATATYPE a41; + r = StringToEnum(indicatorConstantString,a41); + if(r>=0)return r; + ENUM_DAY_OF_WEEK a42; + r = StringToEnum(indicatorConstantString,a42); + if(r>=0)return r; + ENUM_DEAL_ENTRY a43; + r = StringToEnum(indicatorConstantString,a43); + if(r>=0)return r; + ENUM_DEAL_PROPERTY_DOUBLE a44; + r = StringToEnum(indicatorConstantString,a44); + if(r>=0)return r; + ENUM_DEAL_PROPERTY_INTEGER a45; + r = StringToEnum(indicatorConstantString,a45); + if(r>=0)return r; + ENUM_DEAL_PROPERTY_STRING a46; + r = StringToEnum(indicatorConstantString,a46); + if(r>=0)return r; + ENUM_DEAL_REASON a47; + r = StringToEnum(indicatorConstantString,a47); + if(r>=0)return r; + ENUM_DEAL_TYPE a48; + r = StringToEnum(indicatorConstantString,a48); + if(r>=0)return r; + ENUM_DRAW_TYPE a49; + r = StringToEnum(indicatorConstantString,a49); + if(r>=0)return r; + ENUM_DX_BUFFER_TYPE a50; + r = StringToEnum(indicatorConstantString,a50); + if(r>=0)return r; + ENUM_DX_FORMAT a51; + r = StringToEnum(indicatorConstantString,a51); + if(r>=0)return r; + ENUM_DX_HANDLE_TYPE a52; + r = StringToEnum(indicatorConstantString,a52); + if(r>=0)return r; + ENUM_DX_PRIMITIVE_TOPOLOGY a53; + r = StringToEnum(indicatorConstantString,a53); + if(r>=0)return r; + ENUM_DX_SHADER_TYPE a54; + r = StringToEnum(indicatorConstantString,a54); + if(r>=0)return r; + ENUM_ELLIOT_WAVE_DEGREE a55; + r = StringToEnum(indicatorConstantString,a55); + if(r>=0)return r; + ENUM_FILESELECT_FLAGS a56; + r = StringToEnum(indicatorConstantString,a56); + if(r>=0)return r; + ENUM_FILE_POSITION a57; + r = StringToEnum(indicatorConstantString,a57); + if(r>=0)return r; + ENUM_FILE_PROPERTY_INTEGER a58; + r = StringToEnum(indicatorConstantString,a58); + if(r>=0)return r; + ENUM_GANN_DIRECTION a59; + r = StringToEnum(indicatorConstantString,a59); + if(r>=0)return r; + ENUM_INDEXBUFFER_TYPE a60; + r = StringToEnum(indicatorConstantString,a60); + if(r>=0)return r; + ENUM_INDICATOR a61; + r = StringToEnum(indicatorConstantString,a61); + if(r>=0)return r; + ENUM_INIT_RETCODE a62; + r = StringToEnum(indicatorConstantString,a62); + if(r>=0)return r; + ENUM_LICENSE_TYPE a63; + r = StringToEnum(indicatorConstantString,a63); + if(r>=0)return r; + ENUM_LINE_STYLE a64; + r = StringToEnum(indicatorConstantString,a64); + if(r>=0)return r; + ENUM_MA_METHOD a65; + r = StringToEnum(indicatorConstantString,a65); + if(r>=0)return r; + ENUM_MQL_INFO_INTEGER a66; + r = StringToEnum(indicatorConstantString,a66); + if(r>=0)return r; + ENUM_MQL_INFO_STRING a67; + r = StringToEnum(indicatorConstantString,a67); + if(r>=0)return r; + ENUM_OBJECT a68; + r = StringToEnum(indicatorConstantString,a68); + if(r>=0)return r; + ENUM_OBJECT_PROPERTY_DOUBLE a69; + r = StringToEnum(indicatorConstantString,a69); + if(r>=0)return r; + ENUM_OBJECT_PROPERTY_INTEGER a70; + r = StringToEnum(indicatorConstantString,a70); + if(r>=0)return r; + ENUM_OBJECT_PROPERTY_STRING a71; + r = StringToEnum(indicatorConstantString,a71); + if(r>=0)return r; + ENUM_OPENCL_HANDLE_TYPE a72; + r = StringToEnum(indicatorConstantString,a72); + if(r>=0)return r; + ENUM_OPENCL_PROPERTY_INTEGER a73; + r = StringToEnum(indicatorConstantString,a73); + if(r>=0)return r; + ENUM_PLOT_PROPERTY_STRING a74; + r = StringToEnum(indicatorConstantString,a74); + if(r>=0)return r; + ENUM_POINTER_TYPE a75; + r = StringToEnum(indicatorConstantString,a75); + if(r>=0)return r; + ENUM_POSITION_PROPERTY_DOUBLE a76; + r = StringToEnum(indicatorConstantString,a76); + if(r>=0)return r; + ENUM_ORDER_PROPERTY_INTEGER a77; + r = StringToEnum(indicatorConstantString,a77); + if(r>=0)return r; + ENUM_PLOT_PROPERTY_STRING a78; + r = StringToEnum(indicatorConstantString,a78); + if(r>=0)return r; + ENUM_PROGRAM_TYPE a79; + r = StringToEnum(indicatorConstantString,a79); + if(r>=0)return r; + ENUM_SERIESMODE a80; + r = StringToEnum(indicatorConstantString,a80); + if(r>=0)return r; + ENUM_SERIES_INFO_INTEGER a81; + r = StringToEnum(indicatorConstantString,a81); + if(r>=0)return r; + ENUM_SIGNAL_BASE_DOUBLE a82; + r = StringToEnum(indicatorConstantString,a82); + if(r>=0)return r; + ENUM_SIGNAL_BASE_INTEGER a83; + r = StringToEnum(indicatorConstantString,a83); + if(r>=0)return r; + ENUM_SIGNAL_BASE_STRING a84; + r = StringToEnum(indicatorConstantString,a84); + if(r>=0)return r; + ENUM_SIGNAL_INFO_DOUBLE a85; + r = StringToEnum(indicatorConstantString,a85); + if(r>=0)return r; + ENUM_SIGNAL_INFO_INTEGER a86; + r = StringToEnum(indicatorConstantString,a86); + if(r>=0)return r; + ENUM_SIGNAL_INFO_STRING a87; + r = StringToEnum(indicatorConstantString,a87); + if(r>=0)return r; + ENUM_STATISTICS a88; + r = StringToEnum(indicatorConstantString,a88); + if(r>=0)return r; + ENUM_STO_PRICE a89; + r = StringToEnum(indicatorConstantString,a89); + if(r>=0)return r; + ENUM_SYMBOL_CALC_MODE a90; + r = StringToEnum(indicatorConstantString,a90); + if(r>=0)return r; + ENUM_SYMBOL_CHART_MODE a91; + r = StringToEnum(indicatorConstantString,a91); + if(r>=0)return r; + ENUM_SYMBOL_INFO_DOUBLE a92; + r = StringToEnum(indicatorConstantString,a92); + if(r>=0)return r; + ENUM_SYMBOL_INFO_INTEGER a93; + r = StringToEnum(indicatorConstantString,a93); + if(r>=0)return r; + ENUM_SYMBOL_INFO_STRING a94; + r = StringToEnum(indicatorConstantString,a94); + if(r>=0)return r; + ENUM_STATISTICS a95; + r = StringToEnum(indicatorConstantString,a95); + if(r>=0)return r; + ENUM_STO_PRICE a96; + r = StringToEnum(indicatorConstantString,a96); + if(r>=0)return r; + ENUM_SYMBOL_CALC_MODE a97; + r = StringToEnum(indicatorConstantString,a97); + if(r>=0)return r; + ENUM_SYMBOL_CHART_MODE a98; + r = StringToEnum(indicatorConstantString,a98); + if(r>=0)return r; + ENUM_SYMBOL_INFO_DOUBLE a99; + r = StringToEnum(indicatorConstantString,a99); + if(r>=0)return r; + ENUM_SYMBOL_INFO_INTEGER a100; + r = StringToEnum(indicatorConstantString,a100); + if(r>=0)return r; + ENUM_SYMBOL_INFO_STRING a101; + r = StringToEnum(indicatorConstantString,a101); + if(r>=0)return r; + ENUM_SYMBOL_OPTION_MODE a102; + r = StringToEnum(indicatorConstantString,a102); + if(r>=0)return r; + ENUM_SYMBOL_OPTION_RIGHT a103; + r = StringToEnum(indicatorConstantString,a103); + if(r>=0)return r; + ENUM_SYMBOL_ORDER_GTC_MODE a104; + r = StringToEnum(indicatorConstantString,a104); + if(r>=0)return r; + ENUM_SYMBOL_SWAP_MODE a105; + r = StringToEnum(indicatorConstantString,a105); + if(r>=0)return r; + ENUM_SYMBOL_TRADE_EXECUTION a106; + r = StringToEnum(indicatorConstantString,a106); + if(r>=0)return r; + ENUM_SYMBOL_TRADE_MODE a107; + r = StringToEnum(indicatorConstantString,a107); + if(r>=0)return r; + ENUM_TERMINAL_INFO_DOUBLE a108; + r = StringToEnum(indicatorConstantString,a108); + if(r>=0)return r; + ENUM_TERMINAL_INFO_INTEGER a109; + r = StringToEnum(indicatorConstantString,a109); + if(r>=0)return r; + ENUM_TERMINAL_INFO_STRING a110; + r = StringToEnum(indicatorConstantString,a110); + if(r>=0)return r; + ENUM_TIMEFRAMES a111; + r = StringToEnum(indicatorConstantString,a111); + if(r>=0)return r; + ENUM_TRADE_REQUEST_ACTIONS a112; + r = StringToEnum(indicatorConstantString,a112); + if(r>=0)return r; + ENUM_TRADE_TRANSACTION_TYPE a113; + r = StringToEnum(indicatorConstantString,a113); + if(r>=0)return r; + + return(-1); +} diff --git a/Indicators/JsonAPIIndicator.mq5 b/Indicators/JsonAPIIndicator.mq5 new file mode 100644 index 0000000..12d06b7 --- /dev/null +++ b/Indicators/JsonAPIIndicator.mq5 @@ -0,0 +1,200 @@ +//+------------------------------------------------------------------+ +//| JsonAPIIndicator.mq5 | +//| Copyright 2020, Gunther Schulz | +//| https://www.guntherschulz.de | +//+------------------------------------------------------------------+ + +#property copyright "2020 Gunther Schulz" +#property link "https://www.guntherschulz.de" +#property version "1.00" + +#include +#include +#include + +// Set ports and host for ZeroMQ +string HOST="localhost"; +int CHART_SUB_PORT=15562; + +// ZeroMQ Cnnections +Context context("MQL5 JSON API"); +Socket chartLiveSocket(context,ZMQ_SUB); + +//#property indicator_separate_window +//#property indicator_buffers 1 +//#property indicator_plots 1 +//---- plot MA +//#property indicator_label1 "MA" +//#property indicator_type1 DRAW_LINE +//#property indicator_color1 clrRed +//#property indicator_style1 STYLE_SOLID +//#property indicator_width1 1 + +//--- input parameters +input string IndicatorId=""; +input string ShortName="JsonAPI"; +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 Values[]; +//ENUM_TIMEFRAMES originalTF = ChartPeriod(); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { + bool result = chartLiveSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT)); + if (result == false) {Print("Failed to subscrbe on port ", CHART_SUB_PORT);} + else { + Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT); + chartLiveSocket.setSubscribe(""); + chartLiveSocket.setLinger(1000); + // Number of messages to buffer in RAM. + chartLiveSocket.setReceiveHighWaterMark(5); // TODO confirm settings + } + +//--- indicator buffers mapping; + ArraySetAsSeries(Buffer,true); + SetIndexBuffer(0,Buffer,INDICATOR_DATA); + + color colorstyle = StringToColor(ColorSyle); + int linetype = StringToEnumInt(LineType); + int linestyle = StringToEnumInt(LineStyle); + SetStyle(ShortName, colorstyle, linetype, linestyle, LineWidth); +//--- + return(INIT_SUCCEEDED); + } + + +void SetStyle(string shortname, color colorstyle, int linetype, int linestyle, int linewidth) { + IndicatorSetString(INDICATOR_SHORTNAME,shortname); + 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); +} + +//+------------------------------------------------------------------+ +//| Custom indicator iteration function | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + // While a new candle is forming, set the current value to the previous value + if(rates_total>prev_calculated){ + Buffer[0] = EMPTY_VALUE; + } + +/* +https://www.mql5.com/en/docs/constants/structures/mqlparam + +*/ + + +//--- return value of prev_calculated for next call + return(rates_total); + } + +void SubscriptionHandler(ZmqMsg &chartMsg){ + CJAVal message; + + //ResetLastError(); + + // Get data from reguest + string msg=chartMsg.getData(); + if(debug) Print("Processing:"+msg); + + // Deserialize msg to CJAVal array + if(!message.Deserialize(msg)){ + //ActionDoneOrError(65537, __FUNCTION__); + Alert("Deserialization Error"); + ExpertRemove(); + } + if(message["indicatorChartId"]==IndicatorId) WriteToBuffer(message); +} + +void WriteToBuffer(CJAVal &message) { + int bufferSize = ArraySize(Buffer); + int messageDataSize = message["data"].Size(); + if(first==false) { + //ArrayFill(Buffer, 0, ArraySize(Buffer), EMPTY_VALUE); + PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,bufferSize-messageDataSize); + first = true; + } + + for(int i=0;i0){ + // Handle subscription SubscriptionHandler(). + Print(chartMsg.getData()); + SubscriptionHandler(chartMsg); + ChartRedraw(ChartID()); + } +} + +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { + //if(id==CHARTEVENT_CUSTOM+222 && sparam==IndicatorId) CheckMessages(); + if(id==CHARTEVENT_CUSTOM+222) CheckMessages(); + } +//+---------------------------------------------------- diff --git a/clean.sh b/clean.sh index 4db1e7f..48c0908 100755 --- a/clean.sh +++ b/clean.sh @@ -10,3 +10,14 @@ sed -i '1s/^/\xef\xbb\xbf/' ./Experts/JsonAPI.clean.mq5 mv ./Experts/JsonAPI.clean.mq5 ./Experts/JsonAPI.mq5 +# Remove non-printable ASCII characters +tr -cd '[:print:]\n\r' < ./Indicators/JsonAPIIndicator.mq5 > ./Indicators/JsonAPIIndicator.clean.mq5 +# Add UTF-8 BOM +sed -i '1s/^/\xef\xbb\xbf/' ./Indicators/JsonAPIIndicator.clean.mq5 +mv ./Indicators/JsonAPIIndicator.clean.mq5 ./Indicators/JsonAPIIndicator.mq5 + +# Remove non-printable ASCII characters +tr -cd '[:print:]\n\r' < ./Include/EnumStringToInt.mqh > ./Include/EnumStringToInt.clean.mqh +# Add UTF-8 BOM +sed -i '1s/^/\xef\xbb\xbf/' ./Include/EnumStringToInt.clean.mqh +mv ./Include/EnumStringToInt.clean.mqh ./Include/EnumStringToInt.mqh \ No newline at end of file