MT4のEA(MQL4)で新規注文を出すときに使うのがOrderSend()です。引数の意味と、注文が通らないときに確認すべきポイントをまとめます。

OrderSend
OrderSend()は1行で書けるため「注文はこれを呼ぶだけ」と思いがちですが、実際にはそう簡単ではありません。FX業者ごとにシンボル名・ロットの単位・ストップレベルなどが異なり、確認を怠ると「ロジックは成立しているのに注文が出ない」「想定外のロットで発注される」といったトラブルになります。
この記事では、まず関数の定義と各引数の意味を確認し、そのあと実際にEAへ組み込むときの注意点とサンプルコードを紹介します。
Definition(定義)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int OrderSend( string symbol, // symbol int cmd, // operation double volume, // volume double price, // price int slippage, // slippage double stoploss, // stop loss double takeprofit, // take profit string comment=NULL, // comment int magic=0, // magic number datetime expiration=0, // pending order expiration color arrow_color=clrNONE // color ); |
戻り値は、注文が成功したときはトレードサーバーが割り当てたチケット番号、失敗したときは -1 です。失敗した理由は、直後に GetLastError() を呼ぶと取得できます。
Ref: OrderSend – Trade Functions – MQL4 Documentation
Parameters(引数)
symbol:通貨ペア名
通貨ペア名を指定します。次のいずれかにしておくのが安全です。
- Symbol()(EAをセットしたチャートの通貨ペア)
- NULL(Symbol()と同じ意味)
- FX口座に合わせたシンボル名(”USDJPY-b”、”USDJPY.pers”、”USDJPYm” など)
安易に “USDJPY” と固定で書くと、業者によっては存在しないシンボルとなり注文が失敗します。
例えば、Forex ExchangeのMT4で次のコードを実行し、「エキスパート」タブのログを確認してみます。
|
1 2 |
string SymbolName = Symbol(); Print("SymbolName: " + SymbolName); |
ログにはこう表示されました。
|
1 |
SymbolName: USDJPY.pers |
このように、Symbol()が返す名前は業者によって「XXX.pers」「XXX-b」などと異なり、注文もその名前どおりに出す必要があります。同じ業者でも、口座タイプ(最大注文ロット数やEAの利用可否など)ごとにシンボル名を分けている場合があります。
cmd:注文の種類
注文の種類を指定します。売り・買いそれぞれに、成行・指値(limit)・逆指値(stop)の3種類があります。
| ID | 値 | 注文の種類 | price に入れる価格 |
| OP_BUY | 0 | 買いの成行注文 | 現在のAsk |
| OP_SELL | 1 | 売りの成行注文 | 現在のBid |
| OP_BUYLIMIT | 2 | 買いの指値注文 | Askより下 |
| OP_SELLLIMIT | 3 | 売りの指値注文 | Bidより上 |
| OP_BUYSTOP | 4 | 買いの逆指値注文 | Askより上 |
| OP_SELLSTOP | 5 | 売りの逆指値注文 | Bidより下 |
指値・逆指値では、price に指定する価格の位置が決まっています。逆の位置を指定するとエラー(130:ERR_INVALID_STOPS など)になります。
volume:ロット数
注文するロット数です。1ロットが何通貨かは、FX業者・口座タイプ・通貨ペアによって異なります(1万通貨、10万通貨、1,000通貨など)。事前に MarketInfo() の MODE_LOTSIZE で確認しておきましょう。
|
1 |
MarketInfo(Symbol(), MODE_LOTSIZE); |
あわせて、最小ロット(MODE_MINLOT)・最大ロット(MODE_MAXLOT)・ロットの刻み(MODE_LOTSTEP)も確認し、その範囲と刻みに合ったロット数にしないと注文は通りません。
price:注文価格
注文する価格です。成行注文なら、買いは Ask、売りは Bid を指定します。
指値・逆指値の価格を計算するときは、Point(1ポイントの値幅)を使い、NormalizeDouble() で小数点以下の桁数(Digits)に丸めます。業者によって桁数が「2桁か3桁(円絡み)」「4桁か5桁(それ以外)」と違うため、丸めないと「価格が不正」としてエラーになることがあります。
例)現在のAskから100ポイント上に、買いの逆指値(OP_BUYSTOP)を置く価格
|
1 |
NormalizeDouble(Ask + 100 * Point, Digits) |
以下、stoploss・takeprofit など価格を指定する引数でも、同じように NormalizeDouble() で丸めます。
slippage:許容スリッページ
成行注文で許容するスリッページ(注文時の価格とのズレ)を、ポイント単位で指定します。
5桁表示(円絡みは3桁表示)の業者では 1pips=10ポイント なので、slippage に 3 と書くと0.3pipsしか許容しないことになります。pipsで考えたい場合は10倍して指定しましょう。
stoploss:損切り価格
損切り(ストップロス)の価格です。設定しない場合は 0 にします。
ECN口座など、成行注文が「マーケット執行(Market Execution)」方式の口座では、OrderSend() の時点で stoploss / takeprofit を指定するとエラーになることがあります。その場合は 0 で発注し、約定後に OrderModify() で損切り・利確を設定します。
ただし、約定直後に続けてリクエストを送るとサーバー側で拒否されることもあるため、少し待ってから再試行するような処理を入れておくと安心です。
ストップレベルに注意
業者によっては、現在価格から一定の距離(ストップレベル)以上離さないと、指値・逆指値や損切り・利確を置けない場合があります。この距離が足りないと注文は通りません。ストップレベルは次のコードで取得でき、MT4の「気配値表示」→ 通貨ペアの「仕様」からも確認できます。
|
1 |
MarketInfo(Symbol(), MODE_STOPLEVEL); |
なお、値が 0 の場合は「制限なし」の場合と、「サーバー側で動的に管理していて端末からは分からない」場合の両方があります。
takeprofit:利確価格
利確(テイクプロフィット)の価格です。考え方は stoploss と同じで、設定しない場合は 0 にします。
comment=NULL:注文コメント
注文に付けるコメントです。省略しても構いませんが、同じ口座で裁量トレードもしている場合、どれがEAの注文か見分けやすくなるので入れておくのがおすすめです。パラメータで変更できるようにしておくのもよいでしょう。
なお、コメントの末尾はサーバー側で書き換えられることがあります(決済時に「[sl]」「[tp]」が付くなど)。コメントで注文を識別するのは避け、識別には次のマジックナンバーを使いましょう。
magic=0:マジックナンバー
EAが自分の注文を識別するための番号です。EAごと(必要なら通貨ペアや時間足ごと)に重ならない番号を付けておくと、ポジション管理や決済のときに OrderMagicNumber() で自分の注文だけを選び出せます。
expiration=0:待機注文の有効期限
指値・逆指値(待機注文)の有効期限を、日時(datetime型)で指定します。例えば「今から1時間後」なら TimeCurrent() + 3600 のように、サーバー時間を基準にした日時を渡します。成行注文では使いません。
期限を設けない場合は 0 にします。取引サーバーによっては有効期限の設定自体が無効にされていて、指定するとエラーになる場合があります。
arrow_color=clrNONE:矢印の色
約定(エントリー)した位置にチャート上で表示される矢印の色です。省略するか clrNONE にすると矢印は表示されません。
Tips(注意点)
引数のところでも触れましたが、OrderSend() を呼ぶ前後には確認しておきたいことがいくつかあります。必須ではありませんが、手を抜くと「ロジックは成立しているのに注文が出ない」「想定外の結果になる」原因になります。
証拠金・ポジション数の確認
レバレッジをよく理解しないまま始める初心者も多く、証拠金ギリギリで注文が通り、少し逆行しただけで口座が溶けてしまうことがあります。口座内の他のポジションも含めて、レバレッジが高くなりすぎないか確認しておくと安心です。
AccountFreeMarginCheck() を使うと、その注文を出した後に残る余剰証拠金を事前に計算できます。
マジックナンバーの確認
ポジション数を数えたり決済したりする前に、その注文が自分のEAのマジックナンバーかどうかを確認します。他のEAや手動の注文を誤って操作しないためです。
通貨ペアの確認
エントリーするときの通貨ペアは Symbol() または NULL にしておきます。固定で書く場合は、「USDJPYm」「USDJPY.pers」など業者独自の文字が付いていることを考慮します。
損切り・利確の設定確認
前述のとおり、口座の方式によっては OrderSend() で損切り・利確を受け付けないことがあります。その場合は、OrderSend() が返したチケット番号で OrderSelect() し、OrderModify() で設定します。設定に失敗したまま損切りなしのポジションが残らないよう、結果も必ず確認しましょう。
注文が通らないときに確認する関数
- IsStopped():EAの停止(チャートからの削除や端末の終了など)が指示されると true を返します。true なら、それ以上注文を出さずに処理を終えます。
- IsTradeContextBusy():他のEAが同時に注文中などで、取引スレッドが使用中なら true を返します。少し待ってから再試行します。
- GetLastError():注文に失敗したときのエラーコードを返します。エラーの種類によって、再試行すべきものと、すぐにやめるべきものがあります。
代表的なエラーの扱いは次のとおりです。
- 再試行してよいもの:135(価格変更)、136(オフクオート)、138(リクオート)、146(取引スレッドがビジー)など。RefreshRates() で最新価格を取り直してから再発注します。
- 再試行しても無駄なもの:130(不正なストップ)、131(不正なロット数)、134(証拠金不足)など。引数や口座の状態を見直す必要があります。
サンプルコード
ここまでの内容をまとめた、買いの成行注文を出すシンプルな例です。リクオートなど再試行できるエラーのときだけ、最大3回までやり直します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
int BuyMarket(double lots, int slippage, int magic) { for(int i = 0; i < 3; i++) { if(IsStopped()) return(-1); // 他のEAが注文中なら少し待つ while(IsTradeContextBusy()) Sleep(100); RefreshRates(); double price = NormalizeDouble(Ask, Digits); int ticket = OrderSend(Symbol(), OP_BUY, lots, price, slippage, 0, 0, "MyEA", magic, 0, clrNONE); if(ticket > 0) return(ticket); // 成功 int err = GetLastError(); Print("OrderSend failed. error = ", err); // 再試行してよいエラー以外はすぐ終了 if(err != 135 && err != 136 && err != 138 && err != 146) return(-1); Sleep(500); } return(-1); } |
損切り・利確が必要な場合は、返ってきたチケット番号を使って OrderSelect() → OrderModify() で設定します。
References:
OrderSend – Trade Functions – MQL4 Documentation
NormalizeDouble – MQL4 Reference – MQL4 Documentation
Point – Predefined Variables – MQL4 Documentation
Trade Server Return Codes – MQL4 Documentation




















