MetaTrader5
Descarga Historial Completo de Ticks de Símbolos en MetaTrader 5
Si eres trader, seguro que sabes lo importante que es tener acceso a datos históricos completos para tus análisis y pruebas. En este artículo, te mostraré cómo utilizar este código para descargar todos los ticks disponibles de un símbolo en MetaTrader 5. ¿Listo para mejorar tus backtests? Este sistema de trading escaneará el mercado de tu bróker y recopilará los símbolos de los cuales descargará todos los ticks, o hasta una fecha específica que tú decidas. Es ideal para crear gráficos personalizados a partir de esos ticks y realizar análisis más profundos. Recuerda que los ticks se almacenan en la carpeta de datos, así que asegúrate de tener suficiente espacio en tu disco duro. Además, para facilitar la descarga de los símbolos, necesitarás un gestor de descargas primero. Estructura CDownloadManager La estructura CDownloadManager contiene toda la información que necesitamos: struct CDownloadManager
{
bool m_started,m_finished;
string m_symbols[],m_current;
int m_index;
} Estado de la descarga (iniciada/terminada) Lista de símbolos a escanear Símbolo actual Índice del símbolo que se está escaneando También necesitaremos leer y escribir en el disco duro, así que creamos dos funciones rápidas para manejar cadenas de texto en archivos binarios. Función para guardar cadenas en un archivo: void writeStringToFile(int f,string thestring)
{
// Guardar cadena de símbolo
char sysave[];
int charstotal=StringToCharArray(thestring,sysave,0,StringLen(thestring),CP_ACP);
FileWriteInteger(f,charstotal,INT_VALUE);
for(int i=0;i<charstotal;i++)
{
FileWriteInteger(f,sysave[i],CHAR_VALUE);
}
} Esta función recibe: El identificador del archivo f, que debe abrirse con los flags FILE_WRITE|FILE_BIN La cadena que se va a escribir en el archivo La función escribe primero un entero que indica cuántos caracteres hay en la cadena y luego almacena cada carácter. Función para cargar cadenas desde un archivo: string readStringFromFile(int f)
{
string result="";
// Cargar cadena de símbolo
char syload[];
int charstotal=(int)FileReadInteger(f,INT_VALUE);
if(charstotal>0)
{
ArrayResize(syload,charstotal,0);
for(int i=0;i<charstotal;i++)
{
syload[i]=(char)FileReadInteger(f,CHAR_VALUE);
}
result=CharArrayToString(syload,0,charstotal,CP_ACP);
}
return(result);
} Esta función recibe: El identificador del archivo f, que debe abrirse con los flags FILE_READ|FILE_BIN Lee primero un entero que indica cuántos caracteres se esperan en ese punto del archivo, luego lee cada carácter en un arreglo y finalmente genera una cadena a partir de ese arreglo que se devuelve como resultado. Inicializando el Gestor de Descargas Ahora, necesitamos una forma de inicializar el gestor y llenarlo a partir del mercado: //+------------------------------------------------------------------+
//| Obtener símbolos del mercado |
//+------------------------------------------------------------------+
void grab_symbols()
{
//! Solo desde el mercado!
int s=SymbolsTotal(true);
ArrayResize(m_symbols,s,0);
for(int i=0;i<ArraySize(m_symbols);i++)
{
m_symbols[i]=SymbolName(i,true);
}
} Es muy sencillo: Solicitamos cuántos símbolos hay en el mercado (activos) Redimensionamos nuestro arreglo m_symbols para recibirlos Recorremos los símbolos y solicitamos el nombre de cada símbolo El siguiente paso es manejar el proceso de descarga de los datos del símbolo, así que necesitaremos una función que actúe como gestor: //+------------------------------------------------------------------+
//| Gestionar el proceso de descarga de símbolos |
//+------------------------------------------------------------------+
void manage(string folder,string filename)
{
// Esencialmente, esto inicia o navega al siguiente símbolo
// si está configurado
if(ArraySize(m_symbols)>0)
{
// Si no ha comenzado
if(!m_started)
{
m_started=true;
// Ir al primer símbolo
m_current=m_symbols[0];
m_index=1;
save(folder,filename);
if(_Symbol!=m_current)
{
ChartSetSymbolPeriod(ChartID(),m_current,_Period);
}
else
{
ENUM_TIMEFRAMES new_period=PERIOD_M1;
for(int p=0;p<ArraySize(TFS);p++)
{
if(_Period!=TFS[p])
{
new_period=TFS[p];
break;
}
}
ChartSetSymbolPeriod(ChartID(),m_current,new_period);
}
return;
}
// Si comenzó
else
{
m_index++;
if(m_index<=ArraySize(m_symbols))
{
m_current=m_symbols[m_index-1];
save(folder,filename);
if(_Symbol!=m_current)
{
ChartSetSymbolPeriod(ChartID(),m_current,_Period);
}
return;
}
else
{
m_finished=true;
FileDelete(folder+"\"+filename);
Print("Finalizado");
ExpertRemove();
return;
}
}
}
else
{
Print("Por favor, obtén los símbolos primero");
}
} ¿Cómo funciona el sistema? Se abre el gráfico, necesitas al menos un gráfico y se establece un temporizador. Ese temporizador se ejecuta y cancelamos el temporizador. Verificamos si se trata de una nueva descarga o una descarga continuada. Si es una nueva descarga, configuramos el gestor obteniendo todos los símbolos. Si es una descarga continuada, descargamos datos del símbolo actual. Esta es la parte del código que lleva a cabo la descarga en el temporizador: //+------------------------------------------------------------------+
//| Temporizador |
//+------------------------------------------------------------------+
void OnTimer()
{
//--- si está sincronizado
if(SymbolIsSynchronized(_Symbol)&&TerminalInfoInteger(TERMINAL_CONNECTED)==1)
{
EventKillTimer();
//--- cargar el sistema aquí
if(MANAGER.load(MANAGER_FOLDER,MANAGER_STATUS_FILE))
{
//--- sistema cargado, estamos procesando un símbolo
Comment("Sistema cargado y estamos procesando "+MANAGER.m_current);
//--- carga de ticks
//--- encontrar el tick más antiguo disponible en el bróker
int attempts=0;
int ping=-1;
datetime cursor=flatten(TimeTradeServer());
long cursorMSC=((long)cursor)*1000;
long jump=2592000000;//60*60*24*30*1000;
MqlTick receiver[];
long oldest=LONG_MAX;
Comment("Por favor, espera");
while(attempts<5)
{
ping=CopyTicks(_Symbol,receiver,COPY_TICKS_ALL,cursorMSC,1);
if(ping==1)
{
if(receiver[0].time_msc==oldest)
{
attempts++;
}
else
{
attempts=0;
}
if(receiver[0].time_msc<oldest)
{
oldest=receiver[0].time_msc;
}
cursorMSC-=jump;
if(limitDate&&receiver[0].time<=oldestLimit)
{
break;
}
}
else
{
attempts++;
}
Sleep(44);
Comment("Tick más antiguo : "+TimeToString((datetime)(oldest/1000),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"\nCursor("+TimeToString((datetime)(cursorMSC/1000),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+")\nIntentos("+IntegerToString(attempts)+")\nPor favor, espera la respuesta...");
}
//--- en este punto tenemos el tick más antiguo
//--- comenzamos a solicitar ticks desde el más antiguo al más nuevo
if(oldest!=LONG_MAX)
{
ArrayFree(receiver);
datetime newest_tick=0;
//--- recibir la hora del último tick para este símbolo almacenado en symbol_time
datetime most_recent_candle=(datetime)SymbolInfoInteger(_Symbol,SYMBOL_TIME);
while(newest_tick<most_recent_candle)
{
//--- solicitar un nuevo lote comenzando desde el tick más antiguo con el límite de ticks especificado
int pulled=CopyTicks(_Symbol,receiver,COPY_TICKS_ALL,oldest,tick_packets);
if(pulled>0)
{
//--- si extraemos un nuevo lote, actualizamos nuestros tiempos descargados
newest_tick=receiver[pulled-1].time;
oldest=receiver[pulled-1].time_msc;
ArrayFree(receiver);
}
//--- tiempo de espera para las solicitudes del servidor, puedes alterarlo si lo deseas
Sleep(44);
Comment("Se extrajo hasta "+TimeToString(newest_tick,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" hasta ahora");
}
}
else
{
Alert("Por favor, cierra el terminal \n ve a la carpeta de ticks \n y elimina las carpetas vacías");
ExpertRemove();
}
//--- actualiza el gestor y sigue adelante
MANAGER.manage(MANAGER_FOLDER,MANAGER_STATUS_FILE);
}
else
{
//--- obtener los símbolos del mercado para empezar la descarga
Comment("Obteniendo MW y comenzando");
MANAGER.grab_symbols();
MANAGER.manage(MANAGER_FOLDER,MANAGER_STATUS_FILE);
}
}
}
2025.02.22