Voir comment télécharger gratuitement des robots de trading
Retrouvez-nous sur Twitter !
Rejoignez notre page de fans
Un script intéressant ?
Poster un lien vers celui-ci -
laisser les autres l'évaluer
Vous avez aimé le script ? Essayez-le dans le terminal MetaTrader 5
Bibliothèque

A powerful and feature-rich JSON library for MQL5, designed to bring a modern development experience similar to Python/JS - bibliothèque pour MetaTrader 5

Vues:
260
Note:
(1)
Publié:
MQL5 Freelance Besoin d'un robot ou d'un indicateur basé sur ce code ? Commandez-le sur Freelance Aller sur Freelance

    
//+------------------------------------------------------------------+
//|  JsonLib.mqh                                                     |
//|  Version 10.0                                                    |
//|  Copyright 2025, ding9736                                        |
//+------------------------------------------------------------------+
#property strict
#property copyright "Copyright 2025, ding9736"
#property link      "https://www.mql5.com/en/users/ding9736"
#property link      "https://github.com/ding9736/Mql5-JsonLib"
#property version   "10.0"

#ifndef MQL5_JSON_LIBRARY_V10_H
#define MQL5_JSON_LIBRARY_V10_H
/*
//+------------------------------------------------------------------+
//| MQL5 JSON Library - Developer's Manual                           |
//| Author: ding9736                                                 |
//| Version: 10.0                                                    |
//+------------------------------------------------------------------+

//==============================================================================
// 1. Overview
//==============================================================================
//
// The MQL5 JSON Library is a powerful, feature-rich library designed specifically
// for parsing, manipulating, and serializing JSON data within the MQL5
// environment. It provides a simple and intuitive Document Object Model (DOM) API,
// aiming to make the JSON handling experience in MQL5 comparable to modern
// programming languages like JavaScript and Python.
//
// This library is capable of handling a wide range of tasks, from reading simple
// EA configurations to complex real-time data exchange between systems.
// Its main functions and features include:
//
//   --- Parsing and Creation ---
//
//   - **Load from String or File**: Reliably parses JSON text into manipulable
//     in-memory objects (`JsonParse`, `JsonFromFile`).
//   - **Build from Scratch**: Easily create new JSON objects and arrays
//     programmatically using concise APIs like `JsonNewObject` and `JsonNewArray`.
//   - **Flexible Parser**: Optionally supports some non-standard features of JSON5,
//     such as code comments and trailing commas, to enhance compatibility with
//     various data sources.
//
//   --- Manipulation and Access ---
//
//   - **Intuitive DOM Traversal**: Access data using intuitive syntax with keys
//     (`node["key"]`) and indices (`node[0]`), just like using a Python dictionary
//     or a JavaScript object.
//   - **Safe Type Conversion**: Provides a series of methods with default values,
//     such as `AsInt(defaultValue)` and `AsString(defaultValue)`, allowing you
//     to safely extract data of the desired type from a node without worrying
//     about program crashes due to type mismatches or non-existent paths.
//   - **Dynamic Modification**: Freely add, update, or delete key-value pairs
//     in JSON objects and elements in arrays (`Set`, `Add`, `Remove`).
//
//   --- Advanced Querying and Processing ---
//
//   - **Powerful Query Engine**: Built-in support for **JSON Pointer** (RFC 6901,
//     for direct path access) and **JSONPath** (for complex and fuzzy queries),
//     enabling efficient extraction of one or more data nodes from deeply
//     nested, complex structures, either in bulk or with precision.
//   - **Low-Memory Stream Parsing**: Provides `JsonStreamParser` for processing
//     gigabyte-scale, huge JSON files. It reads the file token by token in an
//     event stream manner without loading the entire file into memory, thus
//     achieving ultimate memory efficiency.
//   - **Utility Functions**: Offers advanced features like document cloning (`.Clone()`)
//     and deep merging (`JsonMerge`), which greatly simplify common complex tasks
//     such as merging "default configuration" with "user configuration".
//
//   --- Robustness and Safety ---
//
//   - **Automatic Memory Management**: Adopts the RAII (Resource Acquisition Is
//     Initialization) design pattern. `JsonDocument` is responsible for managing
//     the lifecycle of all its nodes. Developers do not need to manually `new`/`delete`
//     any JSON elements, fundamentally eliminating the risk of memory leaks.
//   - **Cross-Document Operation Safety**: When assigning a node between different
//     `JsonDocument` instances, the library automatically performs a safe deep
//     copy (Clone), preventing dangling pointers and accidental data corruption.
//   - **Detailed Error Reporting**: When parsing fails, the `JsonError` object
//     provides detailed information including the error line number, column number,
//     and context, facilitating rapid problem diagnosis.
//

//==============================================================================
// 2. Core Concepts & Memory Management
//==============================================================================
//
// [!!] 2.1 Namespace - The Key to Integrating Your Project [!!]
//     **Most Important Tip**: All classes in this library (e.g., `JsonDocument`,
//     `JsonNode`) and global functions (e.g., `JsonParse`) are encapsulated
//     within a namespace called `MQL5_Json`.
//
//     **How to Use It Correctly:**
//
//     - **In Header Files (.mqh)**: MQL5 does not allow `using namespace` in the
//       global scope of header files. **Therefore, you must use fully qualified names**.
//       This is the only reliable way in multi-file projects.
//       Incorrect: `JsonDocument doc;`
//       Correct:   `MQL5_Json::JsonDocument doc;`
//
//     - **Inside Functions in Main Program Files (.mq5)**: For convenience, you can use
//       `using namespace MQL5_Json;` inside functions, but to ensure the
//       generality of the examples, all code in this manual will use the fully
//       qualified name approach.
//
//     **If you encounter the `'JsonNode' - declaration without type` compilation error,**
//     **it is almost always because you forgot to add the `MQL5_Json::` prefix**
//     **to the types and functions.**
//
// [!!] 2.2 Memory Management Model
//      `JsonDocument` **owns** the data; `JsonNode` is just a **view**.
//
// [!!] 2.3 Object Passing in MQL5
//      MQL5 requires that all class objects (including `JsonNode`) passed as function
//      arguments **must be passed by reference (using &)**.
//      Incorrect: `void myFunction(MQL5_Json::JsonNode node)`
//      Correct:   `void myFunction(MQL5_Json::JsonNode &node)`
//

//==============================================================================
// 3. API Usage & Examples
//==============================================================================

//--- 3.1. Quick Start -----------------------------------------------
//
// void OnStart()
// {
//     string jsonText = "{ \"name\": \"John Doe\", \"age\": 30, \"isStudent\": false, \"courses\": [\"MQL5\", \"C++\"] }";
//
//     // 1. Parse JSON string (using fully qualified names)
//     MQL5_Json::JsonError error;
//     MQL5_Json::JsonParseOptions options;
//     MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(jsonText, error, options);
//
//     // Always check if the document is valid after parsing
//     if (!doc.IsValid())
//     {
//         Print("Failed to parse JSON: ", error.ToString());
//         return;
//     }
//
//     // 2. Access data
//     MQL5_Json::JsonNode root = doc.GetRoot();
//     string name = root.Get("name").AsString("Unknown");
//     long   age  = root.Get("age").AsInt(0);
//     bool   isStudent = root["isStudent"].AsBool(true); // Using the [] operator
//
//     PrintFormat("Name: %s, Age: %d, Is Student: %s", name, age, isStudent ? "Yes" : "No");
//
//     // 3. Create a new JSON document
//     MQL5_Json::JsonDocument newDoc = MQL5_Json::JsonNewObject();
//     newDoc.GetRoot().Set("status", "OK");
//     newDoc.GetRoot().Set("code", 200);
//
//     // 4. Serialize the new JSON (pretty format)
//     Print("Newly created JSON:\n", newDoc.ToString(true));
// }
//

//--- 3.2. Parsing JSON ----------------------------------------------
//
// void ParseFromStringAndFile()
// {
//     string json_with_comments = "{ \"key\": \"value\", / * comment * / \"key2\": 123, } // trailing comma";
//
//     MQL5_Json::JsonError error;
//     MQL5_Json::JsonParseOptions options;
//     options.allow_trailing_commas = true;
//     options.allow_comments = true;
//
//     MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(json_with_comments, error, options);
//     if (doc.IsValid()) { Print("Flexible parsing successful! Result: ", doc.ToString()); }
//
//     MQL5_Json::JsonDocument docFromFile = MQL5_Json::JsonFromFile("config.json", error, options);
//     if (docFromFile.IsValid()) { Print("Successfully loaded configuration from file."); }
// }
//

//--- 3.3. Creating JSON -----------------------------------------------
//
// void CreateJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//    MQL5_Json::JsonNode root = doc.GetRoot();
//
//    root.Set("product_id", 12345);
//    root.Set("available", true);
//
//    MQL5_Json::JsonNode specs = doc.CreateObjectNode();
//    specs.Set("color", "black");
//    root.Set("specifications", specs);
//
//    MQL5_Json::JsonNode tags = doc.CreateArrayNode();
//    tags.Add("electronics");
//    root.Set("tags", tags);
//
//    Print("Created JSON:\n", doc.ToString(true));
// }
//

//--- 3.4. Accessing & Querying Data --------------------------
//
// void AccessData()
// {
//    string jsonText = "{ \"data\": { \"user_id\": 101, \"tags\": [\"active\"] } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(jsonText, {}, {});
//    if(!doc.IsValid()) return;
//
//    MQL5_Json::JsonNode root = doc.GetRoot();
//
//    long user_id = root["data"]["user_id"].AsInt(-1);
//    string first_tag = root.Get("data").Get("tags").At(0).AsString("default");
//
//    PrintFormat("User ID: %d, First Tag: %s", user_id, first_tag);
// }
//
// void QueryWithJsonPathAndPointer()
// {
//    string text = "{ \"store\": { \"book\": [ { \"title\": \"MQL5 Basics\" } ] } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(text, {}, {});
//    if(!doc.IsValid()) return;
//
//    string title = doc.GetRoot().Query("/store/book/0/title").AsString();
//    Print("JSON Pointer Result: ", title);
//
//    MQL5_Json::JsonNode nodes[];
//    MQL5_Json::JsonError error;
//    int count = doc.GetRoot().SelectNodes(nodes, "$.store.book[*].title", error);
//    if(count > 0) { Print("JSONPath Result: ", nodes[0].AsString()); }
// }
//

//--- 3.5. Modifying Data ----------------------------------------------
//
// void ModifyJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse("{ \"a\": 1, \"b\": 2 }", {}, {});
//    MQL5_Json::JsonNode root = doc.GetRoot();
//    root.Set("a", 100);
//    root.Remove("b");
//    Print("Modified JSON:\n", doc.ToString(true));
// }
//

//--- 3.6. Serialization ------------------------------------------------
//
// void SerializeJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//    doc.GetRoot().Set("message", "hello world");
//
//    string pretty_str = doc.ToString(true);
//    Print("Pretty Format:\n", pretty_str);
//
//    doc.SaveToFile("output.json", true);
// }
//

//==============================================================================
// 4. Advanced Features
//==============================================================================

//--- 4.1. Stream Parsing Large Files (Low Memory Usage) ---
//
// class CTradeCounter : public MQL5_Json::IJsonStreamHandler
// {
//  private:
//    int m_count;
//  public:
//    int GetCount() const { return m_count; }
//    bool OnStartDocument() override { m_count=0; return true; }
//    bool OnString(const string &value) override
//    {
//       if(value == "EURUSD") m_count++;
//       return true;
//    }
//    // (Other empty methods omitted for brevity)
// };
//
// void TestStreamParser()
// {
//    string big_json = "[{\"s\":\"EURUSD\"},{\"s\":\"EURUSD\"}]";
//    MQL5_Json::JsonStreamParser parser;
//    CTradeCounter *handler = new CTradeCounter();
//    MQL5_Json::JsonError error;
//
//    if(parser.Parse(big_json, handler, error, {}))
//       Print("Stream parser found count: ", handler.GetCount());
//    delete handler;
// }
//

//--- 4.2. Merging Documents (JsonMerge) ---
//
// void TestJsonMerge()
// {
//    MQL5_Json::JsonDocument target = MQL5_Json::JsonParse("{ \"a\": 1 }", {}, {});
//    MQL5_Json::JsonDocument patch = MQL5_Json::JsonParse("{ \"b\": 2 }", {}, {});
//    MQL5_Json::JsonDocument result = MQL5_Json::JsonMerge(target, patch);
//    Print("Merge result:\n", result.ToString(true));
// }
//

//--- 4.3. Cloning Documents (Clone) ---
//
// void TestClone()
// {
//    MQL5_Json::JsonDocument base = MQL5_Json::JsonNewObject();
//    base.GetRoot().Set("magic", 12345);
//
//    MQL5_Json::JsonDocument backtest = base.Clone();
//    backtest.GetRoot().Set("magic", 67890);
//
//    Print("Cloned and modified config:\n", backtest.ToString(true));
// }
//

//--- 4.4. Iteration using the Visitor Pattern (ForEach) ---
//
// class CSumVisitor : public MQL5_Json::IJsonArrayVisitor
// {
//  public:
//    double sum;
//    void Visit(int index, const MQL5_Json::JsonNode &item) override
//    {
//       if(item.IsNumber()) sum += item.AsDouble();
//    }
// };
//
// void TestForEach()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse("[10, 20.5, 30]", {}, {});
//    CSumVisitor visitor;
//    doc.GetRoot().ForEach(GetPointer(visitor));
//    Print("Array sum: ", visitor.sum);
// }
//

//--- 4.5. JSONPath - Selecting a Single Node (SelectSingleNode) ---
//
// void TestSelectSingleNode()
// {
//    string text = "{ \"store\": { \"bicycle\": { \"color\": \"red\"} } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(text, {}, {});
//    MQL5_Json::JsonError error;
//    MQL5_Json::JsonNode bike = doc.GetRoot().SelectSingleNode("$.store.bicycle", error);
//    if(bike.IsValid()) { Print("Found bicycle color: ", bike["color"].AsString()); }
// }
//

//==============================================================================
// 5. Design Philosophy & FAQ
//==============================================================================
//
// --- Q: I have correctly #included JsonLib.mqh, so why am I still getting tons of
// ---    `'JsonNode' - declaration without type` compilation errors?
//
// **A: This is the most common integration issue and is 100% caused by improper namespace handling.**
//
//    - **Diagnosis**: The compiler doesn't recognize `JsonNode` because it doesn't know to look inside the `MQL5_Json` namespace.
//    - **Solution**: In your code, modify all calls to `JsonLib` types and functions to their fully qualified form with the `MQL5_Json::` prefix.
//
//    - **Example**:
//      // Incorrect code (will not compile in an .mqh file)
//      JsonDocument doc = JsonNewObject();
//
//      // Correct code (guaranteed to compile)
//      MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//
//    - **Root Cause**: MQL5 does not allow `using namespace` in the global scope of `.mqh` files.
//
//
// --- Q: Why does the function parameter `JsonNode node` cause an `'objects are passed by reference only'` error?
//
// **A: This is a mandatory rule of the MQL5 language.**
//
//    - **The Rule**: MQL5 requires all class objects (including `JsonNode`) to be passed by reference (`&`).
//    - **Solution**: Always use `&` in your function signatures.
//    - **Example**:
//      // Incorrect
//      void ProcessNode(MQL5_Json::JsonNode node);
//
//      // Correct
//      void ProcessNode(MQL5_Json::JsonNode &node);
//

//==============================================================================
// 6. Best Practices & Important Notes
//==============================================================================
//
// To ensure your project integrates smoothly and runs stably, please adhere to the following rules.
//
// 1. **Always Use Fully Qualified Names in `.mqh` Files (Crucial!)**
//    - This is the **number one rule** for successfully integrating `JsonLib` in multi-file projects.
//    - Always use `MQL5_Json::JsonDocument`, `MQL5_Json::JsonNode`, `MQL5_Json::JsonParse`, etc.
//
// 2. **Class Object Parameters Must Be Passed by Reference**
//    - When you write a function that needs to accept a `JsonNode` as a parameter, you must declare it as a reference (`&`).
//    - `void myFunction(MQL5_Json::JsonNode &node);` // Correct
//    - This is to comply with MQL5's language rules and will prevent the `'objects are passed by reference only'` compilation error.
//
// 3. **Memory and Object Lifecycle**
//    - `JsonDocument` **owns** the data; `JsonNode` is just a **view**.
//    - If a `JsonDocument` is destroyed, all of its `JsonNode`s become **invalid**.
//
// 4. **Robust Coding and Error Handling**
//    - After calling `JsonParse`, **always check `doc.IsValid()`**.
//
*/
//+------------------------------------------------------------------+

