how to create objects dynamicly? (Some OOP stuff)

 

Here comes some OOP stuff.

The idea for the program:

* I draw a trendline in the chart and name it "beep" - the next time the price crosses this line, I will get a beep

* I draw a trendline and name it "buy" - the next time the price crosses this line, I will get a long position.

I wrote already an object named "CSmartLine" which is able to beep and buy and sell and close and ... (no coffee service so far).

In my EA I have three lines of code:

CSmartLinie mSmartLinie1;    // Create one object of class CSmartLine  


void OnTick()
      mSmartLinie1.CheckForAction(); // check for crossing prices

void OnChartEvent()
      if(id == CHARTEVENT_OBJECT_CLICK  ||
         id == CHARTEVENT_OBJECT_DRAG   ||
         id == CHARTEVENT_OBJECT_CHANGE ||
         id == CHARTEVENT_OBJECT_CREATE)
         if (sparam == "beep" || sparam == "buy" || sparam == "sell" || sparam == "close")
            {
            mSmartLinie1.CheckForAction(sparam);  // activation and tracking changes
            return;
            };

It works well so far.

Now . . . . I would like to draw any numbers of smart trend lines in the chart.

Assuming the object chances the name of the line (e.g. to "SmartLine_x")  in order to show that the line is under control of it.

Every time the EA detects a new line, it should create a new object of the class "CSmartLine".

The code could be

OnChartEvent()
      if (sparam = "beep")
             mSmartLine2 = new CSmartLine;

OnTick()
      if(mSmartLine2 != Null)
             mSmartLine2.CheckForAction();

But how .... hmmm ....

Maybe "mSmartLine" should be an array of pointers?    If so, which type?

The manual shows at his point an example I can't understand.


When the trend line disappears  (because the user deleted it from the chart for example) .    

Code should be . . .

      delete mSmartLine2;
      mSmartLine2=NULL;

Because it is the object itself which recognizes the disapprerance of the line, it should be the object, which deletes itself, rather then to ask the EA to delete it.

WIllbur

 

Where one can simply use

ObjectCreate(0,"mSmartLinie"+IntegerToString(X),OBJ_HLINE,0,0,0);

Where a simple

X++;

Will increase integer X so as to create

"mSmartLinie0"
"mSmartLinie1"
"mSmartLinie2"
"mSmartLinie3"

And etc.

 
Marco is correct. 

Your issue is that if a "beep" object exists a new one wont be created .
As marco mentioned 
plus 
Include the commands on the first Character of the object name after a 
recognizable character sequence

ex:

A->Beep
B->Buy
C->Sell
sequence -> SMRTLN_

so the first occurance of a beep smartline is named "SMRTLN_A_"+TotalBeepCount
 

In OOP there are common design patterns for storing objects and iterating them. They are called Containers, Sets, Collections, Maps, Vectors (and other similar names) design patterns, but afaik none are delivered with the basic MQL distribution. You have to code them yourself or find them in the code base.

C++ Programming/Code/Design Patterns - Wikibooks, open books for an open world
C++ Programming/Code/Design Patterns - Wikibooks, open books for an open world
  • en.wikibooks.org
