MQL5 trade request structureとは?MqlTradeRequestの使い方・全項目・注文例を完全解説

目次

1. MQL5のtrade request structureとは何か

このセクションでは、MQL5における注文処理の中核である「trade request structure(MqlTradeRequest)」の役割と位置づけを理解します。初心者が最初につまずく「なぜ構造体が必要なのか」も含めて整理します。


1.1 trade request structureの基本概念

MQL5では、注文(エントリー・決済など)を実行する際に
MqlTradeRequest(エムキューエルトレードリクエスト)という構造体を使用します。

構造体とは、
→「複数のデータをまとめて扱うための箱」のことです。

つまり、MqlTradeRequestは
👉「注文に必要な情報をすべてまとめて渡すためのデータセット」です。

例えば、注文には以下のような情報が必要です:

  • 通貨ペア(例:EURUSD)
  • ロット数(取引量)
  • 注文タイプ(Buy / Sell)
  • 価格
  • ストップロス(損切り)
  • テイクプロフィット(利確)

MQL5ではこれらをバラバラに渡すのではなく、
1つの構造体にまとめて OrderSend() に渡す設計になっています。

MqlTradeRequest request;
MqlTradeResult result;

OrderSend(request, result);

この設計により、

  • 注文情報の整合性が保たれる
  • エラー検出がしやすい
  • 拡張性が高い(新しい項目が追加可能)

というメリットがあります。


1.2 なぜ構造体で管理されるのか(設計思想)

MQL4では、OrderSend関数に複数の引数を直接渡していました。

しかしMQL5では設計が大きく変わり、
構造体ベースの注文管理に移行しています。

この理由は主に以下です:

■ 理由1:拡張性(将来対応)

金融システムでは、注文条件が増えることが多いです。
構造体であれば項目追加が容易です。

■ 理由2:可読性(コードの明確化)

request.volume = 0.1;
request.price = Ask;
request.type = ORDER_TYPE_BUY;

このように書くことで、
👉「何を設定しているか」が一目で分かります。

■ 理由3:安全性(バグ防止)

引数が多い関数では、順番ミスが起きやすいです。
構造体なら「名前付き」で管理されるため、誤設定が減ります。


1.3 MQL4との違い(重要)

初心者〜中級者が最も混乱するポイントです。

■ MQL4(旧)

OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0);

■ MQL5(新)

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

👉 大きな違いは「構造体を使うかどうか」です。


よくあるつまずき・注意点

■ ① とりあえずOrderSendだけ使おうとする

→ MQL5では通用しない
→ 必ずMqlTradeRequestの理解が必要

■ ② コピペで動かそうとする

→ ブローカー環境により失敗する
→ 特に以下に注意:

  • type_filling(約定方式)
  • 最小ロット
  • ストップ距離

■ ③ 変数未初期化

MqlTradeRequest request; // ←初期化不足

👉 推奨

MqlTradeRequest request = {};

このセクションのまとめ(重要ポイント)

  • MqlTradeRequestは「注文情報の箱」
  • OrderSendは「その箱を渡す関数」
  • MQL5は構造体ベースの設計に変わっている
  • 初心者はここで必ずつまずくため、理解が最優先

2. MqlTradeRequestの全体構造と必須フィールド

このセクションでは、MqlTradeRequestに含まれる全フィールドと、その中でも「必須で設定すべき項目」を整理します。初心者が迷いやすいポイントを、実務で使う優先度ベースで解説します。


2.1 MqlTradeRequestの構造体一覧

MqlTradeRequestは以下のようなフィールド(メンバ変数)で構成されています。

struct MqlTradeRequest
{
   ENUM_TRADE_REQUEST_ACTIONS action;
   ulong                      magic;
   ulong                      order;
   string                     symbol;
   double                     volume;
   double                     price;
   double                     stoplimit;
   double                     sl;
   double                     tp;
   ulong                      deviation;
   ENUM_ORDER_TYPE            type;
   ENUM_ORDER_TYPE_FILLING    type_filling;
   ENUM_ORDER_TYPE_TIME       type_time;
   datetime                   expiration;
   string                     comment;
   ulong                      position;
   ulong                      position_by;
};

■ 主に使うフィールド(実務優先)

フィールド意味
action実行する操作(新規注文など)
symbol通貨ペア
volumeロット数
price注文価格
type注文タイプ(Buy/Sell)
slストップロス
tpテイクプロフィット
deviation許容スリッページ
type_filling約定方式

👉 実務では「すべて覚える必要はない」
👉 まずは上記9項目を優先して理解


■ あまり使わない(状況依存)

フィールド用途
magicEA識別番号
order既存注文の操作
stoplimit指値+逆指値
type_time有効期限設定
expiration注文期限
positionポジション指定
position_by両建て決済

👉 初心者は後回しでOK


2.2 必須項目と任意項目の違い

MQL5では「全部の項目を設定する必要はありません」。
しかし、最低限設定しないと注文が通らない項目があります。


■ 最低限必要な項目(成行注文)

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

■ 必須項目まとめ

  • action(何をするか)
  • symbol(銘柄)
  • volume(ロット)
  • type(注文種別)
  • price(価格)
  • type_filling(約定方法)※環境依存
  • deviation(スリッページ許容)

■ 任意項目(推奨)

  • sl(損切り)
  • tp(利確)
  • magic(EA識別)

👉 任意だが「実務ではほぼ必須」


2.3 最低限の注文に必要な構成

ここでは、最小限で「確実に通る構成」を示します。


■ 最小構成コード(Buy注文)

MqlTradeRequest request = {};
MqlTradeResult  result  = {};

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

OrderSend(request, result);

■ 手順(初心者向け)

  1. requestを初期化する
  2. 必須項目を設定する
  3. OrderSendに渡す

よくあるつまずき・注意点

■ ① type_filling未設定

→ 注文拒否(特に海外ブローカー)

対策:

request.type_filling = ORDER_FILLING_IOC; // 環境により変更

■ ② priceの取得ミス

→ BuyなのにBidを使うなど

対策:

  • Buy → Ask
  • Sell → Bid

■ ③ volumeエラー

→ 最小ロット未満

対策:

double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

■ ④ request未初期化

→ 不定値でエラー

必ず:

MqlTradeRequest request = {};

このセクションのまとめ(重要ポイント)

  • MqlTradeRequestは多数のフィールドを持つが、全部は不要
  • 必須項目だけでも注文は可能
  • type_filling・price・volumeが特に重要
  • エラーの多くは「設定不足」か「環境差」

3. action・type・type_fillingの違いと正しい使い分け

このセクションでは、MqlTradeRequestで最も混乱しやすい「action」「type」「type_filling」の違いを整理します。ここを誤ると注文は通らないため、実務上の最重要ポイントです。


3.1 actionとは何か(注文の“目的”を指定)

action
👉「このリクエストで何をしたいのか」を定義する項目です。

主に使うのは以下です:

定数意味
TRADE_ACTION_DEAL成行注文(即時約定)
TRADE_ACTION_PENDING指値・逆指値注文
TRADE_ACTION_SLTPSL/TPの変更
TRADE_ACTION_CLOSE_BY両建て決済

■ 最もよく使う(初心者はこれだけでOK)

request.action = TRADE_ACTION_DEAL;

👉 成行注文(最も基本)


■ 指値・逆指値の場合

request.action = TRADE_ACTION_PENDING;

👉 この場合は type が重要になる


3.2 typeとは何か(注文の“種類”)

type
👉「BuyかSellか」「指値か逆指値か」を決める項目です。


■ 成行注文

定数意味
ORDER_TYPE_BUY成行買い
ORDER_TYPE_SELL成行売り

■ 指値注文(価格が有利になったら)

定数意味
ORDER_TYPE_BUY_LIMIT安くなったら買う
ORDER_TYPE_SELL_LIMIT高くなったら売る

■ 逆指値注文(ブレイク狙い)

定数意味
ORDER_TYPE_BUY_STOP上抜けで買う
ORDER_TYPE_SELL_STOP下抜けで売る

■ 例(成行Buy)

request.action = TRADE_ACTION_DEAL;
request.type   = ORDER_TYPE_BUY;

👉 actionとtypeはセットで考える


3.3 type_fillingとは何か(約定方式)

ここが最もエラーが出やすいポイントです。

type_filling
👉「どのように約定させるか」を指定します。


■ 主な約定方式

定数意味
ORDER_FILLING_FOK全量約定 or 全キャンセル
ORDER_FILLING_IOC一部約定OK
ORDER_FILLING_RETURN未約定分を残す

■ 実務での使い分け

  • 安定重視 → IOC(推奨)
  • 厳密な約定 → FOK
  • 指値注文 → RETURN(環境依存)

■ 例

request.type_filling = ORDER_FILLING_IOC;

3.4 3つの関係性(重要)

この3つは独立ではなく、組み合わせで意味が決まるのがポイントです。


■ 正しい組み合わせ例(成行Buy)

request.action = TRADE_ACTION_DEAL;
request.type   = ORDER_TYPE_BUY;
request.type_filling = ORDER_FILLING_IOC;

■ 指値注文の例

request.action = TRADE_ACTION_PENDING;
request.type   = ORDER_TYPE_BUY_LIMIT;
request.type_filling = ORDER_FILLING_RETURN;

👉 この3つが噛み合っていないと
→ 注文拒否(エラー)になります


よくあるつまずき・注意点

■ ① actionとtypeの不一致

例:

action = TRADE_ACTION_DEAL;
type   = ORDER_TYPE_BUY_LIMIT;

👉 成行なのに指値 → エラー


■ ② type_fillingがブローカー非対応

→ 「Invalid filling mode」エラー

対策:

int filling = (int)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);

👉 ブローカー仕様を確認


■ ③ 指値注文なのにprice未設定

→ 注文失敗


■ ④ RETURNを成行で使う

→ 環境によってはエラー


このセクションのまとめ(重要ポイント)

  • action=何をするか(目的)
  • type=注文の種類
  • type_filling=約定方法
  • 3つは必ずセットで整合性を取る必要がある
  • エラーの大半はこの組み合わせミス

4. OrderSendを使った実践コード(成行注文・指値注文)

このセクションでは、MqlTradeRequestを使って実際に注文を出す「完成形コード」を提示します。成行注文と指値注文の両方を扱い、実務でそのまま使えるレベルまで具体化します。


4.1 成行注文(Buy)の完全コード

まずは最も基本となる「成行Buy」の例です。

MqlTradeRequest request = {};
MqlTradeResult  result  = {};

// 現在価格取得
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

// リクエスト設定
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type   = ORDER_TYPE_BUY;
request.price  = ask;
request.sl     = ask - 100 * _Point;
request.tp     = ask + 100 * _Point;
request.deviation = 10;
request.type_filling = ORDER_FILLING_IOC;

// 注文実行
if(OrderSend(request, result))
{
   Print("注文成功: ", result.retcode);
}
else
{
   Print("注文失敗: ", result.retcode);
}

■ 手順整理(初心者向け)

  • 現在価格を取得(Ask)
  • requestに必要項目を設定
  • OrderSendを実行
  • resultで結果確認

■ 補足(重要)

  • _Point:最小価格単位(pipsではない点に注意)
  • retcode:注文結果コード(成功・失敗判定)

4.2 成行注文(Sell)の完全コード

Sellの場合は価格がBidになる点に注意します。

MqlTradeRequest request = {};
MqlTradeResult  result  = {};

double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.1;
request.type   = ORDER_TYPE_SELL;
request.price  = bid;
request.sl     = bid + 100 * _Point;
request.tp     = bid - 100 * _Point;
request.deviation = 10;
request.type_filling = ORDER_FILLING_IOC;

OrderSend(request, result);

4.3 指値注文(Buy Limit)の完全コード

次に、価格指定で注文する「指値注文」です。

MqlTradeRequest request = {};
MqlTradeResult  result  = {};

// 指値価格(現在より下)
double price = SymbolInfoDouble(_Symbol, SYMBOL_BID) - 200 * _Point;

request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.1;
request.type   = ORDER_TYPE_BUY_LIMIT;
request.price  = price;
request.sl     = price - 100 * _Point;
request.tp     = price + 100 * _Point;
request.type_filling = ORDER_FILLING_RETURN;
request.type_time = ORDER_TIME_GTC;

OrderSend(request, result);

■ ポイント

  • action = PENDING
  • type = LIMIT系
  • priceは現在価格より下に設定

4.4 エラーチェックの基本(retcode確認)

OrderSendは「trueでも失敗している場合」があるため、
必ずretcodeを確認します。

if(result.retcode != TRADE_RETCODE_DONE)
{
   Print("エラーコード: ", result.retcode);
}

■ よく使うretcode

コード意味
TRADE_RETCODE_DONE成功
TRADE_RETCODE_REJECT拒否
TRADE_RETCODE_INVALID_VOLUMEロット不正
TRADE_RETCODE_INVALID_PRICE価格不正

よくあるつまずき・注意点

■ ① OrderSendがtrueでも失敗している

→ retcode未確認

👉 必ず確認する


■ ② SL/TPが近すぎる

→ ブローカー制限で拒否

対策:

SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

■ ③ 指値価格が不正

→ Buy Limitなのに現在より上など


■ ④ deviationが小さすぎる

→ 約定失敗


■ ⑤ 約定方式ミス

→ IOC/FOKが環境に合っていない


このセクションのまとめ(重要ポイント)

  • OrderSendはrequestとresultのセットで使う
  • 成行・指値でactionとtypeが変わる
  • retcode確認が必須
  • エラー原因の多くは「環境依存」

5. 注文が通らない原因とデバッグ方法(実務対応)

このセクションでは、MqlTradeRequestを正しく書いているにも関わらず「注文が通らない」場合の原因を体系的に整理します。実務ではここが最も重要であり、問題の切り分けができるかどうかで開発効率が大きく変わります。


5.1 注文失敗の基本構造(原因の分類)

注文が失敗する原因は大きく3つに分類できます。

■ ① パラメータエラー(設定ミス)

  • volume(ロット)
  • price(価格)
  • SL/TP(距離制限)

■ ② 環境依存エラー(ブローカー仕様)

  • type_filling(約定方式)
  • 最小ロット
  • ストップレベル

■ ③ 状態エラー(タイミング・市場)

  • マーケットクローズ
  • 価格変動
  • 証拠金不足

👉 まずは「どのカテゴリか」を切り分けることが重要


5.2 retcodeを使ったエラー特定

最も重要なのは result.retcode です。

Print("retcode: ", result.retcode);

■ よくあるエラーと対策

retcode原因対策
TRADE_RETCODE_INVALID_VOLUMEロット不正最小ロット確認
TRADE_RETCODE_INVALID_PRICE価格不正Ask/Bid確認
TRADE_RETCODE_REJECT条件不一致filling見直し
TRADE_RETCODE_NO_MONEY証拠金不足ロット減らす

5.3 デバッグの基本手順(実務フロー)

以下の手順で原因を特定します。


■ ステップ1:retcode確認

if(result.retcode != TRADE_RETCODE_DONE)
{
   Print("Error: ", result.retcode);
}

■ ステップ2:ログ出力

Print("volume=", request.volume);
Print("price=", request.price);
Print("type=", request.type);

👉 実際に何が送られているか確認


■ ステップ3:環境情報取得

double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

■ ステップ4:約定方式の確認

int filling = (int)SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
Print("filling=", filling);

5.4 典型的なエラーケース


■ ケース1:注文が一切通らない

原因:

  • type_filling不一致

対策:

request.type_filling = ORDER_FILLING_IOC;

■ ケース2:SL/TP設定で失敗

原因:

  • ストップ距離不足

対策:

int stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

■ ケース3:指値注文が拒否される

原因:

  • priceが無効(方向ミス)

例:

  • Buy Limitなのに現在価格より上

■ ケース4:ランダムに失敗する

原因:

  • 価格変動(スリッページ)

対策:

request.deviation = 20;

5.5 実務での安定化テクニック


■ ① 最小ロットを自動調整

double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
request.volume = MathMax(0.1, minLot);

■ ② ストップ距離を考慮

int stopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double sl = request.price - stopLevel * _Point;

■ ③ リトライ処理

