- 1 1. SetIndexBufferとは何か
- 2 2. SetIndexBufferの基本構文と使い方
- 3 3. バッファタイプ(INDICATOR_DATA / CALCULATIONS)の違い
- 4 4. 複数バッファを使ったインジケーター実装
- 5 5. 表示されない原因と具体的な解決方法
- 6 6. ArraySetAsSeriesとの関係と注意点
- 7 7. PlotIndexSet系関数による描画カスタマイズ
- 8 8. 実務で使える完成テンプレート(コピペ可)
- 9 9. FAQ(よくある質問と回答方針)
- 9.1 9.1 SetIndexBufferを書いているのに表示されません
- 9.2 9.2 INDICATOR_DATAとINDICATOR_CALCULATIONSの違いは何ですか?
- 9.3 9.3 SetIndexBufferはどこで呼ぶべきですか?
- 9.4 9.4 配列に値を入れているのに線が出ません
- 9.5 9.5 indicator_buffersとindicator_plotsの違いは何ですか?
- 9.6 9.6 ArraySetAsSeriesは必ず必要ですか?
- 9.7 9.7 複数バッファを使うと表示がおかしくなります
- 9.8 9.8 prev_calculatedを使うと動かなくなります
- 9.9 9.9 SetIndexBufferとPlotIndexSetはどちらが重要ですか?
- 9.10 9.10 MQL4との違いはありますか?
1. SetIndexBufferとは何か
MQL5でカスタムインジケーターを作成する際、最初に理解すべき最重要関数のひとつが「SetIndexBuffer」です。
この関数を正しく理解していないと、「値を計算しているのにチャートに表示されない」という典型的な問題に必ず直面します。
結論から言うと、SetIndexBufferは
「計算結果をチャートに表示するための配列を登録する関数」です。
MQL5では、単に配列に値を入れただけでは表示されません。
必ず「この配列を表示用データとして使う」と明示的に登録する必要があります。
1.1 SetIndexBufferの役割
SetIndexBufferの役割は非常にシンプルですが重要です。
- インジケーターの描画データを配列に紐づける
- チャートに表示するための「データの通り道」を作る
イメージとしては以下の通りです。
計算ロジック → 配列(buffer) → SetIndexBuffer → チャート表示
つまり、SetIndexBufferを使わない場合:
- 配列に値を入れても
→ チャートには一切表示されません
最低限の流れ(重要)
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer, INDICATOR_DATA);
return(INIT_SUCCEEDED);
}
この1行がないだけで、どれだけ正しい計算を書いても表示されません。
よくある失敗
- SetIndexBufferを書いていない
- OnInit以外で呼んでいる
- bufferの宣言を忘れている
これらは初心者のほぼ全員が一度は通るエラーです。
1.2 インジケーターバッファとは何か
「バッファ」という言葉が難しく感じるかもしれませんが、実体は単純です。
👉 バッファ = 値を格納する配列(double配列)
例:
double buffer[];
この配列の各要素は、チャートの各バー(ローソク足)に対応します。
- buffer[0] → 最新バー
- buffer[1] → 1本前
- buffer[2] → 2本前
※ArraySetAsSeriesの設定により逆転する場合あり(後述)
重要なポイント
- インジケーターは「配列単位」で描画される
- 1つのバッファ = 1本のライン(または描画要素)
よくある誤解
- ❌「変数に値を入れれば表示される」
- ❌「Printすれば出る」
→ 配列+SetIndexBufferが必須
1.3 なぜSetIndexBufferが必要なのか
MQL5の設計上、描画と計算は分離されています。
つまり:
- 計算 → OnCalculateで行う
- 表示 → SetIndexBufferで登録した配列のみ
この構造により:
- 高速描画(内部最適化)
- 複数ライン管理
- インジケーターの統一構造
が実現されています。
もしSetIndexBufferを使わないとどうなるか
buffer[i] = Close[i];
このように値を入れても:
- チャートに何も表示されない
- エラーも出ない(これが厄介)
実務での注意点(重要)
- 表示されない原因の80%以上がSetIndexBuffer周り
- デバッグ時はまずここを疑う
チェックリスト(必須)
- OnInitでSetIndexBufferを呼んでいるか
- bufferがdouble配列か
- INDICATOR_DATAが指定されているか
- bufferに値を入れているか
2. SetIndexBufferの基本構文と使い方
SetIndexBufferは「理解」よりも「正しく書けること」が重要です。
ここでは、そのまま使えるレベルまで具体化します。
2.1 基本構文
SetIndexBufferの基本構文は以下の通りです。
bool SetIndexBuffer(
int index,
double buffer[],
ENUM_INDEXBUFFER_TYPE type
);
各引数の意味(重要)
- index
→ バッファ番号(0から開始) - buffer[]
→ 表示・計算に使う配列 - type
→ バッファの用途(表示用 or 内部計算用)
最重要ポイント
- indexは0から始まる
- bufferはdouble配列のみ
- typeで表示可否が決まる
2.2 最小構成の使い方(これだけで動く)
まずは「絶対に動く最小構成」を理解します。
手順(初心者向け)
- 配列を宣言
- OnInitでSetIndexBufferを設定
- OnCalculateで値を入れる
コード例(最小構成)
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer, INDICATOR_DATA);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
return(rates_total);
}
このコードでやっていること
- price[](価格)をそのまま表示
- bufferに代入 → SetIndexBuffer経由で描画
動作確認のポイント
- サブウィンドウにラインが出る
- 値が更新される
2.3 index(バッファ番号)の考え方
indexは「何番目のラインか」を意味します。
例:複数ライン
SetIndexBuffer(0, buffer1, INDICATOR_DATA);
SetIndexBuffer(1, buffer2, INDICATOR_DATA);
- 0 → 1本目のライン
- 1 → 2本目のライン
注意点
- indexとPlotIndexがズレると表示されない
- indicator_buffersと一致させる必要あり
よくある失敗
- indexを1から始めてしまう
- buffer数より多いindexを指定する
2.4 type(バッファタイプ)の基本
typeは初心者が最も混乱するポイントです。
よく使う2種類
INDICATOR_DATA
INDICATOR_CALCULATIONS
違い(重要)
- INDICATOR_DATA
→ チャートに表示される - INDICATOR_CALCULATIONS
→ 内部計算用(表示されない)
初心者は基本これでOK
SetIndexBuffer(0, buffer, INDICATOR_DATA);
よくあるミス
- CALCULATIONSを使って表示されない
- typeを省略(MQL5では不可)
2.5 よくあるエラーと原因
ここは検索意図の核心です。
ケース1:何も表示されない
原因:
- INDICATOR_DATA未指定
- SetIndexBuffer未実行
ケース2:ラインが途中で消える
原因:
- bufferに値を入れていない
- 未初期化のまま使用
ケース3:値がズレる
原因:
- ArraySetAsSeries未設定
- インデックス方向の誤解
2.6 実務での重要チェックポイント
実際の開発では以下を必ず確認します。
チェックリスト
- SetIndexBufferはOnInitで呼んでいるか
- bufferはグローバルで宣言されているか
- indicator_buffersの数と一致しているか
- typeがINDICATOR_DATAになっているか
デバッグのコツ
- Printでbuffer値を確認
- 最初は単純なコピーで動作確認
3. バッファタイプ(INDICATOR_DATA / CALCULATIONS)の違い
SetIndexBufferの中でも、最も誤解されやすく、表示トラブルの原因になりやすいのが「type(バッファタイプ)」です。
ここを曖昧に理解したままだと、「計算はできているのに表示されない」という状態から抜け出せません。
3.1 INDICATOR_DATAとは(表示用バッファ)
INDICATOR_DATAは、チャートに表示されるバッファです。
SetIndexBuffer(0, buffer, INDICATOR_DATA);
この指定をした配列だけが、ラインやヒストグラムとして描画されます。
特徴
- チャートに描画される
- PlotIndexSet系と連動する
- indicator_plotsの対象になる
使用例(典型)
double mainBuffer[];
int OnInit()
{
SetIndexBuffer(0, mainBuffer, INDICATOR_DATA);
return(INIT_SUCCEEDED);
}
実務ポイント
- 「見せたいデータ」は必ずINDICATOR_DATA
- 複数ラインの場合は複数指定
よくある失敗
- INDICATOR_DATAを設定していない
- indexとplot設定が一致していない
3.2 INDICATOR_CALCULATIONSとは(内部計算用)
INDICATOR_CALCULATIONSは、表示しない計算用バッファです。
SetIndexBuffer(1, calcBuffer, INDICATOR_CALCULATIONS);
特徴
- チャートには表示されない
- 中間計算に使う
- パフォーマンス最適化に寄与
使用例(移動平均の途中計算)
double tempBuffer[];
double outputBuffer[];
int OnInit()
{
SetIndexBuffer(0, outputBuffer, INDICATOR_DATA);
SetIndexBuffer(1, tempBuffer, INDICATOR_CALCULATIONS);
return(INIT_SUCCEEDED);
}
典型用途
- EMAの途中計算
- ATRの内部値
- フィルタリング用データ
よくある誤解
- ❌「CALCULATIONSでも表示される」
→ 表示されません
3.3 両者の使い分け(重要)
ここが設計の分岐点です。
判断基準
| 用途 | 指定 |
|---|---|
| チャートに表示する | INDICATOR_DATA |
| 計算だけに使う | INDICATOR_CALCULATIONS |
実務での基本設計
表示用:最終結果 → INDICATOR_DATA
計算用:途中データ → CALCULATIONS
実例(構造イメージ)
価格 → tempBuffer(計算) → outputBuffer(表示)
3.4 初心者がハマる典型パターン
ここは検索ニーズが非常に強い部分です。
パターン1:何も表示されない
SetIndexBuffer(0, buffer, INDICATOR_CALCULATIONS);
→ 原因:CALCULATIONSにしている
パターン2:バッファはあるのに見えない
原因:
- Plot設定が不足
- indicator_plots未定義
パターン3:値は入っているのに線が出ない
原因:
- EMPTY_VALUEが混在
- 描画設定ミス
3.5 設計レベルの理解(中級者向け)
MQL5は以下の思想で設計されています。
分離設計
- 計算(CALCULATIONS)
- 表示(DATA)
これにより:
- 高速処理
- 再利用性
- 安定描画
が実現されています。
実務上のメリット
- 計算ロジックを分離できる
- バグ切り分けが容易
- パフォーマンス改善
3.6 チェックリスト(最重要)
表示されないときはここを確認します。
必須チェック
- 表示したいバッファはINDICATOR_DATAか
- indexとplotが一致しているか
- bufferに値が入っているか
デバッグ手順
- 全てINDICATOR_DATAにする
- 単純な値(Close)を代入
- 徐々にロジックを戻す
3.7 実務アドバイス(期待値ベース)
- 初期段階ではCALCULATIONSは使わない
- まず「表示されること」を優先
- その後に最適化
推奨ステップ
- INDICATOR_DATAのみで構築
- 動作確認
- CALCULATIONSに分離
4. 複数バッファを使ったインジケーター実装
SetIndexBufferは単体でも使えますが、実務では複数バッファを組み合わせて使うケースが基本です。
ここでは、複数ライン(例:メインライン+シグナル)を持つインジケーターを題材に、実装手順を具体化します。
4.1 複数バッファの基本設計
複数バッファを使う場合、以下の設計が基本になります。
buffer0 → メイン表示(INDICATOR_DATA)
buffer1 → サブ表示(INDICATOR_DATA)
buffer2 → 内部計算(INDICATOR_CALCULATIONS)
必須設定
#property indicator_buffers 3
#property indicator_plots 2
- indicator_buffers → 使用する配列数
- indicator_plots → 表示するライン数
重要ポイント
- buffers ≥ plots(必須)
- 表示する数だけplotsを設定
4.2 実装手順(テンプレート)
実務では以下の手順で組み立てます。
手順
- バッファを宣言
- indicator_buffers / plots を定義
- SetIndexBufferで紐付け
- 描画設定(PlotIndexSet系)
- OnCalculateで値を代入
4.3 実用コード例(2ライン+内部計算)
以下は「シンプルな移動平均+シグナルライン」の構成です。
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 2
double mainBuffer[];
double signalBuffer[];
double tempBuffer[];
int OnInit()
{
// バッファ登録
SetIndexBuffer(0, mainBuffer, INDICATOR_DATA);
SetIndexBuffer(1, signalBuffer, INDICATOR_DATA);
SetIndexBuffer(2, tempBuffer, INDICATOR_CALCULATIONS);
// 描画設定
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
tempBuffer[i] = price[i]; // 中間データ
mainBuffer[i] = tempBuffer[i]; // メイン
signalBuffer[i] = mainBuffer[i] * 0.9; // シグナル
}
return(rates_total);
}
このコードの構造
- tempBuffer → 内部計算
- mainBuffer → 表示1
- signalBuffer → 表示2
表示結果
- 2本のラインが描画される
- signalはmainより少し下に表示
4.4 よくある失敗(重要)
複数バッファではエラーが増えます。
ケース1:ラインが1本しか出ない
原因:
- indicator_plotsが不足
- PlotIndexSet未設定
ケース2:何も表示されない
原因:
- indexとbufferの紐付けミス
- INDICATOR_DATA不足
ケース3:配列エラー(out of range)
原因:
- bufferサイズ未初期化
- rates_total未考慮
4.5 実務での設計パターン
複雑なインジケーターでは以下の構造になります。
典型構造
価格
↓
前処理(CALCULATIONS)
↓
メインロジック(CALCULATIONS)
↓
表示用(DATA)
メリット
- ロジック分離
- デバッグ容易
- 再利用性向上
4.6 デバッグの進め方(重要)
複数バッファで問題が出た場合:
手順
- すべてINDICATOR_DATAに変更
- 単純な値(Close)を入れる
- 1本ずつ戻す
期待値の高い切り分け
- 表示問題 → SetIndexBuffer or Plot
- 計算問題 → OnCalculate
4.7 注意点まとめ
- buffer数とpropertyが一致しているか
- indexは0から順番か
- 表示用と計算用を混同していないか
実務アドバイス
- 最初は「1バッファ」で作る
- 動いたら拡張
5. 表示されない原因と具体的な解決方法
SetIndexBufferを使ったインジケーターで最も多いトラブルは、「コンパイルは通るのに何も表示されない」という問題です。
この種の不具合は、文法エラーではなく設定・紐付け・代入のどこかが欠けていることが原因です。
ここでは、実務で発生頻度の高い原因を、確認順序付きで整理します。
5.1 まず確認するべき最小チェック項目
表示されないときは、いきなり複雑なロジックを疑うのではなく、以下を上から順に確認します。
SetIndexBuffer()をOnInit()で呼んでいるか- 表示したい配列が
INDICATOR_DATAになっているか #property indicator_buffersの数が足りているか#property indicator_plotsの数が表示本数と合っているかOnCalculate()内で実際にバッファへ値を代入しているか
この5点のどれかが欠けるだけで、エラーなしで非表示になります。
5.2 原因1:SetIndexBuffer自体が未設定
最も基本的な原因です。
配列を宣言して値を入れていても、SetIndexBufferで登録していなければ、MQL5はそれを描画対象として扱いません。
失敗例
double buffer[];
int OnInit()
{
return(INIT_SUCCEEDED);
}
この状態では、buffer[] に値を入れても表示されません。
修正例
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer, INDICATOR_DATA);
return(INIT_SUCCEEDED);
}
注意点
OnCalculate()の中で毎回SetIndexBuffer()を呼ぶ必要はありません- 基本は OnInitで1回設定 です
5.3 原因2:INDICATOR_CALCULATIONSを使っている
内部計算用バッファを表示しようとしているケースです。
失敗例
SetIndexBuffer(0, buffer, INDICATOR_CALCULATIONS);
この指定では、buffer[] は計算用として扱われるため、チャートには描画されません。
修正例
SetIndexBuffer(0, buffer, INDICATOR_DATA);
判断基準
- 見せたい値 →
INDICATOR_DATA - 内部だけで使う値 →
INDICATOR_CALCULATIONS
よくある失敗
- コードを整理しようとして、全部CALCULATIONSにしてしまう
- 「値が入っているから出るはず」と思い込む
5.4 原因3:OnCalculateで値を代入していない
SetIndexBufferを設定していても、バッファの中身が空であれば表示されません。
特に、ループ条件や prev_calculated の扱いを誤ると、実質的に一度も代入されないことがあります。
失敗例
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
return(rates_total);
}
登録はされていても、何も代入していないため表示されません。
修正例
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
return(rates_total);
}
つまずきやすい点
- ループ開始位置を間違える
- 条件分岐で代入が飛ばされる
- 一部バーしか代入しておらず、表示範囲に値がない
5.5 原因4:property設定が不足している
バッファやプロットの本数に関する #property が不足していると、正しく紐付けても期待通りに出ません。
典型例
#property indicator_buffers 1
#property indicator_plots 1
この状態で2本の表示バッファを使うと、構造が合いません。
修正の考え方
- 使用する全バッファ数 →
indicator_buffers - 実際に見せるライン数 →
indicator_plots
例
#property indicator_buffers 3
#property indicator_plots 2
この場合は、
- 表示用2本
- 計算用1本
のような構成にできます。
注意点
buffersとplotsは同じ意味ではありません- 表示しない計算用バッファも
indicator_buffersには含めます
5.6 原因5:描画設定が足りない
バッファ登録だけでは不十分で、どう描くか の設定が不足している場合があります。
特に複数プロットでは、描画タイプの指定が曖昧だと意図通りに見えません。
例
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
これにより、0番目のプロットをラインとして描画します。
確認ポイント
DRAW_LINEDRAW_HISTOGRAMDRAW_ARROW
など、表示形式が目的に合っているかを確認します。
よくある失敗
- バッファはあるが、描画形式が不一致
- 矢印表示のつもりでライン設定のまま
- カラーや太さ設定以前に、描画タイプ自体が適切でない
5.7 原因6:EMPTY_VALUEや未初期化値の混在
MQL5では、描画しない要素に EMPTY_VALUE を入れることがあります。
これは正しい使い方ですが、全バーにEMPTY_VALUEを入れてしまうと当然何も見えません。
例
for(int i = 0; i < rates_total; i++)
{
buffer[i] = EMPTY_VALUE;
}
このコードだけでは全て非表示です。
使い方の原則
- 表示しないバーだけ
EMPTY_VALUE - 表示するバーには実数値を入れる
注意点
- 条件式が厳しすぎて、全バー非表示になることがある
- デバッグ時は一度
Close[i]など単純な値を入れて確認すると切り分けしやすい
5.8 原因7:インデックス方向の誤解
時系列配列は、環境や使い方によって 新しいバーが0番か、古いバーが0番か の理解を間違えやすいです。
このズレにより、値は入っていても見え方が不自然になったり、想定位置に出なかったりします。
よくある症状
- 線が逆方向に見える
- 最新バーに値が入っていない
- 一部だけおかしな場所に出る
対策
ArraySetAsSeries()の有無を確認するprice[]や独自バッファの方向を統一する- 最初は複雑な最適化をせず、単純ループで挙動確認する
実務上の考え方
表示されないというより、「正しい場所に表示されていない」 問題として出ることが多いです。
5.9 最短で切り分けるデバッグ手順
表示トラブルは、以下の順で絞り込むと早いです。
手順
-
SetIndexBuffer()があるか確認
-
INDICATOR_DATAか確認
-
indicator_buffers / indicator_plotsを確認
-
OnCalculate()でbuffer[i] = price[i];のような単純代入に変更
-
- それで表示されるなら、原因は元の計算ロジック側
実務で有効な簡易テスト
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
これで表示されれば、
- SetIndexBuffer周りは正常
- 問題は計算式または条件分岐
と判断しやすくなります。
5.10 よくある失敗のまとめ
- SetIndexBufferを書いていない
INDICATOR_CALCULATIONSを使っているOnCalculate()で値を入れていないindicator_buffersと実数が合っていないEMPTY_VALUEばかり入っている- 配列方向を誤解している
表示されない問題は、一見複雑に見えても、実際は「登録」「設定」「代入」の3系統にほぼ集約されます。
まずはこの3つを順番に潰すことが、最短での解決につながります。
6. ArraySetAsSeriesとの関係と注意点
SetIndexBufferを正しく使っても、「値は入っているのに表示がズレる」「最新バーに値が出ない」といった問題が発生する場合、ArraySetAsSeriesの扱いが原因であるケースが非常に多いです。
この章では、配列の向き(インデックス方向)を正しく理解し、バグを回避する方法を整理します。
6.1 ArraySetAsSeriesとは何か
ArraySetAsSeriesは、配列のインデックス方向(時系列の並び)を変更する関数です。
ArraySetAsSeries(array, true);
動作の違い
| 設定 | index 0 | index 1 | index 2 |
|---|---|---|---|
| false(デフォルト) | 最古 | → | 最新 |
| true(時系列) | 最新 | → | 過去 |
結論(重要)
true→ MT4風(最新が0)false→ 通常配列(古い順)
6.2 なぜ重要なのか
MQL5では、データ配列の方向が統一されていないと:
- 最新バーに値が入らない
- 線が逆方向に見える
- 一部だけ表示されない
といった問題が発生します。
典型的なズレ
buffer[0] = 最新データのつもり
しかし実際は:
- buffer[0] = 最古データ(ArraySetAsSeries=falseの場合)
→ 意図と逆になる
6.3 実務での基本ルール
混乱を防ぐため、以下のどちらかに統一します。
パターンA(推奨:MT4互換思考)
ArraySetAsSeries(buffer, true);
- buffer[0] = 最新バー
- 直感的でわかりやすい
パターンB(標準配列)
ArraySetAsSeries(buffer, false);
- buffer[0] = 最古
- C言語的な配列構造
結論
👉 初心者は「true」に統一するのが安全
6.4 実装例(正しい設定)
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer, INDICATOR_DATA);
ArraySetAsSeries(buffer, true);
return(INIT_SUCCEEDED);
}
補足
- price[] などの標準配列は通常
true(時系列)で渡される - 自作バッファと方向を揃える必要あり
6.5 よくある失敗(重要)
ここは実務で非常に多いです。
ケース1:表示が逆になる
原因:
- bufferはfalse
- priceはtrue
→ インデックスがズレる
ケース2:最新バーが更新されない
原因:
- ループ方向と配列方向が不一致
ケース3:一部だけ表示されない
原因:
- 配列方向に対して誤った範囲でループ
6.6 ループ設計の注意点
配列方向によってループの書き方が変わります。
true(推奨)
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
falseの場合
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
※同じコードでも意味が変わる点に注意
実務アドバイス
- 初期段階ではループ最適化しない
- まず正しく表示されることを優先
6.7 prev_calculatedとの関係
最適化でよく使う prev_calculated も、配列方向と密接に関係します。
よくあるミス
for(int i = prev_calculated; i < rates_total; i++)
これが正しく動かない原因:
- 配列方向の誤認識
安全な方法(初期段階)
for(int i = 0; i < rates_total; i++)
→ まずはこれで確認
6.8 デバッグの最短ルート
配列方向の問題は、以下で一発確認できます。
テストコード
buffer[0] = 100;
buffer[1] = 50;
buffer[2] = 0;
見え方で判断
- 右端に100 → 正しい
- 左端に100 → 逆
6.9 実務での統一ルール(重要)
トラブルを減らすため、以下に統一します。
推奨ルール
- 全バッファで
ArraySetAsSeries(true) - price配列と同じ方向にする
- ループは0→rates_total
NGパターン
- バッファごとに方向が違う
- 一部だけtrue/false混在
- 意図せずデフォルトに依存
6.10 まとめ(実務視点)
- SetIndexBufferだけでは不十分
- 配列方向がズレると正常に表示されない
- 初心者は trueに統一 が最も安全
7. PlotIndexSet系関数による描画カスタマイズ
SetIndexBufferで「表示するデータの登録」は完了しますが、どのように描画するか(線・色・太さ・スタイルなど)は別途設定が必要です。
この役割を担うのが PlotIndexSet系関数 です。ここを理解すると、実務レベルのインジケーター表現が可能になります。
7.1 PlotIndexSet系の役割
PlotIndexSet系は、インジケーターの見た目(レンダリング設定)を制御する関数群です。
PlotIndexSetInteger(index, property, value);
PlotIndexSetDouble(index, property, value);
PlotIndexSetString(index, property, value);
重要な関係
SetIndexBuffer → データを登録
PlotIndexSet → 見た目を設定
結論
👉 両方セットで初めて「正しく表示される」
7.2 最低限必要な設定(必須)
まずは最低限これだけでOKです。
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
意味
- 0 → バッファ番号
- DRAW_LINE → 線として描画
設定しない場合
- デフォルト描画になる
- 環境によっては意図しない表示になる
7.3 主な描画タイプ(重要)
描画タイプは用途に応じて選びます。
代表的な種類
DRAW_LINE
DRAW_HISTOGRAM
DRAW_ARROW
DRAW_NONE
用途別
- LINE → 移動平均・オシレーター
- HISTOGRAM → MACD・ボリューム
- ARROW → シグナル表示
例
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_HISTOGRAM);
7.4 色・太さ・スタイルの設定
見た目を整えるにはここが重要です。
色設定
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrBlue);
太さ
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
線の種類
PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_DASH);
実務例
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrRed);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
7.5 複数プロットの設定
複数ラインを扱う場合、それぞれに設定が必要です。
例
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrBlue);
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrGreen);
注意点
- indexごとに設定が独立
- 設定漏れ=デフォルト表示
7.6 ラベル設定(重要)
凡例(インジケーター名表示)を設定します。
PlotIndexSetString(0, PLOT_LABEL, "Main Line");
効果
- データウィンドウに表示
- 複数ラインの識別が容易
7.7 よくある失敗(重要)
描画系は見落としやすいです。
ケース1:表示されない(実は描画なし)
原因:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE);
ケース2:色が見えない
原因:
- 背景と同色
- 透明設定
ケース3:ラインが細すぎる
原因:
PLOT_LINE_WIDTH = 1
→ 視認性が低い
7.8 実務テンプレート(推奨)
以下は実務でよく使う安定構成です。
int OnInit()
{
SetIndexBuffer(0, buffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrBlue);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
PlotIndexSetString(0, PLOT_LABEL, "Indicator");
return(INIT_SUCCEEDED);
}
7.9 デバッグ視点での重要ポイント
表示されない場合:
切り分け
- SetIndexBuffer → OKか
- PlotIndexSet → DRAW_TYPEが正しいか
確認方法
一度以下に変更:
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrWhite);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 3);
→ 見えれば描画設定問題
7.10 実務アドバイス
- 最初はLINE固定でOK
- 見た目は後から調整
- 表示されることを最優先
8. 実務で使える完成テンプレート(コピペ可)
ここまでの内容を踏まえ、SetIndexBuffer・ArraySetAsSeries・PlotIndexSetを正しく組み合わせた最小かつ実用的なテンプレートを提示します。
まずはこの形で「確実に表示される状態」を作り、その後ロジックを追加してください。
8.1 最小安定テンプレート(1バッファ)
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
double buffer[];
int OnInit()
{
// バッファ登録(表示用)
SetIndexBuffer(0, buffer, INDICATOR_DATA);
// 配列方向を統一(最新バーが0)
ArraySetAsSeries(buffer, true);
// 描画設定
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrBlue);
PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
PlotIndexSetString(0, PLOT_LABEL, "Sample");
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
// 安全優先:全バー更新
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
return(rates_total);
}
このテンプレートの特徴
- 確実に表示される構成
- 配列方向の不一致を回避
- 描画設定済み
- デバッグしやすい
動作確認ポイント
- サブウィンドウにラインが表示される
- 価格に追従する
8.2 2バッファ(メイン+シグナル)
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots 2
double mainBuffer[];
double signalBuffer[];
int OnInit()
{
SetIndexBuffer(0, mainBuffer, INDICATOR_DATA);
SetIndexBuffer(1, signalBuffer, INDICATOR_DATA);
ArraySetAsSeries(mainBuffer, true);
ArraySetAsSeries(signalBuffer, true);
// メインライン
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrBlue);
// シグナルライン
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrRed);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
mainBuffer[i] = price[i];
signalBuffer[i] = price[i] * 0.9;
}
return(rates_total);
}
ポイント
- バッファごとにSetIndexBuffer
- 描画設定も個別に必要
- indicator_plotsと一致させる
8.3 内部計算バッファ付き(実務構成)
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots 1
double outputBuffer[];
double calcBuffer1[];
double calcBuffer2[];
int OnInit()
{
SetIndexBuffer(0, outputBuffer, INDICATOR_DATA);
SetIndexBuffer(1, calcBuffer1, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, calcBuffer2, INDICATOR_CALCULATIONS);
ArraySetAsSeries(outputBuffer, true);
ArraySetAsSeries(calcBuffer1, true);
ArraySetAsSeries(calcBuffer2, true);
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
for(int i = 0; i < rates_total; i++)
{
calcBuffer1[i] = price[i];
calcBuffer2[i] = calcBuffer1[i] * 2;
outputBuffer[i] = calcBuffer2[i];
}
return(rates_total);
}
実務的な意味
- calcBuffer → 中間処理
- outputBuffer → 表示
8.4 よくあるミス(テンプレ使用時)
テンプレを使っても以下で崩れます。
ミス1:property未変更
- buffers数が足りない
- plots数が一致していない
ミス2:ArraySetAsSeries忘れ
→ 表示位置ズレ
ミス3:OnCalculate未実装
→ 表示されない
ミス4:price配列の扱い誤り
→ 値が不正
8.5 実務での推奨手順(重要)
開発時は以下の順序で進めると安定します。
手順
- このテンプレをそのまま動かす
- 表示確認
- 単純ロジックに置き換え
- 本来のロジックを追加
理由
- SetIndexBufferの問題を先に潰せる
- 表示系と計算系を分離できる
8.6 デバッグ用ミニコード(最強)
問題切り分け用に使います。
for(int i = 0; i < rates_total; i++)
{
buffer[i] = i;
}
効果
- 直線が表示される
- 配列・描画が正常か確認可能
8.7 実務アドバイス(期待値最大化)
- 最初から最適化しない
- prev_calculatedは後回し
- まず「確実に出る」状態を作る
8.8 結論(重要)
SetIndexBufferは単体ではなく:
SetIndexBuffer
+
ArraySetAsSeries
+
PlotIndexSet
この3点が揃って初めて安定動作します。
9. FAQ(よくある質問と回答方針)
9.1 SetIndexBufferを書いているのに表示されません
回答方針:設定・代入・描画の3点を切り分ける
INDICATOR_DATAになっているかOnCalculate()で値を代入しているかPlotIndexSetの描画タイプが正しいか
→ この3点のどれかが欠けているケースが大半
9.2 INDICATOR_DATAとINDICATOR_CALCULATIONSの違いは何ですか?
回答方針:表示可否で明確に区別
INDICATOR_DATA→ 表示されるINDICATOR_CALCULATIONS→ 表示されない(内部用)
→ 表示したいなら必ずDATAを使う
9.3 SetIndexBufferはどこで呼ぶべきですか?
回答方針:OnInit一択と明示
- 基本は
OnInit()で1回だけ呼ぶ OnCalculate()で毎回呼ぶ必要はない
→ 初期化処理として扱う
9.4 配列に値を入れているのに線が出ません
回答方針:EMPTY_VALUEと代入漏れを疑う
- 全要素が
EMPTY_VALUEになっていないか - 条件分岐で代入されていないバーがないか
rates_total分ループしているか
9.5 indicator_buffersとindicator_plotsの違いは何ですか?
回答方針:役割分離で説明
indicator_buffers→ 全バッファ数(計算含む)indicator_plots→ 表示ライン数
→ buffers ≥ plots が必須条件
9.6 ArraySetAsSeriesは必ず必要ですか?
回答方針:必須ではないが統一が重要
- 必須ではないが、方向不一致の原因になる
- 初心者は
trueに統一するのが安全
→ 表示ズレ防止のため実質必須
9.7 複数バッファを使うと表示がおかしくなります
回答方針:index・property・紐付けの整合性確認
- indexが0から順番になっているか
indicator_buffersと一致しているか- 各バッファに対応する描画設定があるか
9.8 prev_calculatedを使うと動かなくなります
回答方針:最適化は後回しにする
- 初期段階では全ループでOK
- prev_calculatedは最適化用
→ まず表示確認 → 後で最適化
9.9 SetIndexBufferとPlotIndexSetはどちらが重要ですか?
回答方針:役割の違いを明確化
- SetIndexBuffer → データ登録(必須)
- PlotIndexSet → 見た目設定(補助)
→ まずSetIndexBufferが正しくないと何も始まらない
9.10 MQL4との違いはありますか?
回答方針:設計思想の違いを簡潔に説明
- MQL5は描画と計算が分離されている
- type(DATA / CALCULATIONS)の概念がある
→ MQL4より厳密で柔軟な設計