Cómo gestionar mejor la fase MARKET_UNCERTAIN en esta función?

 

Estoy creando un EA para un amigo basado en tamaños de mecha y fase de mercado usando ADX, ATR y 3 EMA, pero ahora me gustaría escuchar ideas sobre cómo llevar esto al siguiente nivel.

ENUM_MARKET_PHASE AnalyzeMarketPhase()
  {
// Return uncertain if no filters enabled
   if (!UseTrendFilter && !UseADXFilter && !UseVolatilityFilter)
       return MARKET_UNCERTAIN;

   double adxValue = 0 , atrValue = 0 ;
   double fastMA[], slowMA[], longMA[];
   ArraySetAsSeries (fastMA, true );
   ArraySetAsSeries (slowMA, true );
   ArraySetAsSeries (longMA, true );

// Get ADX value
   if (UseADXFilter)
     {
       double adxBuffer[];
       ArraySetAsSeries (adxBuffer, true );

       if ( CopyBuffer (adx_Handle, 0 , 0 , 3 , adxBuffer) < 3 )
         return MARKET_UNCERTAIN;

       // Now index 0 is truly the CURRENT bar
      adxValue = adxBuffer[ 0 ];

      
       bool adxRising = adxBuffer[ 0 ] > adxBuffer[ 1 ] && adxBuffer[ 1 ] > adxBuffer[ 2 ];
     }

// Get ATR value
   if (UseVolatilityFilter)
     {
       double atrBuffer[];
       ArraySetAsSeries (atrBuffer, true ); 
       if ( CopyBuffer (atr_Handle, 0 , 0 , 3 , atrBuffer) < 3 )
         return MARKET_UNCERTAIN;
      atrValue = atrBuffer[ 0 ] / pipValue;
     }

// Get MA values
   if (UseTrendFilter)
     {
       if ( CopyBuffer (fastMA_Handle, 0 , 0 , 3 , fastMA) < 3 ||
         CopyBuffer (slowMA_Handle, 0 , 0 , 3 , slowMA) < 3 ||
         CopyBuffer (longMA_Handle, 0 , 0 , 3 , longMA) < 3 )
         return MARKET_UNCERTAIN;
     }

// Check for extreme volatility first
   if (UseVolatilityFilter && atrValue > ATR_MaxMultiplier * 50 )
       return MARKET_HIGH_VOLATILITY;

//DX logic with proper gap handling
   if (UseADXFilter)
     {
       // Strong trend: ADX > ADX_MinTrend (typically 25)
       if (adxValue > ADX_MinTrend)
        {
         return DetermineTrendDirection(fastMA, slowMA, longMA);
        }
       // Transition zone: Between ADX_MaxRange and ADX_MinTrend (20-25)
       else
         if (adxValue >= ADX_MaxRange && adxValue <= ADX_MinTrend)
           {
             // In transition zone - check if trend is developing or weakening
             double adxBuffer[];
             if ( CopyBuffer (adx_Handle, 0 , 0 , 3 , adxBuffer) >= 3 )
              {
               bool adxRising = adxBuffer[ 0 ] > adxBuffer[ 1 ] && adxBuffer[ 1 ] > adxBuffer[ 2 ];
               bool adxFalling = adxBuffer[ 0 ] < adxBuffer[ 1 ] && adxBuffer[ 1 ] < adxBuffer[ 2 ];

               if (adxRising)
                 {
                   // ADX rising in transition zone - potential trend developing
                   return DetermineTrendDirection(fastMA, slowMA, longMA);
                 }
               else
                   if (adxFalling)
                    {
                     // ADX falling in transition zone - trend weakening
                     return MARKET_SIDEWAYS;
                    }
                   else
                    {
                     // ADX flat in transition zone - uncertain
                     return MARKET_UNCERTAIN;
                    }
              }
             return MARKET_UNCERTAIN;
           }
         // Clear ranging: ADX < ADX_MaxRange (typically 20)
         else
             if (adxValue < ADX_MaxRange)
              {
               return MARKET_SIDEWAYS;
              }
     }
   else
       if (UseTrendFilter)
        {
         // If ADX filter disabled but trend filter enabled
         return DetermineTrendDirection(fastMA, slowMA, longMA);
        }

   return MARKET_UNCERTAIN;
  }
 

Tres observaciones sobre la función, de mayor a menor impacto:


1. Estás leyendo la vela en formación (CopyBuffer con inicio 0 y luego buffer[0]). El ADX y las EMAs de la vela 0 cambian con cada tick, así que la fase puede ser TRENDING en un tick y SIDEWAYS al siguiente sin que haya pasado nada. Para clasificar fase de mercado usa velas cerradas: copia desde el índice 1 (CopyBuffer(handle, 0, 1, 3, buffer)) y evalúa una vez por vela nueva, no en cada tick. Solo con eso la fase deja de parpadear.


2. Agrega histéresis. Aunque uses velas cerradas, un umbral duro (ADX 25) hace que el estado oscile cuando el valor ronda el borde. La solución estándar es exigir persistencia: no cambies de fase hasta que la nueva se confirme durante 2-3 velas seguidas, o usa umbrales distintos para entrar y salir (entras a TRENDING sobre 25 y no vuelves a SIDEWAYS hasta bajo 20 — la zona 20-25 que ya tienes definida sirve exactamente para eso).


3. Separa "sin datos" de "mercado dudoso". Hoy devuelves MARKET_UNCERTAIN tanto cuando CopyBuffer falla como cuando el ADX está plano en la zona de transición. Son cosas distintas: la primera es un estado técnico transitorio (reintenta el próximo tick y no toques nada), la segunda es información de mercado legítima (quédate fuera o baja el riesgo). Un valor aparte tipo MARKET_NO_DATA evita que un fallo de copia se interprete como señal.


Detalle menor: el adxRising que calculas en el primer bloque queda sin usar (lo vuelves a calcular más abajo); puedes copiar el buffer del ADX una sola vez y reutilizarlo.


Y para saber si la clasificación "funciona": píntala. Colorea el fondo del gráfico histórico por fase (rectángulos o un buffer de color) y en segundos ves si tus fases coinciden con lo que un ojo humano llamaría tendencia o rango, antes de conectarle dinero real.