A design pattern is neither a static solution, nor is it an algorithm. A pattern is a way to describe and address by name (mostly a simplistic description of its goal), a repeatable solution or approach to a common design problem, that is, a common way to solve a generic problem (how generic or complex, depends on how restricted the target goal...
 

I think, I've got it -  this are the magic lines (I hope):

CSmartLine *ArrayOfSmartLineS[10]; // An array of pointers to CSmartLine object


On ChartEvent

           //--- Create another object
           CSmartLine*mSmartLine = new CSmartLine();
           // Make the new object the owner of the new trend line
           mSmartLine.SetName(sparam);
           //--- Place the pointer value in an Array
           ArrayOfSmartLineS[NoLines]=mSmartLine;

In the manual the used the form "CSmartLine*mSmartLine = new CSmartLine();" only when they create the first instance of this class.
Next time it is only "mSmartLine = new CSmartLine();"
That's not possible in my test frame (compilation errors). ? ? ?


I wrote a simple test frame with very poor funktionality but the test for dynamic creation of objects.

Whenever the EA detects a trend line named "beep" - it creates an "SmartLine" object  which renames the line and controls it henceforth.

//+------------------------------------------------------------------+
//| Test frame OOP                                                   |
//+------------------------------------------------------------------+
class CSmartLine
{
protected:
string   iName;
double   iRate;

public:
   void   SetName(string xName)
            {
            for(int i=0;i<99;i++)
               {
               iName = "SmartLine_"+IntegerToString(i);
               if(ObjectFind(0,iName) < 0) break; // find unused name
               }
            ObjectSetString(0,xName,OBJPROP_NAME,0,iName); // rename trend line
            // --- Get rate
            iRate = ObjectGetDouble(0,iName,OBJPROP_PRICE,0);
            // signal identification of the line
               Sleep(300); PlaySound("ok.wav");
               ObjectSetInteger(0,iName,OBJPROP_WIDTH,4); ChartRedraw();
               Sleep(300);
               ObjectSetInteger(0,iName,OBJPROP_WIDTH,1); ChartRedraw();
            //
            };
           
   string GetName(void) {return(iName);}
  
   void   checkForChange(string xName)
            {
            if(xName != iName) return;
            // Check whether the line has been moved
            // get the new position
                        // --- Get rate
            iRate = ObjectGetDouble(0,iName,OBJPROP_PRICE,0);
            MessageBox("New rate: "+iName+" = "+DoubleToString(iRate,5));
            };
   void   checkForAction(double iAsk)
            {
            if(MathAbs(100 * (iRate - iAsk)/iAsk) < 0.005)
              {
              MessageBox("it's hit me "+iName+
              "\n myRate "+DoubleToString(iRate,5)+
              "\n actAsk "+DoubleToString(iAsk, 5)+
              "\n actDiff "+DoubleToString(100 * (iRate - iAsk)/iAsk,5) );
              }
            // Calculation whether the price hits the line
            // action: beep, buy, sell, close
            };         

};

//################# E N D - - - C S m a r t L i n e ##########################

//################# B E G I N of E A program ##################################

//--- Declare an array of object pointers of type CSmartLine

      CSmartLine *ArrayOfSmartLineS[10]; // An array of pointers to CSmartLine object

int   NoLines=0;

//----------------------------------------------------------------------------
void OnInit(void)
{
// --- do I need this?
   for(int i=0;i<10;i++)
     ArrayOfSmartLineS[i]=NULL;     

//--- delete all old trend lines
    ObjectsDeleteAll(0,"SmartLine",-1);

}
//+--------------------------------------------------------------------------
void OnChartEvent(const int id,        
                  const long& lparam,  
                  const double& dparam,
                  const string& sparam) 
{
      if(id == CHARTEVENT_OBJECT_CLICK  ||
         id == CHARTEVENT_OBJECT_DRAG   ||
         id == CHARTEVENT_OBJECT_CHANGE ||
         id == CHARTEVENT_OBJECT_CREATE)
         {
         if(sparam == "beep" || sparam == "buy" || sparam == "sell") 
           {
           //--- Create another object
           CSmartLine*mSmartLine = new CSmartLine();
           // Make to new object the owner of the new line
           mSmartLine.SetName(sparam);
           //--- file the pointer value in the array[0]
           ArrayOfSmartLineS[NoLines]=mSmartLine;
           //--- ask the new object for it's line name
           MessageBox("new object: " + ArrayOfSmartLineS[NoLines].GetName());
           //
           NoLines++;
           };
         if(StringSubstr(sparam,0,10) == "SmartLine_")
           {
           for(int i=0;i<10;i++)  // Ask all exsisting objects to pick up the change if concerns
             {
             if(ArrayOfSmartLineS[i] != NULL)
                ArrayOfSmartLineS[i].checkForChange(sparam);
             }
           }

         }
}
//----------------------------------------------------------------------------
void OnTick(void)
{
      MqlTick last_tick;
  
      SymbolInfoTick(_Symbol,last_tick);
     
      for(int i=0;i<10;i++)  // Ask all exsisting objects
             {
             if(ArrayOfSmartLineS[i] != NULL)
                ArrayOfSmartLineS[i].checkForAction(last_tick.ask);
             }
}
//+------------------------------------------------------------------+
void OnDeinit(const int xReason)
{
      if(xReason == REASON_RECOMPILE   ||
         xReason == REASON_CHARTCHANGE ||
         xReason == REASON_PARAMETERS  ||
         xReason == REASON_ACCOUNT)    return;
     
//--- We must delete all created dynamic objects
      for(int i=0;i<10;i++)
         {
         //--- We can delete only the objects with pointers of POINTER_DYNAMIC type
         if(CheckPointer(ArrayOfSmartLineS[i])==POINTER_DYNAMIC)
            {
            //--- Notify of deletion
            MessageBox("Deleting object "+IntegerToString(i)+" named "+ArrayOfSmartLineS[i].GetName());
            //--- Delete an object by its pointer
            delete ArrayOfSmartLineS[i];
            ArrayOfSmartLineS[i] = NULL;
            }
         }   // Loop i=0;i<10;i++
  }

 

@Marco

I am not sure whether I understood your idea.

Do you mean I should go with the standarad grafic objects, write a class which inheritance every thing from it and increases the functionality to the range I plan for my SmartLines ?!?

I have been thinking about that idea and I wonder whether MT5 allows user build graphic object to be created in a chart (through the normal interface).

Beside this problem my SmartLine objects need to be triggered, when the price chances and I have no idea how to get around this issue.

Do you have any experience in this area?

Willbur

 
Willbur:

@Marco

I am not sure whether I understood your idea.

Do you mean I should go with the standarad grafic objects, write a class which inheritance every thing from it and increases the functionality to the range I plan for my SmartLines ?!?

I have been thinking about that idea and I wonder whether MT5 allows user build graphic object to be created in a chart (through the normal interface).

Beside this problem my SmartLine objects need to be triggered, when the price chances and I have no idea how to get around this issue.

Do you have any experience in this area?

Willbur

It was just an example of doing things.

Whenever i build an GUI or Graphical User Interface i always build control frameworks in a loop.

This means the control buttons are simply created as B0,B1,B2,B3,B4,B5 and etc which translates into button 0 button 1 button 2 and etc.

And i always use IntegerToString() to add the numerical integer to the object name.

If you want the trigger you can also use:

if((Ask+Bid)/2>ObjectGetDouble(0,"object name",OBJPROP_PRICE)
 {
  // Trigger 1
 }

else if((Ask+Bid)/2<ObjectGetDouble(0,"object name",OBJPROP_PRICE)
 {
  // Trigger 2
 }

Or a variation since this is only to give you some ideas.

So you basically take a price Ask or Bid or Median and compare it to the Double your Hline is currently at.

The only limit is your own imagination.

 

Marco, You are still in your EA-Code. Are you?

This not what I am talking about.

The idea was to add functionality to the given grafic object by writing my own object which inherits from the original grafic object and increase it with the "buy" and "sell" functions.

When you go this way my SmartLine object should appear in the MT5 menue beside the trend line, the arrows, the text object and all this stuff.

Where your can pick it with the mouse like the other grafic objects and add it to the chart.

If MT5 allows that, only then we have to discuss the remaining question, how the object could be triggered by the terminal program when the price changes.

Non of the exsisting grafic object are able to react on price changes (as fare as I know).

Willbur

 

I dont like to say your doing it totally wrong but you do, because this is struct programming and not OOP. The big difference is the power of inheritance and overloading. And by the way, you cannot really inherit from real graphical objects, but you can represent anything as a code object and refer to a line or whatever from this object. Thats the way how its usually done in any class no matter if its a MFC or a MQL class, its all the same. 

If your lines are objects, then treat them as such. Dont deal with arrays outside, do it inside a class collection and work with pointers. Take a look at CWndContainer and get an idea of it. This class is a container which mainly manages pointer arrays for CWnd objects. Go one step ahead, your structure should be:

CObject as base for every object

CPriceTimeObjects as base for every price/time based object, such as lines, derives from CObject. It controls creation, holds time and price and calls an OnCreate(), which can be used by the next inheritant. It also has a Tick function which calls virtual OnTick() which is then overloaded by inheritants. 

CTrendLine as base for trendlines, inherits from CPriceTimeObjects and handles OnCreate where it creates the final line using ObjectCreate function. It should also have an OnTick() handler to react/respond on Tick events, cause it shall be price-sensitive as far as I understood.

Besides this, you have a container class which manages a pointer array that holds all the CTimePriceObject objects you want, it inherits itself also from CTimePriceObject and passes OnTick() to its "childs". The container has a also function that handles the OnChartEvent() to add lines or to remove them. It should also have a scan function to scan all existing objects for the case, the expert was added after lines were created. Furthermore it handles the overloaded OnTick() from CTimePrice, loops the array there, asks every CTrendLine object in it if it feels somehow responsible to react by calling the Tick function of every child object which is handled by a virtual OnTick. Why this again? Because the CTrendLine overloads this function also from CTimePrice and this way this class can also be inherited by further inheritants with further functions. 

Your code should look like this later:

CTPContainer container;

::OnChartEvent(...)

container.ChartEvent(id, lparam, dparam, sparam) //.. results in OnCreate() and OnDelete() at each CTrendLineObject. The container decides what to do, not your EA.

::OnTick()

container.Tick() // .. results in OnTick() at every CTrendLine "child" object

and so on. 

Such is a clear OOP base which can easily be enhanced by useful functions without ever touching any EA itself again which uses these classes. 

 
I dont like to say your doing it totally wrong but you do . . .

Wow ... thank you for the lesson. 

Somehow it sounds, like you've got the rigth approch.

I will try to change my code in this direction before I came back with it.

Willbur

 

If you are going to code object oriented consequently and straight away, you will never regret. The beginning may be harder than the normal top-down way, but you will be able to develop on a much higher level which includes more power, more possibilities, more flexibility and easier compatiblity to future changes.

MQL is awesome, but without OOP you will never figure out how much it really is.  

If you got any questions, just post them and I will try to help.  

Reason: