MetaTrader5
Tick-Datenhistorie für MetaTrader 5 herunterladen – So funktioniert's
In diesem Artikel zeige ich dir, wie du mit einem Expert Advisor (EA) alle verfügbaren Tick-Daten eines Symbols in MetaTrader 5 herunterladen kannst. Dieser Code durchsucht die Marktplattform deines Brokers und extrahiert die Symbole, für die er alle verfügbaren Ticks oder Ticks bis zu einem bestimmten Datum herunterlädt.
Dies kann dir helfen, die gesamte Symbolhistorie für Backtests herunterzuladen oder benutzerdefinierte Charts aus diesen Ticks zu erstellen. Achte darauf, dass genug Speicherplatz auf deiner Festplatte vorhanden ist, da die Ticks im Datenordner zwischengespeichert werden.
Um den Download der Symbole zu erleichtern, benötigen wir zuerst einen Download-Manager. Die Struktur CDownloadManager enthält alle Informationen, die wir benötigen.
struct CDownloadManager
{
bool m_started,m_finished;
string m_symbols[],m_current;
int m_index;
}
Der Status des Downloads (gestart/abgeschlossen)
Die Liste der zu scannenden Symbole
Das aktuelle Symbol
Der Index des gerade gescannten Symbols
Wir müssen auch mit der Festplatte lesen und schreiben, und da wir mit Symbolen arbeiten, erstellen wir zwei Funktionen, um Strings aus Binärdateien zu lesen und zu schreiben.
Die Funktion zum Speichern eines Strings in eine Datei:
void writeStringToFile(int f,string thestring)
{
// Speichere das Symbol-String
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);
}
}
Die Funktion erhält:
Die Datei-ID f, einer zum Schreiben geöffneten Datei mit binären Flags FILE_WRITE|FILE_BIN
Den zu speichernden String
Sie schreibt die Länge der Zeichen in die Datei und speichert dann jedes Zeichen im String.
Die Funktion zum Laden eines Strings aus einer Datei:
string readStringFromFile(int f)
{
string result="";
// Lade das Symbol-String
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);
}
Diese Funktion erhält:
Die Datei-ID f, einer zum Lesen geöffneten Datei mit binären Flags FILE_READ|FILE_BIN
Sie liest die Länge der Zeichen und lädt die Zeichen in ein Char-Array, das dann in einen String umgewandelt und zurückgegeben wird.
Zurück zur Struktur CDownloadManager. Wir benötigen eine Möglichkeit, den Manager zu initialisieren und mit den Daten aus der Marktbeobachtung zu füllen:
//+------------------------------------------------------------------+
//| Symbole von der Marktbeobachtung abrufen |
//+------------------------------------------------------------------+
void grab_symbols()
{
//! nur von der MW!
int s=SymbolsTotal(true);
ArrayResize(m_symbols,s,0);
for(int i=0;i<ArraySize(m_symbols);i++)
{
m_symbols[i]=SymbolName(i,true);
}
}
Das ist ziemlich einfach:
Wir fragen, wie viele Symbole in der Marktbeobachtung aktiv sind
Wir passen unser m_symbols-Array an, um diese aufzunehmen
Wir durchlaufen die Symbole und fordern die Namen der Symbole an
Wir sind auch verantwortlich für das Management des Downloads der Symbol-Daten, daher benötigen wir eine Funktion, die im Wesentlichen den Prozess verwaltet:
//+------------------------------------------------------------------+
//| Verwaltung des Downloadprozesses |
//+------------------------------------------------------------------+
void manage(string folder,string filename)
{
// Diese Funktion startet oder wechselt zum nächsten Symbol
// falls gesetzt
if(ArraySize(m_symbols)>0)
{
// wenn nicht gestartet
if(!m_started)
{
m_started=true;
// gehe zum ersten Symbol
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;
}
// Wenn gestartet
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("Fertig");
ExpertRemove();
return;
}
}
}
else
{
Print("Bitte zuerst Symbole abrufen");
}
}
So funktioniert das System:
Das Chart öffnet sich, dafür benötigen wir 1 Chart, und ein Timer wird gesetzt.
Dieser Timer wird ausgeführt, wir stoppen den Timer
Wir prüfen, ob dies ein neuer Download oder ein fortlaufender Download ist
Wenn es ein neuer Download ist, richten wir ihn ein, indem wir alle Symbole abrufen
Wenn es ein fortlaufender Download ist, laden wir die Daten für das aktuelle Symbol herunter
Hier ist der Teil des Codes, der den Download im Timer durchführt:
//+------------------------------------------------------------------+
//| Timer |
//+------------------------------------------------------------------+
void OnTimer()
{
//--- wenn synchronisiert
if(SymbolIsSynchronized(_Symbol)&&TerminalInfoInteger(TERMINAL_CONNECTED)==1)
{
EventKillTimer();
//--- lade das System hier
if(MANAGER.load(MANAGER_FOLDER,MANAGER_STATUS_FILE))
{
//--- System geladen, wir scannen hier ein Symbol
Comment("System geladen und wir verarbeiten "+MANAGER.m_current);
//--- Tick laden
//--- finde den ältesten Tick, der beim Broker verfügbar ist
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("Bitte warten");
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("Ältester Tick : "+TimeToString((datetime)(oldest/1000),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"
Cursor("+TimeToString((datetime)(cursorMSC/1000),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+")
Versuche("+IntegerToString(attempts)+")
Bitte warten auf Antwort...");
}
//--- an diesem Punkt haben wir den ältesten Tick
//--- beginne Ticks vom ältesten zum neuesten anzufordern
if(oldest!=LONG_MAX)
{
ArrayFree(receiver);
datetime newest_tick=0;
//--- erhalte die Zeit des letzten Ticks für dieses Symbol, gespeichert in symbol_time
datetime most_recent_candle=(datetime)SymbolInfoInteger(_Symbol,SYMBOL_TIME);
while(newest_tick<most_recent_candle)
{
//--- fordere ein neues Batch an, beginnend mit der ältesten Zeit und dem angegebenen Tick-Limit
int pulled=CopyTicks(_Symbol,receiver,COPY_TICKS_ALL,oldest,tick_packets);
if(pulled>0)
{
//--- wenn wir ein neues Batch abrufen, aktualisieren wir unsere heruntergeladenen Zeiten
newest_tick=receiver[pulled-1].time;
oldest=receiver[pulled-1].time_msc;
ArrayFree(receiver);
}
//--- Wartezeit für Serveranfragen, ändere sie, wenn du möchtest
Sleep(44);
Comment("Bis jetzt bis "+TimeToString(newest_tick,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+" gezogen");
}
}
else
{
Alert("Bitte schließe das Terminal \n gehe zum Ticks-Ordner \n und lösche die leeren Ordner");
ExpertRemove();
}
//--- aktualisiere den Manager und fahre fort
MANAGER.manage(MANAGER_FOLDER,MANAGER_STATUS_FILE);
}
else
{
//--- hole die Symbole der Marktbeobachtung, um den Download zu starten
Comment("MW abrufen und starten");
MANAGER.grab_symbols();
MANAGER.manage(MANAGER_FOLDER,MANAGER_STATUS_FILE);
}
}
Mit dieser Anleitung bist du nun bestens gerüstet, um die Tick-Datenhistorie für deine Backtests herunterzuladen. Viel Erfolg beim Traden!
2025.02.22