Fehler, Irrtümer, Fragen - Seite 105

 
Interesting:

Der Tester hat eine eigene Liste von Werkzeugen und muss erstellt werden (vorzugsweise bei der Initialisierung des EA).

Herzlichen Dank! Ich hab's. Eine Menge verpasst...
 
Renat:

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:

double CalculateMaxVolume(string symbol)
  {
   double price=0.0;
   double margin=0.0;
//--- select lot size
   if(!SymbolInfoDouble(symbol,SYMBOL_ASK,price))                return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,symbol,1.0,price,margin)) return(0.0);
   if(margin<=0.0)                                            return(0.0);

   double lot_pure=AccountInfoDouble(ACCOUNT_FREEMARGIN)/margin;
   double lot=NormalizeDouble(lot_pure,2);
   Print("lot_pure = ", lot_pure, ", lot = ", lot);
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   if(stepvol>0.0)
     {
      double newlot=stepvol*NormalizeDouble(lot/stepvol,0);
      if(newlot>lot) { Print("Чёрт побери: lot = ", lot, ", newlot = ", newlot);
                       lot=NormalizeDouble(newlot-stepvol,2);
                     }
      else           lot=newlot;
     }

   double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol) lot=0.0;   // 

   double maxvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol) lot=maxvol;
//--- return trading volume
   return(lot);
  }

void OnStart()
{
  Print("CalculateMaxVolume(Symbol()) = ", CalculateMaxVolume(Symbol()));
}

/* Вывод в лог (хронология - сверху вниз)
CO      0       1 (EURUSD,M15)  01:40:33        lot_pure = 7.799703611262773, lot = 7.8
JG      0       1 (EURUSD,M15)  01:40:33        Чёрт побери: lot = 7.8, newlot = 7.800000000000001
MQ      0       1 (EURUSD,M15)  01:40:33        CalculateMaxVolume(Symbol()) = 7.7
*/

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:

double lot=NormalizeDouble(lot_pure,2);

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:

double lot_pure=AccountInfoDouble(ACCOUNT_FREEMARGIN)/margin;

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:

double newlot=stepvol*NormalizeDouble(lot/stepvol,0);

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:

double lot=NormalizeDouble(lot_pure,2);
...
lot=NormalizeDouble(newlot-stepvol,2);
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:

double CalculateMaxVolume_New(string symbol)
{
  double stepvol = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
  double minvol  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
  double maxvol  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);

  // Не доверяем значениям, которые вернули функции
  if(stepvol > 0 && minvol > 0 && maxvol > minvol)
  {
    double tmp = 0;

    // Вычисляем цену Ask, Margin на 1 лот, лотов на FreeMargin
    if(SymbolInfoDouble(symbol, SYMBOL_ASK, tmp)            && tmp > 0       &&
       OrderCalcMargin(ORDER_TYPE_BUY, symbol, 1, tmp, tmp) && tmp > 0       &&
       (tmp = AccountInfoDouble(ACCOUNT_FREEMARGIN) / tmp)         >= minvol &&
       tmp < ULONG_MAX * stepvol)
    {
      Print("pure_lot = ", tmp); // Эту строку нужно удалить из рабочего кода

      if(tmp > maxvol) // Здесь в tmp содержится недискретизированное число лотов
        return maxvol;

      // Привязываемся к сетке дискретизации
      return minvol + stepvol * (ulong)((tmp - minvol) / stepvol);
    }
  }

  return 0;
}

void OnStart()
{
  Print("CalculateMaxVolume_New(Symbol()) = ", CalculateMaxVolume_New(Symbol()));
}

/* Вывод в лог (хронология - сверху вниз)
LQ      0       1 (EURUSD,M15)  01:39:07        pure_lot = 7.799095304944626
KD      0       1 (EURUSD,M15)  01:39:07        CalculateMaxVolume_New(Symbol()) = 7.7
*/

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:

return minvol + stepvol * (ulong)((tmp - minvol) / stepvol);

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:

tmp < (double)ULONG_MAX * stepvol

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:

  1. Ihre anfängliche Bedingung minvol + N * stepvol ist nicht garantiert korrekt, Sie können minlot auf einen anderen Wert setzen und Ihre Logik wird gebrochen.
  2. Du hättest umsonst zu ulong wechseln sollen - du hast dir selbst Schwierigkeiten bereitet und dann eine ganze Seite mit Gedanken darüber geschrieben
  3. Die Ersetzung von tmp in Ihrem Code ist zu clever, meine Version ist in Bezug auf die Operationen viel klarer
 

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.

Общайтесь с разработчиками через Сервисдеск!
Общайтесь с разработчиками через Сервисдеск!
  • www.mql5.com
Ваше сообщение сразу станет доступно нашим отделам тестирования, технической поддержки и разработчикам торговой платформы.
 

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

m_symbol[j].Name(TradeSymbols[i]);

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.

 
Valmars:

Was ist denn los?

Übrigens funktioniert der im letzten Build kompilierte Code auch in diesem Build einwandfrei.

Unser Fehler - wir werden ihn auf jeden Fall beheben.
 
Renat:

Mindestmenge = 0,01


Anmerkungen:

  1. Ihre anfängliche Bedingung minvol + N * stepvol ist nicht garantiert korrekt, Sie können minlot auf einen anderen Wert setzen und Ihre Logik wird gebrochen.
  2. Sie hätten nicht zu ulong wechseln sollen - Sie haben sich selbst Schwierigkeiten bereitet und dann eine ganze Seite mit Gedanken darüber geschrieben
  3. Die Ersetzung von tmp in Ihrem Code ist zu clever, während meine Version in Bezug auf die Operationen viel klarer ist.

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.

 
Urain:

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.

Urain:

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

 
Schreiben eines Skripts zum Testen der Funktion OrderCalcMargin()
void OnStart()
  {
//---
   int total=SymbolsTotal(false);
   double marginbay;
   double marginsell;
   MqlTick last_tick;
   for(int i=0;i<total;i++)
     {

      string symbol=SymbolName(i,false);
      Print("************************************************");
      Print("Инструмент - ",symbol);
      Print("Валюта депозита = ",AccountInfoString(ACCOUNT_CURRENCY));
      Print("Базовая валюта = ",SymbolInfoString(symbol,SYMBOL_CURRENCY_BASE));
      Print("Валюта маржи = ",SymbolInfoString(symbol,SYMBOL_CURRENCY_MARGIN));
      if(SymbolInfoTick(symbol,last_tick))
        {
         OrderCalcMargin(ORDER_TYPE_BUY,symbol,1.0,last_tick.ask,marginbay);
         OrderCalcMargin(ORDER_TYPE_SELL,symbol,1.0,last_tick.bid,marginsell);
         Print("Маржа для покупки = ",marginbay);
         Print("Маржа для продажи = ",marginsell);
        }
      else Print("SymbolInfoTick() failed, error = ",GetLastError());
     }
  }
//+------------------------------------------------------------------+
Die Funktion gibt für einige Instrumente den Wert Null zurück. Ist dies ein Fehler oder ist sie so konzipiert?
 
sergey1294:
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.

Drucken Sie den Namen des Symbols aus, für das Sie ein unerwartetes Ergebnis erhalten, und vergleichen Sie ihn mit der Liste in MarketWatch.
Grund der Beschwerde: