English Русский 中文 Deutsch 日本語 Português
preview
Modelo de riesgo de cartera utilizando el criterio de Kelly y la simulación de Monte Carlo

Modelo de riesgo de cartera utilizando el criterio de Kelly y la simulación de Monte Carlo

MetaTrader 5Trading |
234 9
Zhuo Kai Chen
Zhuo Kai Chen

Introducción

Durante décadas, los operadores han utilizado la fórmula del criterio de Kelly para determinar la proporción óptima de capital que se debe asignar a una inversión o apuesta con el fin de maximizar el crecimiento a largo plazo y minimizar el riesgo de ruina. Sin embargo, seguir ciegamente el criterio de Kelly utilizando el resultado de una sola prueba retrospectiva suele ser peligroso para los operadores individuales, ya que en el trading en vivo, la ventaja comercial disminuye con el tiempo y el rendimiento pasado no es un indicador de resultados futuros. En este artículo, presentaré un enfoque realista para aplicar el criterio de Kelly a la asignación de riesgos de uno o más EA en MetaTrader 5, incorporando los resultados de la simulación de Monte Carlo de Python.


La teoría del modelo de trading en el espacio de apalancamiento

El modelo de negociación espacial de apalancamiento (Leverage Space Trading Model, LSTM) es un marco teórico utilizado principalmente en el contexto de los mercados financieros y la gestión de activos. Integra el concepto de apalancamiento, que se refiere al uso de fondos prestados para amplificar los retornos potenciales, con un enfoque más dinámico y orientado al espacio para modelar el comportamiento del mercado. 

LSTM utiliza el criterio de Kelly para calcular el porcentaje de la cartera que se arriesga por operación para una estrategia única.

Fracción de Kelly

  • L: Factor de apalancamiento.
  • p: Probabilidad de éxito.
  • u: Ratio de ganancia apalancada.
  • l: Índice de pérdida apalancado

Dado un resultado de backtest, podemos obtener el valor de la variable mediante las siguientes fórmulas.

Variables de Kelly

Supongamos que estás operando con un apalancamiento de 2:1. Supongamos lo siguiente:

  • La probabilidad de una operación exitosa (p) = 0,6 (60 % de posibilidades de ganar).
  • El rendimiento esperado (u) = 0,1 (ganancia del 10 % sin apalancamiento, por lo que con un apalancamiento de 2:1 = ganancia del 20 %).
  • La pérdida esperada (l) = 0,05 (5 % de pérdida sin apalancamiento, por lo que con un apalancamiento de 2:1 = 10 % de pérdida).

Sustituye en la fórmula de Kelly:

Ejemplo de Kelly

Por lo tanto, la fracción óptima de su capital que debe arriesgar en esta operación sería el 8 % de su capital total.

Después de aplicar esta fórmula a uno de tus propios Asesores Expertos, creo que inevitablemente sentirás una sensación de incomodidad al ver cuánto riesgo deberías haber asumido por operación. De hecho, esta fórmula supone que sus resultados futuros serán tan buenos como su prueba retrospectiva, lo cual no es realista. Es por eso que, en la industria, la gente normalmente aplica una fracción de Kelly a su riesgo, lo que significa que dividen el valor por algún número entero para disminuir su riesgo y dejar espacio para futuras adversidades.

Ahora tenemos que responder: ¿qué fracción se debe elegir para que los traders se sientan cómodos al arriesgar, y al mismo tiempo maximicen su retorno esperado por operación?

En el libro The Leverage Space Trading Model, de Ralph Vince, se concluyó, mediante un proceso de optimización estocástica, que la función de expectativa de rendimiento es convexa, independientemente de la dimensión. Esto significa que el rendimiento esperado óptimo tiene una única solución, y la expectativa disminuye continuamente a medida que el valor f* se aleja de la solución óptima.

Esto implica que, dado que el trading en vivo no es tan ideal como el backtesting, esperamos que el f* real que maximizará nuestro rendimiento sea menor que el f* calculado a partir de la fórmula de Kelly. Por lo tanto, todo lo que tenemos que hacer es aumentar nuestro riesgo asignado al nivel más alto que podamos tolerar, asegurándonos de que siga siendo inferior al riesgo de Kelly.

