Русский Português
preview
Exploramos modelos de regresión para inferencia causal y operaciones bursátiles

Exploramos modelos de regresión para inferencia causal y operaciones bursátiles

MetaTrader 5Integración |
48 15
dmitrievsky
[Eliminado]

Introducción

A lo largo de varios artículos, hemos explorado diversos métodos para clasificar series temporales, pero no hemos abarcado los modelos de regresión. Los modelos de regresión, a diferencia de la clasificación binaria, nos permiten predecir no la probabilidad de que una observación pertenezca a una clase particular, sino valores continuos, lo cual amplía las posibilidades de su aplicación para la creación de sistemas de negociación automatizados.

La clasificación binaria es una tarea fundamental del aprendizaje automático cuyo objetivo consiste en clasificar los datos de entrada en una de dos categorías o clases diferentes. En el contexto de un bot de trading en Forex, esto generalmente significa predecir una señal de "compra" (representada como 0) o de "venta" (representada como 1). Este enfoque reduce la compleja dinámica del mercado a una decisión direccional simple.

La limitación inherente más significativa de la clasificación binaria para el trading cuantitativo reside en su incapacidad para cuantificar la magnitud o intensidad del movimiento de precios previsto. Un clasificador binario solo indica si el precio subirá o bajará, sin ofrecer ninguna información sobre cuánto se espera que cambie. La falta de este tipo de detalles limita fundamentalmente la complejidad de las decisiones de trading.

La precisión de las predicciones del clasificador por sí sola no considera la magnitud del cambio y, por lo tanto, no resulta muy útil para operar en los mercados financieros. Este aspecto es clave porque pone de relieve que una alta precisión direccional (por ejemplo, predecir la dirección correcta el 70% de las veces) no conduce automáticamente a operaciones rentables. 

Debemos señalar que una alta precisión en la dirección no garantiza la rentabilidad. Por ejemplo, podemos acertar el 30% de las veces y obtener rentabilidad, o acertar el 70% de las veces y no obtenerla. Esto demuestra que el resultado neto de una estrategia de negociación está determinado por la cantidad de beneficios en las operaciones ganadoras en comparación con la cantidad de pérdidas en las operaciones perdedoras, y no simplemente por el porcentaje de victorias.

El modelo de clasificación binaria, al tratar todas las predicciones direccionales correctas por igual, independientemente del movimiento real del precio, no puede distinguir entre un movimiento pequeño e insignificante y uno grande y altamente rentable. Esto puede dar lugar a una situación en la que muchas pequeñas ganancias se vean contrarrestadas por unas pocas pérdidas importantes, o viceversa, lo que puede dar como resultado un PnL general negativo a pesar de una precisión aparentemente alta.

La falta de cuantificación del movimiento de precios implica que el bot de trading no puede priorizar las operaciones con mayores beneficios esperados ni evitar aquellas en las que la pérdida potencial supera sustancialmente los beneficios potenciales, incluso si la dirección se predice correctamente. Sin información sobre la magnitud, el bot opera con un punto ciego respecto al impacto financiero real de sus decisiones, lo que resulta en rendimientos acumulados subóptimos o incluso negativos a pesar de un alto porcentaje de victorias basadas en la dirección.


Modificación de la función de etiquetado

Vamos a analizar el siguiente escenario: disponemos de una serie temporal financiera que queremos predecir a partir de un conjunto de características. En el caso de la clasificación binaria, podemos determinar la dirección de una transacción futura (compra o venta), y estas etiquetas siempre son fijas. No podemos etiquetarlas de manera diferente para obtener una estimación más precisa de la magnitud de las futuras desviaciones de precios. Las operaciones son equivalentes independientemente de cuánto haya variado realmente el precio.

Ahora imaginemos que podemos predecir no solo la dirección de una operación comercial, sino también la magnitud del cambio futuro. Esto permitirá ajustar con mayor precisión el sistema de trading mediante la creación de filtros adicionales que ayudarán a identificar únicamente las fluctuaciones de precios previstas que sean significativas para negociar y a excluir las que no lo sean.

Para entrenar un modelo de regresión, debemos preparar las características y las variables objetivo para su entrenamiento. Las características pueden ser comunes al clasificador y al regresor, mientras que las características objetivo serán distintas.

Vamos a escribir una función sencilla que implemente el etiquetado de ejemplos para un modelo de regresión:

@njit
def calculate_labels_r(close_data, min_val, max_val):
    labels = []
    for i in range(len(close_data) - max_val):
        rand = random.randint(min_val, max_val)
        labels.append(close_data[i + rand] - close_data[i])
    return labels

def get_labels_r(dataset, min = 1, max = 15) -> pd.DataFrame:
    # Extract closing prices from the dataset
    close_data = dataset['close'].values
    labels = calculate_labels_r(close_data, min, max)
    # Trim the dataset to match the length of calculated labels
    dataset = dataset.iloc[:len(labels)].copy() 
    # Add the calculated labels as a new column
    dataset['labels'] = labels
    # Remove rows with NaN values (potentially introduced in 'calculate_labels')
    dataset = dataset.dropna()
    return dataset

La principal diferencia con respecto al marcado de clasificación binaria es que ahora determinamos los cambios de precio (restamos el precio actual al precio futuro) en lugar de simplemente determinar la dirección (compra o venta). El código se acelera mediante Numba, por lo que el marcado de destino es muy rápido.

La función anterior solo considera la diferencia entre un precio futuro elegido al azar en el rango {min_val; max_val} y el precio actual. Esto puede no ser del todo correcto, ya que no se tienen en cuenta las desviaciones intermedias, que pueden ser sustanciales. Le propongo otra modificación de la función de cálculo de la desviación, que se presenta a continuación.

@njit
def calculate_labels_mean_r(close_data, min_val, max_val):
    labels = []
    for i in range(len(close_data) - max_val):
        # Вычисляем среднее значение цен в окне от min_val до max_val
        future_prices = close_data[i + min_val : i + max_val + 1]
        mean_future_price = np.mean(future_prices)
        # Вычисляем разницу между средним будущим значением и текущей ценой
        labels.append(mean_future_price - close_data[i])
    return labels

def get_labels_r(dataset, min = 1, max = 15) -> pd.DataFrame:
    # Extract closing prices from the dataset
    close_data = dataset['close'].values
    # Calculate buy/hold labels based on future price movements
    labels = calculate_labels_mean_r(close_data, min, max)
    # Trim the dataset to match the length of calculated labels
    dataset = dataset.iloc[:len(labels)].copy() 
    # Add the calculated labels as a new column
    dataset['labels'] = labels
    # Remove rows with NaN values (potentially introduced in 'calculate_labels')
    dataset = dataset.dropna()
    return dataset

Ahora la función considera todas las desviaciones en el intervalo dado, calculando el valor promedio. Después de esto, se calcula la diferencia entre el valor promedio de los precios futuros y el precio actual. En consecuencia, la función get_labels_r() ahora llama a la función de etiquetado calculate_labels_mean_r(), en lugar de calculate_labels_r() como antes. Podemos experimentar llamando a diferentes funciones de marcado.


Adición de un sistema de inferencia causal

Para obtener predicciones más precisas, vamos a utilizar un algoritmo similar al descrito en el artículo sobre inferencia de causa y efecto. La principal diferencia radica en que se usa un regresor, no un clasificador.

def meta_learners(data, models_number: int, iterations: int, depth: int):
    data = data.copy()
    data = data[(data.index < hyper_params['forward']) & (data.index > hyper_params['backward'])].copy()

    X = data[data.columns[1:-1]]
    y = data['labels']
    data['meta_labels'] = 0

    for i in range(models_number):
        X_train, X_val, y_train, y_val = train_test_split(
            X, y, train_size = 0.5, test_size = 0.5, shuffle = True)
        
        # fit debias model with train and validation subsets
        meta_m = CatBoostRegressor(iterations = iterations,
                                depth = depth,
                                verbose = False,
                                use_best_model = True)
        
        meta_m.fit(X_train, y_train, eval_set = (X_val, y_val), plot = False)
        
        coreset = X.copy()
        coreset['labels'] = y
        coreset['labels_pred'] = meta_m.predict(X)
        data['meta_labels'] += abs(coreset['labels'] - coreset['labels_pred'])

    data['meta_labels'] = data['meta_labels'] / models_number
    return data

La función entrena múltiples regresores con subconjuntos aleatorios de datos del conjunto de datos de origen y luego compara los valores objetivo reales con los predichos. Por lo tanto, el metamodelo no pronosticará 0 o 1 (negociar o no negociar), sino los valores promedio de las desviaciones de los pronósticos con respecto a los reales. De esta forma podemos filtrar las previsiones que se desvían significativamente de los valores esperados.


Entrenamiento y prueba de modelos entrenados

Para probar modelos de regresión, el simulador ha sido modificado y tiene el sufijo "r". Es hora de entrenar algunos modelos. En este artículo, entrenaremos 10 modelos y seleccionaremos el que sea más de nuestro gusto.

hyper_params = {
    'symbol': 'EURUSD_H1',
    'export_path': '/Users/dmitrievsky/drive_c/Program Files/MetaTrader 5/MQL5/Include/Trend following/',
    'model_number': 0,
    'markup': 0.00010,
    'stop_loss':  0.00500,
    'take_profit': 0.00200,
    'periods': [i for i in range(5, 100, 30)],
    'backward': datetime(2010, 1, 1),
    'forward': datetime(2024, 1, 1),
}

models = []
for i in range(10):
    print('Learn ' + str(i) + ' model')
    data = get_labels_r(get_features(get_prices()), min=1, max=15)
    dataset = meta_learners(data=data, models_number=5, iterations=15, depth=3)
    models.append(fit_final_models(dataset, tol=3e-2))

Aquí debemos prestar atención al parámetro tol, que se transmite a la función de entrenamiento del modelo final. Como queremos que el modelo principal sea lo más robusto posible, no tiene sentido entrenarlo con todos los ejemplos. Solo lo entrenaremos con aquellos ejemplos cuyas predicciones se desvíen de las reales en menos del valor tol.

Dado que las desviaciones de las predicciones se cuentan en puntos, entonces tol=3e-2 significará una diferencia máxima de 0,03, es decir, 300 puntos de cuatro dígitos. Puede parecer un filtro demasiado grande, pero conviene tener en cuenta que se trata de una diferencia en valores absolutos, ya que las predicciones pueden ser tanto positivas como negativas. Podemos experimentar con este parámetro. A continuación se muestra la función en sí.

def fit_final_models(dataset, tol=1e-2) -> list:
    # features for model\meta models. We learn main model only on filtered labels
    X = dataset[dataset['meta_labels'] < tol]
    X, X_meta = X[X.columns[1:-2]], dataset[dataset.columns[1:-2]]
    # labels for model\meta models
    y = dataset[dataset['meta_labels'] < tol]
    y, y_meta = y[y.columns[-2]], dataset[dataset.columns[-1]]
    
    # fit main model with train and validation subsets
    model = RandomForestRegressor(n_estimators=50, max_depth=10)
    model.fit(X, y)
    # fit meta model with train and validation subsets
    meta_model = RandomForestRegressor(n_estimators=50, max_depth=10)
    meta_model.fit(X_meta, y_meta)

    data = get_features(get_prices())
    R2 = test_model_r(data, 
                    [model, meta_model], 
                    hyper_params['stop_loss'], 
                    hyper_params['take_profit'],
                    hyper_params['forward'],
                    hyper_params['backward'],
                    hyper_params['markup'],
                    plt=False)
    
    if math.isnan(R2):
        R2 = -1.0
        print('R2 is fixed to -1.0')
    print('R2: ' + str(R2))
    result = [R2, model, meta_model]
    return result

Ahora vamos a ordenar los modelos y llamar a la función de prueba personalizada:

models.sort(key=lambda x: x[0])
data = get_features(get_prices())
test_model_r(data, 
        models[-1][1:], 
        hyper_params['stop_loss'], 
        hyper_params['take_profit'],
        hyper_params['forward'],
        hyper_params['backward'],
        hyper_params['markup'],
        plt=True)

El modelo está sobreajustado y tiene un rendimiento deficiente con datos nuevos:

Figura 1. Prueba del modelo con etiquetado básico.

Realizaremos exactamente las mismas manipulaciones, pero tomaremos como base el etiquetador de operaciones calculate_labels_mean_r (), que calcula los precios futuros promedio.

Figura 2. Prueba del modelo con etiquetas promediadas.

El segundo indicador comercial, en promedio, muestra resultados más estables con datos nuevos. Aparentemente, esto se debe a que se tiene en cuenta el valor promedio de los precios futuros.

El simulador personalizado no tiene la capacidad de definir umbrales para el modelo de regresión principal, por lo que simplemente divide las predicciones del modelo en positivas y negativas, lo que significa que las señales siguen siendo bastante imprecisas. Pero lo solucionaremos directamente en la terminal MetaTrader 5.


Exportación de modelos al terminal Meta Trader 5

Ahora necesitamos exportar los modelos al terminal en formato ONNX y configurar el sistema de negociación. La función de exportación resulta familiar:

export_model_to_ONNX(model = models[-1],
                     symbol = hyper_params['symbol'],
                     periods = hyper_params['periods'],
                     periods_meta = hyper_params['periods'],
                     model_number = hyper_params['model_number'],
                     export_path = hyper_params['export_path'])

Cabe señalar que no podemos conectar los modelos de regresión CatBoost en formato ONNX a la terminal, por lo que hemos usado el algoritmo de bosque aleatorio.

La dimensionalidad del tensor de entrada se ajusta automáticamente en función de los hiperparámetros (número de características) que se especifican antes de que comience el entrenamiento. A continuación, los modelos se convierten al formato ONNX usando la función convert_sklearn() y se guardan en el disco en el directorio que especificamos en los hiperparámetros.

def export_model_to_ONNX(**kwargs):
    model = kwargs.get('model')
    symbol = kwargs.get('symbol')
    periods = kwargs.get('periods')
    periods_meta = kwargs.get('periods_meta')
    model_number = kwargs.get('model_number')
    export_path = kwargs.get('export_path')

    initial_type = [('float_input', FloatTensorType([None, len(hyper_params['periods'])]))]
    onnx_model = convert_sklearn(model[1], initial_types=initial_type)
    # save main model to ONNX
    with open(export_path +'catmodel ' + symbol + ' ' + str(model_number) +'.onnx', "wb") as f:
        f.write(onnx_model.SerializeToString())
    onnx_model_meta = convert_sklearn(model[2], initial_types=initial_type)
    # save meta model to ONNX
    with open(export_path +'catmodel_m ' + symbol + ' ' + str(model_number) +'.onnx', "wb") as f:
        f.write(onnx_model_meta.SerializeToString())
    
    code = '#include <Math\Stat\Math.mqh>'
    code += '\n'
    code += '#resource "catmodel '+ symbol + ' '+str(model_number)+'.onnx" as uchar ExtModel_' + symbol + '_' + str(model_number) + '[]'
    code += '\n'
    code += '#resource "catmodel_m '+ symbol + ' '+str(model_number)+'.onnx" as uchar ExtModel2_' + symbol + '_' + str(model_number) + '[]'
    code += '\n\n'
    code += 'int Periods' + symbol + '_' + str(model_number) + '[' + str(len(periods)) + \
        '] = {' + ','.join(map(str, periods)) + '};'
    code += '\n'
    code += 'int Periods_m' + symbol + '_' + str(model_number) + '[' + str(len(periods_meta)) + \
        '] = {' + ','.join(map(str, periods_meta)) + '};'
    code += '\n\n'

    # get features
    code += 'void fill_arays' + symbol + '_' + str(model_number) + '( double &features[]) {\n'
    code += '   double pr[], ret[];\n'
    code += '   ArrayResize(ret, 1);\n'
    code += '   for(int i=ArraySize(Periods'+ symbol + '_' + str(model_number) + ')-1; i>=0; i--) {\n'
    code += '       CopyClose(NULL,PERIOD_H1,1,Periods' + symbol + '_' + str(model_number) + '[i],pr);\n'
    code += '       ret[0] = MathStandardDeviation(pr);\n'
    code += '       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }\n'
    code += '   ArraySetAsSeries(features, true);\n'
    code += '}\n\n'

    # get features
    code += 'void fill_arays_m' + symbol + '_' + str(model_number) + '( double &features[]) {\n'
    code += '   double pr[], ret[];\n'
    code += '   ArrayResize(ret, 1);\n'
    code += '   for(int i=ArraySize(Periods_m' + symbol + '_' + str(model_number) + ')-1; i>=0; i--) {\n'
    code += '       CopyClose(NULL,PERIOD_H1,1,Periods_m' + symbol + '_' + str(model_number) + '[i],pr);\n'
    code += '       ret[0] = MathStandardDeviation(pr);\n'
    code += '       ArrayInsert(features, ret, ArraySize(features), 0, WHOLE_ARRAY); }\n'
    code += '   ArraySetAsSeries(features, true);\n'
    code += '}\n\n'

    file = open(export_path + str(symbol) + ' ONNX include' + ' ' + str(model_number) + '.mqh', "w")
    file.write(code)

    file.close()
    print('The file ' + 'ONNX include' + '.mqh ' + 'has been written to disk')


