ObjectCreate Trendline - page 2

 

I suspect that the object isn't drawn fully for the first 2 loops . . .

I have had problems with Comment when running the ST at max speed and grabbing a chart, the comment can lag the chart and I have had comment data that was wrong for the chart it was drawn on, as a result I switched to a Label Object and that fixed my issue.

Try this . . . run at full speed, then at the pause switch to 31 and resume.

The first 10 values are 0 because the channel stops 10 bars ago . . .

extern int length=100;
int initial=0;

#include <WinUser32.mqh>

//---------------------------------------------------------------------------------------+
int init(){
   Comment("");
}
//---------------------------------------------------------------------------------------+
int deinit(){
}
//---------------------------------------------------------------------------------------+
int start(){

   static datetime newBar = 0;
   
   if( newBar==Time[1] )
      return( 0 );
         
   newBar= Time[1]; 
   initial++;
   
   if( initial==2*length || initial == (2*length) + 10 ){
      Regress();
   }
   
   return( 0 );
}
//---------------------------------------------------------------------------------------+
void Regress(){
   
   static bool ChannelDrawn = false;
   
   if(!ChannelDrawn)
      {
      ObjectDelete("regress");
      ObjectCreate("regress",OBJ_REGRESSION,0,Time[length],0,Time[0],0);
      ObjectSet   ("regress",OBJPROP_COLOR, Yellow);
      ChannelDrawn = true;
      keybd_event(19,0,0,0); // 19=Pause
      keybd_event(19,0,KEYEVENTF_KEYUP,0);
      return;
      }
   
   
               
   string str="";
   for( int p=0; p<3; p++ ){
      str = str + "\n\nStart= " + DoubleToStr( ObjectGet("regress",OBJPROP_PRICE2), Digits );
      str = str + "  :: End= "  + DoubleToStr( ObjectGet("regress",OBJPROP_PRICE1), Digits );
      str = str + "\n";
      for( int n=0; n<51; n++ ){
         str= str + "n=" + n + "->" + DoubleToStr( ObjectGetValueByShift("regress",n), Digits ) + "   ";
         if( n % 7 == 6 )
            str = str + "\n";
      }
   }
   Comment( str );
      
   return;
}
 

I tried your code with this modificaltion:

         double shiftedLineValue = ObjectGetValueByShift("regress",n);
         if (shiftedLineValue == 0.0)
            Print("n = " + n + ", shiftedLineValue = " + shiftedLineValue + " -> error code: " + GetLastError());
         str= str + "n=" + n + "->" + DoubleToStr(shiftedLineValue, Digits ) + "   ";

But it not creates even an error code! By placing a Sleep(1); after Object creating lines, the error disappears. But how we know how much time is needed to draw the object, when will be ready, if there is no error code?

 
RaptorUK:

I suspect that the object isn't drawn fully for the first 2 loops . . .

I have had problems with Comment when running the ST at max speed and grabbing a chart, the comment can lag the chart and I have had comment data that was wrong for the chart it was drawn on, as a result I switched to a Label Object and that fixed my issue.

Try this . . . run at full speed, then at the pause switch to 31 and resume.

The first 10 values are 0 because the channel stops 10 bars ago . . .

Interesting method. I tried it. Thanks :-)

Erzo (thank you) your Sleep(1) is the same thing basically. It looks like the regression line has been spawned to a new thread and it does not complete before the ObjectCreate command returns. Therefore some random delay is needed to make it work. That is not a robust solution and could mess up in a real time environment. I suppose we could put in a while loop and just wait until the first value of the regression line is both non-zero and equal to the value by shift function - but that seems too much of a bodge.

I think it is easier to steal the regression code from that indicator I linked to earlier.

 

Well here it is in a script for anyone who is interested ...

extern int initialBar = 1;
extern int finalBar   = 100;

// Graphical comparison of internal regression calculation against home grown version
// Need to use DIY version as internal regression function does not give results in a deterministic time
int start(){
   ObjectsDeleteAll();
   ObjectCreate( "regress",OBJ_REGRESSION,0, Time[finalBar],0,Time[initialBar],0);
   ObjectSet( "regress", OBJPROP_COLOR, Yellow);
      
   DIYregress(finalBar,initialBar);
   
   return(0);
}
//-----------------------------------------------------------------------------------+
bool DIYregress(int last, int first){
   // Basic regression code was lifted from LinearRegressionChannel indicator by dimicr
   
   // We start from the present and work backwards
   // so we want first < last
   if( first >= last ){
      Print("ERROR: needs first < last");
      return( false );
   }
   
   double sumy =  0.0;
   double sumxy = 0.0;
   //double sumx =  0.0;
   //double sumx2 = 0.0;

   int length = last - first + 1;
   
   // calculate the partial sums for the linear regression
   for(int i=0; i<length; i++){
      sumy  += Close[i+first];
      sumxy += Close[i+first]*i;
      // sumx  += i;    // no need to actually do the sumation for i and i * i
      // sumx2 += i*i;  // as there are textbook formulae for them
   }
   double sumx  = ((length-1)*length)/2;
   double sumx2 = ((2*length*length - 3* length + 1 )*length )/6;
      
   double c= sumx2 * length - sumx * sumx;
   if(c==0.0){
      Print("ERROR: zero val in linear regression!");
      c=Point; // well that isn't going to work correctly but prevents a divide-by-zero error
   }
   
   // using the form y= a + b*x;
   double b = ( sumxy*length - sumx*sumy )/c;
   double a = ( sumy - sumx * b )/length;
   
   double firstPrice = a;
   double lastPrice =  a + b * (length-1);
   
   // For test purposes shift line by 1 point to see it, otherwise it is totally overwritten by the regression line
   //ObjectCreate( "DIY",OBJ_TREND,0, Time[last],lastPrice+Point,Time[first],firstPrice+Point);
   ObjectCreate( "DIY",OBJ_TREND,0, Time[last],lastPrice,Time[first],firstPrice);
   ObjectSet( "DIY", OBJPROP_COLOR, Red);
   ObjectSet( "DIY", OBJPROP_RAY, false );
   
   return( true );
}

