【MQL5】平均足をチャートと別枠に表示したい

当ページのリンクには広告が含まれています。
目次

作るもの

たまに平均足を見たくなることがあるのですが、チャートに重ねたくないんですよね。
そこで、オシレータ系指標のように、平均足を別枠に表示するものを作ります。

参考サイト

実装

今回はインジケータを別枠に表示するので、MQLウィザードの カスタムインディケータの描画プロパティ で、サブウィンドウに表示 を選択します。

最小値は 0、最大値は 1 としておきます。

次に、既存の平均足インジケータが参考になりそうなので、ソースコードを開いておきます。

MT5のナビゲータウィンドウにて、Examples – Heiken_Ashi を右クリックし、変更 をクリックします。
すると、MetaEditor に Heiken_Ashi.mq5 が表示されます。

ここで、日本人の皆さんは、MT5の平均足インジケータの名前が
「Heikin_Ashi」ではなく、
「Heiken_Ashi」であることに注意してください。
既存のカスタムインジケータを利用する場合、正確な名前が必要になります。
詳細は後ほど。

それでは、Heiken_Ashi.mql5 を参考にしながら作っていきます。

プロパティとバッファなど

#property indicator_buffers 9
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  Red, DodgerBlue
#property indicator_label1  "Upper/Lower"

double ExtOBuffer[];
double ExtHBuffer[];
double ExtLBuffer[];
double ExtCBuffer[];
double ExtColorBuffer[];

double bufOpen[];
double bufHigh[];
double bufLow[];
double bufClose[];

int hHeiken = 0;

Heiken_Ashi.mq5 からコピーしてきて、書き換えます。

indicator_buffers は、別枠に表示する平均足の 高値、安値、始値、終値、色 と、参照する平均足の 高値、安値、始値、終値 の計9個です。

indicator_typeDRAW_COLOR_CANDLES を指定するとローソクを描画できるんですね。

indicator_color は、へ~、こう書けるんだ といった感じ。

最後に作業用バッファ(buf~[]) と、Heiken_Ashi のハンドルを格納する変数(hHeiken) を追加しておきます。

OnInit()

int OnInit()
{
    // 平均足インジケータを作成
    hHeiken = iCustom(NULL, 0, "Examples\\Heiken_Ashi");
    if (hHeiken == INVALID_HANDLE)
    {
        PrintFormat("[E] Failed to create Heiken_Ashi indicator. [%d]", GetLastError());
        return INIT_FAILED;
    }

    SetIndexBuffer(0, ExtOBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, ExtHBuffer, INDICATOR_DATA);
    SetIndexBuffer(2, ExtLBuffer, INDICATOR_DATA);
    SetIndexBuffer(3, ExtCBuffer, INDICATOR_DATA);
    SetIndexBuffer(4, ExtColorBuffer, INDICATOR_COLOR_INDEX);

    IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
    IndicatorSetString(INDICATOR_SHORTNAME, "Heikin-Ashi");
    PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);

    SetIndexBuffer(5, bufOpen, INDICATOR_CALCULATIONS);
    SetIndexBuffer(6, bufHigh, INDICATOR_CALCULATIONS);
    SetIndexBuffer(7, bufLow, INDICATOR_CALCULATIONS);
    SetIndexBuffer(8, bufClose, INDICATOR_CALCULATIONS);

    return INIT_SUCCEEDED;
}

既存のカスタムインジケータを使用する場合、iCustom関数でハンドルを取得します。

iCustom関数の定義は以下のとおり。

int iCustom(
  string           symbol,    // 銘柄名
  ENUM_TIMEFRAMES  period,    // 期間
  string           name       // フォルダ/カスタム指標名
  ...                         // 指標入力パラメータのリスト
);

symbol に NULL を指定すると、このインジケータを乗せているチャートの銘柄になります。

period に 0(ゼロ) を指定すると、このインジケータを乗せているチャートの時間軸になります。

name はカスタムインジケータの (フォルダ名+) 名前を指定します。
ここで、使用するインジケータの正確な名前が必要になります。
今回は Examples\\Heiken_Ashi です。

残りの初期化処理は、Heiken_Ashi.mq5 を参考にしています。

OnCalculate()

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    int start = prev_calculated - 1;
    if(prev_calculated == 0)
    {
        ExtLBuffer[0] = 0;
        ExtHBuffer[0] = 0;
        ExtOBuffer[0] = 0;
        ExtCBuffer[0] = 0;
        start = 1;
    }

    // 平均足を取得
    CopyBuffer(hHeiken, 0, 0, rates_total, bufOpen);
    CopyBuffer(hHeiken, 1, 0, rates_total, bufHigh);
    CopyBuffer(hHeiken, 2, 0, rates_total, bufLow);
    CopyBuffer(hHeiken, 3, 0, rates_total, bufClose);

    // 正規化した平均足を設定
    for(int i = start; i < rates_total; i++)
    {
        // 最小値と最大値を求める
        double min = low[i];
        double max = high[i];
    
        for (int j = 1; j <= 100; j++)
        {
            int idx = i - j;
            if (idx < 0)
                break;
    
            min = MathMin(min, low[idx]);
            max = MathMax(max, high[idx]);
        }

        double pw = max - min;

        // 正規化
        ExtOBuffer[i] = (bufOpen[i] - min) / pw;
        ExtHBuffer[i] = (bufHigh[i] - min) / pw;
        ExtLBuffer[i] = MathMax((bufLow[i] - min) / pw, 0) + 0.000001;
        ExtCBuffer[i] = (bufClose[i] - min) / pw;

        // 色
        if (bufOpen[i] < bufClose[i])
            ExtColorBuffer[i] = 0.0;
        else
            ExtColorBuffer[i] = 1.0;
    }

    return rates_total;
}

