English Русский 中文 Deutsch 日本語 Português
preview
Ejemplo de toma de beneficios optimizada automáticamente y parámetros de indicadores con SMA y EMA

Ejemplo de toma de beneficios optimizada automáticamente y parámetros de indicadores con SMA y EMA

MetaTrader 5Ejemplos | 17 febrero 2025, 12:34
353 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introducción

En el mundo en constante evolución del trading algorítmico, la innovación es clave para mantenerse a la vanguardia. Hoy, nos complace presentar un sofisticado Asesor Experto (EA) que combina el aprendizaje automático con el análisis técnico tradicional para navegar en los mercados de divisas. Este EA aprovecha un modelo ONNX junto con indicadores técnicos cuidadosamente optimizados para tomar decisiones comerciales en los mercados de divisas.

El enfoque del EA es multifacético y utiliza la predicción de precios de un modelo de aprendizaje automático, técnicas de seguimiento de tendencias y optimización de parámetros adaptativos. Está diseñado para operar principalmente en acciones #AAPL, aunque tiene la flexibilidad de adaptarse a otros instrumentos. Con características como tamaño de lote dinámico, trailing stops y ajuste automático a las condiciones del mercado, este EA representa una combinación de tecnología de vanguardia y principios comerciales probados por el tiempo.

Explicación de los indicadores utilizados:

  1. Media móvil simple (Simple Moving Average, SMA): el EA utiliza un promedio móvil simple con un período optimizado de forma adaptativa. La SMA ayuda a identificar la dirección general de la tendencia y se utiliza junto con el precio y otros indicadores para generar señales comerciales.
  2. Media móvil exponencial (Exponential Moving Average, EMA): también se emplea una media móvil exponencial, con su período optimizado dinámicamente. La EMA responde más rápidamente a los cambios de precios recientes que la SMA, lo que proporciona una perspectiva diferente sobre la dirección de la tendencia.
  3. Rango verdadero promedio (Average True Range, ATR): si bien no se calcula explícitamente en el código, el EA utiliza cálculos basados en ATR para establecer los niveles de stop loss y take profit. Esto permite ajustar el tamaño de las posiciones a la volatilidad y gestionar el riesgo.
  4. Modelo de aprendizaje automático: el EA incorpora un modelo ONNX (Open Neural Network Exchange) para la predicción de precios. Este modelo toma una serie de datos de precios recientes e intenta predecir el próximo movimiento de precios, añadiendo un elemento predictivo a la estrategia de negociación.

Estos indicadores se combinan de forma sofisticada y sus parámetros se optimizan dinámicamente en función de las condiciones recientes del mercado. El EA también incluye funciones como trailing stops y cálculos de expectativas morales para gestionar eficazmente las posiciones abiertas.

La combinación de estos indicadores, junto con el componente de aprendizaje automático, permite al EA adaptarse a las condiciones cambiantes del mercado e identificar potencialmente oportunidades de negociación en diversos estados del mercado.


Desglose del código

1. Configuración inicial e inclusiones

El código comienza con la información sobre los derechos de autor e incluye las bibliotecas necesarias, como Trade.mqh.

#include <Trade\Trade.mqh>

2. Variables y parámetros globales:

  • Se definen los parámetros del modelo ONNX, incluido el tamaño de la muestra y los controladores.
  • Se declaran los parámetros de entrada para los indicadores (SMA, EMA, ATR) y las operaciones comerciales.
  • Se definen enumeraciones y constantes para el movimiento de precios y números mágicos.

#resource "/Files/model.EURUSD.D1.1_1_2024.onnx" as uchar ExtModel[];
input group "----- Indicators Parameters -----"
int SMA_Period = 20;
int EMA_Period = 50;

input double StopLossATR = 1.5;
input double TakeProfitATR = 3.0;
input int OptimizationDays = 1;        // Hours between optimizations
input int LookbackPeriod = 7;         // Hours loockback periods
input int MinSMAPeriod = 5;            // Period min para SMA
input int MaxSMAPeriod = 50;           // Periodo max para SMA
input int MinEMAPeriod = 5;            // Periodo min para EMA
input int MaxEMAPeriod = 50;           // Periodo max para EMA
#define MAGIC_SE 12321
datetime lastOptimizationTime = 0;
double optimizedTakeProfit = 0.0;//InpTakeProfit;
double optimizedStopLoss = 0.0;//InpStopLoss;
double InpTakeProfit1 ;
double InpStopLoss1;

