トップ  >  自作してみる >  MQL4未経験者向け(インジケータ作成の基本)  >  メインウインドウ  >  M6.トレンド系インジケータ作成(トレンド転換シグナルアロー【矢印】)
M6.トレンド系インジケータ作成(トレンド転換シグナルアロー【矢印】)


今回はシグナルアローのインジケータを作成します。
簡単に言うとサインですね。


いつも通りに今回も他カスタムインジケータをベースにして新しいカスタムインジケータを作成します。
それでは以前作成した移動平均線+エンベロープのカスタムインジケータのソースコードのTestMAEnvLine.mq4をコピペして、
ファイル名をTestArrowFractal.mq4に変更しましょう。

インジケータの描画タイプをアローシンボルにする

今回のインジケータは今までのような線では無く、矢印等のシンボルを表示させるので、インジケータの描画タイプをアローシンボルに変更する必要があります。
インジケータプロパティ設定にindicator_typeNの設定を追加して、描画タイプをDRAW_ARROWに設定します。

アローシンボルは小さいと目視で識別し難いので、ついでにindicator_widthNの設定を3に変更します。

ソースコード:
// インジケータプロパティ設定
#property  indicator_buffers    2               // カスタムインジケータのバッファ数
#property  indicator_color1     clrWhite      // インジケータ1の色
#property  indicator_width1     3               // インジケータ1の太さ
#property  indicator_type1      DRAW_ARROW     // インジケータ1の描画タイプ

#property  indicator_color2     clrWhite      // インジケータ2の色
#property  indicator_width2     3               // インジケータ2の太さ
#property  indicator_type2      DRAW_ARROW     // インジケータ2の描画タイプ



コンパイルして動作確認してみましょう。

自作インジケータトレンド転換アロー

ラインがシンボルに変わりました。

アローシンボルを変更する


次はアローシンボルを任意のシンボルに変更します。
任意のシンボルに変更するにはSetIndexArrow()関数を使って、Wingdingsフォントアローコード定数のシンボルーコードを設定します。

OnInit()関数内にソースコードを追加します。

ソースコード:
   //SetIndexLabel(  0, "移動平均線"  );   // インジケータ1のラベル設定
   //SetIndexLabel(  1, "乖離線+"    );   // インジケータ2のラベル設定

   SetIndexArrow( 0 , 218 );     // インジケータ1のアローシンボル設定
   SetIndexArrow( 1 , 217 );     // インジケータ2のアローシンボル設定

SetIndexLabel()の設定は今回邪魔なのでコメントアウトしました。

SetIndexArrow()で設定している217と218という数値はWingdingsフォントのコードです。

自作インジケータトレンド転換アロー


コンパイルして動作確認してみましょう。

自作インジケータトレンド転換アロー

シンボルが指定したものに変わりました。

トレンドの転換点を算出する

トレンドの転換点を算出して、転換点にのみシンボル表示するようにします。
トレンドの転換点はiFractals()関数を使って機械的に算出します。

あくまで機械的に転換点を算出しているので、信頼性は高く有りませんが、相場観が養われていない相場初心者の人はこのインジケータを参考にしてチャートを眺めていると何か掴めるかもしれません。
基本的にテクニカル分析は日足で使われる事を前提で作成されている(と思います)ので、
日足未満の時間軸でテクニカル分析を行っても混乱の元にしかなりません(管理人の独断と偏見です。これに対して異議は受け付けませんw)
VWAPと長いスパンのMAは日足未満の時間軸でも使えますが・・・

OnCalculate()関数内のforループ内の処理をiFractals()関数に置き換えます。

ソースコード:
        double get_lower = iFractals(                // フラクタル算出
                                       Symbol(),      // 通貨ペア
                                       Period(),      // 時間軸
                                       MODE_LOWER,   // ラインインデックス
                                       icount          // シフト
                                      );

        double get_upper = iFractals(                // フラクタル算出
                                       Symbol(),      // 通貨ペア
                                       Period(),      // 時間軸
                                       MODE_UPPER,   // ラインインデックス
                                       icount          // シフト
                                     );


        _IndBuffer1[icount]    = get_lower;     // インジケータ1にフラクタル下を設定
        _IndBuffer2[icount]    = get_upper;     // インジケータ2にフラクタル上を設定

自作インジケータトレンド転換アロー

転換点が表示されるようになりました。

転換点以外は表示されていませんが、これはiFractals()関数が転換点と判断しなかった場合に0を返す為です。
実際には範囲外の価格0の部分にシンボルが並んでいます。

チャートスケールを引き伸ばすと・・・
自作インジケータトレンド転換アロー

見えない部分なので気にしなくてもいいのですが、
見えない部分も手抜きをしたくないエンジニア精神がある人は修正しましょう。

単純にiFractals()の結果が0以下だった場合は、インジケータバッファに値を設定しないようにします。
ソースコード:
        if ( get_lower > 0 ) {
            _IndBuffer1[icount]    = get_lower;     // インジケータ1にフラクタル下を設定
        }
        if ( get_upper > 0 ) {
            _IndBuffer2[icount]    = get_upper;     // インジケータ2にフラクタル上を設定
        }



自作インジケータトレンド転換アロー

普段は見えない部分ですがスッキリしました。


シンボル表示位置をピクセル単位で調整する

これも細かい部分なのですが、
自作インジケータトレンド転換アロー

四本値とシンボルが被ってしまっています。
転換点の高値と安値位置にシンボルを配置している為、オフセットさせなかった場合必ず被ってしまう事になります。
単純に10pipsくらいオフセットさせても良いのですが、南アフリカランドドルみたいに極端にボラティリティの無い通貨ペアとポンドドルみたいに極端にボラティリティのある通貨ペアでは、 同じ10pipsのオフセットでもかなり変ってしまいます。

なのでオフセットは価格レートでは無く、ピクセル単位で行います。
正確にはピクセル単位のオフセットした価格レートを算出します。

それではオフセットする関数を自作しましょう。
処理内容は単純にChartTimePriceToXY()関数で価格値をY座標に変換し、
そのY座標にPixel単位のオフセット値を加えて、
オフセットしたY座標をChartXYToTimePrice()関数で価格値に変換するだけです。

ソースコード:
//+------------------------------------------------------------------+
//| 価格レートをPixel単位でオフセットする
//+------------------------------------------------------------------+
double GetOffsetRate(
    double in_rate,         // 価格レート
    int    in_offset_pixel  // オフセット(Pixel単位)
)
{
   double   ret            = in_rate; // 戻り値
   double   move_rate;                // オフセットしたレート
   datetime dummy_time;               // ダミー時間
   int      bese_axis_x;              // 取得座標X
   int      bese_axis_y;              // 取得座標Y
   int      get_window_no;            // 取得サブウインドウNo
   int      disp_pixel;               // オフセットした座標
   bool     get_bool;                 // 判定結果
     
   get_bool = ChartTimePriceToXY(             // 時間・価格値をX・Y座標に変換
                                 0,           // チャートID
                                 0,           // サブウインドウ番号
                                 Time[0],     // チャート上の時間
                                 in_rate,     // チャート上の価格
                                 bese_axis_x, // X座標
                                 bese_axis_y  // Y座標
                              );
   
   if ( get_bool == true ) {                      // 変換できた場合
      disp_pixel = bese_axis_y + in_offset_pixel; // 座標Yをオフセット
   
      get_bool = ChartXYToTimePrice(                // X・Y座標を時間・価格値に変換
                                    0,              // チャートID
                                    bese_axis_x,    // X座標
                                    disp_pixel,     // Y座標
                                    get_window_no,  // サブウインドウ番号
                                    dummy_time,     // チャート上の時間
                                    move_rate       // チャート上の価格
                                   );
   
      if ( get_bool == true ) {     // 変換できた場合
         ret = move_rate;           // 戻り値に変換後の価格を設定
      }
   }
   
   return ret;
}


ピクセル単位でオフセットする関数が出来た所で、インジケータバッファに設定する前の値を変換しましょう。

ソースコード:
        if ( get_lower > 0 ) {
            get_lower = GetOffsetRate(get_lower, 10); // 価格をピクセル単位でオフセット
            _IndBuffer1[icount]    = get_lower;       // インジケータ1にフラクタル下を設定
        }
        if ( get_upper > 0 ) {
            get_upper = GetOffsetRate(get_upper, -10);  // 価格をピクセル単位でオフセット
            _IndBuffer2[icount]    = get_upper;         // インジケータ2にフラクタル上を設定
        }



自作インジケータトレンド転換アロー

いい感じでオフセットされました。
まぁ細かい部分なので、こういう微調整はインジケータが完成した後の仕上げの時に行って下さい。

最後にインプットパラメータも必要無いので削除します。
ソースコード:
// インプットパラメータ
//input int      _InputMAPeriod     = 25;           // 移動平均期間
//input double  _InputEnv           = 50;          // エンベロープ乖離幅[単位:1pips]



フラクタル用に常時算出バーを変更する

iFractals()関数はトレンド転換を判定する為に、終値が確定したバーを2本必要とします。

自作インジケータトレンド転換アロー

つまり何が言いたいかというと、トレンド転換と判断した時に3本目のバーにシンボルが表示されるという事です。
今のインジケータの作りでは直近2本しか常時更新していないので、新しいバーが生成された時にフラクタルが正しく表示されない事になります。

なので常時更新を直近2本から3本に変更する必要があります。

ソースコード:
// マクロ定義
#define    IND_MIN_INDEX         3               // 最小バー数


このインジケータは本当に大切な事を色々と教えてくれます。
四本値の大切さ、四本値は終値が確定(または確定する直前)してから利用価値が生まれる事、 テクニカル分析は日足以上の時間軸でのみ意味を成す事等々・・・
本来であれば四本値と日足で基本的な事を理解して需給が読めるようになってから、あくまでおまけとしてテクニカル分析を使うべきなのですが、 多くの人が何故かテクニカル分析に執着して四本値と時間軸に関しては無関心です。テクニカル分析をまるで魔法のツールのように崇拝する傾向があります。
(管理人の独断と偏見と妄想です。これに対して異議は受け付けませんw)


完成したサンプルソースコード


最後に出来上がったソースコードをまとめると、

ソースコード:
//+------------------------------------------------------------------+
//|                                             TestArrowFractal.mq4 |
//|                                                             yuki |
//|                                      https://yukifx.web.fc2.com/ |
//+------------------------------------------------------------------+
#property copyright "yuki"
#property link      "https://yukifx.web.fc2.com/"
#property version   "1.00"
#property strict // strictは絶対に削除しない事
#property indicator_chart_window // カスタムインジケータをチャートウインドウに表示する

// インジケータプロパティ設定
#property  indicator_buffers    2               // カスタムインジケータのバッファ数
#property  indicator_color1     clrWhite      // インジケータ1の色
#property  indicator_width1     3               // インジケータ1の太さ
#property  indicator_type1      DRAW_ARROW     // インジケータ1の描画タイプ

#property  indicator_color2     clrWhite      // インジケータ2の色
#property  indicator_width2     3               // インジケータ2の太さ
#property  indicator_type2      DRAW_ARROW     // インジケータ2の描画タイプ

// マクロ定義
#define    IND_MIN_INDEX         3               // 最小バー数

// インジケータ表示用動的配列
double     _IndBuffer1[];                          // インジケータ1表示用動的配列
double     _IndBuffer2[];                          // インジケータ2表示用動的配列


//+------------------------------------------------------------------+
//| OnInit(初期化)イベント
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer( 0, _IndBuffer1 );     // インジケータ1表示用動的配列をインジケータ1にバインドする
   SetIndexBuffer( 1, _IndBuffer2 );     // インジケータ2表示用動的配列をインジケータ2にバインドする

   SetIndexArrow( 0 , 218 );     // インジケータ1のアローシンボル設定
   SetIndexArrow( 1 , 217 );     // インジケータ2のアローシンボル設定

   return( INIT_SUCCEEDED );      // 戻り値:初期化成功
}

