Hier kann man einfach verwenden
ObjectCreate(0,"mSmartLinie"+IntegerToString(X),OBJ_HLINE,0,0,0);
Wo ein einfaches
X++;
die ganze Zahl X erhöhen wird, um
"mSmartLinie0" "mSmartLinie1" "mSmartLinie2" "mSmartLinie3"
Und usw.
Ihr Problem besteht darin, dass, wenn ein "Beep"-Objekt existiert, ein neues nicht erstellt wird.
Wie Marco erwähnte
plus
Fügen Sie die Befehle auf das erste Zeichen des Objektnamens nach einer
erkennbaren Zeichenfolge
Bsp:
A->Beep
B->Kaufen
C->Verkaufen
Folge -> SMRTLN_
Das erste Auftreten eines Signaltons wird also als "SMRTLN_A_"+TotalBeepCount bezeichnet.
In der OOP gibt es gängige Entwurfsmuster für die Speicherung von Objekten und deren Iteration. Sie werden als Container, Sets, Collections, Maps, Vectors (und andere ähnliche Namen) bezeichnet, aber afaik wird keines mit der MQL-Basisdistribution ausgeliefert. Sie müssen sie selbst programmieren oder sie in der Codebasis finden.
- en.wikibooks.org
Ich glaube, ich habe es verstanden - das sind die magischen Linien (hoffe ich):
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;
Im Handbuch wird die Form "CSmartLine*mSmartLine = new CSmartLine();" nur beim Erzeugen der ersten Instanz dieser Klasse verwendet.
Beim nächsten Mal ist es nur noch "mSmartLine = new CSmartLine();"
Das ist in meinem Testframe nicht möglich (Kompilierungsfehler). ? ? ?
Ich habe einen einfachen Test-Frame mit sehr geringer Funktionalität geschrieben, aber der Test für die dynamische Erstellung von Objekten.
Immer wenn der EA eine Trendlinie mit dem Namen "beep" erkennt, erstellt er ein "SmartLine"-Objekt, das die Linie umbenennt und sie fortan kontrolliert.
//+------------------------------------------------------------------+
//| 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
Ich bin mir nicht sicher, ob ich Ihre Idee verstanden habe.
Meinst Du, ich sollte mit den Standard-Grafikobjekten arbeiten, eine Klasse schreiben, die alles davon erbt und die Funktionalität auf den Bereich erweitert, den ich für meine SmartLines plane?!?
Ich habe über diese Idee nachgedacht und frage mich, ob MT5 es erlaubt, vom Benutzer erstellte Grafikobjekte in einem Chart zu erstellen (über die normale Schnittstelle).
Neben diesem Problem müssen meine SmartLine-Objekte ausgelöst werden, wenn der Preis Chancen und ich habe keine Ahnung, wie man dieses Problem zu umgehen.
Haben Sie Erfahrung auf diesem Gebiet?
Willbur
@Marco
Ich bin mir nicht sicher, ob ich Ihre Idee verstanden habe.
Meinst du, ich soll mit den Standard-Grafikobjekten gehen, eine Klasse schreiben, die alles davon erbt und die Funktionalität auf den Bereich erweitert, den ich für meine SmartLines plane?!?
Ich habe über diese Idee nachgedacht und frage mich, ob MT5 es erlaubt, vom Benutzer erstellte grafische Objekte in einem Chart zu erstellen (über die normale Schnittstelle).
Abgesehen von diesem Problem müssen meine SmartLine-Objekte ausgelöst werden, wenn sich der Preis ändert und ich habe keine Ahnung, wie ich dieses Problem umgehen kann.
Haben Sie Erfahrung in diesem Bereich?
Willbur
Das war nur ein Beispiel, wie man es machen kann.
Wann immer ich ein GUI oder eine grafische Benutzeroberfläche baue, baue ich Kontroll-Frameworks in einer Schleife.
Das bedeutet, dass die Schaltflächen einfach als B0,B1,B2,B3,B4,B5 und usw. erstellt werden, was in Schaltfläche 0 Schaltfläche 1 Schaltfläche 2 und usw. übersetzt wird.
Und ich verwende immer IntegerToString(), um die numerische Ganzzahl zum Objektnamen hinzuzufügen.
Wenn Sie den Trigger wollen, können Sie auch verwenden:
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 }
Oder eine Variation, da dies nur als Anregung dienen soll.
Im Grunde genommen nehmen Sie also einen Preis Ask oder Bid oder Median und vergleichen ihn mit dem Double, auf dem sich Ihre Hline gerade befindet.
Die einzige Grenze ist Ihre eigene Vorstellungskraft.
Marco, Du bist noch in Deinem EA-Code. Oder doch?
Das ist nicht das, wovon ich spreche.
Die Idee war, das vorgegebene Grafikobjekt um Funktionalität zu erweitern, indem ich ein eigenes Objekt schreibe, das vom ursprünglichen Grafikobjekt erbt und es um die Funktionen "Kaufen" und "Verkaufen" erweitert.
Wenn Sie diesen Weg gehen, sollte mein SmartLine-Objekt im MT5-Menü neben der Trendlinie, den Pfeilen, dem Textobjekt und all diesen Dingen erscheinen.
Dabei kann man es wie die anderen Grafikobjekte mit der Maus anwählen und in den Chart einfügen.
Wenn MT5 das zulässt, dann bleibt nur noch die Frage zu klären, wie das Objekt durch das Terminalprogramm bei einer Kursänderung ausgelöst werden kann.
Keines der existierenden Grafikobjekte kann auf Preisänderungen reagieren (soweit ich weiß).
Willbur
Ich möchte nicht sagen, dass Sie es völlig falsch machen, aber Sie tun es, denn dies ist Strukturprogrammierung und nicht OOP. Der große Unterschied ist die Macht der Vererbung und Überladung. Übrigens kann man nicht wirklich von echten grafischen Objekten erben, aber man kann alles als Codeobjekt darstellen und von diesem Objekt aus auf eine Linie oder was auch immer verweisen. Das ist die Art und Weise, wie es normalerweise in jeder Klasse gemacht wird, egal ob es eine MFC- oder eine MQL-Klasse ist, es ist alles das Gleiche.
Wenn Ihre Zeilen Objekte sind, dann behandeln Sie sie als solche. Handeln Sie nicht mit Arrays außerhalb, tun Sie es innerhalb einer Klasse Sammlung und arbeiten Sie mit Zeigern. Werfen Sie einen Blick auf CWndContainer und machen Sie sich ein Bild davon. Diese Klasse ist ein Container, der hauptsächlich Zeiger-Arrays für CWnd-Objekte verwaltet. Gehen Sie einen Schritt weiter, Ihre Struktur sollte sein:
CObject als Basis für jedes Objekt
CPriceTimeObjects als Basis für jedes preis-/zeitbasierte Objekt, wie z.B. Linien, leitet sich von CObject ab. Es steuert die Erstellung, hält Zeit und Preis und ruft eine OnCreate() auf, die vom nächsten Erben verwendet werden kann. Es verfügt auch über eine Tick-Funktion, die ein virtuelles OnTick() aufruft, das dann von den Nachfolgern überladen wird.
CTrendLine als Basis für Trendlinien erbt von CPriceTimeObjects und behandelt OnCreate, wobei es die endgültige Linie mit der Funktion ObjectCreate erstellt. Sie sollte auch einen OnTick()-Handler haben, um auf Tick-Ereignisse zu reagieren, da sie preisabhängig sein soll, soweit ich das verstanden habe.
Daneben gibt es eine Containerklasse, die ein Zeigerarray verwaltet, das alle gewünschten CTimePriceObject-Objekte enthält. Sie erbt selbst auch von CTimePriceObject und übergibt OnTick() an ihre "Kinder". Der Container hat auch eine Funktion, die das OnChartEvent() verarbeitet, um Linien hinzuzufügen oder zu entfernen. Er sollte auch eine Scan-Funktion haben, um alle existierenden Objekte für den Fall zu scannen, dass der Experte hinzugefügt wurde, nachdem Linien erstellt wurden. Darüber hinaus behandelt es das überladene OnTick() von CTimePrice, durchläuft das dortige Array, fragt jedes CTrendLine-Objekt, ob es sich irgendwie verantwortlich fühlt, zu reagieren, indem es die Tick-Funktion jedes Kindobjekts aufruft, die von einem virtuellen OnTick behandelt wird. Warum das Ganze noch einmal? Weil die CTrendLine diese Funktion auch von CTimePrice überlädt und somit diese Klasse auch von weiteren Erben mit weiteren Funktionen geerbt werden kann.
Ihr Code sollte später wie folgt aussehen:
CTPContainer Container;
::OnChartEvent(...)
container.ChartEvent(id, lparam, dparam, sparam) //.. führt zu OnCreate() und OnDelete() bei jedem CTrendLineObject. Der Container entscheidet, was zu tun ist, nicht Ihr EA.
::OnTick()
container.Tick() // .. führt zu OnTick() bei jedem CTrendLine-"Kind"-Objekt
und so weiter.
Das ist eine klare OOP-Basis, die leicht um nützliche Funktionen erweitert werden kann, ohne jemals wieder einen EA selbst zu berühren, der diese Klassen verwendet.
Wow ... danke für die Lektion.
Irgendwie hört es sich an, als hättest du den richtigen Ansatz.
Ich werde versuchen, meinen Code in diese Richtung zu ändern, bevor ich mit ihm zurückkomme.
Willbur
Wenn Sie konsequent und auf Anhieb objektorientiert programmieren, werden Sie es nie bereuen. Der Anfang mag schwieriger sein als der normale Top-Down-Weg, aber Sie werden in der Lage sein, auf einem viel höheren Niveau zu entwickeln, das mehr Leistung, mehr Möglichkeiten, mehr Flexibilität und leichtere Kompatibilität mit zukünftigen Änderungen beinhaltet.
MQL ist großartig, aber ohne OOP werden Sie nie herausfinden, wie viel es wirklich ist.
Wenn Sie irgendwelche Fragen haben, posten Sie sie einfach und ich werde versuchen zu helfen.
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Jetzt kommt etwas OOP-Zeug.
Die Idee für das Programm:
* Ich zeichne eine Trendlinie in den Chart und nenne sie "beep" - wenn der Kurs diese Linie das nächste Mal überquert, erhalte ich einen "beep".
* Ich zeichne eine Trendlinie ein und nenne sie "buy" - wenn der Kurs diese Linie das nächste Mal überschreitet, werde ich eine Long-Position eingehen.
Ich habe bereits ein Objekt namens "CSmartLine" geschrieben, das in der Lage ist, zu piepen und zu kaufen und zu verkaufen und zu schließen und ... (bis jetzt kein Kaffee-Service).
In meinem EA habe ich drei Codezeilen:
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;
};
Das funktioniert bisher gut.
Nun ...... Ich möchte eine beliebige Anzahl von Smart-Trend-Linien in den Chart zeichnen.
Angenommen, das Objekt hat die Chance, den Namen der Linie zu ändern (z.B. in "SmartLine_x"), um zu zeigen, dass die Linie von ihm kontrolliert wird.
Jedes Mal, wenn der EA eine neue Linie erkennt, sollte er ein neues Objekt der Klasse "CSmartLine" erstellen.
Der Code könnte so aussehen
OnChartEvent()
if (sparam = "beep")
mSmartLine2 = new CSmartLine;
OnTick()
if(mSmartLine2 != Null)
mSmartLine2.CheckForAction();
Aber wie .... hmmm ....
Vielleicht sollte "mSmartLine" ein Array von Zeigern sein? Wenn ja, welcher Typ?
Das Handbuch zeigt an dieser Stelle ein Beispiel, das ich nicht nachvollziehen kann.
Wenn die Trendlinie verschwindet (weil der Benutzer sie z.B. aus dem Chart gelöscht hat) .
Der Code sollte lauten.
delete mSmartLine2;
mSmartLine2=NULL;
Da es das Objekt selbst ist, das das Verschwinden der Linie erkennt, sollte es das Objekt sein, das sich selbst löscht, anstatt den EA zu bitten, es zu löschen.
WIllbur