come creare oggetti in modo dinamico? (Alcune cose OOP)

 

Ecco un po' di roba OOP.

L'idea del programma:

* Disegno una linea di tendenza nel grafico e la chiamo "beep" - la prossima volta che il prezzo attraversa questa linea, avrò un beep

* Disegno una linea di tendenza e la chiamo "buy" - la prossima volta che il prezzo attraversa questa linea, avrò una posizione lunga.

Ho scritto già un oggetto chiamato "CSmartLine" che è in grado di suonare e comprare e vendere e chiudere e ... (nessun servizio di caffè finora).

Nel mio EA ho tre righe di codice:

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

Finora funziona bene.

Ora . . . Vorrei disegnare un numero qualsiasi di linee di tendenza intelligenti nel grafico.

Assumendo che l'oggetto cambi il nome della linea (per esempio in "SmartLine_x") per mostrare che la linea è sotto il suo controllo.

Ogni volta che l'EA rileva una nuova linea, dovrebbe creare un nuovo oggetto della classe "CSmartLine".

Il codice potrebbe essere

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

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

Ma come .... hmmm ....

Forse "mSmartLine" dovrebbe essere un array di puntatori? Se sì, di che tipo?

Il manuale mostra a suo punto un esempio che non riesco a capire.


Quando la linea di tendenza scompare (perché l'utente l'ha cancellata dal grafico per esempio) .

Il codice dovrebbe essere . . .

      delete mSmartLine2;
      mSmartLine2=NULL;

Poiché è l'oggetto stesso che riconosce la scomparsa della linea, dovrebbe essere l'oggetto stesso a cancellarsi, piuttosto che chiedere all'EA di cancellarlo.

WIllbur

 

Dove si può semplicemente usare

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

Dove un semplice

X++;

aumenterà l'intero X in modo da creare

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

Ed ecc.

 
Marco ha ragione.

Il tuo problema è che se esiste un oggetto "beep" non ne viene creato uno nuovo.
Come ha detto Marco
più
Includete i comandi sul primo carattere del nome dell'oggetto dopo una
sequenza di caratteri riconoscibile

es:

A->Beep
B->Acquista
C->Vendere
sequenza -> SMRTLN_

quindi la prima occorrenza di una smartline bip si chiama "SMRTLN_A_"+TotalBeepCount
 

In OOP ci sono schemi di progettazione comuni per la memorizzazione di oggetti e l'iterazione degli stessi. Sono chiamati Containers, Sets, Collections, Maps, Vectors (e altri nomi simili), ma, a quanto pare, nessuno è fornito con la distribuzione base di MQL. Dovete codificarli voi stessi o trovarli nel codice 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...
 

Penso di aver capito - queste sono le linee magiche (spero):

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;

Nel manuale si usa la forma "CSmartLine*mSmartLine = new CSmartLine();" solo quando si crea la prima istanza di questa classe.
La volta successiva è solo "mSmartLine = new CSmartLine();"
Questo non è possibile nel mio test frame (errori di compilazione). ? ? ?


Ho scritto un semplice test frame con una funktionalità molto povera ma il test per la creazione dinamica di oggetti.

Ogni volta che l'EA rileva una linea di tendenza chiamata "beep" - crea un oggetto "SmartLine" che rinomina la linea e la controlla d'ora in poi.

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

Non sono sicuro di aver capito la tua idea.

Vuoi dire che dovrei andare con gli oggetti grafici standard, scrivere una classe che eredita ogni cosa da essa e aumenta la funzionalità alla gamma che pianifico per le mie SmartLines?

Ho pensato a questa idea e mi chiedo se MT5 permette all'utente di costruire oggetti grafici da creare in un grafico (attraverso la normale interfaccia).

Oltre a questo problema i miei oggetti SmartLine devono essere attivati quando il prezzo cambia e non ho idea di come aggirare questo problema.

Hai qualche esperienza in questo campo?

Willbur

 
Willbur:

@Marco

Non sono sicuro di aver capito la tua idea.

Vuoi dire che dovrei andare con gli oggetti grafici standard, scrivere una classe che erediti ogni cosa da essa e aumenti la funzionalità alla gamma che pianifico per le mie SmartLine?

Ho pensato a questa idea e mi chiedo se MT5 permette all'utente di costruire un oggetto grafico da creare in un grafico (attraverso la normale interfaccia).

Oltre a questo problema i miei oggetti SmartLine devono essere attivati quando il prezzo cambia e non ho idea di come aggirare questo problema.

Hai qualche esperienza in questo campo?

Willbur

Era solo un esempio di come fare le cose.

Ogni volta che costruisco una GUI o Graphical User Interface costruisco sempre i quadri di controllo in un ciclo.

Questo significa che i pulsanti di controllo sono semplicemente creati come B0,B1,B2,B3,B4,B5 ed ecc che si traduce in pulsante 0 pulsante 1 pulsante 2 ed ecc.

E uso sempre IntegerToString() per aggiungere l'intero numerico al nome dell'oggetto.

Se volete il trigger potete anche usare:

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
 }

O una variazione poiché questo è solo per darvi alcune idee.

