//+------------------------------------------------------------------+
//|                                     08_MultiSymbol_Overlay.mq5   |
//|                                     Copyright 2026, FX Blog AI   |
//|                           https://fx-omoshiro-lab.com/           |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX Blog AI"
#property link      "https://fx-omoshiro-lab.com/"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   1

//--- plot OverlayLine
#property indicator_label1  "Overlay"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- input parameters
input string   InpSubSymbol   = "USDJPY"; // 重ねて表示する通貨ペア
input bool     InpAutoScaling = true;     // 自動スケール調整 (画面内の高安に合わせる)

//--- indicator buffers
double         OverlayBuffer[];
double         RawBuffer[]; // raw data buffer (internal)

//--- global variables
int            sub_symbol_digits;
string         SubSymbolName; // 実際に使用するシンボル名（サフィックス補完後）

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- indicator buffers mapping
   SetIndexBuffer(0,OverlayBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,RawBuffer,INDICATOR_CALCULATIONS);
   
   //--- 配列を時系列（0が最新）に設定
   ArraySetAsSeries(OverlayBuffer, true);
   ArraySetAsSeries(RawBuffer, true);
   
   //--- シンボルの存在確認と自動検知
   string actual_symbol = GetActualSymbol(InpSubSymbol);
   
   if(!SymbolInfoInteger(actual_symbol, SYMBOL_SELECT))
   {
      if(!SymbolSelect(actual_symbol, true))
      {
         Alert("指定された通貨ペア '" + InpSubSymbol + "' (または '" + actual_symbol + "') が見つかりません。");
         return(INIT_FAILED);
      }
   }
   
   // 名前が補完された場合、内部変数を更新する必要があるが、
   // InpSubSymbolはinput変数なので変更不可。
   // そのため、これ以降は実際のシンボル名を使う必要がある。
   // グローバル変数として保持するか、入力パラメータを無視して内部で解決するか。
   // ここではグローバル変数 SubSymbolName を定義して使うのが安全。
   SubSymbolName = actual_symbol;
   
   if(SubSymbolName != InpSubSymbol)
   {
      Print("Suffix detected: Changed '" + InpSubSymbol + "' to '" + SubSymbolName + "'");
   }
     
   //--- サブシンボルの小数点桁数を取得
   sub_symbol_digits = (int)SymbolInfoInteger(SubSymbolName, SYMBOL_DIGITS);
   
   //--- プロット設定
   PlotIndexSetString(0, PLOT_LABEL, SubSymbolName);
   
   //--- インジケータ短縮名
   string short_name = "Overlay(" + SubSymbolName + ")";
   IndicatorSetString(INDICATOR_SHORTNAME, short_name);
   
   return(INIT_SUCCEEDED);
  }
  
//+------------------------------------------------------------------+
//| 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 limit;
   
   if(prev_calculated == 0)
   {
      limit = rates_total;
      // 初回計算時は全バッファ初期化
      ArrayInitialize(OverlayBuffer, EMPTY_VALUE);
      ArrayInitialize(RawBuffer, 0.0);
   }
   else
   {
      limit = rates_total - prev_calculated;
      // 新しいバーが追加された場合、その分だけ計算
      if(limit > 0) limit++; 
   }
   
   //--- 時系列配列を設定
   ArraySetAsSeries(time, true);
   ArraySetAsSeries(high, true); 
   ArraySetAsSeries(low, true); 
   // OverlayBuffer, RawBufferはOnInitで設定済み

   //====================================================================
   // Phase 1: データ取得 (Heavy Task)
   //====================================================================
   int fetch_start = limit;
   if(fetch_start >= rates_total) fetch_start = rates_total - 1;
   
   for(int i = fetch_start; i >= 0; i--)
   {
      datetime bar_time = time[i];
      
      // iBarShift は重いので、ループ回数が多い時は要注意
      int sub_shift = iBarShift(SubSymbolName, PERIOD_CURRENT, bar_time);
      
      double sub_val = 0;
      if(sub_shift >= 0)
      {
         sub_val = iClose(SubSymbolName, PERIOD_CURRENT, sub_shift);
      }
      
      RawBuffer[i] = sub_val;
   }
   
   //====================================================================
   // Phase 2: スケーリングと描画 (Light Task)
   //====================================================================
   UpdateOverlay(rates_total, time, high, low);
   
   return(rates_total);
   }

