@@ -1,2 +1,10 @@
|
||||
|
||||
.DS_Store
|
||||
|
||||
*.mq5:CursorPos:$DATA
|
||||
|
||||
*.mq5:LineFlags:$DATA
|
||||
|
||||
*.mqh:CursorPos:$DATA
|
||||
|
||||
*.mqh:LineFlags:$DATA
|
||||
|
||||
+735
-1291
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,316 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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;
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,145 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,307 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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__);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,244 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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);
|
||||
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
+504
-183
@@ -21,26 +21,20 @@ Context context("MQL5 JSON API");
|
||||
Socket chartSubscriptionSocket(context,ZMQ_SUB);
|
||||
|
||||
//--- input parameters
|
||||
#property indicator_buffers 21
|
||||
#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
|
||||
#property indicator_buffers 31
|
||||
#property indicator_plots 30
|
||||
|
||||
input string IndicatorId="";
|
||||
input string ShortName="JsonAPI";
|
||||
input string ShortName="JsonAPIIndicator";
|
||||
|
||||
//--- indicator settings
|
||||
double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[], B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], alive[];
|
||||
bool debug = true;
|
||||
bool first = false;
|
||||
double B0[], B1[], B2[], B3[], B4[], B5[], B6[], B7[], B8[], B9[], B10[];
|
||||
double B11[], B12[], B13[], B14[], B15[], B16[], B17[], B18[], B19[], B20[];
|
||||
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 |
|
||||
@@ -48,21 +42,24 @@ int activeBufferCount = 0;
|
||||
int OnInit()
|
||||
|
||||
{
|
||||
// TODO subscribe only to own IndicatorId topic
|
||||
// Subscribe to all topics
|
||||
chartSubscriptionSocket.setSubscribe("");
|
||||
chartSubscriptionSocket.setLinger(1000);
|
||||
// https://www.randonomicon.com/zmq/2018/09/19/zmq-bind-vs-connect.html
|
||||
// Number of messages to buffer in RAM.
|
||||
// https://dzone.com/articles/zeromq-flow-control-and-other
|
||||
chartSubscriptionSocket.setReceiveHighWaterMark(1000);
|
||||
bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT));
|
||||
if(result == false)
|
||||
{
|
||||
Print("Failed to subscrbe on port ", CHART_SUB_PORT);
|
||||
}
|
||||
else
|
||||
{
|
||||
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT);
|
||||
}
|
||||
|
||||
bool result = chartSubscriptionSocket.connect(StringFormat("tcp://%s:%d", HOST, CHART_SUB_PORT));
|
||||
if (result == false) {Print("Failed to subscrbe on port ", CHART_SUB_PORT);}
|
||||
else {
|
||||
Print("Accepting Chart Indicator data on port ", CHART_SUB_PORT);
|
||||
// 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;
|
||||
ArraySetAsSeries(B0,true);
|
||||
ArraySetAsSeries(B1,true);
|
||||
@@ -84,46 +81,75 @@ int OnInit()
|
||||
ArraySetAsSeries(B17,true);
|
||||
ArraySetAsSeries(B18,true);
|
||||
ArraySetAsSeries(B19,true);
|
||||
ArraySetAsSeries(alive,true);
|
||||
ArraySetAsSeries(B20,true);
|
||||
ArraySetAsSeries(B21,true);
|
||||
ArraySetAsSeries(B22,true);
|
||||
ArraySetAsSeries(B23,true);
|
||||
ArraySetAsSeries(B24,true);
|
||||
ArraySetAsSeries(B25,true);
|
||||
ArraySetAsSeries(B26,true);
|
||||
ArraySetAsSeries(B27,true);
|
||||
ArraySetAsSeries(B28,true);
|
||||
ArraySetAsSeries(B29,true);
|
||||
|
||||
SetIndexBuffer(0,B0,INDICATOR_DATA);
|
||||
SetIndexBuffer(1,B1,INDICATOR_DATA);
|
||||
SetIndexBuffer(2,B2,INDICATOR_DATA);
|
||||
SetIndexBuffer(3,B3,INDICATOR_DATA);
|
||||
SetIndexBuffer(4,B4,INDICATOR_DATA);
|
||||
SetIndexBuffer(5,B5,INDICATOR_DATA);
|
||||
SetIndexBuffer(6,B6,INDICATOR_DATA);
|
||||
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);
|
||||
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
PlotIndexSetInteger(bufferIdx,PLOT_LINE_STYLE,linestyle);
|
||||
PlotIndexSetInteger(bufferIdx,PLOT_LINE_WIDTH,linewidth);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void OnDeinit(const int reason)
|
||||
{
|
||||
// Print("INDI DEINIT ",reason);
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
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);
|
||||
PlotIndexSetInteger(bufferIdx,PLOT_LINE_STYLE,linestyle);
|
||||
PlotIndexSetInteger(bufferIdx,PLOT_LINE_WIDTH,linewidth);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator iteration function |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -138,151 +164,445 @@ int OnCalculate(const int rates_total,
|
||||
const long &volume[],
|
||||
const int &spread[])
|
||||
{
|
||||
// While a new candle is forming, set the current value to be empty
|
||||
|
||||
if(rates_total>prev_calculated){
|
||||
B0[0] = EMPTY_VALUE;
|
||||
B1[0] = EMPTY_VALUE;
|
||||
B2[0] = EMPTY_VALUE;
|
||||
B3[0] = EMPTY_VALUE;
|
||||
B4[0] = EMPTY_VALUE;
|
||||
B5[0] = EMPTY_VALUE;
|
||||
B6[0] = EMPTY_VALUE;
|
||||
B7[0] = EMPTY_VALUE;
|
||||
B8[0] = EMPTY_VALUE;
|
||||
B9[0] = EMPTY_VALUE;
|
||||
B10[0] = EMPTY_VALUE;
|
||||
B11[0] = EMPTY_VALUE;
|
||||
B12[0] = EMPTY_VALUE;
|
||||
B13[0] = EMPTY_VALUE;
|
||||
B14[0] = EMPTY_VALUE;
|
||||
B15[0] = EMPTY_VALUE;
|
||||
B16[0] = EMPTY_VALUE;
|
||||
B17[0] = EMPTY_VALUE;
|
||||
B18[0] = EMPTY_VALUE;
|
||||
B19[0] = EMPTY_VALUE;
|
||||
}
|
||||
if(first==false) alive[0] = 1;
|
||||
// ChartRedraw(0);
|
||||
|
||||
// While a new candle is forming, set the current value to be empty
|
||||
|
||||
|
||||
if(rates_total>prev_calculated && setFormingCandleBlank)
|
||||
{
|
||||
B0[0] = EMPTY_VALUE;
|
||||
B1[0] = EMPTY_VALUE;
|
||||
B2[0] = EMPTY_VALUE;
|
||||
B3[0] = EMPTY_VALUE;
|
||||
B4[0] = EMPTY_VALUE;
|
||||
B5[0] = EMPTY_VALUE;
|
||||
B6[0] = EMPTY_VALUE;
|
||||
B7[0] = EMPTY_VALUE;
|
||||
B8[0] = EMPTY_VALUE;
|
||||
B9[0] = EMPTY_VALUE;
|
||||
B10[0] = EMPTY_VALUE;
|
||||
B11[0] = EMPTY_VALUE;
|
||||
B12[0] = EMPTY_VALUE;
|
||||
B13[0] = EMPTY_VALUE;
|
||||
B14[0] = EMPTY_VALUE;
|
||||
B15[0] = EMPTY_VALUE;
|
||||
B16[0] = EMPTY_VALUE;
|
||||
B17[0] = EMPTY_VALUE;
|
||||
B18[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;
|
||||
}
|
||||
|
||||
//--- return value of prev_calculated for next call
|
||||
return(rates_total);
|
||||
}
|
||||
|
||||
void SubscriptionHandler(ZmqMsg &chartMsg){
|
||||
CJAVal message;
|
||||
// Get data from request
|
||||
string msg=chartMsg.getData();
|
||||
if(debug) Print("Processing:"+msg);
|
||||
// Deserialize msg to CJAVal array
|
||||
if(!message.Deserialize(msg)){
|
||||
Alert("Deserialization Error");
|
||||
ExpertRemove();
|
||||
}
|
||||
if(message["indicatorChartId"]==IndicatorId) {
|
||||
//+------------------------------------------------------------------+
|
||||
//| |
|
||||
//+------------------------------------------------------------------+
|
||||
void SubscriptionHandler(ZmqMsg &chartMsg)
|
||||
{
|
||||
CJAVal message;
|
||||
// Get data from request
|
||||
string msg=chartMsg.getData();
|
||||
if(debug)
|
||||
Print("Processing:"+msg);
|
||||
// Deserialize msg to CJAVal array
|
||||
if(!message.Deserialize(msg))
|
||||
{
|
||||
Alert("Deserialization Error");
|
||||
ExpertRemove();
|
||||
}
|
||||
if(message["chartIndicatorId"]==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);;}
|
||||
if(message["action"]=="PLOT" && message["actionType"]=="DATA")
|
||||
{
|
||||
int bufferIdx = message["indicatorBufferId"].ToInt();
|
||||
if(bufferIdx == 0)
|
||||
{
|
||||
WriteToBuffer(message, B0);
|
||||
SetIndexBuffer(0,B0,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 1)
|
||||
{
|
||||
WriteToBuffer(message, B1);
|
||||
SetIndexBuffer(1,B1,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 2)
|
||||
{
|
||||
WriteToBuffer(message, B2);
|
||||
SetIndexBuffer(2,B2,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 3)
|
||||
{
|
||||
WriteToBuffer(message, B3);
|
||||
SetIndexBuffer(3,B3,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 4)
|
||||
{
|
||||
WriteToBuffer(message, B4);
|
||||
SetIndexBuffer(4,B4,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 5)
|
||||
{
|
||||
WriteToBuffer(message, B5);
|
||||
SetIndexBuffer(5,B5,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 6)
|
||||
{
|
||||
WriteToBuffer(message, B6);
|
||||
SetIndexBuffer(6,B6,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 7)
|
||||
{
|
||||
WriteToBuffer(message, B7);
|
||||
SetIndexBuffer(7,B7,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 8)
|
||||
{
|
||||
WriteToBuffer(message, B8);
|
||||
SetIndexBuffer(8,B8,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 9)
|
||||
{
|
||||
WriteToBuffer(message, B9);
|
||||
SetIndexBuffer(9,B9,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 10)
|
||||
{
|
||||
WriteToBuffer(message, B10);
|
||||
SetIndexBuffer(10,B10,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 11)
|
||||
{
|
||||
WriteToBuffer(message, B11);
|
||||
SetIndexBuffer(11,B11,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 12)
|
||||
{
|
||||
WriteToBuffer(message, B12);
|
||||
SetIndexBuffer(12,B12,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 13)
|
||||
{
|
||||
WriteToBuffer(message, B13);
|
||||
SetIndexBuffer(13,B13,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 14)
|
||||
{
|
||||
WriteToBuffer(message, B14);
|
||||
SetIndexBuffer(14,B14,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 15)
|
||||
{
|
||||
WriteToBuffer(message, B15);
|
||||
SetIndexBuffer(15,B15,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 16)
|
||||
{
|
||||
WriteToBuffer(message, B16);
|
||||
SetIndexBuffer(16,B16,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 17)
|
||||
{
|
||||
WriteToBuffer(message, B17);
|
||||
SetIndexBuffer(17,B17,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 18)
|
||||
{
|
||||
WriteToBuffer(message, B18);
|
||||
SetIndexBuffer(18,B18,INDICATOR_DATA);
|
||||
}
|
||||
if(bufferIdx == 19)
|
||||
{
|
||||
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
|
||||
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();
|
||||
setFormingCandleBlank = message["style"]["blankforming"].ToBool();
|
||||
|
||||
//aa = true;}
|
||||
*/
|
||||
|
||||
SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
|
||||
activeBufferCount = activeBufferCount + 1;
|
||||
}
|
||||
color colorstyle = StringToColor(colorstyleStr);
|
||||
int linetype = StringToEnumInt(linetypeStr);
|
||||
int linestyle = StringToEnumInt(linestyleStr);
|
||||
|
||||
SetStyle(activeBufferCount, linelabel, colorstyle, linetype, linestyle, linewidth);
|
||||
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 |
|
||||
//+------------------------------------------------------------------+
|
||||
void WriteToBuffer(CJAVal &message, double &buffer[]) {
|
||||
|
||||
int bufferSize = ArraySize(buffer);
|
||||
void WriteToBuffer(CJAVal &message, double &buffer[])
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
int bufferSize = ArraySize(buffer);
|
||||
int messageDataSize = message["data"].Size();
|
||||
|
||||
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();
|
||||
}
|
||||
// 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++)
|
||||
{
|
||||
// don't add more elements than the automatically sized buffer array can
|
||||
if(i+offset<bufferSize)
|
||||
{
|
||||
double val = message["data"][i].ToDbl();
|
||||
if(val >= EMPTY_VALUE)
|
||||
val = EMPTY_VALUE;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check for new indicator data function |
|
||||
//+------------------------------------------------------------------+
|
||||
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()
|
||||
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()
|
||||
|
||||
ZmqMsg chartMsg;
|
||||
ZmqMsg chartMsg;
|
||||
|
||||
// Recieve chart instructions stream from client via live Chart socket.
|
||||
chartSubscriptionSocket.recv(chartMsg,true);
|
||||
// Recieve chart instructions stream from client via live Chart socket.
|
||||
chartSubscriptionSocket.recv(chartMsg,true);
|
||||
|
||||
// Request recieved
|
||||
if(chartMsg.size()>0){
|
||||
// Handle subscription SubscriptionHandler()
|
||||
SubscriptionHandler(chartMsg);
|
||||
ChartRedraw(ChartID());
|
||||
// Request recieved
|
||||
if(chartMsg.size()>0)
|
||||
{
|
||||
// Handle subscription SubscriptionHandler()
|
||||
SubscriptionHandler(chartMsg);
|
||||
ChartRedraw(ChartID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| OnTimer() workaround function |
|
||||
@@ -293,6 +613,7 @@ void OnChartEvent(const int id,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
if(id==CHARTEVENT_CUSTOM+222) CheckMessages();
|
||||
if(id==CHARTEVENT_CUSTOM+222)
|
||||
CheckMessages();
|
||||
}
|
||||
//+----------------------------------------------------
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
### Marth 6th
|
||||
- fixed tick data retrival. When requesting tick data, every other tick was skipped
|
||||
- refactored code
|
||||
|
||||
### 30th April 2020
|
||||
|
||||
- add support for spreads
|
||||
|
||||
Reference in New Issue
Block a user