技術辞典

MQL5 ENUM_ORDER_TYPEの基本|注文種類とMqlTradeRequest.typeの指定

EAファンクラブ

MQL5でOrderSendを使う時は、MqlTradeRequestのtypeへ注文種類を指定します。

この注文種類を表す列挙型がENUM_ORDER_TYPEです。成行のBUY / SELLだけでなく、指値、逆指値、StopLimit、Close ByなどもENUM_ORDER_TYPEで指定します。

EAが注文しない、意図しない注文種別になる、指値と逆指値を間違える、StopLimitの価格指定が分からない、といった問題は、ENUM_ORDER_TYPEとMqlTradeRequest.typeの整理から確認すると原因を追いやすくなります。

このページでは、MQL5のENUM_ORDER_TYPEの基本を、注文種類、Buy系とSell系、指値と逆指値、StopLimit、MqlTradeRequest.type、注文種類ミスのログ確認に分けて整理します。

なお、このページはMQL5開発における技術確認を目的とした内容です。売買判断、推奨エントリー、推奨ロット、利益保証、損失回避保証を行うものではありません。

ENUM_ORDER_TYPEとは何か

ENUM_ORDER_TYPEは、MQL5で注文種類を表す列挙型です。

OrderSendで注文要求を送る時は、MqlTradeRequest構造体を作成し、その中のtypeへ注文種類を指定します。

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

request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type   = ORDER_TYPE_BUY;

OrderSend(request, result);

上記の例では、request.typeへORDER_TYPE_BUYを指定しています。

ただし、注文処理では、request.action、request.type、request.price、request.stoplimit、request.type_filling、request.type_timeなどを組み合わせて指定します。typeだけを見ても、注文要求全体が正しいとは限りません。

ENUM_ORDER_TYPEの主な種類

ENUM_ORDER_TYPEには、成行注文、指値注文、逆指値注文、StopLimit注文、Close By注文があります。

定数分類意味
ORDER_TYPE_BUY成行系買いの成行注文
ORDER_TYPE_SELL成行系売りの成行注文
ORDER_TYPE_BUY_LIMIT指値系買い指値注文
ORDER_TYPE_SELL_LIMIT指値系売り指値注文
ORDER_TYPE_BUY_STOP逆指値系買い逆指値注文
ORDER_TYPE_SELL_STOP逆指値系売り逆指値注文
ORDER_TYPE_BUY_STOP_LIMITStopLimit系買いStopLimit注文
ORDER_TYPE_SELL_STOP_LIMITStopLimit系売りStopLimit注文
ORDER_TYPE_CLOSE_BY決済系反対ポジションによるClose By注文

EA開発では、成行、指値、逆指値、StopLimitを混同しないことが重要です。

成行注文のBUY / SELL

成行注文では、ORDER_TYPE_BUYまたはORDER_TYPE_SELLを指定します。

BUYでは買い方向、SELLでは売り方向の注文要求を作ります。成行注文でTRADE_ACTION_DEALを使う場合、注文タイプと価格の扱いは銘柄の約定方式によって変わります。

bool SendMarketOrder(const ENUM_ORDER_TYPE order_type,
                     const double volume,
                     const ulong magic)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action = TRADE_ACTION_DEAL;
   request.symbol = _Symbol;
   request.volume = volume;
   request.type   = order_type;
   request.magic  = magic;
   request.comment = "EAFC_MARKET_ORDER";

   if(order_type == ORDER_TYPE_BUY)
      request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   else if(order_type == ORDER_TYPE_SELL)
      request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   else
   {
      PrintFormat("[ORDER_TYPE_NG] type=%d reason=not_market_order", order_type);
      return false;
   }

   ResetLastError();

   bool ok = OrderSend(request, result);

   PrintFormat("[ORDER_SEND_RESULT] ok=%s type=%s retcode=%u order=%I64u deal=%I64u comment=%s last_error=%d",
               (ok ? "true" : "false"),
               OrderTypeToText(order_type),
               result.retcode,
               result.order,
               result.deal,
               result.comment,
               GetLastError());

   return ok;
}

BUYとSELLでは、確認する価格が異なります。ログでは、注文方向、type、price、Bid、Ask、retcodeを分けて出してください。

指値注文と逆指値注文の違い

指値注文と逆指値注文は、価格条件を指定して発注する保留注文です。

ただし、BUY_LIMIT、SELL_LIMIT、BUY_STOP、SELL_STOPでは、現在価格に対して置く価格の考え方が異なります。

