Strange behaviour of an indicator at weekends (without ticks)

 

If I need to have synchronized data in the indicator, I perform a synchronization check. Unfortunately, if there is no next tick coming (e.g. on weekends), there is no further call to OnCalculate and the indicator is not calculated. I helped myself by calling the ChartSetSymbolPeriod function. In this case, the indicator is calculated (there are values in the data window), but it is not displayed on the chart. If I want the indicator to be displayed as well, I still have to call the ChartRedraw function.

Is there any other solution?

Isn't it basically a bug if the buffer is calculated correctly but not displayed?

I am attaching the code of the dummy indicator that shows a single arrow on the Close of the last bar. It has two inputs, use/not use ChartSetSymbolPeriod and  ChartRedraw.

#property indicator_chart_window
#property indicator_buffers   1
#property indicator_plots     1
#property indicator_color1    clrDeepSkyBlue
#property indicator_width1    2

input bool  useChartSetSymbolPeriod = true;     // Use ChartSetSymbolPeriod
input bool  useChartRedraw          = false;    // Use ChartRedraw

double
   buff[];

int OnInit()
  {
   ::printf("Use ChartRedraw: %s ; Use ChartSetSymbolPeriod: %s", string(useChartRedraw), string(useChartSetSymbolPeriod));
   ::IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   ::SetIndexBuffer(0, buff);
   ::PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
   ::PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   ::PlotIndexSetString(0, PLOT_LABEL, "Arrow");
   ::PlotIndexSetInteger(0, PLOT_ARROW, 232);
   return(INIT_SUCCEEDED);
  }

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[])
  {
   static bool
      isSynchronized = false;
   if(prev_calculated < 1)
     {
      ::ArrayInitialize(buff, EMPTY_VALUE);
      if(!isSynchronized)
        {
         if(::SeriesInfoInteger(_Symbol, _Period, SERIES_SYNCHRONIZED))
           {
            isSynchronized = true;
            ::Print("Is synchronized");
            if(useChartSetSymbolPeriod)
              {
               ::ChartSetSymbolPeriod(0, _Symbol, _Period);
              }
           }
         else
           {
            ::Print("Is not synchronized");
           }
         return -1;
        }
     }
   int
      i = prev_calculated;
   for(; i < rates_total && !_StopFlag; i++) 
     {
      if(i < rates_total - 1)
         buff[i] = EMPTY_VALUE;
      else
         buff[i] = close[i];
     }
   ::printf("%s starts from %d and ends at %d", __FUNCTION__, prev_calculated, i);
   
   if(useChartRedraw && prev_calculated < 1)
      ::ChartRedraw();
   
   return(rates_total - 1);
  }
 

Your code is always returning -1, that's why it doesn't draw anything.

By the way returning a negative value is useless, on the next call, prev_calculate will always be 0.

 
Alain Verleyen #:

Your code is always returning -1, that's why it doesn't draw anything.

By the way returning a negative value is useless, on the next call, prev_calculate will always be 0.

Thanks Alain for the response.

I don't think that's the problem. If I use the ChartRedraw function, the arrow is displayed without any problems. Moreover, I have verified that even if I return zero instead of -1, the behavior does not change.

 
Petr Nosek #:

Thanks Alain for the response.

I don't think that's the problem. If I use the ChartRedraw function, the arrow is displayed without any problems. Moreover, I have verified that even if I return zero instead of -1, the behavior does not change.

It is the problem NOW on a week-end. Even using ChartRedraw (which is useless in your case),  it doesn't draw anything BECAUSE it returns ALWAYS -1. And by that I mean it ALWAYS execute this line :

      return -1;

And your buffer is never set.

Additionally what's the point to call ChartSetSymbolPeriod() is the series IS synchronized ?!

P.S: I was wrong and confused by your strange logic.
 
Using ChartSetSymbolPeriod() to true, the indicator is always correctly displayed on my side. No need for ChartRedraw().
 
Alain Verleyen #:

 it doesn't draw anything BECAUSE it returns ALWAYS -1

It's not true. The indicator after the serie is synchronized and called ChartSetSymbolPeriod() (the purpose of calling is refreshing the chart and new calling OnCalculate() without another tick) right calculate and fill the indicator's buffer (see the first picture), but without calling ChartRedraw not show the arrow on the chart. Oncalculate() returns right value (see the second picture) not -1 or 0.

