Diskussion zum Artikel "Berechnung mathematischer Ausdrücke (Teil 2). Parser nach Pratt und dem Shunting-yard-Algorithmus"

 

Neuer Artikel Berechnung mathematischer Ausdrücke (Teil 2). Parser nach Pratt und dem Shunting-yard-Algorithmus :

In diesem Artikel betrachten wir die Prinzipien der Analyse und Auswertung mathematischer Ausdrücke unter Verwendung von Parsern, die auf der Operator-Priorität basieren. Wir werden Parser nach Pratt und dem Shunting-yard-Algorithmus, Bytecode-Generierung und Auswertungen mit diesem Code implementieren und uns ansehen, wie Indikatoren als Funktionen in Ausdrücken verwendet und wie Handelssignale in Expert Advisors auf der Grundlage dieser Indikatoren eingerichtet werden können.

Wenn Sie den EA im Strategy Tester starten, wird das Ergebnis höchstwahrscheinlich nicht sehr gut sein. Wichtig ist jedoch, dass der EA-Handel und der Handel von den Parsern verwaltet wird. Sie geben keine fertigen, profitablen Systeme, sondern bieten ein zusätzliches Werkzeug, um Strategien zu finden.

Ein Beispiel für den Handel mit Signalen, die durch Ausdrücke ermittelt werden

Ein Beispiel für den Handel mit Signalen, die durch Ausdrücke ermittelt werden

Autor: Stanislav Korotky

 
Wenn Sie die Leistung vergleichen, vergleichen Sie sie mit reiner MMS.
 

Der Vergleich der Leistung unter Berücksichtigung der nativen MQL5 ist wie folgt:

ExpresSParserS (EURUSD,D1)      Evaluation: 105109
ExpresSParserS (EURUSD,D1)      Compilation: 26090
ExpresSParserS (EURUSD,D1)      Pratt bytecode: 24030
ExpresSParserS (EURUSD,D1)      Pratt: 26567
ExpresSParserS (EURUSD,D1)      ShuntingYard: 23884
ExpresSParserS (EURUSD,D1)      MQL5: 12901

MQL5 ist etwa 2-mal schneller als die schnellsten vorgestellten Parser.

Testcode hinzugefügt:

class FuncCalc
{
  private:
    double a;
    double b;
    double c;
  public:
    void setup(double _a, double _b, double _c)
    {
      a = _a;
      b = _b;
      c = _c;
    }
    double execute()
    {
      return (a + b) * (c > 10000 ? c / 4 : c * 4);
    }
};

ulong testMQL5(const int n)
{
  ulong ul = 0, total = 0;
  double r;
  FuncCalc f;

  for(int i = 0; i < n; i++)
  {
    f.setup(rand(), rand(), rand());
    ul = GetMicrosecondCount();
    r = f.execute();
    total += GetMicrosecondCount() - ul;
  }
  return total;
}

Dies ist eine grobe Schätzung. Es gibt noch viel Raum für Forschung (zum Beispiel mit verschiedenen Arten von Ausdrücken) und Parser-Optimierung.

 

jetzt kann ich nur loben.

Natürlich hätte ich Dijkstra erwähnen sollen, denn historisch gesehen wird der Schießplatz eher mit ihm in Verbindung gebracht.

Ich hatte die Idee, einen ähnlichen Artikel zu verfassen, ich war sogar dabei, das Material für mich selbst abzutippen, Sie sind mir zuvorgekommen (etwa bei Teil 2), aber ich hatte die Angewohnheit, alles in Festungen und Stapelmaschinen zu rollen.

Sie haben es geschafft, den Artikel nicht darin einzurollen (oder zu lispeln)!

Die Kirsche auf dem Kuchen wäre der Y-Kombinator.

PS: Aber Bytecodes haben sich als "breit" herausgestellt und werden von Klassen getötet. Sie können pfeifen und 64 Bit tolerieren. Nun, der Chef ist der Chef :-)

 
Maxim Kuznetsov:

jetzt kann ich nur loben.

Natürlich sollte man Dijkstra erwähnen, denn historisch gesehen wird der Schießplatz eher mit ihm in Verbindung gebracht

Ich hatte die Idee, einen ähnlichen Artikel zu verfassen, ich war sogar dabei, das Material für mich selbst abzutippen, du bist mir zuvorgekommen (in Bezug auf Teil 2), aber ich hatte all die üblichen Dinge in die Festung und die Stapelmaschinen geworfen

Sie haben es geschafft, den Artikel nicht mitzurollen (oder zu lispeln)!

Die Kirsche auf dem Kuchen wäre der Y-Kombinator.

PS: Aber Ihre Bytecodes sehen "zu breit" aus und werden von Klassen erschlagen. Du kannst pfeifen und 64 Bit tolerieren. Nun, der Chef ist der Chef :-)