注文種類一般的な価格位置確認ポイント
ORDER_TYPE_BUY_LIMIT現在価格より低い側買い指値として妥当な価格か
ORDER_TYPE_SELL_LIMIT現在価格より高い側売り指値として妥当な価格か
ORDER_TYPE_BUY_STOP現在価格より高い側買い逆指値として妥当な価格か
ORDER_TYPE_SELL_STOP現在価格より低い側売り逆指値として妥当な価格か

価格位置が不正な場合、OrderCheckやOrderSendでエラーになる可能性があります。EAでは、注文種類ごとに現在価格との関係をログに残してください。

Buy系とSell系を分けて考える

ENUM_ORDER_TYPEは、Buy系とSell系で分けて整理すると確認しやすくなります。

方向注文種類用途
Buy系ORDER_TYPE_BUY買い成行
Buy系ORDER_TYPE_BUY_LIMIT買い指値
Buy系ORDER_TYPE_BUY_STOP買い逆指値
Buy系ORDER_TYPE_BUY_STOP_LIMIT買いStopLimit
Sell系ORDER_TYPE_SELL売り成行
Sell系ORDER_TYPE_SELL_LIMIT売り指値
Sell系ORDER_TYPE_SELL_STOP売り逆指値
Sell系ORDER_TYPE_SELL_STOP_LIMIT売りStopLimit

EA内部では、Buy方向かSell方向か、成行か保留注文か、指値か逆指値かを分けておくと、注文種類の取り違えを防ぎやすくなります。

注文タイプを文字列に変換する

ログ確認では、typeの数値だけを出すより、ORDER_TYPE_BUYのような文字列も併記した方が確認しやすくなります。

string OrderTypeToText(const ENUM_ORDER_TYPE type)
{
   switch(type)
   {
      case ORDER_TYPE_BUY:
         return "ORDER_TYPE_BUY";

      case ORDER_TYPE_SELL:
         return "ORDER_TYPE_SELL";

      case ORDER_TYPE_BUY_LIMIT:
         return "ORDER_TYPE_BUY_LIMIT";

      case ORDER_TYPE_SELL_LIMIT:
         return "ORDER_TYPE_SELL_LIMIT";

      case ORDER_TYPE_BUY_STOP:
         return "ORDER_TYPE_BUY_STOP";

      case ORDER_TYPE_SELL_STOP:
         return "ORDER_TYPE_SELL_STOP";

      case ORDER_TYPE_BUY_STOP_LIMIT:
         return "ORDER_TYPE_BUY_STOP_LIMIT";

      case ORDER_TYPE_SELL_STOP_LIMIT:
         return "ORDER_TYPE_SELL_STOP_LIMIT";

      case ORDER_TYPE_CLOSE_BY:
         return "ORDER_TYPE_CLOSE_BY";
   }

   return "ORDER_TYPE_UNKNOWN";
}

注文ログでは、type=%dだけでなく、type_textも出すと、あとから注文種類を確認しやすくなります。

保留注文を作る時の基本

指値や逆指値などの保留注文では、TRADE_ACTION_PENDINGを使い、request.typeへ保留注文の種類を指定します。

bool SendPendingOrder(const ENUM_ORDER_TYPE order_type,
                      const double volume,
                      const double order_price,
                      const double sl,
                      const double tp,
                      const ulong magic)
{
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action = TRADE_ACTION_PENDING;
   request.symbol = _Symbol;
   request.volume = volume;
   request.type   = order_type;
   request.price  = order_price;
   request.sl     = sl;
   request.tp     = tp;
   request.magic  = magic;
   request.comment = "EAFC_PENDING_ORDER";

   if(!IsPendingOrderType(order_type))
   {
      PrintFormat("[ORDER_TYPE_NG] type=%s reason=not_pending_order",
                  OrderTypeToText(order_type));
      return false;
   }

   ResetLastError();

   bool ok = OrderSend(request, result);

   PrintFormat("[PENDING_ORDER_SEND] ok=%s type=%s price=%.5f sl=%.5f tp=%.5f retcode=%u order=%I64u comment=%s last_error=%d",
               (ok ? "true" : "false"),
               OrderTypeToText(order_type),
               request.price,
               request.sl,
               request.tp,
               result.retcode,
               result.order,
               result.comment,
               GetLastError());

   return ok;
}

bool IsPendingOrderType(const ENUM_ORDER_TYPE type)
{
   return (type == ORDER_TYPE_BUY_LIMIT ||
           type == ORDER_TYPE_SELL_LIMIT ||
           type == ORDER_TYPE_BUY_STOP ||
           type == ORDER_TYPE_SELL_STOP ||
           type == ORDER_TYPE_BUY_STOP_LIMIT ||
           type == ORDER_TYPE_SELL_STOP_LIMIT);
}

