移動平均ブレイクアウトEAをインジケーターに変更する
前回作成した移動平均ブレイクアウトの自動売買システム(EA)をインジケーター化してみましょう。
新しいインジケーターの作成
EAをそのまま書き換えても良いのですが、EAとインジケーターでは異なる箇所が多いので新しくインジケーターを作成してEAの処理をコピーした方が早いと思います。
新しいEA作成の時と同様に上部メニューのファイル(File) > 新規作成(New)を選択して「MQL Wizard」を起動します。
Wizardの最初の画面では「Custom Indicator」を選択して次へボタンをクリックします。
インジケーターの名前はお好きな名前を入力してください。
私はMovingSignalとしました。
AuthorとLinkもご自由に。
パラメーターは空のままでOKです。次へボタンを押して下さい。
イベントハンドルの設定画面です。変える項目は無いので次へボタンをクリックしてください。
ドローイングプロパティも変更せずに完了ボタンをクリック
これでインジケータープログラムの「箱」ができました。
EAから処理を移植
「パラメーター」と「変数(OpenBarTime)」移植します。
#propertyの下に以下のコードを追加してください。
input int SlowEMAPeriod = 80; input int FastEMAPeriod = 25; input double HeightPercent = 0.45; datetime OpenBarTime = 0;
EAの「OnTick関数(イベント)」の中身をすべて「OnCalculate関数(イベント)」にコピー&ペースト。
そしてオープンとクローズをAlertに書き換えます。(インジケーターからはOrderSendやOrderCloseは実行できません)
//ticket = OrderSend(Symbol(),OP_BUY,Lots,Ask,Slippage,stopLoss,takeProfit,OrdersComment,Magic,0,clrBlue); Alert("Open Buy Signal");
上記は買いのオープンです。同様に売りのオープンとクローズを書き換えてください。(日本語が良い人は日本語でアラートを出してもOKです。)
Openで使用しているStopLossやTakeProfitは不要なので削除してしまいましょう。パラメーターのSlippageや発注時のエラー処理も不要になります。諸々不要なものをばっさり削除して出来上がったのが下記のプログラムです。
//+------------------------------------------------------------------+ //| MovingSignal.mq4 | //| Copyright 2016, TradeAndSoftware | //| https://tasfx.net | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, TradeAndSoftware" #property link "https://tasfx.net" #property version "1.00" #property strict #property indicator_chart_window input int SlowEMAPeriod = 80; input int FastEMAPeriod = 25; input double HeightPercent = 0.45; datetime OpenBarTime = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { double fastEMA = iMA(Symbol(),0,FastEMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); double slowEMA = iMA(Symbol(),0,SlowEMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); double barHeight = MathAbs(Close[0] - Open[0]); double percentage = (barHeight / Ask) * 100; if(percentage > HeightPercent && Time[0] != OpenBarTime) { if(Close[0] > slowEMA && slowEMA > Open[0] && Close[0] > fastEMA) { Alert("Open Buy Signal"); OpenBarTime = Time[0]; } if(Open[0] > slowEMA && slowEMA > Close[0] && fastEMA > Close[0]) { Alert("Open Sell Signal"); OpenBarTime = Time[0]; } } if(OrdersTotal() > 0) { for(int i=0; i<=OrdersTotal()-1; i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break; if(OrderSymbol() != Symbol()) continue; if(OrderType() == OP_BUY && fastEMA > Ask) { Alert("Close Buy Signal"); } else if(OrderType() == OP_SELL && Bid > fastEMA) { Alert("Close Sell Signal"); } } } return(rates_total); } //+------------------------------------------------------------------+
OrderSendの時に「ポジションを持っているかどうか」チェックしていたのですが、それも今回は不要と判断して削除。
Closeシグナルの際には「ポジションを持っているかどうか」をチェックして、持っていた場合のみクローズシグナルを出します。
ただし、通貨ペアをチェックしていなかったので「インジケーターを設置したチャートの通貨ペアと、持っているポジションの通貨ペアが同じ場合のみシグナルを出す」ように以下のコードを追加しています。
if(OrderSymbol() != Symbol()) continue;
OrderSymbol()がポジションの通貨ペア、Symbol()がインジケーターを設置した通貨ペアです。異なる場合はcontinue(スキップ)します。
また、実際に動作させて気がついたのですが「明らかにシグナルの回数が少ない」ためよく確認してみたところ、OpenBarTimeの更新箇所がマズかったのでAlert表示後に更新するよう修正しています。(EAも修正した方が良いかも…;;)
Alert("Open Buy Signal"); OpenBarTime = Time[0]; //←Alert表示後に更新する
動作確認
このインジケーターはバックテストで動作確認することはできません。
かといって初期値の設定で「0.45%の値動きがあって移動平均がブレイクする」のを待っていたのでは時間がかかって仕方ないので…(笑)
以下のようにパラメーター等調整しました。
- 1分足チャートでインジケーターを実行する
- 短期移動平均(fastMA)と長期移動平均(slowMA)の期間(Period)を5にする
- 値幅(HeightPercent)を0.0001にする(適当に小さな値を設定)
これで「小さな値幅」で「移動平均を実体がブレイクアウト」すればアラートが表示されるはずです。
動作が確認できたら、後は設定を戻して普段のチャートにセットすればOKです。
アラートが上がったら「実際にオープンすべきかどうか」を裁量で判断してからトレードしてください。
裁量トレードに自信がある方は、少し値幅(HeightPercent)を小さくしてトレード回数を増やしても良いかもしれません。(初期設定では滅多にアラートが上がらないと思います)
売買トレードシグナル(矢印)をチャートに表示する
アラートでは分かりづらいことと、後で見た際に「そのシグナルが有効なシグナルだったかどうか」が判断しづらいため売買シグナルらしくチャートに矢印を表示してみます。
チャートに矢印を表示する方法は「インジケーターバッファ」を使う方法と、「オブジェクト作成」する方法があります。今回は「イジケーターバッファ」を使っていきます。
インジケーターバッファを定義する
プロパティにバッファを定義します。「買い」と「売り」の2種類必要なので2つ用意しましょう。
#property copyright "Copyright 2016, TradeAndSoftware" #property link "https://tasfx.net" #property version "1.00" #property strict #property indicator_chart_window #property indicator_buffers 1 #property indicator_buffers 2
indicator_chart_windowの下に2行追加しました。
次にバッファを宣言します。パラメーターの下にあるOrenBufferTimeの下に追加。
datetime OpenBarTime = 0; double BufferBuy[]; double BufferSell[];
[]と記載しているのは「配列」というものですが…説明すると非常に長くなってしまうのでここでは説明しません…。
(気になる方は検索してみてください;;)
次に初期化処理を書きます。今まで一度も使ったことがなかったOnInit関数(イベント)を使います。
int OnInit() { SetIndexBuffer(0, BufferBuy); SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 3, clrCyan); SetIndexArrow(0, 233); SetIndexBuffer(1, BufferSell); SetIndexStyle(1, DRAW_ARROW, STYLE_SOLID, 3, clrRed); SetIndexArrow(1, 234); return(INIT_SUCCEEDED); }
1つ目のバッファ(0番)はBufferBuy配列を使います。
矢印の線はSOLID(実線)で大きさは3、色は水色と定義。
矢印の形は233番(Wingdingsフォントで指定)
・・・のような意味です。
売りの方(2つ目のバッファ)も同様に定義しています。
Wingdingsフォントについては以下のサイトを参考にして下さい。
最後にAlert表示した後、矢印を表示するように書きます。
Alert("Open Buy Signal"); BufferBuy[1] = High[1];
バッファの配列1番目に1本前の高値の入れます。
こうすると「1本前の高値」に矢印を描画します。
売りシグナルも同様に‥
Alert("Open Sell Signal"); BufferSell[1] = Low[1];
「1本前の安値」に矢印を描画しました。
現在の足([0])でも良いのですが、高値/安値が確定していないため「価格が動いて」「足の中に矢印が埋もれて見づらい」という現象が発生したため「1本前の足」にしました。
これで「シグナル発生時」に矢印を描画するようになりました。
以下、ソースコード全文です。
//+------------------------------------------------------------------+ //| MovingSignal.mq4 | //| Copyright 2016, TradeAndSoftware | //| https://tasfx.net | //+------------------------------------------------------------------+ #property copyright "Copyright 2016, TradeAndSoftware" #property link "https://tasfx.net" #property version "1.00" #property strict #property indicator_chart_window #property indicator_buffers 1 #property indicator_buffers 2 input int SlowEMAPeriod = 80; input int FastEMAPeriod = 25; input double HeightPercent = 0.45; datetime OpenBarTime = 0; double BufferBuy[]; double BufferSell[]; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { SetIndexBuffer(0, BufferBuy); SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 3, clrCyan); SetIndexArrow(0, 233); SetIndexBuffer(1, BufferSell); SetIndexStyle(1, DRAW_ARROW, STYLE_SOLID, 3, clrRed); SetIndexArrow(1, 234); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { double fastEMA = iMA(Symbol(),0,FastEMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); double slowEMA = iMA(Symbol(),0,SlowEMAPeriod,0,MODE_EMA,PRICE_CLOSE,0); double barHeight = MathAbs(Close[0] - Open[0]); double percentage = (barHeight / Ask) * 100; if(percentage > HeightPercent && Time[0] != OpenBarTime) { if(Close[0] > slowEMA && slowEMA > Open[0] && Close[0] > fastEMA) { Alert("Open Buy Signal"); BufferBuy[1] = High[1]; OpenBarTime = Time[0]; } if(Open[0] > slowEMA && slowEMA > Close[0] && fastEMA > Close[0]) { Alert("Open Sell Signal"); BufferSell[1] = Low[1]; OpenBarTime = Time[0]; } } if(OrdersTotal() > 0) { for(int i=0; i<=OrdersTotal()-1; i++) { if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break; if(OrderSymbol() != Symbol()) continue; if(OrderType() == OP_BUY && fastEMA > Ask) { Alert("Close Buy Signal"); } else if(OrderType() == OP_SELL && Bid > fastEMA) { Alert("Close Sell Signal"); } } } return(rates_total); } //+------------------------------------------------------------------+
それでは「動作確認」で使った設定に戻して、1分足で矢印表示の確認をしてみましょう。
うまくいっているようです。
なお、このインジケーターは「過去チャート(過去の足)」には描画してくれません。
インジケーターを設置した後の「足」にのみ描画します。(過去チャートに描画することもできますが、修正量が多くなるので入れませんでした)
まとめ
意外と簡単にインジケーター化できたと思います。
単純に「オープン/クローズ」していた箇所をAlertに置き換えるだけでも動いてしまいます!(笑)
Alertを表示するプログラムの方は特に問題ないと思いますが、矢印を表示するプログラムは初心者の方にはちょっと難しいかもしれませんね…。(インジケーターバッファはプログラム経験者でもすぐには理解できないかも知れません。私も最初見た時は「どういうことだろう…」と悩みましたので…)
「ようわからん!ここを教えろ!」というご要望がありましたらコメントでお知らせ下さい。
このインジケーター・・・「設定次第では使えそうだぞ…?」と思えてくるのは私だけでしょうか!?
移動平均のチェックを外して「単純に大きめの陽線/陰線が出現したことを通知するインジケーター」としても良さそうです。(興味ある方はやってみてください!)
以上、「移動平均のブレイクアウト/大きく動いたことを検知するインジケーター」でした。
コメント
この機能をAutoOrderModifyシリーズに移動平均交差(SMA/EMA)で決済するオプションとして搭載をして欲しいです。
ご検討くださればと思います。
申し訳ございませんが、AutoOrderModifyに「一定の決済ロジック」を搭載する予定はございません。
移動平均の交差で手仕舞いするEAを作るのは難しくありません。
次はメール通知を予定しているので、その次の回でこの件、取り上げてみたいと思います。
こちらのインジケーターは、どこかからダウンロードできないのでしょうか?
よろしくお願いします!
書いてある通りに作っていただく想定の記事でした。
ソースコードの全文があるので、コピー&ペーストしてコンパイルするだけで動くのではないかと思います。