#include "Core/JsonCore.mqh"
#include "Core/JsonNode.mqh"
#include "Core/JsonDocument.mqh"
#include "Core/JsonStreamParser.mqh"
#include "Core/JsonApiImpl.mqh"

#endif // MQL5_JSON_LIBRARY_V10_H
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| MQL5 JSON Library - Developer's Manual                           |
//| Author: ding9736                                                 |
//| Version: 10.0                                                    |
//+------------------------------------------------------------------+

//==============================================================================
// 1. Overview
//==============================================================================
//
// The MQL5 JSON Library is a powerful, feature-rich library designed specifically
// for parsing, manipulating, and serializing JSON data within the MQL5
// environment. It provides a simple and intuitive Document Object Model (DOM) API,
// aiming to make the JSON handling experience in MQL5 comparable to modern
// programming languages like JavaScript and Python.
//
// This library is capable of handling a wide range of tasks, from reading simple
// EA configurations to complex real-time data exchange between systems.
// Its main functions and features include:
//
//   --- Parsing and Creation ---
//
//   - **Load from String or File**: Reliably parses JSON text into manipulable
//     in-memory objects (`JsonParse`, `JsonFromFile`).
//   - **Build from Scratch**: Easily create new JSON objects and arrays
//     programmatically using concise APIs like `JsonNewObject` and `JsonNewArray`.
//   - **Flexible Parser**: Optionally supports some non-standard features of JSON5,
//     such as code comments and trailing commas, to enhance compatibility with
//     various data sources.
//
//   --- Manipulation and Access ---
//
//   - **Intuitive DOM Traversal**: Access data using intuitive syntax with keys
//     (`node["key"]`) and indices (`node[0]`), just like using a Python dictionary
//     or a JavaScript object.
//   - **Safe Type Conversion**: Provides a series of methods with default values,
//     such as `AsInt(defaultValue)` and `AsString(defaultValue)`, allowing you
//     to safely extract data of the desired type from a node without worrying
//     about program crashes due to type mismatches or non-existent paths.
//   - **Dynamic Modification**: Freely add, update, or delete key-value pairs
//     in JSON objects and elements in arrays (`Set`, `Add`, `Remove`).
//
//   --- Advanced Querying and Processing ---
//
//   - **Powerful Query Engine**: Built-in support for **JSON Pointer** (RFC 6901,
//     for direct path access) and **JSONPath** (for complex and fuzzy queries),
//     enabling efficient extraction of one or more data nodes from deeply
//     nested, complex structures, either in bulk or with precision.
//   - **Low-Memory Stream Parsing**: Provides `JsonStreamParser` for processing
//     gigabyte-scale, huge JSON files. It reads the file token by token in an
//     event stream manner without loading the entire file into memory, thus
//     achieving ultimate memory efficiency.
//   - **Utility Functions**: Offers advanced features like document cloning (`.Clone()`)
//     and deep merging (`JsonMerge`), which greatly simplify common complex tasks
//     such as merging "default configuration" with "user configuration".
//
//   --- Robustness and Safety ---
//
//   - **Automatic Memory Management**: Adopts the RAII (Resource Acquisition Is
//     Initialization) design pattern. `JsonDocument` is responsible for managing
//     the lifecycle of all its nodes. Developers do not need to manually `new`/`delete`
//     any JSON elements, fundamentally eliminating the risk of memory leaks.
//   - **Cross-Document Operation Safety**: When assigning a node between different
//     `JsonDocument` instances, the library automatically performs a safe deep
//     copy (Clone), preventing dangling pointers and accidental data corruption.
//   - **Detailed Error Reporting**: When parsing fails, the `JsonError` object
//     provides detailed information including the error line number, column number,
//     and context, facilitating rapid problem diagnosis.
//

