
自動売買EAで、トレードさせるにはどうしたらいいの?
OrderSend関数とは
自動売買を作るからには、自動でトレードさせたいですよね!
「ロジックは考えてあるのに、注文を出す方法が分からない」という方は、OrderSend関数を使ってみましょう。
OrderSend関数は、FX会社に注文を出す関数です。
プログラムで実行することで、注文を出すことができます。
対応している注文方法は以下の通りです。
・成り行き注文
・指値注文
・逆指値注文
つまり、エントリー注文だけを出すことができる関数です。
指値の変更や決済の関数は、別の関数がありますので、そちらを利用してください。
OrderSend関数の書き方
OrderSend関数の使い方は、基本的な関数と同じです。
関数をマスターしていない方はこちらの記事が参考になります。
基本的な書き方
OrderSend関数は、引数が非常に多い関数です。
そのため、難しい部分もあるかと思います。
ですが、成り行き注文のプログラムだけ作ってしまえば、あとは簡単に作れてしまうので、まずは成り行き注文のプログラムを作ってみましょう。
さて本題です。
OrderSend関数の基本的な書き方は以下の通りです。
分かりやすいように、引数は省略しています。
int ticketNum = OrderSend( ①, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩, ⑪);
返り値はint型で、引数は11個あります。
まずは返り値から見ていきましょう。
OrderSend関数の返り値(戻り値)
OrderSend関数の返り値はint型です。
返り値は配列のような連続した値ではなく、値が1つだけ返って来ます。
OrderSend関数の返り値は、関数の中でも特殊で、返ってきた値を使うことは、ほとんどありません。
返り値の具体的な値は以下の通りです。
・注文が成功すればチケット番号(注文番号)が返ってきます。
・注文が失敗すれば-1が返ってきます。
ポジションの管理方法をチケット番号にしている場合は、重要になるのですが、その方法は難易度が高いので、今は気にしなくて大丈夫です。
このようにOrderSend関数は、あくまで注文を出すだけの関数なので、返り値は重要ではありません。
OrderSend関数の引数
ここからはOrderSend関数の引数について解説していきます。
数が多いので、ゆっくりと見ていきましょう。
はじめに、OrderSend関数には11個の引数があります。
int ticketNum = OrderSend( ①, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩, ⑪);
一覧でザッと見てみます。
| 番号 | データ型 | 引数名 | 内容 |
| ① | string | symbol | 通貨ペアを設定(NULLなど) |
| ② | int | cmd | 注文の種類を設定(OP_BUYなど) |
| ③ | double | volume | ロット数を設定 |
| ④ | double | price | 注文の価格を設定 |
| ⑤ | int | slippage | 許容するスリッページを設定 |
| ⑥ | double | stoploss | 損切りを設定 |
| ⑦ | double | takeprofit | 利確を設定 |
| ⑧ | string | comment | ポジションのコメントを設定 |
| ⑨ | int | magic | マジックナンバーを設定 |
| ⑩ | datetime | expiration | ポジションの有効期限を設定 |
| ⑪ | color | arrow_color | チャート上のポジションの色を設定 |
1つずつ詳しく見ていきましょう。
①symbol
symbolは、注文を実行する通貨ペアを設定します。
例えばドル円の場合、「USDJPY」という値になります。
ですが、具体的に通貨ペアを設定する必要はありません。
というのもMQLには便利なものがあり、「Symbol」または「NULL」と書くだけで、現在の通貨ペアを設定できます。
そのため通常は、下記のように入力すれば大丈夫です。
int ticketNum = OrderSend( NULL, ②, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩, ⑪);
②cmd
cmdには注文の種類を設定します。
注文の種類は6種類ありますが、「成り行き買い注文(OP_BUY)」と「成り行き売り注文(OP_SELL)」だけ覚えれば問題なしです。
ここでは成り行き買い注文を出す場合を考えています。
int ticketNum = OrderSend( NULL, OP_BUY, ③, ④, ⑤, ⑥, ⑦, ⑧, ⑨, ⑩, ⑪);
実用的なサンプルプログラム
ここからは、OrderSend関数を使った実用的なサンプルプログラムを紹介していきます。
基本の書き方を理解した上で、実際のEAでどのように使うかを見ていきましょう。
サンプル①:エラーハンドリング付きの成り行き注文
実際のEA開発では、注文が失敗したときにエラー内容を確認できるようにしておくことが非常に重要です。
以下のプログラムは、注文の成功・失敗を判定し、失敗した場合はエラーコードをログに出力する実用的なサンプルです。
//+------------------------------------------------------------------+
//| エラーハンドリング付き成り行き買い注文のサンプル |
//+------------------------------------------------------------------+
void OnTick()
{
// すでにポジションを持っている場合は何もしない
if(OrdersTotal() > 0) return;
// 損切り・利確の価格を計算(現在の買い値から50pips離れた位置)
double stopLoss = Ask - 50 * Point; // 損切り:現在価格の50pips下
double takeProfit = Ask + 100 * Point; // 利確:現在価格の100pips上
// 成り行き買い注文を実行
int ticket = OrderSend(
NULL, // 現在の通貨ペア
OP_BUY, // 買いの成り行き注文
0.1, // 0.1ロット
Ask, // 現在の買い値
20, // スリッページ2pips(0.1pips単位)
stopLoss, // 損切り価格
takeProfit, // 利確価格
"Buy Order", // コメント
12345, // マジックナンバー
0, // 有効期限なし
clrBlue // チャート上の矢印の色
);
// 注文結果を判定する
if(ticket >= 0)
{
// 注文成功:チケット番号をログに表示
Print("注文成功!チケット番号: ", ticket);
}
else
{
// 注文失敗:エラーコードを取得してログに表示
int errorCode = GetLastError();
Print("注文失敗!エラーコード: ", errorCode);
}
}GetLastError()を使うことで、なぜ注文が失敗したのかを調べることができます。エラーコードの意味はMQLリファレンスで確認できますので、デバッグに活用してください。
サンプル②:移動平均線のゴールデンクロスで買い注文を出すEA
次は、テクニカル指標と組み合わせた実用的なEAのサンプルです。
短期移動平均線が長期移動平均線を下から上に抜けた(ゴールデンクロス)タイミングで買い注文を出します。
//+------------------------------------------------------------------+
//| 移動平均線ゴールデンクロスで買い注文を出すEA |
//+------------------------------------------------------------------+
// パラメータ設定(外部から変更可能)
extern double LotSize = 0.1; // ロット数
extern int ShortPeriod = 5; // 短期移動平均の期間
extern int LongPeriod = 25; // 長期移動平均の期間
extern int StopLossPips = 30; // 損切り幅(pips)
extern int TakeProfitPips = 60; // 利確幅(pips)
extern int MagicNumber = 1001; // マジックナンバー
void OnTick()
{
// 現在のバーの短期・長期移動平均線の値を取得
double shortMA_current = iMA(NULL, 0, ShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double longMA_current = iMA(NULL, 0, LongPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
// 1本前のバーの短期・長期移動平均線の値を取得
double shortMA_prev = iMA(NULL, 0, ShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double longMA_prev = iMA(NULL, 0, LongPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
// 自分のマジックナンバーのポジションがあるか確認
bool hasPosition = false;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// マジックナンバーと通貨ペアが一致するポジションがあるかチェック
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
{
hasPosition = true;
break;
}
}
}
// すでにポジションがある場合は注文しない
if(hasPosition) return;
// ゴールデンクロスの判定
// 1本前:短期MA ≦ 長期MA かつ 現在:短期MA > 長期MA
if(shortMA_prev <= longMA_prev && shortMA_current > longMA_current)
{
// 損切り・利確の価格を計算
double sl = Ask - StopLossPips * Point;
double tp = Ask + TakeProfitPips * Point;
// 買い注文を実行
int ticket = OrderSend(
NULL, OP_BUY, LotSize, Ask, 20,
sl, tp,
"GoldenCross Buy", // ゴールデンクロスの買い注文
MagicNumber, 0, clrBlue
);
if(ticket < 0)
{
Print("ゴールデンクロス買い注文失敗 エラー: ", GetLastError());
}
else
{
Print("ゴールデンクロス買い注文成功 チケット: ", ticket);
}
}
}このサンプルのポイントは、マジックナンバーを使ってポジションの重複を防いでいるところです。すでに自分のEAがポジションを持っている場合は、新たな注文を出さないようにしています。
サンプル③:買い注文と売り注文を切り替えるEA
実際のEA開発では、条件に応じて買い注文と売り注文を使い分ける必要があります。
以下のサンプルは、RSIの値に応じて売買方向を切り替えるEAです。買い注文と売り注文でAsk/Bidや損切り・利確の方向が逆になる点に注目してください。
//+------------------------------------------------------------------+
//| RSIの値で売買を切り替えるEA |
//+------------------------------------------------------------------+
extern double LotSize = 0.1; // ロット数
extern int RSI_Period = 14; // RSIの期間
extern int RSI_BuyLevel = 30; // RSIがこの値以下なら買い(売られすぎ)
extern int RSI_SellLevel = 70; // RSIがこの値以上なら売り(買われすぎ)
extern int SL_Pips = 40; // 損切り幅(pips)
extern int TP_Pips = 80; // 利確幅(pips)
extern int MagicNumber = 2002; // マジックナンバー
void OnTick()
{
// 自分のポジションがすでにあれば何もしない
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
return; // ポジションがあるので処理を中断
}
}
// RSIの値を取得(現在のバー)
double rsiValue = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE, 0);
// RSIが30以下 → 売られすぎなので買い注文
if(rsiValue <= RSI_BuyLevel)
{
// 買い注文の場合:Askで注文、SLはAskより下、TPはAskより上
double sl = Ask - SL_Pips * Point;
double tp = Ask + TP_Pips * Point;
int ticket = OrderSend(
NULL, OP_BUY, LotSize, Ask, 20,
sl, tp,
"RSI Buy", // RSIによる買い注文
MagicNumber, 0, clrBlue
);
if(ticket >= 0)
Print("RSI買い注文成功 RSI=", rsiValue, " チケット=", ticket);
else
Print("RSI買い注文失敗 エラー=", GetLastError());
}
// RSIが70以上 → 買われすぎなので売り注文
if(rsiValue >= RSI_SellLevel)
{
// 売り注文の場合:Bidで注文、SLはBidより上、TPはBidより下
// ※買い注文とは損切り・利確の方向が逆になる点に注意!
double sl = Bid + SL_Pips * Point;
double tp = Bid - TP_Pips * Point;
int ticket = OrderSend(
NULL, OP_SELL, LotSize, Bid, 20,
sl, tp,
"RSI Sell", // RSIによる売り注文
MagicNumber, 0, clrRed
);
if(ticket >= 0)
Print("RSI売り注文成功 RSI=", rsiValue, " チケット=", ticket);
else
Print("RSI売り注文失敗 エラー=", GetLastError());
}
}初心者がよく間違えるポイントですが、買い注文はAsk、売り注文はBidを使います。また、損切り・利確の方向も売買で逆になりますので、必ず確認するようにしましょう。
サンプル④:注文関数を共通化して使い回す方法
EA開発に慣れてくると、注文処理を関数として共通化しておくと、コードの見通しが良くなり、バグの防止にもつながります。
以下は、買い注文・売り注文をそれぞれ関数化したサンプルです。OnTick()からシンプルに呼び出せるようになります。
//+------------------------------------------------------------------+
//| 注文関数を共通化して使い回すサンプル |
//+------------------------------------------------------------------+
extern double LotSize = 0.1; // ロット数
extern int SL_Pips = 50; // 損切り幅(pips)
extern int TP_Pips = 100; // 利確幅(pips)
extern int Slippage = 20; // スリッページ
extern int MagicNumber = 3003; // マジックナンバー
//+------------------------------------------------------------------+
//| 買い注文を出す関数 |
//+------------------------------------------------------------------+
int SendBuyOrder(string comment)
{
double sl = Ask - SL_Pips * Point;
double tp = Ask + TP_Pips * Point;
int ticket = OrderSend(
NULL, OP_BUY, LotSize, Ask, Slippage,
sl, tp,
comment, MagicNumber, 0, clrBlue
);
if(ticket < 0)
Print("買い注文失敗 エラー: ", GetLastError());
else
Print("買い注文成功 チケット: ", ticket);
return ticket;
}
//+------------------------------------------------------------------+
//| 売り注文を出す関数 |
//+------------------------------------------------------------------+
int SendSellOrder(string comment)
{
double sl = Bid + SL_Pips * Point;
double tp = Bid - TP_Pips * Point;
int ticket = OrderSend(
NULL, OP_SELL, LotSize, Bid, Slippage,
sl, tp,
comment, MagicNumber, 0, clrRed
);
if(ticket < 0)
Print("売り注文失敗 エラー: ", GetLastError());
else
Print("売り注文成功 チケット: ", ticket);
return ticket;
}
//+------------------------------------------------------------------+
//| 自分のポジションがあるか確認する関数 |
//+------------------------------------------------------------------+
bool HasMyPosition()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| メイン処理 |
//+------------------------------------------------------------------+
void OnTick()
{
// すでにポジションがある場合は何もしない
if(HasMyPosition()) return;
// 移動平均線の値を取得
double shortMA = iMA(NULL, 0, 5, 0, MODE_SMA, PRICE_CLOSE, 0);
double longMA = iMA(NULL, 0, 25, 0, MODE_SMA, PRICE_CLOSE, 0);
// 短期MAが長期MAより上なら買い注文
if(shortMA > longMA)
{
SendBuyOrder("MA Buy");
}
// 短期MAが長期MAより下なら売り注文
else if(shortMA < longMA)
{
SendSellOrder("MA Sell");
}
}このように注文処理を関数化しておくと、OnTick()の中がスッキリして読みやすくなります。また、買い注文・売り注文の処理が1か所にまとまるので、修正やバグ修正も簡単になります。
特にHasMyPosition()関数のように、ポジションの有無を確認する処理も関数化しておくと、どのEAでも使い回しができて非常に便利です。
まとめ
今回はOrderSend関数の使い方を解説しました。
ポイントをまとめると以下の通りです。
・OrderSend関数はエントリー注文を出すための関数
・引数は11個あるが、まずは成り行き注文を覚えればOK
・買い注文はAsk、売り注文はBidを使う
・損切り・利確の方向は、買いと売りで逆になる
・エラーハンドリング(GetLastError)を入れておくとデバッグが楽になる
・注文処理を関数化しておくと、コードの管理がしやすくなる
まずはサンプル①のシンプルな成り行き注文から試してみて、慣れてきたらサンプル④のように関数化していくのがおすすめです。
ぜひ、自分のEA開発に活用してみてください!



