ここでは、複数のシグナルやエントリーフィルターを搭載して、それらのどれを使用するかを選択できるEAを作成する方法を紹介します。
今回解説するEAのコード
EAコード全体
今回のEAコードがこちら
#property strict // Main Setting extern double Lots = 0.01; extern double StopLoss = 50; extern double TakeProfit = 100; extern double Slippage = 1; extern string PosComment = "EA"; extern int MagicNumber = 20191208; // Signal Setting //Ma extern bool UseMaCrossSignal = true; extern int MaShortPeriod = 20; extern int MaLongPeriod = 50; //Macd extern bool UseMacdCrossSignal = false; extern int MacdFastPeriod = 12; extern int MacdSlowPeriod = 26; extern int MacdSignalPeriod = 9; // Entry Filter Setting //Ma extern bool UseMaTrendFilter = true; extern int MaTrendPeriod = 100; //ADX extern bool UseAdxFilter = true; extern int AdxPeriod = 14; extern double AdxFilterLevel = 25.0; //ATR extern bool UseAtrFilter = true; extern int AtrPeriod = 14; extern double AtrFilterPips = 10.0; //Exit Setting extern bool ExitReverseSign = true; // グローバル変数 double g_point; int g_entry_bar_buy; int g_entry_bar_sell; //+------------------------------------------------------------------+ int OnInit() { // Parameter setting error if(UseMaCrossSignal == false && UseMacdCrossSignal == false) //シグナルが1つも使われていない場合 { Alert("Signal setting error."); // エラーアラートを出して return(INIT_FAILED); // EAを終了する } // パラメーターをPips入力にする為の処理 g_point = Point; if (Digits % 2 == 1) { g_point *= 10; Slippage *= 10; } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ void OnTick() { // Positions Check ::::::::::::::::::::::::::::::::::::::::::::::::: int pos_ticket_buy = 0; int pos_ticket_sell = 0; for (int i=0 ; i<OrdersTotal() ;i++) { if (OrderSelect(i, SELECT_BY_POS) == false) return; if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; if (OrderType() == OP_BUY) pos_ticket_buy = OrderTicket(); if (OrderType() == OP_SELL) pos_ticket_sell = OrderTicket(); } // Entry Signal :::::::::::::::::::::::::::::::::::::::::::::::::::: // MA int ma_cross_sign = 0; if(UseMaCrossSignal == true) { double ma_s_1 = iMA(NULL, 0, MaShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double ma_s_2 = iMA(NULL, 0, MaShortPeriod, 0, MODE_SMA, PRICE_CLOSE, 2); double ma_l_1 = iMA(NULL, 0, MaLongPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double ma_l_2 = iMA(NULL, 0, MaLongPeriod, 0, MODE_SMA, PRICE_CLOSE, 2); if(ma_l_2 >= ma_s_2 && ma_l_1 < ma_s_1) ma_cross_sign = 1; if(ma_l_2 <= ma_s_2 && ma_l_1 > ma_s_1) ma_cross_sign = -1; } // MACD int macd_sign = 0; if(UseMacdCrossSignal == true) { double macd_1 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_MAIN, 1); double macd_2 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_MAIN, 2); double macd_sig_1 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_SIGNAL, 1); double macd_sig_2 = iMACD(NULL, 0, MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod, PRICE_CLOSE, MODE_SIGNAL, 2); if(macd_sig_2 >= macd_2 && macd_sig_1 < macd_1) macd_sign = 1; if(macd_sig_2 <= macd_2 && macd_sig_1 > macd_1) macd_sign = -1; } // Entry Filter ::::::::::::::::::::::::::::::::::::::::::::::::::::: //MA int ma_filter = 0; if(UseMaTrendFilter == true) { double ma_trend_1 = iMA(NULL, 0, MaTrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double ma_trend_2=iMA(NULL, 0, MaTrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 2); if(ma_trend_2 < ma_trend_1) ma_filter=1; if(ma_trend_2 > ma_trend_1) ma_filter=-1; } // ADX bool adx_filter = false; if(UseAdxFilter == true) { double adx_1 = iADX(NULL, 0, AdxPeriod, PRICE_CLOSE, MODE_MAIN, 1); if(adx_1 >= AdxFilterLevel) adx_filter = true; } // ATR bool atr_filter = false; if(UseAtrFilter == true) { double atr1=iATR(NULL, 0, AtrPeriod, 1); if(atr1 >= AtrFilterPips * g_point) atr_filter = true; } // Entry Sign ****************************************************** int sign = 0; if((UseMaCrossSignal == false || ma_cross_sign == 1) && (UseMacdCrossSignal == false || macd_sign == 1) && (UseMaTrendFilter == false || ma_filter == 1) && (UseAdxFilter == false || adx_filter == true) && (UseAtrFilter == false || atr_filter == true)) sign = 1; if((UseMaCrossSignal == false || ma_cross_sign == -1) && (UseMacdCrossSignal == false || macd_sign == -1) && (UseMaTrendFilter == false || ma_filter == -1) && (UseAdxFilter == false || adx_filter == true) && (UseAtrFilter == false || atr_filter == true)) sign = -1; //Exit Sign::::::::::::::::::::::::::::::::::::::::::::::::::::::::: int exit_sign = 0; if(ExitReverseSign == true) { if((UseMaCrossSignal == false || ma_cross_sign == 1) && (UseMacdCrossSignal == false || macd_sign == 1)) exit_sign = 1; if((UseMaCrossSignal == false || ma_cross_sign == -1) && (UseMacdCrossSignal == false || macd_sign == -1)) exit_sign = -1; } //Exit:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: if (pos_ticket_buy > 0 && exit_sign == -1) { if (OrderSelect(pos_ticket_buy, SELECT_BY_TICKET) == true) { if (OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), (int)Slippage, clrYellow) == true) pos_ticket_buy = 0; } } if (pos_ticket_sell > 0 && exit_sign == 1) { if (OrderSelect(pos_ticket_sell, SELECT_BY_TICKET) == true) { if (OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), (int)Slippage, clrYellow) == true) pos_ticket_sell = 0; } } //Entry::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: int ticket; double sl = 0, tp = 0; if (pos_ticket_buy == 0 && g_entry_bar_buy != Bars && sign == 1) { if (StopLoss > 0) sl = Ask - StopLoss * g_point; if (TakeProfit > 0) tp = Ask + TakeProfit * g_point; ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, (int)Slippage, sl, tp, PosComment, MagicNumber, 0, clrBlue); if (ticket > 0) g_entry_bar_buy = Bars; } if (pos_ticket_sell == 0 && g_entry_bar_sell != Bars && sign == -1) { if (StopLoss > 0) sl = Bid + StopLoss * g_point; if (TakeProfit > 0) tp = Bid - TakeProfit * g_point; ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, (int)Slippage, sl, tp, PosComment, MagicNumber, 0, clrRed); if (ticket > 0) g_entry_bar_buy = Bars; } }
EAファイルをダウンロード
次のリンクから、この記事で解説するサンプルEA【Sample_SwitchSignal_2019.mq4】がダウンロードできます。
新MQL4リメイク版EA【Sample_SwitchSignal_2019.mq4】をダウンロード
次のリンクは、旧MQL4のサンプルEAです。
旧MQL4のEA【Sample_SwitchSignal.zip】をダウンロード
EAコード解説
今回のEAコードの重要な部分を解説するぞい
パラメーター抜粋
次のように、2つのエントリーシグナルと3つのエントリーフィルターをbool(真偽)型のパラメーターにして、true:使用する, false:使用しない を選択できるようにしています。
extern bool UseMaCrossSignal = true; // MAのクロスによるシグナル extern bool UseMacdCrossSignal = false; // MACDのクロスによるシグナル extern bool UseMaTrendFilter = true; // MAの向きによるフィルター extern bool UseAdxFilter = true; // ADXの値によるフィルター extern bool UseAtrFilter = true; // ATRの値によるフィルター
OnInit()関数内でパラメーター設定を制限
OnInit()関数内で次のようにして、エントリーシグナルが一つも使用されない場合は、エラーアラートを出してEA稼働を終了するようにしています。
if(UseMaCrossSignal == false && UseMacdCrossSignal == false) //シグナルが1つも使われていない場合 { Alert("Signal setting error."); // エラーアラートを出して return(INIT_FAILED); // EAを終了する }
OnTick()関数内の構成
OnTick()関数内は次の順で書いています。
- 保有ポジション確認
- エントリーシグナル判定
- エントリーフィルター判定
- エントリーサイン判定
- エグジットサイン判定
- エグジット処理
- エントリー処理
エントリーサイン判定
エントリーサイン判定を次のように、パラメーターで設定した「使用する or 使用しない」が反映されるようにしています。
int sign = 0; if((UseMaCrossSignal == false || ma_cross_sign == 1) && (UseMacdCrossSignal == false || macd_sign == 1) && (UseMaTrendFilter == false || ma_filter == 1) && (UseAdxFilter == false || adx_filter == true) && (UseAtrFilter == false || atr_filter == true)) sign = 1; if((UseMaCrossSignal == false || ma_cross_sign == -1) && (UseMacdCrossSignal == false || macd_sign == -1) && (UseMaTrendFilter == false || ma_filter == -1) && (UseAdxFilter == false || adx_filter == true) && (UseAtrFilter == false || atr_filter == true)) sign = -1;
もし、 UseMaCrossSignal を使用しないまたは、ma_cross_sign が買いシグナル かつ UseMacdCrossSignal を使用しないまたは、macd_sign が買いシグナル かつ UseMaTrendFilter を使用しないまたは、ma_filter が買いOK かつ UseAdxFilter を使用しないまたは、adx_filter がエントリーOK かつ UseAtrFilter を使用しないまたは、atr_filter がエントリーOK の場合、sign を買いサインにする (以下、売りサインの場合も同様)
あとがき
今回のEAコードの書き方は、色々なシグナルやフィルターを試したいときに便利ですので是非カスタマイズして使ってみてください。
では、今回はこのへんで^^
慶次さん、こんにちは。
どうもありがとうございます。
勉強になりました。
この書き方は時間フィルター等いろいろな場面で使える表現方法ですね。
早速、自作EAの修正を行いました。
プログラムがぐんと短くできました。
それでは、今後ともよろしくお願いします。
よっし~さん
こんにちわ^^
私もいろいろな分岐の書き方をやってみましたが、
この書き方が一番修正等が楽です^^;
また、シグナルとフィルタを分けて考えることでエントリシグナルやエグジットシグナルの作成がやりやすくなりますね!
慶次さん。
こんばんは!
いつも、お世話になっております。
私も、シグナル、フィルター、トレイル、クローズ毎に
個々に選択できるように書いてます。
最近のODLでは、成り行き注文時に、初期SL値が設定不可に
なってしまった為、逆指値注文を行うようにしていたので、
オーダー時の仕掛値の設定方法も、複数設定できるように、選択式にしています。
ところで。
MT4でバックテストを行っている際に、
テスト期間が長いと、後半になるにつれて、非常に遅くなることは
ありませんか。
単に、テスト期間を分割して行えばいいのかと思ったのですが、
もし、なにか御存じでしたらと思いまして。
マーサーさん
こんにちわ!
MT4のバックテストでは、
データのVolume(ティック数)によってバックテストのティック数が決められているようです。
Volumeが多いところでは、その分次の足に進むのが遅くなるようです。
また、EA内に繰り返し文で過去すべてのデータから計算されるような部分がありますと、
期間が長ければ長いほど、後の方は処理に時間がかかってしまいます^^;
いつもコメント、ありがとうございます。
確かに、volume(ティック数)も関連しているようですが、
やっぱり後半の方が、遅いような感じです。。
変なこと言って、失礼いたしました。。 ^^;
最近は、以前に作成したR倍数の自動計算するシステムを
改善しまして、複数のシステム・通貨ペア毎の結果より
R倍数の計算結果を、ポートフォリオで、検証を行えるようにして、
ポジションサイズの調整をできるように致しました。
今度のは、かなり、スピードも改善されていますので、
お手隙の時に、チェックしていただけると幸いです!
そういえば、タープ博士の本が、また発売されましたね!
「ポジションサイジング入門」
途中までしか読んでいないのですが、
NLPをもとにしたトレード心理面の強化と、
R倍数をもとにしたポジションサイズの検証方法
をメインにしているようです。
「魔術師たちの心理学」に比べると、
かなり読みやすそうです。
マーサーさん
こんにちわ!
バックテストを繰り返していると、確かに遅くなりますね^^;
メモリを圧迫しているような感じです。
また、何か分かりましたら連絡しますね^^
>複数のシステム・通貨ペア毎の結果より
>R倍数の計算結果を、ポートフォリオで、検証を行えるようにして、
>ポジションサイズの調整をできるように致しました。
すばらしいです!
ぜひ使ってみたいですm(_ _)m
タープ博士「ポジションサイジング入門」が出たんですね^^
ポジションサイジングは最重要項目ですからね^^
早速読んでみます。ありがとうございました!
はじめまして、さつきと申します。
こちらで質問させて頂いてもいいでしょうか?
こちらで勉強させていただいた内容を元にして、
あるインジケーター用のEAに、
別のインジケーターでフィルターをかけようと、
int start()
{
bool SHIFilter = false;
if(UseSHIFilter)
{
double GoSigh = iCustom(Symbol(),0,”SHI_Channel_true”,AllBars,BarsForFract,0,shift+1);
if(GoSigh > 0 ) SHIFilter= true;
}
・
・
・
bool getSignal(int mode)
{
double _1 = 0,_2 = 0;
if(mode == OP_BUY && momentum(OP_BUY) && SHIFilter)
・
・
・
などとしてみましたが、フィルターがかかりません。
どこが間違っているのかお教えいただけないでしょうか?
さつきさん
こんにちわ!
書いていただいた箇所だけでは、なんともいえませんが、
その限られたコードで、
SHIFilterがtrueの場合エントリなし、
getSignal関数のif文でシグナル発生する場合は、
if文の最後は、!SHIFilterになりますね。
慶次さん、こんにちは。
ご回答ありがとうございます。
ひょtっとして、
GoSigh > 0
は、 サインが出ていない状態ということになるのでしょうか?
基本的なことがわかっていなかったようです。
ありがとうございました。
月曜日に試してみます。
また、わからないことがあったら、よろしくお願いいたします。
さつき
こんにちは、さつきと申します。
いつもいろいろお教えいただきありがとうございます。
このページのサンプルプログラムを参考にして、下記のようにしましたが、
Function “MacdSign” is not referenced and will be removed from exp-file
というエラーがでます。
どこを直したらよろしいでしょうか?
長くなるので省略した部分は、サンプルプログラムのコードと同じです。
bool MacdSign(int mode)
{
if(!UseMacdCrossSignal) return(true);
double macd1=iMACD(省略);
double macd2=iMACD(省略);
double macdsignal1=iMACD(省略);
double macdsignal2=iMACD(省略);
if(mode == OP_BUY && macdsignal2>=macd2 && macdsignal1macd1)return(true);
else return(false);
}
続くコードとして
bool getSignal(int mode)
{
double sign = 0;
if(mode == OP_BUY && MacdSign(OP_BUY))
{
sign = iCustom・・・・
というふうにしていきたいのですが。よろしくお願いいたします。
注)if(mode == OP_BUY ・・・
の後には、下記のコードが入っていますが、何度やっても確認画面では消えています。
else if(mode == OP_SELL && macdsignal2macd1)return(true);
自己レスです。
上記の件、理解できました。
どこにも使われてないから、削除するというようなエラーなのですね。
続くコードを入れる前にコンパイルして確かめてからと思っていたので、
エラーが出ていました。
下記の部分を入れたら、出なくなりました。
if(mode == OP_BUY && MacdSign(OP_BUY))
さつきさん
こんにちわ^^
解決されてよかったです^^;
関数が使われていないという警告でしたね^^;
続くコードはすでに書き込んであると思って、不思議に思っておりました・・・。
慶次さん、レスありがとうございます。
少々、あわて者ですので、お許しください。
自信がないと、落ち着いて考える余裕がなくなってしまいます。
また、わからないことがありましたら、質問させていただきます。
よろしくお願いいたします。
さつき
大変参考になる情報を提供していただきじっくりと勉強させてもらっております。が最近更新がないようで少し残念です。
複数のシグナルを使ったEAを作っているのですがEXITのところで詰まってしまい、ご教授頂ければとコメントしました。
例えば、トレンドの時はAのシグナルで、レンジの時はBのシグナルでENTRYし、AのEXITはCの条件で、BのEXITはDの条件で、とするときSAMPLE SWITCHSIGNALを参考にして作るとしたらどの様につくったらよいか色々試しているのですがうまくいかず…です。
大変勝手なお願いですが教えて頂けないでしょうか。宜しくお願いします
Matsuさん
こんにちわ!
>最近更新がないようで少し残念です。
すみません^^;時間を見つけて更新したいとは思っていますが^^;
2つのEAを1つのEAにする感じですね?
シグナルに応じて、マジックナンバーかポジションコメントを変えて、
保有ポジションを分けて認識して、
保有ポジションに応じた決済条件で決済するようにすると
できると思います^^
さっそく返事をいただき大変感激です。
仕事中なので中身を見られないのが残念ですが、今夜帰ったら拝見させて頂きます。
不明な点が有りましたら質問させて頂いてよろしいでしょうか?
お忙しい中大変恐縮です!よろしくお願いします。
慶次さんへ
先日は大変お世話になりありがとうございました。コメントを頂き、あれこれとやってみましたがまだまだ初心者にはハードルが高く一時棚上げとし、別のものを作っておりましたがなかなか上手くいかずこんなコメントがでて解決できないでいます。 (end_of_program’ – unbalanced left parenthesis )
大変恐縮ですがプログラム抜粋したものを張り付けさせていただきましたのでどこをどの様に直したらよいのかご教授いただけないでしょうか。宜しくお願いします。
大変読みにくくて申し訳ありません。
int cnt, CurrentPosition = -1 ;
int Ticket;
for(cnt = 0; cnt Hima1 && HeikinAshi_Close2Close[2]
&& maangle1>Range_hi
&& HeikinAshi_Close11>HeikinAshi_Open11
)
{
Ticket= OrderSend(Symbol(), OP_BUY, lots, Ask, Slippage, Ask-(var2*Point), 0 , “Buy”, 999, 0, Blue);
nowbar = Bars;
}
if(nowbar != Bars
&& HeikinAshi_Close1Loma2 && nehaba1>50
&& ema1>Close[1] && Close[1]ema51 && orderpriceema51 && orderprice>ema30 && orderprice>ema50
)
{
OrderClose(OrderTicket(),OrderLots(),Bid,Slippage,Blue);
Ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, Slippage, Bid+(var2*Point, 0, “Sell”, 999, 0, Red);
}
}
if(OrderType() == OP_SELL)
{
if(
ema30>ema50 && ema31ema30 && orderprice>ema50
)
{
OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, Red);
}
else
if(
ema30>ema50 && ema31<ema51 && orderprice<ema30 && orderprice<ema50
)
{
OrderClose(OrderTicket(),OrderLots(),Ask,Slippage,Red);
Ticket = OrderSend(Symbol(),OP_SELL,lots,Bid,Slippage,Bid+Slippage,Bid(var2*Point,0,”Sell”,999,0,Red);
}
}
}
}
//—-
return(0);
}
//+——————————————————————+
//———————– PRINT COMMENT FUNCTION
//———————– SOURCE : CODERSGURU
int CurrentPosition;
int highestBar;
double highestPrice,lowestPrice,orderprice;
void subPrintDetails()
{
string sComment = “”;
string sp = “—————————————-\n”;
string NL = “\n”;
sComment = sp;
sComment = sComment + “HighestPrice=” + DoubleToStr( High [iHighest(NULL,0,MODE_HIGH,100)],5) + ” | “;
sComment = sComment + sp;
sComment = sComment + “LowestPrice=” + DoubleToStr( Low [iLowest(NULL, 0, MODE_LOW, 100)],5) + ” | “;
sComment = sComment + sp;
sComment = sComment + “OrderOpenPrice=” +DoubleToStr( OrderOpenPrice(),5) + NL;
sComment = sComment + sp;
Comment(sComment);
}
慶次さんへ
お騒がせしました。なんとか解決しました!単なるバカなミスでした。
ただプログラム最後の辺りでreturn(0);の後 画面に過去100期間中の最安値と最高値
及びエントリーしたらそのエントリー値を表示させようとしますがなにか変な値がでてしまいます。ここはどの様にしたらよいでしょうか。ご教授宜しくお願いします。
Matsuさん
こんにちわ^^
変な値とは、
OrderOpenPrice()ですか?
ポジションの情報を取得するには、まずOrderSelect(・・・)でポジションの選択をする必要があります。
OrderSendで返った注文番号でポジション選択できますね^^
慶次さん、はじめまして。
タッキーと申します。
EA自作の初心者です。(^-^;
「Sample_SwitchSignal」を有難く利用させていただいております。
一つ質問というか、お願いがございます。
エグジット用も、エントリー用と同様のやり方でできるとの
ことですが、
エグジット用に、
「一定時間経過後にクローズするフィルタ」を導入したいと思っております。
(エントリー後、ローソク足○本後にクローズという形が理想です。)
(また、○本後は、パラメータで変更可能とするのが理想です。)
お忙しい中、恐縮ではございますが、
ご回答くださいますよう、宜しくお願い申し上げます。m(__)m
タッキーさん
こんにちわ!
決済条件に
iBarShift(NULL, 0, OrderOpenTime()) >= ExitBars
(ExitBarsはパラメータ)
を加えてみてください。