MT4のEA作りの書籍はたくさん出ていたり、ネットで検索するとサンプルのソースコードはたくさん見つかるのですが、バックテストではなく、実トレードで実行するとどうも動かない事が多い。
そこで、僕自身が、MT4のEA作りであれこれ実践して、実際に動いた売買部分だけのベースソースコードを公開したいと思います。
売買のMQL4のベースソース
僕が実際にベースで使ってるソースです。これに、あれこれ条件加えたりしてます。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
#property copyright "Copyright 2020,Yano" #property link "https://www.fx-doremi.com/" #property version "1.00" #property strict #include <stdlib.mqh> #define MAGIC 20200609 extern double Lots = 0.02; //ロット extern int Slippage = 30; //スリッページ extern double Profitrate = 20; //Take Profit 値幅(pips) extern double SLrate = 20; //Stop Loss 損切り(pips) //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- //売買の処理はここで書く //ロングの際の書き方 //Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC); //ショートの際の書き方 //Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC); } //+------------------------------------------------------------------+ //| ロング //| OP_BUYのエントリー。リトライあり //| 引数: my_lot = ロット //| my_slipage = スリッページ //| my_sl = 損切り //| my_tp = 利益 //+------------------------------------------------------------------+ void Org_Long(double my_lot,int my_slipage , double my_sl, double my_tp, int my_magic){ //ticket no int ticket_no=0; int errorcode=0; // エラーコード double losscut_normalize=0; double profit_normalize=0; double losscut_rate=0; double profit_rate=0; // ロスカット価格 losscut_rate = Ask - ( 10 * Point() * my_sl); // 決済価格 profit_rate = Ask + ( 10 * Point() * my_tp); //正規化 losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS))); profit_normalize = NormalizeDouble(profit_rate,int(MarketInfo(Symbol(),MODE_DIGITS))); //ロングエントリー処理 ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,losscut_normalize,profit_normalize,"Buy order",my_magic,0,clrBlue); printf("OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize); if(ticket_no < 0){ errorcode = GetLastError(); // エラーコード取得 printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode)); //再設定 losscut_rate = Ask - ( 10 * Point() * my_sl); profit_rate = Ask + ( 10 * Point() * my_tp); losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS))); profit_normalize = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS))); //オーダー送信と同時に損切り、利益設定エラー対策 ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,0,0,"Buy order",my_magic,0,clrBlue); printf("Resend OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize); //オーダー修正 LimitStop_Set(ticket_no,OP_BUY,clrBlue); }else { printf("Send Done. Ticket NO = %d",ticket_no); } } //+------------------------------------------------------------------+ //| ショート //| OP_SELLのエントリー。リトライあり //| 引数: my_lot = ロット //| my_slipage = スリッページ //| my_sl = 損切り //| my_tp = 利益 //+------------------------------------------------------------------+ void Org_Short(double my_lot,int my_slipage , double my_sl, double my_tp, int my_magic){ //ticket no int ticket_no=0; int errorcode=0; // エラーコード double losscut_normalize=0; double profit_normalize=0; double losscut_rate=0; double profit_rate=0; // ロスカット価格 losscut_rate = Bid + ( 10 * Point() * my_sl); // 決済価格 profit_rate = Bid - ( 10 * Point() * my_tp); //正規化 losscut_normalize = NormalizeDouble(losscut_rate,Digits()); profit_normalize = NormalizeDouble(profit_rate,Digits()); //shortエントリー処理 ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,losscut_normalize,profit_normalize,"Sell order",my_magic,0,clrRed); printf("OrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize); //エラー? if(ticket_no < 0){ errorcode = GetLastError(); // エラーコード取得 printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode)); // 再設定 losscut_rate = Bid + ( 10 * Point() * my_sl); profit_rate = Bid - ( 10 * Point() * my_tp); losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS))); profit_normalize = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS))); //オーダー送信と同時に損切り、利益設定エラー対策 ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,0,0,"Sell order",my_magic,0,clrRed); printf("Resend sOrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize); //オーダー修正 LimitStop_Set(ticket_no,OP_SELL,clrRed); }else { printf("Send Done. Ticket NO = %d",ticket_no); } } //+------------------------------------------------------------------+ //| エントリー中のポジションのリミット・ストップを変更 //| 引数 int in_ticket_no = Ticket no //| double my_sl = Stopp Loss //| double my_tp = Take Profit //+------------------------------------------------------------------+ // void LimitStop_Set( int in_ticket_no, int buysell_type , color mycolor) { int modify_resend_num; // 変更試行回数 bool modify_ret; // 変更判定 int errorcode; bool selbool; double limit_rate,stop_rate; int my_ticket_no; // オーダー中のチケット選択(チケットNo指定) selbool = OrderSelect(in_ticket_no, SELECT_BY_TICKET); if (buysell_type == OP_BUY){ limit_rate = OrderOpenPrice() + ( 10 * Point() * Profitrate); stop_rate = OrderOpenPrice() - ( 10 * Point() * SLrate); }else{ limit_rate = OrderOpenPrice() - ( 10 * Point() * Profitrate); stop_rate = OrderOpenPrice() + ( 10 * Point() * SLrate); } limit_rate = NormalizeDouble(limit_rate , Digits() ); // リミット価格 を正規化 stop_rate = NormalizeDouble(stop_rate , Digits() ); // ストップロス価格を正規化 my_ticket_no = OrderTicket(); for( modify_resend_num = 0; modify_resend_num < 30; modify_resend_num++ ) { modify_ret = OrderModify( my_ticket_no, // チケットNo OrderOpenPrice(), // 注文価格 stop_rate, // ストップロス価格 limit_rate, // リミット価格 OrderExpiration(), // 有効期限 mycolor // 色 ); printf("OrderModify ticket_no:%d , sl=%f , tp=%f",my_ticket_no , stop_rate,limit_rate); if ( modify_ret == false ) { // 注文変更拒否 Sleep(300); // 300msec待ち errorcode = GetLastError(); // エラーコード取得 printf( "[%d]Modify Error! error_code:%d ,detail:%s ", modify_resend_num+1, errorcode , ErrorDescription(errorcode)); } else { // 決済注文約定 Print("Done. Ticket NO=",in_ticket_no); break; } } } //+------------------------------------------------------------------+ //| ポジション決済 | //+------------------------------------------------------------------+ void ClosePositions_BUY(int my_magic){ int i; int my_ticket_no; double my_lots; double my_price = NormalizeDouble(Ask,int(MarketInfo(Symbol(),MODE_DIGITS))); bool chk; int errorcode; for(i=0;i<OrdersTotal();i++){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false){ break; } if(OrderMagicNumber() != my_magic || OrderSymbol() != Symbol()){ continue; } my_ticket_no = OrderTicket(); my_lots = OrderLots(); //買いポジションのチェック if(OrderType() == OP_BUY){ chk = OrderClose(my_ticket_no,my_lots,my_price,Slippage,White); printf("OrderClose ret=%d , ticket_no=%d , lots=%f , BUY price=%f",chk,my_ticket_no,my_lots,my_price); if(chk == False){ errorcode = GetLastError(); // エラーコード取得 printf("OrderClose Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode)); }else{ printf("OrderClose Done!"); } break; } // ループを抜ける break; } } void ClosePositions_SELL(int my_magic){ int i; int my_ticket_no; double my_lots; double my_price = NormalizeDouble(Ask,int(MarketInfo(Symbol(),MODE_DIGITS))); bool chk; int errorcode; for(i=0;i<OrdersTotal();i++){ if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false){ break; } if(OrderMagicNumber() != my_magic || OrderSymbol() != Symbol()){ continue; } my_ticket_no = OrderTicket(); my_lots = OrderLots(); //売りポジションのチェック if(OrderType() == OP_SELL){ chk = OrderClose(my_ticket_no,my_lots,my_price,Slippage,White); printf("OrderClose ret=%d , ticket_no=%d , lots=%f , SELL price=%f",chk,my_ticket_no,my_lots,my_price); if(chk == False){ errorcode = GetLastError(); // エラーコード取得 printf("OrderClose Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode)); }else{ printf("OrderClose Done!"); } break; } // ループを抜ける break; } } |
解説
ロット、スリッページ、利益、損切りをパラメータで設定にするため、extern宣言。
MT4はポイント計算なのですが、利益や損切りは分かりやすくpipsで設定出来るようにしました。(実際はOrg_Long、Org_Short関数内でポイントをpips換算してます)
1 2 3 4 |
extern double Lots = 0.02; //ロット extern int Slippage = 30; //スリッページ extern double Profitrate = 20; //Take Profit 利益(pips) extern double SLrate = 20; //Stop Loss 損切り(pips) |
スリッページは低くしすぎるとエラーになる
スリッページは低くしすぎると、取引所側からエラーが返ってきます。これについては、こちらの記事にまとめました。
利益値幅、損切り値幅も低くしすぎるとエラーになる
利益や損切りについても同様です。以下の記事に書きましたが、XMだと4pips以上は設定しないとエラーになります(それでもエラーになる場合は+1〜+2くらいにすると動くと思います)。
売買はオリジナル関数を用意
売買時に簡潔に書きたかったので、売買時は直接OrderSendを書かずに、オリジナル関数内で処理しました。この中で、小数点の桁合わせや、エラー時のリトライなど、あれこれやってます。
ロング(買い)
使い方はめちゃ簡単にしました。引数に必要な情報を入れるだけ。
1 2 3 4 5 6 |
//引数1:Lots = ロット //引数2:Slippage = スリッページ //引数3:SLrate = 損切り(pips) //引数4:Profitrate = 利益(pips) //引数5:MAGIC = マジックナンバー Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC); |
ショート(売り)
1 2 3 4 5 6 |
//引数1:Lots = ロット //引数2:Slippage = スリッページ //引数3:SLrate = 損切り(pips) //引数4:Profitrate = 利益(pips) //引数5:MAGIC = マジックナンバー Org_Short(Lots,Slippage,SLrate,Profitrate,MAGIC); |
OrderSend後のエラー処理について
エラーが取引所から返ってきた際のリトライ処理は以下のブログの処理を参考にさせて頂きました。それを改造した感じ。
オーダーのクローズ
オーダーのクローズもオリジナル関数を用意しました。基本はOrg_LongやOrg_Short関数で利益や損切りタイミングまで待ちますが、クローズタイミングを自分でしっかり決める場合は以下を使ってます。
引数はマジックナンバー。
1 2 3 4 5 |
//ロングのエントリーをクローズ ClosePositions_BUY(MAGIC); //ショートのエントリーをクローズ ClosePositions_SELL(MAGIC); |
売買の基本ルーチンは以上です。
まとめ
あとは、OnTick()で、エントリータイミングをどう書くかですね。この中で、ボリンジャーバンドみたり、各種テクニカルの数値を見て、エントリータイミングを判断する感じです。
まだまだ研究中
ご質問はコメント欄からお願いします
コメント一覧 (4件)
【MT4】MQL4でEAを作るベースとなるソースコードの公開はどんなEAですか。
コメントありがとうございます。このページに公開している売買のベースコードだけです。
46 Org_Long?
Yes.Org_Long is a wrapper function. Look at line 58