【MT5/MT4】見やすい日本時間表示インジケーターを無料配布!コードも全て公開

japantime-big2 無料インジケーター

MT4・MT5のチャート時間を日本時間で表示し、秒足にも対応した自社開発の無料インジケーター「japantime-big2」を配布しています。コードも全て公開中!

ご要望をいただきました

投稿者
投稿者

お世話になります。
seconds-lookは他のインジケータが使えるので重宝します。
ただ、JAPAN_TIMEのインジケータを何種類かいれて確認しましたが、1分足の時間軸、15本足で15分表示になってしまいます。
何かアドバイスが頂けたら嬉しいです。

綾瀬文也
綾瀬 文也

ご要望ありがとうございます。

MT4やMT5はそもそも秒足には対応していないので、「JAPAN_TIME」系のインジケーターは1分足が最小単位で作られています。

そこで、当社開発の「japantime-big2」に秒足に対応する機能を追加しました。

ご愛用の「JAPAN_TIME」系のインジケーターは使用できませんが、「japantime-big2」も扱いやすく作っていますので、「japantime-big2」で一度試して頂ければ幸いです。

【自社開発】日本時間表示インジケーター「japantime-big2」とは

【自社開発】日本時間表示インジケーター「japantime-big2」は、MT4・MT5のチャートに日本時間を大きく表示できるインジケーターです。

FX会社によって異なるチャートのサーバー時間を日本時間へ変換し、チャート下部へ「年/月/日(曜日)時/分/秒」「時/分/秒」「時/分」などの形式で表示します。

表示内容はボタンを押すだけで切り替えることができ、マウスを合わせた場所の日本時間を確認できる機能も搭載しています。

japantime-big2の秒足

さらに、通常の分足・時間足だけでなく、秒足チャートでも日本時間を表示できるように対応※1しています。

※1 当社オリジナル秒足インジケーター「seconds-look」に対応しています。

機能と使い方

japantime-big2の
機能と使い方

Cボタン

Cボタンは、日本時間として表示する内容を切り替えるボタンです。

※チェンジのCです。

押すたびに、

年 月 日 曜日 時 分 秒 → 年 月 日 時 分 → 時 分 秒 → 時 分 → 月 日 → 月

の順番で切り替わります。

年 月 日 曜日 時 分 秒

例:2026年8月21日(金)10:30:15

年・月・日・曜日・時・分・秒まで確認したい場合に使用します。

年 月 日 時 分

例:2026年8月21日(金)10:30

秒を表示せず、日付と時間をまとめて確認できます。

時 分 秒

例:10:30:15

日付を省略して、時間を秒単位まで確認したい場合に使用します。

時 分

例:10:30

一般的なチャート時間としてシンプルに表示したい場合に使用します。

月 日

例:8月21日

時間を表示せず、日付だけを確認できます。

例:8月

長期間のチャートを表示し、月の変わり目を確認したい場合に使用します。

表示モード 表示例
年月日時分秒 2026年8月21日(金)10:30:15
年月日時分 2026年8月21日(金)10:30
時分秒 10:30:15
時分 10:30
月日 8月21日
8月

Lボタン

japantime-big2のLボタン

Lボタンは、マウスを合わせた場所の日本時間を確認する機能です。

Lボタンをオンにすると、チャート上へ縦の点線が表示され、マウスを合わせているローソク足の日本時間がチャート上部へ表示されます。

過去のローソク足が日本時間で何時だったのかを確認したい時に使用してください。

もう一度Lボタンを押してオフにすると、縦線と日本時間の表示は消えます。

サマータイムに対応

FX会社のサーバー時間は、夏時間と冬時間によって日本との時差が変わる場合があります。

japantime-big2では、サマータイム方式とサーバーGMTを設定することで、その時期に合わせて日本時間との時差を計算します。

サマータイム方式は、

設定 内容
米国方式 米国のサマータイムに合わせて計算
欧州方式 欧州のサマータイムに合わせて計算

から選択できます。

使用しているFX会社のサーバー時間に合わせて設定してください。

時間足ごとに表示間隔を設定

日本時間をすべてのローソク足へ表示すると、文字が重なって見づらくなってしまいます。

そのためjapantime-big2では、時間足ごとに何分間隔で日本時間を表示するか設定できます。

例えば1分足では30分ごと、5分足では60分ごと、15分足では120分ごとのように、それぞれ別々に設定できます。

さらに、チャートを拡大・縮小した場合は文字同士が重なりにくいように表示する場所を調整します。

【オリジナル機能】秒足チャートにも対応

japantime-big2の
オリジナル機能

japantime-big2のオリジナル機能は、通常の分足・時間足だけでなく、秒足チャートでも日本時間を表示できる事です。

一般的な日本時間表示インジケーターでは、1分足以上の通常チャートを前提として作られているものが多く、秒足チャートでは正しい時間を表示出来ません。

japantime-big2では、秒足用に作成されたチャートを判別し、秒足の時間を実際のサーバー時間へ合わせてから日本時間を計算します。

そのため、短い時間の値動きを確認する秒足チャートでも日本時間を確認できます。

秒足を作成するインジケーターではありません

japantime-big2単体で1秒足や5秒足を作成するわけではありません。

秒足を作成するプログラムによって作られた秒足チャート上で、日本時間を正しく表示するための機能です。

通常の分足・時間足で使用する場合は、秒足用の設定を変更する必要はありません。

秒足では秒まで表示

通常の時間足でLボタンを使用した場合は「年月日・曜日・時・分」を表示します。

秒足チャートでは、秒単位の位置まで確認できるように、

2026/08/21(金) 10:30:15

のように秒まで含めて日本時間を表示します。

秒足で短い値動きを確認する場合でも、何時何分何秒のローソク足なのかを確認できます。

パラメーターの設定(インプット)

japantime-big2のインプット画面

サマータイム方式

サーバーが採用しているサマータイム方式を設定します。

米国方式または欧州方式から選択します。

初期値:米国方式

サーバーGMT

使用しているFX会社のサーバーGMTを設定します。

GMT+2 / GMT+3、GMT+1 / GMT+2、GMT+0 / GMT+1、GMT+3固定、GMT+0固定から選択できます。

初期値:GMT+2 / GMT+3

文字サイズ

チャート下部へ表示する日本時間の文字サイズを設定します。

初期値:11

文字色

チャート下部へ表示する日本時間の色を設定します。

初期値:白

年月日時分秒の文字表示間隔

「年月日時分秒」で表示している時に、文字同士をどれだけ離して表示するかを設定します。

初期値:200

年月日時分の文字表示間隔

「年月日時分」で表示している時の文字間隔です。

初期値:200

時分秒の文字表示間隔

「時分秒」で表示している時の文字間隔です。

初期値:200

時分の文字表示間隔

「時分」で表示している時の文字間隔です。

初期値:200

月日の文字表示間隔

「月日」で表示している時の文字間隔です。

初期値:200

月の文字表示間隔

「月」で表示している時の文字間隔です。

初期値:200

カーソル線の色

Lボタンをオンにした時に表示される縦線の色を設定します。

初期値:黄色

カーソルの日本時間文字色

Lボタンをオンにした時に表示される日本時間の文字色を設定します。

初期値:黄色

カーソルの日本時間背景色

Lボタンをオンにした時に表示される日本時間の背景色を設定します。

初期値:黒

秒足ごとの表示間隔

1秒足・5秒足・15秒足・20秒足・25秒足・30秒足・35秒足・40秒足・45秒足・50秒足・55秒足について、それぞれ何秒ごとに日本時間を表示するか設定できます。

時間足ごとの表示間隔

1分足以上のチャートについて、それぞれ何分ごとに日本時間を表示するか設定できます。

時間足が大きくなるほど、初期設定の表示間隔も大きくしています。

日本時間表示インジケーターとは

日本時間表示
インジケーターとは

MT4・MT5のチャートに表示されている時間は、必ずしも日本時間ではありません。

多くのFX会社では取引サーバーの時間がチャートへ表示されているため、日本に住んでいる場合、

「このローソク足は日本時間の何時なのか」

を確認するには時差を計算する必要があります。

例えばサーバーがGMT+2、日本がGMT+9の場合は7時間の差があります。

さらにサマータイムに入るとサーバー側がGMT+3へ変わり、日本との時差が6時間になる場合があります。

日本時間表示インジケーターは、このサーバー時間と日本時間の時差を計算し、チャート上で日本時間を直接確認できるようにするツールです。

過去チャートを確認する場合や、日本時間で経済指標・市場の開始時間などを確認する場合にも便利です。

搭載されている「ロジック」の仕組み

日本時間へ変換する
仕組み

「japantime-big2」は、チャートに記録されているサーバー時間を取得し、設定したサーバーGMTとサマータイム方式を使って日本時間へ変換します。

計算条件1:サーバー時間を取得する

まず、表示するローソク足のサーバー時間を取得します。

例えばチャート上の時間が「10:00」だった場合、この10:00を日本時間へ変換するための基準にします。

計算条件2:夏時間か冬時間かを確認する

次に、その日付がサマータイム期間に入っているか確認します。

米国方式を選択している場合は米国方式、欧州方式を選択している場合は欧州方式の日付を使って判定します。

計算条件3:日本との時差を加える

例えばサーバーGMTがGMT+2 / GMT+3の場合、

冬時間:日本 GMT+9 − サーバー GMT+2 = 7時間

夏時間:日本 GMT+9 − サーバー GMT+3 = 6時間

となります。

チャートのサーバー時間へ、この時差を加えることで日本時間を求めます。

秒足の場合

秒足チャートの場合は、秒足用チャートの時間をそのまま通常の分足として扱わず、秒足の長さに合わせて実際のサーバー時間へ戻してから日本時間を計算します。

これにより、秒足でも「何時何分何秒」の位置なのかを確認できるようにしています。

よくある質問

japantime-big2で
よくある質問

Q.表示されている日本時間がずれています

まず、インプット画面の「サーバーGMT」と「サマータイム方式」を確認してください。

japantime-big2は、設定されたサーバーGMTを基準に日本時間を計算します。

使用しているFX会社のサーバーGMTと設定が違っている場合、日本時間もずれて表示されます。