Por lo general, el nivel de tolerancia de un operador se mide por la caída máxima que puede soportar. Para el resto del artículo, voy a suponer que un nivel de tolerancia razonable es una caída máxima del 30 %.


Aplicación del riesgo apalancado en MQL5

Para aplicar el riesgo apalancado en MQL5, primero declaramos el porcentaje de riesgo como una variable global. En este caso, arriesgamos un 2 % por operación.

input double risk = 2.0;

A continuación, escribiremos una función para calcular el volumen del lote basándonos en el stop loss en la unidad de precio actual. Por ejemplo, si el stop loss se establece a un precio de 0, los puntos de stop loss se corresponderán directamente con el precio actual, y el resultado de la operación reflejará el movimiento exacto del activo subyacente.

//+------------------------------------------------------------------+
//| Calculate the corresponding lot size given the risk              |
//+------------------------------------------------------------------+
double calclots(double slpoints)
{
   double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * risk / 100;

   double ticksize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickvalue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double lotstep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   double moneyperlotstep = slpoints / ticksize * tickvalue * lotstep;
   double lots = MathFloor(riskAmount / moneyperlotstep) * lotstep;
   lots = MathMin(lots, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX));
   lots = MathMax(lots, SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN));
   return lots;
}

El código anterior determina primero el importe del riesgo multiplicando el saldo de la cuenta por el porcentaje de riesgo.

Luego recupera el tamaño del tick del símbolo, el valor del tick y el paso del lote, y calcula el valor monetario de cada paso del lote en función de la distancia del stop loss.

El tamaño del lote se determina dividiendo el monto de riesgo por el dinero por paso de lote y redondeándolo al paso de lote más cercano.

Por último, garantiza que el tamaño del lote calculado esté dentro de los límites de volumen mínimo y máximo permitidos para el símbolo antes de devolver el resultado.

Tenga en cuenta que no todas las estrategias comerciales implican un stop loss fijo y un take profit. Pero en el espacio de trading con apalancamiento, asumimos que estamos usando un punto de stop loss fijo porque en el Criterio de Kelly tenemos que saber cuánto queremos arriesgar antes de colocar una operación.

Llamamos a esta función justo antes de realizar cualquier ejecución. Un ejemplo sería el siguiente.

//+------------------------------------------------------------------+
//| Execute buy trade function                                       |
//+------------------------------------------------------------------+
void executeBuy(double price) {
       double sl = price- slp*_Point;
       sl = NormalizeDouble(sl, _Digits);
       double lots = lotpoint;
       if (risk > 0) lots = calclots(slp*_Point);
       trade.BuyStop(lots,price,_Symbol,sl,0,ORDER_TIME_DAY,1);
       buypos = trade.ResultOrder();
       }

Normalmente, para un EA consistentemente rentable, el resultado de su backtest debería verse similar a una función exponencial como esta:

Curva

Resultado

A continuación se presentan algunas cuestiones a tener en cuenta al analizar las estadísticas de backtest al utilizar este modelo de trading con apalancamiento:

  • Si su Asesor Experto es consistentemente rentable, los resultados recientes tendrán un mayor impacto en el rendimiento general del backtest que los anteriores. Básicamente, estás asignando más peso a la importancia del desempeño reciente.
  • La correlación LR no es útil porque el gráfico será una curva exponencial.
  • El ratio de Sharpe deja de ser realista porque asume una relación lineal entre el riesgo y la rentabilidad. El apalancamiento amplifica tanto los retornos potenciales como los riesgos, lo que genera métricas de desempeño ajustadas al riesgo sesgadas.

Si aún desea evaluar las métricas anteriores, simplemente arregle el tamaño del lote y realice otra prueba.


Simulación de Monte Carlo de caída máxima

Consideramos una curva de capital como una serie de cambios porcentuales en el saldo de nuestra cuenta, y la caída máxima puede verse como el segmento de esa serie con el porcentaje acumulativo más pequeño. Una sola prueba retrospectiva representa solo una disposición posible de esta serie, lo que hace que su robustez estadística sea limitada. El objetivo de esta sección es comprender las posibles reducciones que podríamos encontrar y seleccionar el percentil 95 como nuestra referencia para la tolerancia máxima.

La simulación de Monte Carlo se puede utilizar para simular una posible curva de capital de varias maneras:

  1. Muestreo aleatorio de rendimientos: Al generar rendimientos aleatorios basados en el rendimiento histórico o en distribuciones estadísticas supuestas (por ejemplo, normales), se simulan posibles curvas de capital mediante la capitalización de los rendimientos a lo largo del tiempo.

  2. Bootstrapping: Remuestreo de rendimientos históricos con reemplazo para crear múltiples trayectorias de renta variable simuladas, que reflejan la variabilidad observada en el rendimiento pasado.

  3. Shuffling: Barajar aleatoriamente el orden de los rendimientos históricos y utilizar la serie reordenada para generar diferentes trayectorias de renta variable, lo que permite obtener un conjunto diverso de escenarios.

  4. Ajustes de riesgo/rentabilidad: Modificación de los parámetros de entrada (por ejemplo, límites de volatilidad o de caída) basándose en criterios de riesgo específicos para generar curvas de capital realistas en diferentes condiciones de mercado.

En este artículo, nos centraremos en el método de barajar (Shuffling).

En primer lugar, obtenemos el informe de la operación del backtest haciendo clic derecho de esta manera.

Informe de Excel

Luego abrimos Python y extraemos las filas útiles que tienen el saldo de la cuenta y las ganancias/pérdidas de cada operación con este código.

import pandas as pd
# Replace 'your_file.xlsx' with the path to your file
input_file = 'DBG-XAU.xlsx'
# Load the Excel file and skip the first {skiprows} rows
data = pd.read_excel(input_file, skiprows=10757)

# Select the 'profit' column (assumed to be 'Unnamed: 10') and filter rows as per your instructions
profit_data = data[['Profit','Balance']][1:-1] 
profit_data = profit_data[profit_data.index % 2 == 0]  # Filter for rows with odd indices
profit_data = profit_data.reset_index(drop=True)  # Reset index
# Convert to float, then apply the condition to set values to 1 if > 0, otherwise to 0
profit_data = profit_data.apply(pd.to_numeric, errors='coerce').fillna(0)  # Convert to float, replacing NaN with 0
# Save the processed data to a new CSV file with index
output_csv_path = 'processed-DBG-XAU.csv'
profit_data.to_csv(output_csv_path, index=True, header=['profit_loss','account_balance'])
print(f"Processed data saved to {output_csv_path}")

Las filas a omitir son básicamente las filas por encima de este índice -1.

Encontrar fila

A continuación, debemos convertir la ganancia en cambio porcentual para cada operación para garantizar que la serie reorganizada dé como resultado el mismo saldo final. Esto se hace desplazando la columna del saldo de la cuenta una fila y calculando las ganancias o pérdidas como porcentaje del saldo antes de cada operación.

initial_balance = account_balance.iloc[0] - profit_loss.iloc[0]

# Calculate the account balance before each trade
account_balance_before_trade = account_balance.shift(1)
account_balance_before_trade.iloc[0] = initial_balance

# Compute the percentage change made to the account balance for each trade
percentage_change = profit_loss / account_balance_before_trade

# Fill any NaN values that might have occurred
percentage_change.fillna(0, inplace=True)

Por último, simulamos 1000 series aleatorias y trazamos las 10 con mayor caída máxima. Tenga en cuenta que el capital final debería ser el mismo debido a la propiedad conmutativa de la multiplicación. Multiplicar la serie de variaciones porcentuales dará el mismo resultado, independientemente del orden en que se reorganicen los valores.

Curva de Monte Carlo

La distribución de la caída máxima debe ser similar a la distribución normal, y podemos ver aquí que el percentil 95 % (alrededor de dos desviaciones estándar) es aproximadamente el 30 % de caída máxima.

Distribución de Monte Carlo

La caída máxima de nuestra prueba retrospectiva inicial fue de apenas un 17 %, lo cual es menor que la media de esta distribución. Si lo hubiéramos tomado como la caída máxima que esperábamos, habríamos aumentado nuestro riesgo en un factor de 2 en comparación con el riesgo que ahora estamos dispuestos a asumir después de obtener los resultados de la simulación de Monte Carlo. Elegimos el percentil 95 % porque es un resultado general que los académicos consideran cercano al rendimiento comercial en vivo. Tuvimos suerte aquí porque el percentil del 95 % se alinea estrechamente con nuestra tolerancia máxima del 30 %, que se estableció al principio. Esto significa que si negociamos con este único EA en nuestra cartera, un riesgo del 2 % por operación maximizará nuestras ganancias y nos mantendrá dentro de nuestra tolerancia máxima. Si el resultado difiere, debemos repetir el procedimiento anterior hasta encontrar la solución óptima.


Criterio de Kelly para la optimización de carteras

Si ejecutamos varios EA en una sola cuenta, primero debemos completar el procedimiento anterior para cada EA para determinar su riesgo óptimo. Luego, aplicamos este riesgo al capital asignado para cada EA dentro de la cartera general. Desde la perspectiva de toda la cuenta, el monto de riesgo para cada EA será el riesgo original multiplicado por la fracción asignada.

La fracción de asignación de Kelly para cada EA está determinada por sus correlaciones de retorno con otros Asesores Expertos y su desempeño general en pruebas retrospectivas. Nuestro objetivo principal es garantizar que los Asesores Expertos compensen las caídas de los demás tanto como sea posible, lo que da como resultado una curva de capital más suave para toda la cartera. Es importante tener en cuenta que agregar más Asesores Expertos y estrategias solo mejora la diversidad de la cartera si no están correlacionados; de lo contrario, puede aumentar el riesgo general, de manera similar a amplificar el riesgo de un solo EA.

En concreto, calculamos la fracción de asignación de Kelly para cada estrategia en función de los rendimientos esperados y la matriz de covarianza de rendimientos utilizando las siguientes fórmulas:

Asignación de Kelly

  • r: El retorno de EAi o EAj en el momento t.
  • μ: El rendimiento medio de EAi o EAj.
  • f: Asignación de Kelly para cada EA.
  • Σ−1: La inversa de la matriz de covarianza.
  • u: El vector de rendimiento esperado para cada EA.

Para extraer los valores de las variables mencionadas anteriormente, debemos realizar un backtest para cada estrategia y almacenar la serie de porcentaje de retorno de cada estrategia en un solo marco de datos. A continuación, en función de la frecuencia de todos los Asesores Expertos, seleccionamos el intervalo de tiempo apropiado para el registro, ya que la covarianza se calcula en función de las correlaciones de los retornos dentro del mismo período de tiempo. Realizamos tales operaciones con este código de Python:

# Read returns for each strategy
    for file in strategy_files:
        try:
            data = pd.read_csv(file, index_col='Time')
            # Ensure 'Time' is parsed correctly as datetime
            data.index = pd.to_datetime(data.index, errors='coerce')
            
            # Drop rows where 'Time' or 'return' is invalid
            data.dropna(subset=['return'], inplace=True)
            
            # Aggregate duplicate time indices by mean (or could use 'sum', but here mean can ignore the trade frequency significance)
            data = data.groupby(data.index).agg({'return': 'mean'})
            
            # Append results
            returns_list.append(data['return'])
            strategy_names.append(file)
        except Exception as e:
            print(f"Error processing {file}: {e}")
            continue 
    # Check if any data was successfully loaded
    if not returns_list:
        print("No valid data found in files.")
        return  
    # Combine returns into a single DataFrame, aligning by date
    returns_df = pd.concat(returns_list, axis=1, keys=strategy_names) 
    # Uncomment the below line if u wanna drop rows with missing values across strategies
    #returns_df.dropna(inplace=True)
    #Uncomment the below line if u wanna just fill unaligned rows with 0( I think this is best for backtest that may have years differences)
    returns_df.fillna(0, inplace=True)

