前回は ポジションをクローズする為の記述 について解説しました。
改めて前回の内容をおさらいをしておくと、
- ポジションをクローズする時は、メンバ変数 .actionにTRADE_ACTION_DEALを設定する。
- 決済をする時はメンバ変数 .type には保有しているポジションと逆方向のオーダータイプ定数値を代入する。(保有しているポジションのタイプがORDER_TYPE_BUYならORDER_TYPE_SELLを、保有しているポジションのタイプがORDER_TYPE_SELLならORDER_TYPE_BUYを・・・と言った具合)
ということをお伝えしました。
今回は 待機注文の実行を行うための記述 についてお話ししたいと思います。
※待機注文というのは、成行注文のようにマーケットの現在値でポジションを持つのではなく、特定の価格に到達したらポジションを持つような要求をトレードサーバーにする注文方式です。
今回の記事を読めば、EA(自動売買プログラム)開発において、待機注文型のEA製作という新たな手札を手にすることができるようになり、自動売買の可能性を広げることが可能になります。
新規の待機注文を出す時にはTRADE_ACTION_PENDINGを設定する
新規の待機注文を出すときにはMqlTradeRequest構造体のメンバ変数 .actionに設定する定数値をTRADE_ACTION_PENDINGにします。
その上で、その他メンバ変数のうち、
.type 、.volume、.symbol、.Price 、.sl、.tp、.type_time、.expiration、.type_filling
に特定の値を指定します。
オーダータイプがストップリミット注文の場合は、.stoplimitへの入力も必要です。例によって、実際に待機注文を実行するスクリプトを見ていきましょう。
実際に待機注文を実行するスクリプトを書いてみる
グローバル領域での記述
まずはグローバル領域(関数の外の領域)での記述です。
#property description "待機注文を実行するスクリプト"
#property script_show_inputs
プロパティ命令の” description”はプログラムをチャートに挿入した際、プロパティ画面の共有部に表示される文言を指定する命令記述です↓
define命令でマジックナンバーを定数として設定するのは前回と同じです。↓
#define EXPERT_MAGIC 123456 // エキスパートアドバイザのMagicNumber
続いてはinput変数の記述ですが、
待機注文にも、ストップ注文、リミット注文、ストップリミット注文と種類があるので、パラメータ化して選択できるようになっています。
その他、待機注文の開始価格設定値(現在値から何ポイント離れたところに、待機注文を設定するか)、ストップロスとテイクプロフィットのポイントベースの値、ストップリミット注文の開始価格設定値なども設定できるようにしました。↓
input ENUM_ORDER_TYPE orderType=ORDER_TYPE_BUY_LIMIT; // 注文タイプ
input int offset = 50; //待機注文の開始価格設定値
input int StopLoss=1000;//SL
input int TakeProfit=1000;//TP
input int StopLimitPrice=500;//ストップリミット注文の開始価格設定値
OnStart関数内での記述
グローバル領域での記述が終わったので、OnStart関数内の記述に移ります。
void OnStart()
{
//--- リクエストと結果の宣言と初期化
MqlTradeRequest request= {};
MqlTradeResult result= {};
//--- 未決注文の設定の為のパラメータ
request.action =TRADE_ACTION_PENDING; // 取引操作タイプ
request.symbol =Symbol(); // シンボル
request.volume =0.1; // 0.1ロットのボリューム
request.deviation=2; // 価格からの許容偏差
request.magic =EXPERT_MAGIC; // 注文のMagicNumber
request.type_time=ORDER_TIME_GTC;
最初に申し上げたように、メンバ変数 .actionに設定する定数値をTRADE_ACTION_PENDINGにしています。その他のメンバ変数への入力は、これまでにも見てきている部分なので詳細説明は割愛します。
※もし各メンバ変数の役割などにピンと来ていない部分があれば、↓
- 第60回「OrderSend関数とMqlTradeRequest構造体」
- MQL5 EA講座 第62回「実際に注文を出すコードを書いてみる」
- MQL5 EA講座 第63回「約定したポジションにSLとTPを設定する」
- MQL5 EA講座 第64回「ポジションをクローズする」
等をご覧ください。<m(__)m>
待機注文の有効期限を格納するrequest.type_timeにはORDER_TIME_GTC(有効期限なし)を記述しています。
.type_timeへの値を明示しなければ、自動的にORDER_TIME_GTCになるのですが、待機注文ということで一応明示しておきましす。
なお、.type_timeの値がORDER_TIME_GTCの場合、.expirationへの値入力は不要です。
// 注文設定の為の現在の価格からのオフセット(ポイント)
double price; // 注文の発動価格
double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); // ポイントサイズ
int digits=SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); // 小数点以下の桁数(精度)
変数priceには待機注文の発動価格が格納されます。発動価格の計算式はプログラム挿入時に選択した待機注文の種類によって、変わるようになっています。
変数pointには取引銘柄のポイントが格納されます。ポイントの取得にはSymbolInfoDouble関数の第2引数に定数値「SYMBOL_POINT」を記述します。
変数digitsには、小数点以下の表示桁数が格納されます。小数点以下の表示桁数の取得にはSymbolInfoInteger関数の第2引数にSYMBOL_DIGITSを記述します。
待機注文の種類による条件分岐の記述
次は待機注文の種類による条件分岐の記述です。
ストップ注文、リミット注文、ストップリミット注文と待機注文の種類があるので、どの待機注文をプログラム挿入時選択しているかによって、メンバ変数 .Priceに代入する計算式が変わってきます。
条件分岐-リミット注文の場合-
//--- 操作タイプのチェック
if(orderType==ORDER_TYPE_BUY_LIMIT)
{
request.type =ORDER_TYPE_BUY_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK)-offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price-(StopLoss*point); //SL
request.tp= price+(StopLoss*point); //TP
}
else
if(orderType==ORDER_TYPE_SELL_LIMIT)
{
request.type =ORDER_TYPE_SELL_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)+offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(StopLoss*point); //TP
}
ORDER_TYPE_BUY_LIMIT すなわち リミット買い注文の場合ですが、リミット注文はマーケットの現在値よりも、有利な価格でポジションを持つことを目的とした注文形態なので、
現在値=SymbolInfoDouble(Symbol(),SYMBOL_ASK)
よりも安い価格↓すなわち
SymbolInfoDouble(Symbol(),SYMBOL_ASK)-offset*point
という記述になります。
変数「offset」はinput変数でパラメータ化した値です。
代入前にNormalizeDouble関数という組み込み関数が使われていますが、この関数は第1引数で指定した値を、小数点以下の数を第2引数で指定した桁数で、四捨五入する関数です。
NormalizeDouble関数の第2引数に記述されている変数digitsには、定義済み変数の_Digitsが代入されています。
_Digitsは現在の通貨ペアにおける、価格の小数点以下の桁数を取得する定義済み変数ですから、
ドル円などのクロス円通貨ペアであれば「3」桁、ユーロドルなどのクロスドル通貨ペアであれば、「5」桁に値を調整することになります。
※NormalizeDouble関数が行った桁数調整のような、プログラムが取り扱うルールに則って値を整える作業のことを「正規化」と言います。
※NormalizeDouble関数については、→コチラをご覧ください。
NormalizeDouble関数による正規化が済んで、メンバ変数 .Priceへの値代入が完了したら
メンバ変数 .sl と .tpにストップロスとテイクプロフィットの値を代入していきます。
.sl には.Priceに格納されている値 マイナス (StopLoss*point)
.tp には.Priceに格納されている値 プラス (StopLoss*point)
の値がそれぞれ入ります。
ORDER_TYPE_SELL_LIMIT すなわちリミット売り注文の場合はORDER_TYPE_BUY_LIMITの細かい記述を逆に書き換えただけなので難しくはないですね(^^♪
条件分岐-ストップ注文の場合-
else
if(orderType==ORDER_TYPE_BUY_STOP)
{
request.type =ORDER_TYPE_BUY_STOP; // 注文タイプ
price =SymbolInfoDouble(Symbol(),SYMBOL_ASK)+offset*point; // 発注価格
request.price=NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_SELL_STOP)
{
request.type =ORDER_TYPE_SELL_STOP; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)-offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(TakeProfit*point); //TP
}
ORDER_TYPE_BUY_STOP、すなわちストップ買い注文は、現在値よりも不利な価格(=高く)でポジションを持つ要求になるので、
現在値=SymbolInfoDouble(Symbol(),SYMBOL_ASK)よりも高い価格↓すなわち
SymbolInfoDouble(Symbol(),SYMBOL_ASK)+offset*point
という記述になります。リミット注文との違いはここだけですね。SLやTPの設定値もリミット注文と変わりません。
ORDER_TYPE_SELL_STOP、すなわちストップ売り注文の記述はORDER_TYPE_BUY_STOPの細かい部分を全部逆にしているだけだ、というのはサンプルコードを見てもらうとわかると思います。
条件分岐-ストップリミット注文の場合-
else
if(orderType==ORDER_TYPE_BUY_STOP_LIMIT)
{
request.type =ORDER_TYPE_BUY_STOP_LIMIT; // 注文タイプ
price =SymbolInfoDouble(Symbol(),SYMBOL_BID)+offset*point; // 発注価格
request.price=NormalizeDouble(price,digits); // 正規化された発注価格
double slprice=price-(StopLimitPrice*point); //ストップリミットの約定価格
request.stoplimit=slprice;//
request.sl= slprice-(StopLoss*point); //SL
request.tp= slprice+(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_SELL_STOP_LIMIT)
{
request.type =ORDER_TYPE_SELL_STOP_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)-offset*point; // 発注価格
double slprice=price+(StopLimitPrice*point);
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.stoplimit=slprice;//ストップリミットの約定価格
request.sl= slprice+(StopLoss*point); //SL
request.tp= slprice-(TakeProfit*point); //TP
}
ORDER_TYPE_BUY_STOP_LIMIT、すなわち買いのストップリミット注文の時ですが、
まず大前提として「ストップリミット注文ってなんだっけ?」という方は→コチラをご覧ください。
基本的にブレイクアウトした後、一旦押し目をつくるという想定の元、その押し目で待つような注文方法になります。↓
.Priceにはトリガーとなるストップ価格を、.stoplimitにはポジションを有効化させたいリミット価格を入れます。
成行注文やストップリミット注文以外の待機注文は.Priceに格納されている値が、ポジションを有効化させる値になるのですが、ストップリミット注文の場合は、ポジションを有効化させる値は.stoplimitに格納するという違いに注意が必要です。
「slprice」という変数をつくり、.Priceに格納されているブレイクアウトしたストップ値から指定ポイント分下がった価格を格納できるようにしました。
.sl と .tpにストップロスとテイクプロフィットの値を代入していきます。
.sl には.stoplimitに格納されている値 マイナス (StopLoss*point)
.tp には.stoplimitに格納されている値 プラス (StopLoss*point)
の値がそれぞれ入ります
ORDER_TYPE_SELL_STOP_LIMITは、細かい計算や記述をORDER_TYPE_BUY_STOP_LIMITとは逆にするだけなので、特に難しい点はないかと思います。
全体のコード
全体のコードは以下のようになっています
#property script_show_inputs
#define EXPERT_MAGIC 123456 // エキスパートアドバイザのMagicNumber
input ENUM_ORDER_TYPE orderType=ORDER_TYPE_BUY_LIMIT; // 注文タイプ
input int offset = 50; //待機注文の開始価格設定値
input int StopLoss=1000;//SL
input int TakeProfit=1000;//TP
input int StopLimitPrice=500;//ストップリミット注文の開始価格設定値
//+------------------------------------------------------------------+
//| 未決注文の設定 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- リクエストと結果の宣言と初期化
MqlTradeRequest request= {};
MqlTradeResult result= {};
//--- 未決注文の設定の為のパラメータ
request.action =TRADE_ACTION_PENDING; // 取引操作タイプ
request.symbol =Symbol(); // シンボル
request.volume =0.1; // 0.1ロットのボリューム
request.deviation=2; // 価格からの許容偏差
request.magic =EXPERT_MAGIC; // 注文のMagicNumber
// 注文設定の為の現在の価格からのオフセット(ポイント)
double price; // 注文の発動価格
double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); // ポイントサイズ
int digits=SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); // 小数点以下の桁数(精度)
//--- 操作タイプのチェック
if(orderType==ORDER_TYPE_BUY_LIMIT)
{
request.type =ORDER_TYPE_BUY_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_ASK)-offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price-(StopLoss*point); //SL
request.tp= price+(TakeProfit*point); //TP
request.type_time=ORDER_TIME_GTC;
}
else
if(orderType==ORDER_TYPE_SELL_LIMIT)
{
request.type =ORDER_TYPE_SELL_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)+offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_BUY_STOP)
{
request.type =ORDER_TYPE_BUY_STOP; // 注文タイプ
price =SymbolInfoDouble(Symbol(),SYMBOL_ASK)+offset*point; // 発注価格
request.price=NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_SELL_STOP)
{
request.type =ORDER_TYPE_SELL_STOP; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)-offset*point; // 発注価格
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.sl= price+(StopLoss*point); //SL
request.tp= price-(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_BUY_STOP_LIMIT)
{
request.type =ORDER_TYPE_BUY_STOP_LIMIT; // 注文タイプ
price =SymbolInfoDouble(Symbol(),SYMBOL_ASK)+offset*point; // 発注価格
request.price=NormalizeDouble(price,digits); // 正規化された発注価格
double slprice=price-(StopLimitPrice*point); //ストップリミットの約定価格
request.stoplimit=slprice;//
request.sl= slprice-(StopLoss*point); //SL
request.tp= slprice+(TakeProfit*point); //TP
}
else
if(orderType==ORDER_TYPE_SELL_STOP_LIMIT)
{
request.type =ORDER_TYPE_SELL_STOP_LIMIT; // 注文タイプ
price=SymbolInfoDouble(Symbol(),SYMBOL_BID)-offset*point; // 発注価格
double slprice=price+(StopLimitPrice*point);
request.price =NormalizeDouble(price,digits); // 正規化された発注価格
request.stoplimit=slprice;//ストップリミットの約定価格
request.sl= slprice+(StopLoss*point); //SL
request.tp= slprice-(TakeProfit*point); //TP
}
else
Alert("この例は未決注文の設定のみを対象にしています"); // もし未決注文ではないものが選択されている場合
//--- リクエストの送信
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError()); // もしリクエストの送信に失敗した場合、エラーコードを出力する
//--- 操作情報
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
}
//+------------------------------------------------------------------+
↑のサンプルコードを実際に実行してみると・・・↓
まとめ
今回は 待機注文の実行を行うための記述 について解説しました。
今回の記事では以下のことを学びました
- 新規の待機注文を出すときには、メンバ変数 .actionに設定する定数値をTRADE_ACTION_PENDINGにする。
今回は以上になります。
なお、待機注文に関しては、今後の講座でもオリジナル関数やクラスを作ったり、実際に待機注文用のEA(自動売買プログラム)を作ったりする記事を用意しておりますので、楽しみにMQL5の勉強を進めていただければと思います。
※待機注文に関する今後の講座記事は以下のようなものになります。↓
- MQL5 EA講座 第86回「待機注文関数を作る-その1-」
- MQL5 EA講座 第87回「待機注文関数を作る-その2-」
- MQL5 EA講座 第88回「待機注文情報取得用のクラスを追加する」
- MQL5 EA講座 第89回「待機注文情報取得用クラスにpublic関数を実装する」
- MQL5 EA講座 第90回「待機注文を修正する関数を実装する」
- MQL5 EA講座 第91回「待機注文を削除する関数を実装する」
- MQL5 EA講座 第92回「待機注文クラスを使ってEAを作る」
最後までお読みいただきありがとうございました<m(__)m>
【超入門】MQL5 EA講座 第64回「ポジションをクローズする」【EAの作り方】←
→【超入門】MQL5 EA講座 第66回「待機注文の価格修正」【EAの作り方】
※ツイッターでも、
を用意していますので、よろしければご参照ください。<m(__)m>
待機注文を使ったコード記述については、講座記事とは別に以下のような記事もありますので、参考にしてください↓
コメント