- 1 1. MQL5 OrderSend()とは何か
- 2 2. OrderSend()の基本構文と関数仕様
- 3 3. MqlTradeRequestの主要パラメータと設定方法
- 4 4. OrderSend()の実用コード例(成行注文)
- 5 5. 指値注文・逆指値注文の実装
- 6 6. MqlTradeResultの見方と注文結果の確認方法
- 7 7. OrderSend()でよく発生するエラーと対処方法
- 8 8. OrderSend()を安全に使うためのEA設計ベストプラクティス
- 9 9. FAQ(よくある質問)
1. MQL5 OrderSend()とは何か
OrderSend()は、MQL5(MetaQuotes Language 5)で実際にトレード注文をブローカーへ送信するための関数です。
EA(Expert Advisor:自動売買プログラム)を作る場合、この関数は注文処理の中心となる最重要機能になります。
MetaTrader 5では、売買シグナルを検出するだけではトレードは実行されません。
EAが次の処理を行う必要があります。
- 注文内容を作成する
- ブローカーに送信する
- 約定結果を確認する
この一連の処理のうち、注文送信を担当するのが OrderSend() です。
MQL5では、注文は次のような構造で処理されます。
EA
↓
OrderSend()
↓
取引サーバー
↓
約定結果
つまり、EAが生成した注文リクエストを取引サーバーに送信するインターフェースが OrderSend() です。
1.1 OrderSend()の役割
OrderSend()は、トレード注文を実行するために次の情報をまとめて送信します。
主な注文情報
- 取引する通貨ペア(例:EURUSD)
- 売買方向(Buy / Sell)
- ロットサイズ
- 注文価格
- ストップロス(SL)
- テイクプロフィット(TP)
MQL5では、これらの情報を構造体(データのまとまり)に格納して送信します。
具体的には次の2つの構造体を使います。
| 構造体 | 役割 |
|---|---|
MqlTradeRequest |
注文内容を格納 |
MqlTradeResult |
注文結果を受け取る |
処理の流れは次のようになります。
1 注文内容を作成
2 OrderSend()を実行
3 結果を確認
簡単なイメージコードは次の通りです。
MqlTradeRequest request;
MqlTradeResult result;
OrderSend(request, result);
この関数を実行すると、注文が取引サーバーへ送信され、
結果が result に格納されます。
1.2 MT4 OrderSend()との違い
MQL5の OrderSend() は、MetaTrader4(MQL4)と大きく設計が異なります。
MT4では、注文関数は次のような単一関数形式でした。
OrderSend(Symbol(),OP_BUY,0.1,Ask,10,0,0);
一方、MQL5では構造体ベースの設計になっています。
理由は次の通りです。
- 注文情報が増えて複雑化した
- サーバー処理が高度化した
- 拡張性を高めるため
そのためMQL5では
MqlTradeRequest
という構造体に注文情報をまとめてから OrderSend() を実行します。
この違いにより、MT4経験者でも最初に戸惑うポイントになりやすいです。
初心者がよく混乱するポイント
- MT4と同じ書き方はできない
- 構造体の初期化が必要
- 価格取得方法が異なる
この点は、EA開発で最も多い初期トラブルの一つです。
1.3 OrderSend()が必要になる典型的なケース
OrderSend()は次のような場面で使用されます。
① EAによる自動売買
最も一般的な用途です。
例
RSIが30以下 → Buy
RSIが70以上 → Sell
このとき、売買を実行する処理は OrderSend() が担当します。
② 指値注文・逆指値注文
EAは次のような注文も作れます。
- Buy Limit(押し目買い)
- Sell Limit(戻り売り)
- Buy Stop(ブレイクアウト)
- Sell Stop(ブレイクアウト)
これらのPending注文(予約注文)も OrderSend() で送信します。
③ 複数通貨EA
MT5では
- 複数通貨
- 複数時間足
を同時に扱うEAが多く作られます。
この場合も、各通貨ペアに対して OrderSend() を実行します。
つまずきやすいポイント(初心者注意)
EA開発では、OrderSend()周辺で次のミスが非常に多く発生します。
よくある失敗
① 価格(price)を設定していない
→ 注文拒否になる
② ロットサイズがブローカー制限外
→ Invalid volume エラー
③ SL/TPが近すぎる
→ Invalid stops エラー
④ シンボル未設定
request.symbol=""
→ 注文不可
⑤ Ask / Bidの使い分けミス
| 注文 | 価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
これらの問題は、次章で解説する注文構造を理解すると解決できます。
2. OrderSend()の基本構文と関数仕様
OrderSend()は、MQL5でトレード注文を実行するための中核関数です。
この関数は、EAが作成した注文情報を取引サーバーへ送信し、注文結果を受け取る役割を持ちます。
MQL5では、注文情報を複数の引数で直接渡すのではなく、構造体(データのまとまり)に格納してから送信する設計になっています。
2.1 OrderSend()の関数構文
MQL5における OrderSend() の基本構文は次の通りです。
bool OrderSend(
MqlTradeRequest& request,
MqlTradeResult& result
);
引数の意味は次の通りです。
| 引数 | 説明 |
|---|---|
request |
注文内容を格納する構造体 |
result |
注文結果を受け取る構造体 |
戻り値は bool 型です。
| 戻り値 | 意味 |
|---|---|
true |
サーバーへ注文送信成功 |
false |
注文送信失敗 |
ただし注意点として、trueでも必ず約定したとは限りません。
OrderSend()が成功するのは
サーバーに注文が届いた
という意味であり、注文結果は result を確認する必要があります。
2.2 MqlTradeRequest(注文情報)
MqlTradeRequest は、注文内容を格納する構造体です。
ここに必要な情報を設定してから OrderSend() を実行します。
代表的なメンバーは次の通りです。
| 項目 | 意味 |
|---|---|
action |
注文タイプ |
symbol |
通貨ペア |
volume |
ロットサイズ |
type |
注文方向 |
price |
注文価格 |
sl |
ストップロス |
tp |
テイクプロフィット |
deviation |
許容スリッページ |
magic |
EA識別番号 |
最小構成でも、通常は以下を設定します。
action
symbol
volume
type
price
EAではこれらを正しく設定しないと、注文が拒否されます。
2.3 MqlTradeResult(注文結果)
MqlTradeResult は、注文結果を受け取る構造体です。
主なメンバーは次の通りです。
| 項目 | 意味 |
|---|---|
retcode |
サーバー応答コード |
deal |
約定チケット |
order |
注文チケット |
price |
約定価格 |
特に重要なのが
retcode
です。
これは注文結果を示すコードであり、EA開発では必ず確認します。
例
TRADE_RETCODE_DONE
意味
注文成功
逆に、次のようなコードもあります。
| retcode | 意味 |
|---|---|
TRADE_RETCODE_REJECT |
注文拒否 |
TRADE_RETCODE_INVALID_VOLUME |
ロット不正 |
TRADE_RETCODE_INVALID_PRICE |
価格不正 |
EAでは次のように確認します。
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("注文成功");
}
2.4 最小構成の注文コード
成行Buy注文の最小例は次のようになります。
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
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);
このコードの処理は次の通りです。
1 注文構造体を作成
2 注文内容を設定
3 OrderSend()で送信
EAでは、この処理を売買シグナル発生時に実行します。
つまずきやすいポイント(重要)
OrderSend()の実装では、次のミスが非常に多く発生します。
① ZeroMemory()を忘れる
構造体は初期化しないとゴミデータが入ります。
必ず実行します。
ZeroMemory(request);
② Ask / Bidの間違い
| 注文 | 価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
例
ORDER_TYPE_BUY → Ask
ORDER_TYPE_SELL → Bid
③ volumeがブローカー制限外
例
0.01未満
など。
ブローカーの最小ロットは環境により異なります。
④ deviation未設定
急変相場では注文拒否の原因になります。
例
request.deviation = 10;
⑤ SL/TPが近すぎる
ブローカーは最小ストップ距離を設定しています。
Invalid stops
エラーの原因になります。
実務的なポイント
実際のEAでは次の処理を追加します。
- エラー処理
- retcode確認
- ログ出力
- リトライ処理
この部分を省略すると、EAがトレードしない原因の特定が困難になります。
3. MqlTradeRequestの主要パラメータと設定方法
OrderSend()を正しく使用するためには、MqlTradeRequest構造体の各パラメータを理解することが不可欠です。
この構造体には、トレード注文に必要な情報をすべて設定します。
EA開発で注文が失敗する原因の多くは、このパラメータ設定ミスによるものです。
ここでは、実務で特に重要な項目を中心に解説します。
3.1 action(注文アクション)
actionは、注文の種類(取引タイプ)を指定するパラメータです。
主に使用される値は次の通りです。
| 値 | 意味 |
|---|---|
TRADE_ACTION_DEAL |
成行注文 |
TRADE_ACTION_PENDING |
指値・逆指値注文 |
TRADE_ACTION_SLTP |
SL/TP変更 |
TRADE_ACTION_REMOVE |
注文削除 |
EAで最も多く使用されるのは成行注文です。
例
request.action = TRADE_ACTION_DEAL;
指値注文の場合は次のようになります。
request.action = TRADE_ACTION_PENDING;
3.2 symbol(通貨ペア)
symbol`は、取引する銘柄(通貨ペア)を指定します。
通常は次の値を使用します。
request.symbol = _Symbol;
_Symbolは、現在のチャートの通貨ペアを意味します。
例
EURUSD
USDJPY
XAUUSD
マルチ通貨EAの場合は、明示的に指定する必要があります。
request.symbol = "EURUSD";
3.3 volume(ロットサイズ)
volumeは、取引数量(ロットサイズ)を指定します。
例
request.volume = 0.10;
注意点として、ロットサイズにはブローカー制限があります。
主な制限
- 最小ロット
- 最大ロット
- ロットステップ
例
| 項目 | 例 |
|---|---|
| 最小ロット | 0.01 |
| ロットステップ | 0.01 |
不正な値を設定すると、次のエラーになります。
TRADE_RETCODE_INVALID_VOLUME
EAでは次の関数で確認できます。
SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
3.4 type(注文方向)
typeは、売買方向または注文タイプを指定します。
代表的な値は次の通りです。
| 値 | 意味 |
|---|---|
ORDER_TYPE_BUY |
成行買い |
ORDER_TYPE_SELL |
成行売り |
ORDER_TYPE_BUY_LIMIT |
買い指値 |
ORDER_TYPE_SELL_LIMIT |
売り指値 |
ORDER_TYPE_BUY_STOP |
買い逆指値 |
ORDER_TYPE_SELL_STOP |
売り逆指値 |
例
request.type = ORDER_TYPE_BUY;
3.5 price(注文価格)
priceは、注文価格を指定します。
成行注文の場合
| 注文 | 価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
例
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
Sell注文
request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
価格設定を誤ると、注文は拒否されます。
3.6 sl / tp(ストップロス・テイクプロフィット)
slは損切り価格
tpは利益確定価格です。
例
request.sl = Ask - 100 * _Point;
request.tp = Ask + 200 * _Point;
ここで _Point は
最小価格単位
を意味します。
例
| 通貨ペア | _Point |
|---|---|
| EURUSD | 0.00001 |
| USDJPY | 0.001 |
3.7 deviation(スリッページ許容)
deviationは、価格変動をどこまで許容するかを指定します。
例
request.deviation = 10;
単位は
ポイント
です。
設定しないと、ボラティリティが高い相場で注文拒否される可能性があります。
3.8 magic(EA識別番号)
magicは、EA専用の識別番号です。
これを設定すると
- EAのポジション
- 手動ポジション
を区別できます。
例
request.magic = 123456;
EA開発では必須に近いパラメータです。
つまずきやすいポイント
MqlTradeRequestの設定で特に多いミスをまとめます。
① price未設定
Invalid price
エラーになります。
② symbol未設定
request.symbol = ""
注文失敗になります。
③ volumeが小さすぎる
Invalid volume
④ SL / TPが近すぎる
Invalid stops
ブローカーごとに最小ストップ距離があります。
⑤ actionとtypeの組み合わせミス
例
TRADE_ACTION_DEAL
+
ORDER_TYPE_BUY_LIMIT
これは矛盾した設定です。
実務的なコツ
EAでは次の初期化をよく使います。
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
これを行うことで、不定データによるバグを防止できます。
4. OrderSend()の実用コード例(成行注文)
ここでは、MQL5で OrderSend() を使って成行注文(いますぐ買う・売る注文)を出す基本実装を解説します。
初心者が最初に動かすべきなのは、まず Buy注文 と Sell注文 の最小構成です。
成行注文では、現在の市場価格を使って発注します。
ただし実装時には、単に OrderSend() を呼ぶだけでは不十分です。少なくとも次の3点を押さえる必要があります。
MqlTradeRequestを正しく初期化する- BuyはAsk、SellはBidを使う
result.retcodeで結果確認する
4.1 Buy注文のサンプルコード
まずは、最も基本的な成行Buy注文です。
void BuyOrder()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = ask;
request.deviation = 10;
request.magic = 123456;
request.comment = "MQL5 Buy Order";
if(OrderSend(request, result))
{
Print("Buy注文送信成功, retcode=", result.retcode);
}
else
{
Print("Buy注文送信失敗");
}
}
このコードの流れは次の通りです。
requestとresultを用意するZeroMemory()で初期化する- Ask価格を取得する
- Buy注文に必要な情報をセットする
OrderSend()を実行する- 結果をログで確認する
Buy注文では、価格に Ask を使います。
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.price = ask;
ここをBidにすると、環境や条件によって注文拒否や想定外動作の原因になります。
4.2 Sell注文のサンプルコード
次に、成行Sell注文です。
void SellOrder()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_SELL;
request.price = bid;
request.deviation = 10;
request.magic = 123456;
request.comment = "MQL5 Sell Order";
if(OrderSend(request, result))
{
Print("Sell注文送信成功, retcode=", result.retcode);
}
else
{
Print("Sell注文送信失敗");
}
}
Sell注文では、価格に Bid を使います。
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.price = bid;
成行注文の価格指定は、初心者が非常に間違えやすい部分です。
まずは次の対応を固定で覚えると安全です。
| 注文種別 | 使う価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
4.3 SLとTPを含めた実用例
実運用では、損切りと利確を同時に設定することが多いです。
以下はBuy注文に sl と tp を加えた例です。
void BuyOrderWithSLTP()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY;
request.price = ask;
request.sl = ask - 100 * _Point;
request.tp = ask + 200 * _Point;
request.deviation = 10;
request.magic = 123456;
request.comment = "Buy with SLTP";
if(OrderSend(request, result))
{
Print("Buy注文送信, retcode=", result.retcode);
}
else
{
Print("Buy注文送信失敗");
}
}
ここでは
- 損切り:100ポイント下
- 利確:200ポイント上
に設定しています。
ただし、_Point は銘柄によって値が異なります。
また、ブローカーによっては最小ストップ距離の制限があるため、この値で必ず通るとは限りません。
4.4 MagicNumberの設定
EA開発では、magic の設定が非常に重要です。
これはその注文がどのEAによるものかを識別する番号です。
request.magic = 123456;
MagicNumberを設定しておくと、後でポジション管理を行うときに
- 手動注文
- 他のEAの注文
- 現在のEAの注文
を区別できます。
特に次のような処理で必須に近いです。
- 自分のEAのポジションだけ決済する
- 同じ通貨ペアで複数EAを動かす
- 運用ログを整理する
逆に magic を設定しないと、後から管理が非常に難しくなります。
4.5 最低限の結果確認
OrderSend() は true を返しても、実際の注文結果までは保証しません。
そのため、最低でも result.retcode を確認します。
if(OrderSend(request, result))
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("注文成功");
}
else
{
Print("注文は送信されたが約定失敗, retcode=", result.retcode);
}
}
else
{
Print("OrderSend自体が失敗");
}
初心者がやりがちな失敗は、true だけ見て「注文成功」と判断してしまうことです。
実務では、retcode確認までが1セットです。
つまずきやすい点・注意点・よくある失敗
① BuyなのにBidを使う
価格の対応を逆にすると、注文拒否や挙動不良の原因になります。
- Buy → Ask
- Sell → Bid
② ZeroMemory()を省略する
構造体に不要データが残り、原因不明の失敗につながることがあります。
ZeroMemory(request);
ZeroMemory(result);
は基本として毎回入れる方が安全です。
③ retcodeを見ていない
OrderSend() の戻り値だけでは不十分です。
result.retcode を見ないと、なぜ失敗したか分かりません。
④ ロットサイズが環境に合っていない
0.10 が常に有効とは限りません。
口座や銘柄によって、最小ロット・ロット刻みが異なります。
⑤ SL/TPの距離が近すぎる
ブローカーの制限に引っかかると Invalid stops になります。
固定値で入れる場合は、環境差を考慮する必要があります。
⑥ NormalizeDouble()が常に必要だと思い込む
価格計算で使う場面はありますが、何でも機械的に NormalizeDouble() すればよいわけではありません。
まずは価格取得と計算ロジックを正しくし、そのうえで必要な箇所だけ使う方が安全です。
5. 指値注文・逆指値注文の実装
OrderSend()は成行注文だけでなく、指値注文(Limit)や逆指値注文(Stop)にも対応しています。
EA開発では、ブレイクアウト戦略や押し目買い・戻り売りで予約注文を使う場面が多く、ここを理解すると実装できる戦略の幅が大きく広がります。
成行注文との最大の違いは、注文を今すぐ約定させるのではなく、指定価格に到達したときに発動させる点です。
そのため、action と type の設定に加えて、価格の置き方を正しく理解する必要があります。
5.1 指値注文・逆指値注文の基本
予約注文では、action に次を指定します。
request.action = TRADE_ACTION_PENDING;
そして type で注文種別を選びます。
| 注文タイプ | 意味 |
|---|---|
ORDER_TYPE_BUY_LIMIT |
現在価格より下で買う |
ORDER_TYPE_SELL_LIMIT |
現在価格より上で売る |
ORDER_TYPE_BUY_STOP |
現在価格より上で買う |
ORDER_TYPE_SELL_STOP |
現在価格より下で売る |
まずはこの関係を整理して覚えるのが重要です。
価格位置のイメージ
- Buy Limit
押し目を待って、現在価格より下で買う - Sell Limit
戻りを待って、現在価格より上で売る - Buy Stop
上抜けを確認して、現在価格より上で買う - Sell Stop
下抜けを確認して、現在価格より下で売る
ここを逆に理解すると、EAが意図と反対の場所に注文を置くため、実運用では致命的です。
5.2 Buy Limit の実装例
Buy Limit は、現在価格より下に買い注文を置く場合に使います。
void PlaceBuyLimit()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double price = ask - 100 * _Point;
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY_LIMIT;
request.price = price;
request.sl = price - 100 * _Point;
request.tp = price + 200 * _Point;
request.deviation = 10;
request.magic = 123456;
request.comment = "Buy Limit";
if(OrderSend(request, result))
Print("Buy Limit送信, retcode=", result.retcode);
else
Print("Buy Limit送信失敗");
}
この例では、現在のAskより100ポイント下にBuy Limitを置いています。
重要なのは、Buy Limitの価格は現在価格より下であることです。
逆に上へ置くと、注文不正になります。
5.3 Sell Limit の実装例
Sell Limit は、現在価格より上に売り注文を置く場合に使います。
void PlaceSellLimit()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double price = bid + 100 * _Point;
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_SELL_LIMIT;
request.price = price;
request.sl = price + 100 * _Point;
request.tp = price - 200 * _Point;
request.deviation = 10;
request.magic = 123456;
request.comment = "Sell Limit";
if(OrderSend(request, result))
Print("Sell Limit送信, retcode=", result.retcode);
else
Print("Sell Limit送信失敗");
}
Sell Limit は、戻り売り型のEAでよく使います。
ここでも位置関係が重要で、Sell Limitは現在価格より上です。
5.4 Buy Stop の実装例
Buy Stop は、現在価格より上に買い注文を置く予約注文です。
高値更新・上抜け確認型の戦略でよく使います。
void PlaceBuyStop()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double price = ask + 100 * _Point;
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_BUY_STOP;
request.price = price;
request.sl = price - 100 * _Point;
request.tp = price + 200 * _Point;
request.deviation = 10;
request.magic = 123456;
request.comment = "Buy Stop";
if(OrderSend(request, result))
Print("Buy Stop送信, retcode=", result.retcode);
else
Print("Buy Stop送信失敗");
}
Buy Stop は 現在価格より上 に置きます。
押し目買いのつもりでこれを使うと、ロジックが完全に逆になります。
5.5 Sell Stop の実装例
Sell Stop は、現在価格より下に売り注文を置く予約注文です。
安値割れ・下抜け確認型で使われます。
void PlaceSellStop()
{
MqlTradeRequest request;
MqlTradeResult result;
ZeroMemory(request);
ZeroMemory(result);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double price = bid - 100 * _Point;
request.action = TRADE_ACTION_PENDING;
request.symbol = _Symbol;
request.volume = 0.10;
request.type = ORDER_TYPE_SELL_STOP;
request.price = price;
request.sl = price + 100 * _Point;
request.tp = price - 200 * _Point;
request.deviation = 10;
request.magic = 123456;
request.comment = "Sell Stop";
if(OrderSend(request, result))
Print("Sell Stop送信, retcode=", result.retcode);
else
Print("Sell Stop送信失敗");
}
Sell Stop は 現在価格より下 に置くのが正しい設定です。
5.6 予約注文で追加で意識すべき項目
予約注文では、成行注文以上に価格設定の整合性が重要です。
最低限、次を確認してください。
action = TRADE_ACTION_PENDINGになっているかtypeが予約注文向けになっているかpriceの位置が現在価格との関係で正しいかsl/tpが近すぎないかresult.retcodeを確認しているか
また、環境によっては注文有効期限の設定が必要になることもあります。
使うブローカーや銘柄仕様で差が出るため、必要に応じて type_time や expiration の確認も行います。
つまずきやすい点・注意点・よくある失敗
① Limit と Stop を逆に使う
最も多いミスです。
- 押し目買い →
BUY_LIMIT - 上抜け買い →
BUY_STOP
ここを逆にすると、EAのロジック自体が破綻します。
② 価格位置が不正
例として、Buy Limit を現在価格より上に置くと不正です。
Sell Stop を現在価格より上に置くのも不正です。
注文タイプごとに価格位置のルールがあると理解してください。
③ action を TRADE_ACTION_DEAL のままにしている
成行注文コードを流用したときに起こりやすい失敗です。
予約注文では必ず
request.action = TRADE_ACTION_PENDING;
が必要です。
④ SL/TPの向きが逆
Buy系注文なのにSLを上、TPを下へ置くなどのミスです。
売買方向ごとに整理すると次の通りです。
| 方向 | SL | TP |
|---|---|---|
| Buy系 | 下 | 上 |
| Sell系 | 上 | 下 |
⑤ retcode を見ずに放置する
予約注文は成行注文以上に、仕様不一致で弾かれやすいです。
送信したら必ず result.retcode を確認してください。
6. MqlTradeResultの見方と注文結果の確認方法
OrderSend()を実行したあと、EAは必ず注文結果を確認する処理を行う必要があります。
多くの初心者は、OrderSend() の戻り値(true / false)だけを見て処理を終えてしまいますが、これは不十分です。
なぜなら、OrderSend() の戻り値は
サーバーに注文送信できたか
しか保証していないためです。
実際の注文結果(成功・拒否など)は、MqlTradeResult構造体の内容を確認することで初めて分かります。
6.1 OrderSend()の戻り値の意味
OrderSend() の戻り値は bool 型です。
bool OrderSend(request, result);
意味は次の通りです。
| 戻り値 | 意味 |
|---|---|
true |
注文リクエスト送信成功 |
false |
注文送信自体が失敗 |
ただし、true でも注文が成立したとは限りません。
例
注文送信成功
↓
サーバーで拒否
というケースが普通にあります。
そのため、必ず次を確認します。
result.retcode
6.2 retcode(最重要項目)
retcode は、サーバーの注文結果コードです。
EAではこの値を確認して処理を分岐します。
例
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("注文成功");
}
代表的な retcode は次の通りです。
| retcode | 意味 |
|---|---|
TRADE_RETCODE_DONE |
注文成功 |
TRADE_RETCODE_PLACED |
予約注文成功 |
TRADE_RETCODE_REJECT |
注文拒否 |
TRADE_RETCODE_INVALID_VOLUME |
ロット不正 |
TRADE_RETCODE_INVALID_PRICE |
価格不正 |
TRADE_RETCODE_INVALID_STOPS |
SL/TP不正 |
EA開発では、この retcode をログ出力することでトラブル原因を特定できます。
6.3 deal(約定チケット)
deal は、約定取引のチケット番号です。
result.deal
注文が成立した場合、この値に取引IDが入ります。
例
deal = 123456789
このチケットを使って
- 約定履歴取得
- トレードログ
- 取引分析
などを行えます。
ただし、予約注文の場合はまだ約定していないため deal は0になります。
6.4 order(注文チケット)
order は、注文IDです。
result.order
これは
- 予約注文
- 成行注文
どちらでも発行されます。
例
order = 987654321
このIDは次の用途で使います。
- 注文キャンセル
- SL/TP変更
- 注文管理
EAのポジション管理では、この番号を保存するケースもあります。
6.5 price(約定価格)
price は、実際の約定価格です。
result.price
成行注文では、リクエストした価格と完全一致しないことがあります。
これはスリッページ(価格滑り)によるものです。
例
| 項目 | 価格 |
|---|---|
| 注文価格 | 1.10000 |
| 約定価格 | 1.10002 |
この差は市場の流動性やサーバー処理によって変わります。
6.6 実務で使う結果確認コード
実務では、次のように結果確認とログ出力をセットで実装することが多いです。
if(OrderSend(request, result))
{
if(result.retcode == TRADE_RETCODE_DONE)
{
Print("注文成功");
}
else
{
Print("注文送信成功だが約定失敗 retcode=", result.retcode);
}
}
else
{
Print("OrderSend送信失敗");
}
この形にしておくと
- 送信エラー
- サーバー拒否
- 約定成功
を区別できます。
EA開発では、このログがデバッグの生命線になります。
6.7 EA開発でよく使うログ出力
EAの開発中は、retcodeを必ず表示するようにすると原因特定が容易になります。
例
Print("retcode=", result.retcode);
Print("order=", result.order);
Print("deal=", result.deal);
Print("price=", result.price);
これにより
注文送信
↓
サーバー応答
↓
EAログ
の流れが確認できます。
つまずきやすい点・注意点・よくある失敗
① retcodeを確認していない
OrderSend()の戻り値だけでは、注文結果は判断できません。
② TRADE_RETCODE_DONE以外を無視している
予約注文では
TRADE_RETCODE_PLACED
が正常になります。
③ エラーコードをログに出していない
EA開発ではログがないと原因調査が困難です。
④ dealとorderを混同している
初心者が混乱しやすい部分です。
| 項目 | 意味 |
|---|---|
| order | 注文ID |
| deal | 約定ID |
⑤ 約定価格が違うことをエラーと思う
スリッページは通常の現象です。
完全一致しないことは珍しくありません。
実務での重要ポイント
EAの注文処理は、実際には次の流れで設計します。
OrderSend()
↓
retcode確認
↓
ログ出力
↓
ポジション管理
この設計にしておくと、EAのトラブル対応が格段に容易になります。
7. OrderSend()でよく発生するエラーと対処方法
OrderSend()を使用したEA開発では、注文が拒否されるケースが必ず発生します。
特に初心者が最初に作るEAでは、「注文が通らない」「EAがトレードしない」といった問題の多くが設定ミスまたは環境条件の不一致です。
この章では、実際のEA開発で頻発するエラー原因と、その具体的な対処方法を整理します。
7.1 Invalid volume(ロットサイズ不正)
エラーコード例
TRADE_RETCODE_INVALID_VOLUME
このエラーは、ロットサイズがブローカーの条件を満たしていない場合に発生します。
主な原因
- 最小ロット未満
- 最大ロット超過
- ロットステップ不一致
例
最小ロット 0.01
ロットステップ 0.01
この環境で
volume = 0.015
は無効です。
対処方法
EAでは次の情報を取得しておくと安全です。
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double stepLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
そしてロットを計算するときは、stepに合わせて調整する必要があります。
7.2 Invalid price(価格不正)
エラーコード例
TRADE_RETCODE_INVALID_PRICE
原因
priceが未設定- Bid / Askの使用ミス
- 指値注文の価格位置が不正
例
Buy Limit を現在価格より上に置いた
これは仕様違反となります。
対処方法
基本ルールを整理します。
| 注文 | 価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
また、予約注文では現在価格との位置関係を必ず確認します。
| 注文タイプ | 価格位置 |
|---|---|
| Buy Limit | 現在価格より下 |
| Sell Limit | 現在価格より上 |
| Buy Stop | 現在価格より上 |
| Sell Stop | 現在価格より下 |
7.3 Invalid stops(SL / TP不正)
エラーコード例
TRADE_RETCODE_INVALID_STOPS
原因
- SLが近すぎる
- TPが近すぎる
- SL / TPの方向ミス
ブローカーは最小ストップ距離を設定しています。
例
StopLevel = 20 points
この場合、20ポイント以内のSL / TPは拒否されます。
対処方法
EAでは次の情報を取得できます。
int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
SL / TPを設定する際は、この値より大きく離す必要があります。
7.4 Trade disabled(取引不可)
エラーコード例
TRADE_RETCODE_TRADE_DISABLED
原因
- シンボルが取引不可
- マーケットが閉じている
- 自動売買が無効
対処方法
次の設定を確認します。
- MT5の「自動売買」ボタンがON
- EA設定で「Algo Trading」許可
- 取引時間内
EA側では次のチェックも可能です。
bool tradeAllowed = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_MODE);
7.5 Not enough money(証拠金不足)
エラーコード例
TRADE_RETCODE_NO_MONEY
原因
- 証拠金不足
- ロットサイズ過大
対処方法
注文前に証拠金チェックを行います。
OrderCalcMargin(...)
EAではリスク管理として必須です。
7.6 Off quotes / Requote
これは価格変動による注文拒否です。
原因
- 市場の急変
- スプレッド拡大
- 流動性低下
特に
- 指標発表
- 週明け
などで起こりやすくなります。
対処方法
deviationを設定します。
request.deviation = 10;
ただし、大きすぎると不利な価格で約定する可能性があります。
7.7 EAがトレードしない場合のチェックリスト
EAがトレードしない場合、次の順番で確認すると原因を特定しやすくなります。
- Algo TradingがONか
- ログにエラーが出ていないか
- OrderSend()が実行されているか
- retcodeを確認しているか
- 価格取得が正しいか
- ロットサイズが有効か
ログに retcode を出しておくと、原因特定が格段に早くなります。
つまずきやすい点・注意点・よくある失敗
① Ask / Bidの使い分けミス
初心者が最も多くやるミスです。
② SL / TPの距離不足
ブローカー仕様を考慮していないケースです。
③ ロットサイズの不正
環境によって最小ロットは異なります。
④ ZeroMemory()忘れ
構造体のゴミデータが原因で失敗する場合があります。
⑤ retcodeを見ていない
EA開発では最大のトラブル原因です。
実務的なポイント
EA開発では、注文エラーを完全に防ぐことはできません。
そのため実運用では次の設計を行います。
注文
↓
retcode確認
↓
失敗なら再試行
このリトライ処理を実装することで、実際のトレード環境での安定性が大きく向上します。
8. OrderSend()を安全に使うためのEA設計ベストプラクティス
OrderSend()はEAの中核処理ですが、実運用では単純に注文を出すだけでは不十分です。
相場環境・サーバー応答・ブローカー仕様などの影響を受けるため、安定したEAを作るには注文処理の設計パターンを理解しておく必要があります。
ここでは、実務のEA開発でよく使われる 安全な注文処理の設計方法を整理します。
8.1 注文前チェックを必ず行う
EAは注文を出す前に、取引可能な状態かどうかを確認するべきです。
主にチェックする項目
- 自動売買が許可されているか
- 取引時間内か
- スプレッドが大きすぎないか
- 証拠金が足りているか
例
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
{
Print("自動売買が許可されていません");
return;
}
スプレッドチェックの例
double spread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
if(spread > 30)
{
Print("スプレッドが大きすぎるため注文回避");
return;
}
スプレッドフィルターは、特に
- 指標発表
- 週明け
- 流動性低下
などで重要になります。
8.2 ポジション管理を行う
EAが無制限に注文を出すと、意図しない大量ポジションになる可能性があります。
そのため、注文前に現在のポジション数を確認します。
例
if(PositionsTotal() > 0)
{
Print("既にポジションあり");
return;
}
または、MagicNumberで管理する方法もあります。
for(int i=0;i<PositionsTotal();i++)
{
ulong ticket = PositionGetTicket(i);
}
このようにして
- 同時ポジション数制限
- EA専用ポジション管理
を行います。
8.3 注文失敗時のリトライ処理
リアル口座では、次の理由で注文が失敗することがあります。
- スリッページ
- 価格更新
- サーバー遅延
- 一時的な通信エラー
そのため、EAでは再試行処理(Retry)を入れることが多いです。
例
int retry = 3;
while(retry > 0)
{
if(OrderSend(request,result))
break;
retry--;
Sleep(500);
}
ただし、無限ループは危険です。
最大回数を必ず制限します。
8.4 MagicNumberを必ず使用する
EAでは magic を使って注文を識別します。
request.magic = 10001;
これを設定しておくことで
- 手動注文
- 他EA注文
- 現在EA注文
を区別できます。
ポジション管理では必須に近い項目です。
8.5 ログを必ず残す
EA開発では、ログがないと原因調査が困難になります。
最低限出力するべき情報
retcodeorderdealprice
例
Print("retcode=", result.retcode);
Print("order=", result.order);
Print("deal=", result.deal);
Print("price=", result.price);
このログは
- バックテスト
- フォワードテスト
- 実口座
すべてで重要になります。
8.6 EAの注文処理の基本構造
実務のEAでは、注文処理は次の構造になります。
売買シグナル
↓
注文前チェック
↓
OrderSend()
↓
retcode確認
↓
ログ出力
↓
ポジション管理
この構造にしておくと
- デバッグ
- 運用
- 改良
が非常にやりやすくなります。
つまずきやすい点・注意点・よくある失敗
① 注文条件チェックをしていない
EAが無制限に注文を出す原因になります。
② MagicNumberを使っていない
ポジション管理ができなくなります。
③ ログを出していない
EAが動かない原因を特定できません。
④ リトライ処理を入れていない
リアル環境では注文失敗が普通に起きます。
⑤ スプレッドフィルターがない
指標時に危険な価格で約定する可能性があります。
実務的な設計ポイント
安定したEAでは、注文処理は次の3要素で構成されます。
安全性
安定性
デバッグ性
- 安全性 → 注文条件チェック
- 安定性 → リトライ処理
- デバッグ性 → ログ出力
この3つを実装しておくと、EAの品質は大きく向上します。
9. FAQ(よくある質問)
9.1 OrderSend()とCTradeクラスはどちらを使うべきですか?
どちらでも注文は可能ですが、用途によって使い分けられます。
| 方法 | 特徴 |
|---|---|
OrderSend() |
低レベルAPI。細かい制御が可能 |
CTrade |
ラッパークラス。コードが簡潔 |
初心者は CTrade を使う方がコードが短くなります。
一方で、EAを細かく制御したい場合は OrderSend() の方が柔軟です。
例(CTrade)
CTrade trade;
trade.Buy(0.1);
例(OrderSend)
OrderSend(request,result);
EAの内部処理を深く理解したい場合は、OrderSend()を理解しておく価値があります。
9.2 OrderSend()がtrueを返したのに注文が成立しません
OrderSend()の戻り値は、注文送信が成功したかどうかだけを示します。
実際の注文結果は
result.retcode
を確認する必要があります。
例
if(result.retcode == TRADE_RETCODE_DONE)
これが成立して初めて、注文成功と判断できます。
9.3 Buy注文とSell注文で価格が違うのはなぜですか?
FXでは
| 価格 | 意味 |
|---|---|
| Bid | 売値 |
| Ask | 買値 |
という2つの価格があります。
注文時の対応は次の通りです。
| 注文 | 使用価格 |
|---|---|
| Buy | Ask |
| Sell | Bid |
この仕組みはスプレッド(売買差)によるものです。
9.4 Invalid stopsエラーが出る原因は何ですか?
主な原因は次の3つです。
- SL / TPが近すぎる
- SL / TPの方向が逆
- ブローカーのStopLevel制限
StopLevelは次の関数で確認できます。
SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
この値より離してSL/TPを設定する必要があります。
9.5 OrderSend()が実行されない原因は何ですか?
よくある原因は次の通りです。
- Algo TradingがOFF
- EA設定で自動売買が無効
- ロジック条件が成立していない
- エラーをログ確認していない
EAがトレードしない場合は、まずログ出力を確認することが重要です。
9.6 ZeroMemory()は必ず必要ですか?
強制ではありませんが、実務ではほぼ必須です。
構造体に残る未初期化データを防ぐためです。
例
ZeroMemory(request);
ZeroMemory(result);
これを入れておくことで、原因不明の注文失敗を防げます。
9.7 EAで注文管理を行うときの基本方法は?
EAでは通常、次の方法でポジションを管理します。
- MagicNumberを設定
- 現在ポジションを取得
- EA専用ポジションのみ処理
例
request.magic = 123456;
これにより
- 手動トレード
- 他EAのトレード
と区別できます。
9.8 OrderSend()で注文が不安定になるのはなぜですか?
リアル市場では次の要因があります。
- 価格変動
- サーバー遅延
- スプレッド変化
- 流動性低下
そのため、EAでは次の対策が一般的です。
deviation設定- リトライ処理
- スプレッドフィルター
これらを実装することで、注文の安定性が向上します。