como criar objetos de forma dinâmica? (Algumas coisas do OOP)

 

Aí vêm algumas coisas do OOP.

A idéia para o programa:

* Desenho uma linha de tendência no gráfico e o nome "beep" - na próxima vez que o preço cruzar esta linha, receberei um beep

* Eu desenho uma linha de tendência e a nomeio como "comprar" - na próxima vez que o preço cruzar esta linha, eu terei uma posição longa.

Eu já escrevi um objeto chamado "CSmartLine" que é capaz de apitar e comprar e vender e fechar e ... (sem serviço de café até agora).

Em minha EA, tenho três linhas de código:

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

Até agora, funciona bem.

Agora . . . . Eu gostaria de desenhar qualquer número de linhas de tendência inteligentes no gráfico.

Assumindo as chances do objeto o nome da linha (por exemplo, para "SmartLine_x"), a fim de mostrar que a linha está sob controle.

Toda vez que a EA detecta uma nova linha, ela deve criar um novo objeto da classe "CSmartLine".

O código poderia ser

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

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

Mas como .... hmmm ....

Talvez "mSmartLine" deva ser um conjunto de indicadores? Em caso afirmativo, qual tipo?

O manual mostra em seu ponto um exemplo que eu não consigo entender.


Quando a linha de tendência desaparece (porque o usuário a apagou do gráfico, por exemplo) .

O código deve ser . . .

      delete mSmartLine2;
      mSmartLine2=NULL;

Como é o próprio objeto que reconhece a desapropriação da linha, ele deve ser o objeto, que se apaga a si mesmo, ao invés de pedir à EA que o apague.

WIllbur

 

Onde se pode simplesmente usar

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

Onde um simples

X++;

aumentará o número inteiro X de modo a criar

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

E etc.

 
Marco está correto.

Seu problema é que se um objeto "bip" existir, um novo objeto não será criado.
Como Marco mencionou
mais
Incluir os comandos no primeiro caractere do nome do objeto depois de um
seqüência de caracteres reconhecíveis

ex:

A->Beep
B->Buy
C->Vender
seqüência -> SMRTLN_

portanto, a primeira ocorrência de uma linha de bip inteligente é chamada "SMRTLN_A_"+TotalBeepCount
 

No OOP há padrões comuns de design para armazenar objetos e iterá-los. Eles são chamados Containers, Sets, Colecções, Mapas, Vetores (e outros nomes similares) padrões de design, mas afaik nenhum é entregue com a distribuição básica de MQL. É preciso codificá-los você mesmo ou encontrá-los na base de código.

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

Acho que já o tenho - estas são as linhas mágicas (espero):

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;

No manual, foi utilizada a forma "CSmartLine*mSmartLine = nova CSmartLine();" apenas quando eles criam a primeira instância desta classe.
Da próxima vez é apenas "mSmartLine = nova CSmartLine();".
Isso não é possível no meu quadro de teste (erros de compilação). ? ? ?


Eu escrevi uma moldura de teste simples com muito pouca funcionalidade, mas o teste para criação dinâmica de objetos.

Sempre que a EA detecta uma linha de tendência chamada "beep" - ela cria um objeto "SmartLine" que renomeia a linha e a controla a partir de agora.

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

Não tenho certeza se entendi sua idéia.

Você quer dizer que eu deveria ir com os objetos gráficos padrão, escrever uma classe que herde tudo dela e aumente a funcionalidade para a gama que eu planejo para minhas SmartLines ?!?

Estive pensando sobre essa idéia e me pergunto se o MT5 permite que o usuário crie objetos gráficos em um gráfico (através da interface normal).

Além deste problema, meus objetos SmartLine precisam ser acionados, quando as chances de preço e eu não tenho a menor idéia de como contornar este problema.

Você tem alguma experiência nesta área?

Willbur

 
Willbur:

@Marco

Não tenho certeza se entendi sua idéia.

Você quer dizer que eu deveria ir com os objetos gráficos padrão, escrever uma classe que herde tudo dela e aumente a funcionalidade para a gama que eu planejo para minhas SmartLines ?!?

Estive pensando sobre essa idéia e me pergunto se o MT5 permite que o usuário crie um objeto gráfico em um gráfico (através da interface normal).

Além deste problema, meus objetos SmartLine precisam ser acionados, quando as chances de preço e eu não tenho a menor idéia de como contornar este problema.

Você tem alguma experiência nesta área?

Willbur

Foi apenas um exemplo de como fazer as coisas.

Sempre que construo uma GUI ou Interface Gráfica de Usuário, sempre construo estruturas de controle em loop.

Isto significa que os botões de controle são simplesmente criados como B0,B1,B2,B3,B4,B5 e etc., o que se traduz em botão 0 botão 1 botão 2 e etc.

E eu sempre uso IntegerToString() para adicionar o inteiro numérico ao nome do objeto.

Se você quiser o gatilho, você também pode usar:

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
 }

