MQL5 PositionSelectの使い方完全ガイド|取得できない原因と正しい実装方法

目次

1. MQL5のPositionSelectとは何か

1.1 PositionSelectの概要

PositionSelectは、現在保有しているポジションを選択(内部的に参照可能な状態にする)ための関数です。
MQL5では、ポジション情報を直接取得するのではなく、「選択 → 取得」という2段階の構造になっています。

基本構文は以下です。

bool PositionSelect(string symbol);

この関数は、指定したシンボル(通貨ペアなど)に対応するポジションを選択し、
その後に PositionGetIntegerPositionGetDouble などの関数で詳細情報を取得できるようにします。

重要なポイントは以下です。

  • PositionSelectは「情報取得」ではなく「対象指定」
  • 戻り値は成功(true)/失敗(false)
  • 成功しないと、以降のPositionGet系は正しく動作しない

例:基本の流れ

if(PositionSelect(_Symbol))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

このように、PositionSelectはポジション情報取得の前提条件です。


1.2 なぜPositionSelectが必要なのか

MQL5では、ポジション・注文・履歴などのデータ取得はすべて
「選択状態にあるデータを取得する」設計になっています。

つまり、以下のような構造です。

  • PositionSelect → 対象を選ぶ
  • PositionGetXXX → 選ばれた対象の情報を取得

この設計により、

  • メモリ効率の最適化
  • 処理速度の安定化
  • 内部データ構造の統一

が実現されています(内部仕様は非公開だが、このような意図と考えられる)。

また、MQL4との違いとして重要なのは、

  • MQL4:チケット番号ベースで直接取得
  • MQL5:シンボルまたはチケットを「選択」してから取得

という点です。

この違いを理解していないと、

  • 「値が取得できない」
  • 「常に0が返る」

といった典型的な問題に直面します。


1.3 対象読者がつまずくポイント

PositionSelectはシンプルな関数ですが、以下の点で非常に多くの初学者がつまずきます。

よくある誤解①:PositionGetだけで取得できる

double profit = PositionGetDouble(POSITION_PROFIT); // ← これだけではNG

→ PositionSelectを呼んでいないため、正しい値は取得できません。


よくある誤解②:一度Selectすれば使い回せる

→ 内部状態は常に保証されないため、毎回Selectするのが安全


よくある誤解③:ポジションがないのに取得しようとする

→ PositionSelectがfalseになる


よくある失敗パターン

  • return値(true/false)をチェックしない
  • _Symbol ではなく誤った文字列を指定する
  • 注文直後に取得しようとして失敗(反映遅延)

注意点(重要)

  • PositionSelectは「存在確認」も兼ねる
  • falseの場合は処理を中断するのが基本
if(!PositionSelect(_Symbol))
{
    return; // ポジションなし
}

2. PositionSelectの基本的な使い方

2.1 基本構文

PositionSelectは、指定したシンボルのポジションを選択し、
その後のPositionGet系関数で情報を取得できる状態にします。

