객체를 동적으로 생성하는 방법은 무엇입니까? (일부 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();

하지만 어떻게 .... 흠 ....

"mSmartLine"은 포인터 배열이어야 합니까? 그렇다면 어떤 유형입니까?

매뉴얼은 그의 시점에서 내가 이해할 수 없는 예를 보여줍니다.


추세선이 사라질 때(예를 들어 사용자가 차트에서 삭제했기 때문에) .

코드는 . . .

       delete  mSmartLine2;
      mSmartLine2=NULL;

선의 불합리함을 인지하는 것은 객체 자체이기 때문에 EA에 삭제를 요청하기 보다는 스스로 삭제하는 객체여야 한다.

윌버

 

간단하게 사용할 수 있는 곳

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

어디 간단한

X++;

생성하기 위해 정수 X를 증가시킵니다.

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

그리고 등.

 
마르코 맞습니다.

문제는 "삐" 개체가 존재하는 경우 새 개체가 생성되지 않는다는 것입니다.
마르코가 언급했듯이
...을 더한
다음 개체 이름 의 첫 번째 문자에 명령을 포함합니다.
인식 가능한 문자 시퀀스

전:

A->삐
B->구매
C->판매
시퀀스 -> 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가 "삐"라는 이름의 추세선을 감지할 때마다 - 선의 이름을 변경하고 이후로 제어하는 "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++
  }

 

@마르코

당신의 생각을 이해했는지 잘 모르겠습니다.

표준 그래픽 개체를 사용하여 모든 것을 상속하고 내 SmartLines에 대해 계획한 범위까지 기능 을 증가시키는 클래스를 작성해야 한다는 뜻입니까?!?

나는 그 아이디어에 대해 생각해 왔으며 MT5가 사용자가 그래픽 개체를 차트에서 생성할 수 있도록 허용하는지(일반 인터페이스를 통해) 궁금합니다.

이 문제 외에 내 SmartLine 개체는 가격 기회가 있고 이 문제를 해결하는 방법을 모를 때 트리거되어야 합니다.

이 분야에 대한 경험이 있습니까?

윌버

 
Willbur :

@마르코

당신의 생각을 이해했는지 잘 모르겠습니다.

표준 그래픽 개체를 사용하여 모든 것을 상속하고 내 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
 }

또는 이것은 단지 몇 가지 아이디어를 제공하기 위한 것이기 때문에 변형입니다.

따라서 기본적으로 가격 매도 또는 입찰 또는 중앙값을 취하여 현재 Hline의 두 배와 비교합니다.

유일한 한계는 자신의 상상력입니다.

 

Marco, 당신은 여전히 EA 코드에 있습니다. 당신은?

이것은 내가 말하는 것이 아닙니다.

아이디어는 원래 grafic 개체에서 상속받은 내 자신의 개체를 작성하여 주어진 grafic 개체에 기능을 추가하고 "buy" 및 "sell" 기능으로 증가시키는 것이었습니다.

이 방법으로 이동하면 내 SmartLine 개체가 추세선, 화살표, 텍스트 개체 및 이 모든 항목 옆에 있는 MT5 메뉴에 나타나야 합니다.

다른 그래픽 개체와 마찬가지로 마우스로 선택하여 차트에 추가할 수 있는 곳입니다.

MT5가 이를 허용하는 경우에만 가격이 변경될 때 터미널 프로그램이 개체를 트리거할 수 있는 방법에 대한 나머지 질문에 대해 논의해야 합니다.

기존 그래픽 개체 중 누구도 가격 변경에 반응할 수 없습니다(내가 아는 한 요금).

윌버

 

나는 당신이 그것을 완전히 잘못했다고 말하고 싶지 않지만 이것은 OOP가 아닌 구조체 프로그래밍이기 때문에 그렇게합니다. 가장 큰 차이점은 상속과 오버로딩의 힘입니다. 그건 그렇고, 실제 그래픽 개체에서 실제로 상속할 수는 없지만 코드 개체로 무엇이든 나타낼 수 있고 이 개체에서 선이나 무엇이든 참조할 수 있습니다. 그것이 MFC 또는 MQL 클래스인지 여부에 관계없이 모든 클래스에서 일반적으로 수행되는 방식입니다.