Configuración de umbrales en el terminal MetaTrader 5

Ahora que tenemos dos modelos de regresión en lugar de dos clasificadores, podemos establecer umbrales numéricos específicos.

Figura 3. Establecimiento de umbrales de activación de señal en el terminal.

  • Los umbrales buy_threshhold y sell_threshhold son los responsables de filtrar las señales del modelo de regresión principal. Si la señal está por debajo de este umbral, no se abrirá ninguna operación. Por ejemplo, si el cambio de precio previsto es inferior a 10 pips, abrir una operación de este tipo no tendrá mucho sentido, ya que no cubrirá el spread ni la comisión.
  • El umbral meta_threshhold filtra las señales del modelo principal basándose en la inferencia causal descrita anteriormente. Este comprueba qué tanto podría diferir el pronóstico del cambio real futuro. Si la diferencia es demasiado grande, tampoco se abrirán las operaciones.

Ahora probaremos nuestro modelo en el simulador de MetaTrader 5 con los umbrales dados:

Figura 4. Prueba del modelo con umbrales dados.

Permítame recordarle que el periodo forward comienza a principios de 2024 y que el modelo actualmente lo está ejecutando de manera bastante estable. Esto pone de relieve la importancia de definir y establecer umbrales adecuadamente. Podrá optimizar los valores umbral por sí mismo.

La variedad de modelos puede ser amplia, dependiendo del tipo de características (en este artículo, ambos modelos se entrenan con desviaciones estándar) y de los parámetros de los propios modelos. Por ejemplo, hemos entrenado otro modelo con parámetros diferentes, que funciona bien con datos nuevos incluso sin ajustar los umbrales.

Figura 5. Entrenamiento y prueba de otro modelo con diferentes parámetros de entrenamiento.

Y tras ajustar los umbrales, el modelo ha mostrado un crecimiento constante desde principios de 2024.

Figura 6. Prueba del modelo en el terminal después de configurar los umbrales.

La prueba de los modelos basados en un segundo etiquetador de operaciones y el filtrado por umbrales produce resultados aún más interesantes y precisos:

Figura 7. Prueba del modelo basada en el etiquetador de operación promedio y tol = 1e-2

Si cambiamos el parámetro tol durante el entrenamiento de 1e-2 a 1e-3, los resultados serán aún mejores:

Figura 8. Prueba del modelo basada en el etiquetador de operación promedio y tol = 1e-3


Información adicional

Para exportar modelos, necesitaremos instalar e importar el paquete skl2onnx:

from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

El código de inicio del modelo ONNX en el código del bot de trading también se ha modificado para que gestione correctamente los nuevos modelos de regresión:

vectorf y_main(1), y_meta(1);
   
