add chart control
open and draw indicator lines on chart
This commit is contained in:
+410
-181
@@ -1,4 +1,4 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//+------------------------------------------------------------------+
|
||||
//
|
||||
// Copyright (C) 2019 Nikolai Khramkov
|
||||
//
|
||||
@@ -30,7 +30,12 @@
|
||||
#include <Trade/Trade.mqh>
|
||||
#include <Zmq/Zmq.mqh>
|
||||
#include <Json.mqh>
|
||||
#include <ChartObjects\ChartObject.mqh>
|
||||
#include <EnumStringToInt.mqh>
|
||||
//#include <ChartObjects\ChartObject.mqh>
|
||||
//#include<Canvas\Canvas.mqh>
|
||||
//#include <Graphics\Graphic.mqh>
|
||||
// Starts an Expert Advisor with specified parameters
|
||||
//#include <Expert.mqh>
|
||||
|
||||
// Set ports and host for ZeroMQ
|
||||
string HOST="*";
|
||||
@@ -39,6 +44,8 @@ int DATA_PORT=15556;
|
||||
int LIVE_PORT=15557;
|
||||
int STR_PORT=15558;
|
||||
int IND_DATA_PORT=15559;
|
||||
int CHART_LIVE_PORT=15560;
|
||||
int PUB_CHART_LIVE_PORT=15562;
|
||||
|
||||
// ZeroMQ Cnnections
|
||||
Context context("MQL5 JSON API");
|
||||
@@ -47,24 +54,65 @@ Socket dataSocket(context,ZMQ_PUSH);
|
||||
Socket liveSocket(context,ZMQ_PUSH);
|
||||
Socket streamSocket(context,ZMQ_PUSH);
|
||||
Socket indicatorDataSocket(context,ZMQ_PUSH);
|
||||
Socket chartLiveSocket(context,ZMQ_PULL);
|
||||
Socket pubChartLiveSocket(context,ZMQ_PUB);
|
||||
|
||||
// Global variables
|
||||
bool debug = false;
|
||||
bool liveStream = true;
|
||||
bool connectedFlag= true;
|
||||
int deInitReason = -1;
|
||||
double chartAttached = ChartID();
|
||||
|
||||
// Variables for handling price data stream
|
||||
string chartSymbols[];
|
||||
int chartSymbolCount = 0;
|
||||
string chartSymbolSettings[][3];
|
||||
struct SymbolSubscription {
|
||||
string symbol;
|
||||
string chartTf;
|
||||
datetime lastBar;
|
||||
};
|
||||
|
||||
SymbolSubscription symbolSubscriptions[];
|
||||
//string chartSymbols[];
|
||||
int symbolSubscriptionCount = 0;
|
||||
//string chartSymbolSettings[][3];
|
||||
|
||||
// Variables for controlling indicators
|
||||
|
||||
struct Indicator {
|
||||
long id;
|
||||
string indicatorId;
|
||||
int indicatorHandle;
|
||||
int indicatorParamCount;
|
||||
int indicatorBufferCount;
|
||||
};
|
||||
Indicator indicators[];
|
||||
int indicatorCount = 0;
|
||||
/*
|
||||
double indicators[];
|
||||
string indicatorIds[];
|
||||
int indicatorParamCount[];
|
||||
int indicatorBufferCount[];
|
||||
*/
|
||||
|
||||
// Variables for controlling chart
|
||||
struct ChartWindow {
|
||||
long id;
|
||||
string chartId;
|
||||
string indicatorId;
|
||||
int indicatorHandle;
|
||||
};
|
||||
ChartWindow chartWindows[];
|
||||
int chartWindowCount = 0;
|
||||
|
||||
// Refresh chart windows interval. OnTimer function of indicatore JsonAPIIndicator gets triggered on each interval
|
||||
int chartWindowTimerInterval = 100;
|
||||
int chartWindowTimerCounter = 0;
|
||||
|
||||
|
||||
//string chartWindowObjects[];
|
||||
|
||||
//double chartCurvePositions[][3];
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Bind ZMQ sockets to ports |
|
||||
@@ -82,17 +130,26 @@ bool BindSockets(){
|
||||
result = indicatorDataSocket.bind(StringFormat("tcp://%s:%d", HOST,IND_DATA_PORT));
|
||||
if (result == false) return result;
|
||||
|
||||
result = chartLiveSocket.bind(StringFormat("tcp://%s:%d", HOST,CHART_LIVE_PORT));
|
||||
if (result == false) { return result; } else {Print("Bound 'Chart Live' socket on port ", CHART_LIVE_PORT);}
|
||||
|
||||
result = pubChartLiveSocket.bind(StringFormat("tcp://%s:%d", HOST,PUB_CHART_LIVE_PORT));
|
||||
if (result == false) { return result; } else {Print("Bound 'PUB Chart Live' socket on port ", PUB_CHART_LIVE_PORT);}
|
||||
|
||||
Print("Bound 'System' socket on port ", SYS_PORT);
|
||||
Print("Bound 'Data' socket on port ", DATA_PORT);
|
||||
Print("Bound 'Live' socket on port ", LIVE_PORT);
|
||||
Print("Bound 'Streaming' socket on port ", STR_PORT);
|
||||
Print("Bound 'Indicator Data' socket on port ", IND_DATA_PORT);
|
||||
|
||||
|
||||
sysSocket.setLinger(1000);
|
||||
dataSocket.setLinger(1000);
|
||||
liveSocket.setLinger(1000);
|
||||
streamSocket.setLinger(1000);
|
||||
indicatorDataSocket.setLinger(1000);
|
||||
chartLiveSocket.setLinger(1000);
|
||||
//pubChartLiveSocket.setLinger(1000);
|
||||
|
||||
// Number of messages to buffer in RAM.
|
||||
sysSocket.setSendHighWaterMark(1);
|
||||
@@ -100,6 +157,8 @@ bool BindSockets(){
|
||||
liveSocket.setSendHighWaterMark(1);
|
||||
streamSocket.setSendHighWaterMark(50);
|
||||
indicatorDataSocket.setSendHighWaterMark(5);
|
||||
chartLiveSocket.setReceiveHighWaterMark(1); // TODO confirm settings
|
||||
//pubChartLiveSocket.setReceiveHighWaterMark(1);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -109,10 +168,10 @@ bool BindSockets(){
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit(){
|
||||
/* Bindinig ZMQ ports on init */
|
||||
Print(GetIndicatorConstantValue("VOLUME_TICK"), " ",VOLUME_TICK);
|
||||
|
||||
// Skip reloading of the EA script when the reason to reload is a chart timeframe change
|
||||
if (deInitReason != REASON_CHARTCHANGE){
|
||||
|
||||
|
||||
EventSetMillisecondTimer(1);
|
||||
|
||||
int bindSocketsDelay = 65; // Seconds to wait if binding of sockets fails.
|
||||
@@ -136,50 +195,6 @@ Print(GetIndicatorConstantValue("VOLUME_TICK"), " ",VOLUME_TICK);
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
void testDraw() {
|
||||
// ChartSetSymbolPeriod(ChartID(), Symbol(),PERIOD_M1);
|
||||
|
||||
// long chart_id;
|
||||
// chart_id = ChartOpen("EURUSD",PERIOD_M1);
|
||||
// Print(chart_id);
|
||||
|
||||
long chart_id = 0;
|
||||
int window = 0;
|
||||
|
||||
datetime time1 = 1581891300;
|
||||
double price1 = 1.08346;
|
||||
datetime time2 = 1581891600;
|
||||
double price2 = 1.08354;
|
||||
chart_id = ChartOpen("EURUSD",PERIOD_M5);
|
||||
Print(chart_id);
|
||||
/*
|
||||
bool CChartObjectTrend::Create(long chart_id,string name,int window,
|
||||
datetime time1,double price1,datetime time2,double price2)
|
||||
{
|
||||
bool result=ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2);
|
||||
if(result) result&=Attach(chart_id,name,window,2);
|
||||
//---
|
||||
return(result);
|
||||
}
|
||||
*/
|
||||
CChartObject object;
|
||||
//ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1,price1,time2,price2,time2,price2+0.00005);
|
||||
//ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1-100,price1,time1,price1+0.00010,time1+200,price1);
|
||||
//ObjectCreate(chart_id,"trend",OBJ_TREND,window,time1,price1,time2,price2);
|
||||
ObjectCreate(chart_id,"reactangle",OBJ_TREND,window,time1,price1+0.00010,time2,price2+0.00020);
|
||||
|
||||
|
||||
//--- attach chart object
|
||||
/*
|
||||
if(!object.Attach(ChartID(),"MyObject",0,2))
|
||||
{
|
||||
printf("Object attach error");
|
||||
|
||||
}
|
||||
*/
|
||||
//ChartSetSymbolPeriod(ChartID(), Symbol(),PERIOD_M5);
|
||||
ChartRedraw(chart_id);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Expert deinitialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -204,12 +219,22 @@ void OnDeinit(const int reason){
|
||||
liveSocket.unbind(StringFormat("tcp://%s:%d", HOST,LIVE_PORT));
|
||||
Print("Unbinding 'Streaming' socket on port ", STR_PORT, "..");
|
||||
streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,STR_PORT));
|
||||
Print("Unbinding 'CHart' socket on port ", STR_PORT, "..");
|
||||
streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,CHART_LIVE_PORT));
|
||||
Print("Unbinding 'pub chart' socket on port ", STR_PORT, "..");
|
||||
streamSocket.unbind(StringFormat("tcp://%s:%d", HOST,PUB_CHART_LIVE_PORT));
|
||||
|
||||
// Shutdown ZeroMQ Context
|
||||
context.shutdown();
|
||||
context.destroy(0);
|
||||
|
||||
// Reset
|
||||
ResetSubscriptionsAndIndicators();
|
||||
|
||||
EventKillTimer();
|
||||
for(int i=0;i<ArraySize(chartWindows);i++){
|
||||
ChartClose(chartWindows[i].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,13 +245,13 @@ void OnTick(){
|
||||
*/
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Check if subscribed to symbol and timeframe combination |
|
||||
//| Check if subscribed to symbol and timeframe combination |
|
||||
//+------------------------------------------------------------------+
|
||||
bool HasChartSymbol(string symbol, string chartTF)
|
||||
{
|
||||
for(int i=0;i<ArraySize(chartSymbols);i++)
|
||||
for(int i=0;i<ArraySize(symbolSubscriptions);i++)
|
||||
{
|
||||
if(chartSymbolSettings[i][0] == symbol && chartSymbolSettings[i][1] == chartTF){
|
||||
if(symbolSubscriptions[i].symbol == symbol && symbolSubscriptions[i].chartTf == chartTF){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +265,7 @@ int GetIndicatorIdxByIndicatorId(string indicatorId)
|
||||
{
|
||||
for(int i=0;i<indicatorCount;i++)
|
||||
{
|
||||
if(indicatorIds[i] == indicatorId){
|
||||
if(indicators[i].indicatorId == indicatorId){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -248,19 +273,33 @@ int GetIndicatorIdxByIndicatorId(string indicatorId)
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stream live price data |
|
||||
//| Get 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;
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Stream live price data |
|
||||
//+------------------------------------------------------------------+
|
||||
void StreamPriceData(){
|
||||
// If liveStream == true, push last candle to liveSocket.
|
||||
if(liveStream){
|
||||
CJAVal last;
|
||||
if(TerminalInfoInteger(TERMINAL_CONNECTED)){
|
||||
connectedFlag=true;
|
||||
for(int i=0;i<chartSymbolCount;i++){
|
||||
string symbol=chartSymbolSettings[i][0];
|
||||
string chartTF=chartSymbolSettings[i][1];
|
||||
datetime lastBar=chartSymbolSettings[i][2];
|
||||
|
||||
connectedFlag=true;
|
||||
for(int i=0;i<symbolSubscriptionCount;i++){
|
||||
string symbol=symbolSubscriptions[i].symbol;
|
||||
string chartTF=symbolSubscriptions[i].chartTf;
|
||||
datetime lastBar=symbolSubscriptions[i].lastBar;
|
||||
//Print(symbol," ", chartTF," ",lastBar);
|
||||
CJAVal Data;
|
||||
ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
|
||||
|
||||
@@ -303,10 +342,10 @@ void StreamPriceData(){
|
||||
string t=last.Serialize();
|
||||
if(debug) Print(t);
|
||||
InformClientSocket(liveSocket,t);
|
||||
chartSymbolSettings[i][2]=thisBar;
|
||||
symbolSubscriptions[i].lastBar=thisBar;
|
||||
|
||||
}
|
||||
else chartSymbolSettings[i][2]=thisBar;
|
||||
else symbolSubscriptions[i].lastBar=thisBar;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -329,10 +368,11 @@ void StreamPriceData(){
|
||||
//+------------------------------------------------------------------+
|
||||
void OnTimer(){
|
||||
|
||||
ZmqMsg request;
|
||||
|
||||
// Stream live price data
|
||||
StreamPriceData();
|
||||
|
||||
ZmqMsg request;
|
||||
|
||||
// Get request from client via System socket.
|
||||
sysSocket.recv(request,true);
|
||||
|
||||
@@ -341,24 +381,28 @@ void OnTimer(){
|
||||
// Pull request to RequestHandler().
|
||||
RequestHandler(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
//+------------------------------------------------------------------+
|
||||
//| ChartEvent function |
|
||||
//| This function must be declared, even if it empty. |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
void OnChartEvent(const int id, // event id
|
||||
const long& lparam, // event param of long type
|
||||
const double& dparam, // event param of double type
|
||||
const string& sparam) // event param of string type
|
||||
|
||||
{
|
||||
//--- Add your code here...
|
||||
|
||||
// Publish indicator values for the JsonAPIIndicator indicator
|
||||
ZmqMsg chartMsg;
|
||||
chartLiveSocket.recv(chartMsg, true);
|
||||
if(chartMsg.size()>0){
|
||||
Print(chartMsg.getData());
|
||||
pubChartLiveSocket.send(chartMsg,true);
|
||||
ResetLastError();
|
||||
}
|
||||
*/
|
||||
|
||||
// Trigger the indicator JsonAPIIndicator to check for new Messages
|
||||
if(chartWindowTimerCounter >= chartWindowTimerInterval) {
|
||||
for(int i=0;i<ArraySize(chartWindows);i++){
|
||||
long ChartId = chartWindows[i].id;
|
||||
string chartIndicatorId = chartWindows[i].indicatorId;
|
||||
EventChartCustom(ChartId, 222, 222, 222.0, chartIndicatorId);
|
||||
}
|
||||
chartWindowTimerCounter = 0;
|
||||
}
|
||||
else chartWindowTimerCounter++;
|
||||
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Request handler |
|
||||
@@ -395,6 +439,7 @@ void RequestHandler(ZmqMsg &request){
|
||||
else if(action=="ORDERS") GetOrders(message);
|
||||
else if(action=="RESET") ResetSubscriptionsAndIndicators();
|
||||
else if(action=="INDICATOR") IndicatorControl(message);
|
||||
else if(action=="CHART") ChartControl(message);
|
||||
// Action command error processing
|
||||
else ActionDoneOrError(65538, __FUNCTION__);
|
||||
|
||||
@@ -404,29 +449,36 @@ void RequestHandler(ZmqMsg &request){
|
||||
//| Reconfigure the script params |
|
||||
//+------------------------------------------------------------------+
|
||||
void ScriptConfiguration(CJAVal &dataObject){
|
||||
//testDraw();
|
||||
|
||||
string symbol=dataObject["symbol"].ToStr();
|
||||
string chartTF=dataObject["chartTF"].ToStr();
|
||||
string actionType=dataObject["actionType"].ToStr();
|
||||
//string actionType=dataObject["actionType"].ToStr();
|
||||
|
||||
ArrayResize(symbolSubscriptions, symbolSubscriptionCount+1);
|
||||
symbolSubscriptions[symbolSubscriptionCount].symbol = symbol;
|
||||
symbolSubscriptions[symbolSubscriptionCount].chartTf = chartTF;
|
||||
// to initialze with value 0 skips the first price
|
||||
symbolSubscriptions[symbolSubscriptionCount].lastBar = 0;
|
||||
symbolSubscriptionCount++;
|
||||
/*
|
||||
string symbArr[1];
|
||||
symbArr[0]= symbol;
|
||||
|
||||
if (!HasChartSymbol(symbol, chartTF)) {
|
||||
ArrayInsert(chartSymbols,symbArr,0);
|
||||
ArrayResize(chartSymbolSettings,chartSymbolCount+1);
|
||||
chartSymbolSettings[chartSymbolCount][0]=symbol;
|
||||
chartSymbolSettings[chartSymbolCount][1]=chartTF;
|
||||
ArrayResize(chartSymbolSettings,symbolSubscriptionCount+1);
|
||||
chartSymbolSettings[symbolSubscriptionCount][0]=symbol;
|
||||
chartSymbolSettings[symbolSubscriptionCount][1]=chartTF;
|
||||
// lastBar
|
||||
chartSymbolSettings[chartSymbolCount][2]=0; // to initialze with value 0 skips the first price
|
||||
chartSymbolCount++;
|
||||
chartSymbolSettings[symbolSubscriptionCount][2]=0; // to initialze with value 0 skips the first price
|
||||
symbolSubscriptionCount++;
|
||||
}
|
||||
*/
|
||||
|
||||
if(SymbolInfoInteger(symbol, SYMBOL_EXIST)){
|
||||
ActionDoneOrError(ERR_SUCCESS, __FUNCTION__);
|
||||
}
|
||||
else ActionDoneOrError(ERR_MARKET_UNKNOWN_SYMBOL, __FUNCTION__);
|
||||
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -442,7 +494,6 @@ void IndicatorControl(CJAVal &dataObject){
|
||||
else if(actionType=="START") {
|
||||
StartIndicator(dataObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -457,18 +508,18 @@ void StartIndicator(CJAVal &dataObject){
|
||||
|
||||
indicatorCount++;
|
||||
ArrayResize(indicators,indicatorCount);
|
||||
ArrayResize(indicatorIds,indicatorCount);
|
||||
ArrayResize(indicatorParamCount,indicatorCount);
|
||||
ArrayResize(indicatorBufferCount,indicatorCount);
|
||||
//ArrayResize(indicatorIds,indicatorCount);
|
||||
//ArrayResize(indicatorParamCount,indicatorCount);
|
||||
//ArrayResize(indicatorBufferCount,indicatorCount);
|
||||
|
||||
int idx = indicatorCount-1;
|
||||
|
||||
indicatorIds[idx] = id;
|
||||
indicatorBufferCount[idx] = dataObject["linecount"].ToInt();
|
||||
indicators[idx].indicatorId = id;
|
||||
indicators[idx].indicatorBufferCount = dataObject["linecount"].ToInt();
|
||||
|
||||
double params[];
|
||||
indicatorParamCount[idx] = dataObject["params"].Size();
|
||||
for(int i=0;i<indicatorParamCount[idx];i++){
|
||||
indicators[idx].indicatorParamCount = dataObject["params"].Size();
|
||||
for(int i=0;i<indicators[idx].indicatorParamCount;i++){
|
||||
ArrayResize(params, i+1);
|
||||
params[i] = dataObject["params"][i].ToDbl();
|
||||
}
|
||||
@@ -476,40 +527,40 @@ void StartIndicator(CJAVal &dataObject){
|
||||
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(indicatorParamCount[idx])
|
||||
switch(indicators[idx].indicatorParamCount)
|
||||
{
|
||||
case 0:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName);
|
||||
break;
|
||||
case 1:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0]);
|
||||
break;
|
||||
case 2:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1]);
|
||||
break;
|
||||
case 3:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2]);
|
||||
break;
|
||||
case 4:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3]);
|
||||
break;
|
||||
case 5:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4]);
|
||||
break;
|
||||
case 6:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5]);
|
||||
indicators[idx].indicatorHandle = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5]);
|
||||
break;
|
||||
case 7:
|
||||
indicators[idx] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6]);
|
||||
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] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7]);
|
||||
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] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8]);
|
||||
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] = iCustom(symbol,period,indicatorName, params[0], params[1], params[2], params[3], params[4], params[5], params[6], params[7], params[8], params[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], params[9]);
|
||||
break;
|
||||
default:
|
||||
// TODO error handling
|
||||
@@ -545,15 +596,15 @@ void GetIndicatorResult(CJAVal &dataObject) {
|
||||
int idx = GetIndicatorIdxByIndicatorId(id);
|
||||
|
||||
double values[2];
|
||||
ArrayResize(values, indicatorBufferCount[idx]);
|
||||
ArrayResize(values, indicators[idx].indicatorBufferCount);
|
||||
CJAVal results;
|
||||
// Cycle through all avaliable buffer positions
|
||||
for(int i=0;i<indicatorBufferCount[idx];i++){
|
||||
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], i, fromDate, 1, values) < 0) {/* Error handling */}
|
||||
if(CopyBuffer(indicators[idx].indicatorHandle, i, fromDate, 1, values) < 0) {/* Error handling */}
|
||||
results[i] = DoubleToString(values[0]);
|
||||
}
|
||||
else {
|
||||
@@ -577,6 +628,237 @@ void GetIndicatorResult(CJAVal &dataObject) {
|
||||
//else ActionDoneOrError(ERR_MARKET_UNKNOWN_SYMBOL, __FUNCTION__);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Open new chart or add indicator to chart |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
void ChartControl(CJAVal &dataObject){
|
||||
|
||||
string actionType=dataObject["actionType"].ToStr();
|
||||
|
||||
if(actionType=="ADDINDICATOR") {
|
||||
AddIndicatorChartToChart(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);
|
||||
//ArrayResize(chartWindowIds,chartWindowCount);
|
||||
//ArrayResize(chartWindowPeriods,chartWindowCount);
|
||||
// ArrayResize(chartWindowObjects,chartWindowCount);
|
||||
|
||||
int idx = chartWindowCount-1;
|
||||
|
||||
chartWindows[idx].chartId = chartId;
|
||||
|
||||
ENUM_TIMEFRAMES period = GetTimeframe(chartTF);
|
||||
chartWindows[idx].id = ChartOpen(symbol, period);
|
||||
//chartWindowPeriods[idx] = period;
|
||||
|
||||
CJAVal message;
|
||||
message["chartId"] = (string) chartId;
|
||||
|
||||
string t=message.Serialize();
|
||||
if(debug) Print(t);
|
||||
InformClientSocket(dataSocket,t);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Add JsonAPIIndicator indicator chart to chart |
|
||||
//+------------------------------------------------------------------+
|
||||
void AddIndicatorChartToChart(CJAVal &dataObject){
|
||||
|
||||
string chartIdStr=dataObject["chartId"].ToStr();
|
||||
string chartIndicatorId=dataObject["indicatorChartId"].ToStr();
|
||||
int chartIndicatorSubWindow=dataObject["chartIndicatorSubWindow"].ToInt();
|
||||
string shortname = dataObject["style"]["shortname"].ToStr();
|
||||
string colorstyle = dataObject["style"]["color"].ToStr();
|
||||
string linetype = dataObject["style"]["linetype"].ToStr();
|
||||
string linestyle = dataObject["style"]["linestyle"].ToStr();
|
||||
int linewidth = dataObject["style"]["linewidth"].ToInt();
|
||||
|
||||
int idx = GetChartWindowIdxByChartWindowId(chartIdStr);
|
||||
long ChartId = chartWindows[idx].id;
|
||||
|
||||
double chartIndicatorHandle = iCustom(ChartSymbol(ChartId),ChartPeriod(ChartId),"JsonAPIIndicator",chartIndicatorId,shortname,colorstyle,linetype,linestyle,linewidth);
|
||||
|
||||
ChartIndicatorAdd(ChartId, chartIndicatorSubWindow, chartIndicatorHandle);
|
||||
|
||||
chartWindows[idx].indicatorId = chartIndicatorId;
|
||||
chartWindows[idx].indicatorHandle = chartIndicatorHandle;
|
||||
|
||||
CJAVal message;
|
||||
message["chartId"] = (string) chartIdStr;
|
||||
|
||||
string t=message.Serialize();
|
||||
if(debug) Print(t);
|
||||
InformClientSocket(dataSocket,t);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draw on chart |
|
||||
//+------------------------------------------------------------------+
|
||||
void ChartDraw(CJAVal &dataObject){
|
||||
/*
|
||||
Print("drawchart");
|
||||
|
||||
string id=dataObject["id"].ToStr();
|
||||
//int windowIdx = GetChartWindowIdxByChartWindowId(id);
|
||||
|
||||
int datesSize = dataObject["data"][0].Size();
|
||||
int x[];
|
||||
int y[];
|
||||
double x_dbl[];
|
||||
double y_dbl[];
|
||||
ArrayResize(chartCurvePositions, datesSize);
|
||||
ArrayResize(x,datesSize);
|
||||
ArrayResize(y,datesSize);
|
||||
ArrayResize(x_dbl,datesSize);
|
||||
ArrayResize(y_dbl,datesSize);
|
||||
for(int i=0;i<datesSize;i++){
|
||||
chartCurvePositions[i][0] = dataObject["data"][0][i].ToDbl();
|
||||
chartCurvePositions[i][1] = dataObject["data"][1][i].ToDbl();
|
||||
//chartCurvePositions[i][2] = dataObject["data"]["dates"][2].ToDbl();
|
||||
|
||||
//ChartTimePriceToXY(windowIdx, 0, chartCurvePositions[i][0], chartCurvePositions[i][1], x[i], y[i]);
|
||||
//x_dbl[i] = x[i];
|
||||
//y_dbl[i] = y[i];
|
||||
}
|
||||
int firstBarIdx = ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR,0);
|
||||
int lastBarIdx = firstBarIdx + ChartGetInteger(0, CHART_VISIBLE_BARS,0);
|
||||
|
||||
MqlRates ratesFirst[];
|
||||
MqlRates ratesLast[];
|
||||
CopyRates(Symbol(),PERIOD_M1,firstBarIdx,1, ratesFirst);
|
||||
CopyRates(Symbol(),PERIOD_M1,lastBarIdx,1, ratesLast);
|
||||
//Print(chartCurvePositions[0][0]);
|
||||
int idxStart = ArrayBsearch(chartCurvePositions, ratesFirst[0].time);
|
||||
int idxEnd = ArrayBsearch(chartCurvePositions, ratesLast[0].time);
|
||||
Print(StringToTime(ratesFirst[0].time));
|
||||
Print(ratesLast[0].time);
|
||||
Print("start ", idxStart, " end ", idxEnd, " r " ,ratesFirst[0].time, " ",ratesLast[0].time, " fidx ", firstBarIdx, " lidx ", lastBarIdx );
|
||||
|
||||
|
||||
int j = 0;
|
||||
for(int i=idxStart;i<idxEnd;i++){
|
||||
ChartTimePriceToXY(0, 0, chartCurvePositions[i][0], chartCurvePositions[i][1], x[j], y[j]);
|
||||
x_dbl[j] = x[j];
|
||||
y_dbl[j] = y[j];
|
||||
j++;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
//Print("x ",x[0], x_dbl[0]);
|
||||
CGraphic graphic;
|
||||
uint c = ColorToARGB(clrBlue,0x55);
|
||||
int height=ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,0);
|
||||
int width=ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,0);
|
||||
Print("CHART_HEIGHT_IN_PIXELS =",height,"pixels");
|
||||
Print("CHART_WIDTH_IN_PIXELS =",width,"pixels");
|
||||
graphic.Create(0,"Graphic",0,0,0,width,height);
|
||||
graphic.BackgroundColor(clrBlue);
|
||||
Print(graphic.BackgroundColor(), " ", clrBlue);
|
||||
//graphic.Create(0,"Graphic",0,30,30,780,380);
|
||||
double xx_dbl[]={-10,-4,-1,2,3,4,5,6,7,8};
|
||||
double yy_dbl[]={-5,4,-10,23,17,18,-9,13,17,4};
|
||||
CCurve *curve=graphic.CurveAdd(x_dbl,y_dbl,CURVE_LINES,"curveName");
|
||||
graphic.CurvePlotAll();
|
||||
graphic.Update();
|
||||
//curve.Update(x,y);
|
||||
//Print(curve.Name());
|
||||
*/
|
||||
}
|
||||
|
||||
void ChartDrawX(CJAVal &dataObject){
|
||||
|
||||
// DONT DRAW, if chartid noes not exist any more
|
||||
|
||||
string id=dataObject["id"].ToStr();
|
||||
|
||||
string graphicsType=dataObject["data"]["graphicstype"].ToStr();
|
||||
|
||||
if (graphicsType=="line") {
|
||||
string objectId=dataObject["data"]["objectId"].ToStr();
|
||||
datetime fromDate=dataObject["data"]["fromDate"].ToInt();
|
||||
datetime toDate=dataObject["data"]["toDate"].ToInt();
|
||||
double fromPrice=dataObject["data"]["fromPrice"].ToDbl();
|
||||
double toPrice=dataObject["data"]["toPrice"].ToDbl();
|
||||
|
||||
|
||||
/*
|
||||
double params[];
|
||||
for(int i=0;i<dataObject["params"].Size();i++){
|
||||
ArrayResize(params, i+1);
|
||||
params[i] = dataObject["params"][i].ToDbl();
|
||||
}
|
||||
*/
|
||||
//int paramColor = dataObject["params"]["color"]
|
||||
|
||||
int idx = GetChartWindowIdxByChartWindowId(id);
|
||||
|
||||
//int thisChartWindowObjectsCount = ArraySize(chartWindowObjects);
|
||||
//ArrayResize(chartWindowObjects, thisChartWindowObjectsCount+1);
|
||||
//chartWindowObjects[thisChartWindowObjectsCount] = objectId; // do I need this for deinit/reset? Probably Closing chart is sufficient
|
||||
|
||||
long chart_id = chartWindows[idx].id;
|
||||
int window = 0;
|
||||
//CChartObject object;
|
||||
//bool success = ObjectCreate(chart_id,objectId,OBJ_TREND,window,fromDate,fromPrice,toDate,toPrice); // add color param
|
||||
// ChartRedraw(chart_id);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// datetime time1 = 1581891300;
|
||||
// double price1 = 1.08346;
|
||||
// datetime time2 = 1581891600;
|
||||
// double price2 = 1.08354;
|
||||
|
||||
//chart_id = ChartOpen("EURUSD",PERIOD_M5);
|
||||
//Print(chart_id);
|
||||
/*
|
||||
bool CChartObjectTrend::Create(long chart_id,string name,int window,
|
||||
datetime time1,double price1,datetime time2,double price2)
|
||||
{
|
||||
bool result=ObjectCreate(chart_id,name,OBJ_TREND,window,time1,price1,time2,price2);
|
||||
if(result) result&=Attach(chart_id,name,window,2);
|
||||
//---
|
||||
return(result);
|
||||
}
|
||||
*/
|
||||
// CChartObject object;
|
||||
//ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1,price1,time2,price2,time2,price2+0.00005);
|
||||
//ObjectCreate(chart_id,"ellipse",OBJ_ELLIPSE,window,time1-100,price1,time1,price1+0.00010,time1+200,price1);
|
||||
//ObjectCreate(chart_id,"trend",OBJ_TREND,window,time1,price1,time2,price2);
|
||||
// ObjectCreate(chart_id,"reactangle",OBJ_TREND,window,time1,price1+0.00010,time2,price2+0.00020);
|
||||
|
||||
|
||||
//--- attach chart object
|
||||
/*
|
||||
if(!object.Attach(ChartID(),"MyObject",0,2))
|
||||
{
|
||||
printf("Object attach error");
|
||||
|
||||
}
|
||||
*/
|
||||
//ChartSetSymbolPeriod(ChartID(), Symbol(),PERIOD_M5);
|
||||
//ChartRedraw(chart_id);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Account information |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -950,19 +1232,24 @@ void GetOrders(CJAVal &dataObject){
|
||||
|
||||
void ResetSubscriptionsAndIndicators(){
|
||||
|
||||
ArrayFree(chartSymbols);
|
||||
ArrayFree(chartSymbolSettings);
|
||||
chartSymbolCount=0;
|
||||
ArrayFree(symbolSubscriptions);
|
||||
//ArrayFree(chartSymbolSettings);
|
||||
symbolSubscriptionCount=0;
|
||||
|
||||
bool error = false;
|
||||
for(int i=0;i<chartSymbolCount;i++){
|
||||
if(!IndicatorRelease(indicators[i])) error = true;
|
||||
for(int i=0;i<indicatorCount;i++){
|
||||
if(!IndicatorRelease(indicators[i].indicatorHandle)) error = true;
|
||||
}
|
||||
ArrayFree(indicators);
|
||||
ArrayFree(indicatorIds);
|
||||
//ArrayFree(indicatorIds);
|
||||
indicatorCount = 0;
|
||||
|
||||
if(ArraySize(chartSymbols)!=0 || ArraySize(chartSymbolSettings)!=0 || ArraySize(indicators)!=0 || ArraySize(indicatorIds)!=0 || error){
|
||||
for(int i=0;i<ArraySize(chartWindows);i++){
|
||||
if(!IndicatorRelease(chartWindows[i].indicatorHandle)) error = true;
|
||||
ChartClose(chartWindows[i].id);
|
||||
}
|
||||
|
||||
if(ArraySize(symbolSubscriptions)!=0 || ArraySize(indicators)!=0 || ArraySize(chartWindows)!=0 || error){
|
||||
// TODO Implement propery error codes and descriptions
|
||||
ActionDoneOrError(GetLastError(), __FUNCTION__);
|
||||
}
|
||||
@@ -1168,65 +1455,6 @@ ENUM_TIMEFRAMES GetTimeframe(string chartTF){
|
||||
return(tf);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Convert indicator constants from string to int |
|
||||
//+------------------------------------------------------------------+
|
||||
int GetIndicatorConstantValue(string indicatorConstantString){
|
||||
|
||||
int r = -1;
|
||||
ENUM_APPLIED_PRICE ap;
|
||||
r = StringToEnum(indicatorConstantString,ap);
|
||||
if(r>=0)return r;
|
||||
|
||||
ENUM_APPLIED_VOLUME av;
|
||||
r = StringToEnum(indicatorConstantString,av);
|
||||
if(r>=0)return r;
|
||||
|
||||
ENUM_STO_PRICE sp;
|
||||
r = StringToEnum(indicatorConstantString,sp);
|
||||
if(r>=0)return r;
|
||||
|
||||
ENUM_MA_METHOD mm;
|
||||
r = StringToEnum(indicatorConstantString,mm);
|
||||
if(r>=0)return r;
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
#define MIN_ENUM_VALUES 0
|
||||
#define MAX_ENUM_VALUES 255
|
||||
//+------------------------------------------------------------------+
|
||||
//| StringToEnum : Convert a string to an ENUM value, |
|
||||
//| it loop between min(0) and max(255), adjustable if needed. |
|
||||
//| Non existing enum value defined as -1. If -1 is used as an |
|
||||
//| enum value, code need to be adjusted to an other default. |
|
||||
//| Parameters : |
|
||||
//| in - string to convert |
|
||||
//| out - ENUM value |
|
||||
//| @return - int if conversion succeed, false otherwise |
|
||||
//| |
|
||||
//| Based on: |
|
||||
//| https://www.mql5.com/en/forum/61741/page3#comment_5491344 |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename ENUM>
|
||||
int StringToEnum(string in,ENUM &out)
|
||||
{
|
||||
out=-1;
|
||||
//---
|
||||
for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++)
|
||||
{
|
||||
ENUM enumValue=(ENUM)i;
|
||||
if(in==EnumToString(enumValue))
|
||||
{
|
||||
out=enumValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(out);
|
||||
}
|
||||
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Trade confirmation |
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -1386,4 +1614,5 @@ string getUninitReasonText(int reasonCode)
|
||||
}
|
||||
//---
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
|
||||
#define MIN_ENUM_VALUES 0
|
||||
#define MAX_ENUM_VALUES 255
|
||||
//+------------------------------------------------------------------+
|
||||
//| StringToEnum : Convert a string to an ENUM value, |
|
||||
//| it loops between min(0) and max(255), adjustable if needed. |
|
||||
//| Non existing enum value defined as -1. If -1 is used as an |
|
||||
//| enum value, code need to be adjusted to an other default. |
|
||||
//| Parameters : |
|
||||
//| in - string to convert |
|
||||
//| out - ENUM value |
|
||||
//| @return - int if conversion succeeded, false otherwise |
|
||||
//| |
|
||||
//| Based on: |
|
||||
//| https://www.mql5.com/en/forum/61741/page3#comment_5491344 |
|
||||
//+------------------------------------------------------------------+
|
||||
template<typename ENUM>
|
||||
int StringToEnum(string in,ENUM &out)
|
||||
{
|
||||
out=-1;
|
||||
//---
|
||||
for(int i=MIN_ENUM_VALUES;i<=MAX_ENUM_VALUES;i++)
|
||||
{
|
||||
ENUM enumValue=(ENUM)i;
|
||||
if(in==EnumToString(enumValue))
|
||||
{
|
||||
out=enumValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(out);
|
||||
}
|
||||
|
||||
|
||||
int StringToEnumInt(string indicatorConstantString, bool debug=1){
|
||||
|
||||
int r = -1;
|
||||
|
||||
ENUM_ACCOUNT_INFO_DOUBLE a1;
|
||||
r = StringToEnum(indicatorConstantString,a1);
|
||||
//if(debug) Print("ENUM type: ENUM_ACCOUNT_INFO_DOUBLE");
|
||||
if(r>=0)return r;
|
||||
ENUM_ACCOUNT_INFO_INTEGER a2;
|
||||
r = StringToEnum(indicatorConstantString,a2);
|
||||
if(r>=0)return r;
|
||||
ENUM_ACCOUNT_INFO_STRING a3;
|
||||
r = StringToEnum(indicatorConstantString,a3);
|
||||
if(r>=0)return r;
|
||||
ENUM_ACCOUNT_MARGIN_MODE a4;
|
||||
r = StringToEnum(indicatorConstantString,a4);
|
||||
if(r>=0)return r;
|
||||
ENUM_ACCOUNT_STOPOUT_MODE a5;
|
||||
r = StringToEnum(indicatorConstantString,a5);
|
||||
if(r>=0)return r;
|
||||
ENUM_ACCOUNT_TRADE_MODE a6;
|
||||
r = StringToEnum(indicatorConstantString,a6);
|
||||
if(r>=0)return r;
|
||||
ENUM_ALIGN_MODE a7;
|
||||
r = StringToEnum(indicatorConstantString,a7);
|
||||
if(r>=0)return r;
|
||||
ENUM_ANCHOR_POINT a8;
|
||||
r = StringToEnum(indicatorConstantString,a8);
|
||||
if(r>=0)return r;
|
||||
ENUM_APPLIED_PRICE a9;
|
||||
r = StringToEnum(indicatorConstantString,a9);
|
||||
if(r>=0)return r;
|
||||
ENUM_APPLIED_PRICE a10;
|
||||
r = StringToEnum(indicatorConstantString,a10);
|
||||
if(r>=0)return r;
|
||||
ENUM_APPLIED_VOLUME a11;
|
||||
r = StringToEnum(indicatorConstantString,a11);
|
||||
if(r>=0)return r;
|
||||
ENUM_ARROW_ANCHOR a12;
|
||||
r = StringToEnum(indicatorConstantString,a12);
|
||||
if(r>=0)return r;
|
||||
ENUM_BASE_CORNER a13;
|
||||
r = StringToEnum(indicatorConstantString,a13);
|
||||
if(r>=0)return r;
|
||||
ENUM_BOOK_TYPE a14;
|
||||
r = StringToEnum(indicatorConstantString,a14);
|
||||
if(r>=0)return r;
|
||||
ENUM_BORDER_TYPE a15;
|
||||
r = StringToEnum(indicatorConstantString,a15);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_FREQUENCY a16;
|
||||
r = StringToEnum(indicatorConstantString,a16);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_IMPACT a17;
|
||||
r = StringToEnum(indicatorConstantString,a17);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_IMPORTANCE a18;
|
||||
r = StringToEnum(indicatorConstantString,a18);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_MULTIPLIER a19;
|
||||
r = StringToEnum(indicatorConstantString,a19);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_SECTOR a20;
|
||||
r = StringToEnum(indicatorConstantString,a20);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_TIMEMODE a21;
|
||||
r = StringToEnum(indicatorConstantString,a21);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_TYPE a22;
|
||||
r = StringToEnum(indicatorConstantString,a22);
|
||||
if(r>=0)return r;
|
||||
ENUM_CALENDAR_EVENT_UNIT a23;
|
||||
r = StringToEnum(indicatorConstantString,a23);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_EVENT a24;
|
||||
r = StringToEnum(indicatorConstantString,a24);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_MODE a25;
|
||||
r = StringToEnum(indicatorConstantString,a25);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_POSITION a26;
|
||||
r = StringToEnum(indicatorConstantString,a26);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_PROPERTY_DOUBLE a27;
|
||||
r = StringToEnum(indicatorConstantString,a27);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_PROPERTY_INTEGER a28;
|
||||
r = StringToEnum(indicatorConstantString,a28);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_PROPERTY_STRING a29;
|
||||
r = StringToEnum(indicatorConstantString,a29);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_VOLUME_MODE a30;
|
||||
r = StringToEnum(indicatorConstantString,a30);
|
||||
if(r>=0)return r;
|
||||
ENUM_CL_DEVICE_TYPE a31;
|
||||
r = StringToEnum(indicatorConstantString,a31);
|
||||
if(r>=0)return r;
|
||||
ENUM_COLOR_FORMAT a32;
|
||||
r = StringToEnum(indicatorConstantString,a32);
|
||||
if(r>=0)return r;
|
||||
ENUM_CRYPT_METHOD a33;
|
||||
r = StringToEnum(indicatorConstantString,a33);
|
||||
if(r>=0)return r;
|
||||
ENUM_CUSTOMIND_PROPERTY_DOUBLE a34;
|
||||
r = StringToEnum(indicatorConstantString,a34);
|
||||
if(r>=0)return r;
|
||||
ENUM_CHART_PROPERTY_INTEGER a35;
|
||||
r = StringToEnum(indicatorConstantString,a35);
|
||||
if(r>=0)return r;
|
||||
ENUM_CUSTOMIND_PROPERTY_STRING a36;
|
||||
r = StringToEnum(indicatorConstantString,a36);
|
||||
if(r>=0)return r;
|
||||
ENUM_DATABASE_EXPORT_FLAGS a37;
|
||||
r = StringToEnum(indicatorConstantString,a37);
|
||||
if(r>=0)return r;
|
||||
ENUM_DATABASE_FIELD_TYPE a38;
|
||||
r = StringToEnum(indicatorConstantString,a38);
|
||||
if(r>=0)return r;
|
||||
ENUM_DATABASE_OPEN_FLAGS a39;
|
||||
r = StringToEnum(indicatorConstantString,a39);
|
||||
if(r>=0)return r;
|
||||
ENUM_DATABASE_PRINT_FLAGS a40;
|
||||
r = StringToEnum(indicatorConstantString,a40);
|
||||
if(r>=0)return r;
|
||||
ENUM_DATATYPE a41;
|
||||
r = StringToEnum(indicatorConstantString,a41);
|
||||
if(r>=0)return r;
|
||||
ENUM_DAY_OF_WEEK a42;
|
||||
r = StringToEnum(indicatorConstantString,a42);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_ENTRY a43;
|
||||
r = StringToEnum(indicatorConstantString,a43);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_PROPERTY_DOUBLE a44;
|
||||
r = StringToEnum(indicatorConstantString,a44);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_PROPERTY_INTEGER a45;
|
||||
r = StringToEnum(indicatorConstantString,a45);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_PROPERTY_STRING a46;
|
||||
r = StringToEnum(indicatorConstantString,a46);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_REASON a47;
|
||||
r = StringToEnum(indicatorConstantString,a47);
|
||||
if(r>=0)return r;
|
||||
ENUM_DEAL_TYPE a48;
|
||||
r = StringToEnum(indicatorConstantString,a48);
|
||||
if(r>=0)return r;
|
||||
ENUM_DRAW_TYPE a49;
|
||||
r = StringToEnum(indicatorConstantString,a49);
|
||||
if(r>=0)return r;
|
||||
ENUM_DX_BUFFER_TYPE a50;
|
||||
r = StringToEnum(indicatorConstantString,a50);
|
||||
if(r>=0)return r;
|
||||
ENUM_DX_FORMAT a51;
|
||||
r = StringToEnum(indicatorConstantString,a51);
|
||||
if(r>=0)return r;
|
||||
ENUM_DX_HANDLE_TYPE a52;
|
||||
r = StringToEnum(indicatorConstantString,a52);
|
||||
if(r>=0)return r;
|
||||
ENUM_DX_PRIMITIVE_TOPOLOGY a53;
|
||||
r = StringToEnum(indicatorConstantString,a53);
|
||||
if(r>=0)return r;
|
||||
ENUM_DX_SHADER_TYPE a54;
|
||||
r = StringToEnum(indicatorConstantString,a54);
|
||||
if(r>=0)return r;
|
||||
ENUM_ELLIOT_WAVE_DEGREE a55;
|
||||
r = StringToEnum(indicatorConstantString,a55);
|
||||
if(r>=0)return r;
|
||||
ENUM_FILESELECT_FLAGS a56;
|
||||
r = StringToEnum(indicatorConstantString,a56);
|
||||
if(r>=0)return r;
|
||||
ENUM_FILE_POSITION a57;
|
||||
r = StringToEnum(indicatorConstantString,a57);
|
||||
if(r>=0)return r;
|
||||
ENUM_FILE_PROPERTY_INTEGER a58;
|
||||
r = StringToEnum(indicatorConstantString,a58);
|
||||
if(r>=0)return r;
|
||||
ENUM_GANN_DIRECTION a59;
|
||||
r = StringToEnum(indicatorConstantString,a59);
|
||||
if(r>=0)return r;
|
||||
ENUM_INDEXBUFFER_TYPE a60;
|
||||
r = StringToEnum(indicatorConstantString,a60);
|
||||
if(r>=0)return r;
|
||||
ENUM_INDICATOR a61;
|
||||
r = StringToEnum(indicatorConstantString,a61);
|
||||
if(r>=0)return r;
|
||||
ENUM_INIT_RETCODE a62;
|
||||
r = StringToEnum(indicatorConstantString,a62);
|
||||
if(r>=0)return r;
|
||||
ENUM_LICENSE_TYPE a63;
|
||||
r = StringToEnum(indicatorConstantString,a63);
|
||||
if(r>=0)return r;
|
||||
ENUM_LINE_STYLE a64;
|
||||
r = StringToEnum(indicatorConstantString,a64);
|
||||
if(r>=0)return r;
|
||||
ENUM_MA_METHOD a65;
|
||||
r = StringToEnum(indicatorConstantString,a65);
|
||||
if(r>=0)return r;
|
||||
ENUM_MQL_INFO_INTEGER a66;
|
||||
r = StringToEnum(indicatorConstantString,a66);
|
||||
if(r>=0)return r;
|
||||
ENUM_MQL_INFO_STRING a67;
|
||||
r = StringToEnum(indicatorConstantString,a67);
|
||||
if(r>=0)return r;
|
||||
ENUM_OBJECT a68;
|
||||
r = StringToEnum(indicatorConstantString,a68);
|
||||
if(r>=0)return r;
|
||||
ENUM_OBJECT_PROPERTY_DOUBLE a69;
|
||||
r = StringToEnum(indicatorConstantString,a69);
|
||||
if(r>=0)return r;
|
||||
ENUM_OBJECT_PROPERTY_INTEGER a70;
|
||||
r = StringToEnum(indicatorConstantString,a70);
|
||||
if(r>=0)return r;
|
||||
ENUM_OBJECT_PROPERTY_STRING a71;
|
||||
r = StringToEnum(indicatorConstantString,a71);
|
||||
if(r>=0)return r;
|
||||
ENUM_OPENCL_HANDLE_TYPE a72;
|
||||
r = StringToEnum(indicatorConstantString,a72);
|
||||
if(r>=0)return r;
|
||||
ENUM_OPENCL_PROPERTY_INTEGER a73;
|
||||
r = StringToEnum(indicatorConstantString,a73);
|
||||
if(r>=0)return r;
|
||||
ENUM_PLOT_PROPERTY_STRING a74;
|
||||
r = StringToEnum(indicatorConstantString,a74);
|
||||
if(r>=0)return r;
|
||||
ENUM_POINTER_TYPE a75;
|
||||
r = StringToEnum(indicatorConstantString,a75);
|
||||
if(r>=0)return r;
|
||||
ENUM_POSITION_PROPERTY_DOUBLE a76;
|
||||
r = StringToEnum(indicatorConstantString,a76);
|
||||
if(r>=0)return r;
|
||||
ENUM_ORDER_PROPERTY_INTEGER a77;
|
||||
r = StringToEnum(indicatorConstantString,a77);
|
||||
if(r>=0)return r;
|
||||
ENUM_PLOT_PROPERTY_STRING a78;
|
||||
r = StringToEnum(indicatorConstantString,a78);
|
||||
if(r>=0)return r;
|
||||
ENUM_PROGRAM_TYPE a79;
|
||||
r = StringToEnum(indicatorConstantString,a79);
|
||||
if(r>=0)return r;
|
||||
ENUM_SERIESMODE a80;
|
||||
r = StringToEnum(indicatorConstantString,a80);
|
||||
if(r>=0)return r;
|
||||
ENUM_SERIES_INFO_INTEGER a81;
|
||||
r = StringToEnum(indicatorConstantString,a81);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_BASE_DOUBLE a82;
|
||||
r = StringToEnum(indicatorConstantString,a82);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_BASE_INTEGER a83;
|
||||
r = StringToEnum(indicatorConstantString,a83);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_BASE_STRING a84;
|
||||
r = StringToEnum(indicatorConstantString,a84);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_INFO_DOUBLE a85;
|
||||
r = StringToEnum(indicatorConstantString,a85);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_INFO_INTEGER a86;
|
||||
r = StringToEnum(indicatorConstantString,a86);
|
||||
if(r>=0)return r;
|
||||
ENUM_SIGNAL_INFO_STRING a87;
|
||||
r = StringToEnum(indicatorConstantString,a87);
|
||||
if(r>=0)return r;
|
||||
ENUM_STATISTICS a88;
|
||||
r = StringToEnum(indicatorConstantString,a88);
|
||||
if(r>=0)return r;
|
||||
ENUM_STO_PRICE a89;
|
||||
r = StringToEnum(indicatorConstantString,a89);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_CALC_MODE a90;
|
||||
r = StringToEnum(indicatorConstantString,a90);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_CHART_MODE a91;
|
||||
r = StringToEnum(indicatorConstantString,a91);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_DOUBLE a92;
|
||||
r = StringToEnum(indicatorConstantString,a92);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_INTEGER a93;
|
||||
r = StringToEnum(indicatorConstantString,a93);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_STRING a94;
|
||||
r = StringToEnum(indicatorConstantString,a94);
|
||||
if(r>=0)return r;
|
||||
ENUM_STATISTICS a95;
|
||||
r = StringToEnum(indicatorConstantString,a95);
|
||||
if(r>=0)return r;
|
||||
ENUM_STO_PRICE a96;
|
||||
r = StringToEnum(indicatorConstantString,a96);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_CALC_MODE a97;
|
||||
r = StringToEnum(indicatorConstantString,a97);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_CHART_MODE a98;
|
||||
r = StringToEnum(indicatorConstantString,a98);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_DOUBLE a99;
|
||||
r = StringToEnum(indicatorConstantString,a99);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_INTEGER a100;
|
||||
r = StringToEnum(indicatorConstantString,a100);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_INFO_STRING a101;
|
||||
r = StringToEnum(indicatorConstantString,a101);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_OPTION_MODE a102;
|
||||
r = StringToEnum(indicatorConstantString,a102);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_OPTION_RIGHT a103;
|
||||
r = StringToEnum(indicatorConstantString,a103);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_ORDER_GTC_MODE a104;
|
||||
r = StringToEnum(indicatorConstantString,a104);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_SWAP_MODE a105;
|
||||
r = StringToEnum(indicatorConstantString,a105);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_TRADE_EXECUTION a106;
|
||||
r = StringToEnum(indicatorConstantString,a106);
|
||||
if(r>=0)return r;
|
||||
ENUM_SYMBOL_TRADE_MODE a107;
|
||||
r = StringToEnum(indicatorConstantString,a107);
|
||||
if(r>=0)return r;
|
||||
ENUM_TERMINAL_INFO_DOUBLE a108;
|
||||
r = StringToEnum(indicatorConstantString,a108);
|
||||
if(r>=0)return r;
|
||||
ENUM_TERMINAL_INFO_INTEGER a109;
|
||||
r = StringToEnum(indicatorConstantString,a109);
|
||||
if(r>=0)return r;
|
||||
ENUM_TERMINAL_INFO_STRING a110;
|
||||
r = StringToEnum(indicatorConstantString,a110);
|
||||
if(r>=0)return r;
|
||||
ENUM_TIMEFRAMES a111;
|
||||
r = StringToEnum(indicatorConstantString,a111);
|
||||
if(r>=0)return r;
|
||||
ENUM_TRADE_REQUEST_ACTIONS a112;
|
||||
r = StringToEnum(indicatorConstantString,a112);
|
||||
if(r>=0)return r;
|
||||
ENUM_TRADE_TRANSACTION_TYPE a113;
|
||||
r = StringToEnum(indicatorConstantString,a113);
|
||||
if(r>=0)return r;
|
||||
|
||||
return(-1);
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| JsonAPIIndicator.mq5 |
|
||||
//| Copyright 2020, Gunther Schulz |
|
||||
//| https://www.guntherschulz.de |
|
||||
//+------------------------------------------------------------------+
|
||||
|
||||
#property copyright "2020 Gunther Schulz"
|
||||
#property link "https://www.guntherschulz.de"
|
||||
#property version "1.00"
|
||||
|
||||
#include <StringToEnumInt.mqh>
|
||||
#include <Zmq/Zmq.mqh>
|
||||
#include <Json.mqh>
|
||||
|
||||
// Set ports and host for ZeroMQ
|
||||
string HOST="localhost";
|
||||
int CHART_SUB_PORT=15562;
|
||||
|
||||
// ZeroMQ Cnnections
|
||||
Context context("MQL5 JSON API");
|
||||
Socket chartLiveSocket(context,ZMQ_SUB);
|
||||
|
||||
//#property indicator_separate_window
|
||||
//#property indicator_buffers 1
|
||||
//#property indicator_plots 1
|
||||
//---- plot MA
|
||||
//#property indicator_label1 "MA"
|
||||
//#property indicator_type1 DRAW_LINE
|
||||
//#property indicator_color1 clrRed
|
||||
//#property indicator_style1 STYLE_SOLID
|
||||
//#property indicator_width1 1
|
||||
|
||||
//--- input parameters
|
||||
input string IndicatorId="";
|
||||
input string ShortName="JsonAPI";
|
||||
input string ColorSyle = "clrRed";
|
||||
input string LineType = "DRAW_LINE";
|
||||
input string LineStyle = "STYLE_SOLID";
|
||||
input int LineWidth = 1;
|
||||
|
||||
//--- indicator settings
|
||||
double Buffer[];
|
||||
bool debug = false;
|
||||
|
||||
bool first = false;
|
||||
|
||||
//double Values[];
|
||||
//ENUM_TIMEFRAMES originalTF = ChartPeriod();
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator initialization function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnInit()
|
||||
{
|
||||
bool result = chartLiveSocket.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);
|
||||
chartLiveSocket.setSubscribe("");
|
||||
chartLiveSocket.setLinger(1000);
|
||||
// Number of messages to buffer in RAM.
|
||||
chartLiveSocket.setReceiveHighWaterMark(5); // TODO confirm settings
|
||||
}
|
||||
|
||||
//--- indicator buffers mapping;
|
||||
ArraySetAsSeries(Buffer,true);
|
||||
SetIndexBuffer(0,Buffer,INDICATOR_DATA);
|
||||
|
||||
color colorstyle = StringToColor(ColorSyle);
|
||||
int linetype = StringToEnumInt(LineType);
|
||||
int linestyle = StringToEnumInt(LineStyle);
|
||||
SetStyle(ShortName, colorstyle, linetype, linestyle, LineWidth);
|
||||
//---
|
||||
return(INIT_SUCCEEDED);
|
||||
}
|
||||
|
||||
|
||||
void SetStyle(string shortname, color colorstyle, int linetype, int linestyle, int linewidth) {
|
||||
IndicatorSetString(INDICATOR_SHORTNAME,shortname);
|
||||
PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,colorstyle);
|
||||
PlotIndexSetInteger(0,PLOT_DRAW_TYPE,linetype);
|
||||
PlotIndexSetInteger(0,PLOT_LINE_STYLE,linestyle);
|
||||
PlotIndexSetInteger(0,PLOT_LINE_WIDTH,linewidth);
|
||||
}
|
||||
|
||||
//+------------------------------------------------------------------+
|
||||
//| Custom indicator iteration function |
|
||||
//+------------------------------------------------------------------+
|
||||
int OnCalculate(const int rates_total,
|
||||
const int prev_calculated,
|
||||
const datetime &time[],
|
||||
const double &open[],
|
||||
const double &high[],
|
||||
const double &low[],
|
||||
const double &close[],
|
||||
const long &tick_volume[],
|
||||
const long &volume[],
|
||||
const int &spread[])
|
||||
{
|
||||
// While a new candle is forming, set the current value to the previous value
|
||||
if(rates_total>prev_calculated){
|
||||
Buffer[0] = EMPTY_VALUE;
|
||||
}
|
||||
|
||||
/*
|
||||
https://www.mql5.com/en/docs/constants/structures/mqlparam
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//--- return value of prev_calculated for next call
|
||||
return(rates_total);
|
||||
}
|
||||
|
||||
void SubscriptionHandler(ZmqMsg &chartMsg){
|
||||
CJAVal message;
|
||||
|
||||
//ResetLastError();
|
||||
|
||||
// Get data from reguest
|
||||
string msg=chartMsg.getData();
|
||||
if(debug) Print("Processing:"+msg);
|
||||
|
||||
// Deserialize msg to CJAVal array
|
||||
if(!message.Deserialize(msg)){
|
||||
//ActionDoneOrError(65537, __FUNCTION__);
|
||||
Alert("Deserialization Error");
|
||||
ExpertRemove();
|
||||
}
|
||||
if(message["indicatorChartId"]==IndicatorId) WriteToBuffer(message);
|
||||
}
|
||||
|
||||
void WriteToBuffer(CJAVal &message) {
|
||||
int bufferSize = ArraySize(Buffer);
|
||||
int messageDataSize = message["data"].Size();
|
||||
if(first==false) {
|
||||
//ArrayFill(Buffer, 0, ArraySize(Buffer), EMPTY_VALUE);
|
||||
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,bufferSize-messageDataSize);
|
||||
first = true;
|
||||
}
|
||||
|
||||
for(int i=0;i<messageDataSize;i++){
|
||||
// don't add more elements than the automatically sized buffer array can hold
|
||||
if(i+1<bufferSize){
|
||||
// the first element is the current unformed candle, so we start at index 1
|
||||
// we reverse the order of the incoming values, which are expected to be ascending
|
||||
Buffer[i+1] = message["data"][messageDataSize-1-i].ToDbl();
|
||||
}
|
||||
}
|
||||
Buffer[0] = EMPTY_VALUE;
|
||||
|
||||
|
||||
|
||||
//ArrayResize(Values, bufferSize);
|
||||
//for(int i=0;i<bufferSize;i++){
|
||||
// Values[i] = Buffer[i];
|
||||
// }
|
||||
// Print(Buffer[1], " ", Values[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
TODO:
|
||||
|
||||
display drawing when the last history price arrived, not on first live signal
|
||||
|
||||
buy/sell arrows
|
||||
create custom symbols for backtest data
|
||||
restore after time frame change. try valuestore again?
|
||||
alternative: set Buffer to all EMPTY_VALUE, if not the original TF
|
||||
dependable redraw after calling timer
|
||||
|
||||
*/
|
||||
|
||||
void CheckMessages(){
|
||||
// Timer() works, when the indicator is manually added to a chart, but not with ChartIndicatorAdd()
|
||||
|
||||
ZmqMsg chartMsg;
|
||||
|
||||
// Recieve chart instructions stream from client via live Chart socket.
|
||||
chartLiveSocket.recv(chartMsg,true);
|
||||
|
||||
// Request recived
|
||||
if(chartMsg.size()>0){
|
||||
// Handle subscription SubscriptionHandler().
|
||||
Print(chartMsg.getData());
|
||||
SubscriptionHandler(chartMsg);
|
||||
ChartRedraw(ChartID());
|
||||
}
|
||||
}
|
||||
|
||||
void OnChartEvent(const int id,
|
||||
const long &lparam,
|
||||
const double &dparam,
|
||||
const string &sparam)
|
||||
{
|
||||
//if(id==CHARTEVENT_CUSTOM+222 && sparam==IndicatorId) CheckMessages();
|
||||
if(id==CHARTEVENT_CUSTOM+222) CheckMessages();
|
||||
}
|
||||
//+----------------------------------------------------
|
||||
@@ -10,3 +10,14 @@ sed -i '1s/^/\xef\xbb\xbf/' ./Experts/JsonAPI.clean.mq5
|
||||
mv ./Experts/JsonAPI.clean.mq5 ./Experts/JsonAPI.mq5
|
||||
|
||||
|
||||
# Remove non-printable ASCII characters
|
||||
tr -cd '[:print:]\n\r' < ./Indicators/JsonAPIIndicator.mq5 > ./Indicators/JsonAPIIndicator.clean.mq5
|
||||
# Add UTF-8 BOM
|
||||
sed -i '1s/^/\xef\xbb\xbf/' ./Indicators/JsonAPIIndicator.clean.mq5
|
||||
mv ./Indicators/JsonAPIIndicator.clean.mq5 ./Indicators/JsonAPIIndicator.mq5
|
||||
|
||||
# Remove non-printable ASCII characters
|
||||
tr -cd '[:print:]\n\r' < ./Include/EnumStringToInt.mqh > ./Include/EnumStringToInt.clean.mqh
|
||||
# Add UTF-8 BOM
|
||||
sed -i '1s/^/\xef\xbb\xbf/' ./Include/EnumStringToInt.clean.mqh
|
||||
mv ./Include/EnumStringToInt.clean.mqh ./Include/EnumStringToInt.mqh
|
||||
Reference in New Issue
Block a user