如何动态地创建对象?(一些OOP的东西)

 

这里有一些OOP的东西。

这个程序的想法。

* 我在图表中画了一条趋势线,并将其命名为 "哔"--下次价格越过这条线时,我将得到一个哔声。

* 我画了一条趋势线并命名为 "买入" - 下次价格越过这条线时,我将得到一个多头头寸。

我已经写了一个名为"CSmartLine "的对象,它能够发出哔哔声,买入和卖出,关闭和...。(到目前为止没有咖啡服务)。

在我的EA中,我有三行代码。

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;
            };

到目前为止效果不错。

现在 . . . .我想在图表中绘制任意数量的智能趋势线。

假设该对象改变了线的名称(如改为 "SmartLine_x"),以显示该线是在它的控制之下。

每当EA检测到一条新线,它应该创建一个新的 "CSmartLine "类对象。

代码可以是

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

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

但如何.... hmmm ....

也许 "mSmartLine "应该是一个指针数组? 如果是这样,哪种类型?

手册在他点显示了一个我无法理解的例子。


当趋势线消失时(例如,因为用户从图表中删除了它).

代码应该是 . .

      delete mSmartLine2;
      mSmartLine2=NULL;

因为是对象本身识别了线的消失,所以应该是对象自己删除,而不是要求EA删除它。

WIllbur

 

其中,人们可以简单地使用

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

其中,一个简单的

X++;

将增加整数X,以便创建

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

和等。

 
Marco是正确的。

你的问题是,如果 "beep "对象存在,新的对象不会被创建。
正如Marco所说
加上
对象名称 的第一个字符上包括命令,在一个
可识别的字符序列

例如。

A->Beep
B->买
C->Sell
序列 -> SMRTLN_

所以第一次出现的哔哔声智能线被命名为 "SMRTLN_A_"+TotalBeepCount
 

在OOP中,有一些常见的设计模式 用于存储对象和迭代它们。它们被称为容器、集合、集合、地图、矢量(以及其他类似的名称)设计模式,但据说基本的MQL发行版没有提供这些模式。你必须自己编写代码或在代码库中找到它们。

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...
 

我想,我已经明白了--这就是神奇的线条(我希望)。

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;

在手册中,只有当他们创建这个类的第一个实例时,才使用 "CSmartLine*mSmartLine = new CSmartLine(); "的形式。
下一次,它只是 "mSmartLine = new CSmartLine();"
这在我的测试框架中是不可能的(编译错误)。???


我写了一个简单的测试框架,功能很差,但测试对象的动态创建。

每当EA检测到一条名为 "beep "的趋势线时--它就会创建一个 "SmartLine "对象,为该线重命名,并从此控制它。

//+------------------------------------------------------------------+
//| 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

我不确定我是否理解你的想法。

你的意思是我应该使用标准的图形对象,编写一个类,从它那里继承所有的东西,并将功能 增加到我计划的SmartLines的范围吗?

我一直在考虑这个想法,我想知道MT5是否允许用户在图表中创建图形对象(通过正常界面)。

除了这个问题,我的智能线对象需要在价格变化时被触发,我不知道如何解决这个问题。

你在这方面有什么经验吗?

威尔伯

 
Willbur:

@Marco

我不确定我是否理解你的想法。

你的意思是我应该使用标准的图形对象,写一个继承所有东西的类,并将功能增加到我为我的SmartLines计划的范围吗?

我一直在思考这个想法,我想知道MT5是否允许用户在图表中创建图形对象(通过正常界面)。

除了这个问题,我的SmartLine对象需要在价格变化时被触发,我不知道如何解决这个问题。

你在这方面有什么经验吗?

威尔伯

这只是一个做事的例子。

每当我建立一个GUI或图形用户界面时,我总是在一个循环中建立控制框架。

这意味着控制按钮被简单地创建为B0,B1,B2,B3,B4,B5等,转化为按钮0按钮1按钮2等。

而且我总是使用IntegerToString() 将数字整数添加到对象名称中。

如果你想要触发器,你也可以使用。

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
 }

或者一个变体,因为这只是给你一些想法。

