//USD/JPY の 5､30､4H 足で動作します

//+-------------------------------------------------+
//|                                UWCSV_script.mq4 |
//|                                        Kurokuwa |
//|時間軸ごとの価格履歴をﾃｷｽﾄﾌｧｲﾙ(CSV 形式)で出力   |
//|豊島久道著 FX実践ﾌﾟﾛｸﾞﾗﾐﾝｸﾞを参照しました        |
//|  感謝                                           |
//|                                                 |
//|2025/09/23 USDJPY価格ﾃﾞｰﾀの出力ﾌﾟﾛｸﾞﾗﾑです       |
//|    5分足､30分足､4時間足を出力します             |
//|2025/09/08 ﾌﾟﾛｸﾞﾗﾑから時間軸の変更を試みましたが |
//|           うまくいきませんでした                |
//|           各時間軸で実行する必要があります      |
//|2026/02/23 米国式夏時間の判定関数追加            |
//|           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;
extern int BBPeriod  = 20;
extern int ATRPeriod = 20;
extern int RSIPeriod = 14;



//+-------------------------------------------------+
//| 米国式夏時間の判定関数 (内部計算用)             |
//| あまりうまくいきません                          |
//| 下記の dft = 3600*? の数値を 6(夏) 7(冬)に手動修正|
//+-------------------------------------------------+
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(); //ｻｰﾊﾞｰ時間
 
  // --- 夏時間判定に基づき時差(dft)を決定 ---
  dft = IsUSSummerTime(snow) ? 3600 * 6 : 3600 * 7;
  dft = 3600 * 6; //6時間の時間差 秒で表現 冬時間は7 夏時間は6
  datetime localTime = snow + dft;

  datetime dtm; //現在日時
  string smb, str, sHi, sLo, sCl, sat, srs, sh0, sh1, sh4; 
  string s05, 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, dh0, dh1, dh4, dd1;
  double db0L, db0U, db1L, db1U, db4L, db4U;


  //Period = 5 5分足ﾌｧｲﾙの書出
  //spr = "M05"; // 5分足
  iPer = _Period;
  switch(iPer){
    case  05: str = "USDJPYM05.CSV"; break;
    case  30: str = "USDJPYM30.CSV"; break;
    case 240: str = "USDJPYH04.CSV"; break;
    default:  return;
  }

  smb = "USDJPY";  //ｼﾝﾎﾞﾙ
  if (_Symbol != smb) return;
  
  //ﾌｧｲﾙの最後の行を読込む
  //ﾌｧｲﾙｵｰﾌﾟﾝ(読込/書込用) なければ作成
  handle = FileOpen( str,
           FILE_CSV|FILE_READ|FILE_WRITE, ',' );
  if(handle == INVALID_HANDLE) return;

  //最終行の 2行前 最終項目
  FileSeek(handle, -167, SEEK_END);
  str = FileReadString(handle); //2行前の最終項目読込
  //MessageBox(str);
  str = FileReadString(handle); //最終行の日付
  //MessageBox(str);

  sepnum = StringSplit(str, '/', spst);
  if(sepnum>0) str = spst[0] + "." + spst[1] + 
    "." + spst[2];
  str = str + " " + FileReadString(handle); //最終行の時間
  
  FileSeek(handle, 0, SEEK_END);  //最終位置に移動

  dtm = StrToTime(str);
  iStart = iBarShift(smb, iPer, dtm) -1;

  //最終行の後に追加するのでﾀｲﾄﾙは書き出さない
  //FileWrite(handle, "SDate", "STime",
  //  "High", "Low", "Close", 
  //  "M05", "M20", "H1AV20", "H4AV20", "D1AV20", 
  //  "ATR", "RSI", "B0L", "B0U", "B1L", "B1U", "B4L", "B4U",
  //  "LDate","LTime"); 
  
  id1 = 0;  id4 = 0;  idd = 0;
  for(j = iStart; j >= 0; j--){
    //ｻｰﾊﾞ日時
    TimeToStruct(Time[j], tst);
    sSDate = //例: 2024/06/01
      StringFormat("%4d/%02d/%02d", tst.year, tst.mon,
      tst.day);
    sSTime =  //24:00
      StringFormat("%02d:%02d", tst.hour, tst.min); 

    //ﾛｰｶﾙ日時
    lnow = Time[j] + dft;
    TimeToStruct(lnow, tst);
    sLDate = //例: 2024/06/01
      StringFormat("%4d/%02d/%02d", tst.year, tst.mon,
      tst.day); 
    sLTime = //24:00
      StringFormat("%02d:%02d", tst.hour, tst.min); 

    //価格とｲﾝﾃﾞｨｹｰﾀ
    sHi = DoubleToStr(High[j], 3); //高値
    if (sHi == "0.000") sHi = "000.000"; 
    sLo = DoubleToStr(Low[j], 3);  //安値
    sCl = DoubleToStr(Close[j], 3);//終値

    //idv決定他の時間軸の j 計算
    // 他の時間軸のｲﾝﾃﾞｯｸｽを取得 (iBarShiftを使用)
    // Gemini 様 に関数を教えて頂く(感謝)
    datetime barTime = iTime(smb, iPer, j);
    id1 = iBarShift(smb, PERIOD_H1, barTime);
    id4 = iBarShift(smb, PERIOD_H4, barTime);
    idd = iBarShift(smb, PERIOD_D1, barTime);

    //switch(iPer){
    //  case  05: id1 = j /  12; // 60/ 05 = 12
    //            id4 = j /  48; //240/ 05 = 48
    //            idd = j / 288; //1440/05 = 288
    //            break;
    //  case  30: id1 = j /   2; // 60/ 30 =  2
    //            id4 = j /   8; //240/ 30 =  8
    //            idd = j /  48; //1440/30 = 48
    //            break;
    //  case 240: id1 = j *   4; // 60/240 = 0.25 
    //            id4 = j;       //240/240 =  1
    //            idd = j /   6; //1440/240 = 6
    //            break;
    //}


    //ｲﾝﾃﾞｨｹｰﾀ計算
    d05 = iMA(smb, iPer, 05, 0, MODE_SMA,
      PRICE_CLOSE, j);
    dh0 = 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);
    
    //ATR, RSI を加える
    dat = iATR(smb, 0, ATRPeriod, j);
    drs = iRSI(smb, 0, RSIPeriod, PRICE_CLOSE, j);

    //BB ﾎﾞﾘﾝｼﾞｬｰﾊﾞﾝﾄﾞを加える
    db0L = iBands(smb, iPer, BBPeriod, BBDev, 0,
        PRICE_CLOSE, MODE_LOWER, j); //現在足 Lower
    db0U = iBands(smb, iPer, BBPeriod, BBDev, 0,
        PRICE_CLOSE, MODE_UPPER, j); //現在足 Upper
    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
    sh0 = DoubleToStr(dh0, 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";

    FileWrite(handle, sSDate, sSTime, sHi, sLo, sCl,
      s05, sh0, sh1, sh4, sd1, sat, srs, sb0L, sb0U, 
      sb1L, sb1U, sb4L, sb4U, sLDate, sLTime);
  }
  //ﾌｧｲﾙｸﾛｰｽﾞ
  FileClose(handle);

  //MessageBox("Last Time: " + sLTime);
  MessageBox("End of WriteData");

}
//+-------------------------------------------------+