夏時間と冬時間でGMTが変わるFX会社の場合は、その組み合わせに合った設定を選択してください。

Q.Lボタンは何のためにありますか?

マウスを合わせたローソク足の日本時間を確認するためのボタンです。

Lボタンをオンにすると縦線と日本時間が表示され、マウスの移動に合わせて確認する場所も移動します。

必要ない場合はLボタンをオフにしてください。

Q.日本時間の文字がすべてのローソク足に表示されません

不具合ではありません。

すべてのローソク足へ日本時間を表示すると文字同士が重なってしまうため、設定した表示間隔に合わせて表示しています。

また、チャートの拡大・縮小状態に合わせて、文字同士が近すぎる場合は表示を間引きます。

もっと細かく表示したい場合は、インプット画面の表示間隔を小さくしてください。

Q.チャートを拡大・縮小すると表示される日本時間の数が変わります

正常な動作です。

チャートを縮小して多くのローソク足を表示すると、日本時間の文字同士も近くなります。

文字が重ならないように表示数を自動で調整していますので、そのままご使用ください。

japantime-big2を無料ダウンロード

japantime-big2はMT4/MT5専用のインジケーターです。MT4/MT5の導入方法は関連記事をご確認ください。

【簡単】MT4・MT5の導入~インジケーター導入方法を動画で紹介!
MT4・MT5の導入方法~インジケーターの導入方法を動画付きで分かりやすく紹介しています。また、導入方以外にも、MT4・MT5の注意点やおすすめの業者も紹介しています。

綾瀬文也
綾瀬 文也

※二次配布や販売、自作発言は禁止です。
※本ツールによる損害の責任は負いかねます。
※学習用としてご活用ください。
※シェアして頂けると助かります。

【当サイトオリジナル】インジケーターが全て無料!
無料 30種類を超える当サイトオリジナルのインジケーターがすべて無料になっています。取引を快適にするツールを多く取り揃えていますので、是非ご活用下さい。
【全64種類】おすすめのMT4/MT5インジケーターを無料配布(当サイトオリジナル)
【全64種類】MT4/MT5で使えるおすすめのインジケーターとサインツールを紹介しています。どのツールも当社オリジナルのもので、完全無料になっていますので是非ご活用下さい。FXやバイナリオプションの分析用としてご活用下さい。
↑こちらのページにまとめています。

インジケーター依頼

Japantime-big2【MT5】のコードを公開

コードはコピペでそのまま使えます。

学習用としてご活用下さい。二次配布は固く禁止しています。


#property copyright "pokyun.com"
#property link "https://pokyun.com/"
#property description "※二次配布や販売、自作発言は禁止です。"
#property description "※本ツールによる損害の責任は負いかねます。"
#property description "※学習用としてご活用下さい。"
#property version "1.00"
#property strict           // バージョン番号

//--- インジケータの基本設定 ---
#property indicator_separate_window     // メインチャートではなく、サブウィンドウに表示する
#property indicator_buffers 1      // バッファを1つ確保
#property indicator_plots   0      // プロット(描画設定)を1つ確保
#property indicator_type1   DRAW_NONE // 線は「描画しない(透明)」設定にする

double DummyBuffer[]; // サブウィンドウ確保用のダミー配列

#property indicator_height 35           // サブウィンドウの高さを「35ピクセル」に固定

// 「文字を常に画面の『真ん中』に表示させるために、画面の上下の範囲を固定する設定
#property indicator_minimum 0.0         // 縦軸の最小値を0.0に固定
#property indicator_maximum 2.0         // 縦軸の最大値を2.0に固定(これで高さが固定される)



// enum(列挙型)を使い、サマータイム方式を決められた候補から選べるようにします。
enum ENUM_DST_TYPE
  {
   DST_US, // 米国方式
   DST_EU  // 欧州方式
  };

// サーバーのGMT設定も列挙型にして、入力画面で決められた候補から選択できるようにします。
enum ENUM_SERVER_GMT
  {
   SERVER_GMT_2_3, // GMT+2 / GMT+3
   SERVER_GMT_1_2, // GMT+1 / GMT+2
   SERVER_GMT_0_1, // GMT+0 / GMT+1
   SERVER_GMT_3_3, // GMT+3 固定
   SERVER_GMT_0_0  // GMT+0 固定
  };

input group "=== サマータイム設定 ==="          // ★追加
input ENUM_DST_TYPE Settei_DST_Type = DST_US; // サマータイム方式
input ENUM_SERVER_GMT Settei_Server_GMT = SERVER_GMT_2_3; // サーバーGMT

//====================================================================
// ユーザーが設定画面で変更できるパラメータ (input変数)
//====================================================================
input group "=== 文字と見た目の設定 ==="         // 設定画面でのグループ分け表示
input int    Settei_Moji_Size     = 11;         // 文字サイズ
input color  Settei_Moji_Color       = clrWhite;   // 文字色
input int    Settei_Moji_Kankaku_GatsuHiJifunByou = 200; // 年月日時分秒の文字表示間隔
input int    Settei_Moji_Kankaku_NenGatsuHiJifun = 200;  // 年月日時分の文字表示間隔
input int    Settei_Moji_Kankaku_JifunByou       = 200; // 時分秒の文字表示間隔
input int    Settei_Moji_Kankaku_Jifun           = 200; // 時分の文字表示間隔
input int    Settei_Moji_Kankaku_GatsuHi         = 200; // 月日の文字表示間隔
input int    Settei_Moji_Kankaku_Gatsu           = 200; // 月の文字表示間隔

input group "=== カーソル(十字線)の設定 ==="     // カーソル関連のグループ
input color  Settei_Cursor_Sen_Color  = clrYellow; // カーソル線の色
input color  Settei_Cursor_Moji_Color = clrYellow; // 日本時間の文字色
input color  Settei_Cursor_Haikei   = clrBlack;   // 日本時間の背景色

//--- 秒足ごとのグリッド間隔設定 ---
input group "=== 秒足ごとの表示間隔(秒) ===" // 各秒足で何秒ごとに表示するか
input int Kankaku_S1_Byou  = 30;              // 1秒足の表示間隔
input int Kankaku_S5_Byou  = 60;              // 5秒足の表示間隔
input int Kankaku_S15_Byou = 60;              // 15秒足の表示間隔
input int Kankaku_S20_Byou = 120;             // 20秒足の表示間隔
input int Kankaku_S25_Byou = 120;             // 25秒足の表示間隔
input int Kankaku_S30_Byou = 120;             // 30秒足の表示間隔
input int Kankaku_S35_Byou = 180;             // 35秒足の表示間隔
input int Kankaku_S40_Byou = 180;             // 40秒足の表示間隔
input int Kankaku_S45_Byou = 180;             // 45秒足の表示間隔
input int Kankaku_S50_Byou = 300;             // 50秒足の表示間隔
input int Kankaku_S55_Byou = 300;             // 55秒足の表示間隔

//--- 時間足ごとのグリッド間隔設定 ---
input group "=== 時間足ごとの表示間隔(分) ===" // 各時間足で何分ごとに表示するか
input int Kankaku_M1_Fun  = 30;               // 1分足の表示間隔
input int Kankaku_M2_Fun  = 30;               // 2分足の表示間隔
input int Kankaku_M3_Fun  = 30;               // 3分足の表示間隔
input int Kankaku_M4_Fun  = 60;               // 4分足の表示間隔
input int Kankaku_M5_Fun  = 60;               // 5分足の表示間隔
input int Kankaku_M6_Fun  = 60;               // 6分足の表示間隔
input int Kankaku_M10_Fun = 60;               // 10分足の表示間隔
input int Kankaku_M12_Fun = 120;              // 12分足の表示間隔
input int Kankaku_M15_Fun = 120;              // 15分足の表示間隔
input int Kankaku_M20_Fun = 240;              // 20分足の表示間隔
input int Kankaku_M30_Fun = 240;              // 30分足の表示間隔
input int Kankaku_H1_Fun  = 480;              // 1時間足の表示間隔
input int Kankaku_H2_Fun  = 720;              // 2時間足の表示間隔
input int Kankaku_H3_Fun  = 1440;             // 3時間足の表示間隔
input int Kankaku_H4_Fun  = 1440;             // 4時間足の表示間隔
input int Kankaku_H6_Fun  = 1440;             // 6時間足の表示間隔
input int Kankaku_H8_Fun  = 1440;              // 8時間足の表示間隔
input int Kankaku_H12_Fun = 1440;             // 12時間足の表示間隔
input int Kankaku_D1_Fun  = 14400;            // 日足の表示間隔
input int Kankaku_W1_Fun  = 72000;            // 週足の表示間隔
input int Kankaku_MN1_Fun = 259200;           // 月足の表示間隔



//====================================================================
// グローバル変数(プログラム全体で共通して使う変数)
//====================================================================
string Obj_Namae_No_Atama   = "JST_Moji_";      // 作成する文字オブジェクトの名前の先頭部分

// カーソル(縦線とラベル)の名前を決めておく
string Cursor_Tatesen_Namae = "JST_Cursor_Tatesen"; // 縦線の名前
string Cursor_Label_Namae   = "JST_Cursor_Label";   // 時刻ラベルの名前

// ON/OFFボタンの名前と状態
string Button_Waku_Namae    = "JST_Button_Waku";    // ボタンの「枠」の名前
string Button_Moji_Namae    = "JST_Button_Moji";    // ボタンの「文字」の名前
bool   Button_Switch_ON     = false;                 // ボタンの状態(trueならON、falseならOFF)

// 表示内容切り替え用「C」ボタンの名前と状態
string C_Button_Waku_Namae  = "JST_C_Button_Waku";  // Cボタンの「枠」の名前
string C_Button_Moji_Namae  = "JST_C_Button_Moji";  // Cボタンの「文字」の名前
int    C_Hyouji_Mode        = 0;                     // 0:年月日時分秒 1:年月日時分 2:時分秒 3:時分 4:月日 5:月

string Week_Names[] = {"日", "月", "火", "水", "木", "金", "土"}; //曜日用の配列


//+------------------------------------------------------------------+
//| 【関数】秒足コードで作られたカスタムシンボルか確認して秒数を取得する
//+------------------------------------------------------------------+
// 戻り値intで、現在のシンボルが秒足なら「何秒足か」を返し、通常足なら0を返す関数です。
int Byou_Ashi_Get_Byousuu()
{
   // 現在のシンボル名の中から「_S」が始まる位置を探します。秒足名かどうかを見分ける手掛かりです。
   int p = StringFind(_Symbol, "_S");
   // 「_S」が見つからない場合は秒足ではないので、ここで0を返してこの関数を終了します。
   if(p < 0) return 0;

   // 「_S」の直後から文字を切り出し、S15なら「15」の部分だけを取得します。
   string sec_text = StringSubstr(_Symbol, p + 2);
   // 切り出した秒数の文字列を整数へ変換します。
   int sec = (int)StringToInteger(sec_text);

   // 秒数が0以下なら正しい秒足名ではないと判断し、0を返します。
   if(sec <= 0) return 0;
   // カスタムシンボルでなければ、この秒足コードで作ったシンボルではないため0を返します。
   if(!(bool)SymbolInfoInteger(_Symbol, SYMBOL_CUSTOM)) return 0;

   // ここまで条件を通過した場合だけ、取得した秒数を呼び出し元へ返します。
   return sec;
}


//+------------------------------------------------------------------+
//| 【関数】秒足コードの仮想時間を、元の実際のサーバー時間へ戻す
//+------------------------------------------------------------------+
// 秒足コード内の仮想的な時間を、元シンボルの実際のサーバー時間へ換算する関数です。
datetime Byou_Ashi_Jissai_Jikan(datetime Kasou_Jikan)
{
   // まず現在のカスタムシンボルが何秒足なのかを取得します。
   int sec = Byou_Ashi_Get_Byousuu();
   // 秒足ではない場合は換算不要なので、受け取った時間をそのまま返します。
   if(sec <= 0) return Kasou_Jikan;

   // 現在のシンボル名の中から「_S」が始まる位置を探します。秒足名かどうかを見分ける手掛かりです。
   int p = StringFind(_Symbol, "_S");
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(p < 0) return Kasou_Jikan;

   // 「_S」より前を取り出し、秒足の元になった通貨ペア名を取得します。
   string moto_symbol = StringSubstr(_Symbol, 0, p);

   // 現在のサーバー時刻をミリ秒単位へ直し、実時間の基準値として用意します。
   long ima_real_msc = (long)TimeCurrent() * 1000L;

   // 元シンボルの最新Tick情報を受け取るための専用構造体を用意します。
   MqlTick moto_tick;
   // 元シンボルの最新Tickを取得でき、ミリ秒時刻も有効な場合だけ中の処理を行います。
   if(SymbolInfoTick(moto_symbol, moto_tick) && moto_tick.time_msc > 0)
   {
      // 取得できた最新Tickの時刻を、より正確な現在時刻として採用します。
      ima_real_msc = (long)moto_tick.time_msc;
   }

   // カスタムシンボルの最新M1バー開始時刻を取得し、仮想時間側の基準にします。
   datetime saishin_kasou_m1 = iTime(_Symbol, PERIOD_M1, 0);
   // 最新バー時刻を取得できなければ安全のため換算せず、そのまま返します。
   if(saishin_kasou_m1 <= 0) return Kasou_Jikan;

   // 秒足の秒数をミリ秒へ変換します。
   long sec_msc = (long)sec * 1000L;
   // 現在時刻を秒足の区切り位置へ切り下げ、実時間側の基準スロットを作ります。
   long ima_real_slot_msc = ima_real_msc - (ima_real_msc % sec_msc);

   // 対象の仮想時間が最新M1基準からどれだけ離れているかをミリ秒で計算します。
   long kasou_sa_msc = ((long)Kasou_Jikan - (long)saishin_kasou_m1) * 1000L;
   // 仮想M1上の時間差を、実際の秒足間隔に合わせた時間差へ縮尺変換します。
   long real_sa_msc  = kasou_sa_msc * (long)sec / 60L;

   // 実時間の基準に換算後の差を足し、秒単位のdatetimeとして返します。
   return (datetime)((ima_real_slot_msc + real_sa_msc) / 1000L);
}


//+------------------------------------------------------------------+
//| 【関数】今の秒足に合わせて「何秒間隔」にするか決める場所
//+------------------------------------------------------------------+
// 秒足の種類に応じて、インプットで設定された表示間隔(秒)を返す関数です。
int Kankaku_Get_Byou(int Byou_Ashi)
{
   int kankaku = Byou_Ashi; // とりあえず現在の秒足と同じ秒数を入れておく

   // 今の秒足がどれかによって分岐
   // switch文で値を確認し、一致したcaseの処理だけを実行します。
   switch(Byou_Ashi)
   {
      case 1:  kankaku=Kankaku_S1_Byou;  break; // 1秒足なら設定値を代入してswitchを抜ける
      case 5:  kankaku=Kankaku_S5_Byou;  break; // 5秒足なら...
      case 15: kankaku=Kankaku_S15_Byou; break;
      case 20: kankaku=Kankaku_S20_Byou; break;
      case 25: kankaku=Kankaku_S25_Byou; break;
      case 30: kankaku=Kankaku_S30_Byou; break;
      case 35: kankaku=Kankaku_S35_Byou; break;
      case 40: kankaku=Kankaku_S40_Byou; break;
      case 45: kankaku=Kankaku_S45_Byou; break;
      case 50: kankaku=Kankaku_S50_Byou; break;
      case 55: kankaku=Kankaku_S55_Byou; break;
      default: kankaku=Byou_Ashi; break; // 想定外の秒足なら、その秒足と同じ間隔にする
   }

   if(kankaku <= 0) kankaku = Byou_Ashi; // もし0以下になっていたら秒足と同じ値に直す(安全策)

   return kankaku; // 最終的に決定した「間隔(秒)」を呼び出し元に返す
}



//+------------------------------------------------------------------+
//| 【関数】今の時間足に合わせて「何分間隔」にするか決める場所
//+------------------------------------------------------------------+

// ENUM_TIMEFRAMES = MT5で使える「すべての時間足(M1やH1など)」があらかじめ登録されている「専用のリスト」のこと
// 通常の時間足に応じて、インプットで設定された表示間隔(分)を返す関数です。
int Kankaku_Get_Fun(ENUM_TIMEFRAMES Jikan_Ashi)
{
   int kankaku = -1; // とりあえず初期値として無効な値を入れておく
   
   // 今のチャートの時間足(Jikan_Ashi)がどれかによって分岐
   // switch文で値を確認し、一致したcaseの処理だけを実行します。
   switch(Jikan_Ashi)
   {
      case PERIOD_M1:  kankaku=Kankaku_M1_Fun;  break; // 1分足なら設定値を代入してswitchを抜ける
      case PERIOD_M2:  kankaku=Kankaku_M2_Fun;  break; // 2分足なら...
      case PERIOD_M3:  kankaku=Kankaku_M3_Fun;  break;
      case PERIOD_M4:  kankaku=Kankaku_M4_Fun;  break;
      case PERIOD_M5:  kankaku=Kankaku_M5_Fun;  break;
      case PERIOD_M6:  kankaku=Kankaku_M6_Fun;  break;
      case PERIOD_M10: kankaku=Kankaku_M10_Fun; break;
      case PERIOD_M12: kankaku=Kankaku_M12_Fun; break;
      case PERIOD_M15: kankaku=Kankaku_M15_Fun; break;
      case PERIOD_M20: kankaku=Kankaku_M20_Fun; break;
      case PERIOD_M30: kankaku=Kankaku_M30_Fun; break;
      case PERIOD_H1:  kankaku=Kankaku_H1_Fun;  break;
      case PERIOD_H2:  kankaku=Kankaku_H2_Fun;  break;
      case PERIOD_H3:  kankaku=Kankaku_H3_Fun;  break;
      case PERIOD_H4:  kankaku=Kankaku_H4_Fun;  break;
      case PERIOD_H6:  kankaku=Kankaku_H6_Fun;  break;
      case PERIOD_H8:  kankaku=Kankaku_H8_Fun;  break;
      case PERIOD_H12: kankaku=Kankaku_H12_Fun; break;
      case PERIOD_D1:  kankaku=Kankaku_D1_Fun;  break;
      case PERIOD_W1:  kankaku=Kankaku_W1_Fun;  break;
      case PERIOD_MN1: kankaku=Kankaku_MN1_Fun; break;
      default:          kankaku=60; break;              // 想定外の時間足なら60分にする
   }
   
   if(kankaku <= 0) kankaku = 60; // もし0以下になっていたら60に直す(安全策)
   
   // チャートの時間足自体が何分か計算(例: H1なら60)
   // PeriodSeconds=その時間足が「何秒」なのかを教えてくれる関数
   // 指定時間足1本が何秒かを取得します。
   int Ashi_no_Funsu = (int)(PeriodSeconds(Jikan_Ashi)/60);
   
   // エラー防止
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(Ashi_no_Funsu <= 0)
   {
      Ashi_no_Funsu = 1; // 0なら1にする(割り算エラー防止)
   }

   // 設定した間隔が、足の分数より短かったら意味がないので合わせる
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(kankaku < Ashi_no_Funsu)
   {
      kankaku = Ashi_no_Funsu;
   }
   else
   {
      // キリよく割り切れるように調整(余りが出ないようにする)
      // 「amari」という整数用の変数を用意し、この後の計算や表示処理で使用します。
      int amari = kankaku % Ashi_no_Funsu;
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(amari != 0)
      {
         kankaku += (Ashi_no_Funsu - amari);
      }
   }
   return kankaku; // 最終的に決定した「間隔(分)」を呼び出し元に返す
}

