
MQL4のチャート操作関数|Chart関数とWindow関数の読み分け

2つの系統と、読んだ値
MQL4のチャート操作関数には、2つの系統があります。ChartGetInteger・ChartSetInteger・ChartGetDoubleのように、先頭の引数でチャートID(chart_id)を指定する関数と、WindowBarsPerChart・WindowsTotalのように、プログラムを動かしているチャートだけを対象にするWindow関数です。チャートIDは、ChartIDで取れます。定数の一覧は、公式のチャートのプロパティにあります。
下のスクリプトで、同じ内容を両方の系統で読みました。見えている足の数(CHART_VISIBLE_BARSとWindowBarsPerChart)はどちらも686、左端の足の番号(CHART_FIRST_VISIBLE_BARとWindowFirstVisibleBar)はどちらも64999、ウィンドウの数(CHART_WINDOWS_TOTALとWindowsTotal)はどちらも1でした。ウィンドウのハンドルも、CHART_WINDOW_HANDLEとWindowHandleで同じ値でした。チャートの大きさは、1375×541ピクセルでした。
void ShowInfo()
{
long id = ChartID();
Print("[info] ChartID=", id);
Print("[info] visible bars: ", ChartGetInteger(id, CHART_VISIBLE_BARS),
" / WindowBarsPerChart=", WindowBarsPerChart());
Print("[info] first visible bar: ", ChartGetInteger(id, CHART_FIRST_VISIBLE_BAR),
" / WindowFirstVisibleBar=", WindowFirstVisibleBar());
Print("[info] windows: ", ChartGetInteger(id, CHART_WINDOWS_TOTAL),
" / WindowsTotal=", WindowsTotal());
Print("[info] handle: ", ChartGetInteger(id, CHART_WINDOW_HANDLE),
" / WindowHandle=", WindowHandle(Symbol(), Period()));
Print("[info] WindowHandle(USDJPY, M5)=", WindowHandle("USDJPY", PERIOD_M5));
Print("[info] size: ", ChartGetInteger(id, CHART_WIDTH_IN_PIXELS), " x ",
ChartGetInteger(id, CHART_HEIGHT_IN_PIXELS));
Print("[info] mode=", ChartGetInteger(id, CHART_MODE), " scale=", ChartGetInteger(id, CHART_SCALE),
" shift=", ChartGetInteger(id, CHART_SHIFT), " grid=", ChartGetInteger(id, CHART_SHOW_GRID));
}WindowHandleに、開いていないチャート(USDJPYの5分足)を指定すると、0が返りました。価格の上端と下端は、CHART_PRICE_MAXとCHART_PRICE_MINをChartGetDoubleで読むか、WindowPriceMaxとWindowPriceMinで読みます。サンプルでは、チャートを描き終えたあとの値が、どちらも1.12630と1.10990で一致しました。別の実行で、スクリプトを起動した直後に読んだときは、0.00000でした。
void ShowPrice()
{
long id = ChartID();
Print("[price] ChartGetDouble min/max=", DoubleToString(ChartGetDouble(id, CHART_PRICE_MIN), Digits),
" / ", DoubleToString(ChartGetDouble(id, CHART_PRICE_MAX), Digits),
" WindowPriceMin/Max=", DoubleToString(WindowPriceMin(), Digits),
" / ", DoubleToString(WindowPriceMax(), Digits));
}計測条件は、手元のWindows PC1台、MT4のビルド1492、MetaEditor 5.0.0.2425、EURUSDの1時間足(ヒストリー65,000本)です。この記事の数値は、すべてこの条件で測ったもので、ほかのビルドや口座では変わることがあります。
この記事で使う関数と戻り値
| 関数 | 戻り値 | 役割 |
|---|---|---|
| ChartGetInteger | long | 整数のプロパティを読む |
| ChartSetInteger | bool | 整数のプロパティを設定する |
| ChartScreenShot | bool | チャートを画像で保存する |
| ChartOpen | long(失敗は0) | チャートを開く |
| ChartApplyTemplate | bool | テンプレートを適用する |
| ChartWindowFind | int(失敗は−1) | サブウィンドウの番号を探す |
表の戻り値の型と失敗時の値は、計測した値ではなく、公式の各ページの記述です。ChartSetInteger・ChartScreenShot・ChartApplyTemplateのtrueは、「命令がチャートの待ち行列に入った」という意味で、処理が終わったという意味ではありません。口座やレートなど、チャート以外の情報は口座・相場情報の関数の記事にまとめています。
アドバイス別のチャートの値を読みたいときは、チャートIDを渡せるChart関数を使うよ。Window関数は、動かしているチャートだけが対象だね。
MQL4のチャート設定|ChartSetIntegerで表示を切り替える

