作るもの
たまに平均足を見たくなることがあるのですが、チャートに重ねたくないんですよね。
そこで、オシレータ系指標のように、平均足を別枠に表示するものを作ります。
参考サイト
実装
今回はインジケータを別枠に表示するので、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_type に DRAW_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;
}
//+------------------------------------------------------------------+
コメント