라인이 객체라면 객체로 취급하십시오. 외부 배열을 처리하지 말고 클래스 컬렉션 내부에서 처리하고 포인터로 작업하십시오. CWndContainer를 살펴보고 아이디어를 얻으십시오. 이 클래스는 주로 CWnd 개체에 대한 포인터 배열을 관리하는 컨테이너입니다. 한 단계 더 나아가 귀하의 구조는 다음과 같아야 합니다.

모든 개체의 기반이 되는 CObject

선과 같은 모든 가격/시간 기반 개체에 대한 기본이 되는 CPriceTimeObjects는 CObject에서 파생됩니다. 생성을 제어하고 시간과 가격을 유지하며 다음 상속자가 사용할 수 있는 OnCreate()를 호출합니다. 또한 상속자에 의해 오버로드되는 가상 OnTick()을 호출하는 Tick 함수도 있습니다.

추세선의 기준으로 CTrendLine은 CPriceTimeObjects에서 상속하고 ObjectCreate 함수 를 사용하여 최종 라인을 생성하는 OnCreate를 처리합니다. 또한 Tick 이벤트에 반응/응답하는 OnTick() 처리기가 있어야 합니다. 내가 이해하는 한 가격에 민감해야 하기 때문입니다.

이 외에도 원하는 모든 CTimePriceObject 개체를 보유하는 포인터 배열을 관리하는 컨테이너 클래스가 있습니다. 이 클래스는 CTimePriceObject에서도 자신을 상속하고 OnTick()을 "자식"에 전달합니다. 컨테이너에는 OnChartEvent()를 처리하여 줄을 추가하거나 제거하는 기능도 있습니다. 또한 케이스에 대한 모든 기존 개체를 스캔하는 스캔 기능이 있어야 하며 라인이 생성된 후 전문가가 추가되었습니다. 또한 CTimePrice에서 오버로드된 OnTick()을 처리하고, 거기에서 배열을 반복하고, 가상 OnTick에 의해 처리되는 모든 자식 개체의 Tick 함수를 호출하여 반응해야 하는 책임이 있는지 여부를 모든 CTrendLine 개체에 묻습니다. 또 왜? CTrendLine은 CTimePrice에서도 이 함수를 오버로드하기 때문에 이 클래스는 추가 기능이 있는 추가 상속자도 상속할 수 있습니다.

코드는 나중에 다음과 같아야 합니다.

CTPContainer 컨테이너;

::OnChartEvent(...)

container.ChartEvent(id, lparam, dparam, sparam) //.. 각 CTrendLineObject에서 OnCreate() 및 OnDelete()가 발생합니다. 컨테이너는 EA가 아니라 수행할 작업을 결정합니다.

::온틱()

container.Tick() // .. 모든 CTrendLine "자식" 개체에서 OnTick()이 발생합니다.

등등.

이러한 클래스를 사용하는 EA 자체를 다시 건드리지 않고도 유용한 기능으로 쉽게 향상될 수 있는 명확한 OOP 기반입니다.

 
나는 당신이 그것을 완전히 잘못하고 있다고 말하고 싶지 않지만 당신은 그렇게합니다. . .

와...강의 감사합니다.

어떻게 든 당신이 올바른 접근 방식을 취한 것처럼 들립니다.

코드를 가지고 돌아오기 전에 이 방향으로 코드를 변경하려고 합니다.

윌버

 

결과적으로 즉시 객체 지향을 코딩하려는 경우 절대 후회하지 않을 것입니다. 시작은 일반적인 하향식 방식보다 어려울 수 있지만 더 많은 권한, 더 많은 가능성, 더 많은 유연성 및 향후 변경 사항에 대한 더 쉬운 호환성을 포함하는 훨씬 더 높은 수준에서 개발할 수 있습니다.

MQL은 훌륭하지만 OOP가 없으면 실제로 얼마인지 알 수 없습니다.

질문이 있는 경우 게시해 주시면 최선을 다해 도와드리겠습니다.

사유: