JAson.mqhで学ぶ:用語解説/基礎知識/実践サンプル集(2025年版)
「MQL5では基本的にJSONを使わない」と言われますが、外部APIとの連携や設定ファイルの管理では非常に便利です。この記事では完全に初心者向けに、以下の内容を詳しく解説します:
- JSONとは何か?(オブジェクト/配列/プリミティブの基礎)
- MQL5のJSONライブラリ(JAson.mqh)の使い方
- 実際に動く安全なサンプルコード(よくある間違いを修正済み)
参照ライブラリ: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/long | 123 |
| 数値(小数) | double | 1.23 |
| 真偽値 | bool | true |
| null | — | null |
2. MQL5でJSONを使う準備
2-1. ライブラリのインストール
- ダウンロード:
MQL5記事の JSON Serialization and Deserialization (native MQL) からJAson.mqhを取得 - 配置場所:
C:\Users\[ユーザー名]\AppData\Roaming\MetaQuotes\Terminal\[ID]\MQL5\Include\
ここに JAson.mqh を保存
- インクルード:ソースコード冒頭に以下を記載
#include <JAson.mqh>
2-2. WebRequest を使う場合の設定
外部APIと通信する場合は、MT5の設定が必要です:
- メニュー:
ツール→オプション - タブ:
Expert Advisors - 設定:
WebRequestを許可するURLリストにチェック - 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}]
仕組み:
New()で配列に未定義の空要素を追加- 返されたポインタに
["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つのポイント
- JSONの構造
- オブジェクト:
{ "key": value } - 配列:
[ value1, value2 ] - プリミティブ:文字列・数値・真偽・null
- 基本操作
- 作成:
js["key"] = value;/js.Add(value); - 変換:
Serialize()/Deserialize(json, CP_UTF8) - 取得:
ToInt()/ToDbl()/ToStr()/ToBool()
- 安全な実装
- UTF-8を必ず指定
HasKey()で存在確認- 数値の桁数を意識
参考リンク
- ライブラリ:JAson.mqh(CodeBase)
- MQL5公式:WebRequest ドキュメント
- JSON仕様:json.org