OnnxRun(ExtHandle, ONNX_DEBUG_LOGS, f, y_main);
OnnxRun(ExtHandle2, ONNX_DEBUG_LOGS, f_m, y_meta);

float sig = y_main[0];
float meta_sig = y_meta[0];

Hemos añadido nuevas variables "input" para ajustar y optimizar los umbrales:

input double buy_threshold = 0.00001;
input double sell_threshold = -0.00001;
input double meta_threshold = 0.001;

 Ahora se accede a los nombres de los modelos ONNX mediante directivas #define, lo cual facilita la inclusión de modelos con nombres diferentes:

#define model ExtModel_EURUSD_H1_0
#define model_m ExtModel2_EURUSD_H1_0
#define periods PeriodsEURUSD_H1_0
#define periods_m Periods_mEURUSD_H1_0
#define fill_arrays fill_araysEURUSD_H1_0
#define fill_arrays_m fill_arays_mEURUSD_H1_0

Las señales de trading se generan cuando se cumplen ciertas condiciones en función de los umbrales establecidos:

if((Ask-Bid < max_spread*_Point) && MathAbs(meta_sig) < meta_threshold &&
      AllowTrade(OrderMagic))
      if(countOrders(OrderMagic) < max_orders &&
         CheckMoneyForTrade(_Symbol, LotsOptimized(), ORDER_TYPE_BUY))
        {
         double l = LotsOptimized();
         if(sig > buy_threshold && Allow_Buy)
           {
            int res = -1;
            do
              {
               double stop = Bid - stoploss * _Point;
               double take = Ask + takeprofit * _Point;
               res = mytrade.PositionOpen(_Symbol, ORDER_TYPE_BUY, l, Ask, stop, take, bot_comment);
               Sleep(50);
              }
            while(res == -1);
           }
         else
           {
            if(sig < sell_threshold && Allow_Sell)
              {
               int res = -1;
               do
                 {
                  double stop = Ask + stoploss * _Point;
                  double take = Bid - takeprofit * _Point;
                  res = mytrade.PositionOpen(_Symbol, ORDER_TYPE_SELL, l, Bid, stop, take, bot_comment);
                  Sleep(50);
                 }
               while(res == -1);
              }
           }
        }

También hemos añadido la herramienta de prueba de estrategias modificada y la función de exportación de modelos a los módulos correspondientes y las hemos adjuntado al artículo.


Conclusión

En este artículo, hemos descrito una posible (aunque no la única) manera de construir sistemas de negociación basados en modelos de regresión. Este enfoque permite un ajuste más preciso de los bots basados en aprendizaje automático. También permite convertir modelos claramente no rentables en rentables mediante el establecimiento de umbrales. Podemos utilizar cualquier indicador y/o etiquetador de posición, y también probar este algoritmo en otros instrumentos de negociación y otros marcos temporales.

El archivo Python files.zip contiene los siguientes archivos para desarrollar en el entorno Python:

Nombre del archivo Descripción
causal regression.py 
Script básico para el entrenamiento de modelos
labeling_lib.py
Módulo actualizado con etiquetadores de operaciones
tester_lib.py
Simulador personalizado actualizado para estrategias basadas en aprendizaje automático
export_lib.py Módulo de exportación de modelos al terminal
EURUSD_H1.csv
Archivo con las cotizaciones exportadas desde el terminal MetaTrader 5

El archivo MQL5 files.zip contiene archivos para el terminal MetaTrader 5:

Nombre del archivo Descripción
regression trader.ex5
Bot compilado de este artículo
regression trader.mq5
Bot fuente del artículo
carpeta Include//Trend following
Asimismo, encontrará los modelos ONNX y el archivo de encabezado para conectarse al bot

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/18603

Archivos adjuntos |
MQL5_files.zip (950.36 KB)
Python_files.zip (1094.44 KB)
[Eliminado] | 8 ago 2025 en 08:50
Guanlin Qi #:

Utilizo causal_regression_orig.py para producir el archivo de cabecera de ea, luego compilo ea.

El resultado es test_result pic in below.

