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.
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.
- en.wikibooks.org
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
@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.
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.
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso
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:
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