251 lines
No EOL
7.2 KiB
MQL5
251 lines
No EOL
7.2 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| FolderTaskToCSV2.mq5 |
|
|
//| Copyright 2026,Niquel Mendoza. |
|
|
//| https://www.mql5.com/en/users/nique_372 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2026,Niquel Mendoza."
|
|
#property link "https://www.mql5.com/en/users/nique_372"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Include |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\\Backend\\Tester\\Saver.mqh"
|
|
#include <TSN\\MQLArticles\\Utils\\File.mqh>
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Inputs |
|
|
//+------------------------------------------------------------------+
|
|
input string InpFolder = "";
|
|
input bool InpFolderIsInCommon = true;
|
|
input string InpParamActiveGenerateName = "InpGenerateMode";
|
|
input datetime InpDataStartDate = 0;
|
|
input datetime InpDataEndDate = 0;
|
|
input string InpCsvFileNameOutput = "task.csv";
|
|
input bool InpCsvFileNameOutputIsInCommon = true;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//---
|
|
TaskTester tasks[];
|
|
int profundidad = 0;
|
|
string sym = "";
|
|
ENUM_TIMEFRAMES tf = PERIOD_CURRENT;
|
|
|
|
//---
|
|
ulong antes = GetTickCount64();
|
|
Print(ProccesFolder(InpFolder, tasks, profundidad, sym, tf));
|
|
ulong desp = GetTickCount64();
|
|
PrintFormat("res = %I64u ", (desp - antes));
|
|
|
|
//---
|
|
CTaskSaver saver;
|
|
string ms;
|
|
if(!saver.Save(InpCsvFileNameOutput, tasks, ArraySize(tasks), (InpFolderIsInCommon ? FILE_COMMON : 0), false, ms))
|
|
{
|
|
Print(ms);
|
|
}
|
|
|
|
//---
|
|
return(INIT_FAILED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//---
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//---
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool ProccesFolder(const string& main_folder, TaskTester& taskes[], int& prof, string& curr_symbol, ENUM_TIMEFRAMES& curr_tf)
|
|
{
|
|
//---
|
|
string fn = "";
|
|
const long handle = FileFindFirst(main_folder + "*", fn, (InpFolderIsInCommon ? FILE_COMMON : 0));
|
|
if(handle == INVALID_HANDLE)
|
|
{
|
|
Print("No hay archivos en: ", main_folder);
|
|
prof--;
|
|
return true;
|
|
}
|
|
|
|
//---
|
|
do
|
|
{
|
|
const string full_path = main_folder + fn;
|
|
|
|
//---
|
|
if(fn[StringLen(fn) - 1] == '\\')
|
|
{
|
|
prof++;
|
|
|
|
if(prof == 1)
|
|
{
|
|
// Carpeta simbolo
|
|
curr_symbol = fn;
|
|
StringSetLength(curr_symbol, StringLen(curr_symbol) - 1);
|
|
}
|
|
else
|
|
if(prof == 2)
|
|
{
|
|
string tf_name = fn;
|
|
StringSetLength(tf_name, StringLen(tf_name) - 1);
|
|
curr_tf = StrShortTimeframeToEnumNoRef(tf_name);
|
|
}
|
|
else
|
|
{
|
|
Print("No se procesa folder con mas de 2 de profundidad");
|
|
prof--;
|
|
continue;
|
|
}
|
|
|
|
//---
|
|
if(!ProccesFolder(full_path, taskes, prof, curr_symbol, curr_tf))
|
|
{
|
|
PrintFormat("Fallo al procesar path =%s", full_path);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//---
|
|
const int pos = ArraySize(taskes);
|
|
ArrayResize(taskes, pos + 1);
|
|
|
|
//---
|
|
taskes[pos].symbol = curr_symbol;
|
|
taskes[pos].symbol_folder = curr_symbol;
|
|
taskes[pos].timeframe = curr_tf; // TF desde carpeta, no desde setfile
|
|
|
|
//---
|
|
if(!ProccesSetFile(full_path, taskes[pos]))
|
|
{
|
|
printf("Fallo al procesar set file path = %s, se omitira para no dañar", full_path);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
while(FileFindNext(handle, fn));
|
|
|
|
//---
|
|
FileFindClose(handle);
|
|
|
|
//---
|
|
if(prof)
|
|
{
|
|
prof--;
|
|
// Reseteamos TF al salir de carpeta timeframe
|
|
if(prof == 1)
|
|
curr_tf = WRONG_VALUE; // err
|
|
else
|
|
if(prof == 0)
|
|
curr_symbol = "";
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool ProccesSetFile(const string& path, TaskTester& task)
|
|
{
|
|
//---
|
|
::ResetLastError();
|
|
int fh = FileOpen(path, FILE_READ | FILE_BIN | (InpFolderIsInCommon ? FILE_COMMON : 0));
|
|
if(fh == INVALID_HANDLE)
|
|
{
|
|
PrintFormat("Fallo al abrir el archivo =%s, ultimo error = %d", path, ::GetLastError());
|
|
return false;
|
|
}
|
|
//---
|
|
const ulong size = FileSize(fh);
|
|
string content = FileReadString(fh, int(size));
|
|
FileClose(fh);
|
|
|
|
//--- TF ya asignado desde carpeta, solo completamos el resto
|
|
task.label_id = 0;
|
|
task.label = FileRemoveExtensionNoRef(GetPureFileName(path));
|
|
task.set_file = (InpFolderIsInCommon ? (TERMINAL_MT5_COMMON_PATH + "\\Files\\") : (TERMINAL_MT5_ROOT + "Files\\")) + path;
|
|
task.start_date = InpDataStartDate;
|
|
task.end_date = InpDataEndDate;
|
|
|
|
//--- Modificamos el parametro de aidata gen
|
|
int start_t = StringFind(content, InpParamActiveGenerateName);
|
|
if(start_t == -1)
|
|
{
|
|
PrintFormat("No se encontrol el paramtro activar aidata: '%s', en setfile", InpParamActiveGenerateName);
|
|
return false;
|
|
}
|
|
int start_e = StringFind(content, "=", start_t);
|
|
if(start_e == -1)
|
|
{
|
|
Print("No se encontrol el =");
|
|
return false;
|
|
}
|
|
int end = StringFind(content, "|", start_e);
|
|
if(end == -1)
|
|
{
|
|
Print("No se encontrol el |");
|
|
return false;
|
|
}
|
|
|
|
//---
|
|
start_e++;
|
|
end--;
|
|
|
|
//---
|
|
int pos = 0;
|
|
//Inp=false|
|
|
const static ushort short_arr_true[4] = {'t', 'r', 'u', 'e'};
|
|
for(int i = start_e; i <= end; i++)
|
|
{
|
|
if(pos >= 4)
|
|
{
|
|
DeleteFromStr(content, i, end);
|
|
break;
|
|
}
|
|
content.SetChar(i, short_arr_true[pos++]);
|
|
}
|
|
|
|
//---
|
|
::ResetLastError();
|
|
fh = FileOpen(path, FILE_WRITE | FILE_TXT | (InpFolderIsInCommon ? FILE_COMMON : 0), 0);
|
|
if(fh == INVALID_HANDLE)
|
|
{
|
|
PrintFormat("Fallo al abrir el archivo =%s, ultimo error = %d", path, ::GetLastError());
|
|
return false;
|
|
}
|
|
::FileWriteString(fh, content);
|
|
FileClose(fh);
|
|
|
|
//---
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
// [a][b][c][d][e]
|
|
void DeleteFromStr(string& str, int pos_from, int pos_to)
|
|
{
|
|
const int count = (pos_to - pos_from) + 1;
|
|
const int total = StringLen(str) - count;
|
|
for(int i = pos_from; i < total; i++)
|
|
{
|
|
str.SetChar(i, str[i + count]);
|
|
}
|
|
str.Truncate(total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|