
Cómo integrar los conceptos de dinero inteligente (Smart Money Concepts, SMC) junto con el indicador RSI en un EA
Introducción
En el vertiginoso mundo del comercio de divisas, tener un sistema comercial confiable y eficiente es crucial para el éxito. El trading en general tiene muchos términos, conceptos y estrategias. A menudo, puede resultar abrumador, especialmente para los nuevos operadores que todavía están tratando de encontrar su lugar en la industria del trading. El concepto de dinero inteligente (SMC) es uno de los conceptos de tendencia en el trading de divisas, pero a veces puede resultar difícil para los nuevos operadores o para cualquier persona utilizar los conceptos de dinero inteligente en sus operaciones.
Para resolver este problema, debería existir una herramienta sólida para automatizar las decisiones comerciales basadas en la estructura del mercado y la acción del precio. La solución es combinar el concepto de dinero inteligente (ruptura de estructura) con el popular indicador del índice de fuerza relativa (Relative Strength Index, RSI). Esta combinación proporciona una ventaja estratégica al aprovechar tanto la acción del precio como el análisis del impulso, lo que mejora la precisión de las entradas y salidas comerciales, con el objetivo de optimizar el rendimiento comercial.
La idea del ejemplo del Asesor Experto
La idea y funcionalidad de este ejemplo de Asesor Experto es que el experto detectará los mínimos y máximos de oscilación, ya que algunos conceptos de dinero inteligente utilizan las oscilaciones. El indicador RSI seguirá utilizando la conversión tradicional del nivel 70 para un mercado sobrecomprado y el nivel 30 para un mercado sobrevendido y el período será 8. Cuando el precio del mercado esté por encima del máximo detectado previamente, eso indicará la ruptura de la estructura al alza. De manera similar, cuando el precio del mercado está por debajo del mínimo detectado previamente, eso indicará una ruptura de la estructura a la baja.
Ahora desarrollemos el ejemplo del Asesor Experto
El EA tiene como objetivo abrir órdenes de compra y venta en función de las condiciones del mercado y los niveles de RSI. En concreto:
- Identifica máximos y mínimos oscilatorios en el mercado.
- Comprueba si el mercado está por encima del máximo anterior (para una señal de venta) o por debajo del mínimo anterior (para una señal de compra).
- Luego confirma la señal con niveles RSI.
Dicho esto, básicamente el Asesor Experto buscará una ruptura de la estructura o una ruptura de oscilaciones anteriores (máximo/mínimo) y luego, si el valor RSI está dentro de las configuraciones especificadas, se ejecutará una orden de mercado (BUY/SELL).
Desglose del código
1. Propiedades e 'Includes'
#property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include <Trade/Trade.mqh>
Estas líneas definen las propiedades del EA e incluyen la biblioteca comercial necesaria para ejecutar operaciones.
2. Variables globales y entradas
long MagicNumber = 76543; double lotsize = 0.01; input int RSIperiod = 8; input int RSIlevels = 70; int stopLoss = 200; int takeProfit = 500; bool closeSignal = false;
- MagicNumber: Un identificador único para las operaciones del EA.
- Lotsize: El volumen de cada operación.
- RSIperiod: Periodo para los cálculos del RSI.
- RSIlevels: Nivel umbral para el RSI.
- Stoploss and takeProfit: Niveles SL y TP en puntos.
- CloseSignal: Bandera para el cierre de posiciones basado en la señal opuesta en comparación con la posición que está actualmente abierta.
3. Variables del RSI
int handle; double buffer[]; MqlTick currentTick; CTrade trade; datetime openTimeBuy = 0; datetime openTimeSell = 0;
- Handle: Identificador para el indicador RSI.
- Buffer: Matriz para almacenar los valores RSI.
- currentTick: Estructura para almacenar los precios actuales del mercado.
- Trade: Este es el objeto de las operaciones comerciales.
- openTimeBuy y openTimeSell: Las marcas de tiempo de las últimas señales y operaciones de compra y venta.
4. Función de inicialización
int OnInit() { if (RSIperiod <= 1) { Alert("RSI period <= 1"); return INIT_PARAMETERS_INCORRECT; } if (RSIlevels >= 100 || RSIlevels <= 50) { Alert("RSI level >= 100 or <= 50"); return INIT_PARAMETERS_INCORRECT; } trade.SetExpertMagicNumber(MagicNumber); handle = iRSI(_Symbol, PERIOD_CURRENT, RSIperiod, PRICE_CLOSE); if (handle == INVALID_HANDLE) { Alert("Failed to create indicator handle"); return INIT_FAILED; } ArraySetAsSeries(buffer, true); return INIT_SUCCEEDED; }
- Valida el período y los niveles del RSI.
- Establece el número mágico para la identificación comercial.
- Crea un identificador RSI.
- Establece el búfer como una serie para almacenar valores RSI en orden cronológico inverso.
5. Función de desinicialización
void OnDeinit(const int reason) { if (handle != INVALID_HANDLE) { IndicatorRelease(handle); } }
Libera el identificador del indicador RSI cuando el EA es eliminado.
6. Función OnTick
Como todos sabemos, la función OnTick contiene la lógica central para detectar señales y ejecutar operaciones.
void OnTick() { static bool isNewBar = false; int newbar = iBars(_Symbol, _Period); static int prevBars = newbar; if (prevBars == newbar) { isNewBar = false; } else if (prevBars != newbar) { isNewBar = true; prevBars = newbar; }
En primer lugar, como la función OnTick se ejecuta en cada tick, tenemos que asegurarnos de que cuando detectamos una señal o ejecutamos una operación lo hacemos una vez por barra. Logramos esto declarando una variable booleana estática isNewBar. La establecemos en false inicialmente, y luego declaramos una variable int newBar a la que se le asigna la función iBars para que podamos hacer un seguimiento de cada barra de vela.
- static bool isNewBar: Controla si se ha formado una nueva barra (vela).
- int newbar = iBars(_Symbol, _Period): Obtiene el número actual de barras del gráfico.
- static int prevBars = newbar: Inicializa el recuento de barras anterior.
- El bloque if-else comprueba si la cuenta de barras ha cambiado, indicando una nueva barra. Si se ha formado una nueva barra, 'isNewBar' se establece en 'true', de lo contrario, es 'false'.
const int length = 10; int right_index, left_index; int curr_bar = length; bool isSwingHigh = true, isSwingLow = true; static double swing_H = -1.0, swing_L = -1.0;
A continuación, tenemos que establecer las variables para detectar los máximos y mínimos de oscilación:
- const int length = 10: Define el rango de detección de los máximos y mínimos de oscilación.
- int right_index, left_index: Índices de las barras situadas a la derecha y a la izquierda de la barra actual.
- int curr_bar = length: Establece el índice de la barra actual.
- bool isSwingHigh = true, isSwingLow = true: Estas son banderas para determinar si una barra es un swing alto o un swing bajo.
- static double swing_H = -1.0, swing_L = -1.0: Almacena los últimos valores de oscilación alta y baja detectados.
double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
Las variables son de tipo double y la variable 'Ask' se utiliza para obtener el precio ASK actual del mercado, y la variable 'Bid' se utiliza para obtener el precio BID actual del mercado:
- double Ask: Obtiene el precio de venta actual.
- double Bid: Obtiene el precio de oferta actual.
- NormalizeDouble: Redondea el precio al número correcto de decimales.
if (isNewBar) { for (int a = 1; a <= length; a++) { right_index = curr_bar - a; left_index = curr_bar + a; if ((high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index))) { isSwingHigh = false; } if ((low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index))) { isSwingLow = false; } } if (isSwingHigh) { swing_H = high(curr_bar); Print("We do have a swing high at: ", curr_bar, " H: ", high(curr_bar)); drawswing(TimeToString(time(curr_bar)), time(curr_bar), high(curr_bar), 32, clrBlue, -1); } if (isSwingLow) { swing_L = low(curr_bar); Print("We do have a swing low at: ", curr_bar, " L: ", low(curr_bar)); drawswing(TimeToString(time(curr_bar)), time(curr_bar), low(curr_bar), 32, clrRed, +1); } }
A continuación, procedemos a buscar máximos y mínimos de oscilación, pero antes, si se detecta una nueva barra, la función comprueba las barras circundantes dentro de la length (longitud) definida para identificar si hay máximos o mínimos de oscilación. La variable length es para definir un rango de velas para buscar swings, para cada barra dentro del rango, la función compara el máximo/mínimo de la barra actual con las barras adyacentes.
Si el máximo de la barra actual no es superior al de las barras circundantes, entonces no es un máximo de oscilación. Si el mínimo de la barra actual no es inferior al de las barras circundantes, no se trata de un mínimo oscilatorio. Dado que se cumplen todas esas condiciones entonces se confirma un swing high o un swing low, entonces se almacena el valor respectivo, y luego se dibuja un marcador en el gráfico utilizando la función drawswing.
int values = CopyBuffer(handle, 0, 0, 2, buffer); if (values != 2) { Print("Failed to get indicator values"); return; } Comment("Buffer[0]: ", buffer[0], "\nBuffer[1]: ", buffer[1]);
- copyBuffer(handle, 0, 0, 2, buffer): Copia los últimos valores de RSI en la memoria intermedia.
- Si la función no consigue recuperar los valores RSI, se sale.
- Los valores RSI se mostrarán como un comentario en el gráfico.
int cntBuy = 0, cntSell = 0; if (!countOpenPositions(cntBuy, cntSell)) { return; }
'countOpenPositions(cntBuy, cntSell)': Los valores RSI se mostrarán como un comentario en el gráfico.
if (swing_H > 0 && Ask > swing_H && buffer[0] >= 70) { Print("Sell Signal: Market is above previous high and RSI >= 70"); int swing_H_index = 0; for (int i = 0; i <= length * 2 + 1000; i++) { if (high(i) == swing_H) { swing_H_index = i; break; } } drawBreakLevels(TimeToString(time(0)), time(swing_H_index), high(swing_H_index), time(0), high(swing_H_index), clrBlue, -1); if (cntSell == 0) { double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); double sl = Bid + stopLoss * _Point; double tp = Bid - takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, lotsize, currentTick.bid, sl, tp, "RSI EA"); } swing_H = -1.0; return; }
Como he explicado anteriormente, buscaremos una señal de venta. La lógica es que el precio de venta debe estar por encima del máximo anterior. Además, el valor RSI debe ser algo mayor o igual al nivel 70. Si se cumplen las condiciones, marca el máximo oscilatorio y dibuja un nivel de ruptura en el gráfico. Si no hay posiciones de venta abiertas, se procede a abrir una posición de venta, esta operación de venta se abrirá con el nivel de Stop Loss y Take Profit calculado, y luego se restablecerá el valor máximo del swing.
if (swing_L > 0 && Bid < swing_L && buffer[0] <= 30) { Print("Buy Signal: Market is below previous low and RSI <= 30"); int swing_L_index = 0; for (int i = 0; i <= length * 2 + 1000; i++) { if (low(i) == swing_L) { swing_L_index = i; break; } } drawBreakLevels(TimeToString(time(0)), time(swing_L_index), low(swing_L_index), time(0), low(swing_L_index), clrRed, +1); if (cntBuy == 0) { double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); double sl = Ask - stopLoss * _Point; double tp = Ask + takeProfit * _Point; trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, lotsize, currentTick.ask, sl, tp, "RSI EA"); } swing_L = -1.0; return; } }
Para la señal de compra se aplica la misma lógica opuesta: si el precio de oferta está por debajo del mínimo anterior y el valor RSI es menor o igual al nivel 30, entonces técnicamente la lógica de compra está en orden y se cumple la condición. Cuando se cumple la condición, marca el mínimo oscilatorio y luego dibuja un nivel de ruptura en el gráfico. Y si no hay posiciones de compra abiertas, procederá a abrir una nueva operación de compra con los niveles de stop loss y take profit calculados y, por último, restablecerá el valor mínimo oscilatorio.
Lo que estamos tratando de lograr es lo siguiente:
Una operación de venta con todas las condiciones cumplidas:
Una operación de compra con todas las condiciones cumplidas:
El resumen de la función OnTick:
El experto realiza las siguientes acciones clave en cada tick del mercado
- Detecta nuevas barras: Primero verifica si tenemos una nueva barra de velas que podría haberse formado desde el último tic, y también realiza un seguimiento de todas las velas.
- Identifica los máximos y mínimos de oscilación: Luego identifica puntos de oscilación en el mercado para utilizarlos como niveles de referencia para más adelante cuando el precio del mercado esté por encima del máximo o por debajo del mínimo.
- Recupera valores RSI: Obtiene los últimos valores RSI para la confirmación de la señal.
- Cuenta las posiciones abiertas: Realiza un seguimiento de las posiciones de compra y venta abiertas actuales.
- Genera señales comerciales: Utiliza los puntos de oscilación, que son el máximo y el mínimo, y los niveles RSI para generar señales de compra o venta.
- Ejecuta transacciones: Abre nuevas posiciones basadas en las señales generadas si se cumplen todas las condiciones.
Funciones personalizadas para valores altos, bajos y de tiempo
double high(int index){ return (iHigh(_Symbol, _Period, index)); } double low(int index){ return (iLow(_Symbol, _Period, index)); } datetime time(int index){ return (iTime(_Symbol, _Period, index)); }
La función high (int index) devuelve el precio alto de la barra en el index (índice) especificado. Toma index como parámetro de tipo int. La función MQL5 incorporada iHigh(_symbol,_Period,index) se utiliza para obtener el precio máximo de la barra en index para el símbolo y período actuales. Luego seguido de low (int index) esta función devuelve el precio bajo de la barra en el index especificado, y también toma index como parámetro que es de tipo int, y luego tenemos iLow(_symbol, _Period, index). También es una función incorporada en MQL5 que obtiene el precio bajo de la barra en index para el símbolo actual. Por último, tenemos time (int index) esta función devuelve el tiempo de la barra en el índice especificado, iTime(_symbol, _Period, index) también es una función incorporada en MQL5 para obtener el tiempo de la barra en index para el símbolo y periodo actual el tipo de dato de iTime es de tipo datetime.
La función para dibujar puntos oscilantes
void drawswing(string objName, datetime time, double price, int arrCode, color clr, int direction){ if(ObjectFind(0, objName) < 0){ ObjectCreate(0, objName, OBJ_ARROW, 0, time, price); ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, arrCode); ObjectSetInteger(0, objName, OBJPROP_COLOR, clr); ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10); if(direction > 0){ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_TOP);} if(direction < 0){ObjectSetInteger(0, objName, OBJPROP_ANCHOR, ANCHOR_BOTTOM);} string text = ""; string Descr = objName + text; ObjectCreate(0, Descr, OBJ_TEXT, 0, time, price); ObjectSetInteger(0, Descr, OBJPROP_COLOR, clr); ObjectSetInteger(0, Descr, OBJPROP_FONTSIZE, 10); if(direction > 0){ ObjectSetString(0, Descr, OBJPROP_TEXT," "+text); ObjectSetInteger(0, Descr, OBJPROP_ANCHOR, ANCHOR_LEFT_UPPER); } if(direction < 0){ ObjectSetString(0, Descr, OBJPROP_TEXT," "+text); ObjectSetInteger(0, Descr, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); } } ChartRedraw(0); }
Esta función crea marcadores visuales para los puntos de oscilación (máximos y mínimos) en el gráfico. Toma los siguientes parámetros:
- ObjName: Es el nombre del objeto a crear.
- Time: La hora a la que se ha producido o detectado la oscilación.
- Price: El precio al que se formó la oscilación.
- ArrCode: Código de flechas para la representación visual.
- Clr: Color de la flecha.
- Direction: Dirección de la oscilación (positiva para la alta, negativa para la baja).
Funcionalidad
1. Creación de objetos:
- ObjectFind(0, objName): Comprueba si ya existe un objeto con el nombre dado.
- ObjectCreate(0, objName, OBJ-ARROW, 0, time, price): Crea un objeto flecha a la hora y precio especificados.
- ObjectSetInteger(0, objName, OBJPROP-ARROWCODE, arrCode): Establece el código de flecha.
- ObjectSetInteger(0, objName, OBJPROP-COLOR, clr): Establece el color de la flecha.
- ObjectSetInteger(0, objName, OBJPROP-FONTSIZE, 10): Establece el tamaño de la fuente.
2. Manipulación de la dirección:
- Establece la posición del ancla en función de la dirección.
- OBJPROP-ANCHOR: Establece la posición del punto de anclaje de la flecha.
3. Creación de objetos de texto:
- Crea un objeto de texto asociado a la flecha para mostrar información adicional.
- Establece el color, el tamaño y el punto de anclaje del texto en función de la dirección.
4. Actualización del gráfico:
- ChartRedraw(0): Redibuja el gráfico para reflejar los cambios.
Función para trazar niveles de ruptura
void drawBreakLevels(string objName, datetime time1, double price1, datetime time2, double price2, color clr, int direction){ if(ObjectFind(0, objName) < 0){ ObjectCreate(0, objName, OBJ_ARROWED_LINE, 0, time1, price1, time2, price2); ObjectSetInteger(0, objName, OBJPROP_TIME, 0, time1); ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, price1); ObjectSetInteger(0, objName, OBJPROP_TIME, 1, time2); ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, price2); ObjectSetInteger(0, objName, OBJPROP_COLOR, clr); ObjectSetInteger(0, objName, OBJPROP_WIDTH, 2); string text = "Break"; string Descr = objName + text; ObjectCreate(0, Descr, OBJ_TEXT, 0, time2, price2); ObjectSetInteger(0, Descr, OBJPROP_COLOR, clr); ObjectSetInteger(0, Descr, OBJPROP_FONTSIZE, 10); if(direction > 0){ ObjectSetString(0, Descr, OBJPROP_TEXT,text+" "); ObjectSetInteger(0, Descr, OBJPROP_ANCHOR, ANCHOR_RIGHT_UPPER); } if(direction < 0){ ObjectSetString(0, Descr, OBJPROP_TEXT,text+" "); ObjectSetInteger(0, Descr, OBJPROP_ANCHOR, ANCHOR_RIGHT_LOWER); } } ChartRedraw(0); }
Esta función crea las representaciones visuales para la ruptura de los niveles de precios que son los puntos de oscilación que habrían sido detectados previamente en el gráfico, tiene los siguientes parámetros:
- objName: Nombre del objeto a crear.
- time1, time2: La hora de inicio es la hora en que se formó la oscilación, y la hora final es la hora en que se produce la ruptura.
- price1, price2: El precio inicial (price1) es el precio del máximo o mínimo oscilante y price2 es el precio al que se produce la ruptura del máximo o mínimo oscilante.
- Clr: Color de la flecha.
- Direction: Dirección para el texto de anclaje.
Funcionalidad
1. Creación de objetos:
- ObjectFind(0, objName) < 0: Comprueba si ya existe un objeto con un nombre dado.
- ObjectCreate(0, objName, OBJ_ARROWED_LINE, 0, time1, price1, time2, price2): Crea el objeto flecha a las horas y precios especificados.
- Establece los tiempos y precios para los puntos de inicio y final de la línea de flecha.
- ObjectSetInteger(0, objName, OBJPROP-COLOR, clr): Establece el color de la línea.
- ObjectSetInteger(0, objName, OBJPROP-WIDTH, 2): Establece el ancho de línea.
2. Creación de objetos de texto:
- Crea un objeto de texto asociado a la línea para mostrar información adicional.
- Establece el color, el tamaño de la fuente y el punto de anclaje del texto en función de la dirección.
3. Actualización del gráfico:
- chartRedraw(0): Redibuja el gráfico para reflejar los cambios.
Conclusión
En resumen, las funciones personalizadas mejoran la experiencia de negociación, ya que proporciona un acceso cómodo, hay un acceso simplificado a los valores máximos, mínimos y temporales de las barras. Acoplando el indicador RSI con los conceptos del SMC, podemos visualizar los indicadores y confirmar que el EA sigue las instrucciones. Cuando la función dibuja la línea de flecha en el gráfico, marca puntos significativos, que son los puntos de oscilación (máximos y mínimos). Además, podemos observar los niveles de ruptura. También disponemos de la actualización dinámica, que garantiza que el gráfico esté actualizado en tiempo real con los últimos marcadores e indicadores, ayudando al análisis visual y a la toma de decisiones.
A través de esta completa guía, se ha proporcionado una comprensión completa de cómo integrar el concepto SMC con el indicador RSI a la estructura y funcionalidad de cualquier Asesor Experto. Siguiendo la explicación paso a paso, los lectores deberían tener ahora una comprensión clara del funcionamiento del Asesor Experto SMC_RSI, desde la inicialización de variables hasta la ejecución de operaciones basadas en señales calculadas. Tanto si es un operador experimentado como si es un principiante, esta información exhaustiva le proporcionará los conocimientos necesarios para utilizar y personalizar estas potentes herramientas de forma eficaz en sus operaciones.
Aquí están los resultados de la prueba de nuevo a continuación, puedo decir que la propia EA todavía necesitan algún tipo de optimización para obtener mayor factor de ganancia, ahora por debajo de los resultados de la prueba de nuevo:
Y a continuación podemos ver la representación visual de la curva de equidad, sólo he probado durante 12 meses, así que quién puede decir con precisión cómo se desempeñaría si tal vez probado por un período de 12 años.
Referencias
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/15030





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso