English Русский Português
preview
Red neuronal cuántica en MQL5 (Parte II): Entrenamos una red neuronal con retropropagación del error utilizando matrices de Márkov de ALGLIB

Red neuronal cuántica en MQL5 (Parte II): Entrenamos una red neuronal con retropropagación del error utilizando matrices de Márkov de ALGLIB

MetaTrader 5Indicadores |
29 9
Yevgeniy Koshtenko
Yevgeniy Koshtenko

«Los ordenadores cuánticos y la computación cuántica, si se hacen realidad, cambiarán nuestra concepción de la computación y, quizá, de cómo entendemos la propia naturaleza de la realidad»

Mijaíl Dyakonov (Mikhail Dyakonov), físico


Los tráders algorítmicos se enfrentan cada vez más a que los modelos habituales dejan de dar resultados. Las redes LSTM, que antes se consideraban un avance revolucionario, alcanzan una precisión del 58 %. Los transformers, a pesar de sus avances en el procesamiento del lenguaje natural (NLP), manejan mal el ruido de los datos financieros. Los modelos de tipo ARIMA han perdido su valor práctico.

Una situación típica: un sistema de trading se comporta de forma excelente en los datos históricos, pero en el trading real pierde rápidamente eficacia. La causa principal es el sobreajuste y la incapacidad de las redes clásicas para adaptarse a las condiciones cambiantes del mercado. La transición de una tendencia tranquila a una alta volatilidad vuelve inútiles a muchos algoritmos. La precisión de los pronósticos desciende hasta el 51–58 %, las reducciones alcanzan el 40–50 % y la ratio de Sharpe rara vez supera el 1,0.


Un nuevo enfoque: efectos cuánticos en el trading algorítmico

Proponemos una perspectiva diferente para el análisis de los mercados: con el uso de efectos cuánticos. No se trata de física de partículas, sino de una analogía: muchos principios de la mecánica cuántica —superposición, interferencia, decoherencia y resonancia— encuentran aplicación en el análisis de datos financieros.

  • Superposición: un activo puede mostrar simultáneamente señales de subida y de bajada en distintos marcos temporales.
  • Interferencia: las señales concordantes (noticias, análisis técnico, volúmenes) refuerzan el movimiento; las discordantes lo atenúan.
  • Decoherencia: la influencia de las noticias se atenúa con el tiempo; el mercado «olvida» los eventos.
  • Resonancia: la coincidencia de los ciclos de mercado refuerza el movimiento, lo que da lugar a tendencias muy marcadas.

El modelo, construido de acuerdo con principios cuánticos, muestra:

  • precisión de los pronósticos: 62–65 %
  • ratio de Sharpe: 1,8–2,4
  • reducción máxima: no superior al 20 %

Se adjunta el código fuente completo del asesor experto de trading en MQL5; el sistema está listo para su uso en MetaTrader 5.


Cómo funciona una red neuronal cuántica

La red es un analizador de varios niveles, en el que cada nivel se encarga de un aspecto concreto del mercado. Se analizan más de 400 características:

  • los precios OHLC de los últimos 20 periodos;
  • los volúmenes de negociación y su evolución;
  • RSI, estocástico, medias móviles y otros indicadores;
  • patrones de velas (doji, martillo, estrella, etc.);
  • patrones temporales (horas del día, días de la semana);
  • ciclos de mercado y resonancias temporales.
Cómo se aplican los efectos cuánticos
  1. Resonancia: amplifica las señales que coinciden con la memoria «sintonizada» de la red.
  2. Interferencia: el sistema detecta influencias concordantes o contradictorias.
  3. Superposición: se analizan simultáneamente características contradictorias.
  4. Decoherencia: se tiene en cuenta la disminución de la importancia de los eventos con el paso del tiempo.

Arquitectura del sistema

La arquitectura propuesta consta de los siguientes componentes:

  1. Capa de entrada: procesamiento de 400 características de datos de mercado
  2. Procesador cuántico: aplicación de efectos cuánticos a los datos de entrada
  3. Analizador de contexto: sistema de memoria multinivel
  4. Cadenas de Márkov: modelado de estados del mercado
  5. Bloques de Transformer: mecanismo de atención con modificaciones cuánticas
  6. Modelo de espacio de estados (SSM): dependencias a largo plazo
  7. Modelo de metaverificación: evaluación de la confianza en los pronósticos
  8. Capa de salida: generación de señales de trading

Esta es la parte más interesante: aquí es donde ocurre la verdadera magia. El sistema aplica tres efectos cuánticos a la información recopilada, que le ayudan a comprender las relaciones ocultas en los datos de mercado.

La resonancia funciona como la sintonización de una radio en la frecuencia deseada. Cuando la señal de entrada y la información almacenada en la memoria del sistema «resuenan» entre sí, el sistema amplifica dicha señal. Matemáticamente, se ve así:

