English 日本語
preview
Connexus Observer (Teil 8): Hinzufügen eines Request Observer

Connexus Observer (Teil 8): Hinzufügen eines Request Observer

MetaTrader 5Beispiele | 7 April 2025, 08:38
51 0
joaopedrodev
joaopedrodev

Einführung

Dieser Artikel ist die Fortsetzung einer Reihe von Artikeln, in denen wir eine Bibliothek namens Connexus aufbauen werden. Im ersten Artikel haben wir die grundlegende Funktionsweise der WebRequest-Funktion verstanden, jeden ihrer Parameter kennengelernt und auch einen Beispielcode erstellt, der die Verwendung dieser Funktion und ihre Schwierigkeiten demonstriert. Im letzten Artikel haben wir die Client-Schicht erstellt, eine einfache und intuitive Klasse, die für das Senden von Anfragen, den Empfang eines Anfrageobjekts (CHttpRequest) und die Rückgabe einer Antwort (CHttpResponse) verantwortlich ist, die Informationen über die Anfrage enthält, wie z. B. Statuscode, Dauer, Textkörper und Antwort-Header. Außerdem haben wir die Klasse von der WebRequest-Funktion entkoppelt, um die Bibliothek flexibler zu machen, indem wir eine neue Schicht namens CHttpTransport geschaffen haben.

In diesem achten Artikel der Serie werden wir einen Observer in der Bibliothek verstehen und implementieren, um die Verwaltung von mehreren Anfragen durch den Client zu erleichtern. Los geht's!

Um Sie an den aktuellen Stand der Bibliothek zu erinnern, sehen Sie hier das aktuelle Diagramm:

Diagramm 1


Was ist ein Observer?

Stellen Sie sich den Observer (Beobachter) als den Freund vor, der halb versteckt aus der Ferne zusieht und alles mitbekommt, ohne sich einzumischen. In der Welt der Programmierung tut das Observer-Muster etwas sehr Ähnliches: Es ermöglicht bestimmten Objekten, „benachrichtigt“ zu werden, wenn sich etwas ändert, ohne dass sie genau wissen müssen, wer die Änderung verursacht hat. Es ist fast wie eine magische Berührung: Jemand bewegt ein Teil und derjenige, der es gerade braucht, weiß es schon. Dieses Muster ist einer der Klassiker, wenn es darum geht, das Räderwerk der Geschäftslogik und der Nutzeroberfläche nebeneinander laufen zu lassen. Auf diese Weise erhält das System eine gewisse Fluidität, da sich mehrere Teile automatisch an Ereignisse anpassen.

Die Idee wurde geboren, um eines dieser lästigen Probleme in sehr starren Systemen zu lösen, bei denen ein Objekt von einem anderen abhängt und an diesem „klebt“, ohne viel Spielraum zum Atmen zu haben. Die Lösung? Entkoppeln, es machte es einfacher. Bevor der Observer einen Namen und Nachnamen bekam, suchten die Programmierer bereits nach leichteren Systemen. Damals, im Jahr 1994, stellten **Erich Gamma, Richard Helm, Ralph Johnson und John Vlissides** in ihrer Arbeit Entwurfsmuster (Buch): Elemente wiederverwendbarer objektorientierter Software (1994) den Observer als ideale Möglichkeit vor, mehrere Objekte bei Änderungen an einem einzelnen Objekt auf dem neuesten Stand zu halten, ohne die Ketten einer starken Bindung.


Warum das Observer-Muster verwenden?

Der Observer ist perfekt, wenn wir eine Entkopplung brauchen, wenn wir die Dinge unabhängiger voneinander machen wollen. Das Subjekt muss nicht wissen, wer es beobachtet, es muss einfach nur „Veränderung in Sicht“ schreien und weitermachen. Er kann auch für Echtzeit-Updates**,** nützlich sein. Systeme, die sofort aktualisiert werden müssen, wie z. B. interaktive Schnittstellen oder automatische Benachrichtigungen, sind mit dem Observer viel beweglicher.


Komponenten des Observer-Musters

  1. Thema: Dies ist der „Besitzer des Stücks“, dessen Zustand sich ändert und der die Observer über diese Änderungen informieren muss. Es führt eine Liste von Observer und verfügt über Methoden, um jemanden aus der Liste hinzuzufügen oder zu entfernen.
  2. Observer: Jeder Observer ist wie ein „Zuhörer“, der immer bereit ist, auf die Veränderungen des Subjekts zu reagieren. Es implementiert eine Aktualisierungsmethode, die das Subjekt jedes Mal aufruft, wenn eine Änderung eintritt.

