4 Commits

Author SHA1 Message Date
Gunther Schulz 1c47fc12d1 fix bug tthat every second tick was dropped
Every other tick used to be dropped before this fix, because of incrementing the counter twice in a loop
2020-11-22 13:24:09 +01:00
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
8 changed files with 1128 additions and 1469 deletions
-8
View File
@@ -1,10 +1,2 @@
.DS_Store .DS_Store
*.mq5:CursorPos:$DATA
*.mq5:LineFlags:$DATA
*.mqh:CursorPos:$DATA
*.mqh:LineFlags:$DATA
+1023 -63
View File
File diff suppressed because it is too large Load Diff
-316
View File
@@ -1,316 +0,0 @@
//+------------------------------------------------------------------+
//| Broker.mqh |
//| Gunther Schulz |
//| https://github.com/khramkov/MQL5-JSON-API |
//+------------------------------------------------------------------+
#property copyright "Gunther Schulz"
#property link "https://github.com/khramkov/MQL5-JSON-API"
//+------------------------------------------------------------------+
//| Fetch positions information |
//+------------------------------------------------------------------+
void GetPositions(CJAVal &dataObject)
{
CPositionInfo myposition;
CJAVal data, position;
// Get positions
int positionsTotal=PositionsTotal();
// Create empty array if no positions
if(!positionsTotal)
data["positions"].Add(position);
// Go through positions in a loop
for(int i=0; i<positionsTotal; i++)
{
mControl.mResetLastError();
if(myposition.Select(PositionGetSymbol(i)))
{
position["id"]=PositionGetInteger(POSITION_IDENTIFIER);
position["magic"]=PositionGetInteger(POSITION_MAGIC);
position["symbol"]=PositionGetString(POSITION_SYMBOL);
position["type"]=EnumToString(ENUM_POSITION_TYPE(PositionGetInteger(POSITION_TYPE)));
position["time_setup"]=PositionGetInteger(POSITION_TIME);
position["open"]=PositionGetDouble(POSITION_PRICE_OPEN);
position["stoploss"]=PositionGetDouble(POSITION_SL);
position["takeprofit"]=PositionGetDouble(POSITION_TP);
position["volume"]=PositionGetDouble(POSITION_VOLUME);
data["error"]=(bool) false;
data["positions"].Add(position);
}
CheckError(__FUNCTION__);
}
string t=data.Serialize();
if(debug)
Print(t);
InformClientSocket(dataSocket,t);
}
//+------------------------------------------------------------------+
//| Fetch orders information |
//+------------------------------------------------------------------+
void GetOrders(CJAVal &dataObject)
{
mControl.mResetLastError();
COrderInfo myorder;
CJAVal data, order;
// Get orders
if(HistorySelect(0,TimeCurrent()))
{
int ordersTotal = OrdersTotal();
// Create empty array if no orders
if(!ordersTotal)
{
data["error"]=(bool) false;
data["orders"].Add(order);
}
for(int i=0; i<ordersTotal; i++)
{
if(myorder.Select(OrderGetTicket(i)))
{
order["id"]=(string) myorder.Ticket();
order["magic"]=OrderGetInteger(ORDER_MAGIC);
order["symbol"]=OrderGetString(ORDER_SYMBOL);
order["type"]=EnumToString(ENUM_ORDER_TYPE(OrderGetInteger(ORDER_TYPE)));
order["time_setup"]=OrderGetInteger(ORDER_TIME_SETUP);
order["open"]=OrderGetDouble(ORDER_PRICE_OPEN);
order["stoploss"]=OrderGetDouble(ORDER_SL);
order["takeprofit"]=OrderGetDouble(ORDER_TP);
order["volume"]=OrderGetDouble(ORDER_VOLUME_INITIAL);
data["error"]=(bool) false;
data["orders"].Add(order);
}
// Error handling
CheckError(__FUNCTION__);
}
}
string t=data.Serialize();
if(debug)
Print(t);
InformClientSocket(dataSocket,t);
}
//+------------------------------------------------------------------+
//| Trading module |
//+------------------------------------------------------------------+
void TradingModule(CJAVal &dataObject)
{
mControl.mResetLastError();
CTrade trade;
string actionType = dataObject["actionType"].ToStr();
string symbol=dataObject["symbol"].ToStr();
SymbolInfoString(symbol, SYMBOL_DESCRIPTION);
CheckError(__FUNCTION__);
int idNimber=dataObject["id"].ToInt();
double volume=dataObject["volume"].ToDbl();
double SL=dataObject["stoploss"].ToDbl();
double TP=dataObject["takeprofit"].ToDbl();
double price=NormalizeDouble(dataObject["price"].ToDbl(),_Digits);
double deviation=dataObject["deviation"].ToDbl();
string comment=dataObject["comment"].ToStr();
// Order expiration section
ENUM_ORDER_TYPE_TIME exp_type = ORDER_TIME_GTC;
datetime expiration = 0;
if(dataObject["expiration"].ToInt() != 0)
{
exp_type = ORDER_TIME_SPECIFIED;
expiration=dataObject["expiration"].ToInt();
}
// Market orders
if(actionType=="ORDER_TYPE_BUY" || actionType=="ORDER_TYPE_SELL")
{
ENUM_ORDER_TYPE orderType=ORDER_TYPE_BUY;
price = SymbolInfoDouble(symbol,SYMBOL_ASK);
if(actionType=="ORDER_TYPE_SELL")
{
orderType=ORDER_TYPE_SELL;
price=SymbolInfoDouble(symbol,SYMBOL_BID);
}
if(trade.PositionOpen(symbol,orderType,volume,price,SL,TP,comment))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Pending orders
else
if(actionType=="ORDER_TYPE_BUY_LIMIT" || actionType=="ORDER_TYPE_SELL_LIMIT" || actionType=="ORDER_TYPE_BUY_STOP" || actionType=="ORDER_TYPE_SELL_STOP")
{
if(actionType=="ORDER_TYPE_BUY_LIMIT")
{
if(trade.BuyLimit(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
else
if(actionType=="ORDER_TYPE_SELL_LIMIT")
{
if(trade.SellLimit(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
else
if(actionType=="ORDER_TYPE_BUY_STOP")
{
if(trade.BuyStop(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
else
if(actionType=="ORDER_TYPE_SELL_STOP")
{
if(trade.SellStop(volume,price,symbol,SL,TP,ORDER_TIME_GTC,expiration,comment))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
}
// Position modify
else
if(actionType=="POSITION_MODIFY")
{
if(trade.PositionModify(idNimber,SL,TP))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Position close partial
else
if(actionType=="POSITION_PARTIAL")
{
if(trade.PositionClosePartial(idNimber,volume))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Position close by id
else
if(actionType=="POSITION_CLOSE_ID")
{
if(trade.PositionClose(idNimber))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Position close by symbol
else
if(actionType=="POSITION_CLOSE_SYMBOL")
{
if(trade.PositionClose(symbol))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Modify pending order
else
if(actionType=="ORDER_MODIFY")
{
if(trade.OrderModify(idNimber,price,SL,TP,ORDER_TIME_GTC,expiration))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Cancel pending order
else
if(actionType=="ORDER_CANCEL")
{
if(trade.OrderDelete(idNimber))
{
OrderDoneOrError(false, __FUNCTION__, trade);
return;
}
}
// Action type dosen't exist
else
{
mControl.mSetUserError(65538, GetErrorID(65538));
CheckError(__FUNCTION__);
}
// This part of the code runs if order was not completed
OrderDoneOrError(true, __FUNCTION__, trade);
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
const MqlTradeRequest &request,
const MqlTradeResult &result)
{
ENUM_TRADE_TRANSACTION_TYPE trans_type=trans.type;
switch(trans.type)
{
case TRADE_TRANSACTION_REQUEST:
{
CJAVal data, req, res;
req["action"]=EnumToString(request.action);
req["order"]=(int) request.order;
req["symbol"]=(string) request.symbol;
req["volume"]=(double) request.volume;
req["price"]=(double) request.price;
req["stoplimit"]=(double) request.stoplimit;
req["sl"]=(double) request.sl;
req["tp"]=(double) request.tp;
req["deviation"]=(int) request.deviation;
req["type"]=EnumToString(request.type);
req["type_filling"]=EnumToString(request.type_filling);
req["type_time"]=EnumToString(request.type_time);
req["expiration"]=(int) request.expiration;
req["comment"]=(string) request.comment;
req["position"]=(int) request.position;
req["position_by"]=(int) request.position_by;
res["retcode"]=(int) result.retcode;
res["result"]=(string) GetRetcodeID(result.retcode);
res["deal"]=(int) result.order;
res["order"]=(int) result.order;
res["volume"]=(double) result.volume;
res["price"]=(double) result.price;
res["comment"]=(string) result.comment;
res["request_id"]=(int) result.request_id;
res["retcode_external"]=(int) result.retcode_external;
data["request"].Set(req);
data["result"].Set(res);
string t=data.Serialize();
if(debug)
Print(t);
InformClientSocket(streamSocket,t);
}
break;
default:
{} break;
}
}
//+------------------------------------------------------------------+
-145
View File
@@ -1,145 +0,0 @@
//+------------------------------------------------------------------+
//| ChartControl.mqh |
//| Gunther Schulz |
//| https://github.com/khramkov/MQL5-JSON-API |
//+------------------------------------------------------------------+
// EXPERIMENTAL - DO NOT USE ;)
#property copyright "Gunther Schulz"
#property link "https://github.com/khramkov/MQL5-JSON-API"
#define CHART_CONTROL true
int CHART_DATA_PORT=15560;
int CHART_INDICATOR_DATA_PORT=15562;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Socket chartDataSocket(context,ZMQ_PULL);
Socket chartIndicatorDataSocket(context,ZMQ_PUB);
// Variables for controlling chart
struct ChartWindow
{
long id; // Internal id
string chartId; // UUID
};
ChartWindow chartWindows[];
int chartWindowCount = 0;
struct ChartWindowIndicator
{
long id; // Internal id
string indicatorId; // UUID
int indicatorHandle; // Internal id/handle
};
ChartWindowIndicator chartWindowIndicators[];
int chartWindowIndicatorCount = 0;
//+----------------------------------------------------------------------+
//| Function return index of chart window array by chart window id string|
//+----------------------------------------------------------------------+
int GetChartWindowIdxByChartWindowId(string chartWindowId)
{
for(int i=0; i<chartWindowCount; i++)
{
if(chartWindows[i].chartId == chartWindowId)
{
return i;
}
}
return -1;
}
//+------------------------------------------------------------------+
//| Open new chart or add indicator to chart |
//+------------------------------------------------------------------+
void ChartControl(CJAVal &dataObject)
{
string actionType=dataObject["actionType"].ToStr();
if(actionType=="ADDINDICATOR")
{
AddChartIndicator(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);
int idx = chartWindowCount-1;
chartWindows[idx].chartId = chartId;
ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
chartWindows[idx].id = ChartOpen(symbol, period);
ChartSetInteger(chartWindows[idx].id, CHART_AUTOSCROLL, false);
CJAVal message;
message["error"]=(bool) false;
message["chartId"] = (string) chartId;
message["mtChartId"] = (string) chartWindows[idx].id;
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(dataSocket,t);
}
//+------------------------------------------------------------------+
//| Add JsonAPIIndicator indicator to chart |
//+------------------------------------------------------------------+
void AddChartIndicator(CJAVal &dataObject)
{
string chartIdStr=dataObject["chartId"].ToStr();
string chartIndicatorId=dataObject["chartIndicatorId"].ToStr();
int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt();
string shortName = dataObject["shortName"].ToStr();
int chartIdx = GetChartWindowIdxByChartWindowId(chartIdStr);
long chartId = chartWindows[chartIdx].id;
double chartIndicatorHandle = iCustom(ChartSymbol(chartId),ChartPeriod(chartId),"JsonAPIIndicator",chartIndicatorId,shortName); //linelabel,colorstyle,linetype,linestyle,linewidth);
if(ChartIndicatorAdd(chartId, chartIndicatorSubWindow, chartIndicatorHandle))
{
chartWindowIndicatorCount++;
ArrayResize(chartWindowIndicators,chartWindowIndicatorCount);
int indicatorIdx = chartWindowIndicatorCount-1;
chartWindowIndicators[indicatorIdx].indicatorId = chartIndicatorId;
chartWindowIndicators[indicatorIdx].indicatorHandle = chartIndicatorHandle;
}
if(!CheckError(__FUNCTION__))
{
CJAVal message;
message["error"]=(bool) false;
message["chartId"] = (string) chartIdStr;
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(dataSocket,t);
}
}
//+------------------------------------------------------------------+
-307
View File
@@ -1,307 +0,0 @@
//+------------------------------------------------------------------+
//| HistoryInfo.mqh |
//| Gunther Schulz |
//| https://github.com/khramkov/MQL5-JSON-API |
//+------------------------------------------------------------------+
#property copyright "Gunther Schulz"
#property link "https://github.com/khramkov/MQL5-JSON-API"
//+------------------------------------------------------------------+
//| Get historical data |
//+------------------------------------------------------------------+
void HistoryInfo(CJAVal &dataObject)
{
string actionType = dataObject["actionType"].ToStr();
string chartTF = dataObject["chartTF"].ToStr();
string symbol=dataObject["symbol"].ToStr();
// bool correctTickHistory=dataObject["correctTickHistory"].ToBool();
// Write CVS fle to local directory
if(actionType=="WRITE" && chartTF=="TICK")
{
CJAVal data, d, msg;
MqlTick tickArray[];
string fileName=symbol + "-" + chartTF + ".csv"; // file name
string directoryName="Data"; // directory name
string outputFile=directoryName+"\\"+fileName;
ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
datetime toDate=TimeCurrent();
if(dataObject["toDate"].ToInt()!=NULL)
toDate=(datetime)dataObject["toDate"].ToInt();
Print("Fetching HISTORY");
Print("1) Symbol: "+symbol);
Print("2) Timeframe: Ticks");
Print("3) Date from: "+TimeToString(fromDate));
if(dataObject["toDate"].ToInt()!=NULL)
Print("4) Date to:"+TimeToString(toDate));
int tickCount = 0;
ulong fromDateM = StringToTime(fromDate);
ulong toDateM = StringToTime(toDate);
tickCount=CopyTicksRange(symbol,tickArray,COPY_TICKS_ALL,1000*(ulong)fromDateM,1000*(ulong)toDateM);
if(tickCount < 0)
{
mControl.mSetUserError(65541, GetErrorID(65541));
}
CheckError(__FUNCTION__);
Print("Preparing data of ", tickCount, " ticks for ", symbol);
/*
if(correctTickHistory)
CorrectTicks(symbol,tickArray);
*/
int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV);
if(file_handle!=INVALID_HANDLE)
{
msg["status"] = (string) "CONNECTED";
msg["type"] = (string) "NORMAL";
msg["data"] = (string) StringFormat("Writing to: %s\\%s", TerminalInfoString(TERMINAL_DATA_PATH), outputFile);
if(liveStream)
InformClientSocket(liveSocket, msg.Serialize());
ActionDoneOrError(ERR_SUCCESS, __FUNCTION__, "ERR_SUCCESS");
//ActionDoneOrError(ERR_SUCCESS , __FUNCTION__, dataSocket);
// Inform client that file is avalable for writing
PrintFormat("%s file is available for writing",fileName);
PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
//--- write the time and values of signals to the file
for(int i=0; i<tickCount; i++)
{
FileWrite(file_handle,tickArray[i].time_msc, ",", tickArray[i].bid, ",", tickArray[i].ask);
msg["status"] = (string) "CONNECTED";
msg["type"] = (string) "FLUSH";
msg["data"] = (string) tickArray[i].time_msc;
if(liveStream)
InformClientSocket(liveSocket, msg.Serialize());
}
//--- close the file
FileClose(file_handle);
PrintFormat("Data is written, %s file is closed",fileName);
msg["status"] = (string) "DISCONNECTED";
msg["type"] = (string) "NORMAL";
msg["data"] = (string) StringFormat("Writing to: %s\\%s", outputFile, " is finished");
if(liveStream)
InformClientSocket(liveSocket, msg.Serialize());
}
else
{
// File is not available for writing
mControl.mSetUserError(65542, GetErrorID(65542));
CheckError(__FUNCTION__);
}
connectedFlag=false;
}
// Write CVS fle to local directory
else
if(actionType=="WRITE" && chartTF!="TICK")
{
CJAVal c, d;
MqlRates r[];
int spread[];
string fileName=symbol + "-" + chartTF + ".csv"; // file name
string directoryName="Data"; // directory name
string outputFile=directoryName+"//"+fileName;
int barCount;
ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
datetime toDate=TimeCurrent();
if(dataObject["toDate"].ToInt()!=NULL)
toDate=(datetime)dataObject["toDate"].ToInt();
Print("Fetching HISTORY");
Print("1) Symbol :"+symbol);
Print("2) Timeframe :"+EnumToString(period));
Print("3) Date from :"+TimeToString(fromDate));
if(dataObject["toDate"].ToInt()!=NULL)
Print("4) Date to:"+TimeToString(toDate));
barCount=CopyRates(symbol,period,fromDate,toDate,r);
if(CopySpread(symbol,period, fromDate, toDate, spread)!=1)
{
mControl.mSetUserError(65541, GetErrorID(65541));
}
Print("Preparing tick data of ", barCount, " ticks for ", symbol);
int file_handle=FileOpen(outputFile, FILE_WRITE | FILE_CSV);
if(file_handle!=INVALID_HANDLE)
{
ActionDoneOrError(ERR_SUCCESS, __FUNCTION__, "ERR_SUCCESS");;
PrintFormat("%s file is available for writing",outputFile);
PrintFormat("File path: %s\\Files\\",TerminalInfoString(TERMINAL_DATA_PATH));
//--- write the time and values of signals to the file
for(int i=0; i<barCount; i++)
FileWrite(file_handle,r[i].time, ",", r[i].open, ",", r[i].high, ",", r[i].low, ",", r[i].close, ",", r[i].tick_volume, spread[i]);
//--- close the file
FileClose(file_handle);
PrintFormat("Data is written, %s file is closed", outputFile);
}
else
{
mControl.mSetUserError(65542, GetErrorID(65542));
CheckError(__FUNCTION__);
}
}
else
if(actionType=="DATA" && chartTF=="TICK")
{
CJAVal data, d;
MqlTick tickArray[];
ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
datetime toDate=TimeCurrent();
if(dataObject["toDate"].ToInt()!=NULL)
toDate=(datetime)dataObject["toDate"].ToInt();
if(debug)
{
Print("Fetching HISTORY");
Print("1) Symbol: "+symbol);
Print("2) Timeframe: Ticks");
Print("3) Date from: "+TimeToString(fromDate));
if(dataObject["toDate"].ToInt()!=NULL)
Print("4) Date to:"+TimeToString(toDate));
}
int tickCount = 0;
ulong fromDateM = StringToTime(fromDate);
ulong toDateM = StringToTime(toDate);
tickCount=CopyTicksRange(symbol,tickArray, COPY_TICKS_ALL, 1000*(ulong)fromDateM, 1000*(ulong)toDateM);
Print("Preparing tick data of ", tickCount, " ticks for ", symbol);
/*
if(correctTickHistory)
CorrectTicks(symbol,tickArray);
*/
if(tickCount)
{
for(int i=0; i<tickCount; i++)
{
data[i][0]=(long) tickArray[i].time_msc;
data[i][1]=(double) tickArray[i].bid;
data[i][2]=(double) tickArray[i].ask;
}
d["data"].Set(data);
}
else
{
d["data"].Add(data);
}
Print("Finished preparing tick data");
d["symbol"]=symbol;
d["timeframe"]=chartTF;
PushHistoricalData(d);
}
else
if(actionType=="DATA" && chartTF!="TICK")
{
CJAVal c, d;
MqlRates r[];
int spread[];
int barCount=0;
ENUM_TIMEFRAMES period=GetTimeframe(chartTF);
datetime fromDate=(datetime)dataObject["fromDate"].ToInt();
datetime toDate=TimeCurrent();
if(dataObject["toDate"].ToInt()!=NULL)
toDate=(datetime)dataObject["toDate"].ToInt();
if(debug)
{
Print("Fetching HISTORY");
Print("1) Symbol :"+symbol);
Print("2) Timeframe :"+EnumToString(period));
Print("3) Date from :"+TimeToString(fromDate));
if(dataObject["toDate"].ToInt()!=NULL)
Print("4) Date to:"+TimeToString(toDate));
}
barCount=CopyRates(symbol, period, fromDate, toDate, r);
if(CopySpread(symbol,period, fromDate, toDate, spread)!=1) { /*mControl.Check();*/ }
if(barCount)
{
for(int i=0; i<barCount; i++)
{
c[i][0]=(long) r[i].time;
c[i][1]=(double) r[i].open;
c[i][2]=(double) r[i].high;
c[i][3]=(double) r[i].low;
c[i][4]=(double) r[i].close;
c[i][5]=(double) r[i].tick_volume;
c[i][6]=(int) spread[i];
}
d["data"].Set(c);
}
else
{
d["data"].Add(c);
}
d["symbol"]=symbol;
d["timeframe"]=chartTF;
PushHistoricalData(d);
}
else
if(actionType=="TRADES")
{
CDealInfo tradeInfo;
CJAVal trades, data;
if(HistorySelect(0,TimeCurrent()))
{
// Get total deals in history
int total = HistoryDealsTotal();
ulong ticket; // deal ticket
for(int i=0; i<total; i++)
{
if((ticket=HistoryDealGetTicket(i))>0)
{
tradeInfo.Ticket(ticket);
data["ticket"]=(long) tradeInfo.Ticket();
data["time"]=(long) tradeInfo.Time();
data["price"]=(double) tradeInfo.Price();
data["volume"]=(double) tradeInfo.Volume();
data["symbol"]=(string) tradeInfo.Symbol();
data["type"]=(string) tradeInfo.TypeDescription();
data["entry"]=(long) tradeInfo.Entry();
data["profit"]=(double) tradeInfo.Profit();
trades["trades"].Add(data);
}
}
}
else
{
trades["trades"].Add(data);
}
string t=trades.Serialize();
if(debug)
Print(t);
InformClientSocket(dataSocket,t);
}
else
{
mControl.mSetUserError(65538, GetErrorID(65538));
CheckError(__FUNCTION__);
}
}
//+------------------------------------------------------------------+
-244
View File
@@ -1,244 +0,0 @@
//+------------------------------------------------------------------+
//| StartIndicator.mqh |
//| Gunther Schulz |
//| https://github.com/khramkov/MQL5-JSON-API |
//+------------------------------------------------------------------+
#property copyright "Gunther Schulz"
#property link "https://github.com/khramkov/MQL5-JSON-API"
#define START_INDICATOR true
int INDICATOR_DATA_PORT=15559;
Socket indicatorDataSocket(context,ZMQ_PUSH);
struct Indicator
{
long id; // Internal id
string indicatorId; // UUID
int indicatorHandle; // Internal id/handle
int indicatorParamCount; // Number of parameters to be passed to the indicator
int indicatorBufferCount; // Numnber of buffers to be returned bythe indicator
};
Indicator indicators[];
int indicatorCount = 0;
//+------------------------------------------------------------------+
//| Check if string is a representation of a number |
//+------------------------------------------------------------------+
bool IsNumberAsString(string str)
{
// MQL5 seems to return true if the values are the same, no matter the data type, in this case comparing str and dbl/int.
// (str "2.1" == double 2.1) will return true.
double dbl = StringToDouble(str);
int integer = StringToInteger(str);
// Compaing to both int and double to cover both cases
if(str==dbl || str==integer)
return true;
else
return false;
}
//+------------------------------------------------------------------+
//| Get index of indicator handler array by indicator id string |
//+------------------------------------------------------------------+
int GetIndicatorIdxByIndicatorId(string indicatorId)
{
for(int i=0; i<indicatorCount; i++)
{
if(indicators[i].indicatorId == indicatorId)
{
return i;
}
}
return -1;
}
//+------------------------------------------------------------------+
//| Start new indicator or request indicator data |
//+------------------------------------------------------------------+
void IndicatorControl(CJAVal &dataObject)
{
string actionType=dataObject["actionType"].ToStr();
if(actionType=="REQUEST")
{
GetIndicatorResult(dataObject);
}
else
if(actionType=="ATTACH")
{
StartIndicator(dataObject);
}
}
//+------------------------------------------------------------------+
//| Start new indicator instance |
//+------------------------------------------------------------------+
void StartIndicator(CJAVal &dataObject)
{
// TODO map Indicators Constants https://www.mql5.com/en/docs/constants/indicatorconstants
string symbol=dataObject["symbol"].ToStr();
string chartTF=dataObject["chartTF"].ToStr();
string id=dataObject["id"].ToStr();
string indicatorName=dataObject["name"].ToStr();
indicatorCount++;
ArrayResize(indicators,indicatorCount);
int idx = indicatorCount-1;
indicators[idx].indicatorId = id;
indicators[idx].indicatorBufferCount = dataObject["linecount"].ToInt();
double params[];
indicators[idx].indicatorParamCount = dataObject["params"].Size();
for(int i=0; i<indicators[idx].indicatorParamCount; i++)
{
// TODO test it. Is it ok to pass EnumInts as Doubles for params?
ArrayResize(params, i+1);
string paramStr = dataObject["params"][i].ToStr();
if(IsNumberAsString(paramStr))
params[i] = StringToDouble(paramStr);
else
{
params[i] = StringToEnumInt(paramStr);
mControl.mResetLastError(); // TODO find where the Error 4003 is craeted in StringToEnumInt
}
}
ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
// Case construct for passing variable parameter count to the iCustom function is used, because MQL5 does not seem to support expanding an array to a function parameter list
switch(indicators[idx].indicatorParamCount)
{
case 0:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName);
break;
case 1:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0]);
break;
case 2:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1]);
break;
case 3:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2]);
break;
case 4:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3]);
break;
case 5:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4]);
break;
case 6:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5]);
break;
case 7:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
break;
case 8:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7]);
break;
case 9:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8]);
break;
case 10:
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], params[9]);
break;
default:
// TODO error handling
break;
}
CJAVal message;
if(mControl.mGetLastError())
{
int lastError = mControl.mGetLastError();
string desc = mControl.mGetDesc();
mControl.Check();
message["error"]=(bool) true;
message["lastError"]=(string) lastError;
message["description"]=desc;
message["function"]=(string) __FUNCTION__;
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(indicatorDataSocket,t);
}
else
{
message["error"]=(bool) false;
message["id"] = (string) id;
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(indicatorDataSocket,t);
}
}
//+------------------------------------------------------------------+
//| Get indicator results |
//+------------------------------------------------------------------+
void GetIndicatorResult(CJAVal &dataObject)
{
datetime fromDate=dataObject["fromDate"].ToInt();
string id=dataObject["id"].ToStr();
string indicatorName=dataObject["indicatorName"].ToStr();
int idx = GetIndicatorIdxByIndicatorId(id);
double values[2];
CJAVal results;
// Cycle through all avaliable buffer positions
for(int i=0; i<indicators[idx].indicatorBufferCount; i++)
{
values[0] = 0.0;
values[1] = 0.0;
results[i] = 0.0;
if(idx >= 0)
{
if(CopyBuffer(indicators[idx].indicatorHandle, i, fromDate, 1, values) < 0)
{
if(mControl.mGetLastError())
{
CJAVal message;
int lastError = mControl.mGetLastError();
string desc = mControl.mGetDesc();
mControl.Check();
message["error"]=(bool) true;
message["lastError"]=(string) lastError;
message["description"]=desc;
message["function"]=(string) __FUNCTION__;
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(indicatorDataSocket,t);
}
}
results[i] = DoubleToString(values[0]);
}
}
CJAVal message;
message["error"]=(bool) false;
message["id"] = (string) id;
message["data"].Set(results);
string t=message.Serialize();
if(debug)
Print(t);
InformClientSocket(indicatorDataSocket,t);
}
//+------------------------------------------------------------------+
+75 -352
View File
@@ -21,20 +21,24 @@ Context context("MQL5 JSON API");
Socket chartSubscriptionSocket(context,ZMQ_SUB); Socket chartSubscriptionSocket(context,ZMQ_SUB);
//--- input parameters //--- input parameters
#property indicator_buffers 31 #property indicator_buffers 21
#property indicator_plots 30 #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 IndicatorId="";
input string ShortName="JsonAPIIndicator"; input string ShortName="JsonAPI";
//--- indicator settings //--- indicator settings
double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[]; double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[], B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], alive[];
double B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], B20[]; bool debug = true;
double B21[], B22[], B23[], B24[], B25[], B26[], B27[], B28[], B29[]; bool first = false;
bool debug = false;
int activeBufferCount = 0; int activeBufferCount = 0;
long mtChartId = 0;
bool setFormingCandleBlank = true;
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| Custom indicator initialization function | //| Custom indicator initialization function |
@@ -46,10 +50,8 @@ int OnInit()
// Subscribe to all topics // Subscribe to all topics
chartSubscriptionSocket.setSubscribe(""); chartSubscriptionSocket.setSubscribe("");
chartSubscriptionSocket.setLinger(1000); chartSubscriptionSocket.setLinger(1000);
// https://www.randonomicon.com/zmq/2018/09/19/zmq-bind-vs-connect.html
// Number of messages to buffer in RAM. // Number of messages to buffer in RAM.
// https://dzone.com/articles/zeromq-flow-control-and-other chartSubscriptionSocket.setReceiveHighWaterMark(1000); // TODO confirm settings
chartSubscriptionSocket.setReceiveHighWaterMark(1000);
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)
{ {
@@ -60,6 +62,7 @@ int OnInit()
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT); Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT);
} }
//--- indicator buffers mapping; //--- indicator buffers mapping;
ArraySetAsSeries(B0,true); ArraySetAsSeries(B0,true);
ArraySetAsSeries(B1,true); ArraySetAsSeries(B1,true);
@@ -81,47 +84,30 @@ int OnInit()
ArraySetAsSeries(B17,true); ArraySetAsSeries(B17,true);
ArraySetAsSeries(B18,true); ArraySetAsSeries(B18,true);
ArraySetAsSeries(B19,true); ArraySetAsSeries(B19,true);
ArraySetAsSeries(B20,true); ArraySetAsSeries(alive,true);
ArraySetAsSeries(B21,true);
ArraySetAsSeries(B22,true); SetIndexBuffer(0,B0,INDICATOR_DATA);
ArraySetAsSeries(B23,true); SetIndexBuffer(1,B1,INDICATOR_DATA);
ArraySetAsSeries(B24,true); SetIndexBuffer(2,B2,INDICATOR_DATA);
ArraySetAsSeries(B25,true); SetIndexBuffer(3,B3,INDICATOR_DATA);
ArraySetAsSeries(B26,true); SetIndexBuffer(4,B4,INDICATOR_DATA);
ArraySetAsSeries(B27,true); SetIndexBuffer(5,B5,INDICATOR_DATA);
ArraySetAsSeries(B28,true); SetIndexBuffer(6,B6,INDICATOR_DATA);
ArraySetAsSeries(B29,true); 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
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);
@@ -129,14 +115,6 @@ int OnInit()
return(INIT_SUCCEEDED); return(INIT_SUCCEEDED);
} }
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Print("INDI DEINIT ",reason);
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//| | //| |
@@ -164,11 +142,9 @@ 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;
@@ -190,17 +166,10 @@ 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);
@@ -222,163 +191,52 @@ void SubscriptionHandler(ZmqMsg &chartMsg)
Alert("Deserialization Error"); Alert("Deserialization Error");
ExpertRemove(); ExpertRemove();
} }
if(message["chartIndicatorId"]==IndicatorId) if(message["indicatorChartId"]==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")
@@ -388,165 +246,30 @@ 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 |
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
@@ -554,32 +277,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 // don't add more elements than the automatically sized buffer array can hold
if(i+offset<bufferSize) if(i+1<bufferSize)
{ {
double val = message["data"][i].ToDbl(); // the first element is the current unformed candle, so we start at index 1
if(val >= EMPTY_VALUE) // we reverse the order of the incoming values, which are expected to be ascending
val = EMPTY_VALUE; //buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
buffer[i+offset] = val; 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;
} }
-4
View File
@@ -1,7 +1,3 @@
### Marth 6th
- fixed tick data retrival. When requesting tick data, every other tick was skipped
- refactored code
### 30th April 2020 ### 30th April 2020
- add support for spreads - add support for spreads