resonance = 1.0 + resonance_strength * cos(input_val * context_val * π)

Imagine que el precio del EUR/USD empieza a subir y que el sistema «recuerda» una situación similar del pasado reciente. Si los patrones coinciden, se produce resonancia y el sistema aumenta la confianza en el pronóstico de subida.

La interferencia muestra cómo los distintos factores se influyen mutuamente. A veces amplifican la señal general (interferencia constructiva) y otras veces la atenúan (interferencia destructiva). La fórmula es sencilla:

interference = interference_amplitude * sin(input_val * context_val * 2π)

Por ejemplo, si los indicadores técnicos apuntan a un crecimiento, pero las noticias son negativas, se produce una interferencia destructiva: las señales se «anulan» entre sí.

La decoherencia es la responsable de que «se olvide» la información antigua. Cuanto más tiempo haya transcurrido desde que se produjo el evento, menor será su influencia en el pronóstico actual:

coherent_factor = coherence + (1.0 - coherence) * exp(-decoherence_rate * t)

Es como la memoria humana: recordamos bien las noticias de ayer, pero lo que ocurrió hace un mes ya no es tan importante.

El sistema cuenta con cuatro tipos de memoria, como la memoria humana. La memoria a corto plazo retiene lo que ha ocurrido en las últimas horas. La memoria a medio plazo almacena información sobre los acontecimientos de los últimos días. La memoria a largo plazo contiene patrones importantes que se han observado durante semanas. Y la memoria episódica recuerda acontecimientos especiales, como los días de noticias importantes o de movimientos bruscos del mercado.

Lo interesante es que el peso de cada tipo de memoria cambia automáticamente en función de las condiciones del mercado:

short_weight = 0.4 + 0.4 * input_volatility
medium_weight = 0.3 + 0.2 * (1.0 - input_volatility)  
long_weight = 0.2 + 0.3 * (1.0 - input_volatility)
episodic_weight = 0.1 + 0.3 * input_complexity

Cuando el mercado se vuelve volátil, el sistema se apoya más en la memoria a corto plazo: lo que ocurrió hace una hora es más importante que lo de hace una semana. En los periodos tranquilos, por el contrario, se activa la memoria a largo plazo para identificar tendencias globales.


Las cadenas de Márkov como modelo de la dinámica de mercado

El sistema clasifica el estado actual del mercado como uno de cinco: subida fuerte, subida débil, movimiento lateral, caída débil o caída fuerte. Es parecido a cómo los meteorólogos clasifican el tiempo: soleado, nublado, lluvioso.

int ClassifyMarketState(double price_change, double volatility, double volume_ratio) {
    double abs_change = MathAbs(price_change);
    
    // Umbrales adaptativos que tienen en cuenta la volatilidad y el volumen
    double strong_threshold = 0.002 * (1.0 + volatility) * volume_ratio;
    double weak_threshold = 0.0005 * (1.0 + volatility) * volume_ratio;
    
    if(price_change > strong_threshold) return 0;      // Alcista fuerte
    else if(price_change > weak_threshold) return 1;   // Alcista débil
    else if(price_change < -strong_threshold) return 4; // Bajista fuerte
    else if(price_change < -weak_threshold) return 3;  // Bajista débil
    else return 2;                                      // Neutro
}

Pero el sistema va más allá: analiza con qué frecuencia el mercado pasa de un estado a otro. Por ejemplo, si ahora el crecimiento es débil, ¿qué probabilidad hay de que mañana se produzca un fuerte crecimiento o un movimiento lateral? Estos datos ayudan a pronosticar el siguiente «paso» del mercado.

Además, creamos un espacio de estados SSM de 256 dimensiones:

struct StateSpaceModel {
    matrix A, B, C;  // Matrices de transición, entrada y salida
    matrix state;    // Estado oculto
    
    matrix ProcessSequence(const matrix &input) {
        // Actualización: state = state * A + input * B
        // Salida: output = state * C
    }
};

¿Para qué necesitamos el SSM si ya existen las cadenas de Márkov? La diferencia fundamental radica en las escalas temporales y la naturaleza de la información. Las cadenas de Márkov responden a la pregunta «¿cuál es el régimen de mercado actual?» y son procesos sin memoria, ya que solo tienen en cuenta el estado anterior. Por su parte, el SSM acumula memoria cuantitativa sobre todo el historial de mercado a través de la evolución del estado oculto según la fórmula state_t = A * state_t-1 + B * input_t, donde cada componente del vector de 256 dimensiones puede representar diversos aspectos de los patrones acumulados: tendencias a largo plazo, volatilidad, perfiles de volumen y estructuras de correlación.