Filled buffer without drawing

OnCalculate return

 
Alain Verleyen #:
Using ChartSetSymbolPeriod() to true, the indicator is always correctly displayed on my side. No need for ChartRedraw().

If you turn on the indicator on the weekend without running "Use ChartRedraw", turn off the platform and then start the platform again, the indicator will be calculated correctly but not displayed. It will appear when you click somewhere else with your mouse, when you scroll the chart, etc. But without some other action, it won't show up. If you turn on "Use ChartRedraw" and do the same thing (turn the platform off and on), not only will the indicator calculate, but it will display fine.

 

I have modified the code a bit (see below) so that I can skip the unnecessary condition call on each pass of the main loop in OnCalculate(). I consider this solution as a workaround and still think it is a bug.

#property indicator_chart_window
#property indicator_buffers   1
#property indicator_plots     1
#property indicator_color1    clrDeepSkyBlue
#property indicator_width1    2

input bool  useChartSetSymbolPeriod = true;     // Use ChartSetSymbolPeriod
input bool  useChartRedraw          = false;    // Use ChartRedraw

double
   buff[];

int OnInit()
  {
   ::printf("Use ChartRedraw: %s ; Use ChartSetSymbolPeriod: %s", string(useChartRedraw), string(useChartSetSymbolPeriod));
   ::IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   ::SetIndexBuffer(0, buff);
   ::PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
   ::PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   ::PlotIndexSetString(0, PLOT_LABEL, "Arrow");
   ::PlotIndexSetInteger(0, PLOT_ARROW, 232);
   return(INIT_SUCCEEDED);
  }

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[])
  {
   static bool
      isSynchronized = false;
   
   if(!isSynchronized)
     {
      if(::SeriesInfoInteger(_Symbol, _Period, SERIES_SYNCHRONIZED))
        {
         isSynchronized = true;
         ::Print("Is synchronized");
         ::ArrayInitialize(buff, EMPTY_VALUE);
         if(useChartSetSymbolPeriod)
            ::ChartSetSymbolPeriod(0, _Symbol, _Period);
        }
      else
         ::Print("Is not synchronized");
      return 0;
     }
   else if(useChartRedraw && prev_calculated < 1) ::ChartRedraw();
   
   int
      i = prev_calculated;
   for(; i < rates_total && !_StopFlag; i++) 
     {
      if(i < rates_total - 1)
         buff[i] = EMPTY_VALUE;
      else
         buff[i] = close[i];
     }
   
   ::printf("%s starts from %d and ends at %d and returns %d", __FUNCTION__, prev_calculated, i, rates_total - 1);
   
   return(rates_total - 1);
  }
 
Petr Nosek #:

It's not true. The indicator after the serie is synchronized and called ChartSetSymbolPeriod() (the purpose of calling is refreshing the chart and new calling OnCalculate() without another tick) right calculate and fill the indicator's buffer (see the first picture), but without calling ChartRedraw not show the arrow on the chart. Oncalculate() returns right value (see the second picture) not -1 or 0.


Right, I was running it with useChartSetSymbolPeriod = false;

Your example shows that ChartRedraw() is not needed, as even with it nothing is displayed. I am developing indicators since 10 years now, and I know ChartRedraw() is not needed, something else is at play.

 

Fresh platform start :


Not sure what is happening on your side.

You didn't answer my question... why calling ChartSetSymbolPeriod() when it IS synchronized ?

 
Alain Verleyen #:

You didn't answer my question... why calling ChartSetSymbolPeriod() when it IS synchronized ?

If I skip calling the ChartSetSymbolPeriod() function on the weekend (when there are no ticks) even though the symbol is synchronized, then the code doesn't execute the main loop at all, so nothing is calculated. This can be simulated by entering "Use ChartSetSymbolPeriod" = false.

Without calling ChartSetSymbolPeriod():

Without


With calling ChartSetSymbolPeriod():

With


My terminal build is older than yours, but I don't know if it is the problem (I don't believe it).

The strangest thing is that don't need calling ChartRedraw() now and the arrow is displayed. But the same code didn't work (the arrow didn't displayed but the buffer was filled) a few hours ago.