for(int i=0; i<3; i++)
{
   if(OrderSend(request, result) && result.retcode == TRADE_RETCODE_DONE)
      break;
}

よくあるつまずき・注意点

■ ① 「コードは正しいのに動かない」

→ 環境依存(ほぼこれ)


■ ② ストラテジーテスターでは動く

→ 実口座では失敗

理由:

  • 約定方式
  • スリッページ
  • 制限値

■ ③ Printログを見ていない

→ 原因特定できない


■ ④ 一発で成功させようとする

→ 実務ではリトライ前提


このセクションのまとめ(重要ポイント)

  • エラーは「設定・環境・市場」の3分類で考える
  • retcode確認が最重要
  • デバッグはログ+環境取得で行う
  • 実運用ではリトライ・調整が必須

6. OrderCheckを使った事前検証(注文前チェック)

このセクションでは、OrderSend() の前に OrderCheck() を使って注文内容を検証する方法を解説します。実務では、いきなり注文送信するより、先にチェックして失敗要因を潰すほうが安定します。特にロット、証拠金、ストップ距離、注文条件の確認に有効です。


6.1 OrderCheckとは何か

OrderCheck() は、
👉 この注文内容で発注可能かを事前に確認する関数です。

OrderSend() は実際に注文を送りますが、OrderCheck() は送信前の審査に近い役割です。
そのため、以下のような問題を先に見つけやすくなります。

  • ロット数が不正
  • 必要証拠金が足りない
  • SL/TPが不正
  • 注文価格が条件に合っていない

基本形は以下です。

MqlTradeRequest     request = {};
MqlTradeCheckResult check   = {};

bool ok = OrderCheck(request, check);

check には、チェック結果のコードや証拠金関連の情報が入ります。
つまり、OrderSend() の結果確認が「事後」なら、OrderCheck() は「事前」です。


6.2 OrderCheckの基本コード

成行Buy前にチェックする例です。

MqlTradeRequest     request = {};
MqlTradeCheckResult check   = {};
MqlTradeResult      result  = {};

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

request.action       = TRADE_ACTION_DEAL;
request.symbol       = _Symbol;
request.volume       = 0.1;
request.type         = ORDER_TYPE_BUY;
request.price        = ask;
request.sl           = ask - 100 * _Point;
request.tp           = ask + 100 * _Point;
request.deviation    = 10;
request.type_filling = ORDER_FILLING_IOC;

// 事前チェック
if(!OrderCheck(request, check))
{
   Print("OrderCheck失敗: ", check.retcode);
   return;
}

// チェックOKなら送信
if(OrderSend(request, result))
{
   Print("注文送信成功: ", result.retcode);
}
else
{
   Print("注文送信失敗: ", result.retcode);
}

■ 実務での基本手順

  • MqlTradeRequest を組み立てる
  • OrderCheck() で事前確認する
  • 問題なければ OrderSend() する
  • 問題があればログを出して終了する

この流れにしておくと、
「なぜ失敗したのか分からない」状態をかなり減らせます。


6.3 MqlTradeCheckResultで確認できること

MqlTradeCheckResult には、注文可否以外にも実務で役立つ情報が入ります。

主に見る項目は以下です。

フィールド意味
retcodeチェック結果コード
balance残高
equity有効証拠金ベースの資産
margin必要証拠金
margin_free余剰証拠金
comment補足メッセージ

例えば、必要証拠金を確認したい場合は以下のように出力できます。

Print("retcode=", check.retcode);
Print("margin=", check.margin);
Print("free margin=", check.margin_free);
Print("comment=", check.comment);

これにより、単に「失敗した」ではなく、
「証拠金不足なのか」「条件不正なのか」を分けて判断できます。


6.4 OrderCheckを使うメリット

■ 1. 証拠金不足を先に検出できる

本番口座でありがちな NO_MONEY 系の問題を事前に把握しやすくなります。

■ 2. ロット計算の検証に使える

自動ロット計算をしているEAでは、計算後のロットが本当に通るか確認できます。

■ 3. デバッグ効率が上がる

OrderSend() 後の失敗だけを見るより、原因切り分けがしやすいです。

■ 4. 危険な注文を弾ける

