- 1 1. mql5-create-indicatorとは何か
- 2 2. インジケーター作成の全体フロー
- 3 3. 最小コードで理解するインジケーターの仕組み
- 4 4. IndicatorBufferと描画設定(実務レベル)
- 5 5. OnCalculateの応用(差分計算と実務ロジック)
- 6 6. インジケーターの実装例(移動平均・シグナル追加)
- 7 7. よくあるエラーとトラブルシューティング(原因→対処)
- 8 8. EAとの連携方法(iCustomとCopyBufferの基本)
- 9 9. まとめ(最短で実務レベルに到達するための整理)
- 10 FAQ(よくある質問)
1. mql5-create-indicatorとは何か
MQL5における「create indicator(インジケーター作成)」とは、価格データをもとに独自の計算を行い、その結果をチャート上に可視化するプログラムを作ることです。
結論として、本記事のゴールは以下の状態に到達することです。
- 自作インジケーターを作成できる
- チャートに表示できる
- 基本的な仕組み(Buffer・OnCalculate)を理解する
MQL5では、インジケーターは単なる表示ツールではなく、EA(自動売買)と連携するためのデータ生成装置としても重要です。したがって、ここを理解することで、EA開発の幅が大きく広がります。
1.1 MQL5のインジケーターとは
MQL5のインジケーターとは、価格(Open, High, Low, Closeなど)を加工して視覚化するプログラムです。
代表例:
- 移動平均(MA)
- RSI
- MACD
これらはすべて「価格データ → 計算 → 表示」という構造になっています。
重要なポイントは以下です。
- インジケーターは「売買をしない」
- あくまで「判断材料を表示する」
- 計算結果は配列(Buffer)に格納される
初心者が混同しやすい点:
| 概念 | 役割 |
|---|---|
| インジケーター | 分析・表示 |
| EA | 売買・実行 |
この違いを理解していないと、設計段階で破綻します。
1.2 mql5-create-indicatorでできること
インジケーター作成によって、以下のことが可能になります。
- 独自ロジックの可視化(例:特殊なシグナル)
- エントリー判断の補助
- EAとの連携(後述のiCustom)
特に重要なのは「EAとの連携」です。
double value = iCustom(Symbol(), Period(), "MyIndicator", 0, 0);
このように、自作インジケーターの値をEAから取得可能です。
つまり、
- インジケーター → 計算担当
- EA → 実行担当
という分業構造が成立します。
これは実務では非常に重要で、ロジックを分離することで保守性が上がるというメリットがあります。
1.3 初心者が最初に理解すべきポイント
インジケーター作成で最も重要な本質は、以下の2点です。
① 表示と計算は分離されている
- 計算:OnCalculateで行う
- 表示:IndicatorBufferで行う
つまり、コード構造としては:
計算 → 配列に格納 → 自動的に描画
この流れです。
② OnCalculateがすべての中心
OnCalculateとは、価格データが更新されるたびに呼ばれる関数です。
ここでやることはシンプルです。
- データを取得
- 計算する
- 配列に入れる
③ 初心者がハマるポイント(重要)
以下は非常に高確率で発生します。
- Bufferに値を入れていない → 何も表示されない
- 配列のインデックスミス → エラー
- OnCalculateの理解不足 → 意図通り動かない
特に多いのが「書いたのに表示されない」問題です。
原因の9割は Buffer未設定 or 値未代入です。
2. インジケーター作成の全体フロー
インジケーター作成は複雑に見えますが、実際には決まった手順を順番に進めるだけです。
このセクションでは、初心者が迷わないように「全体像 → 実行手順」の順で整理します。
2.1 作成手順(全体像)
まずは全体の流れを把握してください。
① MetaEditorを開く
② 新規インジケーター作成
③ コードを書く
④ コンパイル
⑤ MT5でチャートに適用
重要なのは、コードを書く前に全体像を理解することです。
初心者がよく失敗するのは以下です。
- いきなりコードを書き始める
- どこにファイルが保存されるか分からない
- コンパイル後の確認方法が不明
これを防ぐため、まずは流れを固定します。
2.2 ファイル構造の理解
インジケーターは、MT5の特定フォルダに保存されます。
基本構造:
MQL5/
└ Indicators/
└ YourIndicator.mq5
ポイント:
.mq5がソースコード- コンパイル後は
.ex5が生成される(実行ファイル)
MetaEditorで作成すると、自動的にこの場所に保存されます。
注意点(重要)
- フォルダを間違えるとMT5に表示されない
- コンパイルしていないと使用不可
2.3 実行までの最短手順(初心者向け)
以下の手順をそのまま実行すれば、インジケーターが表示されます。
手順
- MetaTrader5を起動
- 「ツール → MetaQuotes Language Editor」を開く
- 「新規作成 → カスタムインジケーター」
- 名前を入力(例:MyIndicator)
- ウィザードはデフォルトでOK
- 作成されたコードをそのまま保存
- 「コンパイル(F7)」
- MT5に戻る
- ナビゲータ → インジケーター → 作成した名前をドラッグ
最小コード(そのまま動作確認用)
#property indicator_chart_window
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
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);
}
このコードは、価格をそのまま表示するだけのインジケーターです。
よくある失敗(重要)
初心者がここで止まるポイントを明示します。
① コンパイルしていない
- → MT5に表示されない
② ナビゲータに出てこない
- → フォルダが違う or コンパイル失敗
③ ドラッグしても何も表示されない
- → Buffer設定ミス(次章で解説)
④ エラーを無視している
- → コンパイルログは必ず確認
実務的な補足
- ウィザードで生成されるコードは「テンプレ」
- 実務では必ずカスタマイズする
- 最初は「動くものを作る」ことを優先
3. 最小コードで理解するインジケーターの仕組み
このセクションでは、前章で提示した最小コードを分解し、インジケーターの動作原理を正確に理解します。
ここを理解できれば、以降のカスタマイズ(ロジック追加)が可能になります。
3.1 インジケーターの基本構造(全体像)
まず、MQL5インジケーターは以下の3要素で構成されます。
① プロパティ定義(表示設定)
② 初期化処理(OnInit)
③ 計算処理(OnCalculate)
最小コードを再掲します。
#property indicator_chart_window
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
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);
}
このコードは「価格をそのまま描画」する最小構成です。
3.2 #property の役割(表示設定)
#property indicator_chart_window
これは、インジケーターをどこに表示するかを指定します。
indicator_chart_window→ メインチャート上indicator_separate_window→ サブウィンドウ(RSIなど)
注意点
- 指定を間違えると「表示されているのに見えない」状態になる
- 初心者はまず chart_window を推奨
3.3 IndicatorBuffer(表示データの本体)
double buffer[];
これは、チャートに描画されるデータを格納する配列です。
SetIndexBuffer(0, buffer);
この1行が極めて重要です。
意味:
- buffer配列を「描画対象」として登録する
本質
- Bufferに値を入れる=チャートに描画される
- 値がなければ何も表示されない
よくある失敗
- SetIndexBufferを忘れる → 何も表示されない
- 配列を複数使うのにインデックスがズレる
3.4 OnInit(初期化処理)
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
OnInitは、インジケーター読み込み時に1回だけ実行される関数です。
ここで行うこと:
- Bufferの登録
- パラメータ初期化
- 描画設定
実務ポイント
- 重い処理はここでやらない(軽量にする)
- 設定ミスはここで確定する
3.5 OnCalculate(最重要)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
これは、インジケーターの心臓部です。
役割
- 新しいデータが来るたびに呼ばれる
- 計算処理をすべてここで行う
引数の意味(初心者向け簡略)
rates_total:現在のバー数prev_calculated:前回まで計算済みの数price[]:価格データ(今回は入力)
3.6 ループ処理(描画の本体)
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
ここが実際の処理です。
意味:
- すべてのバーに対して値を設定
- その結果がそのまま描画される
本質理解
データ → 計算 → buffer[i] に代入 → 描画
3.7 初心者が必ずハマるポイント(重要)
このセクションは非常に重要です。
① bufferに値を入れていない
→ 何も表示されない(最頻出)
② インデックスのズレ
→ array out of range エラー
③ rates_totalの理解不足
→ ループ範囲ミス
④ prev_calculated未使用
→ 毎回全計算 → 無駄に重い
3.8 実務レベルの補足(パフォーマンス)
初心者はまず動かすことが優先ですが、実務では以下が重要です。
NG例(毎回全計算)
for(int i = 0; i < rates_total; i++)
改善例(差分計算)
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
for(int i = start; i < rates_total; i++)
{
buffer[i] = price[i];
}
これにより、不要な再計算を防げます。
4. IndicatorBufferと描画設定(実務レベル)
このセクションでは、インジケーターの見た目とデータ構造を決めるIndicatorBufferの実践的な使い方を解説します。
ここを理解すると、「線を表示する」だけでなく、複数ライン・シグナル表示・カスタム描画が可能になります。
4.1 IndicatorBufferの基本(復習+拡張)
IndicatorBufferとは、チャートに描画される値を格納する配列です。
double buffer[];
SetIndexBuffer(0, buffer);
ただし実務では、複数のBufferを使うケースが標準です。
例:
- 移動平均(1本)
- MACD(2本+ヒストグラム)
- シグナル表示(矢印)
4.2 複数バッファの使い方
複数のラインを描画するには、Bufferを複数定義します。
例:2本ライン
double buffer1[];
double buffer2[];
int OnInit()
{
SetIndexBuffer(0, buffer1);
SetIndexBuffer(1, buffer2);
return(INIT_SUCCEEDED);
}
OnCalculate側
for(int i = 0; i < rates_total; i++)
{
buffer1[i] = price[i];
buffer2[i] = price[i] * 1.01;
}
ポイント
- インデックス(0,1,2…)が表示順になる
- bufferとindexの対応がズレるとバグになる
4.3 描画スタイルの設定(色・線・種類)
表示はプロパティで制御します。
#property indicator_plots 2
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlue
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrRed
よく使う描画タイプ
| 種類 | 内容 |
|---|---|
| DRAW_LINE | 線 |
| DRAW_HISTOGRAM | 棒グラフ |
| DRAW_ARROW | 矢印 |
例:矢印表示
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrGreen
4.4 EMPTY_VALUEの重要性(超重要)
描画しない部分は必ず以下を使います。
buffer[i] = EMPTY_VALUE;
理由
- 値があると必ず描画される
- 不要なラインがつながる原因になる
例:条件付き表示
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
4.5 初心者がハマるポイント(重要)
この章はバグの温床です。
① indicator_plots未設定
→ 複数バッファが表示されない
② SetIndexBufferの順番ミス
→ 表示が入れ替わる
③ EMPTY_VALUE未使用
→ 意図しない線が出る
④ bufferサイズの誤解
→ ArrayResize不要(自動管理)
4.6 矢印・シグナル系インジケーターの基本
売買シグナルを出す場合は、矢印が一般的です。
例:上昇時に矢印表示
#property indicator_type1 DRAW_ARROW
for(int i = 1; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
補足
- 矢印コード(Wingdings)設定が必要な場合あり
- 表示位置は価格で決まる
4.7 実務視点:設計の分離
実務では以下の構造が推奨です。
計算ロジック → bufferに代入 → 表示設定
NG例:
- 計算と表示が混在
- 条件分岐が複雑すぎる
OK例:
- ロジック関数化
- bufferは最終出力のみ
4.8 パフォーマンスと安定性
複数バッファは負荷に影響します。
注意点
- 不要なバッファは作らない
- 差分計算を徹底
- 条件分岐を最適化
5. OnCalculateの応用(差分計算と実務ロジック)
このセクションでは、OnCalculateを実務レベルで使いこなすために、prev_calculatedを用いた差分計算とロジック設計を解説します。
結論として、OnCalculateの最適化=パフォーマンスと安定性の核心です。
5.1 prev_calculatedの本質(最重要)
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
結論
prev_calculatedは「前回までに計算済みのバー数」
つまり、
新しく追加された部分だけ計算すればよい
ということです。
5.2 差分計算の基本パターン
NG(初心者がやりがち)
for(int i = 0; i < rates_total; i++)
{
buffer[i] = price[i];
}
問題点:
- 毎回全データを再計算
- 無駄なCPU負荷
- EA併用時に遅延リスク
OK(実務標準)
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
for(int i = start; i < rates_total; i++)
{
buffer[i] = price[i];
}
ポイント
- 直前バーのみ再計算(安全性確保)
- 新規データだけ処理
5.3 なぜ「-1」するのか
prev_calculated - 1
理由:
- 直前バーは値が更新される可能性がある
- 再計算しないとズレる
例
- ティック更新中のバー
- 未確定足
結論
1本前から再計算が基本
5.4 beginパラメータの扱い
const int begin
役割
- 計算開始位置(インジケーターによる)
ただし初心者段階では:
基本的に無視してOK
実務で使う場面
- 他インジケーター連携
- 計算範囲制御
5.5 実務ロジックの書き方(重要)
インジケーターのロジックは以下の構造にすると安定します。
① 必要データ取得
② 条件判定
③ bufferに代入
例:単純なトレンド判定
for(int i = start; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
5.6 配列アクセスの安全性(必須)
初心者が最も多くエラーを出す箇所です。
NG例
if(price[i] > price[i-1])
問題:
- i=0でクラッシュ(i-1が存在しない)
安全な書き方
for(int i = MathMax(start, 1); i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
}
結論
配列参照は必ず境界チェック
5.7 よくある失敗(重要)
この章は実務で頻出です。
① prev_calculated未使用
→ 無駄な再計算
② start位置ミス
→ 計算漏れ or バグ
③ i=0問題
→ array out of range
④ EMPTY_VALUE未設定
→ ゴミ描画
5.8 パフォーマンス設計(実務)
EAと併用する場合、ここは非常に重要です。
悪影響例
- 高頻度計算 → CPU負荷増大
- VPS遅延 → 約定遅れ
改善策
- 差分計算徹底
- 不要なループ削減
- 計算量の軽量化
5.9 実務視点まとめ
OnCalculateは以下で評価されます。
| 評価軸 | 内容 |
|---|---|
| 正確性 | 計算が正しいか |
| 安定性 | エラーが出ないか |
| 軽量性 | 無駄がないか |
6. インジケーターの実装例(移動平均・シグナル追加)
このセクションでは、これまでの知識を使って実際に使えるインジケーターを実装します。
結論として、「計算ロジック → buffer代入」の型を守れば応用は無限に可能です。
6.1 移動平均インジケーターの実装(基本)
まずは最も基本となる「単純移動平均(SMA)」を実装します。
コード例(SMA)
#property indicator_chart_window
#property indicator_plots 1
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlue
input int period = 14;
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
int start = prev_calculated > 0 ? prev_calculated - 1 : period;
for(int i = start; i < rates_total; i++)
{
double sum = 0.0;
for(int j = 0; j < period; j++)
{
sum += price[i - j];
}
buffer[i] = sum / period;
}
return(rates_total);
}
ポイント解説
period:平均期間(ユーザー入力)i - j:過去データ参照period未満は計算不可→ startを調整
よくある失敗
- periodより前のバーで計算 → エラー
- 二重ループで処理が重い → 長期では非効率
6.2 パフォーマンス改善(実務視点)
上記SMAは分かりやすいですが、効率は悪いです。
改善イメージ
前回の合計を使い回す → O(n)に削減
※ただし初心者はまず正しく動かすことを優先
6.3 シグナルインジケーター(矢印表示)
次に、売買シグナルを表示する例です。
条件
- 上昇:BUYシグナル
- 下降:SELLシグナル
コード例
#property indicator_chart_window
#property indicator_plots 1
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrGreen
double buffer[];
int OnInit()
{
SetIndexBuffer(0, buffer);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
int start = prev_calculated > 0 ? prev_calculated - 1 : 1;
for(int i = start; i < rates_total; i++)
{
if(price[i] > price[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
}
return(rates_total);
}
6.4 矢印表示の実務設定(重要)
矢印は見た目調整が必要です。
追加設定例
PlotIndexSetInteger(0, PLOT_ARROW, 233);
補足
- 233:上矢印(Wingdings)
- 値は環境により異なる場合あり
6.5 複合ロジック(移動平均+シグナル)
実務では複数条件を組み合わせます。
例:MAクロス
if(ma_fast[i] > ma_slow[i] && ma_fast[i-1] <= ma_slow[i-1])
buffer[i] = price[i];
else
buffer[i] = EMPTY_VALUE;
本質
条件成立 → 値代入 → 表示
6.6 初心者がハマるポイント(重要)
この段階でエラーが急増します。
① 配列範囲ミス
→ i-1 / i-period
② EMPTY_VALUE未設定
→ 全バーに矢印
③ 条件が曖昧
→ 意図しないシグナル
④ ロジックと表示が混在
→ デバッグ困難
6.7 実務的な設計指針
インジケーター設計は以下を守ると安定します。
① 計算ロジックを分離
② bufferは出力専用
③ 条件は明確に
6.8 EA連携を前提にした設計
将来EAで使う場合は重要です。
ポイント
- buffer番号を固定
- シグナルは明確な値にする
- EMPTY_VALUEで無効化
例
double signal = iCustom(Symbol(), Period(), "MyIndicator", 0, 0);
7. よくあるエラーとトラブルシューティング(原因→対処)
このセクションでは、MQL5インジケーター作成で発生しやすい問題を、原因→対処の形で体系的に整理します。
結論として、トラブルの大半は「Buffer」「配列範囲」「コンパイル」の3点に集約されます。
7.1 表示されない(最頻出)
症状
- インジケーターを適用しても何も表示されない
主な原因
- Bufferに値を入れていない
- SetIndexBuffer未設定
- EMPTY_VALUEの誤用
- 描画タイプ未設定
対処
SetIndexBuffer(0, buffer);
buffer[i] = price[i];
チェックリスト
- bufferに実数値が入っているか
- OnCalculateが実行されているか
- indicator_plotsが設定されているか
7.2 ナビゲータに表示されない
症状
- MT5のインジケーター一覧に出てこない
主な原因
- コンパイルしていない
- コンパイルエラーがある
- 保存場所が間違っている
対処
- F7でコンパイル
- エラーログ確認
- Indicatorsフォルダに配置確認
7.3 array out of range エラー
症状
- 実行時にクラッシュまたはエラー
主な原因
price[i-1]
- i=0で参照している
対処
for(int i = MathMax(start, 1); i < rates_total; i++)
本質
配列アクセスは必ず境界チェック
7.4 indicator buffers関連エラー
症状
- 表示が崩れる・一部だけ表示
主な原因
- buffer数とindicator_plotsが不一致
- SetIndexBufferの順番ミス
対処
#property indicator_plots 2
SetIndexBuffer(0, buffer1);
SetIndexBuffer(1, buffer2);
7.5 値がずれる・遅れる
症状
- 表示がワンテンポ遅れる
主な原因
- prev_calculated未考慮
- 差分計算ミス
対処
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
7.6 すべてのバーに値が出る(誤表示)
症状
- 意図しないライン・矢印が大量に出る
主な原因
- EMPTY_VALUE未使用
対処
buffer[i] = EMPTY_VALUE;
7.7 コンパイルエラー(基本)
症状
- コンパイルできない
主な原因
- 文法ミス
- 型不一致
- セミコロン抜け
対処
- エラーメッセージを必ず読む
- 行番号を確認
7.8 パフォーマンス問題(重い)
症状
- MT5が重い・フリーズ気味
主な原因
- 全計算ループ
- 無駄な処理
対処
int start = prev_calculated > 0 ? prev_calculated - 1 : 0;
7.9 EA連携時のトラブル
症状
- iCustomで値が取れない
主な原因
- buffer番号ミス
- EMPTY_VALUE返却
- パラメータ不一致
対処
iCustom(Symbol(), Period(), "IndicatorName", ...);
チェックポイント
- buffer index確認
- 入力パラメータ一致
- ファイル名正確
7.10 実務的なトラブル回避戦略
実務では以下を徹底します。
① 小さく作る(最小構成)
② 動作確認
③ 徐々に機能追加
NG
- 一気に複雑なロジックを書く
OK
- 段階的に検証
7.11 エラーの優先度(実務判断)
優先順位は以下です。
- クラッシュ(array out of range)
- 表示されない
- 値のズレ
- パフォーマンス
8. EAとの連携方法(iCustomとCopyBufferの基本)
このセクションでは、自作インジケーターをEAから利用する方法を解説します。
結論として、MQL5でインジケーターを作る価値は、表示そのものよりも「EAから再利用できること」にあります。
実務では、インジケーターを分析担当、EAを執行担当として分離すると、保守性と再現性が大きく向上します。
8.1 EAからインジケーターを使う基本構造
MQL5では、EAから自作インジケーターを呼び出すときに、主に以下の流れを使います。
① iCustomでインジケーーターを読み込む
② ハンドルを取得する
③ CopyBufferで値を取り出す
④ 売買条件に使う
ここで重要なのは、インジケーターそのものを直接読むのではなく、Bufferの値を読むという点です。
8.2 iCustomとは何か
iCustom は、EAや別のMQL5プログラムからカスタムインジケーターを呼び出す関数です。
戻り値は、インジケーターの「ハンドル」です。ハンドルとは、対象を操作するための識別番号のようなものです。
基本形
int handle = iCustom(Symbol(), Period(), "MyIndicator");
意味
Symbol():現在の通貨ペアPeriod():現在の時間足"MyIndicator":インジケーター名
注意点
- ファイル名を正確に書く必要がある
- サブフォルダにある場合はパスを含める必要がある
- コンパイル済みでないと動作しない
8.3 inputパラメータがある場合のiCustom
自作インジケーターに input パラメータがある場合は、iCustom 側でも同じ順番で渡します。
例:インジケーター側
input int period = 14;
EA側
int handle = iCustom(Symbol(), Period(), "MyIndicator", 14);
重要
- 順番がズレると誤動作する
- 型が違うと値が正しく渡らない
- 将来パラメータを増やしたときにEA側修正が必要になる
ここは初心者が非常にハマりやすい箇所です。
インジケーターのinput定義と、EA側のiCustom引数は一致させると覚えてください。
8.4 CopyBufferで値を取得する
iCustom で取得したハンドルだけでは、まだ数値は使えません。
実際のBufferの値は CopyBuffer で取得します。
基本形
double values[];
if(CopyBuffer(handle, 0, 0, 3, values) > 0)
{
Print(values[0]);
}
引数の意味
handle:iCustomで取得したハンドル0:Buffer番号0:取得開始位置(最新バー)3:取得個数values:受け取り用配列
実務上の意味
values[0]:最新バーvalues[1]:1本前values[2]:2本前
8.5 Buffer番号の考え方
EA連携では、どのBufferに何を入れているかを明確にしておく必要があります。
例
- Buffer 0:メインライン
- Buffer 1:シグナルライン
- Buffer 2:BUYシグナル
- Buffer 3:SELLシグナル
EA側
double buy_signal[];
double sell_signal[];
CopyBuffer(handle, 2, 0, 1, buy_signal);
CopyBuffer(handle, 3, 0, 1, sell_signal);
注意点
- Buffer番号を途中で変えるとEAが壊れる
- 表示用と連携用を混在させると管理が難しくなる
実務では、Buffer設計は最初に固定するのが望ましいです。
8.6 シグナル判定の基本例
インジケーター側で、シグナルが出たバーだけ値を入れ、それ以外は EMPTY_VALUE にする設計は、EA連携と相性が良いです。
インジケーター側のイメージ
if(buy_condition)
buy_buffer[i] = Close[i];
else
buy_buffer[i] = EMPTY_VALUE;
EA側の判定例
double buy_signal[];
if(CopyBuffer(handle, 2, 0, 1, buy_signal) > 0)
{
if(buy_signal[0] != EMPTY_VALUE)
{
Print("BUY signal");
}
}
この形にすると、EAは単純に
「EMPTY_VALUEでないかどうか」 を見るだけでシグナル判定できます。
8.7 よくある失敗と注意点
EA連携では、以下の失敗が非常に多いです。
① iCustomのファイル名ミス
- 拡張子は通常不要
- フォルダ階層を間違えると取得失敗
② CopyBufferのBuffer番号ミス
- 思っている値と違うBufferを読んでしまう
- 表示は正しいのにEA判定だけズレる原因になる
③ 最新バーの扱いミス
values[0]は未確定足を含む場合がある- 確定足ベースなら
values[1]を使う設計も有効
④ EMPTY_VALUEの理解不足
- シグナルなしなのに 0 と判定してしまう
EMPTY_VALUEと数値0は別物
⑤ ハンドル生成失敗を見ていない
INVALID_HANDLEチェックを入れないと原因不明になりやすい
8.8 ハンドル生成失敗の確認方法
iCustom の結果は必ず検証してください。
int handle = iCustom(Symbol(), Period(), "MyIndicator");
if(handle == INVALID_HANDLE)
{
Print("indicator handle create failed");
return;
}
この確認が必要な理由
- ファイル名ミス
- パラメータ不整合
- インジケーター側の初期化失敗
これを入れないと、後続の CopyBuffer が失敗しても原因が特定しにくくなります。
8.9 実務での設計指針
EA連携を前提にインジケーターを作るなら、以下の方針が有効です。
① Buffer番号を固定する
② シグナルBufferはEMPTY_VALUEで管理する
③ 確定足で使うか未確定足で使うかを明示する
④ input構成を安定させる
再現性の観点で重要なこと
- 表示と売買判定のルールを一致させる
- 後からBuffer番号を変えない
- シグナルの定義を曖昧にしない
これは単なる書き方の問題ではなく、バックテスト結果と実運用結果のズレを防ぐための設計です。
8.10 初心者向けの結論
初心者がまず覚えるべき最小セットは以下です。
iCustomでインジケーターを呼ぶCopyBufferで値を読むEMPTY_VALUEでシグナル有無を判定する
この3点を理解すれば、自作インジケーターをEAへ組み込む基礎は十分です。
9. まとめ(最短で実務レベルに到達するための整理)
ここまでの内容を踏まえ、MQL5インジケーター作成の本質と最短成長ルートを整理します。
結論として、重要なのは「コード量」ではなく、構造理解と再現性のある設計です。
9.1 インジケーターの本質(再定義)
MQL5インジケーターは以下の構造で動作します。
価格データ → OnCalculateで計算 → Bufferに格納 → 自動描画
この流れを理解していれば、どんなインジケーターでも作成可能です。
核となる要素
- OnCalculate(計算エンジン)
- IndicatorBuffer(出力)
- 描画設定(見た目)
9.2 最低限覚えるべき3点(重要)
初心者はまず以下だけに集中すれば十分です。
① Bufferに値を入れると表示される
- 表示されない原因の大半はここ
② OnCalculateがすべてを制御する
- 計算・更新の中心
③ EMPTY_VALUEで描画を制御
- シグナル系では必須
9.3 実務レベルで必要な思考
単に動かすだけでは不十分です。
実務では以下の視点が必要になります。
① 差分計算(パフォーマンス)
prev_calculatedを使う → 無駄な計算を削減
② 配列安全性(安定性)
i-1 / i-period → 必ず境界チェック
③ Buffer設計(再利用性)
EA連携を前提に構造を固定
9.4 初心者が成長するための最短ルート
効率的にスキルを伸ばすには、順番が重要です。
推奨ステップ
① 最小インジケーターを作る
② 表示されることを確認
③ 条件分岐を追加
④ 複数Bufferに拡張
⑤ EAと連携
NGルート
- 最初から複雑なロジックを書く
- 理解せずコピペ
9.5 よくある停滞パターン
多くの初心者がここで止まります。
パターン①
「表示されない → 原因が分からない」
→ Buffer未設定が原因のことが多い
パターン②
「エラーが怖くて進めない」
→ 配列境界を理解すれば解決
パターン③
「ロジックが複雑すぎる」
→ 分割して考えるべき
9.6 実務視点での最重要ポイント
プロレベルでは以下が評価されます。
| 項目 | 内容 |
|---|---|
| 再現性 | 同じ結果が出るか |
| 安定性 | エラーが出ないか |
| 軽量性 | 無駄がないか |
| 拡張性 | EAと連携できるか |
9.7 長期的な応用(発展方向)
インジケーター作成は以下に発展します。
- 自動売買(EA)
- シグナル配信
- 分析ツール化
- 複合ロジック(AI・統計)
特に重要なのは、インジケーターを「部品」として扱う視点です。
9.8 結論(実務的まとめ)
最終的に重要なのは以下です。
① 構造を理解する
② 小さく作る
③ 再現性を確保する
この3点を守れば、安定したインジケーター開発が可能になります。
9.9 次にやるべきこと(実務アクション)
この記事を読んだ後にやるべきことは明確です。
- 最小コードを実際に動かす
- 自分のロジックを1つ追加する
- EAで値を取得してみる
これにより、理解が「知識」から「スキル」に変わります。
FAQ(よくある質問)
Q1. MQL5でインジケーターが表示されない原因は?
A. 多くの場合、Buffer未設定または値未代入です。まずSetIndexBufferと代入処理を確認してください。
Q2. OnCalculateは何をする関数ですか?
A. 価格データを受け取り、計算してBufferに格納する関数です。インジケーターの中核です。
Q3. EMPTY_VALUEとは何ですか?
A. 描画しないための特別な値です。シグナル表示などで必須です。
Q4. prev_calculatedは必ず使うべきですか?
A. 必須ではありませんが、パフォーマンスと安定性のため実務では必ず使用します。
Q5. EAからインジケーターを使う方法は?
A. iCustomで呼び出し、CopyBufferで値を取得します。
Q6. 配列エラー(array out of range)を防ぐ方法は?
A. インデックスの境界チェックを必ず行い、i-1やi-periodを安全に扱います。
Q7. 複数のラインを表示するには?
A. IndicatorBufferを複数定義し、indicator_plotsとSetIndexBufferを対応させます。
Q8. 初心者が最初に作るべきインジケーターは?
A. 価格をそのまま表示するシンプルなものから始めると理解しやすいです。