せっかくMT4(MetaTrader4)を利用するなら、オリジナルのEA(Expert Advisor)やインジケーターを自作してみませんか?
今回は、MQL4言語入門として窓埋めEAの自作方法を解説します。
もちろん、いつもどおりの超簡単な自作方法です。すでに出来上がっているサンプルEAのソースコードの一部を書き換えるだけですから。
最後あたりでEAの完成品を無料ダウンロードできます。ぜひ読んでいってください。
窓埋めとは?
FXでは、土日に市場が閉まることから、前週金曜の終値と月曜朝の始値にギャップ(窓)が開くことがあります。
そして、この窓はだいたい短時間で埋まるのが相場のパターンなので、この窓を埋めようとする相場のパターンを利用してトレードする手法が窓埋めです。
つまり、月曜の朝、市場オープン時にチャートを確認し、もし窓が開いていれば、窓を埋める方向にロングまたはショートの注文を入れるのです。
「窓開け」と呼ばれることもあります。
窓埋めとMT4
窓埋めとMT4のシステムトレードは相性がいいです。
まず、窓埋めは売り買いのタイミングがハッキリしているので、簡単にプログラムが組めます。
また、私たちには仕事や学校などの生活があるので、毎週毎週、月曜朝にチャートの前で待機しておくというのはキツイです。
その点、MT4なら、日曜の晩にPCのMT4を起ち上げておくだけでOKです。あとはMT4が自動売買してくれるので、私たちは普段どおりに生活できます。
あと、相場のパターンとは言っても、窓が開けば即エントリーする戦略だけで勝ち続けることは、実際のところ難しいです(バックテストで確認済み)。
というのも、窓があまりに小さい場合は投資効率が悪すぎるし、窓があまりに大きい場合は埋まる可能性が低いです。また、窓を途中までしか埋めずに反転することもあります。
やはり、新規注文(エントリー)や決裁(エグジット)に何か工夫が必要ですが、こういうときにMT4は便利です。
自作EAなら、エントリー時にだまし対策を施すことも、適切な決裁タイミングを見逃さないよう複数の決済ルールを組み合わせることも自由自在です。
さらに、それら工夫の有用性をバックテストで確認できます。
窓埋めEA『GapHunter.mq4』の内容
EAの内容は、以下のとおりです。
せっかく自作するのですから、単純な窓埋めEAではなく、エントリーやエグジットに私なりの工夫を施しています(^^)v
- 基本は、月曜オープン時に 前週金曜の終値>月曜朝の始値 なら新規買い注文を入れ、逆なら新規売り注文を入れる。
- ただし、窓が大きすぎたり小さすぎればエントリーを見送る。
- 月曜オープン直後は窓を拡げる方向に動くことが多いので、さらに利ザヤ(利益)を稼ぐ。すなわち、エントリー条件を満たす窓が開いた場合でも、すぐにエントリーするのではなく、さらに数pips拡がるのを待つ。
- 決裁タイミングを逃さぬよう、3種類の撤退ルールを用意した。すなわち、逆指値(ストップロス)、トレーリングストップ、エントリー後に一定時間経過したら決裁する時間ストップを組み合わせた。
MetaEditor の起動
それでは、サンプルコード「MACD Sample.mq4」のソースコードを書き換えて、窓埋めEAを作っていきます。
MT4の「メタクォーツ言語エディタ」をクリックします。
MeTaEditorが立ち上がったら、画面左側の「Navigater」内のツリーから「Experts」をダブルクリックします。
「Experts」のツリーから「MACD Sample.mq4」をダブルクリックすると、ソースコードが開きます。
オリジナルEA『GapHunter.mq4』の自作
最初に、名前をつけてファイルを保存します。
「MACD Sample.mq4」が開いている状態で、「File」→「Save As…」 をクリックします。
ファイル名を「GapHunter.mq4」と打ち込んで保存します。
それでは、いよいよソースコードを書き換えていきます。
パラメーターの変更
カーソルを10行目に持って行きます。
ここでは、売買ロットやテクニカルインジケーターに関するパラメーターが記述されています。これらの数値は、MT4上でユーザーが自由に変更できます。
【変更前】
input double TakeProfit =50; input double Lots =0.1; input double TrailingStop =30; input double MACDOpenLevel =3; input double MACDCloseLevel=2; input int MATrendPeriod =26;
【変更後】
input double Lots =0.1; input double TrailingStop =500; input double StopLoss =400; input double MinGap =70; input double MaxGap =1200; input double OverGap =40; input int ExitBar =8; double StopBar;
TrailingStopの値を変更し、不要なパラメーターを削除しました。
新たにストップロス(逆指値)を設定(変数として宣言)し、初期値を400ポイントにする旨を記述しました。
MinGapはエントリーする窓の最小値で、初期値は70ポイントです。
MaxGapはエントリーする窓の最大値で、初期値は1200ポイントです。
上でも書きましたが、窓が小さすぎる場合や大きすぎる場合にはエントリーしません。
ExitBarは時間ストップのパラメーターで、初期値では窓が埋まっていなくても8時間経過で決裁します。
OverGapは窓の大きさ+αの利ザヤで、初期値は40ポイントです。
テクニカルインジケーター変数の宣言の変更
カーソルを下に移動させます。
ここでは、テクニカルインジケーターの変数の宣言が記述されています。
【変更前】
void OnTick(void)
{
double MacdCurrent,MacdPrevious;
double SignalCurrent,SignalPrevious;
double MaCurrent,MaPrevious;
int cnt,ticket,total;
【変更後】
void OnTick(void)
{
double LastDayClose,NewDayOpen,UpGap,DnGap,EntryGap;
int cnt,ticket,total;
MACDと移動平均線の変数の宣言を削除し、新たに窓埋めの変数の宣言を記述しました。
最低利食い幅の記述の削除
カーソルを下に移動させます。
指値(TakeProfit)が10ポイント以下の場合はエントリーしない旨の記述を削除しました。
別にエントリーする窓の最小値を定めているので不要だからです。
if(TakeProfit<10)
{
Print("TakeProfit less than 10");
return;
}
テクニカルインジケーター関数の変更
カーソルを下に移動させます。
ここでは、先ほど宣言した変数に、テクニカルインジケーター関数の値を代入する式が記述されています。
【変更前】
//--- to simplify the coding and speed up access data are put into internal variables
MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
【変更後】
//--- to simplify the coding and speed up access data are put into internal variables
if(DayOfWeek()==1 && Hour()==0)
{
LastDayClose = iClose(NULL,PERIOD_H1,1);
NewDayOpen = iOpen(NULL,PERIOD_H1,0);
}
UpGap = NewDayOpen-LastDayClose;
DnGap = LastDayClose-NewDayOpen;
EntryGap = (MinGap+OverGap)*Point;
MACDと移動平均線の式を削除し、代わりに窓埋めの式を記述しました。
まず、月曜(DayOfWeek()==1)の朝のオープン時(Hour()==0)であることを確認しています。
LastDayCloseには、前週の金曜の終値が入ります。
NewDayOpenには、月曜朝の始値が入ります。
UpGapには、月曜始値>金曜終値 である場合の窓のサイズ(ポイント)が入ります。
DnGapには、金曜終値>月曜始値 である場合の窓のサイズ(ポイント)が入ります。
EntryGapには、最低でも確保すべき利ザヤ(ポイント)が入ります。
買い条件と買い注文の変更
カーソルを下に移動させます。
ここでは、買い条件と買い注文について記述しています。
【変更前】
//--- check for long position (BUY) possibility if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) { ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened :",OrderOpenPrice()); }
【変更後】
//--- check for long position (BUY) possibility if(UpGap<0 && DnGap>MinGap*Point && DnGap<MaxGap*Point) { if(LastDayClose>iHigh(NULL,PERIOD_H1,0) && Ask<(LastDayClose-EntryGap)) { ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Ask-StopLoss*Point,LastDayClose,"gap hunter",16384,0,Green); if(ticket>0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened :",OrderOpenPrice()); StopBar=iBars(NULL,PERIOD_H1); }
買い条件をすべて書き換えます。
一つ目のif文で、金曜終値>月曜始値 であり、かつ、窓のサイズ条件(最小値と最大値)を満たしているか確認しています。
二つ目のif文で、まだ窓を埋めておらず、かつ、最低利ザヤを確保できるかを確認しています。
これらの条件を満たせば買い注文命令(OrderSend)を出します。このとき、指値(LastDayClose)と逆指値(Ask-StopLoss*Point)も指定しています。
StopBarには、現在のバー数(iBars)が入ります。決裁条件で使います。
売り条件と売り注文の変更
カーソルを下に移動させます。
ここでは、売り条件と売り注文について記述しています。
【変更前】
//--- check for short position (SELL) possibility if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) { ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red); if(ticket > 0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened :",OrderOpenPrice()); }
【変更後】
//--- check for short position (SELL) possibility if(DnGap<0 && UpGap>MinGap*Point && UpGap<MaxGap*Point) { if(LastDayClose<iLow(NULL,PERIOD_H1,0) && Bid>(LastDayClose+EntryGap)) { ticket = OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Bid+StopLoss*Point,LastDayClose,"",16384,0,Red); if(ticket > 0) { if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened :",OrderOpenPrice()); StopBar=iBars(NULL,PERIOD_H1); }
売り条件をすべて書き換えます。
一つ目のif文で、月曜始値>金曜終値 であり、かつ、窓のサイズ条件(最小値と最大値)を満たしているか確認しています。
二つ目のif文で、まだ窓を埋めておらず、かつ、最低利ザヤを確保できるかを確認しています。
これらの条件を満たせば売り注文命令(OrderSend)を出します。このとき、指値(LastDayClose)と逆指値(Bid+StopLoss*Point)も指定しています。
StopBarには、現在のバー数(iBars)が入ります。決裁条件で使います。
買い注文の決済条件の変更
カーソルを下に移動させます。
ここでは、買い注文の決済条件について記述しています。
【変更前】
//--- long position is opened
if(OrderType()==OP_BUY)
{
//--- should it be closed?
if(MacdCurrent>0 && MacdCurrentSignalPrevious &&
MacdCurrent>(MACDCloseLevel*Point))
{
【変更後】
//--- long position is opened
if(OrderType()==OP_BUY)
{
//--- should it be closed?
if(StopBar+ExitBar<iBars(NULL,PERIOD_H1))
{
時間ストップの決済条件に書き換えます。
現在のバー(iBars)が時間ストップ(初期設定ではエントリー後8時間)に達しているかを確認しています。
売り注文の決済条件の変更
カーソルを下に移動させます。
ここでは、売り注文の決済条件について記述しています。
【変更前】
else // go to short position
{
//--- should it be closed?
if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
MacdPrevious(MACDCloseLevel*Point))
{
【変更後】
else // go to short position
{
//--- should it be closed?
if(StopBar+ExitBar<iBars(NULL,PERIOD_H1))
{
時間ストップの決済条件に書き換えます。
現在のバー(iBars)が時間ストップ(初期設定ではエントリー後8時間)に達しているかを確認しています。
ソースコードの書き換えは以上です。
一応、記事の最後あたりに、完成品をダウンロードできるよう置いておきます。
ソースコードをコンパイルする
記述し終わったら、「Compile」をクリックします。
記述ミスがなければ、Destrictionに、「0 error(s), 0 warning(s)」と表示されます。
コンパイルとは、プログラムのソースコードをコンピューターが実行可能な機械語に翻訳することです。
ソースコードに記述ミスがあれば、エラーとなります。
エラーがでた場合は、記述を修正して再びコンパイルしましょう。
以下は、よくあるエラーの例です。気を付けましょう。
- 全角で記述している(ソースコードはすべて半角で記述します)
- 変数の型(”int”や”double”など)が違う
- カッコ(” { ” や ” } “)が足りない(多い)
- ” ; ” が抜けている
バックテスト
せっかくオリジナルEAが完成したのですから、バックテストしてみましょう。
バックテストのやり方は別記事にまとめています。
実際にバックテストを行った結果を別記事にまとめています。
なお、窓埋めEAは、移動平均線などでテクニカル分析してるわけではないので、バックテストは5分足でやっても日足でやっても結果は同じ(はず)です。
まとめ|自作EA無料配布
今回は、MQL4言語入門として、窓埋めEAの超簡単な自作方法を解説しました。
もちろん、すでに出来上がっているサンプルEAのソースコードの一部を書き換えるだけの、いつもどおりの超簡単な自作方法です。
思った以上に簡単だったのではないでしょうか?
ぜひあなたの勝てるEA作りの参考にしてください。
完成品(Gap-Hunter.zip)はこちらからダウンロードできます。
・本EAは、あくまでMQL4言語の学習用に無料配布するものです。なので、再配布はやめてください。
・もし、当サイトを宣伝して頂けたり、下のバナーから『XMTrading』の口座を開設していただけると、みなさんに役立つサイト作りをもっともっと頑張れます(*^▽^*)