Discusión sobre el artículo "De Python a MQL5: Un viaje hacia los sistemas de trading inspirados en la cuántica"

 

Artículo publicado De Python a MQL5: Un viaje hacia los sistemas de trading inspirados en la cuántica:

El artículo analiza el desarrollo de un sistema de negociación inspirado en la cuántica, pasando de un prototipo en Python a una implementación en MQL5 para la negociación en el mundo real. El sistema utiliza principios de computación cuántica, como la superposición y el entrelazamiento, para analizar los estados del mercado, aunque funciona en ordenadores clásicos utilizando simuladores cuánticos. Las características principales incluyen un sistema de tres qubits para analizar ocho estados del mercado simultáneamente, períodos de revisión de 24 horas y siete indicadores técnicos para el análisis del mercado. Aunque los índices de precisión puedan parecer modestos, proporcionan una ventaja significativa cuando se combinan con estrategias adecuadas de gestión de riesgos.

En esta exhaustiva investigación sobre los sistemas de trading inspirados en la cuántica, realizaremos un recorrido que conecta las ideas teóricas de la computación cuántica con aplicaciones reales en el mundo del trading. Comenzando con conceptos básicos de computación cuántica y terminando con una implementación real en MQL5, este tutorial está diseñado para guiarle a través de todo el proceso de desarrollo. Analizaremos cómo el trading puede beneficiarse del uso de conceptos cuánticos, describiremos nuestro enfoque de desarrollo desde el prototipo en Python hasta la integración de MQL5, y presentaremos datos reales de rendimiento e implementaciones de código.

Este artículo explora la aplicación de conceptos inspirados en la cuántica en los sistemas de trading, tendiendo un puente entre la computación cuántica teórica y su implementación práctica en MQL5. Te presentaremos los principios cuánticos esenciales y te guiaremos desde la creación de prototipos en Python hasta la integración en MQL5, con datos de rendimiento reales.

A diferencia del trading tradicional, que se basa en la toma de decisiones binarias, los modelos de trading inspirados en la cuántica aprovechan comportamientos del mercado similares a los fenómenos cuánticos: múltiples estados concurrentes, interconexiones y cambios bruscos de estado. Mediante el uso de simuladores cuánticos como Qiskit, podemos aplicar algoritmos inspirados en la cuántica en ordenadores clásicos para gestionar la incertidumbre del mercado y generar información predictiva.


Autor: Javier Santiago Gaston De Iriarte Cabrera

 
Por favor, no utilice el ajuste #2 (dejé la optimización en marcha y fue una estrategia perdedora). Por favor haga optimizaciones y busque el mejor ajuste (y termine el EA).
 

No entiendo mucho de computación cuántica, pero hace tiempo que me interesa el tema.

Envié una pregunta a la IA sobre esta implementación concreta —no con ánimo de criticar, sino porque tenía la idea de probarla en la práctica— y recibí una respuesta detallada y bien argumentada, con un análisis de los errores y una implementación corregida y mejorada. Adjunto la conversación (en ruso) en el archivo, así como la versión final del código fuente (dentro hay varias, a elegir).

double SimulatePureQuantumCircuit(double &features[])
{
    const int num_states = (int)MathPow(2.0, (double)NUM_QUBITS);
    
    // 1. Creamos e inicializamos el vector de estado (evolución determinista)
    double state[];  
    ArrayResize(state, num_states);
    ArrayInitialize(state, 0.0);
    state[0] = 1.0; // Estado |000...0>

    double next_state[];
    ArrayResize(next_state, num_states);

    // --- [Evolución: Válvulas de giro Ry] ---
    for(int qubit = 0; qubit < NUM_QUBITS; qubit++)
    {
        const int feature_idx = qubit % ArraySize(features);
        const double angle = MathMax(MathMin(features[feature_idx] * M_PI, M_PI), -M_PI);
        const double cos_a = MathCos(angle / 2.0);
        const double sin_a = MathSin(angle / 2.0);

        ArrayCopy(next_state, state);
        for(int i = 0; i < num_states; i++)
        {
            if((i & (1 << qubit)) == 0)
            {
                const int i1 = i | (1 << qubit);
                next_state[i]  = cos_a * state[i] - sin_a * state[i1];
                next_state[i1] = sin_a * state[i] + cos_a * state[i1];
            }
        }
        ArrayCopy(state, next_state);
    }

    // --- [Evolución: La confusión de CZ] ---
    for(int i = 0; i < NUM_QUBITS - 1; i++)
    {
        for(int j = i + 1; j < NUM_QUBITS; j++)
        {
            const double phase = M_PI / 2.0 * (features[i] * features[j]);
            if(MathAbs(phase) > M_PI / 4.0) 
            {
                for(int k = 0; k < num_states; k++)
                {
                    if(((k & (1 << i)) != 0) && ((k & (1 << j)) != 0))
                        state[k] = -state[k]; 
                }
            }
        }
    }

    // --- [Cálculo de las probabilidades verdaderas] ---
    double exact_probs[];
    ArrayResize(exact_probs, num_states);
    for(int i = 0; i < num_states; i++)
    {
        // El cuadrado de la amplitud es la probabilidad teórica pura según la ley de Born
        exact_probs[i] = state[i] * state[i]; 
    }

    // 2. Pasamos directamente las probabilidades ideales a la ponderación de los votos
    const double prediction = GetWeightedVote(exact_probs);
    
    return prediction; 
}