//+------------------------------------------------------------------+
//| 【関数】指定した時間がサマータイム(夏時間)かどうかを判定して
//|  日本時間(JST)との時差(秒数)を計算して返す場所
//+------------------------------------------------------------------+
// 指定時刻が夏時間か冬時間かを判定し、サーバー時間から日本時間へ足す秒数を返します。
long Get_JST_Offset(datetime Hantei_Time)
{
   // 日付や曜日を調べやすくするために、時間のデータを分解できる「構造体」に入れます
   // datetimeを年・月・日・曜日・時などに分解して扱うための構造体です。
   MqlDateTime Jikan_Data;
   // 指定された時刻をMqlDateTimeへ分解し、月や曜日を個別に参照できる状態にします。
   TimeToStruct(Hantei_Time, Jikan_Data);

   // 選択したサーバーGMTを、冬時間と夏時間に分けて用意する
   // 「Fuyu_Server_GMT」という整数用の変数を用意し、この後の計算や表示処理で使用します。
   int Fuyu_Server_GMT = 2;
   // 「Natsu_Server_GMT」という整数用の変数を用意し、この後の計算や表示処理で使用します。
   int Natsu_Server_GMT = 3;

   // ユーザーが選んだサーバーGMTの種類に応じて、冬時間と夏時間のGMT値を決めます。
   switch(Settei_Server_GMT)
   {
      case SERVER_GMT_2_3: Fuyu_Server_GMT = 2; Natsu_Server_GMT = 3; break;
      case SERVER_GMT_1_2: Fuyu_Server_GMT = 1; Natsu_Server_GMT = 2; break;
      case SERVER_GMT_0_1: Fuyu_Server_GMT = 0; Natsu_Server_GMT = 1; break;
      case SERVER_GMT_3_3: Fuyu_Server_GMT = 3; Natsu_Server_GMT = 3; break;
      case SERVER_GMT_0_0: Fuyu_Server_GMT = 0; Natsu_Server_GMT = 0; break;
   }

   bool Natsu_Jikan_Desuka = false; // 「今は夏時間ですか?」というフラグ(最初は「いいえ(false)」にしておく)

   //----------------------------------------------------------------
   // 米国方式 (DST_US) の場合
   // 夏時間:3月の第2日曜日 ~ 11月の第1日曜日
   //----------------------------------------------------------------
   // サマータイム方式として米国方式が選ばれている場合の判定へ進みます。
   if(Settei_DST_Type == DST_US)
   {
      // 3月よりあと、かつ、11月より前なら、間違いなく夏時間
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(Jikan_Data.mon > 3 && Jikan_Data.mon < 11) Natsu_Jikan_Desuka = true;
      
      // 3月より前、または、11月よりあとなら、間違いなく冬時間
      // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
      else if(Jikan_Data.mon < 3 || Jikan_Data.mon > 11) Natsu_Jikan_Desuka = false;
      
      // 際どい「3月」と「11月」の判定
      else
      {
         // 3月の場合 (第2日曜日を過ぎているかチェック)
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(Jikan_Data.mon == 3)
         {
            // まず「3月1日」が何曜日だったか逆算して調べる(0:日曜 ~ 6:土曜)
            // 「Tsuitachi_No_Youbi」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Tsuitachi_No_Youbi = (Jikan_Data.day_of_week - (Jikan_Data.day - 1) % 7 + 7) % 7;
            
            // 「第2日曜日」が何日になるか計算
            // 式の意味:1日 + (次の日曜までの日数) + 7日(1週間分)
            // 「Daini_Nichiyoubi_Hizuke」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Daini_Nichiyoubi_Hizuke = 1 + (7 - Tsuitachi_No_Youbi) % 7 + 7;

            // 米国東部時間の冬時間2時=UTC7時なので、サーバー時間へ変換する
            // 「Kaishi_Server_Hour」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Kaishi_Server_Hour = 7 + Fuyu_Server_GMT;
            
            // 今日の日付が、第2日曜より後なら夏時間
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(Jikan_Data.day > Daini_Nichiyoubi_Hizuke) Natsu_Jikan_Desuka = true;
            
            // もし今日がドンピシャで「第2日曜」なら、サーバー時間へ変換した切り替え時刻を過ぎているかチェック
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(Jikan_Data.day == Daini_Nichiyoubi_Hizuke && Jikan_Data.hour >= Kaishi_Server_Hour) Natsu_Jikan_Desuka = true;
         }
         
         // 11月の場合 (第1日曜日までかどうかチェック)
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(Jikan_Data.mon == 11)
         {
            // 「11月1日」が何曜日か調べる
            // 「Tsuitachi_No_Youbi」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Tsuitachi_No_Youbi = (Jikan_Data.day_of_week - (Jikan_Data.day - 1) % 7 + 7) % 7;
            
            // 「第1日曜日」が何日になるか計算
            // 「Daiichi_Nichiyoubi_Hizuke」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Daiichi_Nichiyoubi_Hizuke = 1 + (7 - Tsuitachi_No_Youbi) % 7;

            // 米国東部時間の夏時間2時=UTC6時なので、サーバー時間へ変換する
            // 「Shuuryou_Server_Hour」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Shuuryou_Server_Hour = 6 + Natsu_Server_GMT;
            
            // 今日の日付が、第1日曜より前ならまだ夏時間
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(Jikan_Data.day < Daiichi_Nichiyoubi_Hizuke) Natsu_Jikan_Desuka = true;
            
            // もし今日がドンピシャで「第1日曜」なら、サーバー時間へ変換した切り替え時刻より前なら夏時間
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(Jikan_Data.day == Daiichi_Nichiyoubi_Hizuke && Jikan_Data.hour < Shuuryou_Server_Hour) Natsu_Jikan_Desuka = true;
         }
      }
   }
   
   //----------------------------------------------------------------
   // 欧州方式 (DST_EU) の場合
   // 夏時間:3月の最終日曜日 ~ 10月の最終日曜日
   //----------------------------------------------------------------
   // サマータイム方式として欧州方式が選ばれている場合の判定へ進みます。
   if(Settei_DST_Type == DST_EU)
   {
      // 3月~10月の間なら夏時間の可能性が高い
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(Jikan_Data.mon > 3 && Jikan_Data.mon < 10) Natsu_Jikan_Desuka = true;
      // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
      else if(Jikan_Data.mon < 3 || Jikan_Data.mon > 10) Natsu_Jikan_Desuka = false;
      else
      {
         // 3月の場合 (最終日曜日を過ぎているかチェック)
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(Jikan_Data.mon == 3)
         {
            // 月末(31日)から逆算して、最終日曜日が何日か求める
            // 計算式:31日 - (31日の曜日) ※31日の曜日は現在日から推測
            // 「Matsubi_No_Youbi」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Matsubi_No_Youbi = (Jikan_Data.day_of_week + (31 - Jikan_Data.day)) % 7;
            // 「Saishu_Nichiyoubi_Hizuke」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Saishu_Nichiyoubi_Hizuke = 31 - Matsubi_No_Youbi;

            // 欧州の切り替え時刻1:00 UTCを、冬時間のサーバーGMTへ変換する
            // 「Kaishi_Server_Hour」という整数用の変数を用意し、この後の計算や表示処理で使用します。
            int Kaishi_Server_Hour = 1 + Fuyu_Server_GMT;
            
            // 今日の日付が、最終日曜より後なら夏時間
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(Jikan_Data.day > Saishu_Nichiyoubi_Hizuke) Natsu_Jikan_Desuka = true;
            
            // 当日の場合、サーバー時間へ変換した切り替え時刻を過ぎているかチェック
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(Jikan_Data.day == Saishu_Nichiyoubi_Hizuke && Jikan_Data.hour >= Kaishi_Server_Hour) Natsu_Jikan_Desuka = true;
         }
         
         // 10月の場合 (最終日曜日までかどうかチェック)
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(Jikan_Data.mon == 10)
         {
             // 10月も31日まであるので計算は同じ
             // 「Matsubi_No_Youbi」という整数用の変数を用意し、この後の計算や表示処理で使用します。
             int Matsubi_No_Youbi = (Jikan_Data.day_of_week + (31 - Jikan_Data.day)) % 7;
             // 「Saishu_Nichiyoubi_Hizuke」という整数用の変数を用意し、この後の計算や表示処理で使用します。
             int Saishu_Nichiyoubi_Hizuke = 31 - Matsubi_No_Youbi;

             // 欧州の切り替え時刻1:00 UTCを、夏時間のサーバーGMTへ変換する
             // 「Shuuryou_Server_Hour」という整数用の変数を用意し、この後の計算や表示処理で使用します。
             int Shuuryou_Server_Hour = 1 + Natsu_Server_GMT;
             
             // 今日の日付が、最終日曜より前なら夏時間
             // if文の条件がtrueになった場合だけ、続く処理を実行します。
             if(Jikan_Data.day < Saishu_Nichiyoubi_Hizuke) Natsu_Jikan_Desuka = true;
             
             // 当日の場合、サーバー時間へ変換した切り替え時刻より前なら夏時間
             // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
             else if(Jikan_Data.day == Saishu_Nichiyoubi_Hizuke && Jikan_Data.hour < Shuuryou_Server_Hour) Natsu_Jikan_Desuka = true;
         }
      }
   }

   // --- 結果を秒数で返す ---
   // 選択したサーバーGMTに合わせて、日本時間(GMT+9)との差を計算する
   // 初期設定のGMT+2 / GMT+3なら、夏時間は6時間、冬時間は7時間の差になる
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(Natsu_Jikan_Desuka == true)
   {
      return (9 - Natsu_Server_GMT) * 3600; // 夏時間のサーバーGMTから日本時間との差を計算
   }
   else
   {
      return (9 - Fuyu_Server_GMT) * 3600; // 冬時間のサーバーGMTから日本時間との差を計算
   }
}


//+------------------------------------------------------------------+
// 【関数】パソコンが重くならないように、画面から見えなくなった不要な文字(日時)を削除する関数
// 日本時間を全ての範囲で表示すると処理が重くなる最悪フリーズします。今見えている範囲のみで時間を表示する事が重要になります
//+------------------------------------------------------------------+

// 表示範囲外へ出たこのインジケーターの日時文字を削除し、オブジェクト数を増やし過ぎないための関数です。
void Fuyou_Moji_Sakujyo(long chart_id, int window_num, int start_index, int end_index)
{

   // ObjectsTotal = チャート上に、文字や線などのオブジェクトが「全部で何個あるか」を数えて教えてくれる関数
   int Sousuu = ObjectsTotal(chart_id, window_num, OBJ_TEXT); // 今あるテキストオブジェクトの総数
   
   // 最新のオブジェクトから順番にチェック(削除時は後ろからループするのが鉄則)
   // for文で指定した範囲を順番に繰り返し処理します。
   for(int i = Sousuu - 1; i >= 0; i--)
   {
      // 削除すべきかどうかを判断するために、i番目のテキストオブジェクトの『名前』を読み取って、いったん変数にメモ
      string obj_name = ObjectName(chart_id, i, window_num, OBJ_TEXT); // オブジェクトの名前を取得
      
      // 名前がこのインジケータのもの(JST_Moji_で始まる)かどうか確認
      // 文字列の中から指定した文字が始まる位置を探します。
      if(StringFind(obj_name, Obj_Namae_No_Atama) == 0)
      {
         
         // 名前の後ろの番号部分を取り出す
         // 文字列の一部分だけを切り出します。
         string str_num = StringSubstr(obj_name, StringLen(Obj_Namae_No_Atama));
         int obj_index = (int)StringToInteger(str_num); // 文字列を数字に変換
         
         // 表示すべき範囲(start〜end)の外なら削除する
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(obj_index < start_index || obj_index > end_index)
         {
            ObjectDelete(chart_id, obj_name); // 削除実行
         }
      }
   }
}





//+------------------------------------------------------------------+
// ボタンは枠と文字で作成しています。ボタンを使うのも良いのですが、見た目のカスタムの自由度が下がるので枠と文字を採用しています
// 使い方としては枠と文字を作成して、枠もしくは文字をクリックした際にイベントが発生するようにします
//+------------------------------------------------------------------+
// Lボタンの枠と文字を作成・更新する関数です。
void Button_LINE()
{
   long chart_id = ChartID();          // 今のチャートID
   int sub_window = ChartWindowFind(); // このインジケータがいるサブウィンドウ番号

   // --- 1. ボタンの「枠」を作る(まだ存在しない場合のみ) ---
   // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
   if(ObjectFind(chart_id, Button_Waku_Namae) < 0)
   {
      ObjectCreate(chart_id, Button_Waku_Namae, OBJ_RECTANGLE_LABEL, sub_window, 0, 0); // 枠作成
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_CORNER, CORNER_LEFT_UPPER); // 左上基準
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_XDISTANCE, 2);  // 左から5pxの位置
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_YDISTANCE, 15);  // 上から5pxの位置
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_XSIZE, 18);     // 幅18px
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_YSIZE, 18);     // 高さ18px
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_COLOR, clrBlack); // 枠線の色
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_BACK, false);     // 背景として描画しない
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_SELECTABLE, true); // クリック選択可能にする
      ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_ZORDER, 255);      // 最前面に表示
   }

   // --- 2. ボタンの「文字」を作る(まだ存在しない場合のみ) ---
   // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
   if(ObjectFind(chart_id, Button_Moji_Namae) < 0)
   {
      ObjectCreate(chart_id, Button_Moji_Namae, OBJ_LABEL, sub_window, 0, 0); // ラベル作成
      // オブジェクトの座標を画面のどの角から測るかを設定します。
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_XDISTANCE, 8); // 文字の位置調整X
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_YDISTANCE, 17); // 文字の位置調整Y
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_FONTSIZE, 10);  // 文字サイズ
      ObjectSetString(chart_id, Button_Moji_Namae, OBJPROP_FONT, "Arial");  // フォント
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_COLOR, clrBlack); // 文字色
      // オブジェクトを価格表示などの後ろ側へ置くかどうかを設定します。
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_BACK, false);
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_SELECTABLE, true); // クリック選択可能
      ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_ZORDER, 255);      // 最前面
   }

   // --- 3. ON/OFFの状態に合わせて色と文字を更新する ---
   // ONならライム色(緑)、OFFなら白にする(条件演算子 ? : を使用)
   // オブジェクトの背景色を設定します。
   ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_BGCOLOR, Button_Switch_ON ? clrLime : clrWhite);
   
   // ONなら「LINE」、OFFなら「LINE」と表示する、今回は同じ文字を使っていますが「LINE[ON]」「LINE[OFF]」などにすると分かりやすい
   // オブジェクトに実際に表示する文字列を設定します。
   ObjectSetString(chart_id, Button_Moji_Namae, OBJPROP_TEXT, Button_Switch_ON ? "L" : "L");
   
   // クリックした後に選択枠(ポチポチ)が残らないように選択状態を解除する
   // 現在そのオブジェクトが選択状態かどうかを設定します。
   ObjectSetInteger(chart_id, Button_Waku_Namae, OBJPROP_SELECTED, false);
   // 現在そのオブジェクトが選択状態かどうかを設定します。
   ObjectSetInteger(chart_id, Button_Moji_Namae, OBJPROP_SELECTED, false);
}

//+------------------------------------------------------------------+
//| 【関数】表示内容を切り替える「C」ボタンを作る
//+------------------------------------------------------------------+
// Cボタンの枠と文字を作成・更新する関数です。
void Button_C()
{
   long chart_id = ChartID();          // 今のチャートID
   int sub_window = ChartWindowFind(); // このインジケータがいるサブウィンドウ番号

   // --- 1. Cボタンの「枠」を作る(まだ存在しない場合のみ) ---
   // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
   if(ObjectFind(chart_id, C_Button_Waku_Namae) < 0)
   {
      ObjectCreate(chart_id, C_Button_Waku_Namae, OBJ_RECTANGLE_LABEL, sub_window, 0, 0); // 枠作成
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_CORNER, CORNER_LEFT_UPPER); // 左上基準
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_XDISTANCE, 22); // Lボタンの右側
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_YDISTANCE, 15); // 上から15pxの位置
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_XSIZE, 18);     // 幅18px
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_YSIZE, 18);     // 高さ18px
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_COLOR, clrBlack); // 枠線の色
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_BGCOLOR, clrWhite); // 背景色
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_BACK, false);     // 背景として描画しない
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_SELECTABLE, true); // クリック選択可能にする
      ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_ZORDER, 255);      // 最前面に表示
   }

   // --- 2. Cボタンの「文字」を作る(まだ存在しない場合のみ) ---
   // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
   if(ObjectFind(chart_id, C_Button_Moji_Namae) < 0)
   {
      ObjectCreate(chart_id, C_Button_Moji_Namae, OBJ_LABEL, sub_window, 0, 0); // ラベル作成
      // オブジェクトの座標を画面のどの角から測るかを設定します。
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_XDISTANCE, 28); // 文字の位置調整X
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_YDISTANCE, 17); // 文字の位置調整Y
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_FONTSIZE, 10);  // 文字サイズ
      ObjectSetString(chart_id, C_Button_Moji_Namae, OBJPROP_FONT, "Arial");  // フォント
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_COLOR, clrBlack); // 文字色
      // オブジェクトを価格表示などの後ろ側へ置くかどうかを設定します。
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_BACK, false);
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_SELECTABLE, true); // クリック選択可能
      ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_ZORDER, 255);      // 最前面
   }

   // --- 3. Cボタンの文字と状態を更新する ---
   // オブジェクトの背景色を設定します。
   ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_BGCOLOR, clrWhite);
   // オブジェクトに実際に表示する文字列を設定します。
   ObjectSetString(chart_id, C_Button_Moji_Namae, OBJPROP_TEXT, "C");

   // クリックした後に選択枠(ポチポチ)が残らないように選択状態を解除する
   // 現在そのオブジェクトが選択状態かどうかを設定します。
   ObjectSetInteger(chart_id, C_Button_Waku_Namae, OBJPROP_SELECTED, false);
   // 現在そのオブジェクトが選択状態かどうかを設定します。
   ObjectSetInteger(chart_id, C_Button_Moji_Namae, OBJPROP_SELECTED, false);
}

//+------------------------------------------------------------------+
//| 【関数】日本時間を計算して画面に並べる(メイン処理)
//+------------------------------------------------------------------+
// 画面に必要な日本時間文字を計算し、作成・移動・削除まで行う中心的な描画関数です。
void Jikan_Hyouji_Koushin()
{
   long chart_id = ChartID();              // チャートID
   int sub_window = ChartWindowFind();     // サブウィンドウ番号
   int bar_Sousuu = Bars(_Symbol, _Period); // チャートにあるローソク足の総数

   // --- 今、画面に見えている範囲(左端の場所と、表示されている本数)を取得 ---
   // 画面の「一番左端」に見えているローソク足が、最新(右端)から数えて「何本目」かを取得します
   // 画面の左端に見えているバーが、最新から何本前かを取得します。
   long hidari_hashi_index = ChartGetInteger(chart_id, CHART_FIRST_VISIBLE_BAR); 

   // 画面の横幅の中に、ローソク足が「全部で何本」入っているか(表示本数)を取得します
   // 現在のチャート画面に表示されているバー本数を取得します。
   long mieteru_honsuu     = ChartGetInteger(chart_id, CHART_VISIBLE_BARS);    

   int yohaku = 50; // 計算範囲に少し余裕を持たせる(50本分)
   
   // --- 配列(データの入れ物)のどこからどこまでを計算するか決める ---
   // 【開始位置(画面の左端)】
   // 表示範囲より少し左まで含めた、計算開始位置を古い順のインデックスへ換算します。
   int start_i = bar_Sousuu - 1 - (int)(hidari_hashi_index + yohaku); 

   // 【終了位置(画面の右端)】
   // 表示範囲より少し右まで含めた、計算終了位置を求めます。
   int end_i   = bar_Sousuu - 1 - (int)(hidari_hashi_index - mieteru_honsuu - yohaku);

   // --- 配列の範囲外エラー(Array out of range)を防ぐための補正処理 ---
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(start_i < 0)
   { 
      start_i = 0;
   }
   
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(end_i >= bar_Sousuu)
   {
      end_i = bar_Sousuu - 1;
   }
   
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(start_i > end_i)
   {
      // これ以上処理を続けず、この関数をここで終了します。
      return; // 範囲がおかしい場合は何もしない
   }

   // 画面外にある古いオブジェクトを削除して軽くする
   // 今後使わない表示範囲外の日時文字を先に削除して、処理負荷を抑えます。
   Fuyou_Moji_Sakujyo(chart_id, sub_window, start_i, end_i);

   // --- 表示間隔の準備 ---

   // 関数(Kankaku_Get_Fun)で決めた「何分間隔」を、計算用に「秒」に直します(分 × 60秒)
   // 通常時間足用の表示間隔を分で取得し、比較しやすいよう秒へ変換します。
   long kankaku_byou = Kankaku_Get_Fun(_Period) * 60;

   // 現在が秒足カスタムシンボルなら、その秒数を取得します。通常足なら0です。
   int byou_ashi_sec = Byou_Ashi_Get_Byousuu();
   // 秒足の場合だけ、通常足用ではなく秒足専用の表示間隔へ置き換えます。
   if(byou_ashi_sec > 0) kankaku_byou = Kankaku_Get_Byou(byou_ashi_sec);

   // まず「年月日時分秒」表示用の文字間隔を初期値として入れます。
   int moji_kankaku = Settei_Moji_Kankaku_GatsuHiJifunByou;
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(C_Hyouji_Mode == 1) moji_kankaku = Settei_Moji_Kankaku_NenGatsuHiJifun;
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(C_Hyouji_Mode == 2) moji_kankaku = Settei_Moji_Kankaku_JifunByou;
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(C_Hyouji_Mode == 3) moji_kankaku = Settei_Moji_Kankaku_Jifun;
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(C_Hyouji_Mode == 4) moji_kankaku = Settei_Moji_Kankaku_GatsuHi;
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(C_Hyouji_Mode == 5) moji_kankaku = Settei_Moji_Kankaku_Gatsu;

   // 画面左端からの距離で表示する文字を選ぶと、秒足では新しい足が増えるたびに表示対象がずれてしまうため
   // 「時刻の区切り番号」を基準に固定して間引く回数を決めます
   // 表示候補を何個おきに残すかを表す値です。1なら間引かず全部を候補にします。
   int mabiki_kankaku = 1;

   // サブウィンドウの横幅をピクセル単位で取得します。
   int chart_width = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_PIXELS, sub_window);
   // if文の条件がtrueになった場合だけ、続く処理を実行します。
   if(chart_width > 0 && mieteru_honsuu > 0 && moji_kankaku > 0)
   {
      // チャート横幅を表示バー本数で割り、1本あたりのおおよその横幅を求めます。
      double bar_haba_pixel = (double)chart_width / (double)mieteru_honsuu;
      // 1つの時間表示区切りに何本のバーが含まれるかを入れる変数です。
      double grid_honsuu = 1.0;

      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(byou_ashi_sec > 0)
      {
         grid_honsuu = (double)kankaku_byou / (double)byou_ashi_sec;
      }
      else
      {
         // 指定時間足1本が何秒かを取得します。
         int ashi_byou = PeriodSeconds(_Period);
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(ashi_byou > 0)
            grid_honsuu = (double)kankaku_byou / (double)ashi_byou;
      }

      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(grid_honsuu < 1.0) grid_honsuu = 1.0;

      // 1つの時間表示区切りが画面上で何ピクセル幅になるかを求めます。
      double grid_haba_pixel = bar_haba_pixel * grid_honsuu;
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(grid_haba_pixel > 0.0)
      {
         // 文字が重ならないよう、必要なピクセル間隔から何区切りおきに表示するかを切り上げ計算します。
         mabiki_kankaku = (int)MathCeil((double)moji_kankaku / grid_haba_pixel);
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(mabiki_kankaku < 1) mabiki_kankaku = 1;
      }
   }

   // --- 時間データの取得 ---
   datetime time_array[]; // すべてのローソク足の時間データを入れるための配列(箱)を用意します

   // 1つ前のバーとの比較が必要なので、開始位置より1本前から取得する
   // 時間配列へコピーする範囲の開始インデックスを一度保存します。
   int copy_start_i = start_i;
   // 1本前との比較が必要なので、可能なら開始位置をさらに1本前へ広げます。
   if(copy_start_i > 0) copy_start_i--;

   // 今回必要な本数を計算
   // 開始位置から終了位置まで、何本分の時間データが必要かを計算します。
   int copy_count = end_i - copy_start_i + 1;

   // 「最新から何本前か」に変換
   // CopyTimeが使う「最新から何本前」という形式へ開始位置を変換します。
   int copy_start_pos = bar_Sousuu - 1 - end_i;
   
   // 配列の並び順を「古い順(左から右)」に設定します
   ArraySetAsSeries(time_array, false); 
   
   // チャート上の時間データ(_Symbol, _Period)を、用意した配列(time_array)にコピーします
   // 必要な範囲のバー時刻をMT5からまとめてtime_arrayへコピーし、実際に取得できた本数を受け取ります。
   int copied = CopyTime(_Symbol, _Period, copy_start_pos, copy_count, time_array);
   // 必要本数と取得本数が一致しない場合は、不完全な配列で処理しないよう中断します。
   if(copied != copy_count)
   {
      // これ以上処理を続けず、この関数をここで終了します。
      return;
   }

   // 実際の画面上で直前に表示した文字のX座標を記憶する
   // 土日などローソク足がない期間では日時が近い位置へ並ぶため、文字同士の重なり防止に使用します
   // まだ前の文字が存在しないことを表すため、通常あり得ない大きな負のX座標で初期化します。
   int mae_no_moji_x = -1000000;

   // 計算した範囲(画面に見えている部分+α)のバーを1本ずつチェックするループ
   // for文で指定した範囲を順番に繰り返し処理します。
   for(int i = start_i; i <= end_i; i++)
   {
      // チャート側インデックスiを、今回コピーしたtime_array内の位置へ変換します。
      int time_index = i - copy_start_i;
      string obj_name = Obj_Namae_No_Atama + IntegerToString(i); // バーごとのオブジェクト名を生成(例:JST_Moji_123)
      
      bool is_grid_point = false; // 「ここに時間を表示すべきか?」を判定するフラグ(最初はfalse)
      
      // ★修正:判定関数(Get_JST_Offset)を使って、その瞬間のサマータイム考慮済み時差を取得
      // 対象バーの時刻を、必要なら秒足の仮想時間から実サーバー時間へ戻します。
      datetime current_server_time = Byou_Ashi_Jissai_Jikan(time_array[time_index]);
      // そのバー時点の夏時間・冬時間を考慮した、日本時間までの時差秒数を取得します。
      long offset_sec = Get_JST_Offset(current_server_time);
      long current_jst = (long)current_server_time + offset_sec; // そのバーの日本時間を算出
      long current_block = current_jst / kankaku_byou; // 現在の区切り番号
      
      // 1つ前のバーと比較して、設定した時間区切り(例:1時間)を跨いだかチェック
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(i > 0)
      {
         // 1つ前のバーも、その時点での夏冬判定を行う
         // 比較用として1本前のバーも実サーバー時間へ換算します。
         datetime prev_server_time = Byou_Ashi_Jissai_Jikan(time_array[time_index-1]);
         // 1本前のバー時点についても、その時点の夏冬時間を考慮した時差を取得します。
         long prev_offset_sec = Get_JST_Offset(prev_server_time);
         // 1本前のバー時刻も日本時間へ変換します。
         long prev_jst = (long)prev_server_time + prev_offset_sec;
         
         // 時間を間隔秒数で割ることで「区切り番号」を算出(例:10:59と11:00で番号が変わる)
         long prev_block = prev_jst / kankaku_byou;    // 1つ前の区切り番号
         
         // 区切り番号が変わった=ここが時間の変わり目なので表示ポイントとする
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if(current_block != prev_block)
         {
            // 表示位置ではなく「区切り番号」で間引くため、新しい秒足が増えても表示する時刻がころころ変わらない
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if((current_block % mabiki_kankaku) == 0) is_grid_point = true;
         }
      }
      else
      {
         // 配列の最初(一番左端)は比較対象がないため、固定した区切り番号に当てはまる場合だけ表示候補にする
         // if文の条件がtrueになった場合だけ、続く処理を実行します。
         if((current_block % mabiki_kankaku) == 0) is_grid_point = true;
      }

      if(is_grid_point) // ここが表示ポイントだと判定された場合の処理
      {
         // 時間位置を画面上のピクセル座標へ変換した結果を受け取るX・Y変数です。
         int x, y;
         // その時間(time_array[time_index])が、画面上のどの座標(X,Y)にあるかを取得
         // チャートの時間・価格を画面上のX・Yピクセル座標へ変換します。
         if(ChartTimePriceToXY(chart_id, sub_window, time_array[time_index], 0.0, x, y))
         {
            // 左上の「LINE」ボタンと文字が被らないように、X座標が120未満(左端付近)なら表示しない
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(x < 120)
            {
               // もし既に文字が表示されていたら削除して、次のループへ進む
               // 指定した名前のチャートオブジェクトを削除します。
               if(ObjectFind(chart_id, obj_name) >= 0) ObjectDelete(chart_id, obj_name);
               continue; // 次のループへ(以下の処理はスキップ)
            }

            // 土日などで日時の表示位置が実際の画面上で近すぎる場合は、文字同士が重ならないように表示しない
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(mae_no_moji_x > -1000000 && (x - mae_no_moji_x) < moji_kankaku)
            {
               // 指定した名前のチャートオブジェクトを削除します。
               if(ObjectFind(chart_id, obj_name) >= 0) ObjectDelete(chart_id, obj_name);
               continue;
            }

            // 今回の文字を表示するので、このX座標を次の重なり判定用に記憶する
            mae_no_moji_x = x;

            // 表示する時間を区切りのいい数字に丸める(秒単位のズレを補正して00分や30分ぴったりにする)
            // 区切り番号へ間隔秒数を掛け、表示用のきりの良い時刻へ戻します。
            long rounded_time = current_block * kankaku_byou;
            
            // 表示する年月日・時分秒へ分解するためのMqlDateTime構造体です。
            MqlDateTime dt;
            TimeToStruct((datetime)rounded_time, dt); // 計算しやすいように時間構造体に変換
            
            // 画面に表示するテキストを作成(Cボタンを押すたびに表示内容を切り替える)
            // 最終的にチャートへ表示する文字列を入れる変数です。
            string text;
            // if文の条件がtrueになった場合だけ、続く処理を実行します。
            if(C_Hyouji_Mode == 0)
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%d年%d月%d日(%s)%02d:%02d:%02d", dt.year, dt.mon, dt.day, Week_Names[dt.day_of_week], dt.hour, dt.min, dt.sec);
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(C_Hyouji_Mode == 1)
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%d年%d月%d日(%s)%02d:%02d", dt.year, dt.mon, dt.day, Week_Names[dt.day_of_week], dt.hour, dt.min);
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(C_Hyouji_Mode == 2)
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%02d:%02d:%02d", dt.hour, dt.min, dt.sec);
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(C_Hyouji_Mode == 3)
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%02d:%02d", dt.hour, dt.min);
            // 直前の条件に当てはまらず、この条件がtrueの場合にこの処理を選びます。
            else if(C_Hyouji_Mode == 4)
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%d月%d日", dt.mon, dt.day);
            else
               // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
               text = StringFormat("%d月", dt.mon);
            
            // まだその場所にオブジェクトが存在しなければ新規作成する
            // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
            if(ObjectFind(chart_id, obj_name) < 0)
            {
               // テキストオブジェクトを作成(作成成功したら中身を設定)
               // チャート上に新しい描画オブジェクトを作成します。
               if(ObjectCreate(chart_id, obj_name, OBJ_TEXT, sub_window, time_array[time_index], 1.0))
               {
                  // プロパティ(文字の内容、フォント、色、サイズなど)を設定
                  // オブジェクトに実際に表示する文字列を設定します。
                  ObjectSetString(chart_id, obj_name, OBJPROP_TEXT, text);
                  // 表示に使用するフォント名を設定します。
                  ObjectSetString(chart_id, obj_name, OBJPROP_FONT, "Arial Bold");
                  // オブジェクトの文字色または線色を設定します。
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_COLOR, Settei_Moji_Color);
                  // 表示文字のフォントサイズを設定します。
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_FONTSIZE, Settei_Moji_Size);
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_ANCHOR, ANCHOR_CENTER); // 文字の中心を基準点に合わせる
                  // オブジェクトを価格表示などの後ろ側へ置くかどうかを設定します。
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_BACK, false); 
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_SELECTABLE, false); // マウスで選択できないようにする(誤操作防止)
                  // クリック判定などでの前後優先順位を設定します。値が大きいほど優先されます。
                  ObjectSetInteger(chart_id, obj_name, OBJPROP_ZORDER, 0); 
               }
            }
            else
            {
               // 既にオブジェクトがあるなら、作り直さずにテキスト内容だけ更新(PCの負荷軽減)
               // 既存オブジェクトの時間・価格位置を移動します。
               ObjectMove(chart_id, obj_name, 0, time_array[time_index], 1.0);
               // オブジェクトに実際に表示する文字列を設定します。
               ObjectSetString(chart_id, obj_name, OBJPROP_TEXT, text); 
            }
         }
      }
      else
      {
         // 表示ポイントではない場所(例:10:00と11:00の間の半端な時間)にオブジェクトが残っていたら削除
         // 指定した名前のチャートオブジェクトを削除します。
         if(ObjectFind(chart_id, obj_name) >= 0) ObjectDelete(chart_id, obj_name);
      }
   }
   
   // ボタンの表示も更新しておく
   Button_LINE();
   Button_C();
   
   ChartRedraw(); // 画面を再描画して変更を反映
}

//+------------------------------------------------------------------+
//| 【関数】マウスに合わせてカーソルと時間を表示する場所
//+------------------------------------------------------------------+
// マウス位置に合わせて縦線と日本時間ラベルを更新する関数です。
void Mouse_Cursor_Koushin(long chart_id, int mouse_x, int mouse_y, int sub_window)
{
   // --- 機能OFFの場合の処理 ---
   // ボタンが「OFF」の状態なら、カーソル(縦線とラベル)が表示されていたら邪魔なので消去して終わる
   // L機能がOFFになった場合だけ、中に残っているカーソル表示を消します。
   if(!Button_Switch_ON)
   {
      // 縦線が残っていたら削除
      // 指定した名前のチャートオブジェクトを削除します。
      if(ObjectFind(chart_id, Cursor_Tatesen_Namae) >= 0) ObjectDelete(chart_id, Cursor_Tatesen_Namae);
      // ラベルが残っていたら削除
      // 指定した名前のチャートオブジェクトを削除します。
      if(ObjectFind(chart_id, Cursor_Label_Namae) >= 0) ObjectDelete(chart_id, Cursor_Label_Namae);
      
      ChartRedraw(); // 画面を更新して削除を反映させる
      // これ以上処理を続けず、この関数をここで終了します。
      return;        // ここで関数を強制終了(以下の処理は行わない)
   }

   datetime mouse_time; // マウス位置の時間が入る変数
   double mouse_price;  // マウス位置の価格が入る変数(今回は使わないが関数に必要)
   
   // --- 座標変換 ---
   // マウスの画面上の座標(X,Y)から、その場所の「チャート時間」と「価格」を逆算して取得
   // 取得に成功したら if の中身を実行する
   // 画面上のX・Yピクセル座標からチャートの時間・価格を逆算します。
   if(ChartXYToTimePrice(chart_id, mouse_x, mouse_y, sub_window, mouse_time, mouse_price))
   {
      // --- 日本時間(JST)の計算 ---
      int bar_index = iBarShift(_Symbol, _Period, mouse_time); // マウス位置の足を特定
      datetime bar_start_time = iTime(_Symbol, _Period, bar_index); // その足の開始時間を取得

      // ★修正:判定関数(Get_JST_Offset)を使って、マウス位置の足の時間のサマータイム時差を取得
      // 秒足なら仮想バー時刻を実際のサーバー時間へ戻します。
      datetime real_bar_start_time = Byou_Ashi_Jissai_Jikan(bar_start_time);
      // 「offset_sec」という大きな整数用の変数を用意し、この後の計算や表示処理で使用します。
      long offset_sec = Get_JST_Offset(real_bar_start_time);
      long current_jst = (long)real_bar_start_time + offset_sec; // 開始時間を日本時間に変換
      
      // 表示する年月日・時分秒へ分解するためのMqlDateTime構造体です。
      MqlDateTime dt;
      TimeToStruct((datetime)current_jst, dt); // 年月日を取り出せるように構造体に変換
      
      // カーソル用の表示テキスト作成(例: 2025/12/15 10:00 )
      // 左右にスペースを入れて見た目の余白を作っています
      // 最終的にチャートへ表示する文字列を入れる変数です。
      string text;
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(Byou_Ashi_Get_Byousuu() > 0)
         // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
         text = StringFormat(" %04d/%02d/%02d(%s) %02d:%02d:%02d ", dt.year, dt.mon, dt.day, Week_Names[dt.day_of_week], dt.hour, dt.min, dt.sec);
      else
         // 指定した書式に数値や文字を埋め込み、表示用文字列を作ります。
         text = StringFormat(" %04d/%02d/%02d(%s) %02d:%02d ", dt.year, dt.mon, dt.day, Week_Names[dt.day_of_week], dt.hour, dt.min);

      // --- 1. 縦線 (VLINE) の描画処理 ---
      // まだ縦線オブジェクトが存在しない場合(初回表示など)
      // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
      if(ObjectFind(chart_id, Cursor_Tatesen_Namae) < 0) 
      {
         // 縦線を作成
         // チャート上に新しい描画オブジェクトを作成します。
         ObjectCreate(chart_id, Cursor_Tatesen_Namae, OBJ_VLINE, 0, mouse_time, 0); 
         // オブジェクトの文字色または線色を設定します。
         ObjectSetInteger(chart_id, Cursor_Tatesen_Namae, OBJPROP_COLOR, Settei_Cursor_Sen_Color);
         ObjectSetInteger(chart_id, Cursor_Tatesen_Namae, OBJPROP_STYLE, STYLE_DOT); // 点線スタイル
         // 線の太さを設定します。
         ObjectSetInteger(chart_id, Cursor_Tatesen_Namae, OBJPROP_WIDTH, 2);
         ObjectSetInteger(chart_id, Cursor_Tatesen_Namae, OBJPROP_BACK, true); // ローソク足の「裏側」に表示
         ObjectSetInteger(chart_id, Cursor_Tatesen_Namae, OBJPROP_SELECTABLE, false); // クリック選択不可
         
         // ★重要テクニック:ツールチップ(マウスを乗せた時に出るポップアップ)を無効化
         // "\n"(改行コードだけ)を入れると、ツールチップが出なくなります
         // マウスを重ねた時に表示されるツールチップ文字列を設定します。
         ObjectSetString(chart_id, Cursor_Tatesen_Namae, OBJPROP_TOOLTIP, "\n");
      }
      else
      {
         // 位置をマウスの細かい時間(mouse_time)ではなく、足の開始時間(bar_start_time)にする
         // 既存オブジェクトの時間・価格位置を移動します。
         ObjectMove(chart_id, Cursor_Tatesen_Namae, 0, bar_start_time, 0);
         // マウスを重ねた時に表示されるツールチップ文字列を設定します。
         ObjectSetString(chart_id, Cursor_Tatesen_Namae, OBJPROP_TOOLTIP, "\n");
      }

      // --- 2. 日本時間ラベル (BUTTON) の描画処理 ---
      // ※通常のラベル(OBJ_LABEL)ではなくボタン(OBJ_BUTTON)を使う理由は、背景色を綺麗につけるためです
      // 日本時間ラベルの横幅を180ピクセルとして使います。
      int label_width = 180; 
      // 日本時間ラベルの高さを24ピクセルとして使います。
      int label_height = 24; 
      
      // ラベルが常にマウスの「真上」かつ「中心」に来るようにX座標を計算
      // マウスX位置から、ラベル幅の半分を引くと中心が合います
      // ラベル中央がマウスX位置に合うよう、ラベル幅の半分だけ左へずらします。
      int label_x = mouse_x - (label_width / 2);

      // チャートの横幅を取得
      // メインチャートの横幅を取得し、ラベルのはみ出し防止に使います。
      int chart_width = (int)ChartGetInteger(chart_id, CHART_WIDTH_IN_PIXELS, 0);

      // 左端・右端からラベルがはみ出さないように補正
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(label_x < 0)
         label_x = 0;

      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(label_x + label_width > chart_width)
         label_x = chart_width - label_width;

      int label_y = 5; // Y座標はサブウィンドウの上部(5px)に固定

      // まだラベルが存在しない場合
      // 指定した名前のオブジェクトがチャート上に存在するかを調べます。
      if(ObjectFind(chart_id, Cursor_Label_Namae) < 0) 
      {
         // ボタンオブジェクトを作成
         // チャート上に新しい描画オブジェクトを作成します。
         ObjectCreate(chart_id, Cursor_Label_Namae, OBJ_BUTTON, 0, 0, 0); 
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_CORNER, CORNER_LEFT_UPPER); // 左上基準
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_XSIZE, label_width); // 幅
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_YSIZE, label_height); // 高さ
         // 表示に使用するフォント名を設定します。
         ObjectSetString(chart_id, Cursor_Label_Namae, OBJPROP_FONT, "Arial Bold");
         // 表示文字のフォントサイズを設定します。
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_FONTSIZE, Settei_Moji_Size);
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_COLOR, Settei_Cursor_Moji_Color); // 文字色
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_BGCOLOR, Settei_Cursor_Haikei);    // 背景色
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_BORDER_COLOR, Settei_Cursor_Haikei); // 枠線の色 
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_STATE, false); // ボタンが押し込まれていない状態
         // マウスでそのオブジェクトを選択できるかどうかを設定します。
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_SELECTABLE, false);
         ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_ZORDER, 100); // 他の文字より手前に表示
         
         ObjectSetString(chart_id, Cursor_Label_Namae, OBJPROP_TOOLTIP, "\n"); // ツールチップ消去
      }
      
      // 内容や位置を更新(マウスに合わせて移動)
      // オブジェクトに実際に表示する文字列を設定します。
      ObjectSetString(chart_id, Cursor_Label_Namae, OBJPROP_TEXT, text);
      // 基準となる角から横方向へ何ピクセル離すかを設定します。
      ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_XDISTANCE, label_x);
      // 基準となる角から縦方向へ何ピクセル離すかを設定します。
      ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_YDISTANCE, label_y);
      // オブジェクトの背景色を設定します。
      ObjectSetInteger(chart_id, Cursor_Label_Namae, OBJPROP_BGCOLOR, Settei_Cursor_Haikei); 
      
      ChartRedraw(); // 再描画して、画面上の位置ズレを即座に直す
   }
}