Asegúrese de que todos los resultados de las pruebas retrospectivas comiencen y finalicen al mismo tiempo. Además, seleccione un intervalo de tiempo apropiado para agregar los resultados de modo que ningún intervalo tenga una cantidad excesiva de transacciones, ni ningún intervalo sin transacciones en absoluto. Si los intervalos de tiempo son demasiado discretos, puede que no haya suficientes puntos de datos dentro de los mismos rangos de tiempo para calcular la covarianza con precisión. En nuestro caso, seleccionamos un intervalo de un mes y utilizamos el rendimiento medio de cada mes como característica de rendimiento.

Ahora hacemos los cálculos:

    # Calculate expected returns (mean returns)
    expected_returns = returns_df.mean()
    
    # Calculate the covariance matrix of returns
    cov_matrix = returns_df.cov()
    
    # Compute the inverse of the covariance matrix
    try:
        inv_cov_matrix = np.linalg.inv(cov_matrix.values)
    except np.linalg.LinAlgError:
        # Use pseudo-inverse if covariance matrix is singular
        inv_cov_matrix = np.linalg.pinv(cov_matrix.values)
    
    # Calculate Kelly optimal fractions
    kelly_fractions = inv_cov_matrix @ expected_returns.values
    kelly_fractions = kelly_fractions / np.sum(kelly_fractions)

Al final, el resultado será algo como esto:

         Strategy  Kelly Fraction
0  A1-DBG-XAU.csv        0.211095
1   A1-DBG-SP.csv        0.682924
2   A1-DBG-EU.csv        0.105981

Podemos implementar este riesgo directamente en nuestro código MQL5 original porque el cálculo del riesgo inicial ya estaba basado en el saldo total de la cuenta. A medida que cambia el saldo de la cuenta, el capital asignado se recalculará automáticamente y se aplicará a la próxima operación.

double riskAmount = AccountInfoDouble(ACCOUNT_BALANCE) * risk / 100;

Por ejemplo, para aplicar la fracción de Kelly calculada a nuestro EA de ejemplo, simplemente modificamos esta parte del código original y la tarea está completa.

input double risk = 2.0*0.211095;

Soy plenamente consciente de que alternativamente podríamos recalcular el riesgo en función del cambio en el capital asignado para cada EA, pero es preferible basar el cálculo en toda la cartera por las siguientes razones:

  1. En mi opinión, realizar un seguimiento de los cambios en las distintas capitales asignadas es una tarea difícil. Es posible que sea necesario abrir varias cuentas o escribir un programa para actualizar los cambios después de cada operación.
  2. El criterio de Kelly se utiliza para maximizar el crecimiento a largo plazo de toda la cartera. El rendimiento de cada EA afecta al riesgo de los demás EA, lo que facilita el crecimiento eficiente de una cartera pequeña a medida que se amplía.
  3. Si basamos el riesgo en el cambio en el capital asignado a cada EA, los Asesores Expertos con buen rendimiento verán aumentar su capital asignado con el tiempo, lo que provocará una mayor exposición al riesgo para estas EA. Esto socava nuestra intención inicial de calcular la asignación de riesgos en función de correlaciones.

Sin embargo, nuestro enfoque tiene ciertas limitaciones:

  1. El riesgo de cada EA fluctúa con el rendimiento general de la cartera, lo que dificulta el seguimiento del rendimiento de cada EA individual. La cartera completa puede verse como un índice similar al S&P 500. Para evaluar el rendimiento individual, sería necesario calcular el cambio porcentual en lugar de la ganancia absoluta.
  2. Nuestro cálculo de asignación de riesgos no tiene en cuenta la frecuencia de operaciones de cada EA. Esto significa que si los Asesores Expertos de una misma cuenta tienen frecuencias de negociación significativamente diferentes, podría dar lugar a una exposición al riesgo desigual, a pesar de la asignación.

En general, teniendo en cuenta el potencial de maximizar el crecimiento de los traders individuales, vale la pena adoptar este enfoque.