不正なSL/TPや異常ロットを、本送信前に止められます。


6.5 実務での安全な設計パターン

初心者ほど、注文処理を1か所に詰め込みがちです。
しかし実務では、以下の3段階に分けると安定します。

■ 推奨フロー

  1. リクエストを作る
  2. OrderCheck() で検証する
  3. 問題なければ OrderSend() する

コードの役割を分離すると、後から修正しやすくなります。

// 1. request作成
// 2. OrderCheck
// 3. OrderSend

この構造にしておくと、
将来的に以下も追加しやすくなります。

  • ロット自動調整
  • ストップ距離補正
  • エラー時の再試行
  • ログ保存

よくあるつまずき・注意点

■ ① OrderCheckが通れば必ず約定すると思う

→ そうではありません。
OrderCheck() は事前確認です。
実際の送信時には価格変動や市場状態で失敗することがあります。

■ ② OrderCheckを省略して本番投入する

→ デモでは動いても、本番で失敗率が上がりやすいです。

■ ③ check.retcodeを見ていない

true / false だけでは不十分です。
必ず retcodecomment を確認します。

■ ④ 証拠金計算を自前だけで済ませる

→ 自前計算も有効ですが、最終的には OrderCheck() で口座条件込みの確認をしたほうが安全です。


このセクションのまとめ(重要ポイント)

  • OrderCheck() は注文前の事前検証に使う
  • OrderSend() の前に挟むことで失敗率を下げやすい
  • MqlTradeCheckResult で証拠金やエラー理由を確認できる
  • 実務では「作成 → 検証 → 送信」の3段階設計が安定

7. 再利用しやすく壊れにくい注文処理の設計パターン

このセクションでは、MqlTradeRequest を単発で書いて終わりにせず、EA全体で再利用しやすい構造にする方法を解説します。注文処理は、後から「ロット調整」「SL/TP変更」「エラー対応」を追加しやすい形で作っておくことが重要です。ここを雑に作ると、記事の理解はできても実運用で崩れやすくなります。


7.1 注文処理を1か所に集約する

初心者がやりがちな失敗は、OnTick() の中に直接すべて書くことです。

if(買い条件)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};
   // volume, price, sl, tp, OrderSend...
}

この書き方は最初は動きますが、次の問題が出ます。

  • BuyとSellで重複コードが増える
  • 修正漏れが起きやすい
  • デバッグ箇所が散らばる
  • 指値注文や決済追加で破綻しやすい

そのため、注文処理は専用関数に切り出すのが基本です。


7.2 最低限の関数分離パターン

まずは「Buyを送る関数」を作るだけでも改善します。

bool SendBuyOrder(double volume, double sl, double tp)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = volume;
   request.type         = ORDER_TYPE_BUY;
   request.price        = ask;
   request.sl           = sl;
   request.tp           = tp;
   request.deviation    = 10;
   request.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(request, result))
   {
      Print("Buy注文失敗: ", result.retcode);
      return false;
   }

   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("Buy注文拒否: ", result.retcode);
      return false;
   }

   return true;
}

呼び出し側はシンプルになります。

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl  = ask - 100 * _Point;
double tp  = ask + 100 * _Point;

SendBuyOrder(0.1, sl, tp);

■ この分離のメリット

  • 注文ロジックを再利用できる
  • 失敗時の処理を統一できる
  • OnTick() が読みやすくなる
  • 後で OrderCheck() を追加しやすい

7.3 Buy/Sellを共通化する設計

さらに一歩進めるなら、Buy/Sellを1つの関数で扱います。

bool SendMarketOrder(ENUM_ORDER_TYPE orderType, double volume, double sl, double tp)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   double price = 0.0;

   if(orderType == ORDER_TYPE_BUY)
      price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   else if(orderType == ORDER_TYPE_SELL)
      price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   else
      return false;

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = volume;
   request.type         = orderType;
   request.price        = price;
   request.sl           = sl;
   request.tp           = tp;
   request.deviation    = 10;
   request.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(request, result))
   {
      Print("注文送信失敗: ", result.retcode);
      return false;
   }

   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("注文拒否: ", result.retcode);
      return false;
   }

   return true;
}

