Search code examples
indicatoralgorithmic-tradingmetatrader4forex

Cannot get MT4 indicator to work using prebuilt library


I'm using the code from this article https://www.mql5.com/en/articles/159 to calculate when a new bar opens but it's not displaying the historical data for the indicator.

I have modified the TimeCurrent() to iTime( _Symbol, _Period, shift ) so as to try to handle this, but it's not working.

Could you tell me what I'm doing wrong please?

#property indicator_separate_window #property indicator_buffers 1 #property indicator_color1 RoyalBlue #include <Lib_CisNewBar.mqh> CisNewBar current_chart; //---- input parameters extern int Length=18; // Bollinger Bands Period extern int Deviation=2; // Deviation was 2 extern double MoneyRisk=1.00; // Offset Factor extern int Signal=1; // Display signals mode: 1-Signals & Stops; 0-only Stops; 2-only Signals; extern int Line=1; // Display line mode: 0-no,1-yes extern int Nbars=1000; //---- indicator buffers double TrendBuffer[]; extern bool SoundON=true; bool TurnedUp = false; bool TurnedDown = false; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { string short_name; //---- indicator line SetIndexBuffer(0,TrendBuffer); SetIndexStyle(0,DRAW_LINE,0,1); IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS)); short_name="Example ("+Length+","+Deviation+")"; IndicatorShortName(short_name); SetIndexLabel(0,"Trend Value"); //---- SetIndexDrawBegin(0,Length); //---- return(INIT_SUCCEEDED); } void deinit() { } 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[]) { int shift; for (shift=Nbars;shift>=0;shift--) { TrendBuffer[shift]=0; } for (shift=Nbars-Length-1;shift>=0;shift--) { int period_seconds=PeriodSeconds(_Period); datetime new_time=iTime(_Symbol,_Period,shift)/period_seconds*period_seconds; if(current_chart.isNewBar(new_time)) { Print("time[shift] = "+TimeToString(time[shift])); if( Close[shift] > Close[shift+1] ) TrendBuffer[shift]=1; else if(Close[shift] < Close[shift+1] ) TrendBuffer[shift]=-1; else TrendBuffer[shift]=0; } } return(0); }

Thanks.


Solution


  • a) The "new"-MQL4.56789 has another syntax

    For Custom Indicator, the "new"-MQL4.56789 source shall rather read
    void OnInit(){ ... }
    and
    void OnDeinit( const int anMT4_Reason2callDeinit ){ ... }


    b) The datetime

    Your code defines a variable new_time, typed as a datetime

    The datetime type is intended for storing the date and time as the number of seconds elapsed since January 01, 1970.

    and

    Values range from 1 January, 1970 to 31 December, 3000

    So, in case of your new_time assignment, the proper iTime() value is divided by an amount of PeriodSeconds() and right next it is re-multiplied by the exact same value, which should not change the value of the iTime() result.

    Such operation, while having no theoretical impact on result, might in practice of a code-execution introduce a risk of a numerical inaccuracy, range overflow/underflow and a theoretical notice about a resolution of an 8-byte class storage is not helping to go past the upper bound limit, stated in the documentation as Dec-31, 3000.

    In similar cases unpredicatable results and even MT4 unhandled exceptions and MQL4-code terminations are to be expected.

    What worse one may expect for a production grade software? So, avoid, avoid and avoid any such risk.

    There is no direct positive value for such a Custom Indicator calculation step.


    c) TimeCurrent() / PeriodSeconds() side-effect of rounding

    While iTime() is always divisible by it's "own" time-frame PeriodSeconds(), TimeCurrent() is not.

    Thus one may read the original ( assumed ) construct of

    TimeCurrent() / PeriodSeconds()   // .DIV is subject to rounding to int
                  * PeriodSeconds();  //      before the forthcoming .MUL
    

    "hacks" the need to align a [last known server time, time of the last quote receipt for one of the symbols selected in the "Market Watch" window] to one's "own" time-frame value of a start-of-current bar time.


    d) The article is from 11 October 2010 (!) - be very carefull in MQL4

    Current MQL4 code-execution engine is Build 890 ( 25 Sep 2015 ), so your cited source was using an MQL5 language syntax some 5 years old (!!), which namely in MQL4-domain means _be_very_carefull_

    In the meantime string-s ceased to be string-s,
    many GUI functions have several calling protocols in parallel,
    and
    countless man*years of DLL/API-code-base dev/maint were lost due to similar moving sands.

    So -5- years gap is a warning per-se.


    One never enters the same river twice


    The recent state of "new"-MQL4.56789 allows a clean approach:

    in case your motivation is just to be able to detect on-demand a situation a new bar has started, the Build-890/1174 compiler allows for a cleaner approach:

    bool aNewBarEVENT(   const string anFxSYMBOL,               // _Symbol,
                         const int    aTimeFRAME                // PERIOD_M6
                         )
    {    static int   pBars  = EMPTY;                           // previous
                int   oBars  = iBars( anFxSYMBOL, aTimeFRAME ); // observed
    
         if (         pBars == oBars ) return( False );         // .NACK
                      pBars  = oBars,  return( True  );         // .UPD + .ACK
    }