
//USD/JPY の 5､30､4H 足で動作します
//dft 値 夏時間冬時間自動判定に改善

//+-------------------------------------------------+
//|                                 UWCSV_Multi.mq4 |
//|                                        Kurokuwa |
//|時間軸ごとの価格履歴をﾃｷｽﾄﾌｧｲﾙ(CSV 形式)で出力   |
//|豊島久道著 FX実践ﾌﾟﾛｸﾞﾗﾐﾝｸﾞを参照しました        |
//|  感謝                                           |
//|                                                 |
//|2025/09/23 USDJPY価格ﾃﾞｰﾀの出力ﾌﾟﾛｸﾞﾗﾑです       |
//|    5分足､30分足､4時間足を出力します             |
//|2025/09/08 ﾌﾟﾛｸﾞﾗﾑから時間軸の変更を試みましたが |
//|           うまくいきませんでした                |
//|           各時間軸で実行する必要があります      |
//|2026/01/03 google jemini さんの教えでMulti版に   |
//|           できました｡感謝                       |
//|2026/02/03 現在足 05SMA 20SMA 追加               |
//|2026/02/25 米国式夏時間の判定関数追加            |
//|           Geminiさんに教示いただきました(感謝)  |
//|                                                 |
//+-------------------------------------------------+
#property copyright "Kurokuwa"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+-------------------------------------------------+
//| Script program start function                   |
//+-------------------------------------------------+
extern double BBDev  = 1.9;  // [cite: 9]
extern int BBPeriod  = 20;   // [cite: 9]
extern int ATRPeriod = 20;   // [cite: 9]
extern int RSIPeriod = 14;   // [cite: 10]

//変数の定義
datetime dtm; //現在日時
string smb, str, sHi, sLo, sCl, sat, srs, sh1, sh4; 
string s05, s20, sd1, sb0L, sb0U, sb1L, sb1U, sb4L, sb4U;
string sSDate, sSTime, sLDate, sLTime; //ｻｰﾊﾞ ﾛｰｶﾙ
string spst[];
int    id1, id4, idd, j, sepnum, iStart, handle, iPer;
double dat, drs, d05, d20, dh1, dh4, dd1, dHi, dLo, dCl;
double db0L, db0U, db1L, db1U, db4L, db4U;


//+-------------------------------------------------+
//| 米国式夏時間の判定関数 (内部計算用)             |
//+-------------------------------------------------+
bool IsUSSummerTime(datetime dt) {
   MqlDateTime t;
   TimeToStruct(dt, t);
   
   // その年の3月1日の曜日から､第2日曜日を計算
   datetime march1st = 
     StringToTime(IntegerToString(t.year) 
     + ".03.01 00:00");
   MqlDateTime m1; TimeToStruct(march1st, m1);
   int marchSecondSundayDay = 
     1 + (14 - (m1.day_of_week == 0 ? 7 : 
     m1.day_of_week)) % 7 + 7;
   datetime startDST = 
     StringToTime(IntegerToString(t.year) 
     + ".03." 
     + IntegerToString(marchSecondSundayDay) 
     + " 02:00");
   
   // その年の11月1日の曜日から､第1日曜日を計算
   datetime nov1st = 
     StringToTime(IntegerToString(t.year) 
     + ".11.01 00:00");
   MqlDateTime n1; TimeToStruct(nov1st, n1);
   int novFirstSundayDay = 
     1 + (7 - (n1.day_of_week == 0 ? 7 : 
     n1.day_of_week)) % 7;
   datetime endDST = 
     StringToTime(IntegerToString(t.year) 
     + ".11." 
     + IntegerToString(novFirstSundayDay) 
     + " 02:00");
   
   return (dt >= startDST && dt < endDST);
}




void OnStart()
{
  //ｻｰﾊﾞ日時とﾛｰｶﾙ日時の差
  datetime lnow, snow, dft; //ﾛｰｶﾙ時間 ｻｰﾊﾞ時間 差
  MqlDateTime tst;
  lnow = TimeLocal();   //ﾛｰｶﾙ時間
  snow = TimeCurrent(); //ｻｰﾊﾞ時間
  // ｻｰﾊﾞｰ時間とﾛｰｶﾙ時間の差 (秒) [cite: 12]
  
  //dft = 3600 * 7; //6時間の時間差 秒で表現 冬時間は7 夏時間は6
  
  // --- 夏時間判定に基づき時差(dft)を決定 ---
  dft = IsUSSummerTime(snow) ? 3600 * 6 : 3600 * 7;
  //datetime localTime = snow + dft;
 

  smb = "USDJPY"; // [cite: 19]
  if (_Symbol != smb) {
      Print("USDJPYのﾁｬｰﾄで実行してください｡");
      return;
  }

  // 出力対象の時間軸を定義 
  int targetPeriods[] = {PERIOD_M5, PERIOD_M30, PERIOD_H4};
  string fileNames[]  = {"USDJPYM05.CSV", "USDJPYM30.CSV", "USDJPYH04.CSV"};

  // 各時間軸ごとにﾙｰﾌﾟ処理
  for(int p = 0; p < ArraySize(targetPeriods); p++)
  {
    iPer = targetPeriods[p];
    string strFile = fileNames[p];
    
   //--- 過去ﾃﾞｰﾀの強制ﾛｰﾄﾞ ---
   // これを行わないと iBarsが少ない値を返して
   //途中で終わることがある
    while(!iTime(smb, iPer, iBars(smb, iPer)-1) && 
     !IsStopped()) Sleep(10);

   // ﾌｧｲﾙｵｰﾌﾟﾝ (読込/書込用) [cite: 20]
    handle = FileOpen(strFile, FILE_CSV|FILE_READ|FILE_WRITE, ',');
    if(handle == INVALID_HANDLE) continue;

    // 既存ﾃﾞｰﾀがある場合の開始位置特定 [cite: 22, 23, 24, 25]
    if(FileSize(handle) > 1000) {
       FileSeek(handle,  -1000, SEEK_END);  //多めに戻る
       //行の末尾まで飛ばして最終ﾚｺｰﾄﾞを特定する
       string tempDate = "", tempTime="";
       //ﾌｧｲﾙの最後まで全て読込､一番最後に見つかった
       //日付と時刻を保持する
       int col = 0;
       while(!FileIsEnding(handle)){
         string s = FileReadString(handle);
         //文字列に / が含まれている場合のみ取得
         if(col == 0 && StringFind(s, "/") >= 0){
           tempDate = s;
           tempTime = FileReadString(handle); //次は時刻
           col = 1; //時刻まで読んだので col = 1 に設定
         }
         col ++;
         //このｽｸﾘﾌﾟﾄは1行に20列読み込んでいるため
         //20列読んだらﾘｾｯﾄ
         if(col >= 20) col = 20;
       } 
       // 日付形式の変換 (yyyy/mm/dd -> yyyy.mm.dd)
       if(tempDate != ""){
         StringReplace(tempDate, "/", ".");
         dtm = StrToTime(tempDate + " " + tempTime);
       }  
       //ﾛｸﾞを出力して確認できるようにする
       Print(strFile + " の最終記録日時: " + 
            tempDate + " " + tempTime);
            
       // 最終行の次から開始 [cite: 25]
       iStart = iBarShift(smb, iPer, dtm) - 1;
       //最新ﾃﾞｰﾀがある場合はｽｷｯﾌﾟ
       if(iStart < 0){
          FileClose(handle);
          Print(strFile + " は最新です｡");
          continue;
       }
    } else {
       //新規作成時はﾁｬｰﾄにある全期間(ただし確定足まで)
       iStart = iBars(smb, iPer) - 1;
    }
    
    FileSeek(handle, 0, SEEK_END); // 追記ﾓｰﾄﾞ [cite: 24]

    // ﾃﾞｰﾀ書出しﾙｰﾌﾟ [cite: 26]
    // j = 0 (現在の足) は変動するため､
    //  確定した j=1 から書出
    for(j = iStart; j >= 0; j--)
    {
      datetime barTime = iTime(smb, iPer, j);

      // ｻｰﾊﾞｰ日時 [cite: 27, 28]
      TimeToStruct(barTime, tst);
      sSDate = StringFormat("%4d/%02d/%02d",
         tst.year, tst.mon, tst.day);
      sSTime = StringFormat("%02d:%02d",
         tst.hour, tst.min);

      // ﾛｰｶﾙ日時 [cite: 29, 30, 31]
      TimeToStruct(barTime + dft, tst);
      sLDate = StringFormat("%4d/%02d/%02d",
         tst.year, tst.mon, tst.day);
      sLTime = StringFormat("%02d:%02d",
         tst.hour, tst.min);

      // 価格とｲﾝﾃﾞｨｹｰﾀ [cite: 31, 32]
      dHi = iHigh(smb, iPer, j);
      dLo = iLow(smb, iPer, j);
      dCl = iClose(smb, iPer, j);
      sHi = DoubleToStr(dHi, 3);
      if(sHi == "0.000") sHi = "000.000";
      sLo = DoubleToStr(dLo, 3);
      sCl = DoubleToStr(dCl, 3);

      // 他の時間軸のｲﾝﾃﾞｯｸｽを取得 (iBarShiftを使用)
      //   [cite: 43, 44, 45]
      id1 = iBarShift(smb, PERIOD_H1, barTime);
      id4 = iBarShift(smb, PERIOD_H4, barTime);
      idd = iBarShift(smb, PERIOD_D1, barTime);

      // ｲﾝｼﾞｹｰﾀｰ計算 (ｼﾌﾄに j または計算した id を指定)
      //   [cite: 43-52]
      d05 = iMA(smb, iPer,  5, 0, MODE_SMA, PRICE_CLOSE, j);
      d20 = iMA(smb, iPer, 20, 0, MODE_SMA, PRICE_CLOSE, j);
      dh1 = iMA(smb, PERIOD_H1, 20, 0,
                MODE_SMA, PRICE_CLOSE, id1);
      dh4 = iMA(smb, PERIOD_H4, 20, 0, 
                MODE_SMA, PRICE_CLOSE, id4);
      dd1 = iMA(smb, PERIOD_D1, 20, 0, 
                 MODE_SMA, PRICE_CLOSE, idd);
      dat = iATR(smb, iPer, ATRPeriod, j);
      drs = iRSI(smb, iPer, RSIPeriod, 
                 PRICE_CLOSE, j);
      
      // ﾎﾞﾘﾝｼﾞｬｰﾊﾞﾝﾄﾞ [cite: 47-52]
      db0L = iBands(smb, iPer, BBPeriod, BBDev, 0, 
                    PRICE_CLOSE, MODE_LOWER, j);
      db0U = iBands(smb, iPer, BBPeriod, BBDev, 0,
                    PRICE_CLOSE, MODE_UPPER, j);
      db1L = iBands(smb, PERIOD_H1, BBPeriod, BBDev, 0, 
                    PRICE_CLOSE, MODE_LOWER, id1);
      db1U = iBands(smb, PERIOD_H1, BBPeriod, BBDev, 0,
                    PRICE_CLOSE, MODE_UPPER, id1);
      db4L = iBands(smb, PERIOD_H4, BBPeriod, BBDev, 0,
                    PRICE_CLOSE, MODE_LOWER, id4);
      db4U = iBands(smb, PERIOD_H4, BBPeriod, BBDev, 0,
                    PRICE_CLOSE, MODE_UPPER, id4);

      s05 = DoubleToStr(d05, 3); //現在足移動平均 05
      s20 = DoubleToStr(d20, 3); //現在足移動平均 20
      sh1 = DoubleToStr(dh1, 3); //1H足単純移動平均 20
      if(sh1 == "0.000") sh1 = "000.000";
      sh4 = DoubleToStr(dh4, 3); //4H足単純移動平均 20
      if(sh4 == "0.000") sh4 = "000.000";
      sd1 = DoubleToStr(dd1, 3); //日足単純移動平均 20
      if(sd1 == "0.000") sd1 = "000.000";
      sat = DoubleToStr(dat, 3); //ATR 20
      srs = DoubleToStr(drs, 3); //RSI 14
      if(srs == "0.000") srs = "00.000";
      sb0L = DoubleToStr(db0L, 3); //現在足 BB Lower
      if(sb0L == "0.000") sb0L = "000.000";
      sb0U = DoubleToStr(db0U, 3); //現在足 BB Upper
      if(sb0U == "0.000") sb0U = "000.000";
      sb1L = DoubleToStr(db1L, 3); //1H足 BB Lower
      if(sb1L == "0.000") sb1L = "000.000";
      sb1U = DoubleToStr(db1U, 3); //1H足 BB Upper
      if(sb1U == "0.000") sb1U = "000.000";
      sb4L = DoubleToStr(db4L, 3); //4H足 BB Lower
      if(sb4L == "0.000") sb4L = "000.000";
      sb4U = DoubleToStr(db4U, 3); //4H足 BB Upper
      if(sb4U == "0.000") sb4U = "000.000";
     
      
      
      
      // ﾌｧｲﾙ書き出し [cite: 59]
      FileWrite(handle, sSDate, sSTime, sHi, sLo, sCl, 
        s05, s20, sh1, sh4, sd1, sat, srs, sb0L, sb0U, 
        sb1L, sb1U, sb4L, sb4U, sLDate, sLTime); 
    }
    FileClose(handle); // [cite: 60]
    Print(strFile + " の書き出しが完了しました｡");
  }

  MessageBox("全時間軸のﾃﾞｰﾀ出力が完了しました｡");
}
//+-------------------------------------------------+