Quindi fondamentalmente prendi un prezzo Ask o Bid o Median e lo confronti con il Double che la tua Hline ha attualmente.

L'unico limite è la tua immaginazione.

 

Marco, Sei ancora nel tuo codice EA. Lo sei?

Non è di questo che sto parlando.

L'idea era di aggiungere funzionalità all'oggetto grafic dato scrivendo un mio oggetto che eredita dall'oggetto grafic originale e lo aumenta con le funzioni "buy" e "sell".

Quando si va in questo modo il mio oggetto SmartLine dovrebbe apparire nel menu di MT5 accanto alla linea di tendenza, le frecce, l'oggetto testo e tutta questa roba.

Dove potete prenderlo con il mouse come gli altri oggetti grafici e aggiungerlo al grafico.

Se MT5 lo permette, solo allora dobbiamo discutere la questione rimanente, come l'oggetto potrebbe essere attivato dal programma terminale quando il prezzo cambia.

Nessuno degli oggetti grafici esistenti è in grado di reagire ai cambiamenti di prezzo (per quanto ne so).

Willbur

 

Non mi piace dire che lo state facendo in modo totalmente sbagliato, ma è così, perché questa è programmazione a struttura e non OOP. La grande differenza è il potere dell'ereditarietà e dell'overloading. E a proposito, non si può davvero ereditare da oggetti grafici reali, ma si può rappresentare qualsiasi cosa come un oggetto di codice e fare riferimento a una linea o qualsiasi altra cosa da questo oggetto. Questo è il modo in cui viene fatto di solito in qualsiasi classe, non importa se è una classe MFC o MQL, è tutto uguale.

Se le vostre linee sono oggetti, allora trattatele come tali. Non trattate gli array all'esterno, fatelo all'interno di una collezione di classi e lavorate con i puntatori. Date un'occhiata a CWndContainer e fatene un'idea. Questa classe è un contenitore che gestisce principalmente gli array di puntatori per gli oggetti CWnd. Fai un passo avanti, la tua struttura dovrebbe essere:

CObject come base per ogni oggetto

CPriceTimeObjects come base per ogni oggetto basato sul prezzo/tempo, come le linee, deriva da CObject. Controlla la creazione, tiene il tempo e il prezzo e chiama una OnCreate(), che può essere usata dall'erede successivo. Ha anche una funzione Tick che chiama OnTick() virtuale che viene poi sovraccaricata dagli eredi.

CTrendLine come base per le linee di tendenza, eredita da CPriceTimeObjects e gestisce OnCreate dove crea la linea finale usando la funzione ObjectCreate. Dovrebbe anche avere un gestore OnTick() per reagire/rispondere agli eventi Tick, perché deve essere sensibile al prezzo, per quanto ho capito.

Oltre a questo, hai una classe contenitore che gestisce un array di puntatori che contiene tutti gli oggetti CTimePriceObject desiderati, essa eredita anch'essa da CTimePriceObject e passa OnTick() ai suoi "figli". Il contenitore ha anche una funzione che gestisce l'OnChartEvent() per aggiungere linee o per rimuoverle. Dovrebbe anche avere una funzione di scansione per analizzare tutti gli oggetti esistenti nel caso in cui l'esperto sia stato aggiunto dopo la creazione delle linee. Inoltre gestisce la funzione OnTick() sovraccaricata da CTimePrice, fa un loop sull'array, chiede ad ogni oggetto CTrendLine presente se si sente in qualche modo responsabile di reagire chiamando la funzione Tick di ogni oggetto figlio che è gestita da un OnTick virtuale. Perché ancora questo? Perché la CTrendLine sovraccarica questa funzione anche da CTimePrice e in questo modo questa classe può essere ereditata da ulteriori eredi con ulteriori funzioni.

Il tuo codice dovrebbe assomigliare a questo

CTPContainer container;

::OnChartEvent(...)

container.ChartEvent(id, lparam, dparam, sparam) //.. risulta in OnCreate() e OnDelete() in ogni CTrendLineObject. Il contenitore decide cosa fare, non il tuo EA.

::OnTick()

container.Tick() // .. risulta in OnTick() in ogni oggetto CTrendLine "figlio"

e così via.

Questa è una chiara base OOP che può essere facilmente arricchita da funzioni utili senza toccare mai più alcun EA che usi queste classi.

 
Non mi piace dire che lo stai facendo completamente sbagliato, ma lo fai . . . <br / translate="no">

Wow ... grazie per la lezione.

In qualche modo sembra che tu abbia l'approccio giusto.

Proverò a cambiare il mio codice in questa direzione prima di tornare con esso.

Willbur

 

Se avete intenzione di codificare ad oggetti di conseguenza e subito, non ve ne pentirete. L'inizio può essere più difficile del normale modo top-down, ma sarete in grado di sviluppare ad un livello molto più alto che include più potenza, più possibilità, più flessibilità e più facile compatibilità ai cambiamenti futuri.

MQL è fantastico, ma senza OOP non capirete mai quanto lo sia realmente.

Se avete delle domande, postatele e cercherò di aiutarvi.