4 Commits

Author SHA1 Message Date
Gunther Schulz c845eadfc6 add feature to correct historical tick data
some brokers (markets.com) deliver tick incorrect historical tick data. this commit attempts to automatically correct the tick price data
2020-11-19 14:38:46 +01:00
Gunther Schulz 2510e59cd6 fix indicator plots starting at the wrong timestamp under certain cond.
plots would shift if the processing of indicaters would shift, if a new candle would for in MT while processing of indicator data of the client was still in process. The fix ensure, that any new indicator data starts at the correct timestamp.
2020-11-19 14:38:15 +01:00
Gunther Schulz de0f3468f1 improve indicator display for more clarity
Removed unused buffer value placeholder
Removed 0 as first indicator value
2020-11-08 20:37:05 +01:00
Gunther Schulz 3b85a93e97 add support for indicator short name
apply styler 
shortened indicator refresh. indicators draw much faster now
2020-11-08 13:31:20 +01:00
2 changed files with 2302 additions and 2000 deletions
+108 -84
View File
@@ -101,10 +101,6 @@ struct ChartWindowIndicator
ChartWindowIndicator chartWindowIndicators[]; ChartWindowIndicator chartWindowIndicators[];
int chartWindowIndicatorCount = 0; 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 // Error handling
ControlErrors mControl; ControlErrors mControl;
@@ -113,23 +109,6 @@ ControlErrors mControl;
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
bool BindSockets() bool BindSockets()
{ {
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(1000);
dataSocket.setSendHighWaterMark(1000);
liveSocket.setSendHighWaterMark(1000);
streamSocket.setSendHighWaterMark(1000);
indicatorDataSocket.setSendHighWaterMark(1000);
chartDataSocket.setReceiveHighWaterMark(1000); // TODO confirm settings
chartIndicatorDataSocket.setReceiveHighWaterMark(1000);
bool result = false; bool result = false;
result = sysSocket.bind(StringFormat("tcp://%s:%d", HOST,SYS_PORT)); result = sysSocket.bind(StringFormat("tcp://%s:%d", HOST,SYS_PORT));
if(result == false) if(result == false)
@@ -195,6 +174,23 @@ bool BindSockets()
Print("Bound 'JsonAPIIndicator Data' socket on port ", CHART_INDICATOR_DATA_PORT); 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; return result;
} }
@@ -349,6 +345,7 @@ int GetChartIndicatorIdxByChartIndicatorId(string indicatorId)
void StreamPriceData() void StreamPriceData()
{ {
// If liveStream == true, push last candle to liveSocket. // If liveStream == true, push last candle to liveSocket.
if(liveStream) if(liveStream)
{ {
CJAVal last; CJAVal last;
@@ -364,6 +361,7 @@ void StreamPriceData()
ENUM_TIMEFRAMES period = GetTimeframe(chartTF); ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
datetime thisBar = 0; datetime thisBar = 0;
float price;
MqlTick tick; MqlTick tick;
MqlRates rates[1]; MqlRates rates[1];
int spread[1]; int spread[1];
@@ -392,7 +390,6 @@ void StreamPriceData()
} }
else else
{ {
;
Data[0] = (long) rates[0].time; Data[0] = (long) rates[0].time;
Data[1] = (double) rates[0].open; Data[1] = (double) rates[0].open;
Data[2] = (double) rates[0].high; Data[2] = (double) rates[0].high;
@@ -401,7 +398,6 @@ void StreamPriceData()
Data[5] = (double) rates[0].tick_volume; Data[5] = (double) rates[0].tick_volume;
Data[6] = (int) spread[0]; Data[6] = (int) spread[0];
} }
last["status"] = (string) "CONNECTED"; last["status"] = (string) "CONNECTED";
last["symbol"] = (string) symbol; last["symbol"] = (string) symbol;
last["timeframe"] = (string) chartTF; last["timeframe"] = (string) chartTF;
@@ -465,24 +461,19 @@ void OnTimer()
// Ensure that all indicators have finished intitailisation // Ensure that all indicators have finished intitailisation
for(int i=0; i<ArraySize(chartWindowIndicators); i++) for(int i=0; i<ArraySize(chartWindowIndicators); i++)
{ {
CopyBuffer(chartWindowIndicators[i].indicatorHandle, 7, 0, 1, values); // '7' is the number of the 'alive' indicator buffer //CopyBuffer(chartWindowIndicators[i].indicatorHandle, 7, 0, 1, values); // '7' is the number of the 'alive' indicator buffer
// Wait for CopyBuffer to return. Ensures that indicator has been initialized
CopyBuffer(chartWindowIndicators[i].indicatorHandle, 0, 0, 1, values); // '7' is the number of the 'alive' indicator buffer
} }
chartIndicatorDataSocket.send(chartMsg,true); chartIndicatorDataSocket.send(chartMsg,true);
} }
// Trigger the indicator JsonAPIIndicator to check for new Messages // Trigger the indicator JsonAPIIndicator to check for new Messages
if(chartWindowTimerCounter >= chartWindowTimerInterval) for(int i=0; i<ArraySize(chartWindows); i++)
{ {
for(int i=0; i<ArraySize(chartWindows); i++) long chartId = chartWindows[i].id;
{ EventChartCustom(chartId, 222, 222, 222.0);
long ChartId = chartWindows[i].id;
EventChartCustom(ChartId, 222, 222, 222.0);
}
chartWindowTimerCounter = 0;
} }
else
chartWindowTimerCounter++;
} }
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
@@ -822,6 +813,7 @@ void OpenChart(CJAVal &dataObject)
CJAVal message; CJAVal message;
message["error"]=(bool) false; message["error"]=(bool) false;
message["chartId"] = (string) chartId; message["chartId"] = (string) chartId;
message["mtChartId"] = (string) chartWindows[idx].id;
string t=message.Serialize(); string t=message.Serialize();
if(debug) if(debug)
@@ -836,16 +828,16 @@ void AddChartIndicator(CJAVal &dataObject)
{ {
string chartIdStr=dataObject["chartId"].ToStr(); string chartIdStr=dataObject["chartId"].ToStr();
string chartIndicatorId=dataObject["indicatorChartId"].ToStr(); string chartIndicatorId=dataObject["chartIndicatorId"].ToStr();
int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt(); int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt();
//string shortname = dataObject["style"]["shortname"].ToStr(); string shortName = dataObject["shortName"].ToStr();
int chartIdx = GetChartWindowIdxByChartWindowId(chartIdStr); int chartIdx = GetChartWindowIdxByChartWindowId(chartIdStr);
long ChartId = chartWindows[chartIdx].id; long chartId = chartWindows[chartIdx].id;
double chartIndicatorHandle = iCustom(ChartSymbol(ChartId),ChartPeriod(ChartId),"JsonAPIIndicator",chartIndicatorId,"JsonAPI"); //linelabel,colorstyle,linetype,linestyle,linewidth); double chartIndicatorHandle = iCustom(ChartSymbol(chartId),ChartPeriod(chartId),"JsonAPIIndicator",chartIndicatorId,shortName); //linelabel,colorstyle,linetype,linestyle,linewidth);
if(ChartIndicatorAdd(ChartId, chartIndicatorSubWindow, chartIndicatorHandle)) if(ChartIndicatorAdd(chartId, chartIndicatorSubWindow, chartIndicatorHandle))
{ {
chartWindowIndicatorCount++; chartWindowIndicatorCount++;
ArrayResize(chartWindowIndicators,chartWindowIndicatorCount); ArrayResize(chartWindowIndicators,chartWindowIndicatorCount);
@@ -922,6 +914,32 @@ bool PushHistoricalData(CJAVal &data)
return true; return true;
} }
//+------------------------------------------------------------------+
//| Correct historical tick data |
//+------------------------------------------------------------------+
// Some brokers (markets.com) deliver incorrect historical tick data
// with an incorrect spread.
// This attempts to automatically adjust the
// historical tick data.
// Live bar data is also represented with the same, incorrect spread so we attempt
// to adjust historical tick data by that same amount.
void CorrectTicks(string symbol, MqlTick &copyTicksArray[])
{
MqlTick symbolInfoTick;
double offsetBid, offsetAsk;
int tickCount = ArraySize(copyTicksArray);
SymbolInfoTick(symbol,symbolInfoTick);
offsetBid = copyTicksArray[tickCount-1].bid - symbolInfoTick.bid;
offsetAsk = copyTicksArray[tickCount-1].ask - symbolInfoTick.ask;
for(int i=0; i<tickCount; i++)
{
copyTicksArray[i].bid = copyTicksArray[i].bid - offsetBid;
copyTicksArray[i].ask = copyTicksArray[i].ask - offsetAsk;
}
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Get historical data | //| Get historical data |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
@@ -931,6 +949,7 @@ void HistoryInfo(CJAVal &dataObject)
string actionType = dataObject["actionType"].ToStr(); string actionType = dataObject["actionType"].ToStr();
string chartTF = dataObject["chartTF"].ToStr(); string chartTF = dataObject["chartTF"].ToStr();
string symbol=dataObject["symbol"].ToStr(); string symbol=dataObject["symbol"].ToStr();
bool correctTickHistory=dataObject["correctTickHistory"].ToBool();
// Write CVS fle to local directory // Write CVS fle to local directory
if(actionType=="WRITE" && chartTF=="TICK") if(actionType=="WRITE" && chartTF=="TICK")
@@ -967,6 +986,8 @@ void HistoryInfo(CJAVal &dataObject)
CheckError(__FUNCTION__); CheckError(__FUNCTION__);
Print("Preparing data of ", tickCount, " ticks for ", symbol); Print("Preparing data of ", tickCount, " ticks for ", symbol);
if(correctTickHistory)
CorrectTicks(symbol,tickArray);
int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV); int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV);
if(file_handle!=INVALID_HANDLE) if(file_handle!=INVALID_HANDLE)
{ {
@@ -1092,6 +1113,8 @@ void HistoryInfo(CJAVal &dataObject)
tickCount=CopyTicksRange(symbol,tickArray, COPY_TICKS_ALL, 1000*(ulong)fromDateM, 1000*(ulong)toDateM); tickCount=CopyTicksRange(symbol,tickArray, COPY_TICKS_ALL, 1000*(ulong)fromDateM, 1000*(ulong)toDateM);
Print("Preparing tick data of ", tickCount, " ticks for ", symbol); Print("Preparing tick data of ", tickCount, " ticks for ", symbol);
if(correctTickHistory)
CorrectTicks(symbol,tickArray);
if(tickCount) if(tickCount)
{ {
for(int i=0; i<tickCount; i++) for(int i=0; i<tickCount; i++)
@@ -1099,6 +1122,7 @@ void HistoryInfo(CJAVal &dataObject)
data[i][0]=(long) tickArray[i].time_msc; data[i][0]=(long) tickArray[i].time_msc;
data[i][1]=(double) tickArray[i].bid; data[i][1]=(double) tickArray[i].bid;
data[i][2]=(double) tickArray[i].ask; data[i][2]=(double) tickArray[i].ask;
i++;
} }
d["data"].Set(data); d["data"].Set(data);
} }
@@ -1526,54 +1550,54 @@ ENUM_TIMEFRAMES GetTimeframe(string chartTF)
{ {
ENUM_TIMEFRAMES tf; ENUM_TIMEFRAMES tf;
tf=NULL;
if(chartTF=="TICK") if(chartTF=="TICK")
tf=PERIOD_CURRENT; tf=PERIOD_CURRENT;
else
if(chartTF=="M1") if(chartTF=="M1")
tf=PERIOD_M1; tf=PERIOD_M1;
else
if(chartTF=="M5") if(chartTF=="M5")
tf=PERIOD_M5; tf=PERIOD_M5;
else
if(chartTF=="M15") if(chartTF=="M15")
tf=PERIOD_M15; tf=PERIOD_M15;
else
if(chartTF=="M30") if(chartTF=="M30")
tf=PERIOD_M30; tf=PERIOD_M30;
else
if(chartTF=="H1") if(chartTF=="H1")
tf=PERIOD_H1; tf=PERIOD_H1;
else
if(chartTF=="H2") if(chartTF=="H2")
tf=PERIOD_H2; tf=PERIOD_H2;
else
if(chartTF=="H3") if(chartTF=="H3")
tf=PERIOD_H3; tf=PERIOD_H3;
else
if(chartTF=="H4") if(chartTF=="H4")
tf=PERIOD_H4; tf=PERIOD_H4;
else
if(chartTF=="H6") if(chartTF=="H6")
tf=PERIOD_H6; tf=PERIOD_H6;
else
if(chartTF=="H8") if(chartTF=="H8")
tf=PERIOD_H8; tf=PERIOD_H8;
else
if(chartTF=="H12") if(chartTF=="H12")
tf=PERIOD_H12; tf=PERIOD_H12;
else
if(chartTF=="D1") if(chartTF=="D1")
tf=PERIOD_D1; tf=PERIOD_D1;
else
if(chartTF=="W1") if(chartTF=="W1")
tf=PERIOD_W1; tf=PERIOD_W1;
else
if(chartTF=="MN1") if(chartTF=="MN1")
tf=PERIOD_MN1; tf=PERIOD_MN1;
//error will be raised in config function
else //if tf == NULL an error will be raised in config function
tf=NULL;
return(tf); return(tf);
} }
+359 -81
View File
@@ -21,24 +21,20 @@ Context context("MQL5 JSON API");
Socket chartSubscriptionSocket(context,ZMQ_SUB); Socket chartSubscriptionSocket(context,ZMQ_SUB);
//--- input parameters //--- input parameters
#property indicator_buffers 21 #property indicator_buffers 31
#property indicator_plots 20 #property indicator_plots 30
#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 IndicatorId="";
input string ShortName="JsonAPI"; input string ShortName="JsonAPIIndicator";
//--- indicator settings //--- indicator settings
double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[], B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], alive[]; double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[];
bool debug = true; double B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], B20[];
bool first = false; double B21[], B22[], B23[], B24[], B25[], B26[], B27[], B28[], B29[];
bool debug = false;
int activeBufferCount = 0; int activeBufferCount = 0;
long mtChartId = 0;
bool setFormingCandleBlank = true;
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Custom indicator initialization function | //| Custom indicator initialization function |
@@ -46,12 +42,7 @@ int activeBufferCount = 0;
int OnInit() int OnInit()
{ {
// TODO subscribe only to own IndicatorId topic
// Subscribe to all topics
chartSubscriptionSocket.setSubscribe("");
chartSubscriptionSocket.setLinger(1000);
// Number of messages to buffer in RAM.
chartSubscriptionSocket.setReceiveHighWaterMark(1000); // TODO confirm settings
bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT)); bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT));
if(result == false) if(result == false)
{ {
@@ -59,10 +50,17 @@ int OnInit()
} }
else else
{ {
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT); if(debug)
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT);
// TODO subscribe only to own IndicatorId topic
// Subscribe to all topics
chartSubscriptionSocket.setSubscribe("");
//chartSubscriptionSocket.setLinger(1000);
chartSubscriptionSocket.setLinger(10000);
// Number of messages to buffer in RAM.
chartSubscriptionSocket.setReceiveHighWaterMark(5); // TODO confirm settings
} }
//--- indicator buffers mapping; //--- indicator buffers mapping;
ArraySetAsSeries(B0,true); ArraySetAsSeries(B0,true);
ArraySetAsSeries(B1,true); ArraySetAsSeries(B1,true);
@@ -84,30 +82,47 @@ int OnInit()
ArraySetAsSeries(B17,true); ArraySetAsSeries(B17,true);
ArraySetAsSeries(B18,true); ArraySetAsSeries(B18,true);
ArraySetAsSeries(B19,true); ArraySetAsSeries(B19,true);
ArraySetAsSeries(alive,true); ArraySetAsSeries(B20,true);
ArraySetAsSeries(B21,true);
SetIndexBuffer(0,B0,INDICATOR_DATA); ArraySetAsSeries(B22,true);
SetIndexBuffer(1,B1,INDICATOR_DATA); ArraySetAsSeries(B23,true);
SetIndexBuffer(2,B2,INDICATOR_DATA); ArraySetAsSeries(B24,true);
SetIndexBuffer(3,B3,INDICATOR_DATA); ArraySetAsSeries(B25,true);
SetIndexBuffer(4,B4,INDICATOR_DATA); ArraySetAsSeries(B26,true);
SetIndexBuffer(5,B5,INDICATOR_DATA); ArraySetAsSeries(B27,true);
SetIndexBuffer(6,B6,INDICATOR_DATA); ArraySetAsSeries(B28,true);
SetIndexBuffer(7,B7,INDICATOR_DATA); ArraySetAsSeries(B29,true);
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
SetIndexBuffer(0,B0,INDICATOR_CALCULATIONS);
SetIndexBuffer(1,B1,INDICATOR_CALCULATIONS);
SetIndexBuffer(2,B2,INDICATOR_CALCULATIONS);
SetIndexBuffer(3,B3,INDICATOR_CALCULATIONS);
SetIndexBuffer(4,B4,INDICATOR_CALCULATIONS);
SetIndexBuffer(5,B5,INDICATOR_CALCULATIONS);
SetIndexBuffer(6,B6,INDICATOR_CALCULATIONS);
SetIndexBuffer(7,B7,INDICATOR_CALCULATIONS);
SetIndexBuffer(8,B8,INDICATOR_CALCULATIONS);
SetIndexBuffer(9,B9,INDICATOR_CALCULATIONS);
SetIndexBuffer(10,B10,INDICATOR_CALCULATIONS);
SetIndexBuffer(11,B11,INDICATOR_CALCULATIONS);
SetIndexBuffer(12,B12,INDICATOR_CALCULATIONS);
SetIndexBuffer(13,B13,INDICATOR_CALCULATIONS);
SetIndexBuffer(14,B14,INDICATOR_CALCULATIONS);
SetIndexBuffer(15,B15,INDICATOR_CALCULATIONS);
SetIndexBuffer(16,B16,INDICATOR_CALCULATIONS);
SetIndexBuffer(17,B17,INDICATOR_CALCULATIONS);
SetIndexBuffer(18,B18,INDICATOR_CALCULATIONS);
SetIndexBuffer(19,B19,INDICATOR_CALCULATIONS);
SetIndexBuffer(20,B20,INDICATOR_CALCULATIONS);
SetIndexBuffer(21,B21,INDICATOR_CALCULATIONS);
SetIndexBuffer(22,B22,INDICATOR_CALCULATIONS);
SetIndexBuffer(23,B23,INDICATOR_CALCULATIONS);
SetIndexBuffer(24,B24,INDICATOR_CALCULATIONS);
SetIndexBuffer(25,B25,INDICATOR_CALCULATIONS);
SetIndexBuffer(26,B26,INDICATOR_CALCULATIONS);
SetIndexBuffer(27,B27,INDICATOR_CALCULATIONS);
SetIndexBuffer(28,B28,INDICATOR_CALCULATIONS);
SetIndexBuffer(29,B29,INDICATOR_CALCULATIONS);
//--- //---
IndicatorSetString(INDICATOR_SHORTNAME,ShortName); IndicatorSetString(INDICATOR_SHORTNAME,ShortName);
@@ -115,6 +130,14 @@ int OnInit()
return(INIT_SUCCEEDED); return(INIT_SUCCEEDED);
} }
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Print("INDI DEINIT ",reason);
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| | //| |
@@ -142,9 +165,11 @@ 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 && setFormingCandleBlank)
{ {
B0[0] = EMPTY_VALUE; B0[0] = EMPTY_VALUE;
B1[0] = EMPTY_VALUE; B1[0] = EMPTY_VALUE;
@@ -166,10 +191,17 @@ int OnCalculate(const int rates_total,
B17[0] = EMPTY_VALUE; B17[0] = EMPTY_VALUE;
B18[0] = EMPTY_VALUE; B18[0] = EMPTY_VALUE;
B19[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 value of prev_calculated for next call
return(rates_total); return(rates_total);
@@ -191,52 +223,163 @@ void SubscriptionHandler(ZmqMsg &chartMsg)
Alert("Deserialization Error"); Alert("Deserialization Error");
ExpertRemove(); ExpertRemove();
} }
if(message["indicatorChartId"]==IndicatorId) if(message["chartIndicatorId"]==IndicatorId)
{ {
if(message["action"]=="PLOT" && message["actionType"]=="DATA") if(message["action"]=="PLOT" && message["actionType"]=="DATA")
{ {
int bufferIdx = message["indicatorBufferId"].ToInt(); int bufferIdx = message["indicatorBufferId"].ToInt();
if(bufferIdx == 0) if(bufferIdx == 0)
{
WriteToBuffer(message, B0); WriteToBuffer(message, B0);
SetIndexBuffer(0,B0,INDICATOR_DATA);
}
if(bufferIdx == 1) if(bufferIdx == 1)
{
WriteToBuffer(message, B1); WriteToBuffer(message, B1);
SetIndexBuffer(1,B1,INDICATOR_DATA);
}
if(bufferIdx == 2) if(bufferIdx == 2)
{
WriteToBuffer(message, B2); WriteToBuffer(message, B2);
SetIndexBuffer(2,B2,INDICATOR_DATA);
}
if(bufferIdx == 3) if(bufferIdx == 3)
{
WriteToBuffer(message, B3); WriteToBuffer(message, B3);
SetIndexBuffer(3,B3,INDICATOR_DATA);
}
if(bufferIdx == 4) if(bufferIdx == 4)
{
WriteToBuffer(message, B4); WriteToBuffer(message, B4);
SetIndexBuffer(4,B4,INDICATOR_DATA);
}
if(bufferIdx == 5) if(bufferIdx == 5)
{
WriteToBuffer(message, B5); WriteToBuffer(message, B5);
SetIndexBuffer(5,B5,INDICATOR_DATA);
}
if(bufferIdx == 6) if(bufferIdx == 6)
{
WriteToBuffer(message, B6); WriteToBuffer(message, B6);
SetIndexBuffer(6,B6,INDICATOR_DATA);
}
if(bufferIdx == 7) if(bufferIdx == 7)
{
WriteToBuffer(message, B7); WriteToBuffer(message, B7);
SetIndexBuffer(7,B7,INDICATOR_DATA);
}
if(bufferIdx == 8) if(bufferIdx == 8)
{
WriteToBuffer(message, B8); WriteToBuffer(message, B8);
SetIndexBuffer(8,B8,INDICATOR_DATA);
}
if(bufferIdx == 9) if(bufferIdx == 9)
{
WriteToBuffer(message, B9); WriteToBuffer(message, B9);
SetIndexBuffer(9,B9,INDICATOR_DATA);
}
if(bufferIdx == 10) if(bufferIdx == 10)
{
WriteToBuffer(message, B10); WriteToBuffer(message, B10);
SetIndexBuffer(10,B10,INDICATOR_DATA);
}
if(bufferIdx == 11) if(bufferIdx == 11)
{
WriteToBuffer(message, B11); WriteToBuffer(message, B11);
SetIndexBuffer(11,B11,INDICATOR_DATA);
}
if(bufferIdx == 12) if(bufferIdx == 12)
{
WriteToBuffer(message, B12); WriteToBuffer(message, B12);
SetIndexBuffer(12,B12,INDICATOR_DATA);
}
if(bufferIdx == 13) if(bufferIdx == 13)
{
WriteToBuffer(message, B13); WriteToBuffer(message, B13);
SetIndexBuffer(13,B13,INDICATOR_DATA);
}
if(bufferIdx == 14) if(bufferIdx == 14)
{
WriteToBuffer(message, B14); WriteToBuffer(message, B14);
SetIndexBuffer(14,B14,INDICATOR_DATA);
}
if(bufferIdx == 15) if(bufferIdx == 15)
{
WriteToBuffer(message, B15); WriteToBuffer(message, B15);
SetIndexBuffer(15,B15,INDICATOR_DATA);
}
if(bufferIdx == 16) if(bufferIdx == 16)
{
WriteToBuffer(message, B16); WriteToBuffer(message, B16);
SetIndexBuffer(16,B16,INDICATOR_DATA);
}
if(bufferIdx == 17) if(bufferIdx == 17)
{
WriteToBuffer(message, B17); WriteToBuffer(message, B17);
SetIndexBuffer(17,B17,INDICATOR_DATA);
}
if(bufferIdx == 18) if(bufferIdx == 18)
{
WriteToBuffer(message, B18); WriteToBuffer(message, B18);
SetIndexBuffer(18,B18,INDICATOR_DATA);
}
if(bufferIdx == 19) if(bufferIdx == 19)
{
WriteToBuffer(message, B19); WriteToBuffer(message, B19);
SetIndexBuffer(19,B19,INDICATOR_DATA);
}
if(bufferIdx == 20)
{
WriteToBuffer(message, B20);
SetIndexBuffer(20,B20,INDICATOR_DATA);
}
if(bufferIdx == 21)
{
WriteToBuffer(message, B21);
SetIndexBuffer(21,B21,INDICATOR_DATA);
}
if(bufferIdx == 22)
{
WriteToBuffer(message, B22);
SetIndexBuffer(22,B22,INDICATOR_DATA);
}
if(bufferIdx == 23)
{
WriteToBuffer(message, B23);
SetIndexBuffer(23,B23,INDICATOR_DATA);
}
if(bufferIdx == 24)
{
WriteToBuffer(message, B24);
SetIndexBuffer(24,B24,INDICATOR_DATA);
}
if(bufferIdx == 25)
{
WriteToBuffer(message, B25);
SetIndexBuffer(25,B25,INDICATOR_DATA);
}
if(bufferIdx == 26)
{
WriteToBuffer(message, B26);
SetIndexBuffer(26,B26,INDICATOR_DATA);
}
if(bufferIdx == 27)
{
WriteToBuffer(message, B27);
SetIndexBuffer(27,B27,INDICATOR_DATA);
}
if(bufferIdx == 28)
{
WriteToBuffer(message, B28);
SetIndexBuffer(28,B28,INDICATOR_DATA);
}
if(bufferIdx == 29)
{
WriteToBuffer(message, B29);
SetIndexBuffer(29,B29,INDICATOR_DATA);
}
ChartRedraw(mtChartId);
} }
else else
if(message["action"]=="PLOT" && message["actionType"]=="ADDBUFFER") if(message["action"]=="PLOT" && message["actionType"]=="ADDBUFFER")
@@ -246,30 +389,165 @@ void SubscriptionHandler(ZmqMsg &chartMsg)
string linetypeStr = message["style"]["linetype"].ToStr(); string linetypeStr = message["style"]["linetype"].ToStr();
string linestyleStr = message["style"]["linestyle"].ToStr(); string linestyleStr = message["style"]["linestyle"].ToStr();
int linewidth = message["style"]["linewidth"].ToInt(); int linewidth = message["style"]["linewidth"].ToInt();
setFormingCandleBlank = message["style"]["blankforming"].ToBool();
color colorstyle = StringToColor(colorstyleStr); color colorstyle = StringToColor(colorstyleStr);
int linetype = StringToEnumInt(linetypeStr); int linetype = StringToEnumInt(linetypeStr);
int linestyle = StringToEnumInt(linestyleStr); 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); SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
activeBufferCount = activeBufferCount + 1; activeBufferCount = activeBufferCount + 1;
ClearBuffer(activeBufferCount-1);
} }
} }
} }
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Clear(double &buffer[])
{
int bufferSize = ArraySize(buffer);
for(int i=0; i<bufferSize; i++)
{
buffer[i] = EMPTY_VALUE;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ClearBuffer(int bufferIdx)
{
switch(bufferIdx)
{
case 0:
{
Clear(B0);
}
case 1:
{
Clear(B1);
}
case 2:
{
Clear(B2);
}
case 3:
{
Clear(B3);
}
case 4:
{
Clear(B4);
}
case 5:
{
Clear(B5);
}
case 6:
{
Clear(B6);
}
case 7:
{
Clear(B7);
}
case 8:
{
Clear(B8);
}
case 9:
{
Clear(B9);
}
case 10:
{
Clear(B10);
}
case 11:
{
Clear(B11);
}
case 12:
{
Clear(B12);
}
case 13:
{
Clear(B13);
}
case 14:
{
Clear(B14);
}
case 15:
{
Clear(B15);
}
case 16:
{
Clear(B16);
}
case 17:
{
Clear(B17);
}
case 18:
{
Clear(B18);
}
case 19:
{
Clear(B19);
}
case 20:
{
Clear(B20);
}
case 21:
{
Clear(B21);
}
case 22:
{
Clear(B22);
}
case 23:
{
Clear(B23);
}
case 24:
{
Clear(B24);
}
case 25:
{
Clear(B25);
}
case 26:
{
Clear(B26);
}
case 27:
{
Clear(B27);
}
case 28:
{
Clear(B28);
}
case 29:
{
Clear(B29);
}
break;
default:
{} break;
}
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Update indicator buffer function | //| Update indicator buffer function |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
@@ -277,32 +555,32 @@ 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
if(first==false)
{
for(int i=0; i<activeBufferCount; i++)
{
//Print("BUFF ",bufferSize-messageDataSize, " ",ArraySize(B2)," ", ArraySize(B3), " ",messageDataSize);
PlotIndexSetInteger(i,PLOT_DRAW_BEGIN,bufferSize-messageDataSize);
}
first = true;
}
// calculate the buffer offset
MqlRates r[];
mtChartId =(datetime)message["mtChartId"].ToInt();
datetime fromDate=(datetime)message["fromDate"].ToInt();
datetime toDate=TimeCurrent();
ENUM_TIMEFRAMES period = ChartPeriod(mtChartId);
string symbol = ChartSymbol(mtChartId);
int rateCount;
rateCount = CopyRates(symbol, period, fromDate, toDate, r);
int offset = rateCount - 1;
// write to buffer
for(int i=0; i<messageDataSize; i++) for(int i=0; i<messageDataSize; i++)
{ {
// don't add more elements than the automatically sized buffer array can hold // don't add more elements than the automatically sized buffer array can
if(i+1<bufferSize) if(i+offset<bufferSize)
{ {
// the first element is the current unformed candle, so we start at index 1 double val = message["data"][i].ToDbl();
// we reverse the order of the incoming values, which are expected to be ascending if(val >= EMPTY_VALUE)
//buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl(); val = EMPTY_VALUE;
buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl(); buffer[i+offset] = val;
} }
} }
// Set the most recent plotted value to nothing, as we do not have any data for yet unformed candles
buffer[0] = EMPTY_VALUE;
} }