Ou uma variação, já que isto é apenas para lhe dar algumas idéias.

Então você basicamente pega um preço Ask ou Bid ou Median e o compara com o dobro de sua linha Hline no momento.

O único limite é sua própria imaginação.

 

Marco, Você ainda está em seu Código EA. Você está?

Não é disto que estou falando.

A idéia era acrescentar funcionalidade ao objeto gráfico dado, escrevendo meu próprio objeto que herda do objeto gráfico original e aumentá-lo com as funções "comprar" e "vender".

Quando você segue este caminho, meu objeto SmartLine deve aparecer no menu MT5 ao lado da linha de tendência, as setas, o objeto de texto e todas estas coisas.

Onde você pode escolhê-lo com o mouse como os outros objetos gráficos e adicioná-lo ao gráfico.

Se o MT5 permitir isso, só então teremos que discutir a questão restante, como o objeto poderia ser acionado pelo programa terminal quando o preço mudar.

Não do objeto gráfico existente são capazes de reagir sobre as mudanças de preço (como o preço que eu conheço).

Willbur

 

Eu não gostaria de dizer que você está fazendo isso totalmente errado, mas você faz, porque isto é programação estrutural e não OOP. A grande diferença é o poder da herança e a sobrecarga. E, a propósito, você não pode realmente herdar de objetos gráficos reais, mas pode representar qualquer coisa como um objeto de código e referir-se a uma linha ou o que quer que seja deste objeto. Esta é a maneira como normalmente é feito em qualquer classe, não importa se é uma classe MFC ou MQL, é a mesma coisa.

Se suas linhas são objetos, então trate-os como tal. Não lide com matrizes externas, faça-o dentro de uma coleção de classes e trabalhe com apontadores. Dê uma olhada no CWndContainer e tenha uma idéia do mesmo. Esta classe é um recipiente que gerencia principalmente matrizes de ponteiro para objetos CWnd. Dê um passo à frente, sua estrutura deve estar:

CObject como base para cada objeto

CPriceTimeObjects como base para cada objeto baseado em preço/tempo, tais como linhas, deriva de CObject. Ele controla a criação, detém tempo e preço e chama um OnCreate(), que pode ser usado pelo próximo herdeiro. Ele também tem uma função Tick que chama OnTick() virtual, que é então sobrecarregado pelos herdeiros.

CTrendLine como base para linhas de tendência, herda de CPriceTimeObjects e lida com OnCreate onde cria a linha final usando a função ObjectCreate. Também deve ter um manipulador OnTick() para reagir/responder em eventos Tick, pois deve ser sensível ao preço até onde eu entendi.

Além disto, você tem uma classe de contêineres que gerencia uma matriz de ponteiro que contém todos os objetos CTimePriceObject que você deseja, ela se herda também do CTimePriceObject e passa OnTick() para suas "crianças". O recipiente também tem uma função que manipula o OnChartEvent() para adicionar linhas ou para removê-las. Ele também deve ter uma função de escaneamento para escanear todos os objetos existentes para o caso, o especialista foi adicionado depois que as linhas foram criadas. Além disso, ele lida com o OnTick() sobrecarregado da CTimePrice, faz loops na matriz, pergunta a cada objeto CTrendLine nele se ele se sente de alguma forma responsável para reagir chamando a função Tick de cada objeto criança que é manuseado por um OnTick virtual. Por que isso novamente? Porque a CTrendLine sobrecarrega esta função também do CTimePrice e desta forma esta classe também pode ser herdada por outros herdeiros com outras funções.

Seu código deve se parecer com isto mais tarde:

Recipiente CTPContainer;

::OnChartEvent(...)

container.ChartEvent(id, lparam, dparam, sparam) //... resulta em OnCreate() e OnDelete() em cada CTrendLineObject. O recipiente decide o que fazer, não o seu EA.

::OnTick()

Tick() // ... resulta em OnTick() em cada objeto "criança" da CTrendLine

e assim por diante.

Esta é uma clara base OOP que pode ser facilmente melhorada por funções úteis sem nunca mais tocar em nenhuma EA em si que utilize estas classes.

 
Eu não gostaria de dizer que você está fazendo isso totalmente errado, mas você faz . . . <br / translate="no">

Uau ... obrigado pela lição.

De alguma forma, parece que você tem a aprovação do equipamento.

Vou tentar mudar meu código nesta direção antes de voltar com ele.

Willbur

 

Se você for codificar objetos orientados conseqüentemente e imediatamente, nunca se arrependerá. O início pode ser mais difícil do que o caminho normal de cima para baixo, mas você será capaz de se desenvolver em um nível muito mais alto que inclui mais poder, mais possibilidades, mais flexibilidade e mais fácil compatibilidade com mudanças futuras.

A MQL é impressionante, mas sem o OOP você nunca descobrirá o quanto ela realmente é.

Se você tiver alguma pergunta, basta publicá-la e eu tentarei ajudar.

Razão: