ここでは、MetaTrader4のEAの作り方について説明します。
もし「自作EAを作ってみたい!」とか「EA作成方法を知っておきたい!」と思っていたら、ぜひこの記事を参考にしてみてください。
EAのバックテスト方法について確認したい方は、前回の記事を参考にしてみてください。
前回記事【MetaTrader4のテスター機能でEAの良し悪しを判断する】へ
自作EA新規作成から完成までの流れ
この記事では、次の手順でEAを作成していきます。
- ステップ1:取引ルールとEA名を決める
- ステップ2:メタエディタで新規EAファイルを生成
- ステップ3:メタエディタでコードを入力していく
- ステップ4:テスターでEAの動作チェック
取引ルールとEA名を決める
EA作成に慣れないうちは、すごく簡単な取引ルールにしてEAを作る練習をしましょう。
この記事では、次の取引ルールのEAを作成しながら説明をしていきます。
- ポジション保有最大数は1つ
- 移動平均線を終値が上回ったら次のローソク足で買いエントリー
- 移動平均線を終値が下回ったら次のローソク足で買いポジション決済
- 売りはその逆
EA名は自分で分かりやすい名前を付けると良いです。日本語文字に一部対応していない場合がありますので、半角のアルファベット・記号・数字を使うようにします。
今回はEA名を【MA_Doten_EAv1.00】にしたいと思います。
メタエディタで新規EAファイルを生成
EAやインジケーターをプログラミングするエディタをメタエディタといいます。
メタエディタを開くには、MT4画面のメニューの「ツール」→「メタエディタ」をクリックします。メタクォーツ言語エディタボタンをクリックでも開くことができます。
メタエディタ画面の左上の新規作成ボタンを押すと、MQLウィザードが開きます。
最初の画面で「エキスパートアドバイザ(テンプレート)」にチェックを入れて、次へボタンをします。
名前のボックスの「Experts\」の右側に、EA名を入力します。その後は完了ボタンが出るまで次へボタンをクリックして完了ボタンをクリックします。
※MT4のバージョンによっては、EA名.mq4のように拡張子「.mq4」も入力する必要があります。
メタエディタのタイトルバーのタイトルが「MetaEditor – [EA名.mq4]」となり、次のコードが表示されます。
//+------------------------------------------------------------------+ //| MA_Doten_EAv1.00.mq4 | //| Dr.EA Keiji | //| https://www.dr-ea.com/meta-blog/ | //+------------------------------------------------------------------+ #property copyright "Dr.EA Keiji" #property link "https://www.dr-ea.com/meta-blog/" #property version "1.00" #property strict //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
なんじゃこりゃー
安心しなさい。一つ一つ説明するぞい
EAテンプレートのコード解説
コード入力の前に、表示されているEAのテンプレートのコードを順に見ていきます。
左に // (スラッシュ2つ)がある行はコメントです。コードを見やすくしたりコードの説明をする場合に使用します。コメントはEAの動作に影響しません。
#property で始まる行は、プログラムの特性などを入力します。EA作成の練習段階では、この部分は特に気にしなくても良いです。
下記のコード部分は、OnInit()関数といい、EA稼働開始時に実行される関数です。
int OnInit() { // ここにEA開始時の処理を入力 return(INIT_SUCCEEDED); }
つぎのコード部分は、OnDeinit()関数といい、EA稼働終了時に実行される関数です。
void OnDeinit(const int reason) { // ここにEA終了時の処理を入力 }
最後の関数が、OnTick()関数といい、ティック(値動き)毎に実行される関数です。
void OnTick() { // ここにティック毎の処理を入力 }
MQLウィザードで作成したEAのテンプレートは、コメント・#property・OnInit()関数・OnDeinit()関数・OnTick()関数で構成されていることがわかります。
※ちなみに旧MQL4では、OnInit()関数・OnDeinit()関数・OnTick()関数は、それぞれinit()関数・deinit()関数・start()関数でした。
メタエディタでコードを入力
それでは、コードを入力していくぞい!
はい!(ワクワク♪)
(カタカタ・・・カタカタカタ・・・) ほいっ!
//+------------------------------------------------------------------+ //| MA_Doten_EAv1.00.mq4 | //| Dr.EA Keiji | //| https://www.dr-ea.com/meta-blog/ | //+------------------------------------------------------------------+ #property copyright "Dr.EA Keiji" #property link "https://www.dr-ea.com/meta-blog/" #property version "1.00" #property strict // パラメーター extern double Lots = 0.1; extern int MagicNumber = 20191030; // グローバル変数 int entry_bar; // エントリーした時のバーの数 //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- // 使い回ししそうな変数を宣言 int i, ticket; // 保有ポジションを確認 ------------------------------- int ticket_buy = 0; // 買いポジションの注文番号 double lots_buy = 0; // 買いポジションのロット数 int ticket_sell = 0; // 売りポジションの注文番号 double lots_sell = 0;// 売りポジションのロット数 for (i=0; i<OrdersTotal(); i++) { // ポジション選択 if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return; // 通貨ペアまたはマジックナンバーが違う場合はスキップ if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; // 保有ポジションの注文番号とロット数を変数に代入 if (OrderType() == OP_BUY) { ticket_buy = OrderTicket(); lots_buy = OrderLots(); } if (OrderType() == OP_SELL) { ticket_sell = OrderTicket(); lots_sell = OrderLots(); } } // 取引シグナルを判定 --------------------------------- int entry_sign = 0; // エントリー用シグナル int exit_sign = 0; // 決済用シグナル // MAの値を取得 double ma_1 = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1); double ma_2 = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 2); // 条件を満たしたらシグナル発生 (1: 買いシグナル, -1: 売りシグナル) if (Close[2] <= ma_2 && Close[1] > ma_1) { entry_sign = 1; exit_sign = 1; } if (Close[2] >= ma_2 && Close[1] < ma_1) { entry_sign = -1; exit_sign = -1; } // 決済 ----------------------------------------------- // 買いポジション決済 if (ticket_buy > 0 && exit_sign == -1) { if (OrderClose(ticket_buy, lots_buy, Bid, 0, clrYellow) == true) ticket_buy = 0; else Print("OrderClose error."); } // 売りポジション決済 if (ticket_sell > 0 && exit_sign == 1) { if (OrderClose(ticket_sell, lots_sell, Ask, 0, clrYellow) == true) ticket_sell = 0; else Print("OrderClose error."); } // エントリー------------------------------------------- if (ticket_buy == 0 && ticket_sell == 0 && entry_bar != Bars) { // 買いエントリー if (entry_sign == 1) { ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, 0, 0, 0, NULL, MagicNumber, 0, clrBlue); if (ticket > 0) entry_bar = Bars; else Print("OrderSend error."); } // 売りエントリー if (entry_sign == -1) { ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, 0, 0, 0, NULL, MagicNumber, 0, clrRed); if (ticket > 0) entry_bar = Bars; else Print("OrderSend error."); } } } //+------------------------------------------------------------------+
はぅ。。
EAのパラメーターを設置
EAのパラメーターを設置するには、OnInit()関数の上に次の形式でコードを追加します。
extern データ型 パラメーター名 = 初期値;
データ型には、「int」整数型、「double」実数型、「bool」真偽型、「string」文字列型などがあります。
ここでは、取引数量を設定する実数型のLotsと、マジックナンバーを設定する整数型のMagicNumberをパラメーターとして設置するため、次のコードを追加します。
extern double Lots = 0.1; extern int MagicNumber = 20191030;
この段階でコンパイルボタンをクリックして、MT4画面のテスターでエキスパート設定のパラメーターの入力タブを見ると、パラメーターの項目にLotsとMagicNumberが反映されていることがわかります。
グローバル変数を宣言
パラメーターのコードの下で、グローバル変数を宣言します。変数の宣言方法は次の通りです。
データ型 変数名 = 初期値;
どの関数内でもないこの位置で宣言する変数は、どの関数からも参照できて格納された値を記憶する特別な変数「グローバル変数」となります。
今回は、エントリーした時にチャート全体のローソク足の数を記憶させておく変数として次のように宣言します。
int entry_bar; // エントリーした時のバーの数
初期値が何であってもかまわない場合は初期値設定を省略することもできます。
OnTick()関数内の構成
OnTick()関数内の処理を次のように4つのセクションに分けた基本的な構成にします。
- 保有ポジションを確認
- 取引シグナルを判定
- 決済処理
- エントリー処理
ドテン取引を1ティック内で実行できるように、「決済処理」→「エントリー処理」の順にしています。
ローカル変数を宣言
ローカル変数とは、関数などのブロック内でのみ使用される変数のことで、そのブロックの処理が終われば格納されている値もリセットされます。
OnTick()関数内で初期値を気にせず複数回使いそうな変数は、関数内の最初に宣言しておくと楽です。
今回は、次のように整数変数「i」と「ticket」をカンマ区切りで宣言します。「i」はfor()文などの繰り返し分でよく使い、「ticket」は新規注文の注文番号を受け取る際によく使います。
int i, ticket;
保有ポジションを確認
1つ目のセクションでは、保有ポジションの有無やその情報を確認します。
EA稼働口座内で保有中のポジションや予約注文を一つ一つ見ていき、このEAでのポジションがある場合、そのポジションの情報を変数に格納しておきます。
今回欲しいポジション情報は、注文番号とロット数です。(なぜこの2つの情報が欲しいかは後編で説明します)
ポジション情報を格納する変数として、次のように宣言します。
int ticket_buy = 0; // 買いポジションの注文番号 double lots_buy = 0; // 買いポジションのロット数 int ticket_sell = 0; // 売りポジションの注文番号 double lots_sell = 0;// 売りポジションのロット数
さらに次のコードで、このEAでのポジション情報を取得します。
for (i=0; i<OrdersTotal(); i++) { // ポジション選択 if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false) return; // 通貨ペアまたはマジックナンバーが違う場合はスキップ if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue; // 保有ポジションの注文番号とロット数を変数に代入 if (OrderType() == OP_BUY) { ticket_buy = OrderTicket(); lots_buy = OrderLots(); } if (OrderType() == OP_SELL) { ticket_sell = OrderTicket(); lots_sell = OrderLots(); } }
このコードに関しては、繰り返しのfor()文とOrderSelect()関数について理解するまでは、丸暗記でかまいません。
コード内のforを選択してキーボードのF1キーを押すとfor()文の解説が見られます。
コード内のOrderSelectを選択してキーボードのF1キーを押すとOrderSelect()関数の解説が見られます。
MQL4リファレンスを上手に活用してMQL4を覚えていくのもEA作成スキル上達にとって大切なことです。
続きは、後編で解説します。お楽しみに!
はじめまして、メタトレーダーで取引はしたことありませんが、今回初めてEAを作ろうと、挑戦しているところです。平均足の直近の足が陽線か陰線か調べる方法として、iCustomを使うと可能との事で検索したところこのブログにたどり着きました。具体的にiCustomでどのようなプログラムをしたら上記の内容を調べて返す式を作れるのでしょうか?よろしかったら教えて欲しいです。よろしくお願いいたします。
はじめまして、メタトレーダーで取引はしたことありませんが、今回初めてEAを作ろうと、挑戦しているところです。平均足の直近の足が陽線か陰線か調べる方法として、iCustomを使うと可能との事で検索したところこのブログにたどり着きました。具体的にiCustomでどのようなプログラムをしたら上記の内容を調べて返す式を作れるのでしょうか?よろしかったら教えて欲しいです。よろしくお願いいたします。
kkさん
こんにちわ!
平均足の返す数値にはシグナルがありませんが、カスタムインディケータをEAにする方法の記事を参考に、平均足の各インデックスがどうなれば、表示が陽線かなどを調べるとわかります。
具体的なプログラムは来年度開催予定の勉強会の1つに盛り込みたいと思いますので、ぜひご連絡ください^^
はじめまして、ど初心者のJackyです
基本練習どおりにやりはじめて、最初の1行目でつまづきました
//変数の宣言
のところで日本語の文字を入れようとすると見たことのないような文字が出てきて日本語を書くことができませんが、どこがまちがっているのでしょうか?
初歩的な質問ですみません
Jackyさん
こんにちわ!
日本語を書きたいときは、
Tools→Options→fontで
Script:日本語
にします。
fontによっては日本語がないものもありますのでご注意ください。
ちなみに私は、MS ゴシックを使用してます^^
おひさしぶりです 先日はサイコロジカルラインのご提示ありがとうございました
今回も、厚かましく、お願いがあるのですが、気が向いたらご返答よろしくです
ひとつのEA内で、パラメータの違いによっての、ふたつのポジションで運用するポートフォリオ化をしたい場合、どのようなプログラムになるのかご指導願えますでしょうか
まことにプログラム素人の不勉強の致すところ恥ずかしいのですけど。
あのランダムエントリーでも利益を出すATRストップで例えていただけるとうれしいのですが。
始めまして、Jakiと申します。
貴殿のブログは大変勉強になっております。
初心者なのでまだまだ勉強しないとだめだと思っています。
お忙しい中、ひとつ教授していただきたい件がありメールしました。
CCI(Commodity Channel Index)を使って、
+100及び-100で買われすぎ・売られすぎを判断するとの事のようですが、
その値を超えたらトレードをしないようにするコードの書き方を
御教授していただきたくメールしました。
また、+100及び-100はパラメーターで変更可能にするようにするにはどうしたらいいのか、
初歩的な質問で申し訳ありません。
何卒、明快なご指導をお願いします。
Jakiさん
こんにちわ^^
パラメータにするには、
{}の無いところ、#property・・・の下あたりに、
例えば、
extern double CCI_UpperLimit = 100;
extern double CCI_LowerLimit =-100;
として、
start()関数の{}内に、
int sign;
//シグナル計算でsignに1や-1などのシグナルを代入する
省略
double cci0 = iCCI(NULL,0,14,PRICE_TYPICAL,0);
if(cci0CCI_UpperLimit) sign = 0;
もし、CCI(14)の現在の値が、CCI_LowerLimitより小さい、または、
CCI_UpperLimitより大きい場合、
signに0を代入。
としてあげると、シグナル計算でsignに0以外の数値が代入されていても、
CCIのフィルタ条件に当てはまったときは、signには0が代入されます。
そして、その後に、
sign が 1のとき買い注文を出す等のコードがつづきますね^^
始めまして、いつも楽しく拝見させていただいてます。
VQのEAのパラメータをいろいろ変更してバックテストしていた所、驚くほどすばらしく(?)右肩下がりの結果が出るパラメータがありました。
そのまま逆にポジションを取ったら、うまく右肩上がりになるのか実験してみたいのですが、どこをいじればいいのか、皆目検討もつきません。
図々しいお願いで申し訳ありませんが、ご指導いただけないでしょうか。
よろしくお願いします。
慶次さん こんにちは
いつもEAの勉強の参考にさせていただいてます。
質問させてください。現在62SMA>200SMA>800SMAをトレンド発生とみなして5SMAと25SMAの交差するところで売買するEAを作成中なのですがコンパイルしてもエラーが出ないのでバックテストしてみたらTestGenerator: unmatched data error (low value 113.5300 at 2010.10.15 00:00 is not reached from the least timeframe, low price 114.0910 mismatches)というメッセージが出て動かないので頭をかかえています。あまり難しくないEAだと思うのですが、ご教示願えないでしょうか?
//利食い損切りピプス
extern int TakeProfit = 100;
extern int StopLoss =100;
//ロット数
extern double lots=0.1;
//移動平均の計算期間
extern int FastMAPeriod =5;
extern int SlowMAPeriod =25;
extern int A_SMA=62;
extern int B_SMA=200;
extern int C_SMA=800;
int bar,LastType;
int start()
{
//現在の移動平均線の値
double FastSMA0 = iMA(NULL,0,FastMAPeriod,0,MODE_SMA,PRICE_CLOSE,0);
//1つ前の移動平均線の値
double FastSMA1 = iMA(NULL,0,FastMAPeriod,0,MODE_SMA,PRICE_CLOSE,1);
//
double SlowSMA0 = iMA(NULL,0,SlowMAPeriod,0,MODE_SMA,PRICE_CLOSE,0);
//
double SlowSMA1 = iMA(NULL,0,SlowMAPeriod,0,MODE_SMA,PRICE_CLOSE,1);
//
double A_SMA = iMA(NULL,PERIOD_D1,A_SMA,0,MODE_SMA,PRICE_CLOSE,1);
double B_SMA = iMA(NULL,PERIOD_D1,B_SMA,0,MODE_SMA,PRICE_CLOSE,1);
double C_SMA = iMA(NULL,PERIOD_D1,C_SMA,0,MODE_SMA,PRICE_CLOSE,1);
if(FastSMA0>SlowSMA0 && A_SMA>B_SMA>C_SMA) int sign=1;
if(FastSMA1<SlowSMA1 && A_SMA<B_SMA<C_SMA) sign=-1;
// オーダーチェック(ポジションなどのデータ)
int CurrentPosition=-1;
for(int cnt=0;cnt0)
{
bar=Bars;
LastType=1;
}
}
//売り条件
if(bar!=Bars && LastType!=-1 && sign==-1 )
{
//売りポジションを取る
Ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), “test”, 123, 0, Red);
if(Ticket>0)
{
bar=Bars;
LastType=-1;
}
}
}
// ポジション有り
else
{
//ポジションの選択
OrderSelect(CurrentPosition,SELECT_BY_POS);
//もし買いポジションで売りシグナルがでたら
if(OrderType()==OP_BUY && sign==-1)
{
//手仕舞い
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),3,Green);
//ドテン売り
Ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 3, Bid+(StopLoss*Point), Bid-(TakeProfit*Point), “test”, 123, 0, Red);
if(Ticket>0)
{
bar=Bars;
LastType=-1;
}
}
//もし売りポジションで買いシグナルがでたら
if(OrderType()==OP_SELL && sign==1)
{
//手仕舞い
OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),3,Green);
//ドテン買い
Ticket = OrderSend(Symbol(), OP_BUY,lots, Ask, 3, Ask-(StopLoss*Point), Ask+(TakeProfit*Point), “test”, 123, 0, Blue);
if(Ticket>0)
{
bar=Bars;
LastType=1;
}
}
}
return(0);
}
saruoyajiさん
こんにちわ^^
TestGenerator: unmatched data errorは、
テストで使う時間足と稼動させる時間足のデータが違うときに出力されます。
1分足をもとに、各時間足を生成すると出なくなります。
いつもサンプルを追いかけ勉強させてもらってます。はじめての投稿ですが、「売買システムを作る」のMA(移動平均)のEAですが、スタート実行すると、すぐに買いや売りのポジションを持ってしまいますが、次のシグナルまで待つようにするには、どのようにしたら良いですか?
(強制に手仕舞いしたとき、ストップロスの後)も。ご教授頂ければ幸いです。
miuraさん
こんにちわ^^
ma1 = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
ma2 = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 2);
と1つ前のMAと2つ前のMAを取得して、
if(Close[2] <= ma2 && Close[1] > ma1)
というようにする方法などがあります^^
お世話になります。
iMAの関数は、発見しましたが、iParabolicは、存在してないようです。
どのようにしたらPrabolicのパラメーターが使えるのか、教えて頂ければありがたいです。
山崎さん
こんにちは。
パラボリックは、iSAR()関数を使用します。
Hello sir,
I come across your blog about EA, I am new to EA trading I want to ask how much will it cost to get a good EA for meta trader 4?
Thanks hope to hear from you.
テンプレートEAが入っている【template.zip】をダウンロード
これは移動平均のEAとありましたがどんなロジックですか
おいそがしいとこすみません。
しろうとさん
コメントありがとうございます。
ダウンロードされた記事のコメントで再度ご質問をお願い致します。
https://www.dr-ea.com/meta-blog/metatrader4/ea-sakusei/ea-making-template.html
ここに書いてあるEAは移動平均のEAとありますが
どんな移動平均のEAかわからないところです。短期線と長期線の交差の取引でしょうか。
しろうとさん
コメントありがとうございます。
移動平均と価格(プライス)のクロスで取引するEAです。