保留注文では、注文価格、SL、TP、stop level、freeze level、有効期限、type_timeを合わせて確認してください。

StopLimit注文の注意点

StopLimit注文では、request.priceとrequest.stoplimitの両方を使います。

ORDER_TYPE_BUY_STOP_LIMITやORDER_TYPE_SELL_STOP_LIMITでは、指定価格に到達した後、StopLimit価格に基づいてLimit注文が置かれる構造になります。

項目意味確認すること
request.typeStopLimitの注文種類BUY_STOP_LIMITかSELL_STOP_LIMITか
request.priceStop条件の価格どの価格に到達したらLimit注文を置くか
request.stoplimitLimit注文を置く価格Stop到達後に置かれるLimit価格
request.type_time注文の有効期限種別GTC、当日、期限指定など
request.expiration期限指定時刻type_timeが期限指定の場合に確認

StopLimit注文は通常の指値や逆指値より確認項目が増えます。ログでは、priceとstoplimitを必ず分けて出してください。

PrintFormat("[STOP_LIMIT_REQUEST] type=%s price=%.5f stoplimit=%.5f sl=%.5f tp=%.5f",
            OrderTypeToText(request.type),
            request.price,
            request.stoplimit,
            request.sl,
            request.tp);

ORDER_TYPE_CLOSE_BYの扱い

ORDER_TYPE_CLOSE_BYは、反対方向のポジションを使ってポジションを決済するClose By注文です。

Hedging口座で反対ポジションを持つ構成では、Close Byが関係する場合があります。一方で、通常の成行決済やNetting口座の扱いとは異なるため、汎用EAへ安易に混ぜない方が安全です。

確認項目内容
口座方式Hedging口座か、Netting口座か
反対ポジション同一銘柄で反対方向のポジションがあるか
position決済対象ポジションのticket
position_by反対側ポジションのticket
ログCLOSE_BY_REQUEST、position、position_by、retcode

Close Byを扱う場合は、通常決済と別ルートに分け、ログ名も分けておくと確認しやすくなります。

MqlTradeRequest.typeと他フィールドを混同しない

MqlTradeRequestでは、type以外にも複数の注文関連フィールドがあります。

type、type_filling、type_time、actionを混同すると、注文種類は正しいのに注文要求全体が不正になる場合があります。

フィールド意味
action取引操作の種類TRADE_ACTION_DEAL、TRADE_ACTION_PENDING、TRADE_ACTION_SLTPなど
type注文種類ORDER_TYPE_BUY、ORDER_TYPE_BUY_LIMITなど
type_filling約定方式ORDER_FILLING_FOK、ORDER_FILLING_IOC、ORDER_FILLING_RETURNなど
type_time注文の有効期限種別ORDER_TIME_GTC、ORDER_TIME_DAY、ORDER_TIME_SPECIFIEDなど
price注文価格成行・保留注文・約定方式により扱いが変わる
stoplimitStopLimit価格StopLimit注文で使用

注文処理では、request.typeだけでなく、action、price、type_filling、type_time、expiration、stoplimitをセットで確認してください。

注文種類ミスを防ぐログ設計

ENUM_ORDER_TYPEのミスは、注文前ログでかなり防ぎやすくなります。

OrderSend前に、注文種類、注文価格、現在価格、SL / TP、stop level、type_filling、type_timeを出しておくと、指値と逆指値の取り違えやStopLimit価格の指定漏れを追いやすくなります。