Ich füge unten ein Diagramm hinzu, das zeigt, wie das Observer-Muster funktioniert:

Diagramm 2

  1. Hauptklassen
    • Subject: Diese Klasse verwaltet eine Sammlung von Observer (observerCollection) und bietet Methoden zur Verwaltung dieser Observer. Seine Aufgabe ist es, die Observer zu benachrichtigen, wenn eine Zustandsänderung eintritt.
      • Methoden:
        • registerObserver(observer) : Fügt der Sammlung einen Observer hinzu.
        • unregisterObserver(observer) : Entfernt einen Observer aus der Sammlung.
        • notifyObservers() : Benachrichtigt alle Observer durch Aufruf der Methode update() jedes Observers in der observerCollection .
    • Observer: Dies ist eine Schnittstelle oder abstrakte Klasse, die die Methode update() definiert. Alle konkreten Observer-Klassen (Konkretisierungen von Observer ) müssen diese Methode implementieren, die aufgerufen wird, wenn das Subjekt Änderungen meldet.
  2. Konkrete Klassen
    • ConcreteObserverA und ConcreteObserverB: Dies sind konkrete Implementierungen der Observer-Schnittstelle. Jede implementiert update(), die die spezifische Reaktion auf eine Änderung in Subject definiert.
  3. Beziehung zwischen Subjekt und Observer
    • Das Subjekt verwaltet eine Liste von Observern und benachrichtigt sie, indem es observer.update() für jeden Observer in der Sammlung aufruft.
    • Die konkreten Observer reagieren auf Änderungen, die im Subjekt auftreten, gemäß ihrer spezifischen Implementierung in update().

Wie kann dies in der Connexus-Bibliothek genutzt werden? Wir werden dieses Muster verwenden, um den Client-Code zu informieren, wenn eine Anfrage gesendet wurde, wenn eine Antwort empfangen wurde oder sogar wenn ein unerwarteter Fehler aufgetreten ist. Mit diesem Muster wird der Kunde darüber informiert, dass dies geschehen ist. Dies erleichtert die Verwendung der Bibliothek, da Bedingungen im Code vermieden werden, wie z. B. „wenn ein Fehler erzeugt wurde, dann tu dies“, „wenn eine Anfrage gestellt wurde, dann tu dies“, „wenn eine Antwort empfangen wurde, dann tu dies“.


Praktischer Code

Zunächst zeige ich ein Diagramm, das zeigt, wie wir dieses Muster in den Kontext der Bibliothek einfügen werden:

Diagramm 3

Lassen Sie uns besser verstehen, wie die Umsetzung aussehen wird.

  1. Beachten Sie, dass das Diagramm die gleiche Struktur hat wie das Referenzdiagramm
  2. Ich habe zwei Methoden hinzugefügt, auf die die Observer Zugriff haben werden:
  3. OnSend() → Wenn eine Anfrage gesendet wird.
  4. OnRecv() → Wenn eine Antwort eingegangen ist.
  5. IHttpObserver wird keine abstrakte Klasse sein, sondern eine Schnittstelle.


Erstellen der Schnittstelle IHttpClient

Zuerst erstellen wir die Schnittstelle IHttpClient unter dem Pfad <Connexus/Interface/IHttpClient.mqh> . Und wir definieren die beiden Benachrichtigungsfunktionen

//+------------------------------------------------------------------+
//|                                                IHttpObserver.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include "../Core/HttpRequest.mqh"
#include "../Core/HttpResponse.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
interface IHttpObserver
  {
   void OnSend(CHttpRequest *request);
   void OnRecv(CHttpResponse *response);
  };
//+------------------------------------------------------------------+


Erstellen der Liste der Observer in CHttpClient

Binden wir die Schnittstelle ein.