8つの設定を変えたスクリプト
ChartSetIntegerは、チャートID・プロパティ・値の3つを渡して、設定を変えます。下のスクリプトでは、ローソク足の表示(CHART_MODE)、グリッド(CHART_SHOW_GRID)、右の余白(CHART_SHIFT)、拡大率(CHART_SCALE)、背景・前景・陽線・陰線の色を変えました。変える前と後に、ChartScreenShotで1000×560の画像を保存しています。図の上が変える前、下が変えたあとの、実際のMT4の画面です。
void ChangeAndShoot()
{
long id = ChartID();
ChartScreenShot(id, "mql4chart_before.png", 1000, 560);
Sleep(1500); // the screenshot is queued, wait for it
ChartSetInteger(id, CHART_MODE, CHART_CANDLES);
ChartSetInteger(id, CHART_SHOW_GRID, false);
ChartSetInteger(id, CHART_SHIFT, true);
ChartSetInteger(id, CHART_SCALE, 3);
ChartSetInteger(id, CHART_COLOR_BACKGROUND, clrWhite);
ChartSetInteger(id, CHART_COLOR_FOREGROUND, clrBlack);
ChartSetInteger(id, CHART_COLOR_CANDLE_BULL, clrBlue);
ChartSetInteger(id, CHART_COLOR_CANDLE_BEAR, clrRed);
Print("[set] mode right after set=", ChartGetInteger(id, CHART_MODE),
" bg right after set=", ChartGetInteger(id, CHART_COLOR_BACKGROUND));
ChartRedraw(id);
Sleep(1500);
ChartScreenShot(id, "mql4chart_after.png", 1000, 560);
Sleep(1500);
}設定の直後に値を読むと、変更はすぐに反映されていました。ローソク足の表示は、実行前が0(バー)で、設定の直後に読むと1(ローソク足)でした。背景色も、設定の直後に16777215(clrWhite)でした。公式の説明では、ChartSetIntegerのtrueは命令が待ち行列に入ったという意味です。この環境では、設定の直後に読んだこの2つの値が、どちらも変更後の値でした。
画面の描き直しには、ChartRedrawがあります。サンプルでは、色を変えたあとにこれを呼んで、待ってから撮りました。呼ばなかった場合は試していないので、必要かどうかは測っていません。ChartScreenShotは待ち行列に入る関数なので、保存の前後には、Sleepで待つ時間を入れました。
アドバイス設定は、数字を書くだけで変えられるよ。変える前後を撮っておくと、何が変わったか見比べられるね。
MQL4の画面保存|ChartScreenShotとWindowScreenShot

拡張子と中身の形式
ChartScreenShotは、チャートID・ファイル名・幅・高さを渡すと、チャートを画像にして、MQL4フォルダの中のFilesフォルダへ保存します。公式の説明では、形式はファイル名の拡張子で決まり、GIF・PNG・BMPが使えます。ファイル名は63文字までとされています。WindowScreenShotは、公式の説明ではGIFだけです。
拡張子を.gif・.png・.bmpにしたときは、ファイルの先頭のバイトを調べると、指定どおりGIF・PNG・BMPでした。.txtを指定すると、中身はBMPで、バイト数は.bmpと同じ921,654でした。WindowScreenShotに.pngを指定すると、中身はGIFで、バイト数は.gifと同じ8,995でした。どちらも、戻り値はtrueでした。拡張子と中身が違うファイルができるので、PNGが欲しいときはChartScreenShotで.pngを指定します。
long FileBytes(string name)
{
int h = FileOpen(name, FILE_READ | FILE_BIN);
if(h == INVALID_HANDLE)
return -1;
long n = (long)FileSize(h);
FileClose(h);
return n;
}
void ShotFormats()
{
long id = ChartID();
string names[5] = {"mql4chart_a.gif", "mql4chart_a.png", "mql4chart_a.bmp", "mql4chart_a.txt", "mql4chart_w.gif"};
Print("[shot] ChartScreenShot gif=", ChartScreenShot(id, names[0], 640, 360),
" png=", ChartScreenShot(id, names[1], 640, 360),
" bmp=", ChartScreenShot(id, names[2], 640, 360),
" txt=", ChartScreenShot(id, names[3], 640, 360));
Print("[shot] WindowScreenShot gif=", WindowScreenShot(names[4], 640, 360),
" png=", WindowScreenShot("mql4chart_w.png", 640, 360));
Sleep(2500);
for(int i = 0; i < 5; i++)
Print("[shot] ", names[i], " bytes=", FileBytes(names[i]));
Print("[shot] mql4chart_w.png bytes=", FileBytes("mql4chart_w.png"));
}ファイル名の長さは、63文字を超える78文字の名前でも、この環境では保存できました。ただし、公式の上限は63文字なので、守ってください。WindowScreenShotは、公式の説明では、テスターの中でも使えます。この環境では、テスターでは試していません。
アドバイスPNGで残したいなら、ChartScreenShotで.pngと書こう。WindowScreenShotは、拡張子を変えてもGIFだったよ。
MQL4のチャート開閉|開く・切り替える・閉じる

開く・変える・閉じるの実行結果
ChartOpenは、銘柄と時間足を渡すと、開いたチャートのIDを返します。失敗すると0が返ります。開けるチャートの数には、上限があります。ChartSetSymbolPeriodは、開いているチャートの銘柄と時間足を変え、ChartCloseはチャートを閉じます。開いているチャートの数は、ChartFirstとChartNextで順にたどって数えました。
int CountCharts()
{
int n = 0;
for(long c = ChartFirst(); c >= 0; c = ChartNext(c))
n++;
return n;
}
void ChartsDemo()
{
Print("[open] charts before=", CountCharts());
ResetLastError();
long nid = ChartOpen("EURUSD", PERIOD_H4);
int err = GetLastError();
Print("[open] ChartOpen id=", nid, " err=", err, " charts=", CountCharts());
Sleep(1000);
Print("[open] new chart: ", ChartSymbol(nid), " / ", ChartPeriod(nid));
Print("[open] ChartSetSymbolPeriod ret=", ChartSetSymbolPeriod(nid, "EURUSD", PERIOD_D1));
Sleep(1000);
Print("[open] after change: ", ChartSymbol(nid), " / ", ChartPeriod(nid));
Print("[open] ChartClose ret=", ChartClose(nid));
Sleep(1000);
Print("[open] charts after close=", CountCharts());
}実行前のチャートは2つでした。EURUSDの4時間足を開くと、IDが返り、エラーは0で、チャートは3つになりました。ChartSetSymbolPeriodで日足にすると、戻り値はtrueで、1秒待ってから読むと、時間足は1440分になっていました。ChartCloseのあとは、チャートが2つに戻りました。公式の説明では、銘柄や時間足を変えると、そのチャートで動いているEAは再初期化されます。この記事のサンプルは、スクリプトを別のチャートで動かしているので、この点は確かめていません。
チャートの位置を動かす関数
チャートを左右に動かすには、ChartNavigateを使います。公式の説明では、位置は先頭(CHART_BEGIN)・現在の位置(CHART_CURRENT_POS)・末尾(CHART_END)から選び、shiftで動かす足の数を指定します。この関数も待ち行列に入るので、呼んだ直後に左端の足の番号を読むと、実行のたびに違う値(64999・684・22)が返りました。呼んだ直後の値は、当てにしないでください。
アドバイス開いたチャートのIDは、あとで閉じるときにも使うよ。IDは、開いたときに変数に取っておこう。
MQL4のテンプレート適用|サブウィンドウとChartApplyTemplateの注意点

テンプレートを適用して、サブウィンドウを探す
ChartApplyTemplateは、テンプレートのファイル名を指定して、チャートに適用します。公式の説明では、ファイル名の先頭が「\\」ならMQL4フォルダからの相対、そうでなければ、実行ファイルのあるフォルダ、続いてProfilesのTemplatesフォルダの順に探します。サブウィンドウの番号はChartWindowFind(見つからないときは−1)、サブウィンドウ内のインジケーター名はChartIndicatorName、数はChartIndicatorsTotalで調べます。
void SubDemo()
{
long nid = ChartOpen("EURUSD", PERIOD_H1);
Sleep(1500);
Print("[sub] new chart windows=", ChartGetInteger(nid, CHART_WINDOWS_TOTAL));
ResetLastError();
bool ok = ChartApplyTemplate(nid, "Momentum.tpl");
int err = GetLastError();
int total = (int)ChartGetInteger(nid, CHART_WINDOWS_TOTAL);
Print("[sub] ChartApplyTemplate ret=", ok, " err=", err, " windows=", total);
Print("[sub] ChartIndicatorName(sub1)=", ChartIndicatorName(nid, 1, 0));
Print("[sub] ChartWindowFind(Momentum(8))=", ChartWindowFind(nid, "Momentum(8)"),
" missing=", ChartWindowFind(nid, "NoSuchIndicator"));
Print("[sub] YDISTANCE_1=", ChartGetInteger(nid, CHART_WINDOW_YDISTANCE, 1));
for(int w = 0; w < total; w++)
Print("[sub] window ", w, " indicators=", ChartIndicatorsTotal(nid, w));
ChartClose(nid);
}新しく開いたEURUSDのチャートにMomentum(8)などを含むテンプレートを適用すると、戻り値はtrue、エラーは0で、ウィンドウの数は1から4になりました。サブウィンドウ1の名前は「Momentum(8)」で、ChartWindowFindは1、存在しない名前は−1でした。CHART_WINDOW_YDISTANCEは、サブウィンドウ1で262ピクセルでした。インジケーターの数は、ウィンドウ0から3の順に、1・1・1・2でした。
動かしているチャートのウィンドウを調べるときは、WindowFindとWindowIsVisibleがあります。テンプレートを最初から付けて起動したチャートでは、WindowFindが「Momentum(8)」に1、存在しない名前に−1を返し、サブウィンドウ1のWindowIsVisibleは1でした。サブウィンドウがないチャートでは、WindowIsVisibleは0でした。
自分のチャートに適用すると、スクリプトが止まる
スクリプトを動かしているチャート自身に、チャートID 0でChartApplyTemplateを呼ぶと、戻り値はtrue、エラーは0でしたが、ウィンドウの数は1のままで、スクリプトは終了しました。終了の理由は、REASON_TEMPLATE(7)でした。公式の説明にも、テンプレートの適用でEAがアンロードされるとあります。そのため、サンプルは、新しいチャートを開いて、そこに適用しています。
アドバイステンプレートは、動かしているチャートではなく、新しく開いたチャートに適用しよう。自分のチャートに適用すると、スクリプトが止まるよ。
MQL4のエラー確認|GetLastErrorとコンパイルで確かめる

失敗する呼び出しと、エラー番号
チャート操作の関数は、失敗するとfalseや0を返します。理由は、GetLastError()で調べます。下のスクリプトで、わざと失敗させた4つの呼び出しを試しました。存在しないプロパティ番号9999と、読み取り専用のCHART_WINDOWS_TOTALへの設定は、どちらもfalseで、番号は4210です。存在しないチャートIDを渡すと、falseで4051です。存在しない銘柄をChartOpenに渡すと、IDは0で、4024でした。番号の意味は、公式のエラーコードの一覧で確認できます。
void TestErrors()
{
long id = ChartID();
ResetLastError();
bool ok = ChartSetInteger(id, (ENUM_CHART_PROPERTY_INTEGER)9999, 1);
Print("[err] unknown property: ret=", ok, " err=", GetLastError());
ResetLastError();
ok = ChartSetInteger(id, CHART_WINDOWS_TOTAL, 2);
Print("[err] read-only property: ret=", ok, " err=", GetLastError());
ResetLastError();
ok = ChartSetInteger(123456789, CHART_MODE, CHART_LINE);
Print("[err] bad chart id: ret=", ok, " err=", GetLastError());
ResetLastError();
long nid = ChartOpen("NOSUCHSYM", PERIOD_H1);
Print("[err] ChartOpen bad symbol: id=", nid, " err=", GetLastError());
}エラー番号は、失敗した関数の直後に読みます。Print()の引数は右から評価されるため、1行に関数を並べると、読む順番が入れ替わります。サンプルでは、先に変数に入れてから表示しました。エラーを消すには、ResetLastErrorを使います。