void PrintOrderRequestLog(const MqlTradeRequest &request)
{
   double bid = SymbolInfoDouble(request.symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(request.symbol, SYMBOL_ASK);

   PrintFormat("[ORDER_REQUEST] action=%d type=%s symbol=%s volume=%.2f price=%.5f stoplimit=%.5f sl=%.5f tp=%.5f bid=%.5f ask=%.5f filling=%d time_type=%d expiration=%s magic=%I64u comment=%s",
               request.action,
               OrderTypeToText(request.type),
               request.symbol,
               request.volume,
               request.price,
               request.stoplimit,
               request.sl,
               request.tp,
               bid,
               ask,
               request.type_filling,
               request.type_time,
               TimeToString(request.expiration, TIME_DATE|TIME_SECONDS),
               request.magic,
               request.comment);
}

注文要求ログは、OrderCheck前とOrderSend前に同じ形式で残すと、どの段階で値が変わったかを確認しやすくなります。

注文種類ごとの簡易チェック

注文種類ごとに現在価格との関係を確認するhelperを作ると、明らかな指定ミスを発注前に止めやすくなります。

bool ValidateOrderTypeAndPrice(const string symbol,
                               const ENUM_ORDER_TYPE type,
                               const double price)
{
   double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);

   if(type == ORDER_TYPE_BUY_LIMIT && price >= ask)
   {
      PrintFormat("[ORDER_TYPE_PRICE_NG] type=%s price=%.5f ask=%.5f reason=buy_limit_price_not_below_ask",
                  OrderTypeToText(type), price, ask);
      return false;
   }

   if(type == ORDER_TYPE_SELL_LIMIT && price <= bid)
   {
      PrintFormat("[ORDER_TYPE_PRICE_NG] type=%s price=%.5f bid=%.5f reason=sell_limit_price_not_above_bid",
                  OrderTypeToText(type), price, bid);
      return false;
   }

   if(type == ORDER_TYPE_BUY_STOP && price <= ask)
   {
      PrintFormat("[ORDER_TYPE_PRICE_NG] type=%s price=%.5f ask=%.5f reason=buy_stop_price_not_above_ask",
                  OrderTypeToText(type), price, ask);
      return false;
   }

   if(type == ORDER_TYPE_SELL_STOP && price >= bid)
   {
      PrintFormat("[ORDER_TYPE_PRICE_NG] type=%s price=%.5f bid=%.5f reason=sell_stop_price_not_below_bid",
                  OrderTypeToText(type), price, bid);
      return false;
   }

   PrintFormat("[ORDER_TYPE_PRICE_OK] type=%s price=%.5f bid=%.5f ask=%.5f",
               OrderTypeToText(type), price, bid, ask);

   return true;
}

実際の判定では、銘柄仕様、stop level、freeze level、digits、point、スプレッドも合わせて確認してください。

OrderCheckと組み合わせる

注文種類と価格の簡易チェックを通過しても、取引サーバー側で受け付けられるとは限りません。

OrderSend前には、OrderCheckでMqlTradeRequestを確認し、retcode、comment、margin、margin_freeなどをログに残すと原因追跡がしやすくなります。

bool CheckRequestBeforeSend(const MqlTradeRequest &request)
{
   MqlTradeCheckResult check = {};

   ResetLastError();

   bool ok = OrderCheck(request, check);

   PrintFormat("[ORDER_CHECK] ok=%s type=%s retcode=%u comment=%s margin=%.2f margin_free=%.2f last_error=%d",
               (ok ? "true" : "false"),
               OrderTypeToText(request.type),
               check.retcode,
               check.comment,
               check.margin,
               check.margin_free,
               GetLastError());

   if(!ok)
      return false;

   if(check.retcode != 0)
      return false;

   return true;
}

注文種類ミス、価格位置ミス、証拠金不足、stop level不足は、OrderSend前のログで分けて確認できるようにしてください。

よくあるミス

ENUM_ORDER_TYPE周辺では、次のようなミスが起きやすくなります。

ミス起きる問題確認方法
BUY_LIMITとBUY_STOPを間違える価格位置が不正になり、注文が通らない現在Askとの関係をログに出す
SELL_LIMITとSELL_STOPを間違える価格位置が不正になり、注文が通らない現在Bidとの関係をログに出す
成行注文なのにTRADE_ACTION_PENDINGを使うactionとtypeが噛み合わないrequest.actionとrequest.typeを同時にログ化する
StopLimitでstoplimitを入れ忘れるStopLimit注文要求が不正になるpriceとstoplimitを分けてログ化する
type_fillingとtypeを混同する注文種類と約定方式を取り違えるtype、type_filling、type_timeを別項目で確認する
ORDER_TYPE_CLOSE_BYを通常決済と混ぜる口座方式や反対ポジション確認が不足するClose By専用の処理ルートへ分ける
ログに数値だけ出すあとから注文種類が分かりにくいOrderTypeToTextで文字列も出す

注文処理の不具合調査では、OrderSendのretcodeだけでなく、OrderSend前のrequest内容も確認してください。

ログ出力例

注文種類を確認するログは、type、価格、現在Bid / Ask、retcodeを揃えると見やすくなります。