// ... (existing functions) ...

//+------------------------------------------------------------------+
//| Helper: Auto-detect symbol suffix                                |
//+------------------------------------------------------------------+
string GetActualSymbol(string base_name)
{
   // 1. そのままの名前で存在するか確認
   if(SymbolInfoInteger(base_name, SYMBOL_SELECT)) return base_name;
   if(SymbolSelect(base_name, true)) return base_name;

   // 2. 現在のチャートのシンボルからサフィックスを推定
   string current_symbol = _Symbol;
   string suffix = "";
   
   // 一般的なメジャー通貨ペア名が含まれているか確認し、その差分をサフィックスとする
   string major_pairs[] = {"EURUSD", "USDJPY", "GBPUSD", "AUDUSD", "USDCAD", "USDCHF", "NZDUSD", "EURJPY", "GBPJPY"};
   
   for(int i = 0; i < ArraySize(major_pairs); i++)
   {
      if(StringFind(current_symbol, major_pairs[i]) == 0) // 前方一致
      {
         // "EURUSD.m" - "EURUSD" = ".m"
         suffix = StringSubstr(current_symbol, StringLen(major_pairs[i]));
         break;
      }
   }
   
   // サフィックスが見つかった場合、付加して試す
   if(suffix != "")
   {
      string try_name = base_name + suffix;
      if(SymbolSelect(try_name, true)) return try_name;
   }
   
   // 3. それでもダメなら、MarketWatchにあるシンボルから前方一致で探す（高負荷なので最終手段）
   // 3. それでもダメなら、MarketWatchにあるシンボルから前方一致で探す（高負荷なので最終手段）
   // ここでは簡易的に元の名前を返す
   return base_name;
}

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   // チャートがスクロールまたはズームされたら再描画
   if(id == CHARTEVENT_CHART_CHANGE)
   {
      if(InpAutoScaling)
      {
         // 以前の ChartSetSymbolPeriod は prev_calculated=0 を引き起こし、
         // 重いデータ取得処理(Phase 1)を誘発するため廃止。
         // 代わりに軽量な UpdateOverlay を直接呼ぶ。
         UpdateOverlay();
         ChartRedraw();
      }
   }
  }

//+------------------------------------------------------------------+
//| Helper: Update Overlay Buffer (Scaling & Rendering)              |
//| Version for OnCalculate (Using provided arrays)                  |
//+------------------------------------------------------------------+
void UpdateOverlay(const int rates_total, const datetime &time[], const double &high[], const double &low[])
{
   double main_max = 0;
   double main_min = 0;
   double sub_max  = 0;
   double sub_min  = 0;

   //--- スケーリング情報の計算 (AutoScaling有効時)
   if(InpAutoScaling)
   {
      // 表示されているバーの範囲を取得
      long chart_id = ChartID();
      int visible_bars = (int)ChartGetInteger(chart_id, CHART_VISIBLE_BARS);
      int first_bar    = (int)ChartGetInteger(chart_id, CHART_FIRST_VISIBLE_BAR);
      
      main_max = -DBL_MAX;
      main_min = DBL_MAX;
      sub_max  = -DBL_MAX;
      sub_min  = DBL_MAX;
      
      int end_bar = first_bar - visible_bars + 1;
      if(end_bar < 0) end_bar = 0;
      
      // Visible範囲のMax/Min計算
      for(int i = first_bar; i >= end_bar; i--)
      {
         if(i >= rates_total) continue;
         
         // メインチャート (配列使用)
         double h = high[i];
         double l = low[i];
         
         if(h > main_max) main_max = h;
         if(l  < main_min) main_min = l;
         
         // サブシンボル (RawBuffer)
         if(i < ArraySize(RawBuffer))
         {
            double val = RawBuffer[i];
            if(val > 0)
            {
               if(val > sub_max) sub_max = val;
               if(val < sub_min) sub_min = val;
            }
         }
      }
      
      if(main_max == main_min) main_max += _Point;
      if(sub_max == sub_min)   sub_max += _Point;
   }

   //--- バッファ計算 (描画)
   // 全体再描画
   int size = ArraySize(OverlayBuffer);
   if(size > rates_total) size = rates_total;
   
   for(int i = size - 1; i >= 0; i--)
   {
      double sub_val = RawBuffer[i];
      
      if(sub_val > 0)
      {
         if(InpAutoScaling)
         {
             if(sub_max != sub_min)
             {
                double normalized = (sub_val - sub_min) * (main_max - main_min) / (sub_max - sub_min) + main_min;
                OverlayBuffer[i] = normalized;
             }
             else
             {
                OverlayBuffer[i] = main_min + (main_max - main_min)/2;
             }
         }
         else
         {
            OverlayBuffer[i] = sub_val;
         }
      }
      else
      {
         OverlayBuffer[i] = EMPTY_VALUE;
      }
   }
}