3. Función de inicialización (OnInit):

  • Configura el modelo ONNX desde un búfer.
  • Inicializa indicadores técnicos (SMA, EMA).
  • Llama funciones para optimizar indicadores y parámetros comerciales.

int OnInit()
  {
//--- create a model from static buffer
   ExtHandle = OnnxCreateFromBuffer(ExtModel, ONNX_DEFAULT);
   if(ExtHandle == INVALID_HANDLE)
     {
      Print("OnnxCreateFromBuffer error ", GetLastError());
      return(INIT_FAILED);
     }

//--- set input and output shapes
   const long input_shape[] = {1, SAMPLE_SIZE, 1};
   if(!OnnxSetInputShape(ExtHandle, ONNX_DEFAULT, input_shape))
     {
      Print("OnnxSetInputShape error ", GetLastError());
      return(INIT_FAILED);
     }
   const long output_shape[] = {1, 1};
   if(!OnnxSetOutputShape(ExtHandle, 0, output_shape))
     {
      Print("OnnxSetOutputShape error ", GetLastError());
      return(INIT_FAILED);
     }

   SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE); // Ensure correct period
   if(SMAHandle == INVALID_HANDLE)
     {
      Print("Error initializing SMA indicator: ", GetLastError());
      return INIT_FAILED;
     }
   EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE); // Ensure correct index
   if(EMAHandle == INVALID_HANDLE)
     {
      Print("Error initializing EMA indicator: ", GetLastError());
      return INIT_FAILED;
     }
   trade.SetDeviationInPoints(Slippage);

   trade.SetExpertMagicNumber(MAGIC_SE);
   OptimizeIndicators();
   OptimizeParameters();
   return(INIT_SUCCEEDED);
  }

4. Función de desinicialización (OnDeinit):

Libera controladores para el modelo ONNX y los indicadores.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(ExtHandle != INVALID_HANDLE)
     {
      OnnxRelease(ExtHandle);
      ExtHandle = INVALID_HANDLE;
     }

   IndicatorRelease(SMAHandle);
   IndicatorRelease(EMAHandle);
  }

5. Lógica comercial principal (OnTick):

  • Comprueba si el mercado está cerrado.
  • Optimiza periódicamente los indicadores y parámetros comerciales.
  • Actualiza la lógica del trailing stop.
  • Predice el movimiento de precios utilizando el modelo ONNX.
  • Comprueba las condiciones de posiciones abiertas/cerradas según predicciones e indicadores.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

   if(IsMarketClosed())  // Verificar si el mercado está cerrado
     {
      return; // Si el mercado está cerrado, no hacer nada
     }

   static datetime lastOptimizationTime2 = 0;

   if(TimeCurrent() - lastOptimizationTime2 >= OptimizationDays * PeriodSeconds(PERIOD_H1))
     {
      OptimizeIndicators();
      lastOptimizationTime2 = TimeCurrent();

      // Actualizar los indicadores con los nuevos períodos
      IndicatorRelease(SMAHandle);
      IndicatorRelease(EMAHandle);
      SMAHandle = iMA(_Symbol, _Period, SMA_Period, 0, MODE_SMA, PRICE_CLOSE);
      EMAHandle = iMA(_Symbol, _Period, EMA_Period, 0, MODE_EMA, PRICE_CLOSE);
     }

//--- Optimización cada 2 días
   if(TimeCurrent() - lastOptimizationTime >= PeriodSeconds(PERIOD_H1) * HoursAnalyze)
     {
      OptimizeParameters();
      lastOptimizationTime = TimeCurrent();
     }

//---

   if(NewBarTS()==true)//gather statistics and launch trailing stop
     {
      double open=iOpen(_Symbol,TFTS,1);
      CalcLvl(up,(int)MathRound((iHigh(_Symbol,TFTS,1)-open)/_Point));
      CalcLvl(dn,(int)MathRound((open-iLow(_Symbol,TFTS,1))/_Point));
      buy_sl=CalcSL(dn);
      buy_tp=CalcTP(up);
      sell_sl=CalcSL(up);
      sell_tp=CalcTP(dn);

      if(TypeTS==Simple)//simple trailing stop
         SimpleTS();

      if(TypeTS==MoralExp)//Moral expectation
         METS();
      if(TypeTS==None)//None TS
         return;
     }

   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);

   if(bid==SLNeutral || bid<=SLBuy || (SLSell>0 && bid>=SLSell))
     {
      for(int i=PositionsTotal()-1; i>=0; i--)
        {
         ulong ticket=PositionGetTicket(i);
         if(PositionSelectByTicket(ticket)==true)
            trade.PositionClose(ticket);
        }
     }
//---
//--- check new day
   if(TimeCurrent() >= ExtNextDay)
     {
      GetMinMax();
      ExtNextDay = TimeCurrent();
      ExtNextDay -= ExtNextDay % PeriodSeconds(PERIOD_D1);
      ExtNextDay += PeriodSeconds(PERIOD_D1);
     }

//--- check new bar
   if(TimeCurrent() < ExtNextBar)
      return;
   ExtNextBar = TimeCurrent();
   ExtNextBar -= ExtNextBar % PeriodSeconds();
   ExtNextBar += PeriodSeconds();

//--- check min and max
   float close = (float)iClose(_Symbol, _Period, 0);
   if(ExtMin > close)
      ExtMin = close;
   if(ExtMax < close)
      ExtMax = close;


   double sma[], ema[];//, willr[];
   CopyBuffer(SMAHandle, 0, 0, 1, sma);
   CopyBuffer(EMAHandle, 0, 0, 1, ema);
//CopyBuffer(WillRHandle, 0, 0, 1, willr);

//--- predict next price
   PredictPrice();

//--- check trading according to prediction and indicators
   if(ExtPredictedClass >= 0)
     {
      if(PositionSelect(_Symbol))
         CheckForClose(sma[0], ema[0]);//, willr[0]);
      else
         CheckForOpen(sma[0], ema[0]);//, willr[0]);
     }
  }

6. Funciones comerciales:

  • CheckForOpen: determina si se debe abrir una posición de compra o venta según predicciones y señales de indicadores.
  • CheckForClose: comprueba si las posiciones actuales deben cerrarse según las predicciones.

//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(double sma, double ema)//, double willr)
  {
   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied = CopyRates(_Symbol,0,0,1,rates);
   if(copied <= 0)
     {
      Print("Error copying rates: ", GetLastError());
      return;
     }
   double Close[1];
   Close[0]=rates[0].close;
   double close = Close[0];

   ENUM_ORDER_TYPE signal = WRONG_VALUE;
   Print("ExtPredictedClass ",ExtPredictedClass);

//--- check signals
   if(ExtPredictedClass == 2)//PRICE_DOWN)
     {
      Print("ExtPredictedClass Sell ",ExtPredictedClass);
      Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr);
      // Venta
      if((close < sma && close < ema))// || willr > -20)
        {
         signal = ORDER_TYPE_SELL;
         Print("Order Sell detected");
        }
     }
   else
      if(ExtPredictedClass == 0)//PRICE_UP)
        {
         Print("ExtPredictedClass Buy ",ExtPredictedClass);
         Print("close ",close, " sma ",sma, " ema ", ema);//, " willr ", willr);
         // Compra
         if((close > sma && close > ema))// || willr < -80)
           {
            signal = ORDER_TYPE_BUY;
            Print("Order Buy detected");
           }
        }

//--- open position if possible according to signal
   if(signal != WRONG_VALUE && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print("Proceding open order");
      double price, sl=0, tp=0;
      double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

      MqlTradeRequest request = {};
      MqlTradeResult result = {};

      request.action = TRADE_ACTION_DEAL;
      request.symbol = _Symbol;
      request.deviation = Slippage;
      request.magic = MAGIC_SE;
      request.type_filling = ORDER_FILLING_FOK;
      //request.comment = "AKWr";

      double lotaje;
      if(signal == ORDER_TYPE_SELL)
        {
         price = bid;
         Print("Price: ",price);
         if(inp_lot_type == LOT_TYPE_FIX)
            lotaje=inp_lot_fix ;
         else
            lotaje=get_lot(price);
         if(!CheckVolumeValue(lotaje))
            return;
         if(!InpUseStops && ATR)
           {
            sl = NormalizeDouble(bid + StopLossATR * ATRValue, _Digits);
            tp = NormalizeDouble(ask - TakeProfitATR * ATRValue, _Digits);
            if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_SELL))
              {
               Print("No hay suficiente margen para abrir la posición");
               return;
              }
            request.type = ORDER_TYPE_SELL;
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            request.volume = lotaje;
            request.sl = sl;
            request.tp = tp;
            request.comment = "SEW Opened sell order";
           }
         if(!InpUseStops && ATR)
           {
            sl = 0;
            tp = 0;
           }
         else
           {
            InpTakeProfit1 =optimizedTakeProfit;
            InpStopLoss1= optimizedStopLoss;
            sl = NormalizeDouble(bid + InpStopLoss1*_Point, _Digits);
            tp = NormalizeDouble(ask - InpTakeProfit1*_Point, _Digits);

           }
        }
      else
        {
         price = ask;
         Print("Price: ",price);
         if(inp_lot_type == LOT_TYPE_FIX)
            lotaje=inp_lot_fix ;
         else
            lotaje=get_lot(price);
         if(!CheckVolumeValue(lotaje))
            return;
         if(!InpUseStops)
           {
            sl = NormalizeDouble(ask - StopLossATR * ATRValue, _Digits);
            tp = NormalizeDouble(bid + TakeProfitATR * ATRValue, _Digits);
            if(!CheckMoneyForTrade(_Symbol, lotaje,ORDER_TYPE_BUY))
              {
               Print("No hay suficiente margen para abrir la posición");
               return;
              }
            request.type = ORDER_TYPE_BUY;
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            request.volume = lotaje;
            request.sl = sl;
            request.tp = tp;
            request.comment = "SEW Opened buy order";
           }
         if(!InpUseStops && ATR)
           {
            sl = 0;
            tp = 0;
           }
         else
           {
            InpTakeProfit1 =optimizedTakeProfit;
            InpStopLoss1= optimizedStopLoss;
            sl = NormalizeDouble(ask - InpStopLoss1*_Point, _Digits);
            tp = NormalizeDouble(bid + InpTakeProfit1*_Point, _Digits);
           }
        }
      Print("No InpUseStops used");

      //ExtTrade.PositionOpen(_Symbol, signal, lotaje, price, sl, tp);

      if(!CheckMoneyForTrade(_Symbol, lotaje, (ENUM_ORDER_TYPE)signal))
        {
         Print("No hay suficiente margen para abrir la posición");
         return;
        }
      Print("Volume ", lotaje);
      request.type = signal;
      request.price = price;//SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      request.volume = lotaje;
      request.sl = sl;
      request.tp = tp;
      request.comment = "SEW";
      if(!OrderSend(request, result))
        {
         Print("Error opening the order: ", GetLastError());
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(double sma, double ema)//, double willr)
  {
   if(InpUseStops)
      return;

   bool bsignal = false;

//--- position already selected before
   long type = PositionGetInteger(POSITION_TYPE);

//--- check signals
   if(type == POSITION_TYPE_BUY && ExtPredictedClass == 2)//PRICE_DOWN)
      bsignal = true;
   if(type == POSITION_TYPE_SELL && ExtPredictedClass == 0)//PRICE_UP)
      bsignal = true;

//--- close position if possible
   if(bsignal && TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      ExtTrade.PositionClose(_Symbol);
      CheckForOpen(sma, ema);//, willr);
     }
  }

7. Predicción de precios (PredictPrice):

Utiliza el modelo ONNX para predecir el movimiento futuro de precios.

//+------------------------------------------------------------------+
//| Predict next price                                               |
//+------------------------------------------------------------------+
void PredictPrice(void)
  {
   static vectorf output_data(1);
   static vectorf x_norm(SAMPLE_SIZE);

   if(ExtMin >= ExtMax)
     {
      Print("ExtMin >= ExtMax");
      ExtPredictedClass = -1;
      return;
     }

   if(!x_norm.CopyRates(_Symbol, _Period, COPY_RATES_CLOSE, 1, SAMPLE_SIZE))
     {
      Print("CopyRates ", x_norm.Size());
      ExtPredictedClass = -1;
      return;
     }
   float last_close = x_norm[SAMPLE_SIZE - 1];
   x_norm -= ExtMin;
   x_norm /= (ExtMax - ExtMin);

   if(!OnnxRun(ExtHandle, ONNX_NO_CONVERSION, x_norm, output_data))
     {
      Print("OnnxRun");
      ExtPredictedClass = -1;
      return;
     }

   float predicted = output_data[0] * (ExtMax - ExtMin) + ExtMin;
   float delta = last_close - predicted;
   if(fabs(delta) <= 0.00001)
      ExtPredictedClass = PRICE_SAME;
   else
      if(delta < 0)
         ExtPredictedClass = PRICE_UP;
      else
         ExtPredictedClass = PRICE_DOWN;

// Debugging output
   Print("Predicted price: ", predicted, " Delta: ", delta, " Predicted Class: ", ExtPredictedClass);
  }

8. Funciones del Trailing Stop:

Varias funciones (AllTS, METS, SimpleTS) implementan diferentes estrategias de trailing stop.

Todo explicado en este artículo: El stop dinámico en el trading - Artículos MQL5

9. Funciones de optimización:

  • OptimizeParameters: prueba diferentes valores de take profit y stop loss para encontrar configuraciones óptimas.
  • OptimizeIndicators: encuentra los mejores períodos para los indicadores SMA y EMA.

void OptimizeParameters()
  {
   double bestTakeProfit = InpTakeProfit1;
   double bestStopLoss = InpStopLoss1;
   double bestPerformance = -DBL_MAX;

   for(int tp = 65; tp <= 500; tp += 5) // rango de TakeProfit
     {
      for(int sl = 65; sl <= 500; sl += 5) // rango de StopLoss
        {
         double performance = TestStrategy(tp, sl);
         if(performance > bestPerformance)
           {
            bestPerformance = performance;
            bestTakeProfit = tp;
            bestStopLoss = sl;
            //Print("Best Take Profit",bestTakeProfit);
            //Print("Best Stop Loss",bestStopLoss);
           }
        }
     }

   optimizedTakeProfit = bestTakeProfit;
   optimizedStopLoss = bestStopLoss;

   Print("Optimized TakeProfit: ", optimizedTakeProfit);
   Print("Optimized StopLoss: ", optimizedStopLoss);
  }
void OptimizeIndicators()
  {
   datetime startTime = TimeCurrent() - LookbackPeriod * PeriodSeconds(PERIOD_H1);
   datetime endTime = TimeCurrent();

   int bestSMAPeriod = SMA_Period;
   int bestEMAPeriod = EMA_Period;
   double bestPerformance = -DBL_MAX;

   for(int smaPeriod = MinSMAPeriod; smaPeriod <= MaxSMAPeriod; smaPeriod++)
     {
      for(int emaPeriod = MinEMAPeriod; emaPeriod <= MaxEMAPeriod; emaPeriod++)
        {
         double performance = TestIndicatorPerformance(smaPeriod, emaPeriod, startTime, endTime);

         if(performance > bestPerformance)
           {
            bestPerformance = performance;
            bestSMAPeriod = smaPeriod;
            bestEMAPeriod = emaPeriod;
           }
        }
     }

   SMA_Period = bestSMAPeriod;
   EMA_Period = bestEMAPeriod;

   Print("Optimized SMA Period: ", SMA_Period);
   Print("Optimized EMA Period: ", EMA_Period);
  }

10. Funciones de utilidad y administración del dinero:

Funciones para el cálculo del tamaño del lote, verificación de volumen, verificación de cierre del mercado, incluye funciones para verificar si hay suficiente dinero para las operaciones y para normalizar los tamaños de los lotes, etc.

bool IsMarketClosed()
  {
   datetime currentTime = TimeCurrent();
   MqlDateTime tm;
   TimeToStruct(currentTime, tm);

   int dayOfWeek = tm.day_of_week;
   int hour = tm.hour;

// Verifica si es fin de semana
   if(dayOfWeek <= Sunday || dayOfWeek >= Saturday)
     {
      return true;
     }

// Verifica si está fuera del horario habitual de mercado (ejemplo: 21:00 a 21:59 UTC)
   if(hour >= after || hour < before)  // Ajusta estos valores según el horario del mercado
     {
      return true;
     }

   return false;
  }


//+------------------------------------------------------------------+
//| Check the correctness of the order volume                        |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume)//,string &description)
  {
//--- minimal allowed volume for trade operations
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      //description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- maximal allowed volume of trade operations
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      //description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- get minimal step of volume changing
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      //description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",
      //volume_step,ratio*volume_step);
      return(false);
     }
//description="Correct volume value";
   return(true);
  }
//+------------------------------------------------------------------+
bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type)
  {
//--- Getting the opening price
   MqlTick mqltick;
   SymbolInfoTick(symb,mqltick);
   double price=mqltick.ask;
   if(type==ORDER_TYPE_SELL)
      price=mqltick.bid;
//--- values of the required and free margin
   double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
//--- call of the checking function
   if(!OrderCalcMargin(type,symb,lots,price,margin))
     {
      //--- something went wrong, report and return false
      Print("Error in ",__FUNCTION__," code=",GetLastError());
      return(false);
     }
//--- if there are insufficient funds to perform the operation
   if(margin>free_margin)
     {
      //--- report the error and return false
      Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError());
      return(false);
     }
//--- checking successful
   return(true);
  }
double get_lot(double price)
  {
   if(inp_lot_type==LOT_TYPE_FIX)
      return(normalize_lot(inp_lot_fix));
   double one_lot_margin;
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,one_lot_margin))
      return(inp_lot_fix);
   return(normalize_lot((AccountInfoDouble(ACCOUNT_BALANCE)*(inp_lot_risk/100))/ one_lot_margin));
  }
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
double normalize_lot(double lt)
  {
   double lot_step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lt = MathFloor(lt / lot_step) * lot_step;
   double lot_minimum = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   lt = MathMax(lt, lot_minimum);
   return(lt);
  }

Características principales:

  1. Utiliza aprendizaje automático (modelo ONNX) para la predicción de precios.
  2. Combina indicadores técnicos (SMA, EMA) con predicciones ML (Machine Learning) para decisiones comerciales.
  3. Implementa múltiples estrategias de trailing stop.
  4. Incluye optimización periódica de los parámetros del indicador y configuraciones comerciales.
  5. Tiene gestión de riesgos incorporada (dimensionamiento de lotes, verificación de dinero).
  6. Considera el horario del mercado para realizar operaciones.

Este asesor experto (EA) es bastante sofisticado y combina el análisis técnico tradicional con el aprendizaje automático para el trading de divisas. También incluye varias funciones de gestión y optimización de riesgos para adaptarse a las condiciones cambiantes del mercado.

Entradas (Inputs)

Gráfico AAPL

Prueba retrospectiva de AAPL

Este análisis indica que la estrategia de trading automatizado demostró rentabilidad con un sólido índice Sharpe de 6,21. Sin embargo, tiene una alta caída que sugiere la necesidad de una gestión cuidadosa del riesgo. La capacidad de la estrategia para lograr ganancias consistentes, como lo muestra la curva de capital, refleja su potencial para aplicaciones comerciales en el mundo real. Las optimizaciones futuras podrían centrarse en reducir las caídas y mejorar el factor de recuperación para mejorar el rendimiento general.


Resumen

