Search code examples
mql4metatrader4

Why is an information in my printf() function incorrect in MQL4?


My print formatting is giving me random answers, despite my coding being correct. I'm trying to display the candle bar lengths of the previous two candle bars prior to a trade entry. Here is the coding I've used.

PCL1 & PCL2 are the relevant field entries. They are divided by _Point to give an integer formatting.

PCL2 = Previous Candle Stick length, Shift 2

PCL1 = Previous Candle Stick length, Shift 1

In this example I have focused on the Shift2 Candlestick

Short_Bull_2_Close   =  iClose( Symbol(), 0, 2 );
Short_Bull_2_Open    =  iOpen(  Symbol(), 0, 2 );
CandleBody_2         =  ( Short_Bull_2_Close - Short_Bull_2_Open );
                     // Gives the Candlebody length in pips.

And this is my printf() coding:

printf( "PCL1 [%d] PCL2 [%d]", CandleBody_1 / Point,
                               CandleBody_2 / Point
        ); // ___________________________________________________________  SELL//

However, all I get is as pictured & highlighted..enter image description here


Solution

  • 1) MQL4 is a strong typed language ( declaration precedes any use of a variable )
    + MQL4 has a historical feature of a number "normalisation"

    An assumption (cit.) "They are divided by _Point to give an integer" does not hold.

    Once any number has been declared double in a source code as:

    double upFractal = 0.0,
           dnFractal = 0.0;
    

    the MQL4-compiler handles these numbers forever in an IEEE-754 floating point number representation and calls particular sub-version of operations on any arithmetics operation such number is entring into. The reason is simple, double has different handling than ( New-MQL4.56789 ) float, the more than int et al. Some numbers, represented in IEEE-754, are inexact by-definition, some could remain exact ( if they happen to be some direct power-of-2 and still in it's "virgin"-state ( have not yet been spoiled by any arithmetic operation, that would introduce an un-avoidable im-precision into their binary-representatio ) ).

    Why im-precision?
    Why un-avoidable?

    For non-virgin numbers, the binary-representation may yield into an infinitely-long description of the value. On the contrary, the storage of any value in MQL4 is restricted to { 1 | 4 | 8 }-bytes of memory-space and thus the infinite-representation is un-avoidably cut at some distance, introducing a principal im-precision , expressed by:

    DBL_EPSILON ~ 2.2204460492503131e-016
    FLT_EPSILON ~ 1.192092896e-07
    beyond which any two numbers, represented in IEEE-754 binary-format, look to the compiled code as "equal", even if they are not principally equal, just due to the IEEE-754 format inherent im-precision.

    For indeed historical reasons, double typed values ought have been always NormalizeDouble() converted, if one wants to send these to the MetaTrader Server-side processing and/or compare values on a fair ground.

    2) MQL4 operations with {double | int }- typed variables

    If one had declared a variable to be double, it remains double forever.
    If one had declared a variable to be int, even an int/3 will remain int, ignoring the fractional products of division operation ( which sometimes causes headaches to not so carefull MQL4 coders ).

    The same applied to an initial assumption above yields to a surprise, that double/double -> double even in cases, the division could be satisfactorily considered ( almost ) integer. So never assume a type conversion to happen just by the values of the operands.

    For that purpose, there are two sorts of syntax-supports:

    • an explicit conversion function int( ... ) or double( ... )
    • an inline typecast directive ( (int) CandleBody_1 / _Point )

    Epilogue: ( ... a must read for Custom Indicator designers, where CPU-performance kills )

    As said above, calling (int) NormalizeDouble(...) is a double-nonsense ( well beyond a belt + suspenders paradigm ), first, as a historically built-in function NormalizeDouble still returns double, thus providing zero-benefit from spending CPU to crunch the numbers once it still yields a double, next as the division of the number a double value of _Point is very expensive and inefficient, compared to the fact, the _Point is related to int value of Digits by a formula of 1 / 10^Digits -- so the fastest and cleanest way to do the conversion, without spending avoidable CPU-cycles, is MULTIPLICATION ...
    yes,
    from a computer-side of fast & efficient processing, the best is
    int( MAKE_aPriceDOMAIN_VALUE_an_INT_NUM_OF_POINTs * CandleBody_1 ),
    re-using a constant
    int MAKE_aPriceDOMAIN_VALUE_an_INT_NUM_OF_POINTs = MathPow( 10, Digits );