//+------------------------------------------------------------------+
//| OnCalculate(tick受信)イベント
//| カスタムインジケータ専用のイベント関数
//+------------------------------------------------------------------+
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[],   // Tick出来高
                const long     &volume[],        // Real出来高
                const int      &spread[])        // スプレッド
{
    int end_index = Bars - prev_calculated;  // バー数取得(未計算分)
    if ( end_index <= IND_MIN_INDEX ) {    // 直近数本は常時更新
        end_index = IND_MIN_INDEX;
    }

    if ( Bars <= IND_MIN_INDEX ) {         // ヒストリカルデータ不足時
        return 0;                            // 全て再計算が必要なので、計算済みバー数を0にして終了する
    }

    for( int icount = 0 ; icount < end_index ; icount++ ) {
        double get_lower = iFractals(                // フラクタル算出
                                       Symbol(),      // 通貨ペア
                                       Period(),      // 時間軸
                                       MODE_LOWER,   // ラインインデックス
                                       icount          // シフト
                                      );

        double get_upper = iFractals(                // フラクタル算出
                                       Symbol(),      // 通貨ペア
                                       Period(),      // 時間軸
                                       MODE_UPPER,   // ラインインデックス
                                       icount          // シフト
                                     );
    

        if ( get_lower > 0 ) {
            get_lower = GetOffsetRate(get_lower, 10); // 価格をピクセル単位でオフセット
            _IndBuffer1[icount]    = get_lower;       // インジケータ1にフラクタル下を設定
        }
        if ( get_upper > 0 ) {
            get_upper = GetOffsetRate(get_upper, -10);  // 価格をピクセル単位でオフセット
            _IndBuffer2[icount]    = get_upper;         // インジケータ2にフラクタル上を設定
        }
    }

   return( rates_total ); // 戻り値設定:次回OnCalculate関数が呼ばれた時のprev_calculatedの値に渡される
}

//+------------------------------------------------------------------+
//| 価格レートをPixel単位でオフセットする
//+------------------------------------------------------------------+
double GetOffsetRate(
    double in_rate,         // 価格レート
    int    in_offset_pixel  // オフセット(Pixel単位)
)
{
   double   ret            = in_rate; // 戻り値
   double   move_rate;                // オフセットしたレート
   datetime dummy_time;               // ダミー時間
   int      bese_axis_x;              // 取得座標X
   int      bese_axis_y;              // 取得座標Y
   int      get_window_no;            // 取得サブウインドウNo
   int      disp_pixel;               // オフセットした座標
   bool     get_bool;                 // 判定結果
     
   get_bool = ChartTimePriceToXY(             // 時間・価格値をX・Y座標に変換
                                 0,           // チャートID
                                 0,           // サブウインドウ番号
                                 Time[0],     // チャート上の時間
                                 in_rate,     // チャート上の価格
                                 bese_axis_x, // X座標
                                 bese_axis_y  // Y座標
                              );
   
   if ( get_bool == true ) {                      // 変換できた場合
      disp_pixel = bese_axis_y + in_offset_pixel; // 座標Yをオフセット
   
      get_bool = ChartXYToTimePrice(                // X・Y座標を時間・価格値に変換
                                    0,              // チャートID
                                    bese_axis_x,    // X座標
                                    disp_pixel,     // Y座標
                                    get_window_no,  // サブウインドウ番号
                                    dummy_time,     // チャート上の時間
                                    move_rate       // チャート上の価格
                                   );
   
      if ( get_bool == true ) {     // 変換できた場合
         ret = move_rate;           // 戻り値に変換後の価格を設定
      }
   }
   
   return ret;
}


スポンサーリンク
検索

↑の検索エンジンが表示されない人は、
↓の古い検索エンジンを使用して下さい。
カスタム検索
MQL4リファレンスツリー
スポンサーリンク


Copyright ©2015 MT4でEA自作しちゃお~ All Rights Reserved.


Top

inserted by FC2 system