//==============================================================================
// 2. Core Concepts & Memory Management
//==============================================================================
//
// [!!] 2.1 Namespace - The Key to Integrating Your Project [!!]
//     **Most Important Tip**: All classes in this library (e.g., `JsonDocument`,
//     `JsonNode`) and global functions (e.g., `JsonParse`) are encapsulated
//     within a namespace called `MQL5_Json`.
//
//     **How to Use It Correctly:**
//
//     - **In Header Files (.mqh)**: MQL5 does not allow `using namespace` in the
//       global scope of header files. **Therefore, you must use fully qualified names**.
//       This is the only reliable way in multi-file projects.
//       Incorrect: `JsonDocument doc;`
//       Correct:   `MQL5_Json::JsonDocument doc;`
//
//     - **Inside Functions in Main Program Files (.mq5)**: For convenience, you can use
//       `using namespace MQL5_Json;` inside functions, but to ensure the
//       generality of the examples, all code in this manual will use the fully
//       qualified name approach.
//
//     **If you encounter the `'JsonNode' - declaration without type` compilation error,**
//     **it is almost always because you forgot to add the `MQL5_Json::` prefix**
//     **to the types and functions.**
//
// [!!] 2.2 Memory Management Model
//      `JsonDocument` **owns** the data; `JsonNode` is just a **view**.
//
// [!!] 2.3 Object Passing in MQL5
//      MQL5 requires that all class objects (including `JsonNode`) passed as function
//      arguments **must be passed by reference (using &)**.
//      Incorrect: `void myFunction(MQL5_Json::JsonNode node)`
//      Correct:   `void myFunction(MQL5_Json::JsonNode &node)`
//