bool PositionSelect(string symbol);
  • symbol:通貨ペアや銘柄(例:"EURUSD"
  • 戻り値:
    • true:ポジションあり(選択成功)
    • false:ポジションなし or 取得失敗

実務では、必ず戻り値をチェックするのが前提です。


2.2 最小コード例(即使える形)

以下は、現在のチャートの通貨ペア(_Symbol)に対して
ポジションが存在するか確認し、利益を取得する最小コードです。

void OnTick()
{
    // ポジションの選択
    if(PositionSelect(_Symbol))
    {
        // 利益を取得
        double profit = PositionGetDouble(POSITION_PROFIT);

        Print("現在の利益: ", profit);
    }
    else
    {
        Print("ポジションは存在しません");
    }
}

手順(重要)

  • ① PositionSelectでポジションを選択
  • ② trueならPositionGetで取得
  • ③ falseなら処理を分岐

2.3 戻り値の意味(true / false)

PositionSelectの戻り値は非常に重要です。

戻り値意味
true指定シンボルのポジションが存在
falseポジションなし / 取得失敗

注意点

falseになる主な原因:

  • ポジションを持っていない
  • シンボル名の誤り
  • 注文直後でまだ反映されていない(環境により異なる)

2.4 よくある失敗と対策

失敗①:return値を無視する

PositionSelect(_Symbol);
double profit = PositionGetDouble(POSITION_PROFIT); // 危険

→ Selectが失敗している可能性あり
必ずifでチェック


失敗②:シンボルをハードコードする

PositionSelect("EURUSD"); // 非推奨

→ ブローカーにより表記が異なる場合あり(例:EURUSDm)

対策

PositionSelect(_Symbol);

失敗③:注文直後に取得する

OrderSend(...);
PositionSelect(_Symbol); // すぐ呼ぶとfalseになることがある

→ 約定反映のタイミング差

対策

  • 数ミリ秒待つ(環境依存)
  • 次のTickで処理する

失敗④:複数ポジションを想定していない

→ PositionSelectは1つのポジションのみ対象
→ ヘッジ口座では注意(詳細は後述)


2.5 実務での基本テンプレ(推奨)

以下は、実務でそのまま使える安全なテンプレです。

if(!PositionSelect(_Symbol))
{
    // ポジションなし
    return;
}

// 必要な情報を取得
double volume = PositionGetDouble(POSITION_VOLUME);
double profit = PositionGetDouble(POSITION_PROFIT);
int type = (int)PositionGetInteger(POSITION_TYPE);

// ログ出力
Print("Volume: ", volume, " Profit: ", profit, " Type: ", type);

ポイント

  • 必ず早期returnで分岐
  • 必要な情報をまとめて取得
  • 型変換(intなど)に注意

3. PositionSelectとPositionGet系関数の関係(重要)

3.1 PositionGet系関数とは

PositionSelectでポジションを選択した後、実際のデータを取得するのが
PositionGet系関数です。

主に以下の3種類があります。

  • PositionGetInteger():整数値(例:ポジションタイプ)
  • PositionGetDouble():数値(例:利益、ロット)
  • PositionGetString():文字列(例:シンボル名)

代表的な取得例

double profit = PositionGetDouble(POSITION_PROFIT);
double volume = PositionGetDouble(POSITION_VOLUME);
int type = (int)PositionGetInteger(POSITION_TYPE);
string symbol = PositionGetString(POSITION_SYMBOL);

これらはすべて、PositionSelectが成功している前提で動作します。


3.2 正しい処理フロー(最重要)

MQL5におけるポジション取得は、必ず以下の順序で行います。

① PositionSelect(対象を選択)
② PositionGetXXX(データ取得)

コードで表すと:

if(PositionSelect(_Symbol))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

この順序が崩れると、正しい値は取得できません


3.3 よくある誤り(構造理解不足)

誤り①:Selectなしで取得

double profit = PositionGetDouble(POSITION_PROFIT); // NG

→ 内部的に「どのポジションか不明」なため、値が不定


誤り②:Select対象がズレている

PositionSelect("EURUSD");
double profit = PositionGetDouble(POSITION_PROFIT);

→ 現在のチャートがUSDJPYの場合、意図しない挙動


誤り③:別のSelectで上書きされる

PositionSelect(_Symbol);
PositionSelect("EURUSD"); // 上書きされる
double profit = PositionGetDouble(POSITION_PROFIT);

→ 最後にSelectしたものが有効になる


3.4 内部仕様の理解(実務的に重要)

PositionSelectは、内部的に「現在の選択ポジション」を1つ保持します。

つまり:

  • 常に「最後に選択されたポジション」が対象
  • グローバルに1つだけ保持される(スレッド単位)

このため、以下が重要です。

原則

  • 取得直前に必ずSelectする
if(PositionSelect(_Symbol))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

3.5 安全な書き方(再現性重視)

実務では、以下のように「セットで書く」のが基本です。

double GetCurrentProfit()
{
    if(!PositionSelect(_Symbol))
        return 0.0;

    return PositionGetDouble(POSITION_PROFIT);
}

メリット

  • バグを防止
  • 再利用可能
  • ロジックが明確

3.6 よくあるつまずきポイント

つまずき①:値が0になる

原因:

  • PositionSelectしていない
  • falseなのに処理続行

つまずき②:前回の値が残る

原因:

  • 別のSelectの影響
  • 状態管理ミス

つまずき③:ランダムに動く

原因:

  • Selectタイミングが不安定
  • Tick依存処理

3.7 注意点まとめ(重要)

  • PositionGet系は単体では使えない
  • Select → Getの順序は絶対
  • Selectは毎回行う(使い回し禁止)
  • 1つしか選択されない(上書きされる)

4. 複数ポジション環境でのPositionSelectの扱い方(ヘッジ口座対応)

4.1 ネッティング口座とヘッジ口座の違い

MQL5では、口座タイプによってポジションの扱いが大きく異なります。

ネッティング口座

  • 1シンボルにつきポジションは1つのみ
  • 買い・売りは合算される
  • PositionSelectで問題なく取得できる

ヘッジ口座

  • 同一シンボルで複数ポジションを保有可能
  • 買いと売りを同時に持てる
  • PositionSelectだけでは不十分

4.2 PositionSelectの制限(重要)

PositionSelectは以下の仕様です。

  • 指定シンボルの「いずれか1つ」のポジションを選択
  • 複数ある場合、どれが選ばれるかは保証されない

つまり、ヘッジ口座では:

PositionSelect(_Symbol);

→ 複数ポジションのうち、どれか1つだけが対象になる

これは実務上、重大なバグ要因になります。


4.3 正しい対応方法(複数ポジション処理)

ヘッジ口座では、PositionSelectではなく
PositionSelectByTicket + ループ処理を使います。

手順

  • ① PositionsTotal()で件数取得
  • ② ループで全ポジションを処理
  • ③ チケットごとに選択

4.4 実用コード例(安全パターン)

int total = PositionsTotal();

for(int i = 0; i < total; i++)
{
    ulong ticket = PositionGetTicket(i);

    if(PositionSelectByTicket(ticket))
    {
        string symbol = PositionGetString(POSITION_SYMBOL);

        // 対象シンボルのみ処理
        if(symbol == _Symbol)
        {
            double profit = PositionGetDouble(POSITION_PROFIT);
            Print("Profit: ", profit);
        }
    }
}

4.5 ポイント解説(重要)

ポイント①:PositionGetTicket(i)

  • インデックスからチケット番号を取得

ポイント②:PositionSelectByTicket

  • 特定ポジションを確実に選択

ポイント③:シンボルフィルタ

  • 不要なポジションを除外

4.6 よくある失敗と対策

失敗①:PositionSelectだけで処理

→ 複数ポジションの一部しか見ない


失敗②:ループしているのにSelectしない

for(int i = 0; i < PositionsTotal(); i++)
{
    double profit = PositionGetDouble(POSITION_PROFIT); // NG
}

→ Selectしていないため無効


失敗③:チケットを使わない

→ 正確なポジション指定ができない


4.7 実務での判断基準

どちらを使うかは口座タイプで判断します。

状況推奨
ネッティング口座PositionSelect
ヘッジ口座ループ+PositionSelectByTicket

4.8 注意点(実務重要)

  • ブローカーにより口座タイプが異なる
  • 同じEAでも環境で挙動が変わる
  • 将来的な拡張を考えるとループ構造が安全

4.9 安全設計の考え方

再現性を重視するなら:

  • 常にループ構造で書く
  • シンボルでフィルタ
  • 明示的に制御

→ 多少冗長でも、バグ耐性が高い

5. PositionSelectを使った実践的な売買ロジック例(EA実装)

5.1 ポジション有無でエントリーを制御する

EAの基本ロジックは「ポジションがないときのみエントリー」です。
この判定にPositionSelectを使用します。

void OnTick()
{
    // 既にポジションがある場合は何もしない
    if(PositionSelect(_Symbol))
    {
        return;
    }

    // ポジションがない場合のみエントリー
    // (例:買い注文)
    MqlTradeRequest request;
    MqlTradeResult result;

    ZeroMemory(request);
    ZeroMemory(result);

    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = 0.1;
    request.type   = ORDER_TYPE_BUY;
    request.price  = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

    OrderSend(request, result);
}

5.2 手順整理(再現性重視)

  • ① PositionSelectでポジション有無を確認
  • ② 存在する場合はreturn
  • ③ 存在しない場合のみOrderSend

この構造により、二重エントリーを防止できます。


5.3 利益条件で決済する例

ポジションを持っている場合、利益条件でクローズするロジックです。

void OnTick()
{
    if(!PositionSelect(_Symbol))
        return;

    double profit = PositionGetDouble(POSITION_PROFIT);

    // 利益が10以上で決済
    if(profit >= 10.0)
    {
        ClosePosition();
    }
}

5.4 クローズ関数の例

void ClosePosition()
{
    if(!PositionSelect(_Symbol))
        return;

    ulong ticket = PositionGetInteger(POSITION_TICKET);
    double volume = PositionGetDouble(POSITION_VOLUME);

    MqlTradeRequest request;
    MqlTradeResult result;

    ZeroMemory(request);
    ZeroMemory(result);

    request.action = TRADE_ACTION_DEAL;
    request.symbol = _Symbol;
    request.volume = volume;
    request.type = ORDER_TYPE_SELL; // BUYポジションを閉じる
    request.position = ticket;
    request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    OrderSend(request, result);
}

5.5 よくあるロジックミス

ミス①:ポジションチェックをしない

→ 常にエントリーしてしまう(無限ポジション)


ミス②:決済方向を間違える

request.type = ORDER_TYPE_BUY; // ←間違い

→ BUYポジションはSELLでクローズする必要あり


ミス③:チケットを指定しない

→ 意図しないポジションが対象になる


ミス④:価格取得ミス

  • BUY時 → ASK
  • SELL時 → BID

5.6 実務的な改善ポイント

改善①:スプレッドチェック

double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if(spread > 20) return;

改善②:ロット制御

request.volume = NormalizeDouble(0.1, 2);

改善③:再試行処理

→ OrderSend失敗時のリトライ


5.7 注意点(重要)

  • PositionSelectは状態確認専用
  • 実際の取引はOrderSendで行う
  • 約定タイミングは環境依存

5.8 安全なEA設計の基本

  • ポジション有無 → PositionSelect
  • 情報取得 → PositionGet系
  • 売買実行 → OrderSend

この分離を徹底することで、バグ耐性が高くなる

6. PositionSelectがfalseになる原因とトラブルシューティング

6.1 PositionSelectがfalseになる基本原因

PositionSelectがfalseを返すときは、まず「そのシンボルのポジションを選択できなかった」という意味です。
ただし、その内訳は1つではありません。実務では主に以下の4パターンです。

  • そのシンボルのポジションを保有していない
  • シンボル指定が間違っている
  • 注文直後で、まだポジション情報が反映されていない
  • ヘッジ口座で複数ポジションを想定しているのに、PositionSelectで処理している

最初に確認すべきなのは、「本当に今、そのシンボルにポジションがあるか」です。

if(!PositionSelect(_Symbol))
{
    Print("PositionSelect failed");
    return;
}

このように、false時点で処理を分けるのが基本です。


6.2 最も多い原因①:そもそもポジションを持っていない

最も多いのは、単純にポジション未保有です。
特に以下の場面で起きやすいです。

  • EA起動直後
  • 決済直後
  • 条件未成立で未エントリー
  • 想定していた注文が約定していない

この場合、PositionSelectの動作自体は正常です。
異常ではなく、「ポジションがないのでfalse」という正しい返り値です。

確認コード例

if(!PositionSelect(_Symbol))
{
    Print("現在 ", _Symbol, " にポジションはありません");
}
else
{
    Print("ポジションがあります");
}

つまずきポイント

  • falseを「エラー」と決めつける
  • 未保有なのに取得失敗だと思い込む

6.3 最も多い原因②:シンボル名の指定ミス

次に多いのが、シンボル名の不一致です。
MQL5では、ブローカーによって銘柄名に接尾辞や接頭辞が付くことがあります。

例:

  • EURUSD
  • EURUSDm
  • EURUSD.pro

このため、文字列を固定で書くと失敗しやすくなります。

PositionSelect("EURUSD"); // 環境によっては失敗

推奨

現在のチャートを対象にするなら、_Symbol を使います。

PositionSelect(_Symbol);

注意点

  • 手入力の文字列はミスを生みやすい
  • 大文字小文字よりも、名称そのものの一致が重要

6.4 最も多い原因③:注文直後で反映が間に合っていない

OrderSendの直後にPositionSelectを呼ぶと、環境によってはまだポジション情報が反映されておらず、falseになることがあります。

OrderSend(request, result);

if(!PositionSelect(_Symbol))
{
    Print("まだポジションが見えない");
}

これは特に、

  • 成行注文直後
  • 通信遅延がある環境
  • VPSや回線状況に差がある環境

で起きやすいです。

対策

  • 次のTickで確認する
  • OnTradeTransactionなどの取引イベントで確認する
  • 直後判定を前提にしない

よくある失敗

  • OrderSend成功 = 直後に必ずPositionSelect true だと考える
  • 反映遅延をバグと誤認する

6.5 最も多い原因④:ヘッジ口座で複数ポジションを誤処理している

ヘッジ口座では、同一シンボルで複数ポジションを持てます。
このとき、PositionSelectは複数のうち1つを対象にする設計では不十分です。

つまり、実際にはポジションがあるのに、

  • 想定したポジションを見ていない
  • チケット単位で処理すべきなのにシンボル単位で見ている

という設計ミスが起きます。

対策

  • ヘッジ口座では PositionSelectByTicket() を使う
  • PositionsTotal() とループで処理する

6.6 ログで原因を切り分ける方法

falseの原因を特定するには、ログ出力で状況を見える化するのが最短です。

例:最低限のデバッグ出力

Print("Symbol = ", _Symbol);
Print("PositionsTotal = ", PositionsTotal());

if(!PositionSelect(_Symbol))
{
    Print("PositionSelect failed for symbol: ", _Symbol);
    return;
}

Print("PositionSelect success");

これで少なくとも以下を確認できます。

  • 対象シンボルが何か
  • そもそもポジション総数があるか
  • そのシンボルで選択できたか

実務上のコツ

  • false時のログは必ず残す
  • 成功時も一度はログを出して比較する
  • ログなしで推測だけで直そうとしない

6.7 false時の安全な書き方

PositionSelectがfalseでも、そのまま後続処理を書くと不安定になります。
そのため、早期returnが基本です。

if(!PositionSelect(_Symbol))
{
    return;
}

少し丁寧に書くなら、理由を追いやすい形にします。

if(!PositionSelect(_Symbol))
{
    Print("No selected position for symbol: ", _Symbol);
    return;
}

この書き方の利点

  • 不正なPositionGetを防げる
  • コードが読みやすい
  • バグの位置を特定しやすい

6.8 よくある失敗まとめ

失敗①:falseでもPositionGetを続ける

PositionSelect(_Symbol);
double profit = PositionGetDouble(POSITION_PROFIT); // 危険

失敗②:ハードコードしたシンボルを使う

PositionSelect("EURUSD");

失敗③:注文直後の即時判定に依存する

OrderSend(...);
PositionSelect(_Symbol);

失敗④:ヘッジ口座なのに単純なPositionSelectで済ませる


6.9 トラブル時の確認手順

PositionSelectがfalseのときは、以下の順で確認すると切り分けしやすいです。

  • PositionsTotal() が0ではないか確認
  • _Symbol の値をログ出力する
  • ③ 直前に注文したなら反映タイミングを疑う
  • ④ 口座タイプがヘッジか確認する
  • ⑤ false時に即returnしているか確認する

この順序で見ると、感覚ではなく構造で原因を追えます。

7. PositionSelectを使う際の注意点と安全な実装ルール

7.1 戻り値を必ず確認する

PositionSelectを使う上で最も重要なのは、戻り値を無視しないことです。
この関数は true または false を返しますが、ここを確認せずに後続の PositionGetDoublePositionGetInteger を呼ぶと、意図しない値取得やロジック崩壊の原因になります。

悪い例

PositionSelect(_Symbol);
double profit = PositionGetDouble(POSITION_PROFIT);

この書き方では、PositionSelect が失敗していても処理が続いてしまいます。

良い例

if(!PositionSelect(_Symbol))
{
    return;
}

double profit = PositionGetDouble(POSITION_PROFIT);

注意点

  • falseは「異常」とは限らない
  • ただし、falseのまま先へ進むのは危険
  • 取得処理の前に毎回判定する

7.2 PositionSelectは毎回呼ぶ

初心者が誤解しやすいのが、一度PositionSelectしたら、その後も同じポジションが維持されるという考え方です。
実務ではこの前提に依存しないほうが安全です。

なぜなら、MQL5の選択状態は別処理や別Selectで上書きされる可能性があるからです。
そのため、必要な情報を取得する直前にPositionSelectを呼ぶのが基本になります。

推奨パターン

if(PositionSelect(_Symbol))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

よくある失敗

  • OnInitで1回だけSelectして使い回す
  • 別関数内でSelectが上書きされる
  • 前回の成功状態を前提にする

実務ルール

  • PositionGetの直前にPositionSelect
  • 使い回しより再選択を優先
  • 冗長でも安全性を取る

7.3 シンボル指定は原則として _Symbol を使う

PositionSelectの引数にはシンボル名を文字列で渡しますが、固定文字列を直接書くと環境差に弱くなります。
特にブローカーによっては、シンボル名に接尾辞や接頭辞が付くため、"EURUSD" がそのまま存在しないことがあります。

非推奨

PositionSelect("EURUSD");

推奨

PositionSelect(_Symbol);

_Symbol は現在のチャートのシンボル名です。
そのため、チャート単位でEAを動かす一般的な設計では最も安全です。

つまずきポイント

  • バックテストでは動くのに本番で動かない
  • ブローカー変更後にfalseが増える
  • シンボル名の表記差を見落とす

例外

複数シンボルEAでは、対象シンボルの配列や変数を明示的に管理する必要があります。
その場合でも、実際に使うシンボル名が正しいかログ確認は必須です。


7.4 ヘッジ口座ではPositionSelectだけで完結しない

PositionSelectは、単一シンボルのポジション確認には便利ですが、複数ポジションを正確に扱う用途には向きません。
特にヘッジ口座では、同じシンボルに対して複数ポジションを保有できるため、PositionSelectだけで全件処理しようとすると設計が破綻します。

危険な誤解

  • PositionSelect(_Symbol) でそのシンボルの全ポジションを見られる
  • 1シンボル1ポジション前提で常に通る

実務での安全判断

  • ネッティング口座:PositionSelect中心で可
  • ヘッジ口座:PositionsTotal()PositionSelectByTicket() を併用

判断を誤ると起きる問題

  • 一部ポジションしか見ない
  • 合計損益がずれる
  • 想定外のポジションを残す

7.5 false時は早期returnで止める

PositionSelectが失敗したときに、そのまま処理を続けると、後続コードの意味が崩れます。
そのため、falseならその場で処理を止めるのが安全です。

推奨テンプレート

if(!PositionSelect(_Symbol))
{
    Print("No position for symbol: ", _Symbol);
    return;
}

この形にしておくと、

  • PositionGet系の誤使用を防げる
  • ログで原因追跡しやすい
  • 分岐が明確になる

という利点があります。

注意点

  • false時に代替処理が必要な場合は、returnの代わりに別分岐へ進める
  • ただし、未選択のままPositionGetを呼ばないのは共通原則

7.6 ロジックを関数化して再利用する

PositionSelect周辺の処理は毎回似た形になるため、再利用しやすいように関数化すると保守性が上がります。

例:現在の利益を返す関数

double GetCurrentPositionProfit()
{
    if(!PositionSelect(_Symbol))
        return 0.0;

    return PositionGetDouble(POSITION_PROFIT);
}

メリット

  • 書き忘れを防げる
  • Select → Get の順序が固定される
  • 記事やEA全体の品質が安定する

注意点

  • 0.0 を「ポジションなし」と「利益ゼロ」で区別できない
  • 必要に応じてbool返却や参照渡しに変更する

7.7 PositionSelect運用ルールの実務チェックリスト

PositionSelectを安全に使うなら、最低限以下を守ると安定しやすくなります。

  • 取得前に毎回PositionSelectする
  • 戻り値を必ず確認する
  • false時は早期returnする
  • シンボル指定は原則 _Symbol
  • ヘッジ口座では単体使用に依存しない
  • ログで失敗原因を追えるようにする

このルールを守るだけで、PositionSelect周りの初歩的な事故は大きく減らせます。

8. PositionSelectと関連関数の違い(混同防止)

8.1 PositionSelectとPositionSelectByTicketの違い

MQL5では、ポジション選択に2つの主要な方法があります。

  • PositionSelect(symbol):シンボルで選択
  • PositionSelectByTicket(ticket):チケット番号で選択

比較表

項目PositionSelectPositionSelectByTicket
指定方法シンボルチケット
精度不確定(複数時)完全一致
ヘッジ口座不適切必須
用途単純判定厳密制御

実務判断

  • 単一ポジション → PositionSelect
  • 複数ポジション → PositionSelectByTicket

コード比較

// シンボル指定
PositionSelect(_Symbol);

// チケット指定
PositionSelectByTicket(ticket);

注意点

  • チケットは一意(ユニークな識別子)
  • ヘッジ口座ではチケット単位で管理するのが基本

8.2 PositionGet系との役割の違い

PositionSelectとPositionGetは、役割が完全に分離されています。

役割整理

  • PositionSelect:対象を選ぶ
  • PositionGet:選ばれた対象の情報を取得

間違った理解

  • PositionSelect = データ取得
  • PositionGet = 単体で使える

→ どちらも誤り


正しいセット構造

if(PositionSelect(_Symbol))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

よくある失敗

  • SelectせずにGet
  • Getの値だけ見て判断

8.3 OrderSelectとの違い(重要)

MQL4経験者が最も混乱するのが、OrderSelectとの違いです。

MQL4(旧仕様)

  • 注文・ポジションが混在
  • OrderSelectで全て扱う

MQL5(現行仕様)

  • 注文(Order)
  • ポジション(Position)
  • 約定履歴(History)

が完全に分離されています。


比較

項目OrderSelectPositionSelect
対象注文ポジション
MQL4主流なし
MQL5あり(別用途)主流

実務的な違い

  • OrderSelect:未約定注文(指値・逆指値)
  • PositionSelect:保有中ポジション

典型的な誤り

OrderSelect(...); // ポジション取得のつもり

→ MQL5では無効な発想


8.4 PositionsTotalとの関係

PositionsTotal() は、現在のポジション数を取得する関数です。

int total = PositionsTotal();

役割

  • ポジション数の確認
  • ループ処理の起点

組み合わせ例

for(int i = 0; i < PositionsTotal(); i++)
{
    ulong ticket = PositionGetTicket(i);

    if(PositionSelectByTicket(ticket))
    {
        // 処理
    }
}

注意点

  • PositionsTotalだけでは情報取得できない
  • 必ずSelectが必要

8.5 PositionGetTicketとの関係

PositionGetTicket(index) は、インデックスからチケット番号を取得します。

ulong ticket = PositionGetTicket(i);

流れ

  • index → ticket
  • ticket → PositionSelectByTicket

セット構造

ulong ticket = PositionGetTicket(i);

if(PositionSelectByTicket(ticket))
{
    double profit = PositionGetDouble(POSITION_PROFIT);
}

8.6 よくある混同パターン

混同①:PositionSelect = 全ポジション取得

→ 実際は1つのみ


混同②:PositionGet = 単独で使える

→ Select前提


混同③:OrderSelectでポジション取得

→ MQL5では用途が違う


混同④:チケット不要と思っている

→ ヘッジ口座では必須


8.7 実務での正しい使い分け

以下の基準で使い分けると安全です。

目的使用関数
単一ポジション確認PositionSelect
複数ポジション処理PositionSelectByTicket
情報取得PositionGet系
件数確認PositionsTotal
注文操作Order系

8.8 安全な設計パターン(まとめ)

  • Selectは必ず明示的に行う
  • チケットベースで処理できる設計を優先
  • SelectとGetを分離して考える
  • OrderとPositionを混同しない

9. FAQ(よくある質問と回答)

Q1. PositionSelectを使わずにPositionGetは使えますか?

A. 使えません。
PositionGet系関数は、事前にPositionSelectで対象を選択していることが前提です。
Selectなしで呼び出すと、0や不正な値になる可能性があります。


Q2. PositionSelectがfalseになるのはエラーですか?

A. 必ずしもエラーではありません。
単に「ポジションが存在しない」場合でもfalseになります。
エラーかどうかは、状況(保有しているはずか)で判断します。


Q3. PositionSelectは1回呼べば使い回せますか?

A. 推奨されません。
内部状態は他の処理で上書きされる可能性があるため、
PositionGetの直前に毎回呼ぶのが安全です。


Q4. 複数ポジションがある場合、PositionSelectで全部取得できますか?

A. できません。
PositionSelectは1つのポジションのみ対象にします。
複数ある場合は、PositionSelectByTicket とループ処理が必要です。


Q5. シンボルは “EURUSD” と書けばいいですか?

A. 環境によります。
ブローカーによっては EURUSDm など表記が異なるため、
通常は _Symbol を使うのが安全です。


Q6. OrderSendの直後にPositionSelectがfalseになります

A. 反映遅延の可能性があります。
注文直後はポジション情報がまだ更新されていない場合があります。
次のTickや取引イベントで確認するのが安全です。


Q7. ネッティング口座とヘッジ口座で使い方は変わりますか?

A. はい、変わります。

  • ネッティング口座:PositionSelectで問題なし
  • ヘッジ口座:PositionSelectByTicket+ループが必要

設計を間違えると、ポジションの一部しか扱えません。


Q8. PositionSelectとOrderSelectの違いは何ですか?

A. 対象が異なります。

  • PositionSelect:保有中ポジション
  • OrderSelect:未約定注文(指値・逆指値など)

MQL4と異なり、MQL5では完全に分離されています。