Opening the Indicator in Multiple Charts

636 views Asked by At

I found an interesting MT4 indicator which shows remaining time of the next bar in the chart. But that works for the particular pairs which I would choose.

But I want that program to work/applied on all opened pairs by just applying to any of the opened one pair.

Please check the code below::::

//--- input parameters
input string LabelFont = "Arial";
input int LabelSize = 15;
input color LabelColor = clrRed;
input int LabelDistance = 15;
const string LabelName = "TimeToNextCandle";
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   EventKillTimer();
   ObjectDelete(0, LabelName);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   CalcTime();
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   CalcTime();
  }
//+------------------------------------------------------------------+
void CalcTime(void)
  {
   // checking is there output label. create it if necessary
   if (ObjectFind(LabelName) == -1)
   {
      ObjectCreate(0, LabelName, OBJ_LABEL, 0, 0, 0);
      ObjectSetString(0, LabelName, OBJPROP_FONT, LabelFont);
      ObjectSetInteger(0, LabelName, OBJPROP_FONTSIZE, LabelDistance);
      ObjectSetInteger(0, LabelName, OBJPROP_COLOR, LabelColor);
      ObjectSetInteger(0, LabelName, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER);
      ObjectSetInteger(0, LabelName, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
      ObjectSetInteger(0, LabelName, OBJPROP_XDISTANCE, LabelDistance);
      ObjectSetInteger(0, LabelName, OBJPROP_YDISTANCE, LabelDistance);
   }
   // calculating remaining time to next candle
   datetime TimeTo = PeriodSeconds() - (TimeCurrent() - Time[0]);
   // assembling the output string depending on current period on the chart
   string Out = StringFormat("%.2d", TimeSeconds(TimeTo));
   if (TimeTo >= 3600)
   {
      Out = StringFormat("%.2d:%s", TimeMinute(TimeTo), Out);
      if (TimeTo >= 86400)
        Out = StringFormat("%d day(s) %.2d:%s", int(TimeTo / 86400), TimeHour(TimeTo), Out);
      else
        Out = StringFormat("%d:%s", TimeHour(TimeTo), Out);
   }
   else
     Out = StringFormat("%d:%s", TimeMinute(TimeTo), Out);
   ObjectSetString(0, LabelName, OBJPROP_TEXT, StringFormat("%s (%.0f%s)", Out, 100.0 / PeriodSeconds() * TimeTo, "%"));
  }
//+------------------------------------------------------------------+
1

There are 1 answers

0
user3666197 On

Let's split the task into two parts:
Part I.:
How to measure the time.

Metatrader Terminal architecture has moved the code-execution units into three principal types:
- {0|1}-unique ExpertAdvisor-type of MQL4-code, per MT4.graph
- {0|1|..|n} CustomIndicatero-type of MQL4-code, per MT4.graph
- {0|1}-unique Script-type of MQL4-code, per MT4.graph

This may sound interesting to use more and more CustomIndicators, but there is a catch.

Catch XXII.

All CustomIndicators and all ExpertAdvisors are responsively executed upon a Market Event message arrival. That means, whenever a Market Event arrives, all ExpertAdvisors and all CustomIndicators are pushed to execute their respective processing ( OnTick(){...} function is called in ExpertAdvisor(s), OnCalculate(){...} function is called in CustomIndicator ). That still sounds reasonable. The Catch XXII. is hidden in the fact, that all CustomIndicators share a SINGLE THREAD. Yes, ALL !

This translated into plain english means, avoid everything that could block from CustomIndicators and put it elsewhere, but the CustomIndicator MQL4-code.

Using New-MQL4.56789 EventSetTimer()-facilities does not improve the already obvious problem, just the very opposite, so let's forget to use OnTimer().


So, how to safely design such feature?

The possible way is to use a low-profile service design, deployed in a helper-( non-trading )-MT4.graph for such utility service and best use a Script ( as it is absolutely under one's control, asynchronous to any Event-triggered EA / CI code-execution and works safe and sound even during times, when the Market is closed or the connection to the MetaTrader Server is down ).

This "central"-clock ( timing facility ) provides a unique, reference-time and stores it so as to be available to any "consumer" in other MT4.graphs.

// MQL4-Script
double assembleGV( int aTimeNOW,
                   int aPERIOD
                   ){

#define BrokerServerGMToffset 0                 // Yes, Real World isn't perfect :o)

       int aTimeToEoB = PeriodSeconds( aPERIOD ) - ( aTimeNOW - ( iTime( _Symbol, aPERIOD, 0 ) - BrokerServerGMToffset ) );
       return( aTimeToEoB + aTimeToEoB / PeriodSeconds( aPERIOD ) );                                // INT + FRAC ( non-%, but having the value of the remainder )
}

while True{
      Sleep( 250 ); int TimeNow = TimeGMT();
   // -------------------------------------- COOL DOWN CPU-CORE(s)
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=60",       assembleGV( TimeNow, PERIOD_M1  ) ); // for PERIOD_M1
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=300",      assembleGV( TimeNow, PERIOD_M5  ) ); // for PERIOD_M5 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=900",      assembleGV( TimeNow, PERIOD_M15 ) ); // for PERIOD_M15
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=1800",     assembleGV( TimeNow, PERIOD_M30 ) ); // for PERIOD_M30
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=3600",     assembleGV( TimeNow, PERIOD_H1  ) ); // for PERIOD_H1 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=14400",    assembleGV( TimeNow, PERIOD_H4  ) ); // for PERIOD_H4 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=86400",    assembleGV( TimeNow, PERIOD_D1  ) ); // for PERIOD_D1 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=604800",   assembleGV( TimeNow, PERIOD_W1  ) ); // for PERIOD_W1 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=2592000",  assembleGV( TimeNow, PERIOD_MN1 ) ); // for PERIOD_MN1

      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=120",      assembleGV( TimeNow, PERIOD_M2  ) ); // for PERIOD_M2 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=180",      assembleGV( TimeNow, PERIOD_M3  ) ); // for PERIOD_M3 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=240",      assembleGV( TimeNow, PERIOD_M4  ) ); // for PERIOD_M4 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=360",      assembleGV( TimeNow, PERIOD_M6  ) ); // for PERIOD_M6 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=600",      assembleGV( TimeNow, PERIOD_M10 ) ); // for PERIOD_M10
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=720",      assembleGV( TimeNow, PERIOD_M12 ) ); // for PERIOD_M12
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=1200",     assembleGV( TimeNow, PERIOD_M20 ) ); // for PERIOD_M20
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=7200",     assembleGV( TimeNow, PERIOD_H2  ) ); // for PERIOD_H2 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=10800",    assembleGV( TimeNow, PERIOD_H3  ) ); // for PERIOD_H3 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=21600",    assembleGV( TimeNow, PERIOD_H6  ) ); // for PERIOD_H6 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=28800",    assembleGV( TimeNow, PERIOD_H8  ) ); // for PERIOD_H8 
      GlobalVariableSet( "msMOD_TimeSERVICE_4_PERIOD=43200",    assembleGV( TimeNow, PERIOD_H12 ) ); // for PERIOD_H12
}

