PR

【MQL5】JSON初心者向けガイド

MQL5記事

JAson.mqhで学ぶ:用語解説/基礎知識/実践サンプル集(2025年版)

「MQL5では基本的にJSONを使わない」と言われますが、外部APIとの連携設定ファイルの管理では非常に便利です。この記事では完全に初心者向けに、以下の内容を詳しく解説します:

  1. JSONとは何か?(オブジェクト/配列/プリミティブの基礎)
  2. MQL5のJSONライブラリ(JAson.mqh)の使い方
  3. 実際に動く安全なサンプルコード(よくある間違いを修正済み)

参照ライブラリJSON Serialization and Deserialization (native MQL)(CodeBase)
ライセンス:MIT(商用利用・改変可能)


1. JSONとは?超やさしい基本

1-1. JSONの最小構成

JSON(JavaScript Object Notation)は、データをテキストで表現するフォーマットです。以下の3つの要素で構成されます:

オブジェクト(Object)

{
  "symbol": "EURUSD",
  "risk": 1.5
}
  • { } で囲まれた「キー」と「値」のペアの集まり
  • キーは必ず文字列(ダブルクォートで囲む)
  • 値は何でもOK(文字列、数値、真偽値、null、オブジェクト、配列)

配列(Array)

[1.1000, 1.1050, 1.1100]
  • [ ] で囲まれた値の並び
  • 順序があり、インデックス(0始まり)でアクセス

プリミティブ(Primitive)

  • 文字列"EURUSD" (ダブルクォート必須)
  • 数値123 / 1.23 (整数・小数)
  • 真偽値true / false
  • null:値なし

1-2. 「キー」と「値」をもう一度

初心者が最初につまずくのがキーと値の関係です:

{
  "price": 1.2345,
  "symbol": "USDJPY",
  "active": true
}
キー(Key)値(Value)
"price"1.2345数値(double)
"symbol""USDJPY"文字列(string)
"active"true真偽値(bool)

重要

  • キーは必ず文字列
  • 値はどの型でもOK
  • MQL5の変数に置き換えると、変数名 = 値 のイメージ

1-3. そもそも「プリミティブ」とは?

これ以上分解できない”素の値”のことです:

JSON型MQL5型
文字列string"Hello"
数値(整数)int/long123
数値(小数)double1.23
真偽値booltrue
nullnull

2. MQL5でJSONを使う準備

2-1. ライブラリのインストール

  1. ダウンロード
    MQL5記事の JSON Serialization and Deserialization (native MQL) から JAson.mqh を取得
  2. 配置場所
   C:\Users\[ユーザー名]\AppData\Roaming\MetaQuotes\Terminal\[ID]\MQL5\Include\

ここに JAson.mqh を保存

  1. インクルード:ソースコード冒頭に以下を記載
   #include <JAson.mqh>

2-2. WebRequest を使う場合の設定

外部APIと通信する場合は、MT5の設定が必要です:

  1. メニューツールオプション
  2. タブExpert Advisors
  3. 設定WebRequestを許可するURLリスト にチェック
  4. URL追加:例)https://api.example.com

注意:この設定を忘れると、WebRequest がエラーコード 4014(「WebRequestが許可されていません」)で失敗します。


2-3. 文字コードの重要性

重要:Web APIのほとんどは UTF-8 を使用します。

// ❌ 間違い(デフォルトはCP_ACP = Shift-JISなど)
root.Deserialize(json);

// ✅ 正しい(UTF-8を明示)
root.Deserialize(json, CP_UTF8);

理由

  • ライブラリは静的変数 CJAVal::code_page でエンコーディングを管理
  • UTF-8を指定しないと日本語や特殊文字が文字化けします

3. JAson.mqhの基本概念

3-1. 「1つのクラスで何でも表現」という発想

