EAがポジション持ってて指値や逆指値触るのは嫌だけどここでは決済したいなーみたいな時や、単純に裁量トレードをやっていて指値(TP)と逆指値(SL)を設定するのが面倒な時に使えるようなEAを、今回作りました。
簡単なつくりになっているので、EA作成初心者の方がEAを作るための練習にもなるかと思います。
EAの設定と動き(概要)
自動決済EAですが、設定は以下の4つです。

- 注文番号(Order_No)・・・自動で決済したいポジションの注文番号を設定する(0と設定した時だけマジックナンバー0=裁量のポジション全てとする)
- 指値(Order_TP)・・・TPとして決済したい値を設定する
- 逆指値(Order_SL)・・・SLとして決済したい値を設定する
- アラート(SoundAlert)・・・決済時にアラートで知らせたいかを設定する(true:知らせる false:知らせない)
設定した注文番号に対して指値と逆指値を設定してあげることでそこで決済してくれます。決済したいポジションを指定する方法は、MT4で見ると・・・

ここです。この注文番号とEAの設定を合わせてあげるとそのポジションの自動決済を管理します。
全てを適切に設定するとのチャートの右下に以下のような感じで文言が表示されます。

また指値と逆指値をちゃんと設定すると、指値と逆指値を設定した値段の所に点線が引かれます。逆指値は赤い点線、指値は青い点線です。(ポジションを持ってない場合はグレー)
指値や逆指値に到達した際は勝手に決済されますが、設定のSoundAlertを「true」にしていると決済されたと同時にアラート音とともにポップアップメッセージが表示されます。

決済された場合、先ほどの右下の文言も未監視という形で監視されていない状態に戻ります。
EAのエラーメッセージ
今回のEAは設定がわりとシビア(注文番号や指値、逆指値の値を間違える事がある)なので、設定エラーについても一通り作りました。
正常系
正常に監視されている場合、注文番号及びポジションの値が表示される。

また、正常に決済された際は以下の文言に切り替わる。

注文番号を0にした場合、以下のように[裁量(MagicNunber=0)を操作します]と表示される。
※TPかSLにエラーがあった時のみ表示される文言

異常系
初期状態(何も設定していない場合)は以下のように設定されていないというメッセージが表示される。

注文番号を設定したがみつからなかった場合、赤色で文言[注文番号:XXXXXX取得失敗]と表示される。
注文番号が正しく設定されていないためもう一度管理したいポジションの注文番号と見比べて設定する必要がある。

TPやSLの値が誤っている場合(既にその値を上回ったり下回ったりしている場合)、赤色で文言[TP(SL)設定の誤り~]と表示される。
SLやTPが正しく設定されていないためもう一度値を確認し設定する必要がある。

ソースコード
今回のEAソースコードです。
//+------------------------------------------------------------------+ //| AutoClose.mq4 | //| Copyright 2020, mef Software. | //| https://fx-prog.com/ | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, mef Software." #property link "https://fx-prog.com/" #property version "1.00" input int Order_No = 99999; //注文番号(0の場合はマジックナンバー0のもの) input double Order_TP = 0; //指値 input double Order_SL = 0; //逆指値 input bool SoundAlert = false; //決済時のアラート表示フラグ bool KanshiFlg; //ポジション管理中はtrue int Main_ea_ticket[2]; //ポジションのチケット番号保有用(2だと3ポジまで) 5ポジ持たせたい場合は4にすること //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int init() { //フラグ初期化及びメッセージ表示領域の作成 //--- KanshiFlg = false; ObjectCreate("21", OBJ_LABEL, 0, 0, 0); ObjectSet ("21", OBJPROP_CORNER, 3); ObjectSet ("21", OBJPROP_XDISTANCE, 20); ObjectSet ("21", OBJPROP_YDISTANCE, 110); ObjectSet ("21", OBJPROP_XSIZE, 100); ObjectSet ("21", OBJPROP_YSIZE, 10); ObjectSet ("21", OBJPROP_SELECTABLE, false); ObjectCreate("22", OBJ_LABEL, 0, 0, 0); ObjectSet ("22", OBJPROP_CORNER, 3); ObjectSet ("22", OBJPROP_XDISTANCE, 20); ObjectSet ("22", OBJPROP_YDISTANCE, 90); ObjectSet ("22", OBJPROP_XSIZE, 100); ObjectSet ("22", OBJPROP_YSIZE, 10); ObjectSet ("22", OBJPROP_SELECTABLE, false); ObjectCreate("23", OBJ_LABEL, 0, 0, 0); ObjectSet ("23", OBJPROP_CORNER, 3); ObjectSet ("23", OBJPROP_XDISTANCE, 20); ObjectSet ("23", OBJPROP_YDISTANCE, 70); ObjectSet ("23", OBJPROP_XSIZE, 100); ObjectSet ("23", OBJPROP_YSIZE, 10); ObjectSet ("23", OBJPROP_SELECTABLE, false); ObjectCreate("20", OBJ_LABEL, 0, 0, 0); ObjectSet ("20", OBJPROP_CORNER, 3); ObjectSet ("20", OBJPROP_XDISTANCE, 20); ObjectSet ("20", OBJPROP_YDISTANCE, 50); ObjectSet ("20", OBJPROP_XSIZE, 100); ObjectSet ("20", OBJPROP_YSIZE, 10); ObjectSet ("20", OBJPROP_SELECTABLE, false); //--- return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { //メッセージ表示領域とSL、TPラインの削除 //--- ObjectDelete(0,"20"); ObjectDelete(0,"21"); ObjectDelete(0,"22"); ObjectDelete(0,"23"); ObjectDelete(0,"TP"); ObjectDelete(0,"SL"); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ int start() { string Message = "",AltMsg = ""; int OrderKekka = 0; bool rtnFlg = false; if(KanshiFlg == false){ ObjectSetText("20", "未監視", 9, "Arial Rounded MT Bold", clrYellow); //設定されているか確認///////////////////START if(Order_No == 99999){ Message ="注文番号が設定されていません"; ObjectSetText("21", Message, 9, "Arial Rounded MT Bold", clrRed); rtnFlg = true; }else if(Order_No == 0){ Message ="裁量(MagicNumber=0を操作します)"; ObjectSetText("21", Message, 9, "Arial Rounded MT Bold", clrBlue); }else{ Message ="注文番号:"+Order_No; ObjectSetText("21", Message, 9, "Arial Rounded MT Bold", clrBlue); } if(Order_TP == 0){ Message ="TPが設定されていません"; ObjectSetText("22", Message, 9, "Arial Rounded MT Bold", clrRed); rtnFlg = true; }else{ ObjectCreate("TP",OBJ_HLINE,0,0,Order_TP); ObjectSet("TP",OBJPROP_COLOR,clrGray); ObjectSet("TP",OBJPROP_STYLE,STYLE_DOT); ObjectSetText("22", "", 9, "Arial Rounded MT Bold", clrRed); } if(Order_SL == 0){ Message ="SLが設定されていません"; ObjectSetText("23", Message, 9, "Arial Rounded MT Bold", clrRed); rtnFlg = true; }else{ ObjectCreate("SL",OBJ_HLINE,0,0,Order_SL); ObjectSet("SL",OBJPROP_COLOR,clrGray); ObjectSet("SL",OBJPROP_STYLE,STYLE_DOT); ObjectSetText("23", "", 9, "Arial Rounded MT Bold", clrRed); } if(rtnFlg == true){ //設定されていない場合は以降の処理をしない return(0); } //設定されているか確認///////////////////END //設定内容の確認///////////////////START if(funcOrder_Select(0,Order_No,0,Main_ea_ticket) > 0 && OrderCloseTime() == 0){ Message = ""; if(OrderType()==OP_BUY){ if(Bid >= Order_TP){ Message ="TPの設定誤り 現在:"+Bid+ " 設定:"+Order_TP; rtnFlg = true; } if(Ask <= Order_SL){ Message ="SLの設定誤り 現在:"+Ask+ " 設定:"+Order_SL; rtnFlg = true; } //設定がOKの場合はラインを引く if(Message == ""){ ObjectCreate("TP",OBJ_HLINE,0,0,Order_TP); ObjectSet("TP",OBJPROP_COLOR,clrBlue); ObjectSet("TP",OBJPROP_STYLE,STYLE_DOT); ObjectCreate("SL",OBJ_HLINE,0,0,Order_SL); ObjectSet("SL",OBJPROP_COLOR,clrRed); ObjectSet("SL",OBJPROP_STYLE,STYLE_DOT); } } if(OrderType()==OP_SELL){ if(Ask <= Order_TP){ Message ="TPの設定誤り 現在:"+Ask+ " 設定:"+Order_TP; rtnFlg = true; } if(Bid >= Order_SL){ Message ="SLの設定誤り 現在:"+Bid+ " 設定:"+Order_SL; rtnFlg = true; } //設定がOKの場合はラインを引く if(Message == ""){ ObjectCreate("TP",OBJ_HLINE,0,0,Order_TP); ObjectSet("TP",OBJPROP_COLOR,clrBlue); ObjectSet("TP",OBJPROP_STYLE,STYLE_DOT); ObjectCreate("SL",OBJ_HLINE,0,0,Order_SL); ObjectSet("SL",OBJPROP_COLOR,clrRed); ObjectSet("SL",OBJPROP_STYLE,STYLE_DOT); } } if(rtnFlg == true){ //設定ミスの場合は以降の処理をしない ObjectSetText("22", Message, 9, "Arial Rounded MT Bold", clrRed); return(0); } }else{ Message ="注文番号:"+Order_No+"取得失敗"; ObjectSetText("21", Message, 9, "Arial Rounded MT Bold", clrRed); return(0); } //設定内容の確認///////////////////END KanshiFlg = true; //設定値OK及び監視対象のポジションがある } if(KanshiFlg == true){ if(funcOrder_Select(0,Order_No,0,Main_ea_ticket) > 0 && OrderCloseTime() == 0){ //監視中の時は設定の文言を削除する ObjectDelete(0,"21"); ObjectDelete(0,"22"); ObjectDelete(0,"23"); //監視中の文言表示 ObjectSetText("20", "注文番号:["+OrderTicket()+"]を監視中 価格:" + OrderOpenPrice(), 9, "Arial Rounded MT Bold", clrYellow); //決済処理////////////////////////////START if(OrderType()==OP_BUY){ if(Bid >= Order_TP){ OrderKekka = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrBlue); AltMsg = " TP:"; } if(Bid <= Order_SL){ OrderKekka = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrRed); AltMsg = " SL:"; } } if(OrderType()==OP_SELL){ if(Ask <= Order_TP){ OrderKekka = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrBlue); AltMsg = " TP:"; } if(Ask >= Order_SL){ OrderKekka = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrRed); AltMsg = " SL:"; } } if(AltMsg != "" && SoundAlert == true){ Alert(Symbol(),AltMsg + OrderClosePrice()); } //決済場所////////////////////////////END }else{ //監視対象が無くなった場合は、フラグをfalseに戻す KanshiFlg = false; } } return(0); } //+------------------------------------------------------------------+ //|【関数】オーダーセレクト関数 //| //|【引数】 mode 0:最新ポジション選択(ポジション数も取得) 1:1つ前の決済ポジ 2:2つ前の決済ポジ ・・・ //|【引数】 ticket 0:チケット番号を選択したい場合チケット番号を渡すと保持してくれる //|【引数】 マジックナンバー //|【引数(参照)】 mode 0の場合、最新のチケット番号群を更新する //| //|【戻値】ポジション数(過去の場合はあったINDEX) //| int funcOrder_Select(int mode,int ticket,int ea_order_MagicNo,int &o_Ticket[2]){ int total=0,cnt=0,ticket_buf=0; bool OrderKekka =false; total = 0; if(mode==0){ //チケット配列のクリア for(int i = 0;i<3;i++){ o_Ticket[i]=0; } for(cnt = 0; cnt < OrdersTotal(); cnt++){ if(OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES) == true){ if(OrderMagicNumber() == ea_order_MagicNo){ o_Ticket[total] = OrderTicket(); ticket_buf = OrderTicket(); total = total+1; } } } //件数があった場合、最新のポジションを選択する if(ticket == 0 && ticket_buf !=0){ OrderKekka = OrderSelect(ticket_buf,SELECT_BY_TICKET,MODE_TRADES); } //チケット番号が渡されている場合戻す if(ticket != 0){ OrderKekka = OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES); if(OrderKekka == false){ total = 0; } } }else{ //取引履歴検索 for(cnt = OrdersHistoryTotal(); cnt > 0; cnt--){ if(OrderSelect(cnt-1,SELECT_BY_POS,MODE_HISTORY) == true){ if(OrderMagicNumber() == ea_order_MagicNo){ total = total+1; if(mode <= total){ break; } } } } } return(total); }
“AutoClose.ex4” をダウンロード AutoClose.ex4 – 33 回のダウンロード – 13 KB
ソース概要
主な作りこみ要素としては
- チャート上へのメッセージ表示
- チャート上へのライン表示
- ポジション検索機能
- アラート機能
と、あとはEAを削除した際にメッセージやラインが残らないようにOnDeinit()にも処理を入れ、コメントも多めにととにかく丁寧に作りました。
今回のソースをベースに新規注文処理とかを入れてあげると決まった所で新規注文と決済をどんどん繰り返すEAとかも作れそうですね!
funcOrder_Select()関数について
今回自作したfuncOrder_Select()関数ですが結構汎用的に使えます。マジックナンバーを限定したポジションの取得から複数ポジションの取得、過去履歴の取得、注文番号を指定、戻り値にポジション数を返すとおおよそOrderSelect()関数でやりたいことを詰め込んだつもりです。
【引数】
- mode 0:最新ポジション選択(ポジション数も取得) 1:1つ前の決済ポジ 2:2つ前の決済ポジ ・・・
- ticket 0:最新ポジション選択 0以外:チケット番号のポジションを選択
- MagicNumber:マジックナンバーを選択
- チケット番号配列(参照渡し) 第一引数のmode:0だった場合ポジション分のチケット番号がセットされる
使い方
基本的には、裁量トレードする時間足(5分足等)でEAを実行します。時間足は別にいくつでも大丈夫です。※随時処理します
設定はこんな感じでOrder_Noは0(裁量)にしてTPとSLはチャートを見ながらあらかじめポジションを取る前に設定しておきます。

こうすることでグレーのラインが表示されるのでTPとSLの位置が問題無い事が確認できます。その後は、裁量でエントリーして見守るだけでOKです。ポジションごとにSLやTPを設定しなくても大丈夫です。

さいごに
以上が、『指定したポジションを自動で決済するだけのEA』です。
今回のサンプルソースは稼げるというより便利とか小ネタ系で簡単なつくりとなりました。ただ、初心者向けの内容となっていますのでこのソースを色々改造しながらMT4で遊んでみても面白いと思います。
※ EAのサンプルソースを一覧表にまとめました
※ オススメ記事(EAが使える国内FX業者の一覧)
※ 1からEAの作り方を学びたい人はこちら
コメント