Este artículo presenta un innovador Asesor Experto (EA) para trading algorítmico en el mercado Forex, diseñado específicamente para operar con Apple Inc. Acciones de Apple (#AAPL). El EA representa una combinación sofisticada de aprendizaje automático y análisis técnico tradicional, con el objetivo de navegar por las complejidades de los mercados de divisas con precisión y adaptabilidad.

En el núcleo de este EA se encuentra un modelo ONNX (Open Neural Network Exchange), que actúa como componente de aprendizaje automático. Este modelo tiene la tarea de predecir los movimientos de precios basándose en datos recientes del mercado, añadiendo un elemento prospectivo a la estrategia comercial. El EA combina estas predicciones con indicadores técnicos establecidos, a saber, la media móvil simple (SMA) y la media móvil exponencial (EMA), para generar señales comerciales.

El enfoque del EA es multifacético e incorpora varias características clave:

  1. Optimización dinámica: tanto los indicadores técnicos como los parámetros comerciales están sujetos a una optimización periódica. Esto permite que el EA se adapte a las condiciones cambiantes del mercado, mejorando potencialmente su rendimiento a lo largo del tiempo.
  2. Gestión de riesgos adaptativa: el EA emplea un tamaño de lote dinámico y utiliza cálculos de rango verdadero promedio (ATR) para establecer niveles de stop loss y take profit. Este enfoque tiene como objetivo ajustar el tamaño de las posiciones y la exposición al riesgo en función de la volatilidad actual del mercado.
  3. Múltiples estrategias de trailing stop: el EA implementa varios métodos de trailing stop, lo que permite una gestión flexible de las posiciones abiertas y potencialmente maximizar las ganancias mientras se minimizan las pérdidas.
  4. Conocimiento de las condiciones del mercado: el sistema está diseñado para tener en cuenta los horarios y las condiciones del mercado, garantizando que las operaciones solo se ejecuten cuando sea apropiado.

El artículo proporciona un desglose detallado de la estructura del código de EA y explica sus componentes clave:

  1. Inicialización: Esta fase configura el modelo ONNX y los indicadores técnicos, preparando el EA para su funcionamiento.
  2. Lógica comercial principal: la funcionalidad principal que decide cuándo abrir o cerrar posiciones en función de las señales combinadas del modelo de aprendizaje automático y los indicadores técnicos.
  3. Predicción de precios: utiliza el modelo ONNX para pronosticar movimientos de precios futuros.
  4. Funciones de optimización: ajusta periódicamente los parámetros del indicador y las configuraciones comerciales para mantener la efectividad en condiciones variables del mercado.
  5. Gestión de riesgos: incluye funciones para el cálculo del tamaño del lote, la gestión del dinero y la verificación de las condiciones del mercado.

El rendimiento del EA se evaluó mediante pruebas retrospectivas sobre datos de acciones de AAPL. Los resultados mostraron una rentabilidad prometedora con un índice de Sharpe de 6,21, lo que indica fuertes retornos ajustados al riesgo. Sin embargo, el análisis también reveló cifras de reducción relativamente altas, lo que sugiere áreas para posibles mejoras en la gestión de riesgos.


Conclusión

Bueno, el Asesor Experto (Expert Advisor, EA) que tenemos hoy es un gran salto. Utiliza una combinación de tecnología inteligente (aprendizaje automático) y métodos probados (análisis técnico) para brindar a los operadores decisiones invaluables exclusivas para miembros sobre cómo invertir en acciones de AAPL y otros símbolos.

El EA combinó un modelo ONNX para predecir precios con indicadores técnicos optimizados. Esta combinación implica que puede responder tanto a cambios de precios instantáneos como a movimientos más lentos hacia desarrollos a más largo plazo.

Uno de los aspectos atractivos de este EA es que tiene un sistema de gestión de riesgos cohesivo. Por ejemplo, utiliza tamaños de lote dinámicos (cambia el tamaño de tus operaciones según las condiciones del mercado), niveles de stop loss y take profit basados en ATR (impone límites a lo que puedes perder si las cosas salen mal o a tus ganancias cuando están a tu favor), así como múltiples estrategias de trailing stop con respecto al cambio de precio. Estas herramientas están diseñadas para proteger tu dinero sin que te lo quiten de manera oculta o injusta.

Otra gran cosa acerca de este EA es que actualiza sus indicadores y parámetros comerciales con bastante regularidad. Esto le permitirá seguir el ritmo del mercado cambiante, un componente muy importante para seguir siendo eficaz a lo largo del tiempo.

Sin embargo, los resultados siguen siendo algo decepcionantes a partir del análisis retrospectivo que muestra cómo habría funcionado el EA en el pasado. Aunque los resultados parecen buenos en términos de ganancias y gestión de riesgos, también mostraron algunas caídas importantes (una gran caída en el valor), lo que indica que la gestión de riesgos podría reforzarse. Las futuras versiones del EA pueden incluir mejores protecciones o transacciones más cautelosas durante épocas muy volátiles.

Aunque fue creado para negociar acciones de AAPL, los principios que lo rigen pueden aplicarse fácilmente a otros mercados financieros. Tal flexibilidad hace que valga la pena utilizar este instrumento tanto en el trading actual como modelo para futuros sistemas algorítmicos.

Se trata de un EA de trading automatizado complejo y muy prometedor: una combinación de tecnología de vanguardia y métodos tradicionales, fuerte en gestión de riesgos y adaptable a las condiciones cambiantes del mercado. Sin embargo, al igual que cualquier otra herramienta comercial, requiere monitoreo regular, actualización y pruebas en escenarios del mundo real para garantizar su correcto funcionamiento a lo largo del tiempo.

Por último, si bien este EA parece tener mucho potencial pero se necesita más trabajo en él y mucha optimización, es importante recordar que el trading siempre implica riesgo y el rendimiento pasado no garantiza el éxito futuro. Si está considerando utilizar este o cualquier sistema automatizado, asegúrese de comprender los riesgos, haga su tarea e idealmente pruébelo en un entorno simulado antes de usar dinero real.

Espero que disfrutes leyendo este artículo tanto como yo disfruto escribiéndolo, espero que puedas hacer que este EA sea mucho mejor y obtengas buenos resultados. Este es un buen ejemplo de cómo implementar la optimización automática con stops y con indicadores. Una vez más, espero que les haya gustado esto. ¡Salud!

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

Archivos adjuntos |
SE_v9.mq5 (80.02 KB)
Desarrollo de un sistema de repetición (Parte 75): Un nuevo Chart Trade (II) Desarrollo de un sistema de repetición (Parte 75): Un nuevo Chart Trade (II)
En este artículo explicaré gran parte de la clase C_ChartFloatingRAD. Esta es la encargada de hacer que Chart Trade funcione. Sin embargo, no terminaré la explicación aquí. La finalizaré en el próximo artículo, ya que el contenido de este es bastante denso y necesita ser comprendido a fondo. El contenido expuesto aquí tiene como único objetivo la enseñanza. En ningún caso debe considerarse como una aplicación cuya finalidad sea distinta a la enseñanza y el estudio de los conceptos mostrados.
Desarrollo de un sistema de repetición (Parte 74): Un nuevo Chart Trade (I) Desarrollo de un sistema de repetición (Parte 74): Un nuevo Chart Trade (I)
En este artículo, modificaremos el último código visto en esta secuencia sobre Chart Trade. Estos cambios son necesarios para adaptar el código al modelo actual del sistema de repetición/simulador. El contenido expuesto aquí tiene como único propósito ser didáctico. En ningún caso debe considerarse una aplicación destinada a otros fines que no sean el aprendizaje y el estudio de los conceptos mostrados.
Desarrollo de un sistema de repetición (Parte 76): Un nuevo Chart Trade (III) Desarrollo de un sistema de repetición (Parte 76): Un nuevo Chart Trade (III)
En este artículo, veremos cómo funciona el código faltante del artículo anterior, DispatchMessage. Aquí se introducirá el tema del próximo artículo. Por esta razón, es importante entender el funcionamiento de este procedimiento antes de pasar al siguiente tema. El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación cuya finalidad no sea el aprendizaje y el estudio de los conceptos presentados.
Características del Wizard MQL5 que debe conocer (Parte 31): Selección de la función de pérdida Características del Wizard MQL5 que debe conocer (Parte 31): Selección de la función de pérdida
La función de pérdida es la métrica clave de los algoritmos de aprendizaje automático que proporciona información al proceso de formación cuantificando el rendimiento de un conjunto determinado de parámetros en comparación con el objetivo previsto. Exploramos los distintos formatos de esta función en una clase de asistente personalizada MQL5.