No he realizado ninguna comprobación de los nuevos códigos fuente, ni he rebatido los argumentos de la IA.

¿Quizás alguien más versado en el tema pueda valorarlo?

Archivos adjuntos:
 

A modo de complemento, una variante más «compleja» que tiene en cuenta la conexión entre los rasgos —que deben transmitirse por pares— y que, por lo tanto, los divide en dos partes diferentes (real e imaginaria) de un mismo qubit.

// Configuración general (adapta estos valores a tu sistema de trading)
#define  NUM_QUBITS 3          // Número de qubits (tamaño del vector de estados = 2^NUM_QUBITS)
#define  MIN_CONFIDENCE 0.1    // Umbral de confianza mínima para filtrar el flat

//+------------------------------------------------------------------+
//| Cálculo rápido de los bits activados (método de Brian Kernighan)      |
//+------------------------------------------------------------------+
int CountBits(int n)
{
    int count = 0;
    while(n > 0)
    {
        n &= (n - 1); 
        count++;
    }
    return count;
}

//+------------------------------------------------------------------+
//| Cálculo de la esperanza matemática (Expectation Value)         |
//+------------------------------------------------------------------+
double GetWeightedVote(const double &state_probs[])
{
    double expected_value = 0.0;
    double total_weight = 0.0;
    const int size = ArraySize(state_probs);

    for(int i = 0; i < size; i++)
    {
        const double vote_weight = state_probs[i];
        if(vote_weight <= 0.000001) continue; 

        const int num_ones = CountBits(i);
        const double state_value = (2.0 * (double)num_ones / (double)NUM_QUBITS) - 1.0;

        expected_value += state_value * vote_weight;
        total_weight += vote_weight;
    }

    if(total_weight <= 0.0001) return 0.0;
    
    double final_prediction = expected_value / total_weight;
    if(final_prediction > 1.0)  final_prediction = 1.0;
    if(final_prediction < -1.0) final_prediction = -1.0;

    return final_prediction;
}

//+------------------------------------------------------------------+
//| Simulador de un circuito cuántico complejo determinista            |
//| features[][0] - parámetro de amplitud, features[][1] - parámetro de fase   |
//+------------------------------------------------------------------+
double SimulateQuantumCircuitComplex(double &features_matrix[][])
{
    const int num_states = (int)MathPow(2.0, (double)NUM_QUBITS);
    const int num_features = ArrayRange(features_matrix, 0);
    
    if(num_features == 0)
    {
        Print(«Error: ¡matriz de características vacía!»);
        return 0.0;
    }

    // Vector de estados cuánticos basado en el tipo integrado «complex»
    complex state[];  
    ArrayResize(state, num_states);
    
    // Inicialización del sistema en estado rígido |000...0>
    for(int i = 0; i < num_states; i++) 
    { 
        state[i].real = 0.0; 
        state[i].imag = 0.0; 
    }
    state[0].real = 1.0; // La amplitud del estado fundamental es igual a 1

    // Búfer temporal para la actualización atómica (simultánea) del vector
    complex next_state[];
    ArrayResize(next_state, num_states);

    // --- 1. Codificación compleja de los caracteres (U-Gate: Ry + Rz) ---
    for(int qubit = 0; qubit < NUM_QUBITS; qubit++)
    {
        const int feat_idx = qubit % num_features;
        
        // Limitamos los ángulos de entrada al intervalo [-PI; PI]
        const double theta = MathMax(MathMin(features_matrix[feat_idx][0] * M_PI, M_PI), -M_PI); // Para Ry
        const double phi   = MathMax(MathMin(features_matrix[feat_idx][1] * M_PI, M_PI), -M_PI); // Para Rz

        const double cos_t = MathCos(theta / 2.0);
        const double sin_t = MathSin(theta / 2.0);
        
        // Exponente de Euler para el desplazamiento de fase: e^(i*phi) = cos(phi) + i*sin(phi)
        complex e_phase;
        e_phase.real = MathCos(phi);
        e_phase.imag = MathSin(phi);

        ArrayCopy(next_state, state);

        for(int i = 0; i < num_states; i++)
        {
            if((i & (1 << qubit)) == 0)
            {
                const int i1 = i | (1 << qubit);
                
                // Matriz compleja del ventilador rotativo U(theta, phi):
                // [   cos(theta/2)      ,  -sin(theta/2)           ]
                // [ sin(theta/2)*e^(i*phi),   cos(theta/2)*e^(i*phi) ]
                
                // Cálculo para el bit de destino = 0
                next_state[i].real = cos_t * state[i].real - sin_t * state[i1].real;
                next_state[i].imag = cos_t * state[i].imag - sin_t * state[i1].imag;

                // Cálculo para el bit de destino = 1 (teniendo en cuenta el desplazamiento de fase e^i*phi)
                complex temp_i1;
                temp_i1.real = sin_t * state[i].real + cos_t * state[i1].real;
                temp_i1.imag = sin_t * state[i].imag + cos_t * state[i1].imag;
                
                // Aplicamos el desplazamiento de fase mediante la multiplicación compleja nativa de MQL5
                next_state[i1] = temp_i1 * e_phase;
            }
        }
        ArrayCopy(state, next_state);
    }

    // --- 2. Entrelazamiento cuántico integral honesto (Controlled-Phase Gate) ---
    for(int i = 0; i < NUM_QUBITS - 1; i++)
    {
        for(int j = i + 1; j < NUM_QUBITS; j++)
        {
            const int idx_i = i % num_features;
            const int idx_j = j % num_features;
            
            // Confundimos las fases complejas de dos parámetros relacionados entre sí
            const double cross_phase = M_PI / 2.0 * (features_matrix[idx_i][0] * features_matrix[idx_j][1]);
            
            complex cz_gate;
            cz_gate.real = MathCos(cross_phase);
            cz_gate.imag = MathSin(cross_phase);

            for(int k = 0; k < num_states; k++)
            {
                // Si ambos qubits se encuentran en el estado 1, giramos gradualmente su fase compleja común
                if(((k & (1 << i)) != 0) && ((k & (1 << j)) != 0))
                {
                    state[k] = state[k] * cz_gate; 
                }
            }
        }
    }

    // --- 3. Cálculo de las probabilidades teóricas exactas (paso determinista) ---
    double exact_probs[];
    ArrayResize(exact_probs, num_states);
    
    for(int i = 0; i < num_states; i++)
    {
        // Según la ley de Born, la probabilidad P = |psi|² = real² + imag²
        exact_probs[i] = (state[i].real * state[i].real) + (state[i].imag * state[i].imag);
    }

    // --- 4. Obtención de la previsión final ---
    const double prediction = GetWeightedVote(exact_probs);
    const double confidence = MathAbs(prediction);

    if(confidence < MIN_CONFIDENCE)
    {
        return 0.0; // El mercado se encuentra en una fase de estancamiento/incertidumbre desde el punto de vista de la cadena cuántica
    }

    return prediction;
}
La forma más cómoda de transmitir parámetros relacionados es a través de la matriz features[][] con una segunda dimensión igual a 2, donde:
  • features[i][0] — característica de amplitud (define el ángulo de rotación real (Ry)).
  • features[i][1]: característica de fase (define el ángulo de rotación complejo (Rz)).
Por ejemplo, el código de llamada puede transmitir pares como: [Variación del precio; Variación del volumen] o [Posición del RSI; Volatilidad actual del ATR] .