JAson.mqhは CJAVal という1つのクラスで、以下のすべてを扱えます:

  • オブジェクト(OBJ
  • 配列(ARRAY
  • 文字列(STR
  • 整数(INT
  • 小数(DBL
  • 真偽値(BOOL
  • null(NULL

内部的には enJAType 列挙型で型を管理しています。


3-2. よく使うメソッド一覧(チートシート)

メソッド説明
Serialize()JSON → 文字列に変換string json = js.Serialize();
Deserialize(string, CP_UTF8)文字列 → JSONに変換root.Deserialize(json, CP_UTF8);
ToInt()整数に変換int val = js["count"].ToInt();
ToDbl()小数に変換double price = js["price"].ToDbl();
ToStr()文字列に変換string sym = js["symbol"].ToStr();
ToBool()真偽値に変換bool flag = js["active"].ToBool();
Add(value)配列に要素追加js["arr"].Add(123);
New()配列に空要素追加CJAVal* p = js.New();
HasKey(key, type)キーの存在と型確認if(js.HasKey("risk", jtDBL) != NULL)

3-3. 自動型変換の仕組み

CJAVal js;           // 初期状態:jtUNDEF(未定義)

js["key"] = "abc";   // 文字列を代入 → 自動的にjtOBJに
js["arr"].Add(123);  // Add使用 → 自動的にjtARRAYに

初心者向けポイント

  • 最初に型を宣言する必要はありません
  • 使い方によって自動で適切な型になります

4. 最初の一歩:JSONを作って読む

4-1. オブジェクトを作る → 文字列化(Serialize)

#include <JAson.mqh>

void OnStart()
{
   CJAVal js;

   // 基本的な値の設定
   js["symbol"]  = "EURUSD";
   js["risk"]    = 1.5;      // デフォルトで8桁 → 1.50000000
   js["enabled"] = true;

   // 配列(小数点4桁に指定)
   js["levels"].Add(CJAVal(1.1000, 4));
   js["levels"].Add(CJAVal(1.1050, 4));

   // JSON文字列に変換
   string output = js.Serialize();
   Print(output);

   // 出力例:
   // {"symbol":"EURUSD","risk":1.50000000,"enabled":true,"levels":[1.1000,1.1050]}
}

重要

  • 数値のデフォルト精度は 8桁
  • 桁数を指定したい場合は CJAVal(value, digits) を使用

4-2. 文字列からJSONを読み込む(Deserialize)

#include <JAson.mqh>

void OnStart()
{
   string json_text = "{\"a\":[1,2,3],\"sym\":\"USDJPY\",\"price\":110.50}";

   CJAVal root;

   // JSON文字列を解析(UTF-8指定)
   if(root.Deserialize(json_text, CP_UTF8))
   {
      // 配列の要素を取得
      int first = (int)root["a"][0].ToInt();        // 1

      // 文字列を取得
      string symbol = root["sym"].ToStr();     // "USDJPY"

      // 小数を取得
      double price = root["price"].ToDbl();    // 110.50

      Print("first=", first, " symbol=", symbol, " price=", price);
   }
   else
   {
      Print("JSON解析エラー");
   }
}

4-3. キーの存在確認(HasKey)

間違いやすいポイント:キーが存在しない場合のエラー対策

CJAVal cfg;
cfg.Deserialize("{\"enabled\":true,\"risk\":1.2}", CP_UTF8);

// ❌ 危険:キーが存在しない場合、予期しない値が返る
double risk = cfg["unknown"].ToDbl();  // 0.0が返る

// ✅ 安全:存在と型を確認してから取得
if(cfg.HasKey("risk", jtDBL) != NULL)
{
   double risk = cfg["risk"].ToDbl();
   Print("risk=", risk);
}
else
{
   Print("キー 'risk' が見つかりません");
}

ポイント

  • HasKey(key, type) はキーが存在し、かつ型が一致する場合にポインタを返す
  • NULL でない場合のみ値を取得するのが安全

5. 実践:アカウント情報をJSONで管理する

WebRequestを使う前に、まずは身近なデータでJSONの使い方に慣れましょう。
ここでは、MT5の口座情報をJSONで整理して、ログに出力する例を紹介します。

5-1. 口座情報を収集してJSONに格納

#include <JAson.mqh>

void OnStart()
{
   // --- 1. 口座情報を取得(MT5の組み込み関数を使用)
   long    account_number  = AccountInfoInteger(ACCOUNT_LOGIN);
   string  account_name    = AccountInfoString(ACCOUNT_NAME);
   string  account_server  = AccountInfoString(ACCOUNT_SERVER);
   double  account_balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double  account_equity  = AccountInfoDouble(ACCOUNT_EQUITY);
   double  account_margin  = AccountInfoDouble(ACCOUNT_MARGIN);
   string  account_currency= AccountInfoString(ACCOUNT_CURRENCY);
   
   // --- 2. JSONオブジェクトを作成
   CJAVal account_data;
   
   // 基本情報
   account_data["account"]["number"]   = (int)account_number;
   account_data["account"]["name"]     = account_name;
   account_data["account"]["server"]   = account_server;
   account_data["account"]["currency"] = account_currency;
   
   // 残高情報(小数点2桁で指定)
   account_data["balance"]["balance"] = CJAVal(account_balance, 2);
   account_data["balance"]["equity"]  = CJAVal(account_equity, 2);
   account_data["balance"]["margin"]  = CJAVal(account_margin, 2);
   
   // タイムスタンプ(現在時刻)
   account_data["timestamp"] = TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS);
   
   // --- 3. JSON文字列に変換
   string json_output = account_data.Serialize();
   
   // --- 4. ログに出力
   Print("=== 口座情報(JSON形式) ===");
   Print(json_output);
   
   // --- 5. 整形して見やすく表示(オプション)
   Print("\n=== 整形表示 ===");
   Print("口座番号: ", account_number);
   Print("口座名義: ", account_name);
   Print("サーバー: ", account_server);
   Print("残高: ", DoubleToString(account_balance, 2), " ", account_currency);
   Print("有効証拠金: ", DoubleToString(account_equity, 2), " ", account_currency);
}

【出力結果例】
=== 口座情報(JSON形式) ===
{"account":{"number":12345678,"name":"Taro Yamada","server":"Demo-Server","currency":"USD"},"balance":{"balance":10000.00,"equity":10050.50,"margin":200.00},"timestamp":"2025.01.31 14:19:55"}

=== 整形表示 ===
口座番号: 12345678
口座名義: Taro Yamada
サーバー: Demo-Server
残高: 10000.00 USD
有効証拠金: 10050.50 USD

6. よく使うパターン集

6-1. 配列にオブジェクトを追加(New()の使い方)

CJAVal orders;

// 注文1を追加
CJAVal* order1 = orders.New();  // ordersが自動的に配列に
order1["id"]     = 1001;        // order1が自動的にオブジェクトに
order1["symbol"] = "USDJPY";
order1["volume"] = 0.10;

// 注文2を追加
CJAVal* order2 = orders.New();
order2["id"]     = 1002;
order2["symbol"] = "EURUSD";
order2["volume"] = 0.20;

Print(orders.Serialize());
// 出力:[{"id":1001,"symbol":"USDJPY","volume":0.10000000},{"id":1002,"symbol":"EURUSD","volume":0.20000000}]

仕組み

  1. New() で配列に未定義の空要素を追加
  2. 返されたポインタに ["key"] でアクセス → 自動的にオブジェクト化

6-2. 数値の小数点桁数を指定

CJAVal root;

// パターン1:コンストラクタで指定(推奨)
root["price"] = CJAVal(1.23456, 5);  // 5桁
Print(root.Serialize());  // → {"price":1.23456}

// パターン2:メンバ変数に直接設定(上級者向け)
root["price"] = 1.23456;
root["price"].m_prec = 5;
Print(root.Serialize());  // → {"price":1.23456}

デフォルトm_prec = 8(8桁)


6-3. 入れ子のオブジェクト

CJAVal config;

config["server"]["host"] = "api.example.com";
config["server"]["port"] = 443;
config["server"]["ssl"]  = true;

config["user"]["name"]  = "trader";
config["user"]["level"] = 5;

Print(config.Serialize());
// 出力:{"server":{"host":"api.example.com","port":443,"ssl":true},"user":{"name":"trader","level":5}}

6-4. 配列のループ処理

string json = "{\"prices\":[1.1000, 1.1050, 1.1100]}";

CJAVal root;
root.Deserialize(json, CP_UTF8);

CJAVal* prices = root.FindKey("prices");
if(prices != NULL && prices.m_type == jtARRAY)
{
   int count = prices.Size();
   for(int i = 0; i < count; i++)
   {
      double price = prices[i].ToDbl();
      Print("Price[", i, "] = ", price);
   }
}

7. 初心者が必ず通る落とし穴

7-1. 空文字列は null になる

CJAVal js;
js["empty"] = "";

Print(js.Serialize());  // → {"empty":null}  ← "" ではなく null!

理由:ライブラリの Serialize() 実装で、エスケープ後の文字列長が0の場合に null を出力

対策

// 空文字を保持したい場合
js["empty"] = " ";  // スペース1つ

// または、ライブラリを修正(上級者向け)
// Serialize() の該当行を変更:
// if (StringLen(ss)>=0) js+=StringFormat("\"%s\"", ss);

7-2. 配列の飛び番アクセス

CJAVal arr;
arr[0] = 10;
arr[5] = 50;  // インデックス1〜4は未定義のまま確保される

Print("Size=", arr.Size());  // → 6
Print(arr.Serialize());      // → [10,null,null,null,null,50]

対策Add() で順番に追加するのが安全


7-3. UTF-8指定を忘れる

// ❌ 文字化けする
StringToCharArray(body, data);                      // デフォルトはCP_ACP
CharArrayToString(response_data);                   // デフォルトはCP_ACP
root.Deserialize(json);                             // デフォルトはCP_ACP

// ✅ 正しい
StringToCharArray(body, data, 0, WHOLE_ARRAY, CP_UTF8);
CharArrayToString(response_data, 0, WHOLE_ARRAY, CP_UTF8);
root.Deserialize(json, CP_UTF8);

7-4. 数値の桁数を意識しない

CJAVal js;
js["price"] = 1.23;

Print(js.Serialize());  // → {"price":1.23000000}  ← デフォルト8桁

対策

js["price"] = CJAVal(1.23, 2);  // 2桁に指定
Print(js.Serialize());  // → {"price":1.23}

7-5. CheckPointer の不要な使用

// ❌ 冗長(HasKeyが既にNULLチェック済み)
CJAVal* p = cfg.HasKey("risk", jtDBL);
if(CheckPointer(p) != POINTER_INVALID)  // 不要
   Print(p.ToDbl());

// ✅ シンプル
if(cfg.HasKey("risk", jtDBL) != NULL)
   Print(cfg["risk"].ToDbl());

8. まとめ

覚えるべき3つのポイント

  1. JSONの構造
  • オブジェクト:{ "key": value }
  • 配列:[ value1, value2 ]
  • プリミティブ:文字列・数値・真偽・null
  1. 基本操作
  • 作成:js["key"] = value; / js.Add(value);
  • 変換:Serialize() / Deserialize(json, CP_UTF8)
  • 取得:ToInt() / ToDbl() / ToStr() / ToBool()
  1. 安全な実装
  • UTF-8を必ず指定
  • HasKey() で存在確認
  • 数値の桁数を意識

参考リンク

タイトルとURLをコピーしました