コンパイルと名前の照合
サンプルは、すべて同じファイルにまとめて、MetaEditorでコンパイルしました。結果は、エラー0・警告0です。途中で、FileSizeの戻り値を、long型の変数に入れる行に警告43が出たので、(long)で型を変換して消しました。
名前の照合は、サンプルに出てくる関数24個を、公式のチャート操作のページと突き合わせました。24個とも、専用のページがありました。チャートの定数19個は、すべてチャートのプロパティのページに載っていました。エラー番号の4210・4051・4024も、エラーコードの一覧にあります。
名前が公式にないと、コンパイルの時点で止まります。時間足を変える目的で書かれやすい「ChartSetInteger(0, CHART_PERIOD, PERIOD_H4)」は、CHART_PERIODが宣言されていないというエラー256になりました。CHART_PERIODは、チャートのプロパティのページにもありません。時間足を変えるのは、前の節のChartSetSymbolPeriodです。「WindowHide()」も、関数が定義されていないというエラー168で、公式のページは404でした。コードは、名前を公式で確かめてから書くのが近道です。
アドバイスエラー番号は、失敗した直後に読もう。関数の名前は、公式のページがあるか確かめてから使うと、コンパイルで悩まなくなるよ。
要点
・チャート操作の関数は、チャートIDを渡せるChart関数と、動かしているチャートだけが対象のWindow関数がある。手元のMT4では、見えている足の数・左端の足の番号・ウィンドウの数は同じ値だった
・ChartSetIntegerで、表示・色・拡大率などを変えられる。設定の直後の読み出しに、反映済みの値が返った
・ChartScreenShotに.txtを指定してもBMP、WindowScreenShotに.pngを指定してもGIFが保存された
・ChartOpenで開いたチャートは、ChartSetSymbolPeriodで変え、ChartCloseで閉じる。ChartNavigateの直後の読み出しは安定しない
・ChartApplyTemplateを動かしているチャート自身に使うと、スクリプトが止まった。新しいチャートに適用する
・サンプルはエラー0・警告0でコンパイルでき、関数24個・定数19個・エラー番号3つが公式にあった
MQL4のチャート操作のよくある質問
ChartGetIntegerとWindowBarsPerChartは、どう使い分けますか?
別のチャートを読むなら、ChartGetIntegerです。Window関数は、引数にチャートIDを取らず、プログラムを動かしているチャートだけが対象です。
スクリーンショットは、どこに保存されますか?
MQL4フォルダの中のFilesフォルダです。MT4の「ファイル」から「データフォルダを開く」で開いて探せます。ファイル名は、公式の上限が63文字です。
ChartSetIntegerで、時間足を変えられますか?
変えられません。時間足を変える関数は、ChartSetSymbolPeriodです。CHART_PERIODという定数は、公式にありません。
バックテストの中でも、スクリーンショットは撮れますか?
公式の説明では、WindowScreenShotがテスターの中で使えます。この記事では、テスターでの実行は試していません。
MQL5でも、同じ書き方で動きますか?
MQL5については、この記事では確かめていません。MQL5の関数は、MQL5のチャート操作の記事にまとめています。
MQL4のチャート操作のまとめ
MQL4のチャート操作は、チャートIDを渡せるChart関数と、動かしているチャートだけが対象のWindow関数を、目的で読み分けます。手元のMT4(ビルド1492)では、設定の変更は直後の読み出しに反映され、スクリーンショットの形式は、ChartScreenShotは.gif・.png・.bmpどおり、.txtはBMP、WindowScreenShotは.pngでもGIFでした。チャートの開閉は、ChartOpenで開いたIDを使って、ChartSetSymbolPeriodとChartCloseで進められます。
この記事の確認は、1台のPCと1つのビルドでの実行です。バックテスト中の動き、EAに使ったときの再初期化、ChartNavigateの結果、MQL5での動きは確かめていません。ほかの関数は、MQL言語リファレンスのカテゴリにあります。配列は配列の関数、インジケーターはインジケーターの関数、チャート上の線や文字はオブジェクトの関数、OnStartなどの入口はイベントハンドラ、EAの作り方はEAの作り方の記事を見てください。
この記事はMQL4の関数の情報提供で、特定の取引をすすめるものではありません。FXには価格変動のリスクがあり、元本を超える損失が出ることもあります。サンプルは、デモ口座などで動作を確かめてから使い、取引は自己責任で行ってください。
⚠ リスクに関する注意事項
本記事は情報提供を目的としており、特定の金融商品の売買を推奨するものではありません。FX取引はレバレッジ取引の特性上、預託した証拠金以上の損失が生じる可能性があります。取引の際は、ご自身の判断と責任において行ってください。詳しくは特定商取引法に基づく表記をご確認ください。