//==============================================================================
// 3. API Usage & Examples
//==============================================================================

//--- 3.1. Quick Start -----------------------------------------------
//
// void OnStart()
// {
//     string jsonText = "{ \"name\": \"John Doe\", \"age\": 30, \"isStudent\": false, \"courses\": [\"MQL5\", \"C++\"] }";
//
//     // 1. Parse JSON string (using fully qualified names)
//     MQL5_Json::JsonError error;
//     MQL5_Json::JsonParseOptions options;
//     MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(jsonText, error, options);
//
//     // Always check if the document is valid after parsing
//     if (!doc.IsValid())
//     {
//         Print("Failed to parse JSON: ", error.ToString());
//         return;
//     }
//
//     // 2. Access data
//     MQL5_Json::JsonNode root = doc.GetRoot();
//     string name = root.Get("name").AsString("Unknown");
//     long   age  = root.Get("age").AsInt(0);
//     bool   isStudent = root["isStudent"].AsBool(true); // Using the [] operator
//
//     PrintFormat("Name: %s, Age: %d, Is Student: %s", name, age, isStudent ? "Yes" : "No");
//
//     // 3. Create a new JSON document
//     MQL5_Json::JsonDocument newDoc = MQL5_Json::JsonNewObject();
//     newDoc.GetRoot().Set("status", "OK");
//     newDoc.GetRoot().Set("code", 200);
//
//     // 4. Serialize the new JSON (pretty format)
//     Print("Newly created JSON:\n", newDoc.ToString(true));
// }
//