//+------------------------------------------------------------------+
//| 【関数】後片付け(作ったオブジェクトを全部消す)
//+------------------------------------------------------------------+
// このインジケーターが作成した文字・カーソル・ボタンをまとめて削除する後片付け関数です。
void Zen_Obj_Sakujo()
{
   int Sousuu = ObjectsTotal(0, -1, OBJ_TEXT); // 全テキストオブジェクト数
   // for文で指定した範囲を順番に繰り返し処理します。
   for(int i = Sousuu - 1; i >= 0; i--) {      // 後ろからループ
      // 指定番号のオブジェクト名を取得します。
      string obj_name = ObjectName(0, i, -1, OBJ_TEXT);
      // 名前が一致するなら削除
      // 指定した名前のチャートオブジェクトを削除します。
      if(StringFind(obj_name, Obj_Namae_No_Atama) == 0) ObjectDelete(0, obj_name);
   }
   // カーソルとラベルも削除
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, Cursor_Tatesen_Namae);
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, Cursor_Label_Namae);
   
   // ボタンも削除
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, Button_Waku_Namae);
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, Button_Moji_Namae);
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, C_Button_Waku_Namae);
   // 指定した名前のチャートオブジェクトを削除します。
   ObjectDelete(0, C_Button_Moji_Namae);
}

//+------------------------------------------------------------------+
//| 初期化イベント(インジケータをチャートに入れた瞬間に1回動く)
//+------------------------------------------------------------------+
// インジケーターをチャートへセットした時に最初の1回だけ呼ばれる初期化関数です。
int OnInit()
{

// --- 1. バッファの登録(ウィンドウ確保用) ---
   // ★修正:INDICATOR_DATAだと数値が表示されてしまうため、計算用(CALCULATIONS)に変更
   // 0番バッファへDummyBufferを登録し、表示線ではなく内部計算用バッファとして扱います。
   SetIndexBuffer(0, DummyBuffer, INDICATOR_CALCULATIONS);
   
   // --- 2. 謎の数字を消すための設定(★ここが重要) ---
   // 「0.0」という数字が入っていたら、それは「空っぽ」扱いにして何も表示しない
   // PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); // ★修正:描画しないので削除(コメントアウト)
   
   // バッファの中に入っているゴミデータを捨てて、全部「0.0」で埋める(掃除)
   // DummyBufferの全要素を0.0で初期化し、未初期化値が残らないようにします。
   ArrayInitialize(DummyBuffer, 0.0);

   // --- 3. 見た目の設定 ---
   // ★修正:描画自体をOFFにしたため不要
   // PlotIndexSetString(0, PLOT_LABEL, "");             // ラベル(名前)を消す
   // PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE); // 線を描画しない(透明)
   
   // ★追加:インジケーター名が表示されるのも防ぐ
   // データウィンドウ等へ表示されるインジケーター短縮名を空文字にします。
   IndicatorSetString(INDICATOR_SHORTNAME, "");

   Zen_Obj_Sakujo(); // まず前の残骸があれば綺麗にする
   ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true); // マウスの動きを検知できるように設定ON
   Jikan_Hyouji_Koushin(); // 最初の描画を実行
   return(INIT_SUCCEEDED); // 「初期化成功」をMT5に伝える
}

//+------------------------------------------------------------------+
//| 終了イベント(インジケータを削除した時に1回動く)
//+------------------------------------------------------------------+
// インジケーター削除・時間足変更などで終了する時に呼ばれる後片付けイベントです。
void OnDeinit(const int reason)
{
   ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, false); // マウス検知設定をOFFに戻す
   Zen_Obj_Sakujo(); // 全部消して綺麗にする
   ChartRedraw();    // 最後に画面更新
}

//+------------------------------------------------------------------+
//| 計算イベント(価格が動くたびに何度も動く)
//+------------------------------------------------------------------+
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[])
{
   Jikan_Hyouji_Koushin(); // メインの描画処理を呼び出す
   return(rates_total);    // 処理した数をMT5に返す
}

//+------------------------------------------------------------------+
//| チャートイベント関数(クリック、マウス移動、サイズ変更などを検知して動く場所)
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // どんなイベントが起きたかのID(クリック?移動?変更?)
                  const long &lparam,   // パラメータ1 (マウスのX座標などが入る整数)
                  const double &dparam, // パラメータ2 (マウスのY座標などが入る小数)
                  const string &sparam) // パラメータ3 (クリックしたオブジェクトの名前などが入る文字)
{
   // --- パターン1:チャートの変更イベント ---
   // チャートのサイズが変わった、スクロールされた、ズームされた時など
   // スクロール・ズーム・サイズ変更など、チャート表示状態が変化した場合を判定します。
   if(id == CHARTEVENT_CHART_CHANGE)
   {
      // 表示範囲が変わっている可能性が高いので、日本時間の再計算と再描画を行う
      // 日本時間文字の計算・描画を実行します。
      Jikan_Hyouji_Koushin(); 
   }
   
   // --- パターン2:オブジェクトのクリックイベント ---
   // 画面上の何らかのオブジェクトがクリックされた時
   // チャート上のオブジェクトがクリックされた場合だけ、ボタン判定へ進みます。
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      // クリックされたオブジェクトの名前(sparam)が、このツールの「ボタン枠」か「ボタン文字」だったら
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(sparam == Button_Waku_Namae || sparam == Button_Moji_Namae)
      {
         // ★スイッチ切り替え処理
         // trueならfalseに、falseならtrueに反転させる(!マークは「否定/逆」の意味)
         // 「!」で現在値を反転し、ONならOFF、OFFならONへ切り替えます。
         Button_Switch_ON = !Button_Switch_ON; 
         
         // ボタンの見た目(緑色か白色など)を新しい状態に合わせて更新する
         Button_LINE(); 
         
         // もしOFFになったのなら、画面に残っているカーソル(縦線・ラベル)は邪魔なので即座に消す
         // L機能がOFFになった場合だけ、中に残っているカーソル表示を消します。
         if(!Button_Switch_ON)
         {
            // 指定した名前のチャートオブジェクトを削除します。
            ObjectDelete(0, Cursor_Tatesen_Namae);
            // 指定した名前のチャートオブジェクトを削除します。
            ObjectDelete(0, Cursor_Label_Namae);
         }
         
         // 変更を即座に画面に反映させる
         // チャートを再描画し、直前までの表示変更を画面へ反映します。
         ChartRedraw(); 
      }

      // クリックされたオブジェクトが表示内容切り替え用の「C」ボタンだったら
      // if文の条件がtrueになった場合だけ、続く処理を実行します。
      if(sparam == C_Button_Waku_Namae || sparam == C_Button_Moji_Namae)
      {
         // 年月日時分秒 → 年月日時分 → 時分秒 → 時分 → 月日 → 月 の順番で切り替える
         // Cボタンを1回押すごとに表示モード番号を1つ進めます。
         C_Hyouji_Mode++;
         // 6種類を一巡したら0へ戻し、再び最初の表示形式から繰り返します。
         if(C_Hyouji_Mode >= 6) C_Hyouji_Mode = 0;

         // Cボタンの見た目と、日本時間の表示内容を新しい状態に合わせて更新する
         Button_C();
         // 日本時間文字の計算・描画を実行します。
         Jikan_Hyouji_Koushin();
      }
   }
   
   // --- パターン3:マウスの移動イベント ---
   // マウスカーソルが動いた時(頻繁に発生します)
   // マウスが動いたイベントの場合だけ、カーソル表示の更新を行います。
   if(id == CHARTEVENT_MOUSE_MOVE)
   {
      // このインジケータが表示されているサブウィンドウの番号を取得
      // このインジケーターが入っているサブウィンドウ番号を取得します。
      int sub_window = ChartWindowFind();
      
      // カーソル更新関数を呼び出す
      // lparam にはマウスのX座標、dparamにはY座標が入っているので、それをキャスト(int)して渡す
      // 現在のマウスX・Y座標を整数へ変換し、カーソル更新関数へ渡します。
      Mouse_Cursor_Koushin(0, (int)lparam, (int)dparam, sub_window);
   }
}



コメントをお待ちしています

タイトルとURLをコピーしました