EA(自動売買)を開発するとき、「現在のスプレッドはいくつ?」「このブローカーのストップレベルは?」「1pipあたりの価値は?」といった市場情報の取得は欠かせません。MQL4には、これらの情報を取得するための関数がいくつか用意されています。
この記事では、MarketInfo関数と、より新しいSymbolInfoDouble・SymbolInfoInteger・SymbolInfoString関数の使い方を、実践的なコード例とともに徹底解説します。
MarketInfo関数 ― MQL4の基本
MarketInfo関数は、気配値表示ウィンドウに表示されている通貨ペアのマーケット情報を取得するための、MQL4で最も古くから使われている関数です。
基本構文
double MarketInfo(string symbol, int type);
第1引数に通貨ペア名(例:”USDJPY”)、第2引数にMODE定数を指定します。戻り値はすべてdouble型です。
主なMODE定数一覧
| MODE定数 | 値 | 説明 |
|---|---|---|
| MODE_BID | 9 | 現在のBid価格 |
| MODE_ASK | 10 | 現在のAsk価格 |
| MODE_POINT | 11 | 1ポイントの値(例:0.00001) |
| MODE_DIGITS | 12 | 小数点以下の桁数 |
| MODE_SPREAD | 13 | スプレッド(ポイント単位) |
| MODE_STOPLEVEL | 14 | ストップレベル(ポイント単位) |
| MODE_LOTSIZE | 15 | 1ロットあたりの契約サイズ |
| MODE_TICKVALUE | 16 | 1ティックあたりの価値(口座通貨建て) |
| MODE_TICKSIZE | 17 | 1ティックのサイズ |
| MODE_SWAPLONG | 18 | ロングポジションのスワップ |
| MODE_SWAPSHORT | 19 | ショートポジションのスワップ |
| MODE_MINLOT | 24 | 最小ロット数 |
| MODE_LOTSTEP | 25 | ロットのステップ |
| MODE_MAXLOT | 26 | 最大ロット数 |
| MODE_MARGININIT | 28 | 初期証拠金 |
| MODE_MARGINREQUIRED | 31 | 1ロットあたりの必要証拠金 |
| MODE_FREEZELEVEL | 33 | フリーズレベル(ポイント単位) |
基本的な使用例
void OnStart()
{
string sym = Symbol(); // 現在のチャートの通貨ペア
double bid = MarketInfo(sym, MODE_BID);
double ask = MarketInfo(sym, MODE_ASK);
double spread = MarketInfo(sym, MODE_SPREAD);
double stopLevel = MarketInfo(sym, MODE_STOPLEVEL);
double tickValue = MarketInfo(sym, MODE_TICKVALUE);
double minLot = MarketInfo(sym, MODE_MINLOT);
PrintFormat("Bid=%.5f Ask=%.5f Spread=%.0f StopLevel=%.0f",
bid, ask, spread, stopLevel);
PrintFormat("TickValue=%.5f MinLot=%.2f", tickValue, minLot);
}
MarketInfo関数はシンプルで使いやすいですが、戻り値がすべてdouble型のため、本来は整数値であるスプレッドや桁数もdoubleで返ってきます。キャストが必要になる場面がある点は覚えておきましょう。
SymbolInfo系関数 ― より型安全な新しい方法
MQL4のビルド600以降では、MarketInfoの代替としてSymbolInfo系関数が使えるようになりました。これらはMQL5と共通の関数であり、将来的なMQL5移行を見据えるなら、こちらを使うのがおすすめです。
SymbolInfo系関数は、取得するデータの型に応じて3つに分かれています。
| 関数名 | 戻り値の型 | 主な用途 |
|---|---|---|
| SymbolInfoDouble | double | 価格、スワップ、ロット情報など |
| SymbolInfoInteger | long(整数) | スプレッド、桁数、ストップレベルなど |
| SymbolInfoString | string | 通貨名、シンボル説明など |
SymbolInfoDouble ― double型の市場情報を取得
SymbolInfoDoubleには2つの書式があります。
書式1:戻り値で直接受け取る
double SymbolInfoDouble(string symbol, ENUM_SYMBOL_INFO_DOUBLE prop_id);
書式2:参照引数で受け取る(成否判定付き)
bool SymbolInfoDouble(string symbol, ENUM_SYMBOL_INFO_DOUBLE prop_id, double &value);
書式2はboolを返すため、取得が成功したかどうかを判定できます。安全なコードを書きたい場合はこちらを推奨します。
主なプロパティID
| プロパティID | 説明 |
|---|---|
| SYMBOL_BID | 現在のBid価格 |
| SYMBOL_ASK | 現在のAsk価格 |
| SYMBOL_POINT | 1ポイントの値 |
| SYMBOL_TRADE_TICK_VALUE | 1ティックの価値 |
| SYMBOL_TRADE_TICK_SIZE | 1ティックのサイズ |
| SYMBOL_TRADE_CONTRACT_SIZE | 契約サイズ |
| SYMBOL_VOLUME_MIN | 最小ロット |
| SYMBOL_VOLUME_MAX | 最大ロット |
| SYMBOL_VOLUME_STEP | ロットステップ |
| SYMBOL_SWAP_LONG | ロングスワップ |
| SYMBOL_SWAP_SHORT | ショートスワップ |
| SYMBOL_MARGIN_INITIAL | 初期証拠金 |
コード例
void OnStart()
{
string sym = Symbol();
// 書式1:直接取得
double bid = SymbolInfoDouble(sym, SYMBOL_BID);
double ask = SymbolInfoDouble(sym, SYMBOL_ASK);
PrintFormat("Bid=%.5f Ask=%.5f", bid, ask);
// 書式2:成否判定付き
double tickValue;
if(SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE, tickValue))
PrintFormat("TickValue = %.5f", tickValue);
else
Print("TickValue の取得に失敗しました");
}
SymbolInfoInteger ― 整数型の市場情報を取得
スプレッドや桁数など、整数で扱うべき情報をlong型で返します。MarketInfoではdoubleで返っていたものが正しい型で取得できるようになりました。
主なプロパティID
| プロパティID | 説明 |
|---|---|
| SYMBOL_SPREAD | スプレッド(ポイント単位) |
| SYMBOL_DIGITS | 小数点以下の桁数 |
| SYMBOL_TRADE_STOPS_LEVEL | ストップレベル(ポイント単位) |
| SYMBOL_TRADE_FREEZE_LEVEL | フリーズレベル(ポイント単位) |
| SYMBOL_TRADE_EXEMODE | 約定方式 |
| SYMBOL_TIME | 最終ティックの時刻 |
void OnStart()
{
string sym = Symbol();
long spread = SymbolInfoInteger(sym, SYMBOL_SPREAD);
long digits = SymbolInfoInteger(sym, SYMBOL_DIGITS);
long stopLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
PrintFormat("Spread=%d Digits=%d StopLevel=%d",
(int)spread, (int)digits, (int)stopLevel);
}
SymbolInfoString ― 文字列型の市場情報を取得
通貨ペアの基軸通貨や決済通貨、説明文などの文字列情報を取得します。
| プロパティID | 説明 |
|---|---|
| SYMBOL_CURRENCY_BASE | 基軸通貨(例:”USD”) |
| SYMBOL_CURRENCY_PROFIT | 決済通貨(例:”JPY”) |
| SYMBOL_CURRENCY_MARGIN | 証拠金通貨 |
| SYMBOL_DESCRIPTION | シンボルの説明文 |
| SYMBOL_PATH | シンボルツリー内のパス |
void OnStart()
{
string sym = Symbol();
string baseCurrency = SymbolInfoString(sym, SYMBOL_CURRENCY_BASE);
string profitCurrency = SymbolInfoString(sym, SYMBOL_CURRENCY_PROFIT);
string description = SymbolInfoString(sym, SYMBOL_DESCRIPTION);
PrintFormat("基軸通貨=%s 決済通貨=%s", baseCurrency, profitCurrency);
PrintFormat("説明: %s", description);
}
MarketInfo と SymbolInfo系の対応関係
既存のコードをSymbolInfo系に書き換えたいときは、以下の対応表を参考にしてください。
| MarketInfo (MODE定数) | SymbolInfo系 (プロパティID) | 関数 |
|---|---|---|
| MODE_BID | SYMBOL_BID | SymbolInfoDouble |
| MODE_ASK | SYMBOL_ASK | SymbolInfoDouble |
| MODE_POINT | SYMBOL_POINT | SymbolInfoDouble |
| MODE_DIGITS | SYMBOL_DIGITS | SymbolInfoInteger |
| MODE_SPREAD | SYMBOL_SPREAD | SymbolInfoInteger |
| MODE_STOPLEVEL | SYMBOL_TRADE_STOPS_LEVEL | SymbolInfoInteger |
| MODE_TICKVALUE | SYMBOL_TRADE_TICK_VALUE | SymbolInfoDouble |
| MODE_MINLOT | SYMBOL_VOLUME_MIN | SymbolInfoDouble |
| MODE_LOTSTEP | SYMBOL_VOLUME_STEP | SymbolInfoDouble |
| MODE_MAXLOT | SYMBOL_VOLUME_MAX | SymbolInfoDouble |
| MODE_FREEZELEVEL | SYMBOL_TRADE_FREEZE_LEVEL | SymbolInfoInteger |
実践テクニック
①スプレッドフィルター
スプレッドが広がっているときにエントリーを避ける、シンプルなフィルターです。
// スプレッドが指定pips以上なら取引しない
bool IsSpreadOK(int maxSpreadPoints)
{
long spread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD);
if(spread > maxSpreadPoints)
{
PrintFormat("スプレッドが広すぎます: %d > %d", (int)spread, maxSpreadPoints);
return false;
}
return true;
}
②ストップレベルを考慮したSL/TP設定
ブローカーによってはストップレベルが設定されており、現在価格から一定以上離れていないとSL/TPを設定できません。また、ストップレベルが0を返す場合でも実際にはサーバー側で制限がかかるケースがあるため、最低限のマージンを確保するのがポイントです。
double GetSafeStopDistance()
{
long stopLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
double point = SymbolInfoDouble(Symbol(), SYMBOL_POINT);
// ストップレベルが0の場合でも最低10ポイントは確保
if(stopLevel < 10)
stopLevel = 10;
return stopLevel * point;
}
// 使用例:Buy注文のSL/TPを安全に設定
double safeDistance = GetSafeStopDistance();
double sl = Ask - MathMax(desiredSL, safeDistance);
double tp = Ask + MathMax(desiredTP, safeDistance);
③リスクベースのロット計算
口座残高の一定割合をリスクとして、適切なロット数を計算する関数です。
double CalcLotSize(double riskPercent, double slPoints)
{
string sym = Symbol();
double balance = AccountBalance();
double riskMoney = balance * riskPercent / 100.0;
double tickValue = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(sym, SYMBOL_TRADE_TICK_SIZE);
double point = SymbolInfoDouble(sym, SYMBOL_POINT);
double minLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
if(tickValue == 0 || tickSize == 0) return minLot;
// 1ポイントあたりの価値
double pointValue = tickValue * (point / tickSize);
// ロット計算
double lots = riskMoney / (slPoints * pointValue);
// ロットステップに丸める
lots = MathFloor(lots / lotStep) * lotStep;
// 最小・最大ロットでクランプ
lots = MathMax(lots, minLot);
lots = MathMin(lots, maxLot);
return NormalizeDouble(lots, 2);
}
ストラテジーテスターでの注意点
ストラテジーテスター(バックテスト)では、市場情報の取得に制限があります。
- 他の通貨ペアの情報:テスト対象以外の通貨ペアのMarketInfoやSymbolInfoは、正しい値が返らないことがあります
- TickValueが0になる:テスト開始直後やクロス通貨ペアで、SYMBOL_TRADE_TICK_VALUEが0を返す場合があります
- 対処法:TickValueが0の場合はデフォルト値を使う、またはOnTick()内で値が有効になるまで待つ処理を入れましょう
// テスター対策:TickValueが0なら処理をスキップ
void OnTick()
{
double tickValue = SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE);
if(tickValue <= 0)
{
Print("TickValueが無効です。次のティックを待ちます。");
return;
}
// 通常のEAロジック
// ...
}
まとめ
最後に、この記事のポイントを整理します。
- MarketInfo関数はMQL4の基本関数で、MODE定数を使って様々な市場情報をdouble型で取得できる
- SymbolInfo系関数(Double/Integer/String)はデータ型に応じた3つの関数に分かれており、型安全に情報を取得できる
- MQL5への移行を見据えるなら、SymbolInfo系関数を使う習慣をつけるのがおすすめ
- ストップレベルは0を返す場合でも最低限のマージンを確保すると安全
- TickValueを使ったロット計算は実践的なEAに不可欠
- ストラテジーテスターでは他通貨ペア情報やTickValueが正しく取得できない場合があるため、ガード処理を入れておくことが大切
これらの関数を使いこなせるようになると、ブローカーの取引条件に応じた柔軟なEAが作れるようになります。ぜひ実際にコードを書いて、各関数の返り値を確認してみてください!

