One Reason why rectangle traders don't want to move from MT4 to MT5 - page 2

 
Carl Schreiber #:

I don't understand your problem. A MT5 rectangle is e.g. defined by [1.2.21|10] (corner top left) and [2.3.21|2] (corner bottom right). For the missing other two corners - who ever needs them - you just have swap the coordinate values: [1 .2.21|2] and [ 2.3.21|10]. What is the problem?

Hi @Carl Schreiber

the problem of traders who use rectangles in technical analysis is that we cant resize and move rectangle edges to the level we want. This happens when the other side of rectangle is not visible. In this case you need to zoom out and then try to move rectangle...

This is why we are searching for solution for rectangle to have all four corner points.

I understand your suggestion, but I don't know how to preform this on chart? Will your solution provide 4 rectangle corner points? If so, can you write a code please?

Here is example from chart, why I am still analyzing charts in MT4... So how would you move lower edge of rectangle without changing zoom or timeframe of chart?

rectangle move mt5

 
I cannot find a function able to give you the object under the mouse. I thought, I have read such, but seems, I am wrong.

The issue will be finding the correct object.

You'd need to check the properties of each object known to the terminal. Maybe maintain an internal list of objects for faster access. Keeping this list in sync is probably also quite some work.

It poses some thought challenges.
 
Igor Zizek #:


what about this name:

"Four corner points of rectangle" or just  "Four corner points rectangle"


yes I know it is long but it is accurate :) Any other ideas

4X corner rectangle haha

 

This sort of works.

#include <ChartObjects\ChartObjectsShapes.mqh>
#include <ChartObjects\ChartObjectsTxtControls.mqh>
#include <Arrays\ArrayObj.mqh>
CArrayObj rects,corners;
long chartID=ChartID();
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CHANGE) {
      if(ObjectGetInteger(chartID,sparam,OBJPROP_TYPE)==OBJ_RECTANGLE) {
//---
         CChartObjectRectangle *rect=new CChartObjectRectangle;
         const datetime time0=(datetime)ObjectGetInteger(chartID,sparam,OBJPROP_TIME,0);
         const double price0=ObjectGetDouble(chartID,sparam,OBJPROP_PRICE,0);
         const datetime time1=(datetime)ObjectGetInteger(chartID,sparam,OBJPROP_TIME,1);
         const double price1=ObjectGetDouble(chartID,sparam,OBJPROP_PRICE,1);
         rect.Create(chartID,sparam,0,time0,price0,time1,price1);
         rects.Add(rect);
//---
         datetime Time[]={time0,time1};
         double Price[]={price1,price0};
         string Corner[]={"LL","RU"};
         for(int i=0;i<2;i++) {
            CChartObjectText *corner=new CChartObjectText;
            corner.Create(chartID,sparam+Corner[i],0,Time[i],Price[i]);
            corner.Selectable(true);
            corner.Selected(rect.Selected());
            corner.Color(clrNONE);
            corners.Add(corner); }
//---
         ChartRedraw(chartID); } }
//---
   if(id==CHARTEVENT_OBJECT_DRAG) {
      if(ObjectGetInteger(chartID,sparam,OBJPROP_TYPE)==OBJ_TEXT) {
//---
         int total=rects.Total();
         CChartObjectRectangle *rect;
         for(int i=0;i<total;i++) {
            rect=rects.At(i);
            if(StringFind(rect.Name(),sparam)!=-1)
               break; }
//---
         total=corners.Total();
         for(int i=0;i<total;i++) {
            CChartObjectText *corner=corners.At(i);
            if(StringFind(corner.Name(),sparam)!=-1) {
               if(StringFind(corner.Name(),"RU")!=-1) {
                  rect.SetInteger(OBJPROP_TIME,1,corner.GetInteger(OBJPROP_TIME));
                  rect.SetDouble(OBJPROP_PRICE,0,corner.GetDouble(OBJPROP_PRICE)); }
               if(StringFind(corner.Name(),"LL")!=-1) {
                  rect.SetInteger(OBJPROP_TIME,0,corner.GetInteger(OBJPROP_TIME));
                  rect.SetDouble(OBJPROP_PRICE,1,corner.GetDouble(OBJPROP_PRICE)); } } } }
//---
         ChartRedraw(chartID); }         
  }