//+------------------------------------------------------------------+
//| Helper: Update Overlay Buffer (Scaling & Rendering)              |
//| Version for OnChartEvent (Using API calls, no arrays)            |
//+------------------------------------------------------------------+
void UpdateOverlay()
{
   int rates_total = Bars(_Symbol, _Period);
   
   double main_max = 0;
   double main_min = 0;
   double sub_max  = 0;
   double sub_min  = 0;

   //--- スケーリング情報の計算 (AutoScaling有効時)
   if(InpAutoScaling)
   {
      long chart_id = ChartID();
      int visible_bars = (int)ChartGetInteger(chart_id, CHART_VISIBLE_BARS);
      int first_bar    = (int)ChartGetInteger(chart_id, CHART_FIRST_VISIBLE_BAR);
      
      main_max = -DBL_MAX;
      main_min = DBL_MAX;
      sub_max  = -DBL_MAX;
      sub_min  = DBL_MAX;
      
      int end_bar = first_bar - visible_bars + 1;
      if(end_bar < 0) end_bar = 0;
      
      // Visible範囲のMax/Min計算
      for(int i = first_bar; i >= end_bar; i--)
      {
         if(i >= rates_total) continue;
         
         // メインチャート (API利用)
         double h = iHigh(_Symbol, _Period, i);
         double l = iLow(_Symbol, _Period, i);
         
         if(h > main_max) main_max = h;
         if(l  < main_min) main_min = l;
         
         // サブシンボル (RawBuffer)
         if(i < ArraySize(RawBuffer))
         {
            double val = RawBuffer[i];
            if(val > 0)
            {
               if(val > sub_max) sub_max = val;
               if(val < sub_min) sub_min = val;
            }
         }
      }
      
      if(main_max == main_min) main_max += _Point;
      if(sub_max == sub_min)   sub_max += _Point;
   }

   //--- バッファ計算 (描画)
   int size = ArraySize(OverlayBuffer);
   if(size > rates_total) size = rates_total;
   
   for(int i = size - 1; i >= 0; i--)
   {
      double sub_val = RawBuffer[i];
      
      if(sub_val > 0)
      {
         if(InpAutoScaling)
         {
             if(sub_max != sub_min)
             {
                double normalized = (sub_val - sub_min) * (main_max - main_min) / (sub_max - sub_min) + main_min;
                OverlayBuffer[i] = normalized;
             }
             else
             {
                OverlayBuffer[i] = main_min + (main_max - main_min)/2;
             }
         }
         else
         {
            OverlayBuffer[i] = sub_val;
         }
      }
      else
      {
         OverlayBuffer[i] = EMPTY_VALUE;
      }
   }
}


//+------------------------------------------------------------------+
//| Sub-Support functions (Optional helper logic if needed)          |
//+------------------------------------------------------------------+
// Note: iBarShift, iClose, iTime are now built-in MQL5 functions.
// We removed the custom implementations to avoid conflicts.
