diff --git a/Experts/JsonAPI.mq5 b/Experts/JsonAPI.mq5 index 6f65ffa..36f8f44 100644 --- a/Experts/JsonAPI.mq5 +++ b/Experts/JsonAPI.mq5 @@ -1,4 +1,4 @@ -//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ // // Copyright (C) 2019 Nikolai Khramkov // @@ -30,7 +30,9 @@ #include #include #include +#include +// Set ports and host for ZeroMQ string HOST="*"; int SYS_PORT=15555; int DATA_PORT=15556; @@ -51,13 +53,18 @@ bool debug = false; bool liveStream = true; bool connectedFlag= true; int deInitReason = -1; + +// Variables for handling price data stream string chartSymbols[]; int chartSymbolCount = 0; string chartSymbolSettings[][3]; +// Variables for controlling indicators int indicatorCount = 0; double indicators[]; string indicatorIds[]; +int indicatorParamCount[]; +int indicatorBufferCount[]; //+------------------------------------------------------------------+ //| Bind ZMQ sockets to ports | @@ -102,7 +109,7 @@ 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){ @@ -125,9 +132,54 @@ int OnInit(){ return(INIT_FAILED); } + //testDraw(); 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 | //+------------------------------------------------------------------+ @@ -342,7 +394,7 @@ void RequestHandler(ZmqMsg &request){ else if(action=="POSITIONS") GetPositions(message); else if(action=="ORDERS") GetOrders(message); else if(action=="RESET") ResetSubscriptionsAndIndicators(); - else if(action=="INDICATOR") StartIndicator(message); + else if(action=="INDICATOR") IndicatorControl(message); // Action command error processing else ActionDoneOrError(65538, __FUNCTION__); @@ -352,7 +404,7 @@ void RequestHandler(ZmqMsg &request){ //| Reconfigure the script params | //+------------------------------------------------------------------+ void ScriptConfiguration(CJAVal &dataObject){ - + //testDraw(); string symbol=dataObject["symbol"].ToStr(); string chartTF=dataObject["chartTF"].ToStr(); string actionType=dataObject["actionType"].ToStr(); @@ -377,114 +429,152 @@ void ScriptConfiguration(CJAVal &dataObject){ } +//+------------------------------------------------------------------+ +//| Start new indicator or request indicator data | +//+------------------------------------------------------------------+ +void IndicatorControl(CJAVal &dataObject){ + + string actionType=dataObject["actionType"].ToStr(); + + if(actionType=="REQUEST") { + GetIndicatorResult(dataObject); + } + else if(actionType=="START") { + StartIndicator(dataObject); + } + +} + //+------------------------------------------------------------------+ //| Start new indicator instance | //+------------------------------------------------------------------+ void StartIndicator(CJAVal &dataObject){ - + string symbol=dataObject["symbol"].ToStr(); string chartTF=dataObject["chartTF"].ToStr(); string id=dataObject["id"].ToStr(); - string indicatorName=dataObject["indicatorName"].ToStr(); + string indicatorName=dataObject["name"].ToStr(); - indicatorCount++; + indicatorCount++; ArrayResize(indicators,indicatorCount); ArrayResize(indicatorIds,indicatorCount); + ArrayResize(indicatorParamCount,indicatorCount); + ArrayResize(indicatorBufferCount,indicatorCount); + int idx = indicatorCount-1; + indicatorIds[idx] = id; + indicatorBufferCount[idx] = dataObject["linecount"].ToInt(); double params[]; - int paramsCount = dataObject["indicatorParams"].Size(); - for(int i=0;i= 0) { - if(CopyBuffer(indicators[idx], i, fromDate, 1, values) < 0) values[0] = 0.0; - results[i] = DoubleToString(values[0]); - } - else { - // TODO error handling - } + double values[2]; + ArrayResize(values, indicatorBufferCount[idx]); + CJAVal results; + // Cycle through all avaliable buffer positions + for(int i=0;i= 0) { + if(CopyBuffer(indicators[idx], i, fromDate, 1, values) < 0) {/* Error handling */} + results[i] = DoubleToString(values[0]); + } + else { + // TODO error handling } - - if (liveStream) { - CJAVal data; - data["id"] = (string) id; - data["data"].Set(results); - - string t=data.Serialize(); - if(debug) Print(t); - InformClientSocket(indicatorDataSocket,t); } + + + CJAVal message; + message["id"] = (string) id; + message["data"].Set(results); + + string t=message.Serialize(); + if(debug) Print(t); + InformClientSocket(indicatorDataSocket,t); + + // TODO more error handling + //if(SymbolInfoInteger(symbol, SYMBOL_EXIST)){ + // ActionDoneOrError(ERR_SUCCESS, __FUNCTION__); + //} + //else ActionDoneOrError(ERR_MARKET_UNKNOWN_SYMBOL, __FUNCTION__); } //+------------------------------------------------------------------+ @@ -1077,7 +1167,66 @@ ENUM_TIMEFRAMES GetTimeframe(string chartTF){ else tf=NULL; return(tf); } - + +//+------------------------------------------------------------------+ +//| Convert indicator constants from string to int | +//+------------------------------------------------------------------+ +int GetIndicatorConstantValue(string indicatorConstantString){ + + int r = -1; + ENUM_APPLIED_PRICE ap; + r = StringToEnum(indicatorConstantString,ap); + if(r>=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 | //+------------------------------------------------------------------+