Sie verpassen Handelsmöglichkeiten:
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Registrierung
Einloggen
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Wenn Sie kein Benutzerkonto haben, registrieren Sie sich
Der Tester hat eine eigene Liste von Werkzeugen und muss erstellt werden (vorzugsweise bei der Initialisierung des EA).
Der Code war ungefähr (aus zwei Teilen kopiert), aber Ihre Bemerkungen sind richtig.
Hier ist die korrigierte Fassung:
Ich habe ein paar Print()-Aufrufe hinzugefügt, um zu verdeutlichen, wie es tatsächlich funktioniert:
Sie funktioniert jetzt korrekt. Aber mit einem Vorbehalt - unter den Bedingungen, die jetzt tatsächlich anzutreffen sind. Wenn sie in Zukunft erweitert werden, wird dieser Code in einigen Fällen unter bestimmten Bedingungen Fehler machen. Das werde ich weiter unten erklären.
Ich musste einige Nachforschungen anstellen und habe dabei sehr interessante Ergebnisse erhalten. Aber lassen Sie uns einen nach dem anderen besprechen.
Das erste, was mir auffällt, ist Folgendes: Warum musste ich so viel mit NormalizeDouble() tanzen? Nun, was macht NormalizeDoubel()? Bindet einen freien Wert an das Gitter. Zum Beispiel in diesem Codefragment:
NormalizeDouble() nimmt als Parameter lot_pure (freier Wert, d.h. der Wert, der durch die freie Marge und die notwendige Marge für 1 Lot ohne Rundung und andere Bindung berechnet wird) und gibt den Wert, gebunden an den nächsten Wert des Rasters mit Start bei 0 und Schritt 0,01.
Hier ist es wichtig zu beachten: zum nächstgelegenen Knoten des Gitters, auch zum größeren!
Wofür ist diese Bindung an dieser Stelle des Codes? Und warum auf das 0,01er-Raster und nicht auf, sagen wir, 0,001?
Übrigens können wir sehen, dass das im Protokoll mit CO gekennzeichnete Ergebnis (die erste Zeile des gezeigten Fragments) zu dem erhöhten Wert geführt hat.
Außerdem wissen wir, dass alle Handelsfunktionen, die die Anzahl der Lose als einen der Parameter akzeptieren, verlangen, dass dieser Wert an das Raster gebunden ist: minvol + N * stepvol, wobei N eine ganze Zahl zwischen 0 und dem Wert eines ganzzahligen Teils des Ausdrucks (maxvol - minvol) / stepvol ist. Dementsprechend wird der Wert der freien Partie in diesem Fragment erhalten:
muss an den nächstgelegenen Knoten des angegebenen Gitters gebunden werden: minvol + N * stepvol. Das bedeutet, dass Sie zunächst minvol vom Wert von lot subtrahieren müssen, bevor Sie durch stepvol dividieren (um die ganze Zahl N zu erhalten), und nach der Multiplikation mit N minvol addieren. Aber Sie dividieren sofort durch stepvol, wobei Sie implizit davon ausgehen, dass stepvol ein Teiler von minvol ist, d.h. eine ganzzahlige Anzahl von Malen passt, denn nur wenn diese Bedingung erfüllt ist, können Sie auf diese Weise "vereinfachen", ohne Nebenwirkungen zu bekommen:
Auch hier verwenden Sie NormalizeDouble(), dieses Mal, um sich an ein Raster mit Start bei 0 und Schritt 1 zu binden, d. h. an Ganzzahlen. Die Rasterbindungsparameter sind korrekt, aber das Fangwerkzeug ist etwas unglücklich: Es bindet an den nächstgelegenen Knoten im Raster, einschließlich eines größeren Knotens, wenn dieser zufällig näher ist. Und in unserem Fall wird es zu einer anschließenden obligatorischen Ausarbeitung eines Korrekturcodes führen. Warum nicht hier ein wunderbares Werkzeug der Bindung an "ein Raster von Integer" mit statt Aufruf NormalizeDouble() eine Besetzung zu Integer-Typ , der nicht erhöhen den Wert wird gegossen, sondern nur dekrementieren sie auf die nächste ganze Zahl, wenn nötig, dh - was wir brauchen?
Aber es gibt noch ein weiteres interessantes Artefakt, das in der zweiten Zeile des zitierten Fragments, das mit JG gekennzeichnet ist, nachgewiesen wird. Es stellt sich heraus, dass der Ausdruck "0.1 * NormalizeDouble(7.8 / 0.1)" das Ergebnis 7.800000000000001 liefert, was dazu führt, dass der korrigierende Code funktioniert! Wozu braucht man einen Code, der so schlecht funktioniert, dass man einen korrigierenden Code hinzufügen muss?
Es liegt auf der Hand, dass der Code der Bindung an das Raster der zulässigen Losgrößen durch einen besseren ersetzt werden muss.
Natürlich können wir diesen Code auch stehen lassen - schließlich wird der korrigierende Teil des Codes, wenn überhaupt, funktionieren. Hier ist die dritte Zeile des Protokolls beweist es: das Ergebnis kommt ganz am Ende zurück. Andererseits ist dieser Kodex ein Indikator für die Professionalität und Qualität seiner Schöpfer. Dazu gehört auch die Qualität des Codes der MT5-Plattform. Und den Beweis dafür werde ich antreten, denn ich bin bei meinen Recherchen auf zwei Fehler gestoßen.
Schauen wir uns übrigens noch einmal den Code der anfänglichen Bindung des berechneten lot_pure-Wertes und den Korrekturcode an:
In beiden Fällen besteht eine Bindung an das Gitter mit der Schrittweite 0,01. Warum dieses Gitter? Denn Sie wollen an das Gitter minvol + N * stepvol binden, das ein stepvol hat. Was wird passieren, wenn wir in Zukunft sowohl den Mindestloswert als auch das Stepvol von 0,001 haben werden?Es ist sehr einfach - der Code wird falsche Ergebnisse in den Fällen, wenn in den Prozess der Bindung an das Raster mit dem Schritt 0,01 der freie Wert ändert sich auf den Wert mehr als 0,001 geben. Dies ist der Vorbehalt, den ich eingangs erwähnte.
Beim "Aufrunden" um mehr als 0,001 werden Lot-Werte zurückgegeben, bei denen die freie Marge nicht ausreicht, um die Position zu eröffnen, während beim "Abrunden" um den gleichen Betrag - zu niedrige Werte oder 0, wenn der freie Wert zwischen 0,001 und 0,004999 liegt...
Das heißt, der Code enthält einen potenziellen Fehler für die Zukunft. Es ist eine Frage der Professionalität der Entwickler und der Qualität ihres Codes.
Unter Berücksichtigung dessen, was ich gefunden habe, werde ich nun meine eigene Variante der Funktion vorschlagen:
Es gibt mehrere Fälle, in denen der Wert der Lose (gespeichert in meinem tmp) zwar berechnet, aber noch nicht an ein Raster gültiger Werte gebunden ist. Nennen wir den rastergebundenen Wert diskretisiert.
1. Der Fall, dass tmp < minvol. In diesem Fall bleibt die Ungleichheit auch nach der Diskretisierung von tmp bestehen, da der Diskretisierungsprozess nur die Reduzierung des berechneten Wertes beinhaltet (andernfalls gibt es nicht genügend freien Spielraum, da der berechnete Wert der maximal mögliche Wert für den gegebenen freien Spielraum ist).
Daher kann dieser Fall bereits in einem frühen Stadium, vor der Probenahme, ausgeschlossen werden.
2. Der Fall, dass tmp > maxvol. In diesem Fall ist die Begrenzung nicht die freie Marge, sondern die maximal zulässige Anzahl von Lots, die von den Handelsfunktionen akzeptiert werden. In diesem Fall geben Sie einfach den Wert von maxvol zurück.
Für die einfache Rückgabe des Wertes von maxvol ist keine Abtastung von tmp erforderlich, so dass auch dieser Fall vor dem Abtastcode abgeschnitten wird.
3. Der Fall, dass minvol <= tmp <= maxvol. In diesem Fall muss diskretisiert werden, aber der diskretisierte Wert bleibt innerhalb einer Ungleichung für diesen Fall, d.h. es besteht keine Notwendigkeit, nach der Diskretisierung etwas zu korrigieren.
Der Probenahmecode ist einfach und effizient:
Hier berechnet der Ausdruck "(tmp - minvol) / stepvol" dieselbe Zahl N (den Ankerrasterparameter), jedoch mit einem Bruchteil. Da die Ungleichung minvol <= tmp (Fall 3) hier erfüllt ist, ist damit gewährleistet, dass der berechnete Wert nicht negativ ist. Dann wird der berechnete Wert explizit in einen Wert vom Typ ulong umgewandelt. Es ist ulong, weil garantiert ist, dass der berechnete Wert nicht negativ ist.
Bei der Konvertierung in den Ganzzahlentyp wird der gebrochene Teil des reellen Typs verworfen. Es wird nicht auf den nächsten Wert aufgerundet, sondern der Bruchteil wird verworfen, wodurch gewährleistet wird, dass der Höchstwert der Lose, den der freie Spielraum erlaubt, nicht erhöht wird. Das ist genau das, was wir brauchen.
Da der ganzzahlige Wert von N erhalten wird, wird der maximale diskretisierte Wert der Lose, der die Anforderungen an den freien Spielraum erfüllt, auf die übliche Weise erhalten (d.h. die nächste ganze Zahl im Raster der Diskretisierung der maximalen Loswerte wird die Anforderungen an den freien Spielraum nicht erfüllen, während das erhaltene N immer noch die Anforderungen an den freien Spielraum erfüllen wird): "minvol + stepvol * N".
Ich möchte einen ganz wichtigen Punkt hervorheben. Die Sache ist die, dass Zahlen vom Typ double maximale Werte bis zu etwa 1.8e308 annehmen können, während Zahlen vom Typ ulong - nur etwa 1.8e19 (es ist nur ein Eintrag für die Bequemlichkeit, die Konstante 1.8e19 selbst ist nicht vom Typ ulong).
Was passiert, wenn der Wert des Ausdrucks "(tmp - minvol) / stepvol" 1,8e19 überschreitet? In diesem Fall wird bei der Umwandlung in den Typ ulong "abgeschnitten" - der Wert ist der Rest der ganzzahligen Division des Ausdruckswerts durch ULONG_MAX.
Wären die Zahlen nicht so groß, würde es in Bezug auf MQL5 wie "X % ULONG_MAX" aussehen, wobei X eine ganze Zahl ist, die gleich "(tmp - minvol) / stepvol" ist.
Dies ist kein typischer Fall, aber warum sollte man Fehler im Code lassen? Außerdem kann man den Funktionen der MQL5-Bibliothek nicht trauen, sie können jeden beliebigen Unsinn zurückgeben (ich werde den Beweis dafür antreten).
Für Fälle, in denen der Wert des Ausdrucks "tmp / stepvol" nicht in 1.8e19 passt, haben wir absichtlich eine Prüfung eingeführt (die letzte Zeile der if-Bedingung):
tmp < ULONG_MAX * stepvol
Sie können natürlich auch "tmp / stepvol <" schreiben. (double)ULONG_MAX", aber erstens versuche ich, Divisionsoperationen zu vermeiden, wenn es nicht explizit notwendig ist, und zweitens müsste ich eine explizite Typkonvertierung durchführen, da die Konstante ULONG_MAX vom Typ ulong ist, Wenn man Operanden vergleicht, werden sie nicht implizit in einen höheren Typ gecastet (zumindest ist das in C/C++ so), und im dritten Fall - ich wäre nicht auf einen netten Fehler in der Sprache selbst gestoßen, auch nicht in Bibliotheksfunktionen - ist der Fehler nicht der in der DNA, sondern buchstäblich in den Molekülen und Atomen von MQL5.
Der linke Operand der Vergleichsoperation ist tmp und hat den Typ double, während der rechte Operand der Ausdruck "ULONG_MAX * stepvol" ist und ebenfalls den Typ double hat.
Dieser Ausdruck hat zwei Operanden, einen vom Typ ulong und den anderen vom Typ double. Nach den Regeln der impliziten Typkonvertierung wird zunächst der Operand des niedrigeren Typs in den Operanden des höheren Typs umgewandelt, die Operation ausgeführt und das Ergebnis in den Operanden des höheren Typs umgewandelt. Der double-Typ ist "älter" als ulong, deshalb wird der ULONG_MAX-Wert von ulong implizit in double umgewandelt, die Operation wird durchgeführt und das Ergebnis ist vom double-Typ.
Allerdings gibt es hier einen Fehler, der übrigens nicht immer, sondern nur in einigen Fällen auftritt, darunter auch in diesem, und der Fehler besteht darin, dass das Ergebnis des Ausdrucks "ULONG_MAX * stepvol" nur der Wert von stepvol ist.
Daher funktioniert die Funktion, die ich anzeige, nicht und wird auch nicht funktionieren, bis die Entwickler von MetaQuotes diesen Fehler beheben.
Um diese Funktion jetzt zu nutzen, sollten Sie sich die Besonderheit des Fehlers zunutze machen: Er verschwindet, wenn Sie eine explizite Typkonvertierung durchführen:
Um auf die beschriebene Prüfung zurückzukommen: Sie garantiert, dass der Wert des Ausdrucks "tmp / stepvol" ULONG_MAX nicht überschreitet. Der Probenahmecode verwendet jedoch den Ausdruck "(tmp - minvol) / stepvol".
Der Wert dieses Ausdrucks wird auch ULONG_MAX nicht überschreiten, da die vorherigen Überprüfungen sicherstellen, dass minvol > 0 und tmp >= minvol ist, d.h. tmp - minvol < tmp.
Daher gilt die Garantie, dass ULOMG_MAX nicht überschritten wird, auch für den Ausdruck "(tmp - minvol) / stepvol".
Im Allgemeinen besteht einer der Hauptunterschiede zwischen einem Fachmann und einem Laien darin, dass ein Fachmann zumindest etwas garantieren kann, während ein Laie...
Ich habe die beiden gefundenen Fehler in dem anderenBeitrag zerlegt und gleichzeitig klargestellt, was MetaQuotes getan und nicht getan hat.
Для чего в этом месте кода выполняется эта привязка? И почему именно к сетке 0.01, а не к, скажем, 0.001?
Im System ist das Mindestlos = 0,01
Anmerkungen:
Ich spreche nur für mich selbst (aber wenn Sie Ihr Spiegelbild sehen, sind Sie nicht der Einzige).
In den letzten Monaten des Wettlaufs um Bugs habe ich mir angewöhnt, einen Bug im MetaTrader überhaupt erst als Bug zu betrachten.
Warum auch, es ist einfach ein gut getestetes Muster, wenn etwas nicht funktioniert, dann ist es ein Fehler und lässt die Alarmglocken läuten.
Beispiel: Ich habe einen Fehler gefunden, eine Anfrage an servicedesk geschickt, sie haben einen Verifizierungscode geschrieben, aber nichts.
Ich habe mich erneut beworben und in Erwartung einer Antwort meine Ungeschicklichkeit festgestellt.
Das Ergebnis ist, dass ich mich schäme, die Leute vor Ort abgelenkt zu haben.
Aber wenn ich den Nachrichtenfluss analysiere, verstehe ich, dass die Masse der Menschen, auch wenn sie intelligent sind, immer noch der Psychologie der Masse unterworfen ist.
Wenn es Fehler gibt, schreibe ich einen Bug und lasse Renat meinen Code aussortieren und mit dem Finger auf meinen Fehler zeigen.
Ich verstehe, dass Toleranz nicht erlaubt zu sagen: Ja, du bist ein Idiot, dein Code ist krumm.
Aber man kann nicht so weit gehen, und es weiter zu verlängern alle Mitarbeiter MQ wird bald in, dass sitzen auf anderen Menschen Codes in trauernden Kontemplation "aber warum brauchen wir es alle", während die Meisterschaft kommt, und dort und gehen Sie zu den realen Konten sind nicht weit weg.
Mein Motto für heute lautet: "Wenn du einen Fehler veröffentlichst, prüfe, ob das Problem in deinen Händen liegt.
Neues Gebäude - neue Probleme. Expert, das nach der Kompilierung in 314 (Kompilierung ohne Fehler) in 306 einwandfrei funktionierte, gibt im Testprogramm den Geist auf:
2010.08.21 17:03:36 Kern 1 getrennt2010.08.21 17:03:36 Kern 1 Tester angehalten, weil OnInit fehlgeschlagen
2010.08.21 17:03:36 Core 1 2010.01.04 00:00:00 Zugriffsverletzung gelesen auf 0x0000000000000014
2010.08.21 17:03:36 Kern 1 2010.01.04 00:00:00 Saldo=10000.00 Eigenkapital=10000.00 Gewinn=0.00
2010.08.21 17:03:36 Kern 1 2010.01.04 01.04 00:00:00 PriceChannel_multi_Ch_Timer Expert Advisor arbeitet seit 2010.01.04 00:00 im EURUSD-Chart für den Zeitraum H1
Es entlädt sich auch im wirklichen Leben. Es hat sich gezeigt, dass die Fehlerquelle eine Zeile ist
Ersetzen durch ein paar Zeilen
string curSymbol=TradeSymbols[i]; m_symbol[j].Name(curSymbol);
den Status quo an den Expert Advisor zurückgegeben.
Was ist denn los?
Übrigens, der Code, der im letzten Build kompiliert wurde, funktioniert auch in diesem gut.
Was ist denn los?
Übrigens funktioniert der im letzten Build kompilierte Code auch in diesem Build einwandfrei.
Mindestmenge = 0,01
Anmerkungen:
Im Moment ist die Mindestmenge des Systems = 0,01. Aber was ist in einem Jahr? In zwei Jahren?
1) Welche Bedingung ist richtig? Wie lautet nun die richtige Formel? Sagen wir, für minvol = 0,15 und stepvol = 0,1 - was wären die ersten paar gültigen Losgrößen? a) 0,15, 0,25, 0,35... ? б) 0.15, 0.2, 0.3... ? в) ... ? Ich bin davon ausgegangen, dass es sich um Option a handelt.
2. Ich bin aus einem bestimmten Grund zu ulong gewechselt - ich habe das Recht, den Typ mit der größten Reichweite zu wählen, so dass er für eine möglichst große Anzahl von Fällen ausreicht, denn solche Funktionen sind sehr grundlegende Bausteine. Und die Tatsache, dass ich auf einen Fehler gestoßen bin, bedeutet nicht, dass ich es war, der die Probleme verursacht hat. :) Reasoning schrieb mehr für andere, um ein möglichst breites Spektrum zu verstehen - wir haben es hier nicht mit einem persönlichen Briefwechsel zu tun.
3. Die Substitution ist nicht schwierig - es geht nur darum, zu sparen, um keine Variablen zu haben, die nur einmal verwendet werden. Und es wurde geprüft und verifiziert, dass die Variable per Referenz übergeben wird, wenn eine Funktion höchstens einmal aufgerufen wird, so dass mögliche Fehler dadurch vermieden werden. Wenn es einige Leute stört, können sie für jeden übertragenen Wert (auch für einen Zwischenwert, wie z. B. den Briefkurs) eine Variable erstellen, wie Sie es getan haben. Dieser Punkt ist nicht wichtig.
Viel wichtiger ist der Mechanismus der Bindung an das Raster der zulässigen Werte, der im Übrigen keine Korrekturen erfordert und das Auftreten von Störungen in verschiedenen, nicht sehr typischen Fällen garantiert, wobei die größtmögliche Einfachheit erhalten bleibt.
Die Prämisse ist, dass der Grundbaustein so robust und vielseitig wie möglich sein sollte - dann wird das ganze Haus wahrscheinlich sogar ein Erdbeben überstehen.
Ich spreche nur für mich selbst (aber wenn Sie Ihr Spiegelbild sehen, sind Sie nicht der Einzige).
In den letzten Monaten des Wettlaufs um Bugs habe ich mir angewöhnt, einen Bug im MetaTrader überhaupt erst als Bug zu betrachten.
Warum auch immer, es ist einfach ein bewährtes Muster: Wenn etwas nicht funktioniert, dann ist es ein Fehler und die Alarmglocken läuten.
Die Tatsache, dass MQL5 und MQL5-Fehler sehr ähnlich aussehen, spielt hier eine wichtige Rolle. Und es gibt eine Menge MQL5-Fehler.
Wenn MQL5 deutlich weniger Fehler hätte und sie nicht so einfach wären, wäre es viel schwieriger, sie zu verwechseln.
Sie haben bereits begonnen, über die Möglichkeit nachzudenken, die Meisterschaft zu starten, und es ist an der Zeit, dass sie mit der Arbeit an den echten Handelskonten beginnen.
Das heutige Motto lautet: "Wenn du einen Fehler veröffentlichst, prüfe, ob das Problem in deinen Händen liegt".
Die Tatsache, dass die Meisterschaft für NUR in MQL5 geschriebene Expert Advisors ein Glücksspiel ist, war zum Zeitpunkt der Bekanntgabe der Entscheidung klar. Aber das EA-Management hat seine eigene Vision. Das haben sie selbst so entschieden. Niemand hat sich in ihre Entscheidung eingemischt. Was soll's, wenn die Meisterschaft vor der Tür steht, sie haben sich ein Leben aufgebaut.
Hier ist es einfach: Sie müssen an der Lokalisierung des Fehlers arbeiten: Beginnen Sie damit, alles aus dem Code zu entfernen, was den Fehler nicht beeinflusst. Schließlich erhalten Sie eine Art Testbeispiel, das zwar klein genug ist, aber den Fehler weitgehend demonstriert. Dies wird nicht mehr "der Code von jemand anderem" sein, sondern "Code, der den Fehler MQL5 demonstriert".
Ich habe ein Skript geschrieben, um die Funktion OrderCalcMargin() zu überprüfen. Die Funktion gibt für einige Symbole Null zurück.
Dies gilt wahrscheinlich für die Symbole, die nicht in MarketWatch enthalten sind, da SymbolName für SymbolName angegeben ist:
SymbolName
Gibt den Namen des angegebenen Symbols zurück.
stringSymbolName(
intpos,// Nummer in der Liste
bool selected// true - nur Symbole in MarketWatch
);
Parameter
pos
[in] Symbolnummer in Reihenfolge.
ausgewählt
Abfragemodus [in]. Wenn ja, wird das Symbol aus der Liste der in MarketWatch ausgewählten Symbole genommen. Wenn der Wert false ist, wird das Symbol aus der gemeinsamen Liste genommen.
Zurückgegebener Wert
Wert vom Typ String mit Symbolname.