Part II.:
How to display the time in all MT4.graphs
in a most lightweight form?

Given the central service takes care of respective ENUM_TIMEFRAMES listed ( being "visited" or not by other MT4.graphs ) and posting the pre-fabbed results of such "time-service" calculus,
any potential "consumer"
may just asynchronously check and react to the "time-service" posted values,
in places, where feasible and safe in it's respective flow of code-execution, kind users are under full control to declare, where such lightweight GUI-call may appear and where all updates may benefit from ( a potentially deferred ) enforced GUI-repaint:

/* MQL4-ExpertAdvisor
      or
        other Script
      or even
        a lightweight add-on to a CustomIndicator */

#define LabelNAME          "msMOD_StackOverflowDEMO"

bool    aDeferred_GUI_REPAINT = False;
.
..
RepaintTIME();
..
.
if (  aDeferred_GUI_REPAINT ){
      aDeferred_GUI_REPAINT = False;
      WindowRedraw();
}

void RepaintTIME(){
     static string aGlobalVariableNAME = "msMODmsMOD_TimeSERVICE_4_PERIOD=" + (string)PeriodSeconds();

     ObjectSetString( 0,
                      LabelNAME,            // external responsibility to set/create
                      OBJPROP_TEXT,
                      StringFormat( "%d (%.0f %%)",
                                     int( GlobalVariableGet( aGlobalVariableNAME ) ),                       // SECONDS TILL EoB
                                     (    GlobalVariableGet( aGlobalVariableNAME ) % 1 ) * 100.0 )          // PER CENTO [%] EXPRESSED REMAINDER
                      );
     aDeferred_GUI_REPAINT = True;
}

enter image description here