//--- 3.2. Parsing JSON ----------------------------------------------
//
// void ParseFromStringAndFile()
// {
//     string json_with_comments = "{ \"key\": \"value\", / * comment * / \"key2\": 123, } // trailing comma";
//
//     MQL5_Json::JsonError error;
//     MQL5_Json::JsonParseOptions options;
//     options.allow_trailing_commas = true;
//     options.allow_comments = true;
//
//     MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(json_with_comments, error, options);
//     if (doc.IsValid()) { Print("Flexible parsing successful! Result: ", doc.ToString()); }
//
//     MQL5_Json::JsonDocument docFromFile = MQL5_Json::JsonFromFile("config.json", error, options);
//     if (docFromFile.IsValid()) { Print("Successfully loaded configuration from file."); }
// }
//

//--- 3.3. Creating JSON -----------------------------------------------
//
// void CreateJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//    MQL5_Json::JsonNode root = doc.GetRoot();
//
//    root.Set("product_id", 12345);
//    root.Set("available", true);
//
//    MQL5_Json::JsonNode specs = doc.CreateObjectNode();
//    specs.Set("color", "black");
//    root.Set("specifications", specs);
//
//    MQL5_Json::JsonNode tags = doc.CreateArrayNode();
//    tags.Add("electronics");
//    root.Set("tags", tags);
//
//    Print("Created JSON:\n", doc.ToString(true));
// }
//

