Optimal F Service
- Utilidades
- Semen Racheev
- Versión: 1.0
- Activaciones: 10
Servicio Óptimo F
- Tipo de Aplicación: Servicio
- Funciones de la Aplicación: Cálculo de la fracción óptima y el volumen de operación para lograr el máximo crecimiento de la curva de capital, basado en los resultados de operaciones previas.
Acerca de esta aplicación
La gestión del capital es el componente más crucial y, a menudo, subestimado de cualquier sistema de trading. Una gestión adecuada puede mejorar—y en algunos casos significativamente—el rendimiento de tu algoritmo de trading.
Esta aplicación calcula automáticamente la fracción óptima y el volumen de operación utilizando el algoritmo propuesto por Ralph Vince en su libro "The Mathematics of Money Management", para lograr el máximo crecimiento geométrico del saldo de la cuenta. Este punto es único para cualquier sistema de trading y es esencial conocerlo. ¡En tus sistemas de trading, nunca debes usar un tamaño de operación que exceda el valor óptimo!
Los algoritmos de gestión de capital NO están diseñados para sistemas matemáticamente perdedores basados en promedios, martingala o estrategias similares. Estos sistemas serán filtrados por la aplicación antes de realizar cálculos, ya que la fracción óptima y el volumen de operación para estos sistemas siempre es igual a cero. Los algoritmos de gestión de capital pueden mejorar los resultados ÚNICAMENTE para sistemas de trading matemáticamente rentables (aquellos con una expectativa matemática positiva). Por lo tanto, este servicio se recomienda SOLO para profesionales que entienden lo que están haciendo.
Además, el algoritmo no considera correlaciones (dependencias) entre sistemas que operan simultáneamente. Para que el algoritmo funcione de manera efectiva, es necesario un conjunto bien diversificado de sistemas de trading.
Cómo usar
Parámetros:
- LOG_LEVEL - Nivel de registro para la sección de Expertos del terminal. DEBUG proporciona la información más detallada, mientras que ERROR registra el mínimo.
- MAGIC_LIST - Lista separada por comas de identificadores de sistemas (Magic Numbers) que operan simultáneamente y requieren cálculos.
- TRADE_FILES_PATH - Ruta al directorio que contiene los archivos con los resultados de operaciones previas (relativa a <Carpeta de Datos>/MQL5/Files/).
- OUTPUT_FILE_PATH - Ruta al archivo donde se guardarán los resultados de los cálculos (relativa a <Carpeta de Datos>/MQL5/Files/).
- WORK_PERIOD - Frecuencia de los recálculos en segundos.
- BALANCE_MATRIX_PERIOD - Periodo sobre el cual se agregan los resultados, con cálculos basados en este periodo agregado en lugar de cada operación individual.
Antes del primer lanzamiento cada sistema de trading debe probarse en el probador de estrategias hasta el momento presente. Se recomienda seleccionar un marco temporal que incluya al menos 100 operaciones. Utiliza el Test Trade Saver Script y sigue las instrucciones para extraer los archivos de resultados de las pruebas (*.tst) en el formato requerido.
Si el sistema de trading ya se ha utilizado en el terminal y hay posiciones en el historial con el MAGIC especificado, ¡debes configurar un parámetro CUSTOM_MAGIC_NUMBER diferente en el script!
Luego para garantizar que los archivos de datos se actualicen regularmente, ejecuta el Trade Saver Service siguiendo las instrucciones.
Después de la exportación inicial de datos desde las pruebas con el Trade Saver Script, el Trade Saver Service actualizará continuamente los archivos con nuevos datos a medida que estén disponibles, mientras que el Optimal F Service calculará y escribirá regularmente nuevos valores en el archivo de resultados.
Algoritmo
- Extrae la lista de sistemas que requieren cálculos del parámetro MAGIC_LIST.
- Utiliza archivos de texto llamados <MAGIC>.csv en el formato <MAGIC>,<POSITION_CLOSE_TIME>,<LOTS>,< RESULT_$> que contengan los resultados de operaciones previas desde el directorio especificado por TRADE_FILES_PATH. Construye una matriz para la función de la curva de balance, donde cada valor a[i][j] representa el resultado del sistema de trading i para el periodo j.
- Verifica cada sistema para al menos un periodo negativo en sus resultados. Si un sistema no tiene periodos negativos, exclúyelo de cálculos posteriores (estos sistemas deben eliminarse).
- Evalúa la expectativa matemática de cada sistema. Si un sistema no tiene un valor esperado positivo, exclúyelo de cálculos posteriores (estos sistemas deben eliminarse).
- Determina el margen de error necesario para calcular el volumen de operación con una precisión de 0.01.
- Para cada sistema restante, calcula su fracción óptima.
- Divide el saldo actual en partes iguales para los sistemas restantes. Para cada sistema y su saldo asignado, calcula el volumen de operación en lotes correspondiente a la fracción óptima.
- Escribe los resultados en el archivo de texto especificado por OUTPUT_FILE_PATH en el formato <MAGIC>,<BIGGEST_LOSS>,<OPTIMAL_F>,<OPTIMAL_LOTS>.
Enlaces y referencias
- Ralph Vince - The Mathematics of Money Management: Risk Analysis Techniques for Traders (ISBN-13: 978-0471547389)
Para desarrolladores
Puedes usar la siguiente clase para integrar los resultados en tus sistemas de trading:
#include "OptimalFResultsLoader.mqh" // create loader COptimalFResultsLoader* optimalFResultsLoader = new COptimalFResultsLoader("/SRProject/results.csv"); // print all fields for magic = '1111' Print(optimalFResultsLoader.getOptimalFFor(1111), " ", optimalFResultsLoader.getBiggestLossFor(1111), " ", optimalFResultsLoader.getOptimalLotsFor(1111)); // delete loader from memory 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)); } //+------------------------------------------------------------------+
