Optimal F Service
- Utilitys
- Semen Racheev
- Version: 1.0
- Aktivierungen: 10
Optimaler F-Service
- Anwendungstyp: Dienst
- Funktionen der Anwendung: Berechnung des optimalen Anteils und Handelsvolumens, um ein maximales Wachstum der Aktienkurve zu erreichen, basierend auf den Ergebnissen früherer Geschäfte.
Über diese Anwendung
Das Kapitalmanagement ist die wichtigste und oft unterschätzte Komponente eines jeden Handelssystems. Richtiges Kapitalmanagement kann die Leistung Ihres Handelsalgorithmus verbessern - und manchmal sogar erheblich steigern.
Diese Anwendung berechnet automatisch den optimalen Anteil und das optimale Handelsvolumen unter Verwendung des von Ralph Vince in seinem Buch "The Mathematics of Money Management" vorgeschlagenen Algorithmus, um ein maximales geometrisches Wachstum des Kontosaldos zu erreichen. Dieser Punkt existiert und ist für jedes Handelssystem einzigartig, deshalb ist es wichtig, ihn zu kennen. In Ihren Handelssystemen dürfen Sie niemals eine Handelsgröße verwenden, die den optimalen Wert überschreitet!
Kapitalverwaltungsalgorithmen sind NICHT für mathematisch verlierende Systeme konzipiert, die auf Durchschnittsbildung, Martingale oder ähnlichen Strategien basieren. Solche Systeme werden von der Anwendung vor allen Berechnungen herausgefiltert, da der optimale Anteil und das Handelsvolumen für diese Systeme immer gleich Null sind. Kapitalmanagement-Algorithmen können die Ergebnisse NUR bei mathematisch profitablen Handelssystemen verbessern (solche mit einer positiven mathematischen Erwartung). Daher wird dieser Service NUR für Profis empfohlen, die wissen, was sie tun.
Außerdem berücksichtigt der Algorithmus keine Korrelationen (Abhängigkeiten) zwischen gleichzeitig arbeitenden Systemen. Damit der Algorithmus effektiv arbeiten kann, ist ein gut diversifizierter Satz von Handelssystemen erforderlich.
Wie man ihn benutzt
- LOG_LEVEL - Die Protokollierungsstufe für den Expertenbereich des Terminals. DEBUG liefert die detailliertesten Informationen, während ERROR die wenigsten protokolliert.
- MAGIC_LIST - Eine durch Kommata getrennte Liste von Systembezeichnern (Magic Numbers), die gleichzeitig arbeiten und eine Berechnung erfordern.
- TRADE_FILES_PATH - Der Pfad zu dem Verzeichnis, das Dateien mit den Ergebnissen früherer Trades enthält (relativ zu <Datenordner>/MQL5/Files/ ).
- OUTPUT_FILE_PATH - Der Pfad zu der Datei, in der die Berechnungsergebnisse gespeichert werden (relativ zu <Datenordner>/MQL5/Files/ ).
- WORK_PERIOD - Die Häufigkeit der Neuberechnungen in Sekunden.
- BALANCE_MATRIX_PERIOD - Der Zeitraum, über den die Ergebnisse aggregiert werden, wobei die Berechnungen auf diesem aggregierten Zeitraum und nicht auf jedem einzelnen Handel basieren.
Vor dem ersten Start muss jedes Handelssystem im Strategietester für den Zeitraum bis zum jetzigen Zeitpunkt getestet werden. Es wird empfohlen, einen Zeitrahmen zu wählen, der mindestens 100 Trades umfasst. Extrahieren Sie dann mit Hilfe des Test Trade Saver Scripts und unter Beachtung der Anweisungen die Ergebnisdateien aus den Testdateien (*.tst) im gewünschten Format.
Wenn das Handelssystem bereits im Terminal verwendet wurde und in der Historie Positionen mit dem angegebenen MAGIC vorhanden sind, müssen Sie im Skript einen anderen Parameter CUSTOM_MAGIC_NUMBER einstellen!
Um sicherzustellen, dass die Datendateien regelmäßig aktualisiert werden und aktuell bleiben, müssen Sie als nächstes den Trade Saver Service gemäß den mitgelieferten Anweisungen ausführen.
Nach dem anfänglichen Datenexport aus den Tests mit dem Trade Saver Script aktualisiert der Trade Saver Service die Dateien also kontinuierlich mit neuen Daten, sobald diese verfügbar sind, während der Optimal F Service regelmäßig neue Werte berechnet und in die Ergebnisdatei schreibt
Algorithmus
- Extrahieren Sie die Liste der zu berechnenden Systeme aus dem Parameter MAGIC_LIST.
- Verwenden Sie Textdateien mit dem Namen <MAGIC>.csv im Format <MAGIC>,<POSITION_CLOSE_TIME>,<LOTS>,<RESULT_$>, die die Ergebnisse früherer Trades enthalten, aus dem durch TRADE_FILES_PATH angegebenen Verzeichnis. Konstruieren Sie eine Matrix für die Bilanzkurvenfunktion, wobei jeder Wert a[i][j] das Ergebnis des Handelssystems i für den Zeitraum j darstellt.
- Überprüfen Sie jedes System auf mindestens eine negative Periode in seinen Ergebnissen. Wenn ein System keine negativen Perioden aufweist, schließen Sie es von den weiteren Berechnungen aus (solche Systeme müssen entfernt werden).
- Bewerten Sie den mathematischen Erwartungswert eines jeden Systems. Wenn ein System keinen positiven Erwartungswert hat, schließen Sie es von den weiteren Berechnungen aus (solche Systeme müssen entfernt werden).
- Bestimmen Sie die Fehlermarge, die erforderlich ist, um das Handelsvolumen mit einer Genauigkeit von 0,01 zu berechnen.
- Berechnen Sie für jedes verbleibende System seinen optimalen Anteil.
- Teilen Sie den aktuellen Saldo in gleiche Teile für die verbleibenden Systeme auf. Berechnen Sie für jedes System und seinen zugewiesenen Saldo das Handelsvolumen in Losen, das dem optimalen Anteil entspricht.
- Schreiben Sie die Ergebnisse in die durch OUTPUT_FILE_PATH angegebene Textdatei in dem Format <MAGIC>,<BIGGEST_LOSS>,<OPTIMAL_F>,<OPTIMAL_LOTS>.
Links und Verweise
- Ralph Vince - Die Mathematik des Geldmanagements: Risikoanalyse-Techniken für Händler (ISBN-13978-0471547389)
Für Entwickler
Sie können die folgende Klasse verwenden, um die Ergebnisse in Ihre Handelssysteme zu integrieren:#include "OptimalFResultsLoader.mqh" // Lader erstellen COptimalFResultsLoader* optimalFResultsLoader = new COptimalFResultsLoader("/SRProject/results.csv"); // alle Felder drucken für magic = '1111' Print(optimalFResultsLoader.getOptimalFFor(1111), " ", optimalFResultsLoader.getBiggestLossFor(1111), " ", optimalFResultsLoader.getOptimalLotsFor(1111)); // Lader aus dem Speicher löschen delete(optimalFResultsLoader);
//+------------------------------------------------------------------+ //|OptimalFResultsLoader.mqh | //|Semyon Racheev | //|| //+------------------------------------------------------------------+ #property copyright "Semyon Racheev" #property link "" #property version "1.00" #include <Files\FileTxt.mqh> class COptimalFResultsLoader { private: const string name_; const uchar delimiter_; const ushort separator_; const string srcFilePath_; bool checkStringForOptimalFResultsDeserializing(string &inputStr[]) const; ushort calculateCharCode(const uchar separator) const; public: COptimalFResultsLoader(const string srcFilePath, uchar separator); ~COptimalFResultsLoader(); double getOptimalLotsFor(const ulong magicNumber) const; double getOptimalFFor(const ulong magicNumber) const; double getBiggestLossFor(const ulong magicNumber) const; }; //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ COptimalFResultsLoader::COptimalFResultsLoader(const string srcFilePath = "/SRProject/results.csv", uchar separator = ','):name_("OptimalFResultsLoader"), srcFilePath_(srcFilePath), delimiter_(separator), separator_(calculateCharCode(separator)) { } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ COptimalFResultsLoader::~COptimalFResultsLoader() { } //+------------------public------------------------------------------+ //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ double COptimalFResultsLoader::getOptimalLotsFor(const ulong inputMagicNumber) const { double rsl = 0.0; CFileTxt* file = new CFileTxt(); int fileHandle = file.Open(srcFilePath_,FILE_READ|FILE_UNICODE|FILE_CSV); while (!FileIsEnding(fileHandle)) { string readString = file.ReadString(); string str[]; StringSplit(readString, separator_, str); if (checkStringForOptimalFResultsDeserializing(str)) { if (inputMagicNumber == (ulong)StringToInteger(str[0])) { rsl = StringToDouble(str[3]); } } } file.Close(); delete(file); return(rsl); } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ double COptimalFResultsLoader::getOptimalFFor(const ulong inputMagicNumber) const { double rsl = 0.0; CFileTxt* file = new CFileTxt(); int fileHandle = file.Open(srcFilePath_,FILE_READ|FILE_UNICODE|FILE_CSV); while (!FileIsEnding(fileHandle)) { string readString = file.ReadString(); string str[]; StringSplit(readString, separator_, str); if (checkStringForOptimalFResultsDeserializing(str)) { if (inputMagicNumber == (ulong)StringToInteger(str[0])) { rsl = StringToDouble(str[2]); } } } file.Close(); delete(file); return(rsl); } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ double COptimalFResultsLoader::getBiggestLossFor(const ulong inputMagicNumber) const { double rsl = 0.0; CFileTxt* file = new CFileTxt(); int fileHandle = file.Open(srcFilePath_,FILE_READ|FILE_UNICODE|FILE_CSV); while (!FileIsEnding(fileHandle)) { string readString = file.ReadString(); string str[]; StringSplit(readString, separator_, str); if (checkStringForOptimalFResultsDeserializing(str)) { if (inputMagicNumber == (ulong)StringToInteger(str[0])) { rsl = StringToDouble(str[1]); } } } file.Close(); delete(file); return(rsl); } //+---------------------private--------------------------------------+ //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ bool COptimalFResultsLoader::checkStringForOptimalFResultsDeserializing(string &inputStr[]) const { if (ArraySize(inputStr) < 4) { return(false); } return(true); } //+------------------------------------------------------------------+ //|| //+------------------------------------------------------------------+ ushort COptimalFResultsLoader::calculateCharCode(const uchar separator) const { string str = CharToString(separator); return(StringGetCharacter(str,0)); } //+------------------------------------------------------------------+