The comparison to the internal regression line is perfect and the trendline version gets covered by the other regression line, even though the trendline version is drawn afterwards.

 

I found the source code for the regression line from Metaquotes, linked here for reference.

https://www.mql5.com/en/forum/45148

Unsurprisingly it is almost identical with mine. The sad thing is that the calculation of the standard deviation channel is not there. Mine is close to the built in version but is in error by about 5% high or low depending on the chart and the length :-(

This code follows immediately after code above (but before the return in the DIYregress function). Using OBJ_STDDEVCHANNEL for this comparison.

This code follows on from the line ObjectSet( "DIY", OBJPROP_RAY, false );

   double dev= 0.0;
   for(i=0; i<length; i++){
      double d = Close[i+first] - a - b*i;   // the difference between the regression line and the data
      dev += d * d;
   }
   
   dev = 1.05*MathSqrt( dev/(length-2.0) );
   
   ObjectCreate( "upper",OBJ_TREND,0, Time[last],lastPrice+dev,Time[first],firstPrice+dev);
   ObjectSet( "upper", OBJPROP_COLOR, Aqua);
   ObjectSet( "upper", OBJPROP_RAY, false );
 
Good insight.
 

Dabbler I discovered by testing MQ uses population deviation. It's slightly different to regular deviation, that might be the cause of your 5% dev error. Here is my test script. Place a Std Dev Channel on the chart and name it "testchannel". Script tries to find the line equations of that testchannel and then draws trendlines of them, so it should match testchannel with 3 trendlines. I let my ones ray so you can see them.

//+------------------------------------------------------------------------+
//| test script finds line equations of a StdDevChannal already on chart   |
//| named "testchannel" then tests equations with trendlines.   SDC 2013   |
//+------------------------------------------------------------------------+
int init()
 
{
 ObjectDelete("regress");
 ObjectDelete("highdev");
 ObjectDelete("lowdev");
 return(0);
}
//+------------------------------------------------------------------------+
int start()
{
 if(ObjectFind("testchannel")<0)
 {
  Alert("testchannel not found");
  return(0);
 }
 double a,b,y,m,n,x,sumx,sumx2,sumxy,sumy,sumy_m2;
 double slope,intercept,dev,y1,y2;
//get beginning and end bar times from testchannel
 double time1 = ObjectGet("testchannel",OBJPROP_TIME1);
 double time2 = ObjectGet("testchannel",OBJPROP_TIME2);
//get first and last bar numbers of test channel
 int begin = iBarShift(Symbol(),0,time1,true);
 int end = iBarShift(Symbol(),0,time2,true);

//---- get vals for least squares regression
 for(int i=begin; i>=end;i--)
 {
  y = Close[i];			//-- loop through closes
  x=i;                   	//-- bars by chart index
  n++;                   	//-- number of bars in channel
  sumx += x;             	//-- sum of bars in channel
  sumy += y;             	//-- sum of close prices
  sumxy += (x*y);        	//-- sum of bars*close
  sumx2 += (x*x);        	//-- sum of bars squared
  m = sumy/n;            	//-- mean of close prices
 }
//---- get val for deviation
 for(i=begin;i>=end;i--)
 {
  y = Close[i];          	//-- loop through closes
  sumy_m2 += (y-m)*(y-m);	//-- sum of closes-mean squared
 }
//---- slope(b) intercept(a)
 b = (n*sumxy-sumx*sumy)/(n*sumx2-sumx*sumx);
 a = (sumy - (b*sumx))/n;
//---- insert first and last testchannel bar numbers into equation
 y1 = a+b*begin;
 y2 = a+b*end;
//---- calculate deviation
 dev = MathSqrt(sumy_m2)/MathSqrt(n);
//---- draw test trendlines
 ObjectCreate("regress",OBJ_TREND,0,time1,y1,time2,y2);
 ObjectCreate("lowdev",OBJ_TREND,0,time1,y1-dev,time2,y2-dev);
 ObjectCreate("highdev",OBJ_TREND,0,time1,y1+dev,time2,y2+dev);
//----
 return(0);
}
Reason: