English 日本語
preview
Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 1): Implementierung der JSON-Verarbeitung für KI-APIs

Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 1): Implementierung der JSON-Verarbeitung für KI-APIs

MetaTrader 5Handelssysteme |
23 2
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In dieser Artikelserie stellen wir die Integration von Künstliche Intelligenz (KI) in Handelssysteme unter Verwendung von MetaQuotes Language 5 (MQL5) vor. In diesem Teil entwickeln wir zunächst ein robustes System zum Parsen von JavaScript Object Notation (JSON), um den Datenaustausch für Interaktionen mit Application Programming Interface (API) für KI wie ChatGPT zu ermöglichen. Wir konzentrieren uns auf die Schaffung einer Grundlage für die Verarbeitung von JSON-Strukturen, um eine nahtlose Kommunikation mit KI-Diensten für zukünftige Handelsanwendungen zu ermöglichen. Wir werden die folgenden Themen behandeln:

  1. JSON und seine Rolle bei der KI-Integration verstehen
  2. Implementation in MQL5
  3. Testen des JSON-Parsers
  4. Schlussfolgerung

Am Ende werden Sie eine solide Grundlage für den Umgang mit JSON-Daten haben und die Voraussetzungen für KI-gesteuerte Handelssysteme schaffen – legen wir los!


JSON und seine Rolle bei der KI-Integration verstehen

JSON (JavaScript Object Notation) ist ein leichtgewichtiges, textbasiertes Datenaustauschformat, das aufgrund seiner Einfachheit, Lesbarkeit und Kompatibilität mit anderen Programmiersprachen häufig zur Strukturierung und Übertragung von Daten zwischen Systemen, insbesondere in webbasierten APIs, verwendet wird. Im Kontext von KI-gestützten Handelssystemen, wie wir sie aufbauen wollen, dient es als Standardformat für den Datenaustausch mit KI-APIs, wie ChatGPT von OpenAI, und ermöglicht es MQL5-Anwendungen, handelsbezogene Aufforderungen zu senden und strukturierte Antworten für die Entscheidungsfindung zu erhalten. Unser Ansatz in diesem Artikel konzentriert sich auf die Entwicklung eines Systems zum Parsen von JSON, um diese API-Interaktionen zu verarbeiten und die Grundlage für die Integration von KI-gesteuerten Erkenntnissen in automatisierte Handelsstrategien zu schaffen.

Was ist JSON und warum ist es wichtig?

JSON stellt Daten in Form von Schlüssel-Wert-Paaren, Arrays und verschachtelten Objekten dar und eignet sich daher ideal für die Kodierung komplexer Informationen wie Marktdaten, Handelssignale oder KI-Antworten in einem Format, das sowohl für Menschen lesbar als auch maschinell ‚geparst‘ werden können. Ein JSON-Objekt könnte zum Beispiel so aussehen:

{
  "model": "gpt-3.5-turbo",
  "messages": [
    {"role": "user", "content": "Analyze EURUSD trend"},
    {"role": "assistant", "content": "EURUSD shows a bullish trend"}
  ],
  "max_tokens": 500
}

Diese Struktur umfasst Strings, Zahlen, Arrays und verschachtelte Objekte, die ein MQL5 Expert Advisor (EA) analysieren muss, um relevante Informationen zu extrahieren, wie z. B. die Antwort der KI auf eine Handelsanfrage. Die Rolle von JSON bei der KI-Integration ist hier von entscheidender Bedeutung, da APIs Antworten im JSON-Format zurücksenden, sodass das Programm die Eingaben mit der Serialisierung konvertieren (Daten in JSON umwandeln) und die Ausgaben deserialisieren (JSON in verwertbare Daten parsen) muss, um dynamische Handelsentscheidungen zu ermöglichen. Wenn sich das für Sie wie ein Fachjargon anhört, finden Sie hier eine kurze Visualisierung dessen, was Daten-Serialisierung und -Deserialisierung bedeutet.

SERIALISIERUNG UND DESERIALISIERUNG

Vorgehensplan für die Umsetzung

Unser Implementierungsplan sieht die Erstellung einer Klasse zur Verarbeitung von JSON vor, die die folgenden Funktionen unterstützt:

  • Darstellung der Daten: Eine Klasse zum Speichern von JSON-Werten mit Attributen für Typ, Schlüssel und Wert (z. B. als String, Zahl oder Boolean) und einem Array für untergeordnete Elemente zur Handhabung verschachtelter Strukturen.
  • Logik des Parsens: Die Methoden zur Deserializierung von JSON-Strings in Objekten, Verarbeitung von Zeichen zur Identifizierung von Strukturen wie Objekten, Arrays und primitiven Typen bei gleichzeitiger Behandlung von Leerzeichen und Escape-Sequenzen.
  • Logik der Serialisierung: Methoden zur Rückkonvertierung interner Daten in JSON-Zeichenfolgen, die eine ordnungsgemäße Formatierung für API-Anfragen gewährleisten, einschließlich der Unterdrückung von Sonderzeichen.
  • Fehlerbehandlung: Robuste Prüfungen auf ungültiges JSON, Typabweichungen und auf Zugriffe außerhalb des zulässigen Bereichs zur Vermeidung von Abstürzen während der API-Kommunikation.
  • Vorbereitung der Nutzeroberfläche: Schaffung der Voraussetzungen für eine künftige Integration mit einer Nutzeroberfläche zur Eingabe von Aufforderungen und zur Anzeige von KI-Antworten, die auf geparsten JSON-Daten beruhen wird.

Wir werden dieses Framework testen, um sicherzustellen, dass es typische KI-API-Antworten, z. B. von OpenAI, parsen und handelsbezogene Aufforderungen genau serialisieren kann (siehe unten).

MQL5 KI ANTWORTEN

Durch die Beherrschung des JSON-Parsing in diesem Artikel stellen wir sicher, dass künftige KI-gesteuerte Programme komplexe Datenstrukturen verarbeiten können, und ebnen so den Weg für anspruchsvolle Handelsstrategien, die Preisaktionen, Chartmuster und KI-generierte Erkenntnisse kombinieren. Kommen wir nun zur Umsetzung!


Implementation in MQL5

Um die Integration zu implementieren, werden wir zunächst eine umfassende Parsing-Klasse erstellen, die wir für unsere ersten Prompts und zukünftige Anwendungen verwenden werden. Wie wir das erreichen, erfahren Sie hier.

//+------------------------------------------------------------------+
//|                                            a. JSON Code File.mq5 |
//|                           Copyright 2025, Allan Munene Mutiiria. |
//|                                   https://t.me/Forex_Algo_Trader |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Allan Munene Mutiiria."
#property link "https://t.me/Forex_Algo_Trader"
#property version "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){return(INIT_SUCCEEDED);}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){}
//+------------------------------------------------------------------+
//| JSON (JavaScript Object Notation)                                |
//+------------------------------------------------------------------+
#define DEBUG_PRINT false
//+------------------------------------------------------------------+
//| Enumeration of JSON value types                                  |
//+------------------------------------------------------------------+
enum JsonValueType {JsonUndefined,JsonNull,JsonBoolean,JsonInteger,JsonDouble,JsonString,JsonArray,JsonObject};
//+------------------------------------------------------------------+
//| Class representing a JSON value                                  |
//+------------------------------------------------------------------+
class JsonValue{
   public:
      // CONSTRUCTOR
      virtual void Reset(){
         m_parent=NULL;                                         //--- Set parent pointer to NULL
         m_key="";                                              //--- Clear the key string
         m_type=JsonUndefined;                                  //--- Set type to undefined
         m_booleanValue=false;                                  //--- Set boolean value to false
         m_integerValue=0;                                      //--- Set integer value to zero
         m_doubleValue=0;                                       //--- Set double value to zero
         m_stringValue="";                                      //--- Clear the string value
         ArrayResize(m_children,0);                             //--- Resize children array to zero
      }
      virtual bool CopyFrom(const JsonValue &source){
         m_key=source.m_key;                                    //--- Copy the key from source
         CopyDataFrom(source);                                  //--- Copy data from source
         return true;                                           //--- Return success
      }
      virtual void CopyDataFrom(const JsonValue &source){
         m_type=source.m_type;                                  //--- Copy the type from source
         m_booleanValue=source.m_booleanValue;                  //--- Copy the boolean value from source
         m_integerValue=source.m_integerValue;                  //--- Copy the integer value from source
         m_doubleValue=source.m_doubleValue;                    //--- Copy the double value from source
         m_stringValue=source.m_stringValue;                    //--- Copy the string value from source
         CopyChildrenFrom(source);                              //--- Copy children from source
      }
      virtual void CopyChildrenFrom(const JsonValue &source){
         int numChildren=ArrayResize(m_children,ArraySize(source.m_children)); //--- Resize children array to match source size
         for(int index=0; index<numChildren; index++){          //--- Loop through each child
            m_children[index]=source.m_children[index];         //--- Copy child from source
            m_children[index].m_parent=GetPointer(this);        //--- Set parent of child to current object
         }
      }
   public:
      JsonValue m_children[];                                   //--- Array to hold child JSON values
      string m_key;                                             //--- Key for this JSON value
      string m_temporaryKey;                                    //--- Temporary key used during parsing
      JsonValue *m_parent;                                      //--- Pointer to parent JSON value
      JsonValueType m_type;                                     //--- Type of this JSON value
      bool m_booleanValue;                                      //--- Boolean value storage
      long m_integerValue;                                      //--- Integer value storage
      double m_doubleValue;                                     //--- Double value storage
      string m_stringValue;                                     //--- String value storage
      static int encodingCodePage;                              //--- Static code page for encoding
   public:
      JsonValue(){
         Reset();                                               //--- Call reset to initialize
      }
      JsonValue(JsonValue *parent,JsonValueType type){
         Reset();                                               //--- Call reset to initialize
         m_type=type;                                           //--- Set the type
         m_parent=parent;                                       //--- Set the parent
      }
      JsonValue(JsonValueType type,string value){
         Reset();                                               //--- Call reset to initialize
         SetFromString(type,value);                             //--- Set value from string based on type
      }
      JsonValue(const int integerValue){
         Reset();                                               //--- Call reset to initialize
         m_type=JsonInteger;                                    //--- Set type to integer
         m_integerValue=integerValue;                           //--- Set integer value
         m_doubleValue=(double)m_integerValue;                  //--- Convert to double
         m_stringValue=IntegerToString(m_integerValue);         //--- Convert to string
         m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
      }
      JsonValue(const long longValue){
         Reset();                                               //--- Call reset to initialize
         m_type=JsonInteger;                                    //--- Set type to integer
         m_integerValue=longValue;                              //--- Set integer value
         m_doubleValue=(double)m_integerValue;                  //--- Convert to double
         m_stringValue=IntegerToString(m_integerValue);         //--- Convert to string
         m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
      }
      JsonValue(const double doubleValue){
         Reset();                                               //--- Call reset to initialize
         m_type=JsonDouble;                                     //--- Set type to double
         m_doubleValue=doubleValue;                             //--- Set double value
         m_integerValue=(long)m_doubleValue;                    //--- Convert to integer
         m_stringValue=DoubleToString(m_doubleValue);           //--- Convert to string
         m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
      }
      JsonValue(const bool booleanValue){
         Reset();                                               //--- Call reset to initialize
         m_type=JsonBoolean;                                    //--- Set type to boolean
         m_booleanValue=booleanValue;                           //--- Set boolean value
         m_integerValue=m_booleanValue;                         //--- Convert to integer
         m_doubleValue=m_booleanValue;                          //--- Convert to double
         m_stringValue=IntegerToString(m_integerValue);         //--- Convert to string
      }
      JsonValue(const JsonValue &other){
         Reset();                                               //--- Call reset to initialize
         CopyFrom(other);                                       //--- Copy from other object
      }
      // DECONSTRUCTOR
      ~JsonValue(){
         Reset();                                               //--- Call reset to clean up
      }
}

Wir beginnen mit der Implementierung des Systems zur Analyse von JSON und konzentrieren uns dabei auf die grundlegende Klasse „JsonValue“ zur Verarbeitung von JSON-Daten für die KI-API-Integration. Zunächst definieren wir das Makro „DEBUG_PRINT“, das auf false gesetzt wird, um die Debugging-Ausgabe zu steuern und eine minimale Protokollierung während der Produktion zu gewährleisten. Dann wird eine Enumeration „JsonValueType“ mit Werten (JsonUndefined, JsonNull, JsonBoolean, JsonInteger, JsonDouble, JsonString, JsonArray, JsonObject) eingeführt, um die Datentypen von JSON zu kategorisieren, sodass die Klasse mit verschiedenen Strukturen umgehen kann, wie sie von APIs zurückgegeben werden.

Als Nächstes implementieren wir die Klasse „JsonValue“ mit öffentlichen Mitgliedern: einem Array „m_children“ für verschachtelte JSON-Elemente, den Strings „m_key“ und „m_temporaryKey“ für die Speicherung der Schlüssel während des Parsens, einem Zeiger „m_parent“ für hierarchische Beziehungen, einer „JsonValueType“-Variablen „m_type“ für den Datentyp und die Variablen „m_booleanValue“, „m_integerValue“, „m_doubleValue“ und „m_stringValue“ für die Speicherung der jeweiligen Daten, sowie eine statische „encodingCodePage“ für die Zeichenkodierung. Wir stellen mehrere Konstruktoren zur Initialisierung von „JsonValue“-Objekten zur Verfügung: einen Standardkonstruktor, der „Reset“ aufruft, einen mit Parent und Typ, einen mit Typ und String-Wert und weitere für Integer-, Long-, Double-, Boolean- und Copy-Konstruktionen, die Flexibilität bei der Erstellung von JSON-Elementen gewährleisten.

Die Methode „Reset“ setzt alle Elemente auf ihre Standardwerte zurück (z. B. null-Elternelement, leere Zeichenfolgen, undefinierter Typ, auf Null gesetzte Werte und leeres abgeleitetes Array), während die Methoden „CopyFrom“, „CopyDataFrom“ und „CopyChildrenFrom“ das tiefe Kopieren von JSON-Strukturen einschließlich untergeordneter Elemente mit korrekter Neuzuweisung der übergeordneten Elemente ermöglichen. Mit dieser grundlegenden Implementierung wird die Struktur für das Parsen und Verarbeiten von JSON-Daten geschaffen, die für künftige KI-API-Interaktionen entscheidend ist. Wir können dann fortfahren, eine rein virtuelle Funktion der Klasse zu implementieren, der Vollständigkeit halber immer noch unter einem öffentlichen Zugriffsspezifizierer. Wir verwenden Virtual, um das System flexibel und polymorph zu gestalten.

public:
   virtual bool IsNumericValue(){
      return (m_type==JsonDouble || m_type==JsonInteger);    //--- Check if type is double or integer
   }
   virtual JsonValue *FindChildByKey(string key){
      for(int index=ArraySize(m_children)-1; index>=0; --index){ //--- Loop backwards through children
         if(m_children[index].m_key==key){                   //--- Check if key matches
            return GetPointer(m_children[index]);            //--- Return pointer to matching child
         }
      }
      return NULL;                                           //--- Return NULL if no match
   }
   virtual JsonValue *HasChildWithKey(string key,JsonValueType type=JsonUndefined);
   virtual JsonValue *operator[](string key);
   virtual JsonValue *operator[](int index);
   void operator=(const JsonValue &value){
      CopyFrom(value);                                       //--- Copy from value
   }
   void operator=(const int integerValue){
      m_type=JsonInteger;                                    //--- Set type to integer
      m_integerValue=integerValue;                           //--- Set integer value
      m_doubleValue=(double)m_integerValue;                  //--- Convert to double
      m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
   }
   void operator=(const long longValue){
      m_type=JsonInteger;                                    //--- Set type to integer
      m_integerValue=longValue;                              //--- Set integer value
      m_doubleValue=(double)m_integerValue;                  //--- Convert to double
      m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
   }
   void operator=(const double doubleValue){
      m_type=JsonDouble;                                     //--- Set type to double
      m_doubleValue=doubleValue;                             //--- Set double value
      m_integerValue=(long)m_doubleValue;                    //--- Convert to integer
      m_booleanValue=m_integerValue!=0;                      //--- Set boolean based on integer
   }
   void operator=(const bool booleanValue){
      m_type=JsonBoolean;                                    //--- Set type to boolean
      m_booleanValue=booleanValue;                           //--- Set boolean value
      m_integerValue=(long)m_booleanValue;                   //--- Convert to integer
      m_doubleValue=(double)m_booleanValue;                  //--- Convert to double
   }
   void operator=(string stringValue){
      m_type=(stringValue!=NULL)?JsonString:JsonNull;        //--- Set type to string or null
      m_stringValue=stringValue;                             //--- Set string value
      m_integerValue=StringToInteger(m_stringValue);         //--- Convert to integer
      m_doubleValue=StringToDouble(m_stringValue);           //--- Convert to double
      m_booleanValue=stringValue!=NULL;                      //--- Set boolean based on string presence
   }

   bool operator==(const int integerValue){return m_integerValue==integerValue;}  //--- Compare integer value
   bool operator==(const long longValue){return m_integerValue==longValue;}       //--- Compare long value
   bool operator==(const double doubleValue){return m_doubleValue==doubleValue;}  //--- Compare double value
   bool operator==(const bool booleanValue){return m_booleanValue==booleanValue;} //--- Compare boolean value
   bool operator==(string stringValue){return m_stringValue==stringValue;}        //--- Compare string value
  
   bool operator!=(const int integerValue){return m_integerValue!=integerValue;}  //--- Check inequality for integer
   bool operator!=(const long longValue){return m_integerValue!=longValue;}       //--- Check inequality for long
   bool operator!=(const double doubleValue){return m_doubleValue!=doubleValue;}  //--- Check inequality for double
   bool operator!=(const bool booleanValue){return m_booleanValue!=booleanValue;} //--- Check inequality for boolean
   bool operator!=(string stringValue){return m_stringValue!=stringValue;}        //--- Check inequality for string

   long ToInteger() const{return m_integerValue;}            //--- Return integer value
   double ToDouble() const{return m_doubleValue;}            //--- Return double value
   bool ToBoolean() const{return m_booleanValue;}            //--- Return boolean value
   string ToString(){return m_stringValue;}                  //--- Return string value

   virtual void SetFromString(JsonValueType type,string stringValue){
      m_type=type;                                           //--- Set the type
      switch(m_type){                                        //--- Handle based on type
      case JsonBoolean:
         m_booleanValue=(StringToInteger(stringValue)!=0);   //--- Convert string to boolean
         m_integerValue=(long)m_booleanValue;                //--- Set integer from boolean
         m_doubleValue=(double)m_booleanValue;               //--- Set double from boolean
         m_stringValue=stringValue;                          //--- Set string value
         break;                                              //--- Exit case
      case JsonInteger:
         m_integerValue=StringToInteger(stringValue);        //--- Convert string to integer
         m_doubleValue=(double)m_integerValue;               //--- Set double from integer
         m_stringValue=stringValue;                          //--- Set string value
         m_booleanValue=m_integerValue!=0;                   //--- Set boolean from integer
         break;                                              //--- Exit case
      case JsonDouble:
         m_doubleValue=StringToDouble(stringValue);          //--- Convert string to double
         m_integerValue=(long)m_doubleValue;                 //--- Set integer from double
         m_stringValue=stringValue;                          //--- Set string value
         m_booleanValue=m_integerValue!=0;                   //--- Set boolean from integer
         break;                                              //--- Exit case
      case JsonString:
         m_stringValue=UnescapeString(stringValue);          //--- Unescape the string
         m_type=(m_stringValue!=NULL)?JsonString:JsonNull;   //--- Set type based on string presence
         m_integerValue=StringToInteger(m_stringValue);      //--- Convert to integer
         m_doubleValue=StringToDouble(m_stringValue);        //--- Convert to double
         m_booleanValue=m_stringValue!=NULL;                 //--- Set boolean based on string
         break;                                              //--- Exit case
      }
   }
   virtual string GetSubstringFromArray(char &jsonCharacterArray[],int startPosition,int substringLength){
      #ifdef __MQL4__
            if(substringLength<=0) return "";                //--- Return empty if length invalid in MQL4
      #endif
      char temporaryArray[];                                 //--- Declare temporary array
      ArrayCopy(temporaryArray,jsonCharacterArray,0,startPosition,substringLength); //--- Copy substring to temporary array
      return CharArrayToString(temporaryArray, 0, WHOLE_ARRAY, JsonValue::encodingCodePage); //--- Convert to string using code page
   }
   virtual void SetValue(const JsonValue &value){
      if(m_type==JsonUndefined) {m_type=JsonObject;}         //--- Set type to object if undefined
      CopyDataFrom(value);                                   //--- Copy data from value
   }
   virtual void SetArrayValues(const JsonValue &list[]);
   virtual JsonValue *AddChild(const JsonValue &item){
      if(m_type==JsonUndefined){m_type=JsonArray;}           //--- Set type to array if undefined
      return AddChildInternal(item);                         //--- Call internal add child
   }
   virtual JsonValue *AddChild(const int integerValue){
      JsonValue item(integerValue);                          //--- Create item from integer
      return AddChild(item);                                 //--- Add the item
   }
   virtual JsonValue *AddChild(const long longValue){
      JsonValue item(longValue);                             //--- Create item from long
      return AddChild(item);                                 //--- Add the item
   }
   virtual JsonValue *AddChild(const double doubleValue){
      JsonValue item(doubleValue);                           //--- Create item from double
      return AddChild(item);                                 //--- Add the item
   }
   virtual JsonValue *AddChild(const bool booleanValue){
      JsonValue item(booleanValue);                          //--- Create item from boolean
      return AddChild(item);                                 //--- Add the item
   }
   virtual JsonValue *AddChild(string stringValue){
      JsonValue item(JsonString,stringValue);                //--- Create item from string
      return AddChild(item);                                 //--- Add the item
   }
   virtual JsonValue *AddChildInternal(const JsonValue &item){
      int currentSize=ArraySize(m_children);                 //--- Get current children size
      ArrayResize(m_children,currentSize+1);                 //--- Resize array to add one more
      m_children[currentSize]=item;                          //--- Add the item
      m_children[currentSize].m_parent=GetPointer(this);     //--- Set parent to current object
      return GetPointer(m_children[currentSize]);            //--- Return pointer to added child
   }
   virtual JsonValue *CreateNewChild(){
      if(m_type==JsonUndefined) {m_type=JsonArray;}          //--- Set type to array if undefined
      return CreateNewChildInternal();                       //--- Call internal create new child
   }
   virtual JsonValue *CreateNewChildInternal(){
      int currentSize=ArraySize(m_children);                 //--- Get current children size
      ArrayResize(m_children,currentSize+1);                 //--- Resize array to add one more
      return GetPointer(m_children[currentSize]);            //--- Return pointer to new child
   }

   virtual string EscapeString(string value);
   virtual string UnescapeString(string value);

Noch unter dem öffentlichen Zugriffsspezifizierer implementieren wir die Methode „IsNumericValue“, die prüft, ob der JSON-Wert eine Zahl ist, indem sie true zurückgibt, wenn „m_type“ „JsonDouble“ oder „JsonInteger“ ist, was eine typspezifische Behandlung für numerische Daten ermöglicht. Dann entwickeln wir die Methode „FindChildByKey“, die rückwärts durch das Array „m_children“ iteriert, um ein Kind mit einem passenden Schlüssel zu finden, und einen Zeiger darauf oder NULL zurückgibt, wenn es nicht gefunden wird, was den Zugriff auf verschachtelte JSON-Objekte erleichtert.

Als Nächstes definieren wir überladene Zuweisungsoperatoren („operator=“) für die Typen „JsonValue“, Integer, Long, Double, Boolean und String und aktualisieren „m_type“ und die entsprechenden Wertfelder („m_integerValue“, „m_doubleValue“, „m_stringValue“, „m_booleanValue“), wobei die Typkonsistenz sichergestellt wird, z. B. durch die Umwandlung von Ganzzahlen in Doubles und Strings für eine einheitliche Speicherung. Wir implementieren auch Vergleichsoperatoren („operator==“ und „operator!=“) für Integer-, Long-, Double-, Boolean- und String-Typen, die einen direkten Wertevergleich mit den jeweiligen Feldern ermöglichen.

Zusätzlich gibt es die Konvertierungsmethoden „ToInteger“, „ToDouble“, „ToBoolean“ und „ToString“, um Werte in ihren jeweiligen Formaten abzurufen. Die Methode „SetFromString“ legt den JSON-Wert auf der Grundlage des angegebenen „JsonValueType“ fest und behandelt die Typen Boolean, Integer, Double und String, indem sie den Eingabestring konvertiert und die zugehörigen Felder aktualisiert, wobei String-Werte über „UnescapeString“ ‚unescaped‘ werden. Die Methode „GetSubstringFromArray“ extrahiert eine Teilzeichenkette aus einem Zeichenarray, indem sie einen bestimmten Teil kopiert und ihn mithilfe von „CharArrayToString“ mit der definierten „encodingCodePage“ in eine Zeichenkette umwandelt.

Schließlich implementieren wir Methoden zur Verwaltung von untergeordneten Elementen: „AddChild“ (für „JsonValue“, integer, long, double, boolean, string) fügt ein neues Kind zu „m_children“ hinzu, wobei das Elternteil und der Typ nach Bedarf festgelegt werden; „CreateNewChild“ und „CreateNewChildInternal“ erzeugen ein leeres Kind; und „SetValue“ kopiert Daten aus einem anderen „JsonValue“, wodurch sichergestellt wird, dass die Klasse JSON-Strukturen konstruieren, manipulieren und darauf zugreifen kann. Schließlich können wir die Klasse abschließen, indem wir Methoden zur Serialisierung, Deserialisierung und Kodierung von Zeichen aus Antworten und Aufforderungen aufnehmen.

public:
   virtual void SerializeToString(string &jsonString,bool includeKey=false,bool includeComma=false);
   virtual string SerializeToString(){
      string jsonString;                                     //--- Declare json string
      SerializeToString(jsonString);                         //--- Call serialize with default params
      return jsonString;                                     //--- Return the serialized string
   }
   virtual bool DeserializeFromArray(char &jsonCharacterArray[],int arrayLength,int &currentIndex);
   virtual bool ExtractStringFromArray(char &jsonCharacterArray[],int arrayLength,int &currentIndex);
   virtual bool DeserializeFromString(string jsonString,int encoding=CP_ACP){
      int currentIndex=0;                                    //--- Initialize current index
      Reset();                                               //--- Reset the object
      JsonValue::encodingCodePage=encoding;                  //--- Set encoding code page
      char characterArray[];                                 //--- Declare character array
      int arrayLength=StringToCharArray(jsonString,characterArray,0,WHOLE_ARRAY,JsonValue::encodingCodePage); //--- Convert string to char array
      return DeserializeFromArray(characterArray,arrayLength,currentIndex); //--- Call deserialize from array
   }
   virtual bool DeserializeFromArray(char &jsonCharacterArray[],int encoding=CP_ACP){
      int currentIndex=0;                                    //--- Initialize current index
      Reset();                                               //--- Reset the object
      JsonValue::encodingCodePage=encoding;                  //--- Set encoding code page
      return DeserializeFromArray(jsonCharacterArray,ArraySize(jsonCharacterArray),currentIndex); //--- Call deserialize with size
   }

Hier implementieren wir die Methode „SerializeToString“ mit Parametern für eine String-Referenz, „includeKey“ und „includeComma“, die die JSON-Struktur in einen String konvertiert; sie fügt ein Komma hinzu, wenn „includeComma“ wahr ist, fügt den Schlüssel hinzu, wenn „includeKey“ wahr ist, und behandelt verschiedene Typen („JsonNull“ als „null“, „JsonBoolean“ als „true“ oder „false“, „JsonInteger“ und „JsonDouble“ über Stringkonvertierung, „JsonString“ mit escapeten Werten, „JsonArray“ mit eingeklammerten Kindelementen und „JsonObject“ mit verschlüsselten Kindelementen), rekursive Serialisierung von Kindern für verschachtelte Strukturen. Eine Komfortüberladung von „SerializeToString“ erzeugt eine Zeichenkette, ruft die parametrisierte Version auf und gibt das Ergebnis zurück.

Als Nächstes implementieren wir „DeserializeFromString“, das eine JSON-Zeichenfolge und eine Kodierung (standardmäßig CP_ACP) annimmt, das Objekt zurücksetzt, „encodingCodePage“ festlegt, die Zeichenfolge mit StringToCharArray in ein Zeichenarray umwandelt und an „DeserializeFromArray“ delegiert. Die Überladung „DeserializeFromArray“ mit Encoding initialisiert den Index, setzt das Objekt zurück, setzt „encodingCodePage“ und ruft die Hauptmethode „DeserializeFromArray“ auf, die ein Zeichenarray parst, indem sie durch Zeichen iteriert, Leerzeichen behandelt, Arrays („[“ bis „]“), Objekte („{“ bis „}“), Boolesche Werte („true“ oder „false“), Null („null“), Zahlen (Erkennung von ganzen oder reellen Zahlen über gültige Zeichen) und Zeichenketten (mit Escape-Behandlung), Erstellung von untergeordneten Elementen nach Bedarf und Verwaltung der Hierarchie mit „m_parent“ und „m_temporaryKey“.

Schließlich analysiert „ExtractStringFromArray“ die Zeichenketten innerhalb des Arrays und behandelt dabei maskierte Zeichen (z. B. „\n“, „\t“, Unicode „\uXXXX“) bis zu einem schließenden Anführungszeichen, nur für den Fall, dass wir uns entscheiden, Unicode Zeichen wie Emojis zu verwenden, um eine genaue Zeichenextraktion sicherzustellen. So sehen sie aus.

UNICODE-MUSTER

Wir können diese Methoden nun so definieren, dass sie ihre beabsichtigte Aufgabe genau erfüllen.

int JsonValue::encodingCodePage=CP_ACP;                      //--- Initialize static code page
//+------------------------------------------------------------------+
//| Checks if child with specific key and optional type exists       |
//+------------------------------------------------------------------+
JsonValue *JsonValue::HasChildWithKey(string key,JsonValueType type){
   for(int index=0; index<ArraySize(m_children); index++) if(m_children[index].m_key==key){ //--- Loop through children
      if(type==JsonUndefined || type==m_children[index].m_type){ //--- Check type condition
         return GetPointer(m_children[index]);               //--- Return matching child
      }
      break;                                                 //--- Exit loop
   }
   return NULL;                                              //--- Return NULL if no match
}
//+------------------------------------------------------------------+
//| Accessor for object key, creates if not exists                   |
//+------------------------------------------------------------------+
JsonValue *JsonValue::operator[](string key){
   if(m_type==JsonUndefined){m_type=JsonObject;}             //--- Set type to object if undefined
   JsonValue *value=FindChildByKey(key);                     //--- Find child by key
   if(value){return value;}                                  //--- Return if found
   JsonValue newValue(GetPointer(this),JsonUndefined);       //--- Create new undefined value
   newValue.m_key=key;                                       //--- Set key for new value
   value=AddChild(newValue);                                 //--- Add new value as child
   return value;                                             //--- Return the new value
}
//+------------------------------------------------------------------+
//| Accessor for array index, expands if necessary                   |
//+------------------------------------------------------------------+
JsonValue *JsonValue::operator[](int index){
   if(m_type==JsonUndefined) m_type=JsonArray;               //--- Set type to array if undefined
   while(index>=ArraySize(m_children)){                      //--- Loop to expand array if needed
      JsonValue newElement(GetPointer(this),JsonUndefined);  //--- Create new undefined element
      if(CheckPointer(AddChild(newElement))==POINTER_INVALID){return NULL;} //--- Add and check pointer
   }
   return GetPointer(m_children[index]);                     //--- Return pointer to element at index
}
//+------------------------------------------------------------------+
//| Sets array values from list                                      |
//+------------------------------------------------------------------+
void JsonValue::SetArrayValues(const JsonValue &list[]){
   if(m_type==JsonUndefined){m_type=JsonArray;}              //--- Set type to array if undefined
   int numChildren=ArrayResize(m_children,ArraySize(list));  //--- Resize children to list size
   for(int index=0; index<numChildren; ++index){             //--- Loop through list
      m_children[index]=list[index];                         //--- Copy from list
      m_children[index].m_parent=GetPointer(this);           //--- Set parent to current
   }
}

Um die Methoden der Klasse außerhalb des Körpers zu definieren, verwenden wir den Operator zur Auflösung des Bereichs. Wir könnten sie auch intern definieren, aber so ist der Code modular. Wir initialisieren das statische Mitglied „encodingCodePage“ auf CP_ACP (Active Code Page), um die Standard-Zeichenkodierung für String-Konvertierungen festzulegen und die Kompatibilität mit JSON-Daten aus KI-APIs zu gewährleisten. Dann implementieren wir die Methode „HasChildWithKey“, die das Array „m_children“ vorwärts durchläuft, um ein Kind mit einem passenden Schlüssel und optional einem bestimmten „JsonValueType“ zu finden (Standardwert ist „JsonUndefined“, um den Typ zu ignorieren), wobei ein Zeiger auf das passende Kind zurückgegeben wird oder NULL, wenn es nicht gefunden wird, was die Effizienz gegenüber „FindChildByKey“ verbessert, indem frühzeitig abgebrochen wird und typspezifische Prüfungen möglich sind.

Als Nächstes entwickeln wir die überladene Methode „operator“, die „m_type“ auf „JsonObject“ setzt, wenn es nicht definiert ist, mit „FindChildByKey“ nach einem Kind mit dem angegebenen Schlüssel sucht und, wenn es nicht gefunden wird, ein neues „JsonValue“ mit dem Schlüssel erstellt und es über „AddChild“ zu „m_children“ hinzufügt, wobei ein Zeiger auf das vorhandene oder neue Kind zurückgegeben wird, um einen nahtlosen Objektzugriff zu ermöglichen. In ähnlicher Weise setzt die Methode „operator“ „m_type“ auf „JsonArray“, wenn sie undefiniert ist, erweitert das „m_children“-Array mit undefinierten Elementen, wenn der Index seine Größe mit „AddChild“ überschreitet, und gibt einen Zeiger auf das Element am angegebenen Index zurück, um einen sicheren Array-Zugriff zu gewährleisten.

Zuletzt implementieren wir „SetArrayValues“, das „m_type“ auf „JsonArray“ setzt, wenn es undefiniert ist, die Größe von „m_children“ an die Größe der Eingabeliste anpasst, jeden „JsonValue“ aus der Liste in „m_children“ kopiert und den Eltern von jedem Kind auf das aktuelle Objekt setzt, was eine Massenzuweisung von Array-Werten ermöglicht. Für die anderen Methoden werden wir ein ähnliches Format verwenden. Beginnen wir mit Methoden zur Serialisierung und Deserialisierung von Zeichenketten.

//+------------------------------------------------------------------+
//| Serializes the JSON value to string                              |
//+------------------------------------------------------------------+
void JsonValue::SerializeToString(string &jsonString,bool includeKey,bool includeComma){
   if(m_type==JsonUndefined){return;}                        //--- Return if undefined
   if(includeComma){jsonString+=",";}                        //--- Add comma if needed
   if(includeKey){jsonString+=StringFormat("\"%s\":", m_key);} //--- Add key if needed
   int numChildren=ArraySize(m_children);                    //--- Get number of children
   switch(m_type){                                           //--- Handle based on type
   case JsonNull:
      jsonString+="null";                                    //--- Append null
      break;                                                 //--- Exit case
   case JsonBoolean:
      jsonString+=(m_booleanValue?"true":"false");           //--- Append true or false
      break;                                                 //--- Exit case
   case JsonInteger:
      jsonString+=IntegerToString(m_integerValue);           //--- Append integer as string
      break;                                                 //--- Exit case
   case JsonDouble:
      jsonString+=DoubleToString(m_doubleValue);             //--- Append double as string
      break;                                                 //--- Exit case
   case JsonString:
   {
      string value=EscapeString(m_stringValue);              //--- Escape the string
      if(StringLen(value)>0){jsonString+=StringFormat("\"%s\"",value);} //--- Append escaped string if not empty
      else{jsonString+="null";}                              //--- Append null if empty
   }
   break;                                                    //--- Exit case
   case JsonArray:
      jsonString+="[";                                       //--- Start array
      for(int index=0; index<numChildren; index++){m_children[index].SerializeToString(jsonString,false,index>0);} //--- Serialize each child
      jsonString+="]";                                       //--- End array
      break;                                                 //--- Exit case
   case JsonObject:
      jsonString+="{";                                       //--- Start object
      for(int index=0; index<numChildren; index++){m_children[index].SerializeToString(jsonString,true,index>0);} //--- Serialize each child with key
      jsonString+="}";                                       //--- End object
      break;                                                 //--- Exit case
   }
}
//+------------------------------------------------------------------+
//| Deserializes from character array                                |
//+------------------------------------------------------------------+
bool JsonValue::DeserializeFromArray(char &jsonCharacterArray[],int arrayLength,int &currentIndex){
   string validNumericCharacters="0123456789+-.eE";          //--- Define valid number characters
   int startPosition=currentIndex;                           //--- Set start position
   for(; currentIndex<arrayLength; currentIndex++){          //--- Loop through array
      char currentCharacter=jsonCharacterArray[currentIndex]; //--- Get current character
      if(currentCharacter==0){break;}                        //--- Break if null character
      switch(currentCharacter){                              //--- Handle based on character
      case '\t':
      case '\r':
      case '\n':
      case ' ':                                              //--- Skip whitespace
         startPosition=currentIndex+1;                       //--- Update start position
         break;                                              //--- Exit case
      case '[':                                              //--- Start of array
      {
         startPosition=currentIndex+1;                       //--- Update start position
         if(m_type!=JsonUndefined){                          //--- Check if type is undefined
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug if error
            return false;                                    //--- Return false on error
         }
         m_type=JsonArray;                                   //--- Set type to array
         currentIndex++;                                     //--- Increment index
         JsonValue childValue(GetPointer(this),JsonUndefined); //--- Create child value
         while(childValue.DeserializeFromArray(jsonCharacterArray,arrayLength,currentIndex)){ //--- Deserialize children
            if(childValue.m_type!=JsonUndefined){AddChild(childValue);} //--- Add if not undefined
            if(childValue.m_type==JsonInteger || childValue.m_type==JsonDouble || childValue.m_type==JsonArray){currentIndex++;} //--- Increment if certain types
            childValue.Reset();                              //--- Reset child
            childValue.m_parent=GetPointer(this);            //--- Set parent
            if(jsonCharacterArray[currentIndex]==']'){break;} //--- Break if end of array
            currentIndex++;                                  //--- Increment index
            if(currentIndex>=arrayLength){                   //--- Check bounds
               if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
               return false;                                 //--- Return false
            }
         }
         return (jsonCharacterArray[currentIndex]==']' || jsonCharacterArray[currentIndex]==0); //--- Return true if properly ended
      }
      break;                                                 //--- Exit case
      case ']':                                              //--- End of array
         if(!m_parent){return false;}                        //--- Return false if no parent
         return (m_parent.m_type==JsonArray);                //--- Check parent is array
      case ':':                                              //--- Key-value separator
      {
         if(m_temporaryKey==""){                             //--- Check temporary key
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         JsonValue childValue(GetPointer(this),JsonUndefined); //--- Create child
         JsonValue *addedChild=AddChild(childValue);           //--- Add child
         addedChild.m_key=m_temporaryKey;                      //--- Set key
         m_temporaryKey="";                                    //--- Clear temporary key
         currentIndex++;                                       //--- Increment index
         if(!addedChild.DeserializeFromArray(jsonCharacterArray,arrayLength,currentIndex)){ //--- Deserialize child
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         break;                                              //--- Exit case
      }
      case ',':                                              //--- Value separator
         startPosition=currentIndex+1;                       //--- Update start
         if(!m_parent && m_type!=JsonObject){                //--- Check conditions
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         else if(m_parent){                                  //--- If has parent
            if(m_parent.m_type!=JsonArray && m_parent.m_type!=JsonObject){ //--- Check parent type
               if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
               return false;                                //--- Return false
            }
            if(m_parent.m_type==JsonArray && m_type==JsonUndefined){return true;} //--- Return true for undefined in array
         }
         break;                                              //--- Exit case
      case '{':                                              //--- Start of object
         startPosition=currentIndex+1;                       //--- Update start
         if(m_type!=JsonUndefined){                          //--- Check type
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         m_type=JsonObject;                                  //--- Set type to object
         currentIndex++;                                     //--- Increment index
         if(!DeserializeFromArray(jsonCharacterArray,arrayLength,currentIndex)){ //--- Recurse deserialize
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         return (jsonCharacterArray[currentIndex]=='}' || jsonCharacterArray[currentIndex]==0); //--- Check end
         break;                                              //--- Exit case
      case '}':                                              //--- End of object
         return (m_type==JsonObject);                        //--- Check type is object
      case 't':
      case 'T':                                              //--- Start of true
      case 'f':
      case 'F':                                              //--- Start of false
         if(m_type!=JsonUndefined){                          //--- Check type
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         m_type=JsonBoolean;                                 //--- Set type to boolean
         if(currentIndex+3<arrayLength){                     //--- Check for true
            if(StringCompare(GetSubstringFromArray(jsonCharacterArray, currentIndex, 4), "true", false)==0){ //--- Compare substring
               m_booleanValue=true;                          //--- Set to true
               currentIndex+=3;                              //--- Advance index
               return true;                                  //--- Return true
            }
         }
         if(currentIndex+4<arrayLength){                     //--- Check for false
            if(StringCompare(GetSubstringFromArray(jsonCharacterArray, currentIndex, 5), "false", false)==0){ //--- Compare substring
               m_booleanValue=false;                         //--- Set to false
               currentIndex+=4;                              //--- Advance index
               return true;                                  //--- Return true
            }
         }
         if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
         return false;                                       //--- Return false
         break;                                              //--- Exit case
      case 'n':
      case 'N':                                              //--- Start of null
         if(m_type!=JsonUndefined){                          //--- Check type
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         m_type=JsonNull;                                    //--- Set type to null
         if(currentIndex+3<arrayLength){                     //--- Check bounds
            if(StringCompare(GetSubstringFromArray(jsonCharacterArray,currentIndex,4),"null",false)==0){ //--- Compare substring
               currentIndex+=3;                              //--- Advance index
               return true;                                  //--- Return true
            }
         }
         if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
         return false;                                       //--- Return false
         break;                                              //--- Exit case
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '-':
      case '+':
      case '.':                                              //--- Start of number
      {
         if(m_type!=JsonUndefined){                          //--- Check type
            if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
            return false;                                    //--- Return false
         }
         bool isDouble=false;                                //--- Initialize double flag
         int startOfNumber=currentIndex;                     //--- Set start of number
         while(jsonCharacterArray[currentIndex]!=0 && currentIndex<arrayLength){ //--- Loop to parse number
            currentIndex++;                                  //--- Increment index
            if(StringFind(validNumericCharacters,GetSubstringFromArray(jsonCharacterArray,currentIndex,1))<0){break;} //--- Break if invalid char
            if(!isDouble){isDouble=(jsonCharacterArray[currentIndex]=='.' || jsonCharacterArray[currentIndex]=='e' || jsonCharacterArray[currentIndex]=='E');} //--- Set double flag
         }
         m_stringValue=GetSubstringFromArray(jsonCharacterArray,startOfNumber,currentIndex-startOfNumber); //--- Get number string
         if(isDouble){                                       //--- If double
            m_type=JsonDouble;                               //--- Set type to double
            m_doubleValue=StringToDouble(m_stringValue);     //--- Convert to double
            m_integerValue=(long)m_doubleValue;              //--- Convert to integer
            m_booleanValue=m_integerValue!=0;                //--- Set boolean
         }
         else{                                               //--- Else integer
            m_type=JsonInteger;                              //--- Set type to integer
            m_integerValue=StringToInteger(m_stringValue);   //--- Convert to integer
            m_doubleValue=(double)m_integerValue;            //--- Convert to double
            m_booleanValue=m_integerValue!=0;                //--- Set boolean
         }
         currentIndex--;                                     //--- Decrement index
         return true;                                        //--- Return true
         break;                                              //--- Exit case
      }
      case '\"':                                             //--- Start of string or key
         if(m_type==JsonObject){                             //--- If object type
            currentIndex++;                                  //--- Increment index
            int startOfString=currentIndex;                  //--- Set start of string
            if(!ExtractStringFromArray(jsonCharacterArray,arrayLength,currentIndex)){ //--- Extract string
               if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
               return false;                                 //--- Return false
            }
            m_temporaryKey=GetSubstringFromArray(jsonCharacterArray,startOfString,currentIndex-startOfString); //--- Set temporary key
         }
         else{                                               //--- Else value string
            if(m_type!=JsonUndefined){                       //--- Check type
               if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
               return false;                                 //--- Return false
            }
            m_type=JsonString;                               //--- Set type to string
            currentIndex++;                                  //--- Increment index
            int startOfString=currentIndex;                  //--- Set start of string
            if(!ExtractStringFromArray(jsonCharacterArray,arrayLength,currentIndex)){ //--- Extract string
               if(DEBUG_PRINT){Print(m_key+" "+string(__LINE__));} //--- Print debug
               return false;                                 //--- Return false
            }
            SetFromString(JsonString,GetSubstringFromArray(jsonCharacterArray,startOfString,currentIndex-startOfString)); //--- Set from extracted string
            return true;                                     //--- Return true
         }
         break;                                              //--- Exit case
      }
   }
   return true;                                           
      //--- Return true at end
}

Wir setzen die Implementierung des Analyse-Systems fort und konzentrieren uns dabei auf die kritischen Methoden zur Serialisierungs und Deserialisierung.

Zunächst definieren wir die Methode „SerializeToString“, die eine JSON-Struktur in eine Zeichenkette umwandelt; sie überspringt undefinierte Typen, fügt ein Komma hinzu, wenn „includeComma“ wahr ist, fügt den Schlüssel an, wenn „includeKey“ wahr ist, und verwendet StringFormat, und behandelt jeden „m_type“-Fall: „JsonNull“ fügt „null“ an, „JsonBoolean“ fügt „true“ oder „false“ basierend auf „m_booleanValue“ an, „JsonInteger“ verwendet IntegerToString für „m_integerValue“, „JsonDouble“ verwendet DoubleToString für „m_doubleValue“, „JsonString“ bricht „m_stringValue“ mit „EscapeString“ und verpackt es in Anführungszeichen (oder „null“, wenn es leer ist), „JsonArray“ verpackt Kinder in Klammern mit rekursiven Aufrufen von „SerializeToString“ (ohne Schlüssel, mit Kommas für nicht-erste Elemente), und „JsonObject“ verpackt Kinder in geschweifte Klammern mit eingeschlossenen Schlüsseln. Eine bequeme Überladung von „SerializeToString“ erzeugt eine Zeichenkette, ruft die parametrisierte Version mit Standardargumenten auf und gibt das Ergebnis zurück.

Als Nächstes implementieren wir „DeserializeFromArray“, das ein Zeichenarray analysiert, um eine JSON-Struktur zu erstellen, wobei eine Zeichenfolge aus gültigen numerischen Zeichen („0123456789+-.eE“) verwendet und das Array durchlaufen wird. Es überspringt Leerzeichen, verarbeitet Arrays („[“) durch Setzen von „m_type“ auf „JsonArray“ und rekursives Deserialisieren von untergeordneten Elementen bis zu einer schließenden Klammer, validiert den Array-Abschluss, verarbeitet Schlüssel-Wert-Trennzeichen („:“) durch Zuweisen von „m_temporaryKey“ zu einem neuen untergeordneten Element, verarbeitet Wertetrennzeichen („,“), verarbeitet Objekte („{“), indem es „m_type“ auf „JsonObject“ setzt und untergeordnete Elemente bis zu einer schließenden Klammer deserialisiert, überprüft den Objektabschluss, analysiert Boolesche Werte („true“ oder „false“), indem es „m_booleanValue“ setzt, Parsen von Null („null”) durch Setzen von „m_type” auf „JsonNull”, Parsen von Zahlen durch Erkennen der Dezimal- oder Exponentialdarstellung, um „m_type” auf „JsonDouble” oder „JsonInteger” zu setzen, und Parsen von Zeichenfolgen (in Anführungszeichen) unter Verwendung von „ExtractStringFromArray” zur Verarbeitung von Escape-Zeichen.

Die Methode „DeserializeFromArray“ gewährleistet ordnungsgemäße Eltern-Kind-Beziehungen und eine Fehlerbehandlung über „DEBUG_PRINT“-Protokolle für ungültige Strukturen, was sie für das Parsen von Antworten robust macht. Schließlich können wir die Escape-Methoden definieren.

//+------------------------------------------------------------------+
//| Extracts string from array handling escapes                      |
//+------------------------------------------------------------------+
bool JsonValue::ExtractStringFromArray(char &jsonCharacterArray[],int arrayLength,int &currentIndex){
   for(; jsonCharacterArray[currentIndex]!=0 && currentIndex<arrayLength; currentIndex++){ //--- Loop through string
      char currentCharacter=jsonCharacterArray[currentIndex]; //--- Get current char
      if(currentCharacter=='\"') break;                      //--- Break on closing quote
      if(currentCharacter=='\\' && currentIndex+1<arrayLength){ //--- Handle escape
         currentIndex++;                                     //--- Increment for escaped char
         currentCharacter=jsonCharacterArray[currentIndex];  //--- Get escaped char
         switch(currentCharacter){                           //--- Handle escaped type
         case '/':
         case '\\':
         case '\"':
         case 'b':
         case 'f':
         case 'r':
         case 'n':
         case 't':
            break;                                           //--- Allowed escapes
         case 'u':                                           //--- Unicode escape
         {
            currentIndex++;                                  //--- Increment
            for(int hexDigitIndex=0; hexDigitIndex<4 && currentIndex<arrayLength && jsonCharacterArray[currentIndex]!=0; hexDigitIndex++,currentIndex++){ //--- Loop hex digits
               if(!((jsonCharacterArray[currentIndex]>='0' && jsonCharacterArray[currentIndex]<='9') || (jsonCharacterArray[currentIndex]>='A' && jsonCharacterArray[currentIndex]<='F') || (jsonCharacterArray[currentIndex]>='a' && jsonCharacterArray[currentIndex]<='f'))){ //--- Check hex
                  if(DEBUG_PRINT){Print(m_key+" "+CharToString(jsonCharacterArray[currentIndex])+" "+string(__LINE__));} //--- Print debug
                  return false;                                 //--- Return false on invalid hex
               }
            }
            currentIndex--;                                  //--- Decrement after loop
            break;                                           //--- Exit case
         }
         default:
            break;                                           //--- Handle other (commented return false)
         }
      }
   }
   return true;                                              //--- Return true
}
//+------------------------------------------------------------------+
//| Escapes special characters in string                             |
//+------------------------------------------------------------------+
string JsonValue::EscapeString(string stringValue){
   ushort inputCharacters[], escapedCharacters[];               //--- Declare arrays
   int inputLength=StringToShortArray(stringValue, inputCharacters); //--- Convert string to short array
   if(ArrayResize(escapedCharacters, 2*inputLength)!=2*inputLength){return NULL;} //--- Resize escaped array, return NULL on fail
   int escapedIndex=0;                                          //--- Initialize escaped index
   for(int inputIndex=0; inputIndex<inputLength; inputIndex++){ //--- Loop through input
      switch(inputCharacters[inputIndex]){                      //--- Handle special chars
      case '\\':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='\\';                  //--- Add backslash
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case '"':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='"';                   //--- Add quote
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case '/':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='/';                   //--- Add slash
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case 8:
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='b';                   //--- Add backspace
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case 12:
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='f';                   //--- Add form feed
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case '\n':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='n';                   //--- Add newline
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case '\r':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='r';                   //--- Add carriage return
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      case '\t':
         escapedCharacters[escapedIndex]='\\';                  //--- Add escape
         escapedIndex++;                                        //--- Increment
         escapedCharacters[escapedIndex]='t';                   //--- Add tab
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      default:
         escapedCharacters[escapedIndex]=inputCharacters[inputIndex]; //--- Copy normal char
         escapedIndex++;                                        //--- Increment
         break;                                                 //--- Exit case
      }
   }
   stringValue=ShortArrayToString(escapedCharacters,0,escapedIndex); //--- Convert back to string
   return stringValue;                                          //--- Return escaped string
}
//+------------------------------------------------------------------+
//| Unescapes special characters in string                           |
//+------------------------------------------------------------------+
string JsonValue::UnescapeString(string stringValue){
   ushort inputCharacters[], unescapedCharacters[];             //--- Declare arrays
   int inputLength=StringToShortArray(stringValue, inputCharacters); //--- Convert to short array
   if(ArrayResize(unescapedCharacters, inputLength)!=inputLength){return NULL;} //--- Resize, return NULL on fail
   int outputIndex=0,inputIndex=0;                              //--- Initialize indices
   while(inputIndex<inputLength){                               //--- Loop through input
      ushort currentCharacter=inputCharacters[inputIndex];      //--- Get current char
      if(currentCharacter=='\\' && inputIndex<inputLength-1){   //--- Handle escape
         switch(inputCharacters[inputIndex+1]){                 //--- Handle escaped type
         case '\\':
            currentCharacter='\\';                              //--- Set to backslash
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case '"':
            currentCharacter='"';                               //--- Set to quote
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case '/':
            currentCharacter='/';                               //--- Set to slash
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case 'b':
            currentCharacter=8;                                 //--- Set to backspace
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case 'f':
            currentCharacter=12;                                //--- Set to form feed
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case 'n':
            currentCharacter='\n';                              //--- Set to newline
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case 'r':
            currentCharacter='\r';                              //--- Set to carriage return
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         case 't':
            currentCharacter='\t';                              //--- Set to tab
            inputIndex++;                                       //--- Increment
            break;                                              //--- Exit case
         }
      }
      unescapedCharacters[outputIndex]=currentCharacter;        //--- Copy to output
      outputIndex++;                                            //--- Increment output
      inputIndex++;                                             //--- Increment input
   }
   stringValue=ShortArrayToString(unescapedCharacters,0,outputIndex); //--- Convert back to string
   return stringValue;                                          //--- Return unescaped string
}

Wir schließen die Implementierung ab, indem wir uns auf die Methoden zur Behandlung von Zeichenketten konzentrieren. Zunächst implementieren wir die Methode „ExtractStringFromArray“, die eine Zeichenfolge aus einem Zeichenarray analysiert, indem sie so lange iteriert, bis ein schließendes Anführungszeichen oder das Ende des Arrays erreicht ist, und dabei Escape-Sequenzen (z. B. "", """, "/", "\b", "\f", "\n", "\r", "\t") und Escapes von Unicode ("\uXXXX") verarbeitet, indem sie vier Hexadezimalziffern validiert, bei ungültigen Hexadezimalzahlen oder Begrenzungsfehlern false zurückgibt und „DEBUG_PRINT“ zum Debuggen ungültiger Fälle verwendet, um eine genaue Zeichenfolgen-Extraktion für die JSON-Parsing zu gewährleisten.

Dann entwickeln wir die Methode „EscapeString“, die eine Zeichenkette in ihre JSON-konforme Form umwandelt, indem sie sie mit StringToShortArray in ein Array vom Typ short umwandelt, ein Ausgabe-Array auf die doppelte Länge der Eingabe verkleinert, um Escape-Zeichen unterzubringen, und durch jedes Zeichen iteriert, um Sonderfälle zu behandeln: Backslash, Anführungszeichen, Schrägstrich, Backspace (8), Formfeed (12), Zeilenumbruch, Wagenrücklauf und Tabulator werden mit einem vorangestellten Backslash escaped (z. B., „\n“ für neue Zeile, während andere Zeichen direkt kopiert werden und die maskierte Zeichenfolge über die Funktion ShortArrayToString zurückgegeben wird.

Zuletzt implementieren wir die Methode „UnescapeString“, die den Escape-Prozess umkehrt, indem sie die Eingabezeichenfolge in ein kurzes Array konvertiert, die Größe eines Ausgabe-Arrays an die Eingabelänge anpasst und Escape-Sequenzen iterativ verarbeitet: Wenn ein Backslash angetroffen wird, wird das nächste Zeichen interpretiert (z. B., „\n“ für Zeilenumbruch, „\t“ für Tabulator), wobei das nicht verkappte Zeichen in die Ausgabe kopiert wird, während nicht verkappte Zeichen direkt kopiert werden und die nicht verkappte Zeichenkette über „ShortArrayToString“ oder NULL bei einem Größenänderungsfehler zurückgegeben wird. Diese Methoden stellen sicher, dass die Klasse „JsonValue“ mit Sonderzeichen in JSON-Strings umgehen kann, was für die korrekte Formatierung von API-Anfragen und das Parsen von KI-Antworten auf robuste und zuverlässige Weise entscheidend ist. Hier ein Beispiel für die Verwendung von Sonderzeichen, die für eine einfachere Kommunikation und ein reibungsloses Verständnis korrekt interpretiert werden.

BEISPIEL FÜR DIE VERWENDUNG VON SONDERZEICHEN

Nachdem die Klassenimplementierung abgeschlossen ist, können wir nun mit der Parsing-Logik beginnen. Aber lassen Sie uns zuerst den Parser testen und sicherstellen, dass alles in Ordnung ist. Wir werden dies im nächsten Abschnitt tun.


Testen des JSON-Parsers

Um die Zuverlässigkeit unseres JSON-Parsing-Frameworks zu gewährleisten, testen wir die Klasse „JsonValue“ in MQL5 rigoros, um ihre Fähigkeit zu überprüfen, verschiedene JSON-Strukturen zu verarbeiten, die für die KI-API-Integration entscheidend sind. Im Folgenden wird der Testansatz beschrieben, einschließlich der Testfälle, der erwarteten Ergebnisse und der Methoden zur Validierung der Funktionalität des Parsers in einer Handelsumgebung. Wir werden eine Codefunktion definieren und sie in OnInit aufrufen und den Inhalt ausdrucken. Hier ist der erste Code. Wir werden die gleiche Datei verwenden. Drucken wir zunächst „Hello world“, wie im Falle eines Anfangs.

//+------------------------------------------------------------------+
//| Test Functions                                                   |
//+------------------------------------------------------------------+
void TestBasicSerialization(){
   Print("\n--- Testing Basic Serialization ---");
   
   JsonValue root;
   root["string"] = "hello world";
   root["number"] = 42;
   root["double"] = 3.14159;
   root["boolean"] = true;
   root["empty"] = "";
   
   string json = root.SerializeToString();
   Print("Serialized JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("Deserialization successful");
      Print("String: ", parsed["string"].ToString());
      Print("Number: ", (int)parsed["number"].ToInteger());
      Print("Double: ", parsed["double"].ToDouble());
      Print("Boolean: ", parsed["boolean"].ToBoolean());
      Print("Empty: ", parsed["empty"].ToString());
   } else {
      Print("Deserialization failed!");
   }
}

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   TestBasicSerialization();
return(INIT_SUCCEEDED);
}

Wir erstellen eine Funktion „TestBasicSerialization“ und erstellen das Objekt „JsonValue“ mit dem Namen „root“ und weisen Werte mit „operator[]“ zu: „string“ zu „hello world“, „number“ zu 42, „double“ zu 3.14159, „boolean“ auf true und „empty“ auf eine leere Zeichenkette, wobei die wichtigsten JSON-Datentypen (JsonString, JsonInteger, JsonDouble, JsonBoolean) abgedeckt werden. Dann rufen wir „SerializeToString“ auf „root“ auf, um einen JSON-String zu generieren, speichern ihn in „json“ und geben ihn zur Überprüfung mit Print auf dem Terminal MetaTrader 5 aus.

Als Nächstes erstellen wir ein neues „JsonValue“-Objekt mit dem Namen „parsed“ und rufen „DeserializeFromString“ mit dem „json“-String auf, um die JSON-Struktur zu rekonstruieren, wobei wir prüfen, ob der Wert true zurückgegeben wird, um den Erfolg zu bestätigen. „ToString“, „ToInteger“ (Umwandlung in int), „ToDouble“ und „ToBoolean“, um die Werte von „string“, „number“ und „double“ abzurufen und zu drucken, „number“, „double“, „boolean“ und „empty“ über „operator[]“ abrufen und ausgeben; schlägt dies fehl, drucken wir „Deserialization failed!“. In OnInit rufen wir schließlich „TestBasicSerialization“ auf, um den Test bei der Programminitialisierung auszuführen und „INIT_SUCCEEDED“ zurückzugeben, um die erfolgreiche Einrichtung anzuzeigen. Hier ist die Ausgabe, die wir erhalten.

INITIALE BASISSERIALISIERUNG

Aus dem Bild geht hervor, dass die grundlegende Serialisierung erfolgreich war. Testen wir nun die grundlegende Deserialisierung und sehen wir nach.

void TestBasicDeserialization(){
   Print("\n--- Testing Basic Deserialization ---");
   
   string testJson = "{\"name\":\"John\",\"age\":30,\"isStudent\":false,\"salary\":1500.75}";
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(testJson)){
      Print("Parsed successfully:");
      Print("Name: ", parsed["name"].ToString());
      Print("Age: ", (int)parsed["age"].ToInteger());
      Print("Is Student: ", parsed["isStudent"].ToBoolean());
      Print("Salary: ", parsed["salary"].ToDouble());
   } else {
      Print("Failed to parse JSON");
   }
}

Bei der Prüfung erhalten wir folgendes Ergebnis.

ERSTE GRUNDLEGENDE DESERIALISIERUNG

Auch das war ein Erfolg. Erhöhen wir nun den Komplexitätsgrad und sehen wir weiter.

void TestComplexObject(){
   Print("\n--- Testing Complex Object ---");
   
   JsonValue root;
   root["person"]["name"] = "Alice";
   root["person"]["age"] = 25;
   root["person"]["isActive"] = true;
   root["person"]["score"] = 95.5;
   root["person"]["address"]["street"] = "123 Main St";
   root["person"]["address"]["city"] = "New York";
   root["person"]["address"]["zipcode"] = "10001";
   
   root["person"]["hobbies"].AddChild("reading");
   root["person"]["hobbies"].AddChild("gaming");
   root["person"]["hobbies"].AddChild("coding");
   
   root["person"]["preferences"]["theme"] = "dark";
   root["person"]["preferences"]["notifications"] = true;
   
   string json = root.SerializeToString();
   Print("Complex JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("Round-trip successful");
      Print("Name: ", parsed["person"]["name"].ToString());
      Print("Age: ", (int)parsed["person"]["age"].ToInteger());
      Print("City: ", parsed["person"]["address"]["city"].ToString());
      Print("Zipcode: ", parsed["person"]["address"]["zipcode"].ToString());
      Print("Theme: ", parsed["person"]["preferences"]["theme"].ToString());
      Print("Hobby count: ", ArraySize(parsed["person"]["hobbies"].m_children));
   }
}

void TestArrayHandling(){
   Print("\n--- Testing Array Handling ---");
   
   JsonValue root;
   
   // Array of numbers
   for(int i = 0; i < 5; i++){
      root["numbers"].AddChild(i * 10);
   }
   
   // Array of mixed types
   root["mixed"].AddChild("string");
   root["mixed"].AddChild(123);
   root["mixed"].AddChild(45.67);
   root["mixed"].AddChild(true);
   
   // Array of objects
   JsonValue item;
   item["id"] = 1;
   item["name"] = "Item 1";
   item["price"] = 19.99;
   root["items"].AddChild(item);
   
   item["id"] = 2;
   item["name"] = "Item 2";
   item["price"] = 29.99;
   root["items"].AddChild(item);
   
   // Nested arrays
   JsonValue nestedArray;
   nestedArray.AddChild("nested1");
   nestedArray.AddChild("nested2");
   root["nested"].AddChild(nestedArray);
   
   string json = root.SerializeToString();
   Print("Array JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("Numbers array length: ", ArraySize(parsed["numbers"].m_children));
      Print("Mixed array length: ", ArraySize(parsed["mixed"].m_children));
      Print("Items array length: ", ArraySize(parsed["items"].m_children));
      Print("First item name: ", parsed["items"][0]["name"].ToString());
      Print("Second item price: ", parsed["items"][1]["price"].ToDouble());
   }
}

void TestErrorHandling(){
   Print("\n--- Testing Error Handling ---");
   
   JsonValue parsed;
   
   // Test invalid JSON
   string invalidJson = "{\"name\": \"test\", \"age\": }";
   if(!parsed.DeserializeFromString(invalidJson)){
      Print("✓ Correctly rejected invalid JSON");
   }
   
   // Test malformed JSON
   string malformedJson = "{\"name\": \"test\" \"age\": 30}"; // Missing comma
   if(!parsed.DeserializeFromString(malformedJson)){
      Print("✓ Correctly rejected malformed JSON");
   }
   
   // Test empty string
   if(!parsed.DeserializeFromString("")){
      Print("✓ Correctly handled empty string");
   }
   
   // Test incomplete object
   string incompleteJson = "{\"name\": \"test\"";
   if(!parsed.DeserializeFromString(incompleteJson)){
      Print("✓ Correctly rejected incomplete JSON");
   }
}

Wir testen und erhalten das folgende Ergebnis.

KOMPLEXE TESTS

Testen wir nun Leistung, verschachtelte Strukturen und Datentypen.

void TestPerformance(){
   Print("\n--- Testing Performance ---");
   
   int startTime = GetTickCount();
   int iterations = 100;
   int successCount = 0;
   
   for(int i = 0; i < iterations; i++){
      JsonValue root;
      root["test_id"] = i;
      root["name"] = "Test Item " + IntegerToString(i);
      root["value"] = i * 1.5;
      root["active"] = (i % 2 == 0);
      
      // Add array
      for(int j = 0; j < 5; j++){
         root["tags"].AddChild("tag" + IntegerToString(j));
      }
      
      string json = root.SerializeToString();
      
      JsonValue parsed;
      if(parsed.DeserializeFromString(json)){
         successCount++;
      }
   }
   
   int endTime = GetTickCount();
   Print("Performance: ", iterations, " iterations in ", endTime - startTime, "ms");
   Print("Success rate: ", successCount, "/", iterations, " (", DoubleToString(successCount*100.0/iterations, 1), "%)");
}

void TestNestedStructures(){
   Print("\n--- Testing Nested Structures ---");
   
   JsonValue root;
   
   // Deep nesting
   root["level1"]["level2"]["level3"]["level4"]["value"] = "deep_nested";
   root["level1"]["level2"]["level3"]["level4"]["number"] = 999;
   
   // Array of objects with nesting
   JsonValue user;
   user["name"] = "John";
   user["profile"]["age"] = 30;
   user["profile"]["settings"]["theme"] = "dark";
   user["profile"]["settings"]["notifications"] = true;
   root["users"].AddChild(user);
   
   user["name"] = "Jane";
   user["profile"]["age"] = 25;
   user["profile"]["settings"]["theme"] = "light";
   user["profile"]["settings"]["notifications"] = false;
   root["users"].AddChild(user);
   
   string json = root.SerializeToString();
   Print("Nested JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("✓ Nested structures parsed successfully");
      Print("Deep value: ", parsed["level1"]["level2"]["level3"]["level4"]["value"].ToString());
      Print("User count: ", ArraySize(parsed["users"].m_children));
      Print("First user theme: ", parsed["users"][0]["profile"]["settings"]["theme"].ToString());
      Print("Second user age: ", (int)parsed["users"][1]["profile"]["age"].ToInteger());
   }
}

void TestDataTypes(){
   Print("\n--- Testing Data Types ---");
   
   JsonValue root;
   
   // All supported data types
   root["string_type"] = "hello world";
   root["int_type"] = 42;
   root["long_type"] = 1234567890123;
   root["double_type"] = 3.14159265358979;
   root["bool_true"] = true;
   root["bool_false"] = false;
   root["empty_string"] = "";
   
   // Scientific notation
   root["scientific_positive"] = 1.23e+10;
   root["scientific_negative"] = 1.23e-10;
   
   string json = root.SerializeToString();
   Print("Data Types JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("✓ All data types parsed successfully");
      Print("String: ", parsed["string_type"].ToString());
      Print("Integer: ", (int)parsed["int_type"].ToInteger());
      Print("Long: ", parsed["long_type"].ToInteger());
      Print("Double: ", parsed["double_type"].ToDouble());
      Print("Bool True: ", parsed["bool_true"].ToBoolean());
      Print("Bool False: ", parsed["bool_false"].ToBoolean());
      Print("Scientific Positive: ", parsed["scientific_positive"].ToDouble());
      Print("Scientific Negative: ", parsed["scientific_negative"].ToDouble());
   }
}

Hier ist die Ausgabe.

LEISTUNG, VERSCHACHTELTE STRUKTUREN UND DATENTYPENTEST

Das war ein Erfolg. Lassen Sie uns nun die Escape-Zeichen testen.

void TestEscapeCharacters(){
   Print("\n--- Testing Escape Characters ---");
   
   JsonValue root;
   
   // Various escape sequences - using only MQL5 supported escapes
   root["backslash"] = "\\\\"; // Double backslash for single backslash
   root["quote"] = "\\\"";     // Escaped quote
   root["newline"] = "\\n";    // Escaped newline
   root["tab"] = "\\t";        // Escaped tab
   root["carriage_return"] = "\\r"; // Escaped carriage return
   
   // For form feed and backspace, we need to use their actual ASCII codes
   // since MQL5 doesn't support \f and \b escape sequences
   root["form_feed"] = "\\u000C"; // Unicode escape for form feed
   root["backspace"] = "\\u0008"; // Unicode escape for backspace
   
   root["mixed_escapes"] = "Line1\\nLine2\\tTabbed\\\"Quoted\\\"\\\\Backslash";
   
   string json = root.SerializeToString();
   Print("Escape Chars JSON: ", json);
   
   JsonValue parsed;
   if(parsed.DeserializeFromString(json)){
      Print("✓ Escape characters parsed successfully");
      Print("Backslash: '", parsed["backslash"].ToString(), "'");
      Print("Quote: '", parsed["quote"].ToString(), "'");
      Print("Newline: '", parsed["newline"].ToString(), "'");
      Print("Tab: '", parsed["tab"].ToString(), "'");
      Print("Carriage Return: '", parsed["carriage_return"].ToString(), "'");
      Print("Form Feed: '", parsed["form_feed"].ToString(), "'");
      Print("Backspace: '", parsed["backspace"].ToString(), "'");
      Print("Mixed: '", parsed["mixed_escapes"].ToString(), "'");
   } else {
      Print("✗ Escape characters parsing failed");
   }
}

Wir kommen zu folgendem Ergebnis.

ESCAPE-ZEICHEN

Das war ein Erfolg. Da wir bestätigt haben, dass unsere JSON-Implementierung brauchbar ist, können wir sie nun für die Erstellung von KI-Integrationen in zukünftigen Programmen verwenden, die wir erstellen werden.


Schlussfolgerung

Insgesamt haben wir ein JSON (JavaScript Object Notation)-Parsing-Framework in MQL5 entwickelt und eine „JsonValue“-Klasse implementiert, um die Serialisierung und Deserialisierung von JSON-Daten zu handhaben, die für die Interaktionen der API (Application Programming Interface) wichtig sind. Durch Methoden wie „SerializeToString“, „DeserializeFromArray“ und „EscapeString“ sowie Tests mit Funktionen wie „TestBasicSerialization“ stellen wir eine zuverlässige Verarbeitung verschiedener JSON-Strukturen sicher und schaffen so eine solide Grundlage für zukünftige KI-gesteuerte Handelssysteme. In den folgenden Teilen werden wir die KI in unsere Handelsanwendungen integrieren und mit ihr interagieren. Bleiben Sie am Ball.

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

Beigefügte Dateien |
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Peter Wlliams
Peter Wlliams | 23 Sept. 2025 in 23:44

Sieht fantastisch aus. Wo soll man anfangen?

Ist die heruntergeladene Datei a._JSON_Code_File.mq5 und EA?

Ich habe A_JSON_Code_File.mq5 umbenannt (sah vertrauter aus) und dann kompiliert. Keine Fehler.

Allerdings konnte ich auf meiner Plattform keine Referenz als EXPERT sehen - d.h. ich konnte es nicht laden und ausführen.

Ich muss nur 'spielen' und versuchen zu verstehen, was passiert und warum.


Vielen Dank für die Bereitstellung einer fantastischen Möglichkeit zur Nutzung von KI

Allan Munene Mutiiria
Allan Munene Mutiiria | 24 Sept. 2025 in 11:44
Peter Wlliams #:

Sieht fantastisch aus. Wo soll ich anfangen?

Ist die Download-Datei ein._JSON_Code_File.mq5 und EA?

Ich habe A_JSON_Code_File.mq5 umbenannt (sah vertrauter aus), dann kompiliert. Keine Fehler

Allerdings konnte ich auf meiner Plattform keine Referenz als EXPERT sehen - d.h. ich konnte es nicht laden und ausführen.

Ich muss nur 'spielen' und versuchen zu verstehen, was passiert und warum.


Vielen Dank für die Bereitstellung einer fantastischen Möglichkeit zur Nutzung von KI

Vielen Dank für das Feedback. Es scheint, als müssten Sie den Artikel wirklich lesen. Es geht um JSON, um die KI-Integration in zukünftigen Versionen zu ermöglichen.
Beherrschung der Fair Value Gaps: Bildung, Logik und automatisierter Handel von Ausbrüchen und Marktstrukturverschiebungen Beherrschung der Fair Value Gaps: Bildung, Logik und automatisierter Handel von Ausbrüchen und Marktstrukturverschiebungen
Dies ist ein Artikel, den ich geschrieben habe, um Fair Value Gaps, ihre Entstehungslogik und den automatisierten Handel von Ausbrüchen und Marktstrukturverschiebungen zu erläutern und zu erklären.
Entwicklung des Price Action Analysis Toolkit (Teil 40): Markt-DNA-Pass Entwicklung des Price Action Analysis Toolkit (Teil 40): Markt-DNA-Pass
In diesem Artikel wird die einzigartige Identität der einzelnen Währungspaare anhand ihrer historischen Kursentwicklung untersucht. Inspiriert vom Konzept der genetischen DNA, die den individuellen Bauplan eines jeden Lebewesens kodiert, wenden wir einen ähnlichen Rahmen auf die Märkte an, indem wir die Kursentwicklung als „DNA“ eines jeden Paares betrachten. Durch die Aufschlüsselung struktureller Verhaltensweisen wie Volatilität, Schwankungen, Rückschritte, Ausschläge und Sitzungsmerkmale zeigt das Tool das zugrunde liegende Profil, das ein Paar von einem anderen unterscheidet. Dieser Ansatz bietet einen tieferen Einblick in das Marktverhalten und gibt Händlern eine strukturierte Methode an die Hand, um ihre Strategien auf die natürlichen Tendenzen der einzelnen Instrumente abzustimmen.
Den Marktstimmungsindikator automatisieren Den Marktstimmungsindikator automatisieren
In diesem Artikel entwickeln wir einen nutzerdefinierten Indikator für die Marktstimmung, um die Bedingungen in aufwärts, abwärts, mehr und weniger Risiko oder neutral zu klassifizieren. Der Expert Advisor liefert Echtzeit-Einblicke in die vorherrschende Stimmung und vereinfacht den Analyseprozess für aktuelle Markttrends oder -richtungen.
Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 2): Entwicklung eines ChatGPT-integrierten Programms mit Nutzeroberfläche Aufbau von KI-gesteuerten Handelssystemen in MQL5 (Teil 2): Entwicklung eines ChatGPT-integrierten Programms mit Nutzeroberfläche
In diesem Artikel entwickeln wir ein in ChatGPT integriertes Programm in MQL5 mit einer Nutzeroberfläche, das das JSON-Parsing-Framework aus Teil 1 nutzt, um Prompts an die API von OpenAI zu senden und die Antworten auf einem MetaTrader 5-Chart anzuzeigen. Wir implementieren ein Dashboard mit einem Eingabefeld, einer Übermittlungsschaltfläche und einer Antwortanzeige, wobei wir die API-Kommunikation und den Textumbruch für die Nutzerinteraktion übernehmen.