[ORDER_REQUEST] action=1 type=ORDER_TYPE_BUY_LIMIT symbol=GOLD volume=0.10 price=2345.00 stoplimit=0.00 sl=2340.00 tp=2355.00 bid=2350.10 ask=2350.15 filling=2 time_type=0 expiration=1970.01.01 00:00:00 magic=24016 comment=EAFC_PENDING_ORDER
[ORDER_TYPE_PRICE_OK] type=ORDER_TYPE_BUY_LIMIT price=2345.00 bid=2350.10 ask=2350.15
[ORDER_CHECK] ok=true type=ORDER_TYPE_BUY_LIMIT retcode=0 comment=Done margin=120.50 margin_free=9879.50 last_error=0
[PENDING_ORDER_SEND] ok=true type=ORDER_TYPE_BUY_LIMIT price=2345.00 sl=2340.00 tp=2355.00 retcode=10009 order=123456789 comment=Request executed last_error=0

上記はログ形式の例です。実際のretcode、価格、証拠金、注文可否は、口座、銘柄、約定方式、取引時間、ブローカー設定によって変わります。

関連ページ

ENUM_ORDER_TYPEは、MQL5の列挙型、注文関数、発注前チェック、OrderSend結果ログと合わせて確認すると理解しやすくなります。

関連ページ確認できること
MQL5列挙型・定数辞典ENUM_ORDER_TYPE、ENUM_TIMEFRAMES、ORDER_FILLINGなどの定数整理
MQL5でEAの発注前チェックを作る考え方OrderSend前のspread、lot、margin、trading allowed確認
MQL5 OrderSend結果ログを実コードで解説MqlTradeRequest、MqlTradeResult、TRADE_RETCODE確認
MQL5注文・ポジション・履歴管理完全ガイドOrder、Position、Deal、History管理の全体像
MQL5ロット・証拠金・銘柄仕様完全ガイドvolume step、stop level、銘柄仕様、証拠金確認

注文処理全体を確認する場合

ENUM_ORDER_TYPEは、BUY、SELL、指値、逆指値など、注文種類を指定するための列挙型です。MqlTradeRequestで注文を送る場合は、request.typeに注文種類を指定し、request.type_fillingでは約定方式を指定します。

確認したいこと確認するページ主な確認内容
注文関数と取引構造体の全体を確認したいMQL5注文関数・取引構造体辞典OrderSend、OrderCheck、MqlTradeRequest、MqlTradeResult、注文処理全体の確認
注文種類と約定方式を分けて確認したいMQL5 ORDER_FILLINGの違いFOK、IOC、RETURN、type_filling、SYMBOL_FILLING_MODE、注文エラー確認

注文エラーを確認する時は、ORDER_TYPEとORDER_FILLINGを混同しないようにしてください。注文種類はrequest.type、約定方式はrequest.type_fillingとして分けてログに出すと、原因を追いやすくなります。

開発依頼前に整理したい情報

注文種類、指値・逆指値、StopLimit、Close By、注文エラーの調査を相談する場合は、次の情報を整理しておくと確認が進めやすくなります。

整理する情報確認内容
対象EA新規EA、既存EA改修、注文処理追加、不具合調査のどれか
注文種類成行、指値、逆指値、StopLimit、Close Byのどれを使うか
注文方向BUY系、SELL系、両方対応のどれか
注文価格現在価格からの距離、pips指定、価格指定、ライン指定など
SL / TP固定価格、pips指定、内部決済、トレーリング、建値移動など
発注前チェックspread、lot、margin、stop level、freeze level、trading allowed
ログrequest内容、OrderCheck結果、OrderSend結果、retcode、GetLastError
口座方式Hedging / Netting、Close By利用有無

注文処理の不具合を相談する場合は、OrderSend後のretcodeだけでなく、OrderSend前のMqlTradeRequest内容を確認できるログを用意してください。

MT4/MT5の開発・改修相談はこちら

まとめ

ENUM_ORDER_TYPEは、MQL5で注文種類を指定するための列挙型です。

成行注文ではORDER_TYPE_BUY / ORDER_TYPE_SELL、指値注文ではORDER_TYPE_BUY_LIMIT / ORDER_TYPE_SELL_LIMIT、逆指値注文ではORDER_TYPE_BUY_STOP / ORDER_TYPE_SELL_STOPを使います。

StopLimit注文では、request.priceとrequest.stoplimitの両方を確認します。Close Byを扱う場合は、Hedging口座、position、position_byを分けて確認してください。

EA開発では、request.typeだけでなく、action、price、stoplimit、type_filling、type_time、SL / TP、OrderCheck、OrderSend結果をセットでログ化すると、注文種類ミスを追跡しやすくなります。

ABOUT ME
記事URLをコピーしました