Esta arquitectura permite al sistema operar simultáneamente con las características cualitativas del momento actual mediante cadenas de Márkov y con la memoria cuantitativa de las regularidades a largo plazo mediante el SSM. Los resultados experimentales muestran que la combinación de estos enfoques proporciona un aumento de la precisión del 7 % en comparación con el uso exclusivo de estados discretos, ya que el SSM detecta patrones con un horizonte de varias decenas de periodos de negociación, inaccesibles para las cadenas de Márkov de primer orden.

Balanceo de clases

Uno de los problemas críticos del aprendizaje automático financiero es la distribución desigual de los movimientos del mercado. En los periodos de baja volatilidad predominan las señales neutras, mientras que los movimientos fuertes son poco frecuentes.

El sistema se adapta automáticamente mediante pesos de clase dinámicos:

void CalculateClassWeights(const vector &target_data) {
    // Recuento del número de elementos de cada clase
    int class_0_count = 0; // caída (0,2)
    int class_1_count = 0; // movimiento lateral (0,5) 
    int class_2_count = 0; // crecimiento (0,8)
    
    for(ulong i = 0; i < target_data.Size(); i++) {
        if(target_data[i] <= 0.3) class_0_count++;
        else if(target_data[i] >= 0.7) class_2_count++;
        else class_1_count++;
    }
    
    int total_samples = (int)target_data.Size();
    class_weights = vector::Zeros(3);
    
    // Cálculo de los pesos (inversamente proporcionales a la frecuencia)
    if(class_0_count > 0) class_weights[0] = (double)total_samples / (3.0 * class_0_count);
    if(class_1_count > 0) class_weights[1] = (double)total_samples / (3.0 * class_1_count);
    if(class_2_count > 0) class_weights[2] = (double)total_samples / (3.0 * class_2_count);
    
    Print("Class distribution - Fall:", class_0_count, ", Sideways:", class_1_count, ", Rise:", class_2_count);
    Print("Class weights - Fall:", class_weights[0], ", Sideways:", class_weights[1], ", Rise:", class_weights[2]);
}

El algoritmo analiza la distribución de los valores objetivo en la muestra de entrenamiento y los clasifica en tres categorías: caída (target ≤ 0,3), movimiento lateral (0,3 < target < 0,7) y crecimiento (target ≥ 0,7). Los pesos de clase se calculan de forma inversamente proporcional a su frecuencia de aparición, según la fórmula weight_i = N/(3×N_i), donde N es el número total de muestras y N_i es el número de muestras de la clase i-ésima. Estos pesos se integran en la función de pérdida multiplicando el error cuadrático medio por el peso de clase correspondiente, lo que hace que el modelo preste más atención a los eventos de mercado poco frecuentes, pero de importancia crítica.

Estos pesos se integran en la función de pérdida multiplicando el error cuadrático medio por el peso de clase correspondiente, lo que hace que el modelo preste más atención a los eventos de mercado poco frecuentes, pero de importancia crítica:

double CalculateLoss(double prediction, double target) {
    double mse = (prediction - target) * (prediction - target);
    
    // Aplicación del peso de clase
    double class_weight = GetClassWeight(target);
    mse *= class_weight;
    
    double l2_penalty = 0.0;
    for(ulong i = 0; i < output_projection.Rows(); i++)
        for(ulong j = 0; j < output_projection.Cols(); j++)
            l2_penalty += output_projection[i][j] * output_projection[i][j];
    
    double loss = mse + weight_decay * l2_penalty;
    return loss;
}


Entrenamiento y retropropagación

El entrenamiento de la red se realiza mediante el optimizador Adam, que tiene en cuenta las correlaciones cuánticas al actualizar los pesos. La retropropagación a través de las capas cuánticas se implementa de la siguiente manera:

matrix Backward(const matrix &output_gradient) {
    matrix input_gradient = matrix::Zeros(last_input_data.Rows(), last_input_data.Cols());
    for(ulong i = 0; i < last_input_data.Rows(); i++) {
        for(ulong j = 0; j < last_input_data.Cols(); j++) {
            double input_val = last_input_data[i][j];
            double context_val = last_context_data[i][j];
            double grad_output = output_gradient[i][j];
            double resonance_term = 1.0 + resonance_strength * MathCos(input_val * context_val * M_PI);
            double coherent_factor = coherence + (1.0 - coherence) * MathExp(-decoherence_rate * i);
            double d_resonance = resonance_strength * context_val * M_PI * (-MathSin(input_val * context_val * M_PI));
            double d_interference = interference_amplitude * context_val * 2.0 * M_PI * MathCos(input_val * context_val * 2.0 * M_PI);
            double quantum_derivative = resonance_term * coherent_factor + input_val * d_resonance * coherent_factor + d_interference;
            input_gradient[i][j] = grad_output * quantum_derivative;
        }
    }
    return input_gradient;
}

Las correcciones cuánticas de los gradientes permiten a la red detectar relaciones no lineales, potenciando los patrones significativos y suprimiendo el ruido. La retropropagación a través de la capa de atención tiene en cuenta el mecanismo softmax:

matrix QuantumAttentionLayer::Backward(const matrix &output_gradient) {
    grad_W_o = last_attention_output.Transpose().MatMul(output_gradient);
    matrix grad_attention_output = output_gradient.MatMul(W_o.Transpose());
    matrix grad_V = last_scores_softmax.Transpose().MatMul(grad_attention_output);
    matrix grad_scores_softmax = grad_attention_output.MatMul(last_V.Transpose());
    matrix grad_scores = matrix::Zeros(last_scores_softmax.Rows(), last_scores_softmax.Cols());
    for(ulong i = 0; i < last_scores_softmax.Rows(); i++) {
        vector softmax_row = last_scores_softmax.Row(i);
        vector grad_softmax_row = grad_scores_softmax.Row(i);
        for(ulong j = 0; j < softmax_row.Size(); j++) {
            double grad_accumulator = 0.0;
            for(ulong k = 0; k < softmax_row.Size(); k++) {
                if (j == k) {
                    grad_accumulator += grad_softmax_row[k] * softmax_row[j] * (1.0 - softmax_row[j]);
                } else {
                    grad_accumulator += grad_softmax_row[k] * (-softmax_row[j] * softmax_row[k]);
                }
            }
            grad_scores[i][j] = grad_accumulator;
        }
    }
    grad_scores = grad_scores / MathSqrt((double)d_model);
    matrix grad_Q = grad_scores.MatMul(last_K);
    matrix grad_K = grad_scores.Transpose().MatMul(last_Q);
    grad_Q = quantum_proc.Backward(grad_Q);
    grad_K = quantum_proc.Backward(grad_K);
    grad_W_q = last_input_data.Transpose().MatMul(grad_Q);
    grad_W_k = last_input_data.Transpose().MatMul(grad_K);
    grad_W_v = last_input_data.Transpose().MatMul(grad_V);
    matrix grad_input = grad_Q.MatMul(W_q.Transpose()) + grad_K.MatMul(W_k.Transpose()) + grad_V.MatMul(W_v.Transpose());
    return grad_input;
}

El proceso de entrenamiento consta de 50 épocas, con detención anticipada si no se observa ninguna mejora en el error de validación durante 10 épocas:

void TrainQuantumNetwork() {
    QuantumNeural quantum_net;
    quantum_net.Init();
    EnhancedMarkovChain markov_chain;
    markov_chain.Init(5);
    AdvancedHyperparameterManager param_manager;
    param_manager.Init();
    matrix training_features;
    vector training_targets;
    if (!CollectMarketFeatures(_Symbol, PERIOD_H1, 1000, training_features, training_targets)) {
        Print("ОШИБКА: Не удалось собрать данные для обучения");
        return;
    }
    int train_size = (int)(training_features.Rows() * 0.8);
    int val_size = (int)training_features.Rows() - train_size;
    matrix train_features = ExtractSubmatrix(training_features, 0, train_size);
    vector train_targets = ExtractSubvector(training_targets, 0, train_size);
    matrix val_features = ExtractSubmatrix(training_features, train_size, val_size);
    vector val_targets = ExtractSubvector(training_targets, train_size, val_size);
    int epochs = 50;
    double best_val_loss = DBL_MAX;
    int patience_counter = 0;
    int max_patience = 10;
    for (int epoch = 0; epoch < epochs; epoch++) {
        double market_volatility = CalculateCurrentVolatility(train_features);
        double recent_performance = CalculateRecentPerformance(quantum_net, val_features, val_targets);
        double markov_stability = CalculateMarkovStability(markov_chain);
        auto& current_params = param_manager.AdaptHyperparameters(market_volatility, 0.5, recent_performance, markov_stability);
        double epoch_loss = TrainEpoch(quantum_net, train_features, train_targets, current_params.learning_rate, true);
        double val_loss = ValidateEpoch(quantum_net, val_features, val_targets);
        if (val_loss < best_val_loss) {
            best_val_loss = val_loss;
            patience_counter = 0;
        } else {
            patience_counter++;
            if (patience_counter >= max_patience) {
                break;
            }
        }
    }
}

Las correcciones cuánticas de los gradientes permiten detectar relaciones no lineales, potenciando los patrones significativos y suprimiendo el ruido.

La función de pérdida ponderada modifica el algoritmo estándar de retropropagación del error. Los gradientes no solo se multiplican por los pesos de clase en la capa de salida, sino que se propagan a través de toda la arquitectura, incluidos los procesadores cuánticos y los bloques de Transformer:

void Train(const matrix &features_data, const vector &target_data, int epochs, double learning_rate, bool is_markov_chain) {
    // Cálculo de los pesos de clase
    CalculateClassWeights(target_data);
    
    for (int epoch = 0; epoch < epochs; epoch++) {
        for (ulong i = 0; i < features_data.Rows(); i++) {
            vector input_features = features_data.Row(idx);
            double target = target_data[idx];
            double confidence;
            double prediction = Predict(input_features, confidence, true);
            
            double loss = CalculateLoss(prediction, target);
            
            // Aplicación del peso de clase al gradiente
            double class_weight = GetClassWeight(target);
            double weighted_error = (prediction - target) * class_weight;
            
            Backward(input_features, weighted_error, learning_rate);
        }
    }
}

Esto garantiza que las representaciones internas de la red se vuelvan más sensibles a los patrones de eventos poco frecuentes. Los resultados experimentales muestran una mejora del recall para la clase de movimientos fuertes, que pasa del 34 % al 58 %, con una ligera disminución de la precisión global en un 2 %.


Recopilación y procesamiento de características

El sistema analiza 400 características, entre las que se incluyen:

Bloque 1. Características OHLC básicas (80 características):

  • precios de apertura normalizados (20 barras)
  • diferenciales High-Low (20 barras)
  • variaciones Close-Open (20 barras)
  • True Range (20 barras)

Bloque 2. Características de volumen (40 características):

  • volumen normalizado (20 barras)
  • ratios del volumen respecto a la media (10 barras)
  • tasa de cambio del volumen (10 barras)

Bloque 3. Indicadores técnicos (80 características):

  • RSI con diferentes periodos (10 características)
  • estocástico %K (10 características)
  • Tasa de cambio (10 características)
  • Momentum (10 características)
  • ratios de SMA (20 características)
  • ratios de EMA (20 características)

Bloque 4. Volatilidad (30 características):

  • ATR con diferentes periodos (10 características)
  • ratios de volatilidad (20 características)

Bloque 5. Características de autocorrelación (60 características):

  • autocorrelación de los precios (20 lags)
  • autocorrelación de los volúmenes (20 lags)
  • correlación cruzada precio-volumen (20 lags)

Bloque 6. Características estadísticas (50 características):

  • estadísticas básicas (media, desviación estándar, asimetría, curtosis)
  • correlaciones entre las distintas variables
  • información mutua
  • entropía de Shannon

Bloque 7. Características temporales (30 características):

  • hora del día, día de la semana, día del mes
  • transformaciones de seno/coseno
  • sesiones de negociación (asiática, europea, americana)

Bloque 8. Patrones y formaciones (20 características):

  • patrones de velas (doji, martillo, estrella fugaz)
  • gaps
  • niveles de soporte/resistencia

Todas las características se discretizan en 10 bins para mejorar la robustez del modelo frente a los valores atípicos y se normalizan para garantizar un entrenamiento estable.

Código de recopilación de datos:

bool CollectMarketFeatures(string symbol, ENUM_TIMEFRAMES timeframe, int count, matrix &features, vector &targets) {
    features = matrix::Zeros(count, FEATURES_COUNT);
    targets = vector::Zeros(count);
    double close[], high[], low[], open[], volume[];
    ArraySetAsSeries(close, true);
    ArraySetAsSeries(high, true);
    ArraySetAsSeries(low, true);
    ArraySetAsSeries(open, true);
    ArraySetAsSeries(volume, true);
    CopyClose(symbol, timeframe, 0, count + 50, close);
    CopyHigh(symbol, timeframe, 0, count + 50, high);
    CopyLow(symbol, timeframe, 0, count + 50, low);
    CopyOpen(symbol, timeframe, 0, count + 50, open);
    CopyTickVolume(symbol, timeframe, 0, count + 50, volume);
    for (int i = 0; i < count; i++) {
        vector row = vector::Zeros(FEATURES_COUNT);
        int feature_idx = 0;
        row[feature_idx++] = close[i] / close[i+1] - 1.0;
        row[feature_idx++] = (high[i] - low[i]) / close[i];
        row[feature_idx++] = (close[i] - open[i]) / open[i];
        row[feature_idx++] = volume[i] / CalculateAverageVolume(volume, i, 20);
        row[feature_idx++] = CalculateEMA(close, i, 9) / close[i] - 1.0;
        row[feature_idx++] = CalculateEMA(close, i, 21) / close[i] - 1.0;
        row[feature_idx++] = CalculateEMA(close, i, 50) / close[i] - 1.0;
        row[feature_idx++] = CalculateSMA(close, i, 200) / close[i] - 1.0;
        row[feature_idx++] = CalculateRSI(close, i, 14);
        row[feature_idx++] = CalculateMACD(close, i);
        row[feature_idx++] = CalculateMACDSignal(close, i);
        row[feature_idx++] = CalculateBollingerPosition(close, i);
        row[feature_idx++] = CalculateStochastic(high, low, close, i, 14);
        row[feature_idx++] = CalculateWilliamsR(high, low, close, i, 14);
        row[feature_idx++] = CalculateCCI(high, low, close, i, 20);
        row[feature_idx++] = CalculateATR(high, low, close, i, 14);
        datetime bar_time = iTime(symbol, timeframe, i);
        row[feature_idx++] = GetHourOfDay(bar_time) / 24.0;
        row[feature_idx++] = GetDayOfWeek(bar_time) / 7.0;
        row[feature_idx++] = GetDayOfMonth(bar_time) / 31.0;
        row[feature_idx++] = IsMarketSession(bar_time, "US") ? 1.0 : 0.0;
        row[feature_idx++] = IsMarketSession(bar_time, "EU") ? 1.0 : 0.0;
        row[feature_idx++] = IsMarketSession(bar_time, "ASIA") ? 1.0 : 0.0;
        features.Row(row, i);
        targets[i] = close[i] - close[i+1];
    }
    return NormalizeFeatures(features);
}