//+------------------------------------------------------------------+
Files:
Rect.mq5  5 kb
 

If this is the problem: "This happens when the other side of rectangle is not visible."

just set the time of the right corner to the minimum of either the calculated end of the rectangle or the opening time of most recent bar on the chart everytime the timeframe of the chart has changed.

 
Carl Schreiber #:

I don't understand your problem. A MT5 rectangle is e.g. defined by [1.2.21|10] (corner top left) and [2.3.21|2] (corner bottom right). For the missing other two corners - who ever needs them - you just have swap the coordinate values: [1 .2.21|2] and [ 2.3.21|10]. What is the problem?

the op didnt say that he wanted to use a mouse to manually extend those missing 2 corners, however i think he clearly showed that in the images. Changing the parameters like that is not as fast or convenient as a simple drag of the mouse.

 

I found a way to achive this easy.

The event is called  CHARTEVENT_OBJECT_CLICK 

It will give the object name to solve the task. 

Here an example, untested code on how to do it. Anyone implementing this?

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
        const int x_pos = (int)lparam;
        const int y_pos = (int)dparam;


switch(id)
{
        case CHARTEVENT_OBJECT_CLICK:

                if( (ObjectFind(ChartID(), sparam))
                 && (ObjectGetInteger(ChartID(), sparam, OBJPROP_TYPE) == OBJ_RECTANGLE) )
                {
                        // Get coordinates
                        datetime left   = (datetime)ObjectGetInteger(ChartID(), sparam, OBJPROP_TIME, 0);
                        datetime right  = (datetime)ObjectGetInteger(ChartID(), sparam, OBJPROP_TIME, 1);
                        double top      = ObjectGetDouble(ChartID(), sparam, OBJPROP_PRICE, 0);
                        double bottom   = ObjectGetDouble(ChartID(), sparam, OBJPROP_PRICE, 1);

                        // Unify coords
                        datetime x_date = NULL;
                        double y_price  = NULL;
                        int sub_window  = NULL;
                        if(!ChartXYToTimePrice(ChartID(), x_pos, y_pos, sub_window, x_date, y_price))
                        { return; }

                        // Rectangle coord set
                        const bool rect_top_left        = ((left > right) && (top > bottom)) || ((left < right) && (top < bottom));

                        // Find closest rectangle corner
                        const bool mouse_left_bottom    = (MathAbs(left - x_date) < MathAbs(right - x_date)) && (MathAbs(top - y_price) >= MathAbs(bottom - y_price));
                        const bool mouse_right_bottom   = (MathAbs(left - x_date) >= MathAbs(right - x_date)) && (MathAbs(top - y_price) >= MathAbs(bottom - y_price));
                        const bool mouse_left_top       = (MathAbs(left - x_date) < MathAbs(right - x_date)) && (MathAbs(top - y_price) < MathAbs(bottom - y_price));
                        const bool mouse_right_top      = (MathAbs(left - x_date) >= MathAbs(right - x_date)) && (MathAbs(top - y_price) < MathAbs(bottom - y_price));

                        // Reassign rectangle coords 
                        if( ((mouse_left_bottom || mouse_right_top) && rect_top_left)
                         || ((mouse_left_top || mouse_right_bottom) && !rect_top_left) )
                        {
                                ObjectSetInteger(ChartID(), sparam, OBJPROP_TIME, 0, right);
                                ObjectSetInteger(ChartID(), sparam, OBJPROP_TIME, 1, left);
				ChartRedraw();
                        }
                }
        break;

        default:
                return;
}

return;
}
 