//--- 3.4. Accessing & Querying Data --------------------------
//
// void AccessData()
// {
//    string jsonText = "{ \"data\": { \"user_id\": 101, \"tags\": [\"active\"] } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(jsonText, {}, {});
//    if(!doc.IsValid()) return;
//
//    MQL5_Json::JsonNode root = doc.GetRoot();
//
//    long user_id = root["data"]["user_id"].AsInt(-1);
//    string first_tag = root.Get("data").Get("tags").At(0).AsString("default");
//
//    PrintFormat("User ID: %d, First Tag: %s", user_id, first_tag);
// }
//
// void QueryWithJsonPathAndPointer()
// {
//    string text = "{ \"store\": { \"book\": [ { \"title\": \"MQL5 Basics\" } ] } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(text, {}, {});
//    if(!doc.IsValid()) return;
//
//    string title = doc.GetRoot().Query("/store/book/0/title").AsString();
//    Print("JSON Pointer Result: ", title);
//
//    MQL5_Json::JsonNode nodes[];
//    MQL5_Json::JsonError error;
//    int count = doc.GetRoot().SelectNodes(nodes, "$.store.book[*].title", error);
//    if(count > 0) { Print("JSONPath Result: ", nodes[0].AsString()); }
// }
//

//--- 3.5. Modifying Data ----------------------------------------------
//
// void ModifyJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse("{ \"a\": 1, \"b\": 2 }", {}, {});
//    MQL5_Json::JsonNode root = doc.GetRoot();
//    root.Set("a", 100);
//    root.Remove("b");
//    Print("Modified JSON:\n", doc.ToString(true));
// }
//