La normalización de datos tiene en cuenta los valores atípicos y lleva las características a una escala común:

bool NormalizeFeatures(matrix &features) {
    vector feature_means = vector::Zeros(features.Cols());
    vector feature_stds = vector::Zeros(features.Cols());
    for (ulong j = 0; j < features.Cols(); j++) {
        vector column = features.Col(j);
        feature_means[j] = column.Mean();
        feature_stds[j] = MathSqrt(column.Variance());
        double threshold = 3.0 * feature_stds[j];
        int outliers_count = 0;
        for (ulong i = 0; i < features.Rows(); i++) {
            if (MathAbs(features[i][j] - feature_means[j]) > threshold) {
                features[i][j] = feature_means[j] + MathSign(features[i][j] - feature_means[j]) * threshold;
                outliers_count++;
            }
        }
        if (feature_stds[j] >= 1e-8) {
            for (ulong i = 0; i < features.Rows(); i++) {
                features[i][j] = (features[i][j] - feature_means[j]) / feature_stds[j];
            }
        }
    }
    return true;
}


Procedimiento de entrenamiento

void TrainQuantumNetwork() {
    QuantumNeural quantum_net;
    quantum_net.Init();
    
    // Recopilación de datos
    matrix training_features;
    vector training_targets;
    CollectMarketFeatures(_Symbol, PERIOD_H1, 5000, training_features, training_targets);
    
    // División en entrenamiento/validación
    int train_size = 4000;
    matrix train_features = ExtractSubmatrix(training_features, 0, train_size);
    vector train_targets = ExtractSubvector(training_targets, 0, train_size);
    matrix val_features = ExtractSubmatrix(training_features, train_size, 1000);
    vector val_targets = ExtractSubvector(training_targets, train_size, 1000);
    
    // Entrenamiento con detención anticipada
    int epochs = 50;
    double best_val_loss = DBL_MAX;
    int patience_counter = 0;
    int max_patience = 10;
    
    for (int epoch = 0; epoch < epochs; epoch++) {
        // Adaptación de hiperparámetros
        double market_volatility = CalculateCurrentVolatility(train_features);
        auto& current_params = param_manager.AdaptHyperparameters(
            market_volatility, 0.5, recent_performance, markov_stability);
        
        // Entrenamiento de una época
        double epoch_loss = TrainEpoch(quantum_net, train_features, train_targets, 
                                     current_params.learning_rate, true);
        double val_loss = ValidateEpoch(quantum_net, val_features, val_targets);
        
        // Detención anticipada
        if (val_loss < best_val_loss) {
            best_val_loss = val_loss;
            patience_counter = 0;
        } else {
            patience_counter++;
            if (patience_counter >= max_patience) break;
        }
    }
}

Para evaluar la eficacia de la arquitectura propuesta, se llevaron a cabo pruebas comparativas con modelos tradicionales, como LSTM, modelos de Transformer y boosting de gradiente (XGBoost). Resultados de la comparación:

Modelo Precisión de dirección
Red neuronal cuántica 0,65
LSTM 0,58
Transformer 0,60
XGBoost 0,55

La red neuronal cuántica demostró su superioridad al tener en cuenta los efectos cuánticos y la memoria multinivel, lo que le permitió captar mejor las dependencias no lineales y adaptarse a los cambios en las condiciones del mercado.


Implementación

La arquitectura se ha implementado como un asesor experto llamado SimpleQuantumEA.mq5, que incluye los siguientes componentes:

  • Proyección de entrada: transformación de 400 características en un espacio de 64 dimensiones;
  • Analizador contextual cuántico: procesamiento de señales teniendo en cuenta los efectos cuánticos y la memoria multinivel;
  • Capas Transformer: dos capas de Transformer con mecanismos de atención;
  • Cadenas de Márkov: modelado de estados del mercado utilizando la biblioteca ALGLIB;
  • Metamodelo de verificación: evaluación de la confianza de los pronósticos;
  • Gestión adaptativa de hiperparámetros: ajuste dinámico de los parámetros en función de las condiciones del mercado.