Hay tan menos oficios que el que ha publicado.

Entonces, ¿cuál es la diferencia entre estos.

¿Hay muchas operaciones en python tester? Si es así, es necesario volver a configurar los umbrales para la apertura de operaciones en el programa mql5, tal vez son demasiado grandes.
Guanlin Qi
Guanlin Qi | 14 ago 2025 en 07:00
Maxim Dmitrievsky #:
¿Hay muchas operaciones en python tester? Si es así, es necesario volver a configurar los umbrales para la apertura de operaciones en el programa mql5, tal vez son demasiado grandes.


Este es el resultado de python tester, uso el mismo código que adjuntaste en este post. He comprobado en mt5 tester config panel, el buy_threshold y sell_threshold son ambos 0.0001 y -0.0001, igual que la configuración en este post.

He comprobado el código, y no sabía lo que es la diferencia entre esto.

[Eliminado] | 18 ago 2025 en 21:05
Guanlin Qi #:


Este es el resultado python tester, yo uso el mismo código que adjunta en este post. He comprobado en mt5 tester config panel, el buy_threshold y sell_threshold son 0.0001 y -0.0001, igual que la configuración en este post.

He comprobado el código, y no sabía lo que es la diferencia entre esto.

En el artículo meta-umbral es 0,001, debido a esto puede haber pocos oficios también. Este umbral se debe aumentar, trate de hacerlo 0,01 o 0,1 para las pruebas. Debería funcionar. Todos los umbrales pueden ser optimizados más tarde para un ajuste más fino.
GOT.IT
GOT.IT | 12 sept 2025 en 14:37

Saludos Maxim, muchas gracias por compartir con nosotros.

Pregunta. Después de calcular ONNX para un nuevo ticker y colocarlo en la carpeta Trend Following, ¿cómo puedo asegurarme de que el EA comience a utilizar los datos entrenados para el nuevo ticker? Para otros tickers, incluso si borro ONNX_EURUSD y coloco otro, el EA se comporta de forma idéntica. ¿Tengo que cambiar algo en el MQL5 Expert Advisor al cambiar el ticker?

[Eliminado] | 21 sept 2025 en 10:30
GOT.IT #:

Saludos Maxim, muchas gracias por compartir con nosotros.

Pregunta. Después de calcular ONNX para un nuevo ticker y colocarlo en la carpeta Trend Following, ¿cómo puedo asegurarme de que el EA comience a utilizar los datos entrenados para el nuevo ticker? Para otros tickers, incluso si borro ONNX_EURUSD y coloco otro, el EA se comporta de forma idéntica. ¿Tengo que cambiar algo en el MQL5 Expert Advisor al cambiar el ticker?

Hola, necesitas conectar el archivo .mqh con el nuevo ticker en el código del EA.

#include <Trend following/EURUSD_H1 ONNX include 0.mqh>

Es decir, cambiar el seleccionado a otro archivo con un nombre diferente, que fue generado por el script python.

Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Algoritmo de mercado bursátil de Intercambio — Exchange Market Algorithm (EMA) Algoritmo de mercado bursátil de Intercambio — Exchange Market Algorithm (EMA)
Este artículo ofrece un análisis detallado del algoritmo de mercado bursátil (EMA), inspirado en el comportamiento de los tráders en el mercado de valores. El algoritmo simula el proceso de negociación de acciones, donde los participantes del mercado con distintos niveles de éxito emplean distintas estrategias para maximizar sus beneficios.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Formulación de un Asesor Experto Multipar Dinámico (Parte 3): Estrategias de reversión a la media y de impulso Formulación de un Asesor Experto Multipar Dinámico (Parte 3): Estrategias de reversión a la media y de impulso
En este artículo, analizaremos la tercera parte de nuestro proceso de creación de un asesor experto (EA) dinámico para múltiples pares, centrándonos específicamente en la integración de las estrategias de trading de reversión a la media y momentum. Analizaremos cómo detectar y reaccionar ante las desviaciones de los precios respecto a la media (puntuación Z), y cómo medir el impulso en varios pares de divisas para determinar la dirección de la operación.