プライスアクション。つつみ線パターンのトレード戦略を自動化するには

Dmitry Iglakov | 16 10月, 2015

はじめに

すべての為替トレーダーはどこかのポイントでプライスアクションに出会います。これは単なるチャート分析テクニックではなく、未来の値動きの方向を定義する全体的なシステムです。本稿では、つつみ線のパターン分析をおこない、このパターンをフォローし関連するトレードの決定をおこなうエキスパートアドバイザーを作成していきます。

前回プライスアクションに基づく自動化トレードを見ていきました。それはプライスアクション。はらみ足(Inside Bar)トレード戦略の自動化の記事にあるはらみ足のことでした。


つつみ線パターンのルール

つつみ線のパターンはローソク足の実体とヒゲが前のローソク足の実体とヒゲを完全につつみこむことです。パターンには2つのタイプがあります。:

図1. チャート上のつつみ線のパターン

図1. チャート上のつつみ線のパターン

このパターンをよく見ていきましょう。

BUOVB. チャートは外側のローソク足の高値が前のローソク足の高値より高く、外側のローソク足の安値が前のローソク足の安値より安いことを示しています。

BEOVB. このパターンも容易に見つけることができます。外側のローソク足の高値が前のローソク足の高値より高く、外側のローソク足の安値が前のローソク足の安値より安いところです。

これらの違いはそれぞれのパターンがそれぞれ相場の方向を明確に与えてくれることです。

図2パターンの構造

図2パターンの構造

つつみみ線パターンのルール:


「BUOVB」のエントリーポイントの確立、ストップオーダーの設定

図3逆指値買いとストップオーダーの設定

図3逆指値買いとストップオーダーの設定

上記の例を使って BUOVB (bullish outside vertical bar)のエントリールールとストップオーダーの設定を分析していきます。:

  1. 逆指値買い待機注文を外側のローソク足の高値のやや上(ほんの少しのポイントだけ上)に設定します。
  2. ストップロスレベルは外側のローソク足の安値より安いところに設定します。
  3. そして利益確定レベルは次のレジスタンスレベルに届く前のところに設定します。


「BUOVB」のエントリーポイントの確立、ストップオーダーの設定

図4逆指値売りとストップ注文の設定

図4 逆指値売りとストップオーダーの設定

上記の例を使って BEOVB (bearish outside vertical bar)のエントリールールとストップオーダーの設定を分析していきます。:

  1. 逆指値売り待機注文を外側のローソク足の安値のやや下(ほんの少しのポイントだけ下)に設定します。
  2. ストップロスレベルは外側のローソク足の高値より高いところに設定します。
  3. そして利益確定レベルは次のサポートレベルに届く前のところに設定します。


つつみ線パターンをトレードするエキスパートアドバイザーの作成

つつみ線のパターンを解説し、いかに安全に相場へエントリーするかを学び、また損失を制限し利益を確かなものにするストップオーダーを設定しました。

次はエキスパートアドバイザーのアルゴリズムを実行しつつみ足のパターンを自動化してみましょう。

メタエディターメタトレーダー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 
     }

結果として以下のコードができます。:

//+------------------------------------------------------------------+
//|                                              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テストにおける入力パラメーター

図5テストにおける入力パラメーター

  1. テストのため通過ペアを選択します。ここではユーロオーストラリアドルを選択しました。
  2. 「すべての時間軸」モードに設定しテストがヒストリーデータ上で行われるようにしてください。ここでは2014年1年分を選択しました。
  3. 時間軸を日足にセットします。
  4. テストを開始します。
  5. テストが完了したら、ログをチェックします。ご覧のように、このプロセスでは実行エラーをありませんでした。

図6テスト条件の設定

図6テスト条件の設定

以下がEAのテスト記録です。:

図7エキスパートアドバイザーのテスト記録l

図7エキスパートアドバイザーのテスト記録l

ミスがないのを確認しEAの最適化をおこないます。


最適化

ここでは最適化のために以下のパラメーターを選びます。:

図8最適化パラメーター

図8最適化パラメーター

図9最適化の設定

図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テスト結果

図10テスト結果

図11テスト結果チャート

図11テスト結果チャート


まとめ

  1. 本稿でつつみ線のパターンをトレードするエキスパートアドバイザーを作成しました。
  2. 追加の相場エントリーのフィルターなしでもプライスアクションのパターンでトレードてきることが分かりました。
  3. トリック(マーチンゲールや均等化)は使っていません。
  4. ドローダウンは正確なストップオーダーの設定を通じ最小化されました。
  5. テクニカルインディケーターは使ってません。トレードロボットは単に「ありのままの」チャートを読み解くことに基づいているだけです。

読んで頂きありがとうございました。本稿がお力になれることを願っております。