所以你基本上采取一个价格Ask或Bid或Median,并将其与你的Hline目前所处的Double进行比较。

唯一的限制是你自己的想象力。

 

马可,你还在你的EA代码中。你是吗?

这不是我在谈论的问题。

我的想法是通过编写我自己的对象来增加给定的格拉菲克对象的功能,该对象继承了原始格拉菲克对象,并增加了 "买入 "和 "卖出 "功能。

当你这样做的时候,我的SmartLine对象应该出现在MT5的菜单中,旁边还有趋势线、箭头、文本对象 和所有这些东西。

你可以像其他grafic对象一样用鼠标选取它并将其添加到图表中。

如果MT5允许这样做,那么我们就必须讨论剩下的问题,即当价格变化时,终端程序如何触发该对象。

现有的抓取对象都不能对价格变化作出反应(据我所知)。

威尔伯

 

我不想说你的做法是完全错误的,但你确实这样做了,因为这是结构编程,而不是OOP。最大的区别在于继承和重载的力量。顺便说一下,你不能真正继承真正的图形对象,但你可以把任何东西表示成一个代码对象,并从这个对象中引用一条线或其他东西。这就是通常在任何类中的做法,不管是MFC还是MQL类,它都是一样的。

如果你的行是对象,那么就把它们当作对象。不要在外面处理数组,在类的集合中处理,用指针工作。看一下CWndContainer,对它有一个概念。这个类是一个容器,主要管理CWnd对象的指针数组。再往前走一步,你的结构应该是。

CObject作为每个对象的基础

CPriceTimeObjects作为每个基于价格/时间的对象的基础,比如线,派生自CObject。它控制创建,持有时间和价格,并调用OnCreate(),这可以被下一个继承者使用。它也有一个Tick函数,调用虚拟的OnTick(),然后被继承者重载。

CTrendLine作为趋势线的基础,继承自CPriceTimeObjects并处理OnCreate,它使用ObjectCreate函数 创建最终线。它还应该有一个OnTick()处理程序来对Tick事件做出反应/回应,因为据我所知,它应该是对价格敏感的。

除此之外,你还有一个容器类,它管理着一个指针数组,里面有你想要的所有CTimePriceObject对象,它本身也继承自CTimePriceObject,并将OnTick()传递给它的 "孩子"。容器也有一个处理OnChartEvent()的函数,用于添加或删除线条。它还应该有一个扫描函数来扫描所有现有的对象,以备不时之需,专家是在线条被创建后添加的。此外,它处理来自CTimePrice的重载OnTick(),在那里循环数组,询问其中的每个CTrendLine对象,如果它觉得有责任通过调用每个子对象的Tick函数来做出反应,这是由虚拟OnTick处理的。为什么又是这样?因为CTrendLine也从CTimePrice重载了这个函数,这样这个类也可以被更多的继承者继承,并有更多的函数。

你的代码以后应该是这样的。

CTPContainer容器。

::OnChartEvent(...)

container.ChartEvent(id, lparam, dparam, sparam) //...在每个CTrendLineObject的结果是OnCreate() 和OnDelete()。容器决定要做什么,而不是你的EA。

::OnTick()

container.Tick() // ...导致每个CTrendLine "子 "对象的OnTick()

等等。

这是一个清晰的OOP基础,可以很容易地通过有用的函数来增强,而不需要再去碰任何使用这些类的EA本身。

 
我不喜欢说你的做法完全错误,但你确实......。<br / translate="no">

哇......谢谢你的教诲。

不知为什么,听起来,你已经得到了正确的方法。

我将试着在这个方向上改变我的代码,然后再回来用它。

威尔伯

 

如果你打算直接进行面向对象的编码,你将永远不会后悔。开始的时候可能比正常的自上而下的方式更难,但你将能够在一个更高的水平上开发,包括更多的力量、更多的可能性、更多的灵活性和更容易兼容未来的变化。

MQL是非常棒的,但是如果没有OOP,你永远不会知道它到底有多棒。

如果你有任何问题,请发表出来,我将尽力帮助你。