Problems with a script to plot lines at round numbers

 

Hi forum,

I have no idea why this script works sometimes and sometimes it doesn't. If I use it on NZDUSD H1 it looks fine but if I use it on EURUSD there are a lot of lines missing. Also when I change timeframes there a many lines missing. Additionally JPY-pairs cause some trouble. I have three levels for the lines. The first level are numbers like 1.1 / 1.2 / 130.00 / 0.80 etc. The second level is 1.15 / 1.55 / 0.85 / 135.00 .... and the last level are numbers like 1.1050 / 1.4950 / 0.8250 / 129.50. I think you got the point.

Hopefully somebody has an idea why my script doesn't work properly. By the way, I only print the lines in the visible area on the screen. As soon as the script works fine I do it as an indicator which will adjust itself to the current chart.

Here is my script:

void OnStart()
{
   ObjectsDeleteAll();
   int Level1, Level2, Level3;
   if (Digits == 3) {
      Level1 = 1000;
      Level2 = 100;
      Level3 = 50;
   }
   else if (Digits == 5) {
      Level1 = 1000;
      Level2 = 100;
      Level3 = 50;
   }
   double PriceMax   = WindowPriceMax();
   double PriceMin   = WindowPriceMin();
   double Price      = NormalizeDouble(PriceMax, Digits);
   int counter       = (int)MathFloor((PriceMax - PriceMin)/Point);
   for (int i = 1; i <= counter; i++) {
      double calc = (Price-MathFloor(Price))*MathPow(10, Digits-1);
      if (MathMod(calc, Level1) == 0) {
         ObjectCreate(0, (string)Price, OBJ_HLINE, 0, 0, Price);
         ObjectSetInteger(0, (string)Price, OBJPROP_COLOR, clrBlack);
         ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_SOLID);
      }
      else if (MathMod(calc, Level2) == 0) {
         ObjectCreate(0, (string)Price, OBJ_HLINE, 0, 0, Price);
         ObjectSetInteger(0, (string)Price, OBJPROP_COLOR, clrBlack);
         ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_DASHDOT);
      }
      else if (MathMod(calc, Level3) == 0) {
         ObjectCreate(0, (string)Price, OBJ_HLINE, 0, 0, Price);
         ObjectSetInteger(0, (string)Price, OBJPROP_COLOR, clrBlack);
         ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_DOT);
      }
      Price = NormalizeDouble(Price - Point, Digits);
   }
}
 
mar:why my script doesn't work properly.
     if (MathMod(calc, Level1) == 0) {
  1. Comparing with equality will usually not be true. The == operand. - MQL4 forum
  2. Just typed, Not compiled.
    double   MathNearest(  double v, double to){ return to * MathRound(v / to);    }
    ////////////////////////////
       double Level1 = 1000 * pips2dbl,
              Level2 = 100 * pips2dbl,
              Level3 = 50 * pips2dbl;
       double PriceMax   = WindowPriceMax();
       double PriceMin   = WindowPriceMin();
       for( double price = MathNearest(PriceMin, Level3); price < Price_Max; price += Level3){
             ObjectCreate(0, (string)Price, OBJ_HLINE, 0, 0, Price);
             ObjectSetInteger(0, (string)Price, OBJPROP_COLOR, clrBlack);
          if(price == MathNearest(price, Level1)
             ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_SOLID);        
          else if(price == MathNearest(price, Level2)
             ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_DASHDOT);
          else
             ObjectSetInteger(0, (string)Price, OBJPROP_STYLE, STYLE_DOT);
       }
    Just typed, Not compiled.
  3. Had you checked your return code you would have found that you are not calling ObjectCreate. What are Function return values ? How do I use them ? - MQL4 forum and Common Errors in MQL4 Programs and How to Avoid Them - MQL4 Articles
 

This is awesome! Thank you very much!!! 

I still don't understand everything but I will. Pretty unclear is the fact that comparing with equality will usually not be true. That's new for me. I am going to read your links about the == operand now.

Thanks again! 

 

This:

double pips2dbl = 10*Point;

is not correct!

10 is regarded as integer and therefore 10*Point will be an integer so 10*0.00001 = 0.0

Just write:

double pips2dbl = 10.0*Point;

Same problems here:

   double Level1 = 1000 * pips2dbl,
          Level2 = 100 * pips2dbl,
          Level3 = 50 * pips2dbl;
 

Good to know, thank you gooly!

I changed the code a bit and now it's working. The last code was only working with JPY pairs and I modified it according to WHRoeders postings about the == operand:

double MathNearest(  double v, double to){ return to * MathRound(v / to);    }
double pips2dbl = 10*Point;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   ObjectsDeleteAll();
   double Level1 = 1000 * pips2dbl,
          Level2 = 100 * pips2dbl,
          Level3 = 50 * pips2dbl;
   double PriceMax   = iHigh(NULL, PERIOD_MN1, iHighest(NULL, PERIOD_MN1, MODE_HIGH, Bars-1, 0));
   double PriceMin   = iLow(NULL, PERIOD_MN1, iLowest(NULL, PERIOD_MN1, MODE_LOW, Bars-1, 0));
   double price;
   for (price = MathNearest(PriceMin, Level3); price < PriceMax; price += Level3) {
      ObjectCreate(0, (string)price, OBJ_HLINE, 0, 0, price);
      if (MathAbs(price - MathNearest(price, Level1)) < Point / 2.) {        // if (a==b)
         ObjectSetInteger(0, (string)price, OBJPROP_COLOR, clrBlack);
         ObjectSetInteger(0, (string)price, OBJPROP_STYLE, STYLE_SOLID);
      }    
      else if (MathAbs(price - MathNearest(price, Level2)) < Point / 2.) {  // if (a==b)
         ObjectSetInteger(0, (string)price, OBJPROP_COLOR, clrGray);
         ObjectSetInteger(0, (string)price, OBJPROP_STYLE, STYLE_DASHDOT);
      }
      else {
         ObjectSetInteger(0, (string)price, OBJPROP_COLOR, clrDarkGray);
         ObjectSetInteger(0, (string)price, OBJPROP_STYLE, STYLE_DOT);
      }
   }
}

But I will also change the definition of the pips2dbl now.

 
gooly:

This:

is not correct!

10 is regarded as integer and therefore 10*Point will be an integer so 10*0.00001 = 0.0


I think that you are wrong there. As Point is a double the result will be correct at 0.0001

It is when dividing integers ie 5/2, the result would return as an integer 2.0 whereas 5.0/2 would return 2.5 

 

Ahh - you're right, I just checked it.

As far as I remember it was before b600+ the case.

 
gooly: 10 is regarded as integer and therefore 10*Point will be an integer so 10*0.00001 = 0.0
False. The int will be expanded to a double for the multiple.  Typecasting - MQL4 Documentation
You're thinking of int/int is still an int?


 
WHRoeder:
gooly: 10 is regarded as integer and therefore 10*Point will be an integer so 10*0.00001 = 0.0
False. The int will be expanded to a double for the multiple.  Typecasting - MQL4 Documentation
You're thinking of int/int is still an int?



I was right the type cast is not always what you might expect and this is the script-example:

void OnStart()
  {
//---
int i = 0,all = 100;
double done1,done2;

   while(i++<all){
      done1 = i/all;
      done2 =1.0*i/all;
      Comment("i[",i,"] done1: ",DoubleToString(done1,3),"   done2: ",DoubleToString(done2,3));
      Sleep(300);
   }
}

done1 stays 0.000 until i=100 and then it becomes 1 other than done2!!

 
      done1 = i/all;
Integer divided by an integer=integer
Reason: