English Русский 中文 Español Deutsch Português
プライスアクション。はらみ足(Inside Bar)トレード戦略の自動化

プライスアクション。はらみ足(Inside Bar)トレード戦略の自動化

MetaTrader 4 | 16 10月 2015, 14:54
12 080 0
Dmitry Iglakov
Dmitry Iglakov

はじめに

すべての為替トレーダーはどこかのポイントでプライスアクションに出会います。これは単なるチャート分析テクニックではなく、未来の値動きの方向を定義する全体的なシステムです。本稿において、はらみ足のパターンを詳しく見ていき、はらみ足をとらえるEAを開発してパターンに基づいたトレードをおこないます。


プライスアクションについて

プライスアクションとは、インディケーターによらずシンプルでいくつかのパターンに基づいて値動きを見極める方法です。補助的なチャート要素と同じように使います。(水平線、垂直線、トレンドライン、フィボナッチレベル、サポート・レジスタンスレベルなど)。

一見するとこの手法は複雑に見えるかもしれませんがそんなことはありません。この方法は年々有名になってきています。他のテクニカル指標をつかった方法と例を比べると利点があるからです。


はらみ足

はらみ足とはその実体をヒゲが前の足(母足、Mother bar)の範囲に収まっている足のことを言います。はらみ足の高値は母足のそれよりも低く、安値は高い位置にあります。母足とはらみ足はエントリーシグナルになり得るパターンを形成します。

これはトレンドの転換、または継続を示唆する両方のパターンがあります。

図1. はらみ足

図1. はらみ足

図2 はらみ足のパターンについて

図2 はらみ足のパターンについて

はらみ足ルール
  • はらみ足のパターンは4時間足や日足のような大きな時間軸で使うことに意義があります。
  • パターンはトレンドの転換か継続のどちらかを示します。
  • 他の描画分析ツール加えてより正確なエントリーをします。トレンドライン、サポート・レジスタンスレベル、フィボナッチレベル、別のプライスアクションパターンなどを加えます。
  • 弱くまた間違った相場のエントリーを回避するため指値注文を使います。
  • フラットな相場で繰り返し発生するはらみ足はエントリーシグナルとして使ってはいけません。

図3ポンドドル日足におけるはらみ足の例

図3ポンドドル日足におけるはらみ足の例

このルールを念頭において、実際のはらみ足を見ていきましょう。上のチャートでは、鋭い下向きの値動きの後に上向きの足が形成されたのが分かります。. しかし、足は完全に前の足の幅の中におさまっています。このパターンはサポートレベルで形成された事実を知らせてくれます。3本目フラットではありません。このパターンはルールを満たすので、本物とみなすことができます。.


エントリーポイントとストップオーダーを決めるには

チャートに本物のはらみ足をみつけました。どのように相場にエントリーし、どこにストップオーダーを入れるべきでしょうか?図4をみてみましょう。7

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

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

最初に上記の例を使ってストップレベルの設定ルールについて考えていきましょう。:

  1. 母足の高値のやや上に逆指値買いを設定します。(少しのポイントだけ上です)。
  2. ストップロスレベルはサポートレベルのやや下に設定します。母足の安値の少し下です。これは注文が入れられ値がサポートレベルに届くと跳ね返ってその後反対方向へ動き出してしまう場合の追加の防衛策です。
  3. レジスタンスレベル近くのやや下に決済レベルを設定します。
はらみ足はトレンドの転換になるか逆指値売りを必要とするトレンドの継続が続くことを忘れないでください。

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

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

最初に上記の例を使ってストップレベルの設定ルールについて考えていきましょう。:

  1. 母足の安値のやや下に逆指値売りを設定します。(少しのポイントだけ下です)
  2. 母足の高値の上にストップロスレベルを設定します。
  3. サポートレベル近くのやや上に決済レベルを設定します。


はらみ足トレードに基づくエキスパートアドバイザーの開発

実際のはらみ足を見つけること、相場へのエントリーとストップ注文を設定することに必要なルールを知りました。これではらみ足のパターンを使ってトレードするのに適したエキスパートアドバイザーを実行できます。

メタトレーダー4のターミナルからメタエディターを開き新しいエキスパートアドバイザーを作成します。(これは説明しなくてもよいでしょう。ウェブサイトにはどうやってエキスパートアドバイザーを作成するか十分な情報があるからです)。このステージではすべてのパラメータは空白のままです。好きな名前を付けることができます。作成したコードは以下のとおりです。:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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を作成した後、ローソク足がクローズしたらはらみ足を定義しなければなりません。そのためには、新しい変数を使って値を割り当てます。コードは以下のとおりです。:

//+------------------------------------------------------------------+
//|                                                    InsideBar.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);
  }
//+------------------------------------------------------------------+

母足が強気(bar 1)の場合の一方で、例として母足が弱気 (bar 2)の場合を考えてみましょう。条件をOnTick()関数本体に加えます。

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);
//--- 2本目のバーが下降で1番目が上昇の場合
   if(open2>close2 && //t2番目のバーは上昇
      close1>open1 && //1番目のバーは下降
      high2>high1 &&  //バー2の高値が1番目の高値を越える場合
      open2>close1 && //2番目のバーの始値が1番目のバーの安値を越える場合
      low2<low1)      //2番目のバーの安値が1番目のバーの安値より小さい
     {
      //--- 1番目のバーが2番目のバーの内側に完全に収まるすべての条件を羅列しました。
     }
  }
  • カスタマイズできる変数を作成します。:ストップオーダー、スリッページ、注文期間、EAのマジックナンバー、トレードロット数です。ストップロスが抜けています。これははらみ足のルールで定義されるからです。
  • 変数を標準化するためローカル変数を入力します。
  • ストップロスはローソク足の値からある距離をとって設定されます。実行するために、ローソク足の高値/安値とストップオーダーレベルの間に基づく内部変数を加えます。指値注文レベルも同様です。
  • このパターンでオーダーが再び出されるのを避けるため時間はらみ足変数を加えます。
  • 母足が十分に大きいことを確かにうるbar2size変数を加えます。現在の相場がフラットでないことを示す良いサインになります。

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

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //インターバル
extern double  lot               = 0.1;                              //ロットサイズ
extern int     TP                = 300;                              //利益確定
extern int     magic             = 555124;                           //マジックナンバー
extern int     slippage          = 2;                                //スリッページ
extern int     ExpDate           = 48;                               //有効期間オーダー
extern int     bar2size          = 800;                              //バー2のサイズ

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     _bar2size;
datetime timeBarInside;         //はらみ足オーダーがオープンされた場所での再オープンを回避するためのバーの時間
//+------------------------------------------------------------------+
//| エキスパート初期化関数                           |
//+------------------------------------------------------------------+
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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- 2本目のバーが下降で1番目が上昇の場合
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない
      _bar2size>bar2size && //2番目のバーが十分に大きく、そのためマーケットはフラットでない
      open2>close2 && //2番目のバーは上昇
      close1>open1 && //1番目のバーは下降
      high2>high1 &&  //バー2の高値が1番目の高値を越える場合
      open2>close1 && //2番目のバーの始値が1番目のバーの終値を越える場合
      low2<low1)      //2番目のバーの安値が1番目のバーの安値より小さい
     {
      //--- 1番目のバーが2番目のバーの内側に完全に収まるすべての条件を羅列しました。
      timeBarInside=iTime(Symbol(),Period(),1); //このパターンでオーダーがすでに置かれたことを示す
     }
  }
//+------------------------------------------------------------------+


ストップオーダーレベルの設定

すべての準備は整いました。あとはストップオーダーレベルとオーダー値を決めるだけです。また、オーダー期限の算出も忘れないようにしましょう。

以下のコードをOnTick()関数のボディに付け加えます。:

buyPrice=NormalizeDouble(high2+interval*_point,Digits);       //インターバルを考慮したオーダー値を定義
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //インターバルを考慮したストップロスを定義
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //利益確定ポイントを定義
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //ペンディングオーダー有効期間の計算
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+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));
        }
     }
//--- check stop orders for selling
   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);
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//|                                                    InsideBar.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          = 20;                               //インターバル
extern double  lot               = 0.1;                              //ロットサイズ
extern int     TP                = 300;                              //利益確定
extern int     magic             = 555124;                           //マジックナンバー
extern int     slippage          = 2;                                //スリッページ
extern int     ExpDate           = 48;                               //有効期間オーダー
extern int     bar2size          = 800;                              //バー2のサイズ

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     _bar2size;
datetime timeBarInside;       //はらみ足オーダーがオープンされた場所での再オープンを回避するためのバーの時間
//+------------------------------------------------------------------+
//| エキスパート初期化関数                           |
//+------------------------------------------------------------------+
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);
//---
   _bar2size=NormalizeDouble(((high2-low2)/_point),0);
//--- 2本目のバーが下降で1番目が上昇の場合
   if(timeBarInside!=iTime(Symbol(),Period(),1) && //このパターンではまだオーダーはオープンしていない
      _bar2size>bar2size && //2番目のバーが十分に大きく、そのためマーケットはフラットでない
      open2>close2 && //2番目のバーは上昇
      close1>open1 && //1番目のバーは下降
      high2>high1 &&  //バー2の高値が1番目の高値を越える場合
      open2>close1 && //2番目のバーの始値が1番目のバーの終値を越える場合
      low2<low1)      //2番目のバーの安値が1番目のバーの安値より小さい
     {
      buyPrice=NormalizeDouble(high2+interval*_point,Digits); //インターバルを考慮したオーダー値を定義l
      buySL=NormalizeDouble(low2-interval*_point,Digits);     //インターバルを考慮したストップロスを定義l
      buyTP=NormalizeDouble(buyPrice+TP*_point,Digits);       //利益確定ポイントを定義
      _ExpDate=TimeCurrent()+ExpDate*60*60;                   //ペンディングオーダー有効期間の計算
      sellPrice=NormalizeDouble(low2-interval*_point,Digits);
      sellSL=NormalizeDouble(high2+interval*_point,Digits);
      sellTP=NormalizeDouble(sellPrice-TP*_point,Digits);
      OrderOpenF(Symbol(),OP_BUYSTOP,lot,buyPrice,slippage,buySL,buyTP,NULL,magic,_ExpDate,Blue);
      OrderOpenF(Symbol(),OP_SELLSTOP,lot,sellPrice,slippage,sellSL,sellTP,NULL,magic,_ExpDate,Blue);
      //--- 1番目のバーが2番目のバーの内側に完全に収まるすべての条件を羅列しました。
      timeBarInside=iTime(Symbol(),Period(),1); //このパターンでオーダーがすでに置かれたことを示す
     }
  }
//+------------------------------------------------------------------+

編集したコードを稼働しログでエラーをチェックしましょう。


エキスパートアドバイザーのテスト

作成したエキスパートアドバイザーでテストします。ストラテジーテスターを起動しパラメーターを入力します。以下のとおりパラメーターをを指定しました。:

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

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

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

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

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

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

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


最適化

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

図8最適化パラメーター

図8最適化パラメーター

図9最適化の設定

図9最適化の設定

これで使用可能ロボットができました。


最適化とテスト結果

図10テスト結果

図10テスト結果

図11テスト結果グラフ

図11テスト結果グラフ


まとめ

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

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

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1771

添付されたファイル |
insidebar.mq4 (38.7 KB)
DLLを経由したメタトレーダーターミナルの管理 DLLを経由したメタトレーダーターミナルの管理
本稿は通知機能の設定をする例を紹介しながら補助DLLライブラリを経由してメタトレーダーユーザーのインターフェイスを使うことについて書かれています。ライブラリソースコードとスクリプトのサンプルを添付しています。
サポートレジスタンス、プライスアクションからトレードセットアップをおこなうには サポートレジスタンス、プライスアクションからトレードセットアップをおこなうには
本稿は、良いタイミングのエントリーをするためのプライスアクションとサポート・レジスタンスレベル(ライン)の観察について書かれています。トレードのセットアップ(エントリー条件)のために、この二つを上手く組み合わせたトレードシステムは何なのか、考えていきます。MQL4のコードには、これらのトレード・コンセプトに基づいたEAに利用されているものがあります。
プライスアクション。つつみ線パターンのトレード戦略を自動化するには プライスアクション。つつみ線パターンのトレード戦略を自動化するには
本稿はつつみ線パターンに基づくメタトレーダー4のためのエキスパートアドバイザーを作成する手順について書かれています。パターン認識のルール、待機注文とストップ注文の設定ルールについても書かれています。テストと最適化の結果もあなたの質となるよう提供します。
ラブシェール資産運用法の統計的検証 ラブシェール資産運用法の統計的検証
この記事では、マーチンゲール法よりは攻撃的ではないが、かけ金のアップは2倍ではなく一定の額というラブシェール資産運用法の統計的性質を検証する。