【MQL4】市場情報を取得する関数を完全解説!MarketInfo・SymbolInfoDouble・SymbolInfoInteger・SymbolInfoStringの使い方

【中級編】MQLプログラムの読み方・書き方

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ロジック
    // ...
}

まとめ

最後に、この記事のポイントを整理します。

  1. MarketInfo関数はMQL4の基本関数で、MODE定数を使って様々な市場情報をdouble型で取得できる
  2. SymbolInfo系関数(Double/Integer/String)はデータ型に応じた3つの関数に分かれており、型安全に情報を取得できる
  3. MQL5への移行を見据えるなら、SymbolInfo系関数を使う習慣をつけるのがおすすめ
  4. ストップレベルは0を返す場合でも最低限のマージンを確保すると安全
  5. TickValueを使ったロット計算は実践的なEAに不可欠
  6. ストラテジーテスターでは他通貨ペア情報やTickValueが正しく取得できない場合があるため、ガード処理を入れておくことが大切

これらの関数を使いこなせるようになると、ブローカーの取引条件に応じた柔軟なEAが作れるようになります。ぜひ実際にコードを書いて、各関数の返り値を確認してみてください!