これなら、呼び出し側は方向だけ変えれば済みます。

SendMarketOrder(ORDER_TYPE_BUY,  0.1, slBuy, tpBuy);
SendMarketOrder(ORDER_TYPE_SELL, 0.1, slSell, tpSell);

7.4 リクエスト生成と送信を分ける

実務では、さらに
「requestを作る処理」と「送る処理」を分ける
と保守性が上がります。

■ 役割分担の考え方

  • 生成:注文内容を組み立てる
  • 検証:OrderCheck() する
  • 送信:OrderSend() する

例えば以下のような分離です。

void BuildBuyRequest(MqlTradeRequest &request, double volume, double sl, double tp)
{
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = volume;
   request.type         = ORDER_TYPE_BUY;
   request.price        = ask;
   request.sl           = sl;
   request.tp           = tp;
   request.deviation    = 10;
   request.type_filling = ORDER_FILLING_IOC;
}

送信側:

bool ExecuteRequest(MqlTradeRequest &request)
{
   MqlTradeResult result = {};

   if(!OrderSend(request, result))
   {
      Print("送信失敗: ", result.retcode);
      return false;
   }

   if(result.retcode != TRADE_RETCODE_DONE)
   {
      Print("約定失敗: ", result.retcode);
      return false;
   }

   return true;
}

この設計だと、後から以下を入れやすくなります。

  • OrderCheck() の追加
  • ロット補正
  • 許容スリッページの変更
  • ログ出力の標準化
  • 銘柄ごとの分岐

7.5 実務で入れておきたい最低限の防御

注文関数には、最低限以下を入れておくと安定しやすいです。

■ 1. volumeチェック

double minLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

■ 2. stop距離チェック

int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

■ 3. OrderCheck追加

MqlTradeCheckResult check = {};
OrderCheck(request, check);

■ 4. retcodeログ出力

Print("retcode=", result.retcode);

これを毎回手作業で書くのではなく、共通関数にまとめるのがポイントです。


よくあるつまずき・注意点

■ ① OnTickに全部書く

→ 小規模のうちは動いても、すぐ保守不能になります。

■ ② Buy用・Sell用を完全コピペで増やす

→ 後から修正点が増えると事故率が上がります。

■ ③ エラー処理を呼び出し元ごとに変える

→ ログの形式がバラバラになり、解析しにくくなります。

■ ④ request生成と送信を分けない

OrderCheck() や条件補正を入れにくいです。

■ ⑤ 将来の拡張を想定しない

→ 指値注文、分割決済、複数銘柄対応で崩れます。


このセクションのまとめ(重要ポイント)

  • 注文処理は関数化して1か所に集約する
  • Buy/Sellの重複コードはできるだけ共通化する
  • 「生成」「検証」「送信」を分離すると壊れにくい
  • 実務ではロット・ストップ距離・retcode確認を共通化する

8. ブローカー環境や実口座で失敗しやすい注意点

このセクションでは、MqlTradeRequest のコード自体は正しく見えても、ブローカー仕様・口座種別・実行環境の差によって注文が失敗する典型パターンを整理します。MQL5の注文処理は、言語仕様だけで完結せず、取引環境の制約も前提にする必要があります。


8.1 ブローカーごとに約定条件が違う

MQL5では同じコードでも、ブローカーによって通る注文と通らない注文があります。特に差が出やすいのは以下です。

  • type_filling(約定方式)
  • 最小ロット・ロット刻み
  • SYMBOL_TRADE_STOPS_LEVEL(最小ストップ距離)
  • 対応している注文種別
  • 取引時間

例えば、ORDER_FILLING_IOC は通るが ORDER_FILLING_RETURN は拒否される、といった差があります。
そのため、固定値を決め打ちするより、まず銘柄情報を取得して確認するほうが安全です。

long fillingMode = SymbolInfoInteger(_Symbol, SYMBOL_FILLING_MODE);
double minLot    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double lotStep   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
int stopLevel    = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);

8.2 デモ口座では動くのに本番で失敗する理由

