MQL5のインジケーターは、
`#property indicator_type1`で最初に描画タイプを決めたら、
あとは再コンパイルしないと変えられないと思っていませんか。
実際には、PlotIndexSetIntegerという関数を使うと、
チャートに適用したインジケーターを外さずに、
描画タイプをその場で切り替えられます。
この記事では、ボタンをクリックすると、
ラインとヒストグラムの表示が切り替わる、
実際に動くインジケーターを作りながら解説します。
・PlotIndexSetInteger関数の2つの書式
・ENUM_DRAW_TYPEの18種類の描画タイプ
・ボタンで描画タイプを実行中に切り替える実装
・多色系(DRAW_COLOR_*)へ切り替える際の制約
実行中に描画タイプを切り替えるとはどういうことか
まず、この記事が何を実現するのか、全体像を確認します。
#property indicator_type1は「初期値」にすぎない
`#property indicator_type1 DRAW_LINE`という指定は、
インジケーターをチャートに適用した瞬間の、
初期状態を決めているだけです。
プログラムの実行中にこの値を変える関数が、別に用意されています。
PlotIndexSetIntegerが担う役割
・PlotIndexSetIntegerは、プロットの設定を実行中に変える関数
・色や太さ、矢印の種類など、描画に関する整数プロパティ全般を変更できる
・この記事では、描画タイプ(PLOT_DRAW_TYPE)だけに絞って解説する
MQL4には同等の機能がない
MQL4の`SetIndexStyle`は、
描画スタイルを変更できる点では似ていますが、
MQL5の`plot`という概念自体が、MQL4には存在しません。
この記事はMQL5限定の仕組みを扱います。
PlotIndexSetInteger関数のシグネチャ
実行中に描画タイプを変更する、土台になる関数の書式を確認します。
2つのオーバーロード
bool PlotIndexSetInteger(int plot_index, ENUM_PLOT_PROPERTY_INTEGER prop_id, int prop_value); bool PlotIndexSetInteger(int plot_index, ENUM_PLOT_PROPERTY_INTEGER prop_id, int prop_modifier, int prop_value);
引数が3個の書式と4個の書式があります。
4個の書式は、色のインデックスなど、
「どの色番号を変えるか」を指定したいときに使います。
今回の描画タイプの変更は、3個の書式で十分です。
PLOT_DRAW_TYPEというプロパティ
`prop_id`に`PLOT_DRAW_TYPE`を渡すと、
`prop_value`に指定した値へ、描画タイプが切り替わります。
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_HISTOGRAM);
`plot_index`の0は、1本目のプロットを指しています。
戻り値とエラーチェック
戻り値は`bool`で、成功時は`true`、失敗時は`false`です。
`plot_index`が存在しない番号のとき等に、
`false`が返るため、本記事のコードでも戻り値を確認します。
ENUM_DRAW_TYPEの18種類と使い分け
`prop_value`に渡せる描画タイプの全体像を確認します。
単色系(1本のプロットで足りるもの)
| 定数 | 意味 |
|---|---|
| DRAW_LINE | 線 |
| DRAW_SECTION | 区間(値がないバーをつながない線) |
| DRAW_HISTOGRAM | ゼロラインからのヒストグラム |
| DRAW_HISTOGRAM2 | 2つの指標バッファ間のヒストグラム |
| DRAW_ARROW | 矢印 |
| DRAW_ZIGZAG | ジグザグ(バーの垂直断面を描ける) |
| DRAW_FILLING | 2レベル間の塗りつぶし |
| DRAW_BARS | バーの列として表示 |
| DRAW_CANDLES | ローソク足の列として表示 |
多色系(DRAW_COLOR_*)は色インデックス用バッファが必要
・DRAW_COLOR_LINE等の多色系は、色番号を格納する専用バッファが別途必要
・単色系から多色系へ切り替えると、バッファ未設定で正しく描画されない
・多色系を使うなら、最初から色バッファを含めて設計する必要がある
この記事で切り替えるのはDRAW_LINEとDRAW_HISTOGRAMだけ
色バッファの用意が不要な、単色系どうしの切り替えであれば、
バッファ構成を変えずに、安全に切り替えられます。
本記事のコードは、この安全な組み合わせだけを扱います。
ボタンで切り替えるインジケーターの設計
実際に画面上のボタンをクリックして切り替える仕組みを作ります。
OBJ_BUTTONの設置
ObjectCreate(0, ButtonName, OBJ_BUTTON, 0, 0, 0); ObjectSetInteger(0, ButtonName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, ButtonName, OBJPROP_XDISTANCE, 10); ObjectSetInteger(0, ButtonName, OBJPROP_YDISTANCE, 20); ObjectSetInteger(0, ButtonName, OBJPROP_XSIZE, 160); ObjectSetInteger(0, ButtonName, OBJPROP_YSIZE, 24);
チャートの左上に、クリック可能なボタンを1つ配置します。
OnChartEventでのクリック検知
if(id == CHARTEVENT_OBJECT_CLICK && sparam == ButtonName)
{
isHistogramMode = !isHistogramMode;
//ここでPlotIndexSetIntegerを呼ぶ
}
ボタンがクリックされるたびに、状態を表すフラグを反転させます。
切り替え後にChartRedraw()が必要な理由
・PlotIndexSetIntegerは、次のティックまで画面に反映されないことがある
・ChartRedraw(0)を呼べば、即座にチャートの再描画を強制できる
・ボタンのOBJPROP_STATEもfalseへ戻さないと押されたままに見える
実際に動くコード全体
ここまでの要素をまとめた、実際にMetaEditorでコンパイルできるコードです。
//+------------------------------------------------------------------+
//| PlotDrawTypeSwitch.mq5 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots 1
#property indicator_label1 "MA"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrDodgerBlue
input int InpMAPeriod = 14;//移動平均の期間
double MaBuffer[];
int maHandle = INVALID_HANDLE;
bool isHistogramMode = false;
string ButtonName = "BtnToggleDrawType";
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, MaBuffer, INDICATOR_DATA);
maHandle = iMA(_Symbol, PERIOD_CURRENT, InpMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("iMAのハンドル作成に失敗しました。エラーコード=", GetLastError());
return(INIT_FAILED);
}
ObjectCreate(0, ButtonName, OBJ_BUTTON, 0, 0, 0);
ObjectSetInteger(0, ButtonName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, ButtonName, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, ButtonName, OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, ButtonName, OBJPROP_XSIZE, 160);
ObjectSetInteger(0, ButtonName, OBJPROP_YSIZE, 24);
ObjectSetString(0, ButtonName, OBJPROP_TEXT, "表示切替: LINE");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
ObjectDelete(0, ButtonName);
}
//+------------------------------------------------------------------+
//| 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 copied = CopyBuffer(maHandle, 0, 0, rates_total, MaBuffer);
if(copied <= 0)
return(0);
return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(id == CHARTEVENT_OBJECT_CLICK && sparam == ButtonName)
{
isHistogramMode = !isHistogramMode;
bool ok;
if(isHistogramMode)
{
ok = PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_HISTOGRAM);
ObjectSetString(0, ButtonName, OBJPROP_TEXT, "表示切替: HISTOGRAM");
}
else
{
ok = PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
ObjectSetString(0, ButtonName, OBJPROP_TEXT, "表示切替: LINE");
}
if(!ok)
Print("PlotIndexSetIntegerに失敗しました。エラーコード=", GetLastError());
ObjectSetInteger(0, ButtonName, OBJPROP_STATE, false);
ChartRedraw(0);
}
}
//+------------------------------------------------------------------+
ボタンを押すたびに`isHistogramMode`が反転し、
`PlotIndexSetInteger`で描画タイプが切り替わります。
MetaEditorでのコンパイル・動作確認手順
実際に動かすまでの手順です。
- MetaTrader 5の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
- 「ファイル」→「新規作成」→「インジケーター」を選び、名前を「PlotDrawTypeSwitch」にして作成する(中身は空のテンプレートで構いません)
- テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
- F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- サブウィンドウにチャートへ適用し、左上のボタンを押すとラインとヒストグラムが切り替わることを確認する
よくあるエラーと注意点
実装・運用でつまずきやすいポイントをまとめます。
PlotIndexSetIntegerがfalseを返す
・plot_indexが、indicator_plotsの宣言数を超えていないか確認する
・本記事は1本のプロットのみなので、plot_indexは必ず0を指定する
多色系(DRAW_COLOR_*)へ切り替えると色が崩れる
前述の通り、多色系には専用の色インデックスバッファが必要です。
単色系と多色系を相互に切り替える設計にしたい場合は、
最初から色バッファを含めた本数で設計してください。
ボタンが押せない・残り続ける
`OnDeinit()`で`ObjectDelete`を呼び忘れると、
インジケーターを外してもボタンだけがチャート上に残ります。
インジケーターの着脱を繰り返す場合は、
必ずこの後始末を入れてください。
よくある質問
PlotIndexSetIntegerについて、よく検索される疑問に回答します。
描画タイプ以外にPlotIndexSetIntegerで変えられるものは?
色・太さ・矢印の種類など、
プロットに関する整数プロパティ全般を、
同じ関数で変更できます。
色を変えたい場合はPlotIndexSetInteger、
ラベルの文字列を変えたい場合はPlotIndexSetStringという使い分けです。
EAからもPlotIndexSetIntegerは使えますか?
いいえ。
この関数はカスタムインジケーター専用です。
EA(Expert Advisor)にはプロットという概念自体が存在しないため、
EA側で呼び出してもコンパイルエラーになります。
MQL4のSetIndexStyleと同じことができますか?
部分的にはできますが、設計思想が異なります。
SetIndexStyleは1回の呼び出しで、
描画タイプ・太さ・色をまとめて指定しますが、
MQL5はそれぞれ別の関数で個別に変更する設計です。
【MQL5】インジケーターの描画タイプを実行中に切り替える方法|PlotIndexSetIntegerでDRAW_LINEとDRAW_HISTOGRAMを変える:まとめ
MQL5の描画タイプは、
コンパイル時に固定されるものではなく、
PlotIndexSetIntegerを呼ぶだけで、
実行中にいつでも切り替えられます。
単色系どうしの切り替えは安全ですが、
DRAW_COLOR_*等の多色系へ切り替えるには、
色インデックス用バッファが別途必要になる点だけ、
設計時に意識してください。
コメント