4 Commits

Author SHA1 Message Date
Gunther Schulz 1a0ce7af3a fix incorrect setting of high water mark
Socket settings need to be set before connecting to the socket
Also, increase high water mark
2020-11-22 13:21:39 +01:00
Gunther Schulz 08b83713af fix compiler failure 2020-11-22 13:15:51 +01:00
Gunther Schulz 775a962d38 format code with new MT5 code styler 2020-11-22 13:14:33 +01:00
Nikolai b17e82d99d Merge pull request #9 from Gunther-Schulz/indicator
Drawing custom indicator data to charts
2020-10-12 10:25:50 +03:00
2 changed files with 1733 additions and 1284 deletions
+1456 -1051
View File
File diff suppressed because it is too large Load Diff
+189 -145
View File
@@ -40,27 +40,27 @@ bool debug = true;
bool first = false; bool first = false;
int activeBufferCount = 0; int activeBufferCount = 0;
int activeBufferCount = 0;
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Custom indicator initialization function | //| Custom indicator initialization function |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
int OnInit() int OnInit()
{ {
// TODO subscribe only to own IndicatorId topic
bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT)); // Subscribe to all topics
if (result == false) {Print("Failed to subscrbe on port ", CHART_SUB_PORT);} chartSubscriptionSocket.setSubscribe("");
else { chartSubscriptionSocket.setLinger(1000);
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT); // Number of messages to buffer in RAM.
// TODO subscribe only to own IndicatorId topic chartSubscriptionSocket.setReceiveHighWaterMark(1000); // TODO confirm settings
// Subscribe to all topics bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT));
chartSubscriptionSocket.setSubscribe(""); if(result == false)
//chartSubscriptionSocket.setLinger(1000); {
chartSubscriptionSocket.setLinger(10000); Print("Failed to subscrbe on port ", CHART_SUB_PORT);
// Number of messages to buffer in RAM. }
chartSubscriptionSocket.setReceiveHighWaterMark(5); // TODO confirm settings else
} {
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT);
}
//--- indicator buffers mapping; //--- indicator buffers mapping;
@@ -116,13 +116,17 @@ int OnInit()
} }
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); void SetStyle(int bufferIdx, string linelabel, color colorstyle, int linetype, int linestyle, int linewidth)
PlotIndexSetInteger(bufferIdx,PLOT_LINE_STYLE,linestyle); {
PlotIndexSetInteger(bufferIdx,PLOT_LINE_WIDTH,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);
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Custom indicator iteration function | //| Custom indicator iteration function |
@@ -138,151 +142,190 @@ int OnCalculate(const int rates_total,
const long &volume[], const long &volume[],
const int &spread[]) const int &spread[])
{ {
// While a new candle is forming, set the current value to be empty // While a new candle is forming, set the current value to be empty
if(rates_total>prev_calculated){ if(rates_total>prev_calculated)
B0[0] = EMPTY_VALUE; {
B1[0] = EMPTY_VALUE; B0[0] = EMPTY_VALUE;
B2[0] = EMPTY_VALUE; B1[0] = EMPTY_VALUE;
B3[0] = EMPTY_VALUE; B2[0] = EMPTY_VALUE;
B4[0] = EMPTY_VALUE; B3[0] = EMPTY_VALUE;
B5[0] = EMPTY_VALUE; B4[0] = EMPTY_VALUE;
B6[0] = EMPTY_VALUE; B5[0] = EMPTY_VALUE;
B7[0] = EMPTY_VALUE; B6[0] = EMPTY_VALUE;
B8[0] = EMPTY_VALUE; B7[0] = EMPTY_VALUE;
B9[0] = EMPTY_VALUE; B8[0] = EMPTY_VALUE;
B10[0] = EMPTY_VALUE; B9[0] = EMPTY_VALUE;
B11[0] = EMPTY_VALUE; B10[0] = EMPTY_VALUE;
B12[0] = EMPTY_VALUE; B11[0] = EMPTY_VALUE;
B13[0] = EMPTY_VALUE; B12[0] = EMPTY_VALUE;
B14[0] = EMPTY_VALUE; B13[0] = EMPTY_VALUE;
B15[0] = EMPTY_VALUE; B14[0] = EMPTY_VALUE;
B16[0] = EMPTY_VALUE; B15[0] = EMPTY_VALUE;
B17[0] = EMPTY_VALUE; B16[0] = EMPTY_VALUE;
B18[0] = EMPTY_VALUE; B17[0] = EMPTY_VALUE;
B19[0] = EMPTY_VALUE; B18[0] = EMPTY_VALUE;
} B19[0] = EMPTY_VALUE;
if(first==false) alive[0] = 1; }
// ChartRedraw(0); if(first==false)
alive[0] = 1;
// ChartRedraw(0);
//--- return value of prev_calculated for next call //--- return value of prev_calculated for next call
return(rates_total); return(rates_total);
} }
void SubscriptionHandler(ZmqMsg &chartMsg){ //+------------------------------------------------------------------+
CJAVal message; //| |
// Get data from request //+------------------------------------------------------------------+
string msg=chartMsg.getData(); void SubscriptionHandler(ZmqMsg &chartMsg)
if(debug) Print("Processing:"+msg); {
// Deserialize msg to CJAVal array CJAVal message;
if(!message.Deserialize(msg)){ // Get data from request
Alert("Deserialization Error"); string msg=chartMsg.getData();
ExpertRemove(); 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);;}
//aa = true;}
*/
SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
activeBufferCount = activeBufferCount + 1;
}
}
} }
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;
}
}
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Update indicator buffer function | //| Update indicator buffer function |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
void WriteToBuffer(CJAVal &message, double &buffer[]) { void WriteToBuffer(CJAVal &message, double &buffer[])
{
int bufferSize = ArraySize(buffer); int bufferSize = ArraySize(buffer);
int messageDataSize = message["data"].Size(); int messageDataSize = message["data"].Size();
// TODO check if this is working as expected. Seems to // TODO check if this is working as expected. Seems to
if(first==false) { if(first==false)
for(int i=0;i<activeBufferCount;i++) { {
//Print("BUFF ",bufferSize-messageDataSize, " ",ArraySize(B2)," ", ArraySize(B3), " ",messageDataSize); for(int i=0; i<activeBufferCount; i++)
PlotIndexSetInteger(i,PLOT_DRAW_BEGIN,bufferSize-messageDataSize); {
} //Print("BUFF ",bufferSize-messageDataSize, " ",ArraySize(B2)," ", ArraySize(B3), " ",messageDataSize);
first = true; PlotIndexSetInteger(i,PLOT_DRAW_BEGIN,bufferSize-messageDataSize);
}
first = true;
}
for(int i=0; i<messageDataSize; i++)
{
// don't add more elements than the automatically sized buffer array can hold
if(i+1<bufferSize)
{
// the first element is the current unformed candle, so we start at index 1
// we reverse the order of the incoming values, which are expected to be ascending
//buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
}
}
// Set the most recent plotted value to nothing, as we do not have any data for yet unformed candles
buffer[0] = EMPTY_VALUE;
} }
for(int i=0;i<messageDataSize;i++){
// don't add more elements than the automatically sized buffer array can hold
if(i+1<bufferSize){
// the first element is the current unformed candle, so we start at index 1
// we reverse the order of the incoming values, which are expected to be ascending
//buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
}
}
// Set the most recent plotted value to nothing, as we do not have any data for yet unformed candles
buffer[0] = EMPTY_VALUE;
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Check for new indicator data function | //| Check for new indicator data function |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
void CheckMessages(){ void CheckMessages()
// This is a workaround for Timer(). It is needed, because OnTimer() works if the indicator is manually added to a chart, but not with ChartIndicatorAdd() {
// This is a workaround for Timer(). It is needed, because OnTimer() works if the indicator is manually added to a chart, but not with ChartIndicatorAdd()
ZmqMsg chartMsg; ZmqMsg chartMsg;
// Recieve chart instructions stream from client via live Chart socket. // Recieve chart instructions stream from client via live Chart socket.
chartSubscriptionSocket.recv(chartMsg,true); chartSubscriptionSocket.recv(chartMsg,true);
// Request recieved // Request recieved
if(chartMsg.size()>0){ if(chartMsg.size()>0)
// Handle subscription SubscriptionHandler() {
SubscriptionHandler(chartMsg); // Handle subscription SubscriptionHandler()
ChartRedraw(ChartID()); SubscriptionHandler(chartMsg);
ChartRedraw(ChartID());
}
} }
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| OnTimer() workaround function | //| OnTimer() workaround function |
@@ -293,6 +336,7 @@ void OnChartEvent(const int id,
const double &dparam, const double &dparam,
const string &sparam) const string &sparam)
{ {
if(id==CHARTEVENT_CUSTOM+222) CheckMessages(); if(id==CHARTEVENT_CUSTOM+222)
CheckMessages();
} }
//+---------------------------------------------------- //+----------------------------------------------------