//--- 3.6. Serialization ------------------------------------------------
//
// void SerializeJson()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//    doc.GetRoot().Set("message", "hello world");
//
//    string pretty_str = doc.ToString(true);
//    Print("Pretty Format:\n", pretty_str);
//
//    doc.SaveToFile("output.json", true);
// }
//

//==============================================================================
// 4. Advanced Features
//==============================================================================

//--- 4.1. Stream Parsing Large Files (Low Memory Usage) ---
//
// class CTradeCounter : public MQL5_Json::IJsonStreamHandler
// {
//  private:
//    int m_count;
//  public:
//    int GetCount() const { return m_count; }
//    bool OnStartDocument() override { m_count=0; return true; }
//    bool OnString(const string &value) override
//    {
//       if(value == "EURUSD") m_count++;
//       return true;
//    }
//    // (Other empty methods omitted for brevity)
// };
//
// void TestStreamParser()
// {
//    string big_json = "[{\"s\":\"EURUSD\"},{\"s\":\"EURUSD\"}]";
//    MQL5_Json::JsonStreamParser parser;
//    CTradeCounter *handler = new CTradeCounter();
//    MQL5_Json::JsonError error;
//
//    if(parser.Parse(big_json, handler, error, {}))
//       Print("Stream parser found count: ", handler.GetCount());
//    delete handler;
// }
//

//--- 4.2. Merging Documents (JsonMerge) ---
//
// void TestJsonMerge()
// {
//    MQL5_Json::JsonDocument target = MQL5_Json::JsonParse("{ \"a\": 1 }", {}, {});
//    MQL5_Json::JsonDocument patch = MQL5_Json::JsonParse("{ \"b\": 2 }", {}, {});
//    MQL5_Json::JsonDocument result = MQL5_Json::JsonMerge(target, patch);
//    Print("Merge result:\n", result.ToString(true));
// }
//

//--- 4.3. Cloning Documents (Clone) ---
//
// void TestClone()
// {
//    MQL5_Json::JsonDocument base = MQL5_Json::JsonNewObject();
//    base.GetRoot().Set("magic", 12345);
//
//    MQL5_Json::JsonDocument backtest = base.Clone();
//    backtest.GetRoot().Set("magic", 67890);
//
//    Print("Cloned and modified config:\n", backtest.ToString(true));
// }
//

//--- 4.4. Iteration using the Visitor Pattern (ForEach) ---
//
// class CSumVisitor : public MQL5_Json::IJsonArrayVisitor
// {
//  public:
//    double sum;
//    void Visit(int index, const MQL5_Json::JsonNode &item) override
//    {
//       if(item.IsNumber()) sum += item.AsDouble();
//    }
// };
//
// void TestForEach()
// {
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse("[10, 20.5, 30]", {}, {});
//    CSumVisitor visitor;
//    doc.GetRoot().ForEach(GetPointer(visitor));
//    Print("Array sum: ", visitor.sum);
// }
//