Here is a tested implementation solving the problem:

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
        // Local init

                const int               x_pos           = (int)lparam;
                const int               y_pos           = (int)dparam;
                const string    object_name     = sparam;


        // Event id selector

                switch(id)
                {
                        case CHARTEVENT_OBJECT_CLICK:

                                if(ObjectGetInteger(ChartID(), object_name, OBJPROP_TYPE) == OBJ_RECTANGLE)
                                {
                                        // Get coordinates
                                        const datetime  _left   = (datetime)ObjectGetInteger(ChartID(), object_name, OBJPROP_TIME, 0);
                                        const datetime  _right  = (datetime)ObjectGetInteger(ChartID(), object_name, OBJPROP_TIME, 1);
                                        const double    _top    = ObjectGetDouble(ChartID(), object_name, OBJPROP_PRICE, 0);
                                        const double    _bottom = ObjectGetDouble(ChartID(), object_name, OBJPROP_PRICE, 1);
                                
                                        // Sort rectangle coords
                                        const datetime  left    = MathMin(_left, _right);
                                        const datetime  right   = MathMax(_left, _right);
                                        const double    bottom  = MathMin(_top, _bottom);
                                        const double    top     = MathMax(_top, _bottom);
                                
                                        // Unify coords
                                        datetime    x_date      = NULL;
                                        double      y_price     = NULL;
                                        int         window_id   = NULL;
                                        if(!ChartXYToTimePrice(ChartID(), x_pos, y_pos, window_id, x_date, y_price))
                                        { return; }
                                
                                        // Rectangle coord set
                                        const bool  rect_top_left       = ((_left < _right) && (_top > _bottom)) || ((_left > _right) && (_top < _bottom));

                                        // Find closest rectangle corner
		                	const bool  mouse_left_bottom   = ((x_date - left) < (right - x_date)) && ((top - y_price) >= (y_price - bottom));
                			const bool  mouse_right_bottom  = ((x_date - left) >= (right - x_date)) && ((top - y_price) >= (y_price - bottom));
                			const bool  mouse_left_top      = ((x_date - left) < (right - x_date)) && ((top - y_price) < (y_price - bottom));
		                	const bool  mouse_right_top     = ((x_date - left) >= (right - x_date)) && ((top - y_price) < (y_price - bottom));

                                        // Reassign rectangle coords 
                                        if( ((mouse_left_bottom || mouse_right_top) && rect_top_left)
                                         || ((mouse_left_top || mouse_right_bottom) && !rect_top_left) )
                                        {
                                                ObjectSetInteger(ChartID(), object_name, OBJPROP_TIME, 0, _right);
                                                ObjectSetInteger(ChartID(), object_name, OBJPROP_TIME, 1, _left);
                                                ChartRedraw();
                                        }
                                        return;
                                }
                }

        // Return
        return;
}
 
Dominik Egert #:

I found a way to achieve this easy.

The event is called  CHARTEVENT_OBJECT_CLICK 

It will give the object name to solve the task. 

Here an example, untested code on how to do it. Anyone implementing this?

That's a better implementation. Only need to check if coordinates are opposite though.

#include <ChartObjects\ChartObjectsShapes.mqh>
long chartID=ChartID();
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_OBJECT_CLICK && ObjectGetInteger(chartID,sparam,OBJPROP_TYPE)==OBJ_RECTANGLE) {
      CChartObjectRectangle rect;
      rect.Attach(chartID,sparam,0,2);
      int wnd;
      //get time/price coordinates
      datetime time,time0=rect.Time(0),time1=rect.Time(1);
      double prce,prce0=rect.Price(0),prce1=rect.Price(1);
      ChartXYToTimePrice(chartID,(int)lparam,(int)dparam,wnd,time,prce);
      //check if Time(0) && Price(1) || Time(1) && Price(0) coordinates and switch time coordinates
      if((MathAbs(time0-time)<MathAbs(time1-time) && MathAbs(prce1-prce)<MathAbs(prce0-prce)) ||
         (MathAbs(time1-time)<MathAbs(time0-time) && MathAbs(prce0-prce)<MathAbs(prce1-prce))) { 
         rect.Time(0,time1);
         rect.Time(1,time0);
         rect.Detach();
         ChartRedraw(chartID); }
      rect.Detach(); }
//---
  }
//+------------------------------------------------------------------+
 
Why is your implementation better? It does take longer to compute as it has more function calls.
I get the idea of how you shorten the evaluation, that is for sure better than mine. But you use more resources to accomplish the task.
So, what is "better", how do you define this?