12~20、29行目

このようにすると、処理範囲を狭められるんですね。ほほぅ...
参考になりました。φ(..)メモメモ

32~51行目

表示領域の上限と下限を動的に変える方法が分からなかったので、平均足の高値、安値、始値、終値を 0~1 の値に正規化して表示しました。

今回は、最大値と最小値を次のように定義し、この範囲で各値を 0~1 になるように正規化しました。

最大値: 過去100本のローソク足の安値の最小値

最小値: 過去100本のローソク足の高値の最大値

50行目

安値の調整についてですが、バーが最小値に差し掛かるとローソク自体が表示されなかったので、このような対策をとりました。最小値でもダメでした。

きっと、ただならぬ事情があるのでしょう...( ´_ゝ`)フーン

ザツな対策ですみません。
私的にはこれで十分なので...

最大値のほうは、いまのところ問題は起きていません。
同様の問題がみつかったら、同じ対策を入れようと思います。

動かしてみる

作成したインジケータをチャートに ドラッグ&ドロップ してみると...

こんなかんじ。

今回はやることが単純だったし、参考になるものがあったので、サクッとできました。

これで一歩、野望に近付きました...

それではまた。

コード全体

//+------------------------------------------------------------------+
//|                                         Heikin-Ashi_SubFrame.mq5 |
//|                                            Copyright 2024, Hailu |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
// 参考: Heiken_Ashi.mql5

#property copyright "Copyright 2024, Hailu"
#property link      "https://www.mql5.com"
#property version   "1.00"

#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 1

#property indicator_buffers 9
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  Red, DodgerBlue
#property indicator_label1  "Upper/Lower"

double ExtOBuffer[];
double ExtHBuffer[];
double ExtLBuffer[];
double ExtCBuffer[];
double ExtColorBuffer[];

double bufOpen[];
double bufHigh[];
double bufLow[];
double bufClose[];

int hHeiken = 0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
    // 平均足インジケータを作成
    hHeiken = iCustom(NULL, 0, "Examples\\Heiken_Ashi");
    if (hHeiken == INVALID_HANDLE)
    {
        PrintFormat("[E] Failed to create Heiken_Ashi indicator. [%d]", GetLastError());
        return INIT_FAILED;
    }

    SetIndexBuffer(0, ExtOBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, ExtHBuffer, INDICATOR_DATA);
    SetIndexBuffer(2, ExtLBuffer, INDICATOR_DATA);
    SetIndexBuffer(3, ExtCBuffer, INDICATOR_DATA);
    SetIndexBuffer(4, ExtColorBuffer, INDICATOR_COLOR_INDEX);

    IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
    IndicatorSetString(INDICATOR_SHORTNAME, "Heikin-Ashi");
    PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);

    SetIndexBuffer(5, bufOpen, INDICATOR_CALCULATIONS);
    SetIndexBuffer(6, bufHigh, INDICATOR_CALCULATIONS);
    SetIndexBuffer(7, bufLow, INDICATOR_CALCULATIONS);
    SetIndexBuffer(8, bufClose, INDICATOR_CALCULATIONS);

    return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
    int start = prev_calculated - 1;
    if(prev_calculated == 0)
    {
        ExtLBuffer[0] = 0;
        ExtHBuffer[0] = 0;
        ExtOBuffer[0] = 0;
        ExtCBuffer[0] = 0;
        start = 1;
    }

    // 平均足を取得
    CopyBuffer(hHeiken, 0, 0, rates_total, bufOpen);
    CopyBuffer(hHeiken, 1, 0, rates_total, bufHigh);
    CopyBuffer(hHeiken, 2, 0, rates_total, bufLow);
    CopyBuffer(hHeiken, 3, 0, rates_total, bufClose);

    // 正規化した平均足を設定
    for(int i = start; i < rates_total; i++)
    {
        // 最小値と最大値を求める
        double min = low[i];
        double max = high[i];
    
        for (int j = 1; j <= 100; j++)
        {
            int idx = i - j;
            if (idx < 0)
                break;
    
            min = MathMin(min, low[idx]);
            max = MathMax(max, high[idx]);
        }

        double pw = max - min;

        // 正規化
        ExtOBuffer[i] = (bufOpen[i] - min) / pw;
        ExtHBuffer[i] = (bufHigh[i] - min) / pw;
        ExtLBuffer[i] = MathMax((bufLow[i] - min) / pw, 0) + 0.000001;
        ExtCBuffer[i] = (bufClose[i] - min) / pw;

        // 色
        if (bufOpen[i] < bufClose[i])
            ExtColorBuffer[i] = 0.0;
        else
            ExtColorBuffer[i] = 1.0;
    }

    return rates_total;
}
//+------------------------------------------------------------------+
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA



reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

目次