#include "../Interface/IHttpObserver.mqh"
Erstellen wir nun das Array der Observer im privaten Bereich der Klasse. Denken Sie daran, dass dieses Array Zeiger speichern soll, also müssen wir den „*“ vor den Variablennamen setzen. Wir werden auch öffentliche Methoden zum Hinzufügen, Entfernen und Benachrichtigen aller Observer erstellen, die im Array gespeichert sind.
//+------------------------------------------------------------------+
//|                                                   HttpClient.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "HttpRequest.mqh"
#include "HttpResponse.mqh"
#include "../Constants/HttpMethod.mqh"
#include "../Interface/IHttpTransport.mqh"
#include "../Interface/IHttpObserver.mqh"
#include "HttpTransport.mqh"
//+------------------------------------------------------------------+
//| class : CHttpClient                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpClient                                        |
//| Heritage    : No heritage                                        |
//| Description : Class responsible for linking the request and      |
//|               response object with the transport layer.          |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpClient
  {
private:
   IHttpObserver     *m_observers[];                     // Array of observers
   
public:
   //--- Observers
   void              RegisterObserver(IHttpObserver *observer);
   void              UnregisterObserver(IHttpObserver *observer);
   void              OnSendNotifyObservers(CHttpRequest *request);
   void              OnRecvNotifyObservers(CHttpResponse *response);
  };
//+------------------------------------------------------------------+
//| Add observer pointer to observer list                            |
//+------------------------------------------------------------------+
void CHttpClient::RegisterObserver(IHttpObserver *observer)
  {
   int size = ArraySize(m_observers);
   ArrayResize(m_observers,size+1);
   m_observers[size] = observer;
  }
//+------------------------------------------------------------------+
//| Remove observer pointer to observer list                         |
//+------------------------------------------------------------------+
void CHttpClient::UnregisterObserver(IHttpObserver *observer)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      if(GetPointer(m_observers[i]) == GetPointer(observer))
        {
         ArrayRemove(m_observers,i,1);
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//| Notifies observers that a request has been made                  |
//+------------------------------------------------------------------+
void CHttpClient::OnSendNotifyObservers(CHttpRequest *request)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      m_observers[i].OnSend(request);
     }
  }
//+------------------------------------------------------------------+
//| Notifies observers that a response has been received             |
//+------------------------------------------------------------------+
void CHttpClient::OnRecvNotifyObservers(CHttpResponse *response)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      m_observers[i].OnRecv(response);
     }
  }
//+------------------------------------------------------------------+
Schließlich rufen wir die Benachrichtigungsfunktion innerhalb der Funktion auf, die die Anfrage sendet, damit die Observer tatsächlich informiert werden:
//+------------------------------------------------------------------+
//| class : CHttpClient                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpClient                                        |
//| Heritage    : No heritage                                        |
//| Description : Class responsible for linking the request and      |
//|               response object with the transport layer.          |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpClient
  {
private:
   
   IHttpObserver     *m_observers[];                     // Array of observers
   
public:
   //--- Basis function
   bool              Send(CHttpRequest &request, CHttpResponse &response);
  };
//+------------------------------------------------------------------+
//| Basis function                                                   |
//+------------------------------------------------------------------+
bool CHttpClient::Send(CHttpRequest &request, CHttpResponse &response)
  {
   //--- Request
   uchar body_request[];
   request.Body().GetAsBinary(body_request);
   
   //--- Response
   uchar body_response[];
   string headers_response;
   
   //--- Notify observer of request
   this.OnSendNotifyObservers(GetPointer(request));
   
   //--- Send
   ulong start = GetMicrosecondCount();
   int status_code = m_transport.Request(request.Method().GetMethodDescription(),request.Url().FullUrl(),request.Header().Serialize(),request.Timeout(),body_request,body_response,headers_response);
   ulong end = GetMicrosecondCount();
   
   //--- Notify observer of response
   this.OnRecvNotifyObservers(GetPointer(response));
   
   //--- Add data in Response
   response.Clear();
   response.Duration((end-start)/1000);
   response.StatusCode() = status_code;
   response.Body().AddBinary(body_response);
   response.Header().Parse(headers_response);
   
   //--- Return is success
   return(response.StatusCode().IsSuccess());
  }
//+------------------------------------------------------------------+

Die Arbeit ist getan, und es ist einfacher als es scheint, wenn wir den Code schreiben, nicht wahr? Damit haben wir die gesamte Implementierung innerhalb der Bibliothek abgeschlossen. Wir müssen die Observer erstellen, d. h. die konkreten Klassen, die den IHttpObserver implementieren. Wir werden dies im nächsten Abschnitt, den Tests, tun.


Tests

Jetzt müssen wir nur noch die Bibliothek nutzen. Dazu erstelle ich eine neue Testdatei namens TestObserver.mq5 im Pfad <Experts/Connexus/Tests/TestObserver.mq5>. Wir importieren die Bibliothek und belassen nur OnInit().

//+------------------------------------------------------------------+
//|                                                 TestObserver.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include <Connexus/Core/HttpClient.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Direkt unter dem Einbinden werde ich eine konkrete Klasse erstellen, die die IHttpClient-Schnittstelle implementiert und die Daten, die über die Bibliothek gesendet und empfangen wurden, auf der Terminal-Konsole ausgibt:

//+------------------------------------------------------------------+
//|                                                 TestObserver.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include <Connexus/Core/HttpClient.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CMyObserver : public IHttpObserver
  {
public:
                     CMyObserver(void);
                    ~CMyObserver(void);
   
   void              OnSend(CHttpRequest *request);
   void              OnRecv(CHttpResponse *response);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::CMyObserver(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::~CMyObserver(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::OnSend(CHttpRequest *request)
  {
   Print("-----------------------------------------------");
   Print("Order sent notification received in CMyObserver");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::OnRecv(CHttpResponse *response)
  {
   Print("-----------------------------------------------");
   Print("Response notification received in CMyObserver");
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Create objects
   CHttpRequest request;
   CHttpResponse response;
   CHttpClient client;
   CMyObserver *my_observer = new CMyObserver();
   
   //--- Configure request
   request.Method() = HTTP_METHOD_GET;
   request.Url().Parse("https://httpbin.org/get");
   
   //--- Adding observer
   client.RegisterObserver(my_observer);
   
   //--- Send
   client.Send(request,response);
   
   //--- Delete pointer
   delete my_observer;
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Wenn wir dies auf das Diagramm anwenden, erhalten wir dieses Ergebnis:

Dies zeigt, dass die Funktionen der Klasse CMyObserver innerhalb der Bibliothek aufgerufen wurden, dies ändert alles, wir vervollständigen die Bibliothek mit dem erreichten Hauptziel, dass sie flexibel ist.

Der interessanteste Teil ist, dass wir mehrere Observer in verschiedenen Teilen des Codes haben können, wenn wir einen EA haben, der in mehrere Klassen unterteilt ist, können wir jede dieser Klassen eine Implementierung von IHttpObserver erstellen lassen und das war's! Wir werden benachrichtigt, sobald die Anfrage abgeschickt oder eine Antwort eingegangen ist.

Mit diesen Ergänzungen der Observer ergibt sich nun das aktuelle Diagramm der Bibliothek:

Diagramm 4



Umstrukturierung der Verzeichnisse

Derzeit sieht das Verzeichnis aller Bibliotheksdateien wie folgt aus:

|--- Connexus
|--- |--- Constants
|--- |--- |--- HttpMethod.mqh
|--- |--- |--- HttpStatusCode.mqh
|--- |--- Core
|--- |--- |--- HttpClient.mqh
|--- |--- |--- HttpRequest.mqh
|--- |--- |--- HttpResponse.mqh
|--- |--- |--- HttpTransport.mqh
|--- |--- Data
|--- |--- |--- Json.mqh
|--- |--- Header
|--- |--- |--- HttpBody.mqh
|--- |--- |--- HttpHeader.mqh
|--- |--- Interface
|--- |--- |--- IHttpObserver.mqh
|--- |--- |--- IHttpTransport.mqh
|--- |--- URL
|--- |--- |--- QueryParam.mqh
|--- |--- |--- URL.mqh

Wir nehmen zwei Anpassungen vor: Wir fügen die Dateien aus dem URL-Ordner in den Data-Ordner ein und benennen sie in Utils um, sodass beide Ordner, die Dateien mit ähnlichem Zweck enthalten, vereinfacht werden. Wir fügen auch den Ordner interfaces in den Ordner Core ein, da die Schnittstellen zum Kern der Bibliothek gehören. Am Ende sieht die Ordnerstruktur der Bibliothek wie folgt aus:

|--- Connexus
|--- |--- Constants
|--- |--- |--- HttpMethod.mqh
|--- |--- |--- HttpStatusCode.mqh
|--- |--- Core
|--- |--- |--- Interface
|--- |--- |--- |--- IHttpObserver.mqh
|--- |--- |--- |--- IHttpTransport.mqh
|--- |--- |--- HttpClient.mqh
|--- |--- |--- HttpRequest.mqh
|--- |--- |--- HttpResponse.mqh
|--- |--- |--- HttpTransport.mqh
|--- |--- Utils
|--- |--- |--- Json.mqh
|--- |--- |--- QueryParam.mqh
|--- |--- |--- URL.mqh
|--- |--- Header
|--- |--- |--- HttpBody.mqh
|--- |--- |--- HttpHeader.mqh


Umbenennung einiger Methoden

Wenn es darum geht, einen Code zu schreiben, der leicht zu verstehen, zu pflegen und zu verbessern ist, macht die Übernahme eines standardisierten Stils der Codierung den entscheidenden Unterschied. Ein einheitlicher Standard beim der Erstellung von Bibliotheken geht weit über die reine Ästhetik hinaus. Er schafft Klarheit, Vorhersehbarkeit und eine solide Grundlage für alle, die den Code heute oder in Zukunft verwenden oder mit ihm zusammenarbeiten. Dieser einheitliche Stil ist nicht nur eine Frage der Organisation, sondern eine Investition in die Qualität, die Robustheit und das gesunde Wachstum der Bibliothek im Laufe der Zeit. Und auch wenn es zunächst nur wie ein Detail aussieht, ist es am Ende der rote Faden, der den Code sicher und entwicklungsfähig macht.


Warum ist ein Standardstil unerlässlich?

  • Konsistenz und Lesbarkeit: Gut strukturierter Code mit einem einheitlichen Stil macht das Lesen flüssiger und verständlicher für jeden Entwickler. Mit einem klar definierten Standard müssen die Mitarbeiter keine Zeit mit der Entschlüsselung von Abweichungen oder Inkonsistenzen verschwenden, sondern können sich auf das konzentrieren, was wirklich wichtig ist: die Logik des Codes. Aspekte wie Abstände, Einrückungen und Benennungen sind Details, die zusammen ein intuitiveres und unkompliziertes Erlebnis schaffen. Alles ist aufeinander abgestimmt, was die Navigation erleichtert und die durch unterschiedliche und unzusammenhängende Stile verursachten Stolpersteine reduziert.
  • Leichte Wartung und Erweiterung: Bibliotheken bleiben selten konstant; neue Herausforderungen entstehen, und es ist ganz natürlich, dass sie angepasst werden müssen. Mit einem standardisierten Kodierungsstil wird die Wartung einfacher und weniger fehleranfällig. Das spart nicht nur Zeit bei der Fehlerbehebung, sondern erleichtert auch neuen Entwicklern das schnelle Verständnis des Codes und die effiziente Zusammenarbeit. Und natürlich ist eine Bibliothek, die von Anfang an gut strukturiert ist, viel leichter zu skalieren, da jede neue Funktion eine vorhersehbare und organisierte Umgebung vorfindet, in die sie integriert werden kann.

Dennoch sollten wir einige Standards im Code festlegen, vor allem bei der Benennung von Funktionen. Einige andere Normen wurden bereits angewandt, wie z. B.:

  • Alle Klassen verwenden das Präfix „C“ vor dem Namen.
  • Alle Schnittstellen verwenden das Präfix „I“ vor dem Namen.
  • Private Variablen verwenden das Präfix „m_“.
  • Methoden müssen immer mit Großbuchstaben beginnen
  • ENUM-Werte müssen in Großbuchstaben geschrieben werden

Alle diese Standards wurden bereits während der Entwicklung der Bibliothek angewandt, aber wir werden weitere hinzufügen, wie zum Beispiel:

  • Methoden zum Setzen/Lesen von Attributen einer Klasse müssen das Präfix Get oder Set verwenden.
  • Methoden, die die Größe des Arrays zurückgeben, müssen den Namen „Size“ tragen.
  • Methoden, die die Klassenattribute zurücksetzen, müssen den Namen „Clear“ tragen.
  • Methoden zur Konvertierung in einen String müssen „ToString“ heißen.
  • Vermeiden Sie Namensredundanz in Kontextklassen. Die Klasse CQueryParam hat zum Beispiel die Methode AddParam(), die keinen Sinn macht. Ideal wäre nur Add(), da wir uns bereits im Kontext der Parameter befinden.

Ich werde also nicht alle Methoden in der Bibliothek auflisten, die ich umbenennen werde, und ich werde auch nicht den Quellcode zur Verfügung stellen, da ich nicht die Implementierung der Methode ändere, sondern nur den Namen. Aber mit den Änderungen, werde ich ein Diagramm unten, dass alle Klassen in der Bibliothek mit den Namen der aktualisierten Methoden und ihre Beziehungen zeigt verlassen.

Diagramm 5


Schlussfolgerung

Mit diesem letzten Artikel schließen wir die Serie über die Erstellung der Connexus-Bibliothek ab, die zur Vereinfachung der HTTP-Kommunikation entwickelt wurde. Es war eine ganz schöne Reise: Wir gingen die Grundlagen durch, vertieften uns in fortgeschrittenere Design- und Code-Verfeinerungstechniken und erforschten das Observer-Muster, um Connexus die Reaktivität zu verleihen, die für dynamische und flexible Systeme unerlässlich ist. Wir haben dieses Muster in die Praxis umgesetzt, sodass verschiedene Teile der Anwendung automatisch auf Änderungen reagieren können, wodurch eine robuste und anpassungsfähige Struktur entsteht.

Zusätzlich zum Observer haben wir die gesamte Datei- und Ordnerarchitektur organisiert und den Code modular und intuitiv gestaltet. Wir haben auch Methoden umbenannt, um die Übersichtlichkeit zu erhöhen und die Verwendung der Bibliothek direkter und konsistenter zu machen - Details, die den Unterschied ausmachen, wenn es um sauberen Code und langfristige Wartung geht.

Connexus wurde entwickelt, um die HTTP-Integration so einfach und intuitiv wie möglich zu gestalten. Wir hoffen, dass wir in dieser Serie jeden wichtigen Punkt des Prozesses aufzeigen konnten und die Design-Entscheidungen, die dies möglich gemacht haben. Mit diesem letzten Artikel hoffe ich, dass Connexus nicht nur Ihre HTTP-Integrationen vereinfacht, sondern auch zu kontinuierlichen Verbesserungen anregt. Danke, dass Sie sich mit mir auf diese Reise begeben haben. Möge Connexus ein Verbündeter bei Ihren Projekten sein!

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16377

MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 49): Verstärkungslernen mit Optimierung der proximalen Politik MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 49): Verstärkungslernen mit Optimierung der proximalen Politik
Die „Proximal Policy Optimization“ ist ein weiterer Algorithmus des Reinforcement Learning, der die „Policy“, oft in Form eines Netzwerks, in sehr kleinen inkrementellen Schritten aktualisiert, um die Stabilität des Modells zu gewährleisten. Wir untersuchen, wie dies in einem von einem Assistenten zusammengestellten Expert Advisor von Nutzen sein könnte, wie wir es in früheren Artikeln getan haben.
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 2):  Ein Script für analytische Kommentare Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 2): Ein Script für analytische Kommentare
Im Einklang mit unserer Vision, das Preisgeschehen zu vereinfachen, freuen wir uns, Ihnen ein weiteres Tool vorstellen zu können, das Ihre Marktanalyse erheblich verbessern und Ihnen helfen kann, gut informierte Entscheidungen zu treffen. Dieses Tool zeigt wichtige technische Indikatoren an, wie z. B. die Kurse des Vortags, wichtige Unterstützungs- und Widerstandsniveaus und das Handelsvolumen, und generiert automatisch visuelle Hinweise auf dem Chart.
Automatisieren von Handelsstrategien in MQL5 (Teil 1): Das Profitunity System (Trading Chaos von Bill Williams) Automatisieren von Handelsstrategien in MQL5 (Teil 1): Das Profitunity System (Trading Chaos von Bill Williams)
In diesem Artikel untersuchen wir das Profitunity System von Bill Williams, indem wir seine Kernkomponenten und seinen einzigartigen Ansatz für den Handel im Marktchaos aufschlüsseln. Wir führen die Leser durch die Implementierung des Systems in MQL5 und konzentrieren uns dabei auf die Automatisierung von Schlüsselindikatoren und Einstiegs-/Ausstiegssignalen. Schließlich testen und optimieren wir die Strategie und geben Einblicke in ihre Leistung in verschiedenen Marktszenarien.
Datenwissenschaft und ML (Teil 32): KI-Modelle auf dem neuesten Stand halten, Online-Lernen Datenwissenschaft und ML (Teil 32): KI-Modelle auf dem neuesten Stand halten, Online-Lernen
In der sich ständig verändernden Welt des Handels ist die Anpassung an Marktveränderungen nicht nur eine Option, sondern eine Notwendigkeit. Täglich entstehen neue Muster und Trends, die es selbst den fortschrittlichsten Modellen für maschinelles Lernen erschweren, angesichts der sich verändernden Bedingungen effektiv zu bleiben. In diesem Artikel erfahren Sie, wie Sie Ihre Modelle durch ein automatisches Neu-Training relevant halten und auf neue Marktdaten reagieren können.