プライスアクション。つつみ線パターンのトレード戦略を自動化するには
はじめに
すべての為替トレーダーはどこかのポイントでプライスアクションに出会います。これは単なるチャート分析テクニックではなく、未来の値動きの方向を定義する全体的なシステムです。本稿では、つつみ線のパターン分析をおこない、このパターンをフォローし関連するトレードの決定をおこなうエキスパートアドバイザーを作成していきます。
前回プライスアクションに基づく自動化トレードを見ていきました。それはプライスアクション。はらみ足(Inside Bar)トレード戦略の自動化の記事にあるはらみ足のことでした。
つつみ線パターンのルール
つつみ線のパターンはローソク足の実体とヒゲが前のローソク足の実体とヒゲを完全につつみこむことです。パターンには2つのタイプがあります。:
- BUOVB — Bullish Outside Vertical Bar(強気つつみ線)。;
- BEOVB — Bearish Outside Vertical Bar(弱気つつみ線)。
図1. チャート上のつつみ線のパターン
このパターンをよく見ていきましょう。
BUOVB. チャートは外側のローソク足の高値が前のローソク足の高値より高く、外側のローソク足の安値が前のローソク足の安値より安いことを示しています。
BEOVB. このパターンも容易に見つけることができます。外側のローソク足の高値が前のローソク足の高値より高く、外側のローソク足の安値が前のローソク足の安値より安いところです。
これらの違いはそれぞれのパターンがそれぞれ相場の方向を明確に与えてくれることです。
図2パターンの構造
つつみみ線パターンのルール:
- 長い時間軸においてこのパターンを運用する必要があります。:4時間足、日足です。
- より正確なエントリーのため、グラフ分析の追加要素を導入します。トレンドライン、サポート・レジスタンスレベル、フィボナッチレベル、別のプライスアクションパターンなどです。
- 弱くまた間違った相場のエントリーを回避するため指値注文を使います。
- フラットな相場で繰り返すパターンは相場エントリーのシグナルとして使うべきではありません。
「BUOVB」のエントリーポイントの確立、ストップオーダーの設定
図3逆指値買いとストップオーダーの設定
上記の例を使って BUOVB (bullish outside vertical bar)のエントリールールとストップオーダーの設定を分析していきます。:
- 逆指値買い待機注文を外側のローソク足の高値のやや上(ほんの少しのポイントだけ上)に設定します。
- ストップロスレベルは外側のローソク足の安値より安いところに設定します。
- そして利益確定レベルは次のレジスタンスレベルに届く前のところに設定します。
「BUOVB」のエントリーポイントの確立、ストップオーダーの設定
図4 逆指値売りとストップオーダーの設定
上記の例を使って BEOVB (bearish outside vertical bar)のエントリールールとストップオーダーの設定を分析していきます。:
- 逆指値売り待機注文を外側のローソク足の安値のやや下(ほんの少しのポイントだけ下)に設定します。
- ストップロスレベルは外側のローソク足の高値より高いところに設定します。
- そして利益確定レベルは次のサポートレベルに届く前のところに設定します。
つつみ線パターンをトレードするエキスパートアドバイザーの作成
つつみ線のパターンを解説し、いかに安全に相場へエントリーするかを学び、また損失を制限し利益を確かなものにするストップオーダーを設定しました。
次はエキスパートアドバイザーのアルゴリズムを実行しつつみ足のパターンを自動化してみましょう。
メタエディターをメタトレーダー4のターミナルから開き新しいエキスパートアドバイザーを作成します。(これは説明しなくてもよいでしょう。ウェブサイトにはどうやってエキスパートアドバイザーを作成するか十分な情報があるからです) 特定にステージいおいてすべてのパラメーターは空白のままです。そこには好きな名前をつけることができます。作成すると、以下のような結果を得ます。:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_Bar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict //+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int OnInit() { //--- //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| エキスパート非初期化関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| エキスパートティック関数 | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+
パターンをMQL4のアルゴリズムにコンバートします。
EAを作成した後、ローソク足がクローズしたらつつみ足を定義しなければなりません。そのためには、新しい変数を使って値を割り当てます。コードは以下のとおりです。:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_Bar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict double open1,//1番目ローソク足始値 open2, //2番目ローソク足始値 close1, //1番目ローソク足終値 close2, //2番目ローソク足終値 low1, //1番目ローソク足安値 low2, //2番目ローソク足安値 high1, /1番目ローソク足の高値 high2; //2番目ローソク足高値 //+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| エキスパート非初期化関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| エキスパートティック関数 | //+------------------------------------------------------------------+ void OnTick() { //--- 必要なバーの値を特定 open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); } //+------------------------------------------------------------------+
つつみ線の両方タイプを探します。:
void OnTick() { //--- 必要なバーの値を特定 open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //---下降パターンBEOVBの検索 if(low1 < low2 &&// 1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&//1番目のバーの高値が2番目のバーの高値より小さい close1 < open2 && //1番目のバーの終値が2番目のバーの始値より小さい open1 > close1 && //1番目のバーは陰線 open2 < close2) //2番目のバーは陽線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陰線であることを示すすべての条件を書きました。 }
同じように上昇パターンを探します。:
//--- 上昇パターンBUOVBの検索 if(low1 < low2 &&// 1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&// 1番目のバーの高値が2番目のバーの高値より大きい close1 > open2 && //1番目のバーの終値が2番目のバーの始値より大きい open1 < close1 && //1番目のバーは陽線 open2 > close2) //2番目のバーは陰線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陽線であることを示すすべての条件を書きましたr }
- カスタマイズできる変数を作成します。:ストップオーダー、スリッページ、注文期間、EAのマジックナンバー、トレードロット数です。ストップロスが抜けています。これははらみ足のルールで定義されるからです。
- 変数をの標準のフォームに組み込むためローカル変数を導入します。
- さらに、ストップオーダーはローソク足の値からある距離をとって設定されます。実行するために、ローソク足の高値/安値とストップオーダーレベルの間に基づく内部変数を加えます。指値注文レベルも同様です。
- このパターンでオーダーが再び出されるのを避けるためtimeBUOVB_BEOVB足変数を加えます。
- 外側のローソク足が十分に大きいかどうかチェックするためbar1size変数をにゅうりょくします。これで現在の相場がフラットでないことがわかります。
結果として以下のコードができます。:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_bar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict extern int interval = 25; //インターバル extern double lot = 0.1; //ロットサイズ extern int TP = 400; //利益確定 extern int magic = 962231; //マジックナンバー extern int slippage = 2; //スリッページ extern int ExpDate = 48; //有効期間オーダー extern int bar1size = 900; //バー1のサイズ double buyPrice,//逆指値買いの値を定義 buyTP, //逆指値買い利益確定 buySL, //逆指値買いストップロス sellPrice, //逆指値売りの値を定義 sellTP, //逆指値売り利益確定 sellSL; //逆指値売りストップロス double open1,//1番目ローソク足始値 open2, //2番目ローソク足始値 close1, //1番目ローソク足終値 close2, //second candle Close price low1, //1番目ローソク足安値 low2, //2番目ローソク足安値 high1, //1番目ローソク足の高値 high2; //2番目ローソク足高値 datetime _ExpDate =0; // ペンディングオーダー有効期間を定義するローカル関数 double _bar1size;// フラットなマーケットの回避を要求するローカル変数 ptdatetime timeBUOVB_BEOVB;// パターンオーダーがオープンされた場所での再オープンを回避するためのバーの時間 //+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| エキスパート非初期化関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| エキスパートティック関数 | //+------------------------------------------------------------------+ void OnTick() { double _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // define Low price double _ask = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //上値を定義 double _point = MarketInfo(Symbol(), MODE_POINT); //--- 必要なバーの値を特定 open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //--- _bar1size=NormalizeDouble(((high1-low1)/_point),0); //---下降パターンBEOVBの検索 if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない _bar1size > bar1size && //2番目のバーが十分に大きく、そのためマーケットはフラットでない low1 < low2 &&//1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&// 1番目のバーの高値が2番目のバーの高値より大きい close1 < open2 && //First bar's Сlose price is lower than second bar's Open price open1 > close1 && //1番目のバーは陰線 open2 < close2) //2番目のバーは陽線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陰線であることを示すすべての条件を書きました。 timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // このパターンでオーダーがすでに置かれたことを示す } //--- 上昇パターンBUOVBの検索 if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない _bar1size > bar1size && //1番目のバーがフラットなマーケットと考えられないほど十分に大きい low1 < low2 &&//1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&// 1番目のバーの高値が2番目のバーの高値より大きい close1 > open2 && //1番目のバーの終値が2番目のバーの始値より大きい open1 < close1 && //1番目のバーは陽線 open2 > close2) //2番目のバーは陰線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陽線であることを示すすべての条件を書きましたr timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); // このパターンでオーダーがすでに置かれたことを示す } } //+------------------------------------------------------------------+
ストップオーダーレベルの設定
すべての条件を満たし高い精度のパターンを見つけました。次はストップオーダーレベル、待機注文値、それぞれのパターンにおける注文期間を設定する必要があります。
以下のコードをOnTick()関数のボディに付け加えます。:
//--- オーダーとストップオーダーの値を定義 buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //インターバルを考慮したオーダー値を定義 buySL =NormalizeDouble(low1-interval * _point,Digits); //インターバルを考慮したストップロスを定義 buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //利益確定ポイントを定義 _ExpDate =TimeCurrent() + ExpDate*60*60; //ペンディングオーダー有効期間の計算 //--- 売り注文も計算します。 sellPrice=NormalizeDouble(low1-interval*_point,Digits); sellSL=NormalizeDouble(high1+interval*_point,Digits); sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
エラー実行の訂正
今までエキスパートアドバイザーの開発に取り組んだことがあるなら、オーダーをクローズかセットする時や、待機時間、不正確なストップなどの時にエラーがよく起こると知っているでしょう。このようなエラーを失くすために、基本エラーの小さなビルトインハンドラを使った分岐関数を書かなければいけません。
//+----------------------------------------------------------------------------------------------------------------------+ //| オーダーをオープンするかセットする関数 | //| symbol - 取引が行われている場所のシンボル | //| cmd - 取引(どんな取引値とも同等かもしれない) | //| volume - ロット合計 | //| price - 始値 | //| slippage - マーケット買い・売りオーダーの最大許容値幅 | //| stoploss - 不採算レベルに到達した際のポジション終値(不採算レベルでないならば0)| //| takeprofit - 採算レベルに到達した際のポジション終値(採算レベルでないならば0)| //| comment - オーダーコメントコメントの最後の部分はトレードサーバーによって変えられます。 | //| magic - オーダーマジックナンバーウーザー定義IDとして使われます。 | //| expiration - ペンディングオーダー有効期間 | //| arrow_color - チャート上のオープン矢印の色もしパラメータがないかCLR_NONEと同等の場合、 | //| オープン矢印はチャートに表示されません。 | //+----------------------------------------------------------------------------------------------------------------------+ int OrderOpenF(string OO_symbol, int OO_cmd, double OO_volume, double OO_price, int OO_slippage, double OO_stoploss, double OO_takeprofit, string OO_comment, int OO_magic, datetime OO_expiration, color OO_arrow_color) { int result = -1;// オーダーをオープンした結果 int Error = 0; // オーダーをオープンしたときのエラー int attempt = 0; // 試みられた量 int attemptMax = 3; // 試みの最大量 bool exit_loop = false; // ループ処理をイグジット string lang =TerminalInfoString(TERMINAL_LANGUAGE);// メッセージ言語を定義するためのトレードターミナル言語 double stopllvl =NormalizeDouble(MarketInfo (OO_symbol, MODE_STOPLEVEL) * MarketInfo (OO_symbol, MODE_POINT),Digits);// 最小ストップロス/利益確定レベル、小数値 /モジュールは安全なオーダーオープンを提供します //--- 買い注文のためのストップオーダーをチェック if(OO_cmd==OP_BUY || OO_cmd==OP_BUYLIMIT || OO_cmd==OP_BUYSTOP) { double tp = (OO_takeprofit - OO_price)/MarketInfo(OO_symbol, MODE_POINT); double sl = (OO_price - OO_stoploss)/MarketInfo(OO_symbol, MODE_POINT); if(tp>0 && tp<=stopllvl) { OO_takeprofit=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT); } if(sl>0 && sl<=stopllvl) { OO_stoploss=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT)); } } //--- 売り注文のためのストップオーダーをチェック if(OO_cmd==OP_SELL || OO_cmd==OP_SELLLIMIT || OO_cmd==OP_SELLSTOP) { double tp = (OO_price - OO_takeprofit)/MarketInfo(OO_symbol, MODE_POINT); double sl = (OO_stoploss - OO_price)/MarketInfo(OO_symbol, MODE_POINT); if(tp>0 && tp<=stopllvl) { OO_takeprofit=OO_price -(stopllvl+2*MarketInfo(OO_symbol,MODE_POINT)); } if(sl>0 && sl<=stopllvl) { OO_stoploss=OO_price+stopllvl+2*MarketInfo(OO_symbol,MODE_POINT); } } //--- ループ処理 while(!exit_loop) { result=OrderSend(OO_symbol,OO_cmd,OO_volume,OO_price,OO_slippage,OO_stoploss,OO_takeprofit,OO_comment,OO_magic,OO_expiration,OO_arrow_color); //特定パラメータを利用してオーダーをオープンする試み //---オーダーをオープンした際にエラーがあるか if(result<0) { Error = GetLastError(); //エラーにコードを割り当て switch(Error) //エラー列挙 { //エラー列挙をクローズするオーダーとそれらをフィクスする試み case 2: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 Sleep(3000); //3秒間遅延 RefreshRates(); break; //スイッチをイグジット } if(attempt==attemptMax) { attempt=0; //試みの残りをゼロにリセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 3: RefreshRates(); exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 4: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 Sleep(3000); //3秒間遅延 RefreshRates(); break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにリセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 5: exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 6: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 Sleep(5000); //3秒間遅延 break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにリセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 8: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 Sleep(7000); //3秒間遅延 break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにリセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 64: exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 65: exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 128: Sleep(3000); RefreshRates(); continue; //スイッチをイグジット case 129: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 Sleep(3000); //3秒間遅延 RefreshRates(); break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにリセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 130: exit_loop=true; //この間にイグジット break; case 131: exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 132: Sleep(10000); //10秒間スリープ RefreshRates(); //更新データ //exit_loop = true; //この間にイグジット break; //スイッチをイグジット case 133: exit_loop=true; //この間にイグジット break; //スイッチをイグジット case 134: exit_loop=true; //この間にイグジット break; //スイッチをイグジット case 135: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 RefreshRates(); break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 136: if(attempt<attemptMax) { attempt=attempt+1; //もう1つ試みを定義 RefreshRates(); break; //スイッチをイグジット } if(attempt==attemptMax) { attempt = 0; //試みの残りをゼロにセット exit_loop = true; //この間にイグジット break; //スイッチをイグジット } case 137: if(attempt<attemptMax) { attempt=attempt+1; Sleep(2000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 138: if(attempt<attemptMax) { attempt=attempt+1; Sleep(1000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 139: exit_loop=true; break; case 141: Sleep(5000); exit_loop=true; break; case 145: exit_loop=true; break; case 146: if(attempt<attemptMax) { attempt=attempt+1; Sleep(2000); RefreshRates(); break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 147: if(attempt<attemptMax) { attempt=attempt+1; OO_expiration=0; break; } if(attempt==attemptMax) { attempt=0; exit_loop=true; break; } case 148: exit_loop=true; break; default: Print("Error: ",Error); exit_loop=true; //この間にイグジット break; //他のオプション } } //--- 削除するエラーがない場合 else { if(lang == "Russian") {Print("Ордер успешно открыт. ", result);} if(lang == "Japanese") {Print("発注に成功しました。", result);} Error = 0; //エラーコードをゼロにリセット break; //この間にイグジット //errorCount =0; //試みの残りをゼロにリセット } } return(result); } //+------------------------------------------------------------------+
結果として以下のコードができます。:
//+------------------------------------------------------------------+ //| BEOVB_BUOVB_bar.mq4 | //| Copyright 2015, Iglakov Dmitry. | //| cjdmitri@gmail.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2015, Iglakov Dmitry." #property link "cjdmitri@gmail.com" #property version "1.00" #property strict extern int interval = 25; //インターバル extern double lot = 0.1; //ロットサイズ extern int TP = 400; //利益確定 extern int magic = 962231; //マジックナンバー extern int slippage = 2; //スリッページ extern int ExpDate = 48; //有効期間オーダー extern int bar1size = 900; //バー1のサイズ double buyPrice,//逆指値買いの値を定義 buyTP, //逆指値買い利益確定 buySL, //逆指値買いストップロス sellPrice, //逆指値売りの値を定義 sellTP, //逆指値売り利益確定 sellSL; //逆指値売りストップロス double open1,//1番目ローソク足始値 open2, //2番目ローソク足始値 close1, //1番目ローソク足終値 close2, //2番目ローソク足終値 low1, //1番目ローソク足安値 low2, //2番目ローソク足安値 high1, //1番目ローソク足の高値 high2; //2番目ローソク足高値 datetime _ExpDate =0; // ペンディングオーダー有効期間を定義するローカル関数 double _bar1size;// フラットなマーケットの回避を要求するローカル変数 ptdatetime timeBUOVB_BEOVB;// パターンオーダーがオープンされた場所での再オープンを回避するためのバーの時間 //+------------------------------------------------------------------+ //| エキスパート初期化関数 | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| エキスパート非初期化関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| エキスパートティック関数 | //+------------------------------------------------------------------+ void OnTick() { double _bid = NormalizeDouble(MarketInfo (Symbol(), MODE_BID), Digits); // 安値を定義 double _ask = NormalizeDouble(MarketInfo(Symbol(), MODE_ASK), Digits); //上値を定義 double _point = MarketInfo(Symbol(), MODE_POINT); //--- 必要なバーの値を特定 open1 = NormalizeDouble(iOpen(Symbol(), Period(), 1), Digits); open2 = NormalizeDouble(iOpen(Symbol(), Period(), 2), Digits); close1 = NormalizeDouble(iClose(Symbol(), Period(), 1), Digits); close2 = NormalizeDouble(iClose(Symbol(), Period(), 2), Digits); low1 = NormalizeDouble(iLow(Symbol(), Period(), 1), Digits); low2 = NormalizeDouble(iLow(Symbol(), Period(), 2), Digits); high1 = NormalizeDouble(iHigh(Symbol(), Period(), 1), Digits); high2 = NormalizeDouble(iHigh(Symbol(), Period(), 2), Digits); //--- オーダーとストップオーダーの値を定義 buyPrice =NormalizeDouble(high1 + interval * _point,Digits); //インターバルを考慮したオーダー値を定義 buySL =NormalizeDouble(low1-interval * _point,Digits); //define stop loss with an interval buyTP =NormalizeDouble(buyPrice + TP * _point,Digits); //利益確定ポイントを定義 _ExpDate =TimeCurrent() + ExpDate*60*60; //ペンディングオーダー有効期間の計算 //--- 売り注文も計算します。 sellPrice=NormalizeDouble(low1-interval*_point,Digits); sellSL=NormalizeDouble(high1+interval*_point,Digits); sellTP=NormalizeDouble(sellPrice-TP*_point,Digits); //--- _bar1size=NormalizeDouble(((high1-low1)/_point),0); //---下降パターンBEOVBの検索 if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない _bar1size > bar1size && //1番目のバーが十分に大きく、そのためマーケットはフラットでない low1 < low2 &&//1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&// 1番目のバーの高値が2番目のバーの高値より大きい close1 < open2 && //1番目のバーの終値が2番目のバーの始値より大きい open1 > close1 && //1番目のバーは陰線 open2 < close2) //2番目のバーは陽線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陰線であることを示すすべての条件を書きました。 OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue); timeBUOVB_BEOVB=iTime(Symbol(),Period(),1); //このパターンでオーダーがすでに置かれたことを示す } //--- 上昇パターンBUOVBの検索 if(timeBUOVB_BEOVB!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない _bar1size > bar1size && //1番目のバーが十分に大きく、そのためマーケットはフラットでない low1 < low2 &&//1番目のバーの安値が2番目のバーの安値より小さい high1 > high2 &&// 1番目のバーの高値が2番目のバーの高値より大きい close1 > open2 && //1番目のバーの終値が2番目のバーの始値より大きい open1 < close1 && //1番目のバーは陽線 open2 > close2) //2番目のバーは陰線 { //--- 1番目のバーが2番目のバーを完全に包み込み、また1番は陽線であることを示すすべての条件を書きましたr OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue); timeBUOVB_BEOVB = iTime(Symbol(),Period(),1); //このパターンでオーダーがすでに置かれたことを示す } } //+------------------------------------------------------------------+
編集したコードを稼働しログでエラーをチェックしましょう。
エキスパートアドバイザーのテスト
作成したエキスパートアドバイザーでテストします。ストラテジーテスターを起動しパラメーターを入力します。
図5テストにおける入力パラメーター
- テストのため通過ペアを選択します。ここではユーロオーストラリアドルを選択しました。
- 「すべての時間軸」モードに設定しテストがヒストリーデータ上で行われるようにしてください。ここでは2014年1年分を選択しました。
- 時間軸を日足にセットします。
- テストを開始します。
- テストが完了したら、ログをチェックします。ご覧のように、このプロセスでは実行エラーをありませんでした。
図6テスト条件の設定
以下がEAのテスト記録です。:
図7エキスパートアドバイザーのテスト記録l
ミスがないのを確認しEAの最適化をおこないます。
最適化
ここでは最適化のために以下のパラメーターを選びます。:
図8最適化パラメーター
図9最適化の設定
最適化とテスト結果を得たので、これで使用可能なロボットができました。
最適化とテスト結果
最もポピュラーな通貨ペアの最適化の後、以下の結果を得ます。:
通貨ペア | 純利益 | プロフィットファクター | ドローダウン(%) | 総利益 | 総損失 |
---|---|---|---|---|---|
EURAUD | $523.90 | 3.70 | 2.13 | $727,98 | $196.86 |
USDCHF | $454.19 | - | 2.25 | $454.19 | $0.00 |
GBPUSD | $638.71 | - | 1.50 | $638.71 | $0.00 |
ユーロドル | $638.86 | - | 1.85 | $638.86 | $0.00 |
USDJPY | $423.85 | 5.15 | 2.36 | $525.51 | $102.08 |
USDCAD | $198.82 | 2.41 | 2.74 | $379.08 | $180.26 |
AUDUSD | $136.14 | 1.67 | 2.39 | $339.26 | $203.12 |
表1最適化結果
通貨ペアユーロオーストラリアドルにおけるより詳細なテスト結果を得ました。
図10テスト結果
図11テスト結果チャート
まとめ
- 本稿でつつみ線のパターンをトレードするエキスパートアドバイザーを作成しました。
- 追加の相場エントリーのフィルターなしでもプライスアクションのパターンでトレードてきることが分かりました。
- トリック(マーチンゲールや均等化)は使っていません。
- ドローダウンは正確なストップオーダーの設定を通じ最小化されました。
- テクニカルインディケーターは使ってません。トレードロボットは単に「ありのままの」チャートを読み解くことに基づいているだけです。
読んで頂きありがとうございました。本稿がお力になれることを願っております。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1946
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索