stevehopwoodforex.com
https://www.stevehopwoodforex.com/phpBB3/
Print view

Workaround for Indicator Boot Problems
https://www.stevehopwoodforex.com/phpBB3/viewtopic.php?t=3983
Page 1 of 1
Author:  autoabacus [ Tue Dec 09, 2014 3:00 am ]
Post subject:  Workaround for Indicator Boot Problems

Empty4 starts to run an indicator without waiting for account information to be available or history updating to be completed. For more sophisticated indicators this can lead to crashes with out of range index or divide by zero errors, or odd results, on changing period, or when Empty4 is restarted after being closed down with indicators loaded on charts.

EAs do not have the same problem. I reported this indicator problem to MetaQuotes as a bug, but got the response that it was working as designed.

This "design feature" also prevents use of the Account Server name with indicators, something I often want when storing indicator data that can be different for different brokers.

So I developed the following workaround, which after 4 versions to cope with additional quirks, seems to be working well. The workaround involves:

- splitting OnInit() into two parts, a part with nothing critical in it that kicks off a one second timer, and the main initialisation code in OwnInit() or whatever.

- start() being prevented from running until the timer gives the all clear

- the timer code checks for Empty4 being ready, and scrolls the chart backwards to download more history if required. Once all is ok the timer code runs OwnInit(), and allows start() to run.

Note: This workaround can only be used with an indicator which uses start() rather than OnCalculate() if weekend (market closed) running is required.

I started on this workaround at Build 722 time. At the time of posting I am using it with Build 752.

The code required is:

Code: Select all

// Globals

bool BootingB,    // Empty4 startup workaround in progress
     AutoScrollB; // To remember the chart's auto scroll setting as it is set to off while the Empty4 startup workaround is in progress

int EnoughBars;   // Bars sufficient for the indicator to run, allowing the Empty4 indicator booting problem workaround to exit

datetime InitTickT; // TST of the last tick at initialisation time

int OnInit() {
  ... anything which will not error on lack of account info or history can go here as usual e.g. buffer and indicator function calls.
  // Start of workaround
  BootingB  = true;
  InitTickT = TimeCurrent();
  EnoughBars = ... as requited by the indicator for the current period
  AutoScrollB = ChartGetInteger(0, CHART_AUTOSCROLL);
  if (AutoScrollB) ChartSetInteger(0, CHART_AUTOSCROLL, false); // turn off auto scroll if on
  if (EventSetTimer(1))
    Print("1 second timer started");
  else
    return InitError("EventSetTimer() failed"); // this will abort
  // Everything else is done in OwnInit() called from OnTimer() once the timer has determined that the history is ok
  return INIT_SUCCEEDED;
}

// bool OwnInit()
//      -------
// Initialisation function called from OnTimer() once Empty4 booting is complete
bool OwnInit() {
  // All the stuff which the indicator wants to do during initialisation which involves use of account info and history.
  ...
}

void OnTimer() {
  if (BootingB) {
    static int sPrevBars, sScrollsAtLastBarsChange, sScrolls, sNumNoConnection;
    if (!IsConnected()) {
      // Test for connectivity with comment to show what is happening rather than let the following code handle it with potentially a lot of log messages.
      // On the first time here on an Empty4 boot after closedown with the indi loaded the IsConnected() call gives false even when connected.
      Comment("Waiting for internet connection");
      return;
    }
    Comment("");
    PrintFormat("Empty4 indicator start workaround: Enough Bars %d, Acct# %d, Bars %d, Prev Bars %d, Scrolling %d", EnoughBars, AccountNumber(), Bars, sPrevBars, sScrolls);
    if (!AccountNumber() || Bars>sPrevBars || ((!EnoughBars || Bars<=EnoughBars) && (sScrolls-sScrollsAtLastBarsChange<3))) {
    //  Login not available (AccountNumber() serving as a check for all account info) || Bars still increasing || (not enough bars && scroll back attempt in progress)
      // Empty4 booting not complete yet
      if (AccountNumber() && Bars == sPrevBars) {
        // Login available and Bars have stopped increasing but EnoughBars haven't been reached or are still in a scroll back attempt, so scroll back in order to try to download more history
        ChartNavigate(0, CHART_BEGIN, -2000); // only does the number of bars visible on screen so this must be repeated
        sScrolls++;
      }else
        sScrollsAtLastBarsChange = sScrolls; // Used because it seemed that more than 1 second is needed to complete downloading a screen's worth of bars. 3 times was enough for all brokers I have tested this with.
      sPrevBars = Bars;
      return; // Empty4 booting not complete yet
    }
    // Empty4 booting appears to be complete
    BootingB = false;
    ChartSetInteger(0, CHART_AUTOSCROLL, AutoScrollB); // restore the auto scroll setting
    ChartNavigate(0, CHART_END, Bars); // navigate to the end of the chart
    if (!OwnInit()) return;
    if (TimeCurrent() == InitTickT) start(); // No tick has arrived since startup so call start() like Empty4 does for an indicator after running OnInit() to give weekend output
  }
  ... anything else to be done by the timer
}

void start() {
  if (BootingB) return; // Part of working around the Empty4 design fault of calling OnInit() for an indicator before history updating is complete or account information is available.
  ... rest of start() as usual
}
All times are UTC Page 1 of 1