Du kannst eine Fortsetzung mit Byte-Code-Schrumpfung, Beschleunigung und neuen Arten von Parsern schreiben. Ich habe es nicht geschafft, alles abzudecken, eigentlich wollte ich nur einen Artikel schreiben, aber wie immer hat es nicht gepasst.

 
Stanislav Korotky:

Sie können eine Fortsetzung mit Byte-Code-Schrumpfung, Beschleunigung und neuen Arten von Parsern schreiben. Ich habe es nicht geschafft, alles abzudecken. Eigentlich wollte ich nur einen Artikel schreiben, aber wie üblich hat es nicht gepasst.

Bytecode hängt von der virtuellen Maschine ab. Einerseits bin ich versucht, 128 Bit oder mehr für den Op-Code "Addition von zwei Zahlen" ....

und neue Arten von Parsern sind noch nicht erfunden worden, sie sind alle Jahre alt ;-) und es gibt nur 2 und eine Hälfte von ihnen.

PS die Sortierstation für die Bedürfnisse von Terminalbenutzern ist überholt - man kann eine bekannte Formel in das Eingabefeld eingeben und erhält das Ergebnis.

 
Im Gegensatz zu einigen der anderen Artikel sind diese beiden Artikel sehr gut. Klar, detailliert, zugänglich. Ich danke Ihnen.
 
Die aktualisierte Version des Rechners 1.1 ist dem Artikel über die Partikelschwarmoptimierung beigefügt. Außerdem gibt es eine kleine Fehlerbehebung in der Diskussion.
Параллельная оптимизация методом роя частиц (Particle Swarm Optimization)
Параллельная оптимизация методом роя частиц (Particle Swarm Optimization)
  • www.mql5.com
Как известно, MetaTrader 5 позволяет оптимизировать торговые стратегии с помощью встроенного тестера на основе двух алгоритмов: прямого перебора входных параметров и генетики (генетический алгоритм - ГА). Генетическая оптимизация является одной из разновидностей эволюционных алгоритмов, которые предоставляют значительное ускорение процесса...
 
Bitte zeigen Sie, wie man einen Parser für eine solche Zeichenkette verwendet.
"(EURUSD^2) / (GBPUSD * AUDUSD)"

Die Schwierigkeit besteht darin, dass wir automatisch feststellen müssen, in welchem Fall und an welcher Stelle Geld/Brief zu ersetzen sind.

In dem obigen Beispiel sollte es so sein.

Value_Bid = (EURUSD_Bid * EURUSD_Bid / (GBPUSD_Ask * AUDUSD__Ask);
Value_Ask = (EURUSD_Ask * EURUSD_Ask / (GBPUSD_Bid * AUDUSD__Bid);


Der Algorithmus zur Bestimmung von Bid/Ask sieht folgendermaßen aus. Unter Verwendung desselben Beispiels.

F(EURUSD, GBPUSD, AUDUSD) = (EURUSD^2) / (GBPUSD * AUDUSD);

bool EURUSD_flag = (F(1, 1, 1) < F(2, 1, 1));
bool GBPUSD_flag = (F(1, 1, 1) < F(1, 2, 1));
bool AUDUSD_flag = (F(1, 1, 1) < F(1, 1, 2));

Value_Bid = F(EURUSD_flag ? EURUSD_Bid : EURUSD_Ask,
              GBPUSD_flag ? GBPUSD_Bid : GBPUSD_Ask,
              AUDUSD_flag ? AUDUSD_Bid : AUDUSD_Ask);

Value_Ask = F(EURUSD_flag ? EURUSD_Ask : EURUSD_Bid,
              GBPUSD_flag ? GBPUSD_Ask : GBPUSD_Bid,
              AUDUSD_flag ? AUDUSD_Ask : AUDUSD_Bid);
 
fxsaber:
Bitte zeigen Sie mir, wie ich den Parser für eine solche Zeichenkette verwenden kann.

Die Hauptschwierigkeit besteht darin, die Namen aller Variablen in dem Ausdruck zu ermitteln. So dass Sie etwas Ähnliches schreiben können.

TestSuiteEvaluator evaluator("EURUSD=1.5;GBPUSD=2.5;AUDUSD=5");
 
Aus der Sicht des Parsers kann eine Variable nicht 2 Werte haben: Bid und Ask. Es ist wahrscheinlich möglich, Komponenten in Funktionen zu verpacken (entweder die Funktionen Bid(symbol), Ask(symbol) oder die gesamte Funktion "basket" einführen, wenn die Anzahl der Komponenten vordefiniert ist). Im Grunde ist das ursprüngliche Problem nicht klar: Wenn es sich um einen synthetischen Korb aus drei Symbolen handelt, dann wird jede Komponente darin eindeutig entweder von Ask oder Bid erworben, je nach Richtung. Sie können auch die Möglichkeit verschiedener Ausdrücke je nach Richtung der Transaktionen in Betracht ziehen.