Conclusión

En este artículo, presentamos el criterio de Kelly dentro del contexto del Modelo de Trading de Espacio de Apalancamiento y su aplicación al trading. Luego proporcionamos el código de implementación en MQL5. Luego de esto, utilizamos la simulación de Monte Carlo para determinar la reducción máxima óptima a considerar con base en una sola prueba retrospectiva, que luego se aplicó para evaluar el riesgo de los EA individuales. Por último, presentamos un enfoque para la asignación de capital a cada EA en función de su desempeño de backtest y sus correlaciones.


Tabla de archivos

Nombre Uso
KellyMultiFactors.ipynb Calcular las fracciones de Kelly para asignar capital.
MonteCarloDrawdown.ipynb Realizar simulaciones de Monte Carlo.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16500

Archivos adjuntos |
Risk_Management.zip (190.96 KB)
Stanislav Korotky
Stanislav Korotky | 15 dic 2024 en 11:27
Dominic Michael Frehner #:

Sería realmente una locura construir un EA que gestionara toda la cuenta con el criterio de Kelly antes de que un EA coloque una operación. Esta es probablemente la parte más difícil.

Hay el probador para simular oficios en el pasado, entonces usted puede procesar los informes del probador en lugar de en línea.

RustyKanuck
RustyKanuck | 1 ene 2025 en 21:04
Es impresionante, ¡buen trabajo!
Zhuo Kai Chen
Zhuo Kai Chen | 2 ene 2025 en 02:58
RustyKanuck #:
Es impresionante, ¡buen trabajo!

Gracias

Too Chee Ng
Too Chee Ng | 29 abr 2025 en 09:51
Buen artículo para el debate.
Yevgeniy Koshtenko
Yevgeniy Koshtenko | 30 jun 2025 en 09:22
Gran artículo.
Cambiamos a MQL5 Algo Forge (Parte 2): Trabajando con varios repositorios Cambiamos a MQL5 Algo Forge (Parte 2): Trabajando con varios repositorios
Hoy analizaremos uno de los posibles enfoques para organizar el almacenamiento del código fuente de un proyecto en un repositorio público. Utilizando la distribución en diferentes ramas, crearemos reglas claras y cómodas para el desarrollo del proyecto.
Creamos y optimizamos un sistema comercial basado en los volúmenes negociados (Chaikin Money Flow (CMF)) Creamos y optimizamos un sistema comercial basado en los volúmenes negociados (Chaikin Money Flow (CMF))
En este artículo, le presentaremos el indicador Chaikin Money Flow (CMF), basado en el volumen, después de aprender cómo se puede construir, calcular y utilizar. Asimismo, veremos cómo crear un indicador personalizado, analizaremos algunas estrategias sencillas que podemos utilizar y las pondremos a prueba para ver cuál es la mejor.
Métodos de ensamble para mejorar predicciones numéricas en MQL5 Métodos de ensamble para mejorar predicciones numéricas en MQL5
En este artículo presentamos la implementación de varios métodos de aprendizaje por ensamble en MQL5 y examinamos su efectividad en distintos escenarios.
Creación de un Panel de administración de operaciones en MQL5 (Parte VIII): Panel de análisis Creación de un Panel de administración de operaciones en MQL5 (Parte VIII): Panel de análisis
Hoy profundizamos en la incorporación de métricas de trading útiles dentro de una ventana especializada integrada en el EA del Panel de Administración. Este debate se centra en la implementación de MQL5 para desarrollar un panel de análisis y destaca el valor de los datos que proporciona a los administradores de operaciones bursátiles. El impacto es principalmente educativo, ya que se extraen valiosas lecciones del proceso de desarrollo, lo que beneficia tanto a los desarrolladores noveles como a los experimentados. Esta función demuestra las oportunidades ilimitadas que ofrece esta serie de desarrollo al equipar a los gestores comerciales con herramientas de software avanzadas. Además, exploraremos la implementación de las clases PieChart y ChartCanvas como parte de la continua expansión de las capacidades del panel del administrador de operaciones.