periodgen
Download scriptThis script is designed to automate the generation of historical trading data across multiple timeframes using a single source of minute-by-minute data. Instead of requiring you to manually calculate or download every different timeframe (like 5-minute, 30-minute, or 4-hour charts), this tool "builds" them for you from a raw M1 (1-minute) data file.
How the Logic Works
1. Data Input and Setup The script starts by looking into a specific folder on your computer (the "databank") to find a historical record of 1-minute price movements for a specific asset. It also allows for a "Time Shift" adjustment, which ensures the data aligns correctly with your specific server's clock.
2. Creating Multiple Outputs The script is programmed to simultaneously create seven different timeframes: M1, M5, M15, M30, H1, H4, and D1. For each of these, it creates a new individual data file.
3. Processing the Data (The Conversion Engine) The core logic works by reading the 1-minute data line by line and "grouping" the information:
- Aggregation: As it reads every minute, it checks if that minute belongs to a new candle for the larger timeframes (for example, every 5 minutes for an M5 chart).
- Price Calculation:
- If the current minute is still part of an ongoing candle (like the 3rd minute of a 5-minute block), it updates the "High" price if the current price is higher, the "Low" price if it is lower, and adds to the total "Volume."
- Once a minute crosses into a new candle boundary, it "saves" the final data for the previous candle (closing price, final high, and final low) into its respective file.
- Progress Tracking: While processing large amounts of data, the script provides feedback by calculating the percentage of completion based on the total number of records found.
4. Logging and Completion Throughout the process, the script maintains a log file. This log records:
- The specific asset and files being processed.
- Header information (like versioning and time stamps).
- The exact start and end times of the data.
- A final summary showing exactly how many records were created for each timeframe.
Summary for the User
Essentially, this script acts as a data factory. You provide it with one large "raw" file of 1-minute data, and it automatically "repackages" that information into all the standard timeframes you need for your analysis, ensuring that every high, low, and closing price is mathematically accurate based on the original minute-by-minute movements.
//+------------------------------------------------------------------+
//| periodgen.mq4 |
//| Igor Morozov |
//+------------------------------------------------------------------+
//| Quickly create historical data from M1 data. Change TIMESHIFT to |
//| shift time for your server. |
//| Steps to create data: |
//| 1. create subfolder .../experts/files/databank/ |
//| 2. copy M1 data into databank and call M1_XXXXXX.hst |
//| (alpari format) |
//| 3. attach script 'periodgen' to the same chart XXXXXX, frame |
//| doesn't matter |
//| 4. It will create subfolder .../experts/files/databank/XXXXXX |
//| in which you will find all timeframes up to D1 will be |
//| generated |
//+------------------------------------------------------------------+
#property copyright "Igor Morozov"
#property link ""
//----
#include <stdlib.mqh>
#define NUM_FILES 7
#define DATA_FOLDER "databank"
#define BS "\\"
#define TIMESHIFT 3 // timeshift in hours
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
// initialize
int i;
int iFile, lFile, pFile[7];
string iFileName = "M1_" + Symbol() + ".hst"; // alpari input file
string lFileName = Symbol() + BS + Symbol() + ".log";
int pTime[NUM_FILES];
double pOpen[NUM_FILES];
double pLow[NUM_FILES];
double pHigh[NUM_FILES];
double pClose[NUM_FILES];
double pVolume[NUM_FILES];
int pCount[NUM_FILES];
int pPeriod[NUM_FILES];
pPeriod[0] = PERIOD_M1;
pPeriod[1] = PERIOD_M5;
pPeriod[2] = PERIOD_M15;
pPeriod[3] = PERIOD_M30;
pPeriod[4] = PERIOD_H1;
pPeriod[5] = PERIOD_H4;
pPeriod[6] = PERIOD_D1;
string pFileName[NUM_FILES];
for(i = 0; i < NUM_FILES; i++)
pFileName[i] = Symbol() + BS + Symbol() + pPeriod[i] + ".hst";
int f_Unused[13];
// open files
iFile = FileOpen(DATA_FOLDER + BS + iFileName, FILE_BIN|FILE_READ);
if(iFile < 0)
{
Print(iFileName, " Open Error: ", ErrorDescription(GetLastError()));
return(0);
}
lFile = FileOpen(DATA_FOLDER + BS + lFileName, FILE_CSV|FILE_WRITE, " ");
if(lFile < 0)
{
Print(lFileName, " Open Error: ", ErrorDescription(GetLastError()));
return(0);
}
if(FileSize(iFile) < 192)
{
Print(iFileName, " has no data");
return(0);
}
for(i = 0; i < NUM_FILES; i++)
{
pFile[i] = FileOpen(DATA_FOLDER + BS + pFileName[i], FILE_BIN|FILE_WRITE);
if(pFile[i] < 0)
{
Print(pFileName[i], " Open Error: ", ErrorDescription(GetLastError()));
return(0);
}
}
FileWrite(lFile, TimeToStr(TimeCurrent()));
FileWrite(lFile, "Creating all timeframes for", Symbol(), "from",
DATA_FOLDER + BS + iFileName);
FileWrite(lFile, "Time Shift ", TIMESHIFT);
// read header
int f_Version = FileReadInteger(iFile);
string f_CopyRight = FileReadString(iFile, 64);
string f_Symbol = FileReadString(iFile, 12);
int f_Period = FileReadInteger(iFile);
int f_Digits = FileReadInteger(iFile);
int f_TimeStamp = FileReadInteger(iFile);
int f_Sync = FileReadInteger(iFile);
FileReadArray(iFile, f_Unused, 0, 13);
FileWrite(lFile, "*------------------------------------------------");
FileWrite(lFile, "Header Information copied:");
FileWrite(lFile, " Version:", "\t", f_Version);
FileWrite(lFile, " CopyRight:", "\t", f_CopyRight);
FileWrite(lFile, " Symbol:", "\t", f_Symbol);
FileWrite(lFile, " Period:", "\t", f_Period);
FileWrite(lFile, " Digits:", "\t", f_Digits);
FileWrite(lFile, "Time Stamp:", "\t", TimeToStr(f_TimeStamp));
FileWrite(lFile, " Sync:", "\t", f_Sync);
FileWrite(lFile, "*------------------------------------------------");
// write output headers
for(i = 0; i < NUM_FILES; i++)
{
FileWriteInteger(pFile[i], f_Version, LONG_VALUE);
FileWriteString(pFile[i], f_CopyRight, 64);
FileWriteString(pFile[i], f_Symbol, 12);
FileWriteInteger(pFile[i], pPeriod[i], LONG_VALUE);
FileWriteInteger(pFile[i], f_Digits, LONG_VALUE);
FileWriteInteger(pFile[i], TimeCurrent(), LONG_VALUE); //timesign
FileWriteInteger(pFile[i], f_Sync, LONG_VALUE); //last_sync
FileWriteArray(pFile[i], f_Unused, 0, 13);
}
// init timeframes
int iCount;
int tCount = (FileSize(iFile) - 148) / 44;
int f_Time = FileReadInteger(iFile) + TIMESHIFT*3600;
double f_Open = FileReadDouble(iFile);
double f_Low = FileReadDouble(iFile);
double f_High = FileReadDouble(iFile);
double f_Close = FileReadDouble(iFile);
double f_Volume = FileReadDouble(iFile);
iCount++;
FileWrite(lFile, "Start Time: ", TimeToStr(f_Time));
for(i = 0; i < NUM_FILES; i++)
{
pTime[i] = f_Time - f_Time % (pPeriod[i]*60);
pOpen[i] = f_Open;
pLow[i] = f_Low;
pHigh[i] = f_High;
pClose[i] = f_Close;
pVolume[i] = f_Volume;
}
// creation loop
// int testcount;
while(true)
{
bool isEndOfFile = FileTell(iFile) >= FileSize(iFile) - 1;
if(!isEndOfFile)
{
f_Time =FileReadInteger(iFile) + TIMESHIFT*3600;
f_Open =FileReadDouble(iFile);
f_Low =FileReadDouble(iFile);
f_High =FileReadDouble(iFile);
f_Close =FileReadDouble(iFile);
f_Volume =FileReadDouble(iFile);
iCount++;
if(iCount % 100000 == 0)
Print(DoubleToStr(iCount*100.0 / tCount, 0), "% processed");
}
for(i = 0; i < NUM_FILES; i++)
{
int newtime = f_Time - f_Time % (pPeriod[i]*60);
if(newtime != pTime[i] || isEndOfFile)
{
FileWriteInteger(pFile[i], pTime[i]);
FileWriteDouble(pFile[i], pOpen[i]);
FileWriteDouble(pFile[i], pLow[i]);
FileWriteDouble(pFile[i], pHigh[i]);
FileWriteDouble(pFile[i], pClose[i]);
FileWriteDouble(pFile[i], pVolume[i]);
pCount[i]++;
if(pCount[i] % 100000 == 0)
FileFlush(pFile[i]);
if(!isEndOfFile)
{
pTime[i] = newtime;
pOpen[i] = f_Open;
pLow[i] = f_Low;
pHigh[i] = f_High;
pClose[i] = f_Close;
pVolume[i] = f_Volume;
}
}
else
{
pClose[i] = f_Close;
if(pLow[i] > f_Low)
pLow[i] = f_Low;
if(pHigh[i] < f_High)
pHigh[i] = f_High;
pVolume[i] += f_Volume;
}
}
if(isEndOfFile)
break;
}
// finish up
FileWrite(lFile, " End Time: ", TimeToStr(f_Time));
FileWrite(lFile, "*------------------------------------------------");
FileWrite(lFile, "Records Processed (" + Symbol() + "1): ", iCount);
FileWrite(lFile, "Records Created:");
for(i = 0; i < NUM_FILES; i++)
FileWrite(lFile, Symbol() + pPeriod[i] + ":", pCount[i]);
FileClose(iFile);
FileClose(lFile);
for(i = 0; i < NUM_FILES; i++)
FileClose(pFile[i]);
return(0);
}
//+------------------------------------------------------------------+
Comments