//--- 4.5. JSONPath - Selecting a Single Node (SelectSingleNode) ---
//
// void TestSelectSingleNode()
// {
//    string text = "{ \"store\": { \"bicycle\": { \"color\": \"red\"} } }";
//    MQL5_Json::JsonDocument doc = MQL5_Json::JsonParse(text, {}, {});
//    MQL5_Json::JsonError error;
//    MQL5_Json::JsonNode bike = doc.GetRoot().SelectSingleNode("$.store.bicycle", error);
//    if(bike.IsValid()) { Print("Found bicycle color: ", bike["color"].AsString()); }
// }
//

//==============================================================================
// 5. Design Philosophy & FAQ
//==============================================================================
//
// --- Q: I have correctly #included JsonLib.mqh, so why am I still getting tons of
// ---    `'JsonNode' - declaration without type` compilation errors?
//
// **A: This is the most common integration issue and is 100% caused by improper namespace handling.**
//
//    - **Diagnosis**: The compiler doesn't recognize `JsonNode` because it doesn't know to look inside the `MQL5_Json` namespace.
//    - **Solution**: In your code, modify all calls to `JsonLib` types and functions to their fully qualified form with the `MQL5_Json::` prefix.
//
//    - **Example**:
//      // Incorrect code (will not compile in an .mqh file)
//      JsonDocument doc = JsonNewObject();
//
//      // Correct code (guaranteed to compile)
//      MQL5_Json::JsonDocument doc = MQL5_Json::JsonNewObject();
//
//    - **Root Cause**: MQL5 does not allow `using namespace` in the global scope of `.mqh` files.
//
//
// --- Q: Why does the function parameter `JsonNode node` cause an `'objects are passed by reference only'` error?
//
// **A: This is a mandatory rule of the MQL5 language.**
//
//    - **The Rule**: MQL5 requires all class objects (including `JsonNode`) to be passed by reference (`&`).
//    - **Solution**: Always use `&` in your function signatures.
//    - **Example**:
//      // Incorrect
//      void ProcessNode(MQL5_Json::JsonNode node);
//
//      // Correct
//      void ProcessNode(MQL5_Json::JsonNode &node);
//

//==============================================================================
// 6. Best Practices & Important Notes
//==============================================================================
//
// To ensure your project integrates smoothly and runs stably, please adhere to the following rules.
//
// 1. **Always Use Fully Qualified Names in `.mqh` Files (Crucial!)**
//    - This is the **number one rule** for successfully integrating `JsonLib` in multi-file projects.
//    - Always use `MQL5_Json::JsonDocument`, `MQL5_Json::JsonNode`, `MQL5_Json::JsonParse`, etc.
//
// 2. **Class Object Parameters Must Be Passed by Reference**
//    - When you write a function that needs to accept a `JsonNode` as a parameter, you must declare it as a reference (`&`).
//    - `void myFunction(MQL5_Json::JsonNode &node);` // Correct
//    - This is to comply with MQL5's language rules and will prevent the `'objects are passed by reference only'` compilation error.
//
// 3. **Memory and Object Lifecycle**
//    - `JsonDocument` **owns** the data; `JsonNode` is just a **view**.
//    - If a `JsonDocument` is destroyed, all of its `JsonNode`s become **invalid**.
//
// 4. **Robust Coding and Error Handling**
//    - After calling `JsonParse`, **always check `doc.IsValid()`**.
//
Multi_Divergence_EA Multi_Divergence_EA

The EA identifies trade setups by waiting for a user-defined number of indicators (e.g., 2 out of 3) to show divergence simultaneously. This multi-layer confirmation approach filters out market noise. Key Features: Triple Confirmation Engine: Analyzes RSI, MACD, & Stochastic divergence. Advanced Filters: Optional Trend Filter (MA) and Volume Filter for superior signal quality. Full Customization: Control all indicator settings, divergence sensitivity, and trade logic. Professional Risk Management: Use fixed lots or percentage-based money management with SL/TP.

Average Range Average Range

It is an indicator that determines target levels according to the average of price movements.

Accelerator Oscillator (AC) Accelerator Oscillator (AC)

The Acceleration/Deceleration Indicator (AC) measures acceleration and deceleration of the current driving force.

MACD Signals MACD Signals

Indicator edition for new platform.