MQL5の文字列関数を完全網羅。StringFind・StringFormat・StringSplit・StringReplaceなど、EA開発で使うすべての文字列操作をコード付きで解説します。ログ出力、トレードコメント生成、CSV解析、設定ファイルのパースまで、実践的なパターンを豊富に紹介。MQL4との違いも併記しています。
MQL5文字列の基礎知識
MQL5の文字列(string型)はUnicodeベースで、日本語を含むマルチバイト文字を正しく処理できます。C++のstd::stringに近い使い勝手ですが、MQL5独自の関数群で操作します。
// 文字列の宣言と初期化
string str1 = "Hello MQL5";
string str2 = ""; // 空文字列
string str3 = NULL; // NULL文字列(空文字列とは異なる)
// 文字列の結合(+演算子)
string result = "Price: " + DoubleToString(1.2345, 4);
// result = "Price: 1.2345"
// 文字列の比較
if(str1 == "Hello MQL5") Print("一致"); // ==で比較可能
if(str1 != str2) Print("不一致");
// 日本語文字列
string jpStr = "移動平均線";
Print("文字数: ", StringLen(jpStr)); // 5(Unicodeなので正確)MQL4とMQL5の文字列の違い
| 項目 | MQL4 | MQL5 |
|---|---|---|
| エンコーディング | ANSI(1バイト) | Unicode(2バイト) |
| StringSplit | 対応 | 対応 |
| StringFormat | 対応(ビルド600+) | 対応(C言語のsprintfと同等) |
| StringReplace | 対応(MQL4ビルド600+) | 対応 |
| StringToCharArray | ANSI文字配列 | UTF-8またはANSI選択可 |
| StringGetCharacter | 対応 | 対応(Unicode値を返す) |
| StringSetCharacter | 対応 | 対応 |
| StringCompare | 対応 | 対応(大小比較可能) |
StringLen — 文字列の長さ
int StringLen(
string string_value // 対象の文字列
);
// 戻り値: 文字数(NULL文字列の場合は0)
// 使用例
string s = "USDJPY";
Print(StringLen(s)); // 6
string jp = "ドル円";
Print(StringLen(jp)); // 3(Unicodeなので正確)
// 空チェック
string comment = "";
if(StringLen(comment) == 0)
Print("コメントは空です");
// NULLチェック
string nullStr = NULL;
if(nullStr == NULL)
Print("NULL文字列です"); // これが出力される
Print(StringLen(nullStr)); // 0StringFind — 文字列の検索
文字列内で指定したパターンを検索し、最初に見つかった位置を返します。見つからない場合は-1を返します。
int StringFind(
string string_value, // 検索対象の文字列
string match_substring, // 検索する部分文字列
int start_pos = 0 // 検索開始位置
);
// 戻り値: 見つかった位置(0ベース)、見つからない場合 -1
// 基本使用
string comment = "MA_Cross_Buy_USDJPY";
int pos = StringFind(comment, "Buy");
if(pos >= 0)
Print("'Buy'が位置", pos, "に見つかりました"); // 位置9
// 複数回検索(全出現位置を取得)
void FindAll(string str, string pattern)
{
int startPos = 0;
int found;
while((found = StringFind(str, pattern, startPos)) >= 0)
{
Print("位置 ", found, " に発見");
startPos = found + 1;
}
}
// トレードコメントの解析
bool IsMyTrade(string comment, string eaName)
{
return StringFind(comment, eaName) >= 0;
}StringSubstr — 部分文字列の抽出
string StringSubstr(
string string_value, // 対象の文字列
int start_pos, // 開始位置(0ベース)
int length = -1 // 抽出する文字数(-1=最後まで)
);
// 戻り値: 抽出された部分文字列
// 基本使用
string symbol = "USDJPY_micro";
string base = StringSubstr(symbol, 0, 3); // "USD"
string quote = StringSubstr(symbol, 3, 3); // "JPY"
string suffix = StringSubstr(symbol, 6); // "_micro"
// 日付文字列の解析
string dateStr = "2025.03.15 10:30:00";
string year = StringSubstr(dateStr, 0, 4); // "2025"
string month = StringSubstr(dateStr, 5, 2); // "03"
string day = StringSubstr(dateStr, 8, 2); // "15"
string time = StringSubstr(dateStr, 11); // "10:30:00"
// StringFindと組み合わせて区切り文字で分割
string GetValueAfterKey(string str, string key)
{
int pos = StringFind(str, key);
if(pos < 0) return "";
return StringSubstr(str, pos + StringLen(key));
}
// 使用例
string data = "profit=123.45";
string value = GetValueAfterKey(data, "profit="); // "123.45"StringReplace — 文字列の置換
int StringReplace(
string& str, // 対象の文字列(参照渡し・書き換えられる)
const string find, // 検索する文字列
const string replacement // 置換する文字列
);
// 戻り値: 置換した回数
// 基本使用
string text = "Hello World Hello MQL5";
int count = StringReplace(text, "Hello", "Hi");
// text = "Hi World Hi MQL5", count = 2
// CSV用エスケープ(ダブルクォートを二重に)
string EscapeCsv(string value)
{
string result = value;
StringReplace(result, "\"", "\"\"");
return "\"" + result + "\"";
}
// テンプレート文字列の置換
string FormatTradeComment(string tmpl, string symbol, double lot, double price)
{
string result = tmpl;
StringReplace(result, "{SYMBOL}", symbol);
StringReplace(result, "{LOT}", DoubleToString(lot, 2));
StringReplace(result, "{PRICE}", DoubleToString(price, _Digits));
return result;
}
// 使用例
string tmpl = "EA_v1 {SYMBOL} Lot:{LOT} @{PRICE}";
string comment = FormatTradeComment(tmpl, "USDJPY", 0.1, 150.123);
// "EA_v1 USDJPY Lot:0.10 @150.123"StringSplit — 文字列の分割
文字列を指定した区切り文字で分割し、文字列配列に格納します。CSV解析やコマンドパースに不可欠な関数です。
int StringSplit(
const string string_value, // 分割する文字列
const ushort separator, // 区切り文字(Unicode値)
string& result[] // 結果配列
);
// 戻り値: 分割された要素数
// 基本使用(カンマ区切り)
string csv = "USDJPY,150.123,0.10,Buy";
string parts[];
int count = StringSplit(csv, ',', parts);
// parts[0]="USDJPY", parts[1]="150.123", parts[2]="0.10", parts[3]="Buy"
// セミコロン区切り
string config = "period=20;method=EMA;price=close";
string items[];
StringSplit(config, ';', items);
// 各項目をさらにキー=値に分割
for(int i = 0; i < ArraySize(items); i++)
{
string kv[];
StringSplit(items[i], '=', kv);
if(ArraySize(kv) == 2)
Print("Key=", kv[0], " Value=", kv[1]);
}
// 区切り文字にStringGetCharacterを使う場合
ushort tab = StringGetCharacter("\t", 0); // タブ文字
ushort pipe = StringGetCharacter("|", 0); // パイプ文字
string data = "col1\tcol2\tcol3";
StringSplit(data, tab, parts); // タブ区切りStringSplit()の第2引数はchar型ではなくushort型です。文字リテラルを直接渡す(',')か、StringGetCharacter()で変換してください。文字列を渡すとコンパイルエラーになります。
StringFormat — 書式付き文字列生成
C言語のsprintf()と同等の書式指定文字列です。ログ出力やコメント生成に非常に便利です。
string StringFormat(
string format, // 書式文字列
... // 引数(可変長)
);
// 書式指定子
// %s = 文字列
// %d = 整数
// %f = 浮動小数点
// %.Nf = 小数点以下N桁
// %e = 指数表記
// %% = %文字そのもの
// 基本使用
string msg = StringFormat("Symbol=%s Price=%.5f Lot=%.2f", _Symbol, 1.23456, 0.10);
// "Symbol=USDJPY Price=1.23456 Lot=0.10"
// 整数のゼロ埋め
string orderNum = StringFormat("EA_%04d", 42); // "EA_0042"
// パーセント表示
string pct = StringFormat("勝率: %.1f%%", 65.5); // "勝率: 65.5%"
// 複数行ログ
string log = StringFormat(
"=== Trade Report ===\n"
"Symbol: %s\n"
"Direction: %s\n"
"Entry: %.5f\n"
"SL: %.5f\n"
"TP: %.5f\n"
"Lot: %.2f",
_Symbol, "BUY", 1.12345, 1.12000, 1.13000, 0.10
);
Print(log);StringFormat()はMQL4でもビルド600以降で利用可能です。複雑なログ出力にはPrintFormat()(StringFormatの結果を直接出力)も便利です。
StringConcatenate — 高速文字列結合
int StringConcatenate(
string& string_var, // 結合先(参照渡し)
... // 結合する値(可変長・型混在OK)
);
// 戻り値: 結合後の文字列長
// +演算子より高速(特に大量結合時)
string result;
StringConcatenate(result, "Price=", 1.23456, " Time=", TimeCurrent());
// ループでの文字列構築(+演算子よりStringConcatenateが高速)
string report = "";
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
string line;
StringConcatenate(line,
PositionGetString(POSITION_SYMBOL), " ",
PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY ? "Buy" : "Sell", " ",
DoubleToString(PositionGetDouble(POSITION_VOLUME), 2), " lots ",
DoubleToString(PositionGetDouble(POSITION_PROFIT), 2), " JPY\n"
);
report += line;
}
Print(report);StringTrimLeft / StringTrimRight — 空白の除去
int StringTrimLeft(string& string_var); // 左側の空白を除去
int StringTrimRight(string& string_var); // 右側の空白を除去
// 戻り値: 処理後の文字列長
// 両側の空白を除去
string Trim(string str)
{
StringTrimLeft(str);
StringTrimRight(str);
return str;
}
// CSVパース時に使用
string csv = " USDJPY , 150.123 , 0.10 ";
string parts[];
StringSplit(csv, ',', parts);
for(int i = 0; i < ArraySize(parts); i++)
{
StringTrimLeft(parts[i]);
StringTrimRight(parts[i]);
Print(i, ": [", parts[i], "]");
}
// 0: [USDJPY] 1: [150.123] 2: [0.10]StringToLower / StringToUpper — 大文字・小文字変換
bool StringToLower(string& string_var); // 小文字に変換
bool StringToUpper(string& string_var); // 大文字に変換
// 戻り値: 成功でtrue
// 大文字小文字を無視した比較
bool EqualsIgnoreCase(string a, string b)
{
string lowerA = a, lowerB = b;
StringToLower(lowerA);
StringToLower(lowerB);
return lowerA == lowerB;
}
// シンボル名の正規化
string NormalizeSymbol(string symbol)
{
string upper = symbol;
StringToUpper(upper);
// サフィックスを除去(例: "usdjpy.m" → "USDJPY")
int dotPos = StringFind(upper, ".");
if(dotPos > 0)
upper = StringSubstr(upper, 0, dotPos);
return upper;
}StringCompare — 文字列の大小比較
int StringCompare(
const string& string1, // 文字列1
const string& string2, // 文字列2
bool case_sensitive = true // 大文字小文字を区別
);
// 戻り値: 0=等しい、<0=string1が小さい、>0=string1が大きい
// 大文字小文字を無視して比較
if(StringCompare("usdjpy", "USDJPY", false) == 0)
Print("同じシンボルです");
// ソートでの使用(シンボル名の辞書順ソート)
void SortSymbols(string &symbols[])
{
int size = ArraySize(symbols);
for(int i = 0; i < size - 1; i++)
{
for(int j = i + 1; j < size; j++)
{
if(StringCompare(symbols[i], symbols[j]) > 0)
{
string temp = symbols[i];
symbols[i] = symbols[j];
symbols[j] = temp;
}
}
}
}StringGetCharacter / StringSetCharacter — 文字単位の操作
ushort StringGetCharacter(
string string_value, // 対象文字列
int pos // 位置
);
// 戻り値: 指定位置のUnicode文字コード
bool StringSetCharacter(
string& string_var, // 対象文字列(参照渡し)
int pos, // 位置
ushort character // 設定する文字コード
);
// 文字コードの確認
string s = "ABC";
ushort ch = StringGetCharacter(s, 0); // 65 ('A')
Print("文字コード: ", ch);
// 文字の置換
StringSetCharacter(s, 0, 'X'); // s = "XBC"
// 文字列の末尾に文字を追加(StringSetCharacterの特殊用法)
string str = "Hello";
StringSetCharacter(str, StringLen(str), '!'); // str = "Hello!"
// 特定の文字をカウント
int CountChar(string str, ushort ch)
{
int count = 0;
for(int i = 0; i < StringLen(str); i++)
{
if(StringGetCharacter(str, i) == ch)
count++;
}
return count;
}
// 使用例: CSVのカラム数を推定
string csvLine = "a,b,c,d,e";
int columns = CountChar(csvLine, ',') + 1; // 5StringInit — 文字列の初期化
bool StringInit(
string& string_var, // 対象文字列
int new_len = 0, // 新しい長さ
ushort character = 0 // 埋める文字
);
// 使用例: 固定長文字列の生成
string separator;
StringInit(separator, 50, '-'); // "──────────..." (50文字のハイフン)
// 使用例: 文字列バッファの確保
string buffer;
StringInit(buffer, 1024, ' '); // 1024文字のスペース
// 使用例: ゼロクリア
string data = "some data";
StringInit(data); // 空文字列に初期化StringBufferLen — バッファサイズの取得
int StringBufferLen(
string string_value // 対象文字列
);
// 戻り値: 内部バッファのサイズ(StringLenとは異なる場合がある)
// StringLen vs StringBufferLen
string s = "Hello";
Print("StringLen: ", StringLen(s)); // 5
Print("StringBufferLen: ", StringBufferLen(s)); // 16(内部バッファは余裕を持って確保)
// StringInitでバッファを事前確保した場合
string buf;
StringInit(buf, 1000);
Print("Len: ", StringLen(buf)); // 0(実際の文字列は空)
Print("Buffer: ", StringBufferLen(buf)); // 1000以上(確保済み)StringToCharArray / CharArrayToString — 文字列と配列の変換
文字列をuchar型の文字配列に変換、またはその逆を行います。ファイル操作やWebRequest()でのデータ送受信に使用します。
int StringToCharArray(
string text_string, // 変換する文字列
uchar& array[], // 出力配列
int start = 0, // 開始位置
int count = -1, // 文字数(-1=全部)
uint codepage = CP_ACP // コードページ(CP_UTF8推奨)
);
string CharArrayToString(
uchar array[], // 入力配列
int start = 0, // 開始位置
int count = -1, // 文字数
uint codepage = CP_ACP // コードページ
);
// WebRequest用のデータ変換
string jsonBody = "{\"symbol\":\"USDJPY\",\"action\":\"buy\"}";
uchar postData[];
StringToCharArray(jsonBody, postData, 0, WHOLE_ARRAY, CP_UTF8);
// WebRequestの応答を文字列に変換
uchar responseData[];
string headers;
int result = WebRequest("GET", "https://api.example.com/data",
NULL, 5000, postData, responseData, headers);
string response = CharArrayToString(responseData, 0, WHOLE_ARRAY, CP_UTF8);
Print("Response: ", response);
// バイナリデータのHEXダンプ
string HexDump(uchar &data[], int count)
{
string result = "";
for(int i = 0; i < MathMin(count, ArraySize(data)); i++)
{
result += StringFormat("%02X ", data[i]);
if((i + 1) % 16 == 0) result += "\n";
}
return result;
}StringToCharArray()でCP_ACP(デフォルト)を使うと、日本語環境ではShift-JISに変換されます。JSON/XMLの送受信や日本語を含むデータを扱う場合は必ずCP_UTF8を指定してください。
実践パターン:EA開発での文字列活用
パターン1:高機能ログフォーマッター
enum ENUM_LOG_LEVEL { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR };
input ENUM_LOG_LEVEL LogLevel = LOG_INFO;
input bool LogToFile = false;
string LogLevelToString(ENUM_LOG_LEVEL level)
{
switch(level)
{
case LOG_DEBUG: return "DEBUG";
case LOG_INFO: return "INFO ";
case LOG_WARN: return "WARN ";
case LOG_ERROR: return "ERROR";
default: return "?????";
}
}
void Log(ENUM_LOG_LEVEL level, string message)
{
if(level < LogLevel) return;
MqlDateTime dt;
TimeCurrent(dt);
string timestamp = StringFormat("%04d.%02d.%02d %02d:%02d:%02d",
dt.year, dt.mon, dt.day,
dt.hour, dt.min, dt.sec);
string logLine = StringFormat("[%s] [%s] [%s] %s",
timestamp,
LogLevelToString(level),
_Symbol,
message);
Print(logLine);
if(LogToFile)
{
int handle = FileOpen("EA_Log.txt", FILE_WRITE | FILE_READ | FILE_TXT | FILE_SHARE_READ);
if(handle != INVALID_HANDLE)
{
FileSeek(handle, 0, SEEK_END);
FileWriteString(handle, logLine + "\n");
FileClose(handle);
}
}
}
// 使用例
void OnTick()
{
Log(LOG_DEBUG, StringFormat("Bid=%.5f Ask=%.5f Spread=%d",
SymbolInfoDouble(_Symbol, SYMBOL_BID),
SymbolInfoDouble(_Symbol, SYMBOL_ASK),
(int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)));
Log(LOG_INFO, StringFormat("新規注文: Buy %.2f lots @ %.5f", 0.10, 1.12345));
Log(LOG_ERROR, StringFormat("注文失敗: error=%d (%s)", GetLastError(), "OrderSend failed"));
}パターン2:CSV読み書きヘルパー
// CSVの1行を解析して各フィールドを取得
bool ParseCsvLine(string line, string &fields[], int expectedCount = 0)
{
int count = StringSplit(line, ',', fields);
if(count <= 0) return false;
// 各フィールドの前後の空白を除去
for(int i = 0; i < count; i++)
{
StringTrimLeft(fields[i]);
StringTrimRight(fields[i]);
// ダブルクォート除去
if(StringLen(fields[i]) >= 2
&& StringGetCharacter(fields[i], 0) == '"'
&& StringGetCharacter(fields[i], StringLen(fields[i])-1) == '"')
{
fields[i] = StringSubstr(fields[i], 1, StringLen(fields[i]) - 2);
}
}
if(expectedCount > 0 && count != expectedCount)
{
Print("CSV列数不一致: 期待=", expectedCount, " 実際=", count);
return false;
}
return true;
}
// CSVの1行を生成
string BuildCsvLine(string &fields[])
{
string result = "";
for(int i = 0; i < ArraySize(fields); i++)
{
if(i > 0) result += ",";
// カンマやダブルクォートを含む場合はエスケープ
if(StringFind(fields[i], ",") >= 0 || StringFind(fields[i], "\"") >= 0)
{
string escaped = fields[i];
StringReplace(escaped, "\"", "\"\"");
result += "\"" + escaped + "\"";
}
else
result += fields[i];
}
return result;
}パターン3:トレードコメントの生成と解析
// トレードコメントの生成(構造化データの埋め込み)
string BuildTradeComment(string eaName, string logic, int signalId)
{
// 形式: "EA名|ロジック名|シグナルID|エントリー時刻"
return StringFormat("%s|%s|%d|%s",
eaName, logic, signalId,
TimeToString(TimeCurrent(), TIME_DATE | TIME_MINUTES));
}
// トレードコメントの解析
struct TradeInfo
{
string eaName;
string logic;
int signalId;
string entryTime;
};
bool ParseTradeComment(string comment, TradeInfo &info)
{
string parts[];
int count = StringSplit(comment, '|', parts);
if(count < 4) return false;
info.eaName = parts[0];
info.logic = parts[1];
info.signalId = (int)StringToInteger(parts[2]);
info.entryTime = parts[3];
return true;
}
// 使用例
void OnTick()
{
// エントリー時
string comment = BuildTradeComment("MyEA_v2", "GoldenCross", 42);
// comment = "MyEA_v2|GoldenCross|42|2025.03.15 10:30"
// ポジション分析時
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
string posComment = PositionGetString(POSITION_COMMENT);
TradeInfo info;
if(ParseTradeComment(posComment, info))
{
PrintFormat("EA=%s Logic=%s Signal=%d Entry=%s",
info.eaName, info.logic, info.signalId, info.entryTime);
}
}
}パターン4:チャートコメントの整形表示
input int MagicNumber = 12345; // マジックナンバー
// チャート左上に整形された情報を表示
void UpdateChartComment()
{
string sep;
StringInit(sep, 40, '-');
string comment = "";
comment += "=== MyEA v2.0 ===\n";
comment += sep + "\n";
comment += StringFormat("Symbol: %s\n", _Symbol);
comment += StringFormat("Timeframe: %s\n", EnumToString(Period()));
comment += StringFormat("Spread: %d pt\n",
(int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD));
comment += StringFormat("Bid: %.5f\n",
SymbolInfoDouble(_Symbol, SYMBOL_BID));
comment += StringFormat("Ask: %.5f\n",
SymbolInfoDouble(_Symbol, SYMBOL_ASK));
comment += sep + "\n";
// ポジション情報
double totalProfit = 0;
int posCount = 0;
for(int i = 0; i < PositionsTotal(); i++)
{
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)
{
posCount++;
totalProfit += PositionGetDouble(POSITION_PROFIT)
+ PositionGetDouble(POSITION_SWAP);
}
}
comment += StringFormat("Positions: %d\n", posCount);
comment += StringFormat("P/L: %.2f %s\n",
totalProfit,
AccountInfoString(ACCOUNT_CURRENCY));
comment += sep + "\n";
comment += StringFormat("Updated: %s",
TimeToString(TimeCurrent(), TIME_SECONDS));
Comment(comment);
}文字列関数一覧リファレンス
| 関数 | 機能 | MQL4 | MQL5 |
|---|---|---|---|
| StringLen | 文字列の長さ | 対応 | 対応 |
| StringFind | 部分文字列の検索 | 対応 | 対応 |
| StringSubstr | 部分文字列の抽出 | 対応 | 対応 |
| StringReplace | 文字列の置換 | 対応(ビルド600+) | 対応 |
| StringSplit | 文字列の分割 | 対応 | 対応 |
| StringFormat | 書式付き文字列生成 | 対応(600+) | 対応 |
| StringConcatenate | 高速文字列結合 | 対応 | 対応 |
| StringTrimLeft/Right | 空白除去 | 対応 | 対応 |
| StringToLower/Upper | 大文字・小文字変換 | 対応 | 対応 |
| StringCompare | 文字列比較(大小) | 対応 | 対応 |
| StringGetCharacter | 文字コード取得 | 対応 | 対応 |
| StringSetCharacter | 文字の設定 | 対応 | 対応 |
| StringInit | 文字列初期化 | 対応 | 対応 |
| StringBufferLen | バッファサイズ取得 | 対応 | 対応 |
| StringToCharArray | 文字列→文字配列 | 対応(ANSI) | 対応(Unicode) |
| CharArrayToString | 文字配列→文字列 | 対応 | 対応 |
- StringFormatはログ出力の品質を大幅に向上させる必須テクニック
- StringSplitでCSVやコマンド文字列を効率的に解析
- StringReplaceでテンプレート文字列による柔軟なコメント生成
- StringToCharArrayはWebRequest()とのデータ連携に必須(CP_UTF8指定を忘れずに)
- 構造化されたトレードコメントでポジション管理の精度を高める
プロが開発したEAをお探しの方は → シストレ.COM EA一覧