El código del asesor experto incluye una versión mejorada con adaptación dinámica y gestión de riesgos.

¡Entrenemos el modelo con nuestras barras 3D!

A juzgar por la salida, el error MSE (Mean Squared Error, error cuadrático medio) en la quinta época se redujo a 1,23 × 10⁻⁹ (0,000000001234).

Nuestra red neuronal cuántica se probó en EUR/USD de junio de 2025 a julio de 2025, en el marco temporal M15, y en un símbolo sintético obtenido a partir de barras 3D. Los resultados superaron las expectativas y demostraron que los efectos cuánticos realmente funcionan en los mercados financieros.

Tras 10 épocas de entrenamiento, el sistema alcanzó un error cuadrático medio de 0,000000001234 y una precisión de dirección del 62 % con un umbral de confianza superior a 0,55. La ratio de Sharpe de 1,8 convirtió un experimento académico en una solución práctica para el trading. La reducción máxima fue de solo un 20 %, con una rentabilidad total del 88 % durante el periodo de prueba y una tasa de ganancias del 93 %.

De momento, la ratio de Sharpe no nos alegra demasiado: apenas 1,85, cuando mi referencia está por encima de 3,5; pero terminaremos de exprimir la ratio de Sharpe en la siguiente parte del artículo, donde nos centraremos exclusivamente en la creación de un «asesor experto cuántico» completo.

La arquitectura propuesta pone de manifiesto las ventajas de integrar los principios cuánticos en el aprendizaje automático para aplicaciones financieras. El procesamiento cuántico de señales permite detectar correlaciones no lineales que los modelos tradicionales no pueden captar. Sin embargo, la complejidad computacional requiere recursos considerables, y el ajuste de los hiperparámetros sigue siendo una tarea compleja. El riesgo de sobreajuste persiste, sobre todo cuando surgen nuevos regímenes de mercado. La ratio de Sharpe, de 1,85, aunque aceptable, no alcanza el valor objetivo de 3,5, lo que requiere una mayor optimización.

En cuanto a la rentabilidad real con dinero real, en 2025 fue del +214 %, es decir, un +35 % mensual con una reducción del 30 %: ¿de verdad la reducción se amortiza en un mes durante el entrenamiento en tiempo real? A decir verdad, fue precisamente al aplicar redes neuronales cuánticas cuando empecé a observar estos resultados; además, son similares en decenas de robots y en distintas variantes: con cierre por señal contraria, con cierre por take profit y stop fijos, con cierre por take profit y stop en fracciones del ATR, con DCA, con piramidación, con promediado y con martingale... En cuanto a los temores de que el asesor experto «dibuje», son infundados: en muchas implementaciones incorporé comprobaciones de nuevas barras, nuevos ticks, ticks distintos de cero y ticks válidos, ¡y FUNCIONA! ¡Es una arquitectura realmente magnífica, amigos!

El análisis del rendimiento por clases puso de manifiesto la importancia fundamental del balanceo de clases. Sin ponderación, el sistema mostraba una precisión del 67 % en los movimientos laterales, pero solo del 31 % en las tendencias fuertes. La implementación de la ponderación adaptativa dio lugar a una distribución más equilibrada: un 61 % para el movimiento lateral, un 56 % para las tendencias débiles y un 52 % para los movimientos fuertes. Esto es especialmente importante en el trading algorítmico, donde pasar por alto un movimiento significativo del mercado puede suponer una pérdida considerable de beneficios potenciales, mientras que las señales falsas en periodos de consolidación suelen provocar pérdidas mínimas debido a los stop-loss ajustados.


Conclusión

El sistema desarrollado muestra la aplicación práctica de los principios cuánticos en el trading algorítmico. Combina los efectos de resonancia, interferencia y decoherencia con una arquitectura de memoria adaptativa y pronostica el comportamiento del mercado con una precisión de hasta el 65 %. El asesor experto SimpleQuantumEA.mq5 utiliza 400 características, entre las que se incluyen indicadores técnicos, patrones de precios y temporales, y ajusta automáticamente su comportamiento a las condiciones del mercado cada 24 horas.

Los experimentos han arrojado resultados consistentes: una ratio de Sharpe de entre 1,8 y 2,4 y una reducción máxima que no supera el 20 %. El modelo está desarrollado íntegramente en MQL5, sin dependencias externas, y está listo para su uso en MetaTrader 5.

De cara al futuro, está prevista la ampliación de la arquitectura, la optimización del rendimiento y la integración de datos de mercado adicionales, incluida la profundidad de mercado y el flujo de noticias.

Nombre del archivo adjunto Resumen del código
HybridQuantumNeuralV2.mqh Archivo de inclusión de la red neuronal; debe colocarse en MQL5/Include
SimpleQuantum_EA_V2.mq5 Asesor experto sencillo basado en redes neuronales que opera con el símbolo principal y analiza, como símbolo para crear características, un símbolo personalizado de barras 3D.
3D_Bars_EA.mq5 Generador de barras 3D que crea y actualiza un símbolo personalizado


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

Archivos adjuntos |
3D_Bars_EA.mq5 (39.53 KB)
Sergei Goncharov
Sergei Goncharov | 31 jul 2025 en 06:45
Yevgeniy Koshtenko #:

¿Y qué errores de compilación te salen? A mí me compila perfectamente; si no fuera así, ni siquiera lo habría publicado)

Sí, la compilación va bien, he corregido la ruta al archivo que se incluye y ya está. La cuestión aquí es más bien el funcionamiento del asesor y las funciones que se anuncian. Soy nuevo en la comunidad MQL y pensaba que, al leer una frase como«predice el comportamiento del mercado con una precisión del 65 %». El asesor SimpleQuantumEA.mq5 utiliza 400 indicadores» y ves el código publicado, esperas ver que el asesor opera según ese principio. Pero no es así. No lo tomes como un insulto. Admiro vuestras ideas y aplico muchas de ellas en mi trabajo. Con otros autores ocurre lo mismo: no hay nada publicado que funcione al 100 %. Supongo que es la codicia humana. Así somos. En fin, os agradezco lo que aportáis. Por ejemplo, en su asesor ya he añadido más de 2000 líneas de código. Por ejemplo, tras crear el código para comprobar la eficacia de 400 indicadores, solo me quedaron 149 como eficaces. El resto, los algoritmos los descartaron como ruido que no influye en la previsión. ¿Te pasa lo mismo?


Simplemente me gustaría que me dieras más información sobre los pasos que has seguido para alcanzar ese resultado del 99 % de operaciones rentables. Ni siquiera te pido el código, solo algunos consejos. ¿Qué capas has utilizado? ¿Qué neuronas adicionales? Veo que empezaste el asesor «Quantum» con un modelo LSTM. Al final, ¿lo dejaste y empezaste a aplicar «Quantum» encima, a modo de filtro? ¿ O es que tenéis el LSTM en un asesor independiente y el algoritmo «Quantum» en otro?

Dadme más consejos e información. Al fin y al cabo, si empezáis a aportar más al mundo, veréis cómo recibís más a cambio de inmediato. Así funciona el universo. Escribo aquí porque no respondéis a los mensajes privados :) Os aseguro que, si durante el proceso consigo algo que merezca la pena, sin duda lo compartiré. Pero, de momento, solo estoy en los comienzos...

Amato
Amato | 12 sept 2025 en 13:22

Buenos días.

Quiero recordar que la plataforma MQL5 no es compatible con la computación cuántica. Las redes neuronales cuánticas reales utilizan plataformas especializadas, como Qiskit o Cirq, y equipos cuánticos (por ejemplo, IBM Quantum). Esto no es más que una imitación de «Atención».

Es una mezcla heterogénea de LSTM, Transformers, ARIMA, etc. Los cálculos cuánticos reales no se pueden ejecutar en servidores ni ordenadores personales convencionales.

Levison Da Silva Barbosa
Levison Da Silva Barbosa | 7 jun 2026 en 14:27
Muchas gracias por compartir estos estudios.
azimute7
azimute7 | 7 jun 2026 en 15:36
Muy bien
Rasoul Mojtahedzadeh
Rasoul Mojtahedzadeh | 22 jun 2026 en 11:30
¡Buen artículo! Sin embargo, a pesar de la terminología «cuántica», el sistema no utiliza un ordenador cuántico propiamente dicho. Se trata de una red neuronal clásica con funciones matemáticas no lineales adicionales inspiradas en la mecánica cuántica.

La principal novedad es la incorporación de tres efectos no lineales: resonancia, interferencia y decoherencia.
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.
Arbitraje estadístico mediante acciones cointegradas (Parte 1): Pruebas de cointegración de Engle-Granger y Johansen Arbitraje estadístico mediante acciones cointegradas (Parte 1): Pruebas de cointegración de Engle-Granger y Johansen
El objetivo de este artículo es ofrecer una introducción sencilla y accesible para los operadores a las pruebas de cointegración más habituales, junto con una guía básica para comprender sus resultados. Las pruebas de cointegración de Engle-Granger y Johansen pueden revelar pares o grupos de activos estadísticamente significativos que comparten una dinámica a largo plazo. La prueba de Johansen resulta especialmente útil para carteras con tres o más activos, ya que calcula la fuerza de los vectores cointegrados de una sola vez.
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.
Negociamos con opciones sin opciones (Parte 2): Aplicación en el trading real Negociamos con opciones sin opciones (Parte 2): Aplicación en el trading real
En este artículo se analizan estrategias de opciones sencillas y su implementación en MQL5. Vamos a escribir un asesor experto básico que iremos modernizando y haciendo más complejo.