これは非常によくあります。主な理由は次の通りです。

  • デモは約定しやすく、価格変動の影響が軽い
  • 本番は流動性(注文の通りやすさ)が変化する
  • スプレッド拡大時に pricesl/tp が不適切になる
  • ニュース時に deviation が足りない
  • 証拠金条件が厳しくなる

つまり、テスター・デモ・本番は同一ではありません
テスターで成功したコードをそのまま本番投入するのではなく、最低でも以下を入れておくべきです。

  • OrderCheck() による事前確認
  • retcode のログ出力
  • ロットとストップ距離の補正
  • スプレッド異常時の発注回避

8.3 VPS・複数EA運用で起きる実務上の問題

VPS(仮想サーバー)や複数EA運用では、単体検証では見えない問題が出ます。

■ よくある問題

  • 複数EAが同時に発注して想定外のポジションを持つ
  • magic 未設定で他EAの注文と区別できない
  • 再起動後に状態管理がずれる
  • 通信遅延で価格ズレが増える

対策として、少なくとも magic は設定しておくべきです。

request.magic = 10001;

また、ポジション管理側でも magicsymbol を条件に絞って扱わないと、別EAの注文を誤って変更・決済する危険があります。


8.4 実口座前に確認したいチェック項目

実口座投入前は、次を最低限確認してください。

  • 最小ロットとロット刻み
  • 対応する type_filling
  • 最小ストップ距離
  • その銘柄の取引時間
  • スプレッド拡大時の挙動
  • magic による識別
  • retcode の記録

よくあるつまずき・注意点

■ ① テスター成功=本番成功だと思う

→ これは危険です。実口座は約定条件が別です。

■ ② ブローカー差を無視する

→ 同じEAでも業者変更で失敗率が変わります。

■ ③ magic を使わない

→ 複数EA運用で事故の原因になります。

■ ④ 固定のSL/TP幅を全銘柄に使う

→ 銘柄ごとのボラティリティ差を無視すると不適切になります。


このセクションのまとめ(重要ポイント)

  • MQL5の注文処理は、コードだけでなく取引環境にも依存する
  • ブローカー差・口座差・本番差を前提に設計する必要がある
  • 実務では magicOrderCheck()、環境取得を組み合わせると安定しやすい
  • テスターで終わらせず、実口座前の確認工程を必ず入れる

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

Q1. MqlTradeRequestは必ず使わないといけませんか?

回答方針:
はい、MQL5では必須です。MQL4のように直接OrderSendへ複数引数を渡す方式は使えず、注文はすべてMqlTradeRequestを通じて行います。


Q2. type_fillingはどれを使えばいいですか?

回答方針:
環境依存です。まずは ORDER_FILLING_IOC を試し、エラーが出る場合は SymbolInfoInteger(..., SYMBOL_FILLING_MODE) で対応方式を確認します。ブローカーごとに異なります。


Q3. OrderSendがtrueなのに注文が通っていません

回答方針:
OrderSend() の戻り値ではなく result.retcode を確認してください。trueは「送信成功」であり、「約定成功」ではありません。TRADE_RETCODE_DONE を確認する必要があります。


Q4. SL/TPを設定するとエラーになります

回答方針:
最小ストップ距離(SYMBOL_TRADE_STOPS_LEVEL)を下回っている可能性があります。銘柄ごとに制限があるため、値を取得して調整する必要があります。


Q5. デモでは動くのに本番で失敗します

回答方針:
約定条件・スプレッド・流動性の違いが原因です。本番では deviation を広げる、OrderCheck() を使う、ログを確認するなどの対策が必要です。


Q6. volumeエラーが出る原因は何ですか?

回答方針:
最小ロット未満、またはロット刻みに合っていない可能性があります。SYMBOL_VOLUME_MINSYMBOL_VOLUME_STEP を取得して補正します。


Q7. 指値注文が通らないのはなぜですか?

回答方針:
価格方向が間違っている可能性があります。

  • Buy Limit → 現在価格より下
  • Sell Limit → 現在価格より上
    条件が逆だと拒否されます。

Q8. OrderCheckは必ず使うべきですか?

回答方針:
必須ではありませんが、実務では強く推奨されます。証拠金不足や条件エラーを事前に検出できるため、特に自動売買では安定性が大きく向上します。