
Integración de Smart Money Concepts (SMC), Order Blocks (OB) y Fibonacci para entradas óptimas
Introducción
Los conceptos de dinero inteligente (Smart Money Concepts, SMC) y los bloques de órdenes (Order Blocks, OB) son áreas críticas en el gráfico donde los operadores institucionales suelen ejecutar grandes órdenes de compra o venta. Estas zonas a menudo marcan el origen de movimientos de precios significativos, lo que las hace vitales para los operadores que buscan alinear sus estrategias con la actividad del mercado institucional. Comprender cómo estos niveles clave influyen en la acción del precio puede proporcionar a los operadores minoristas una visión más profunda de la dinámica subyacente del mercado, lo que les permite anticipar movimientos de alta probabilidad.
Cuando se combinan con herramientas como el retroceso de Fibonacci, los operadores pueden refinar aún más sus estrategias de entrada. El retroceso de Fibonacci identifica niveles de retroceso potenciales entre un máximo y un mínimo recientes, y ofrece una forma de medir hasta dónde puede retroceder el precio antes de continuar su tendencia. Este enfoque ayuda a los operadores a identificar puntos de entrada óptimos al alinear el flujo de órdenes institucionales con áreas de interés del mercado, mejorando la precisión de sus operaciones.
Lógica
Bloque de orden alcista:
Un bloque de orden alcista se puede identificar en los gráficos cuando una vela bajista es seguida por una vela alcista que envuelve a la vela bajista anterior, lo que marca el comienzo de un impulso alcista significativo. Para que la formación califique como un Bloque de Orden Alcista, las velas que siguen a la vela bajista deben consistir en al menos dos velas alcistas o una serie de velas alcistas. El enfoque correcto para operar con un bloque de orden alcista es esperar a que el precio retroceda y vuelva a sumergirse en la zona identificada del bloque de orden alcista, momento en el que se puede ejecutar una posición de compra.
Retroceso de Fibonacci alcista:
Para encontrar una entrada comercial óptima después de identificar un bloque de orden alcista, se utiliza la herramienta de retroceso de Fibonacci. Una vez que se ubica el bloque de orden alcista, el comerciante busca el máximo y el mínimo recientes asociados con el bloque de orden. Luego, el retroceso de Fibonacci se dibuja desde el mínimo hasta el máximo del gráfico. El retroceso ayuda a confirmar que el bloque de órdenes alcistas se encuentra en o por debajo del nivel del 61,8%, una zona de retroceso clave que indica una posible oportunidad de compra en alineación con el flujo de órdenes institucionales.
Bloque de orden bajista:
Un bloque de orden bajista se identifica cuando una vela alcista es seguida por una vela bajista que envuelve a la vela alcista anterior, lo que indica el inicio de un impulso bajista significativo. Para que el patrón se considere un bloque de orden bajista, al menos dos velas bajistas o una serie de velas bajistas deben seguir a la vela alcista. La forma correcta de operar con un bloque de orden bajista es esperar a que el precio regrese y volver a probar la zona del bloque de orden bajista, donde luego se puede ejecutar una posición de venta.
Retroceso bajista de Fibonacci:
Para un bloque de orden bajista, se utiliza la herramienta de retroceso de Fibonacci para localizar entradas comerciales óptimas. Después de identificar el bloque de orden bajista, el comerciante busca el máximo y el mínimo recientes. En este caso, el retroceso de Fibonacci se dibuja desde el máximo hasta el mínimo, ya que el foco está en una orden de venta. El retroceso confirma que el bloque de orden bajista está en o por encima del nivel del 61,8%, lo que indica un punto de entrada de alta probabilidad para una posición corta.
Para empezar:
//+------------------------------------------------------------------+ //| FIB_OB.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include <Trade/Trade.mqh> CTrade trade; #define BullOB clrLime #define BearOB clrRed
`# include <Trade/Trade.mqh>`: Esta línea incluye la biblioteca MQL5 Trade, que proporciona funciones integradas para gestionar operaciones, órdenes y posiciones. El archivo `Trade.mqh` contiene clases y funciones predefinidas que simplifican las operaciones bursátiles, como abrir, cerrar y modificar órdenes. Creamos una instancia de `CTrade` llamada `trade`. La clase `CTrade` encapsula las operaciones bursátiles (como realizar órdenes de compra/venta, cerrar posiciones y modificar operaciones). Al crear este objeto, podrá gestionar fácilmente las operaciones utilizando el método orientado a objetos en su Asesor Experto (EA).
A continuación, definimos dos constantes para los colores que utilizaremos para visualizar los bloques de órdenes alcistas y los bloques de órdenes bajistas. A «BullOB» se le asigna el color «clrLime» (verde) para los bloques de órdenes alcistas, lo que indica las áreas en las que los compradores pueden haber entrado en el mercado. A «BearOB» se le asigna el color «clrRed» para los bloques de órdenes bajistas, lo que indica las áreas en las que los vendedores pueden haber entrado en el mercado.
//+------------------------------------------------------------------+ //| Global vars | //+------------------------------------------------------------------+ double Lots = 0.01; int takeProfit = 170; //int stopLoss = 200; int length = 100; input double stopLoss = 350; input double Mgtn = 00.85; bool isBullishOB = false; bool isBearishOB = false; input int Time1Hstrt = 3; input int Time1Hend = 4;
`isBullishOB` e `isBearishOB` son los indicadores booleanos que utilizamos para realizar un seguimiento de la detección de bloques de órdenes (OB). Entre las variables globales tenemos los parámetros de entrada `Time1Hstrt` y `Time2Hend` para la configuración del tiempo. `Time1Hstrt`: Representa la hora de inicio de una ventana de negociación específica; en nuestro caso, representa la sesión bursátil de Nueva York. `Time1Hend`: Representa la hora de finalización de ese intervalo de tiempo.
class COrderBlock : public CObject { public: int direction; datetime time;//[] double high; double low; void draw(datetime tmS, datetime tmE, color clr){ string objOB = " OB REC" + TimeToString(time); ObjectCreate( 0, objOB, OBJ_RECTANGLE, 0, time, low, tmS, high); ObjectSetInteger( 0, objOB, OBJPROP_FILL, true); ObjectSetInteger( 0, objOB, OBJPROP_COLOR, clr); string objtrade = " OB trade" + TimeToString(time); ObjectCreate( 0, objtrade, OBJ_RECTANGLE, 0, tmS, high, tmE, low); // trnary operator ObjectSetInteger( 0, objtrade, OBJPROP_FILL, true); ObjectSetInteger( 0, objtrade, OBJPROP_COLOR, clr); } };
Definimos una clase denominada «COrderBlock», que utilizaremos para modelar un bloque de órdenes (OB) en el gráfico de operaciones. Incluye propiedades para la dirección del bloque de órdenes, el tiempo, los valores máximos y mínimos, así como el método (`draw`) para dibujar el bloque de órdenes en el gráfico. La clase `COrderBlock` hereda de la clase base `CObject`, que es una clase de uso general en MQL5 utilizada para crear objetos. Esto le da a `COrderblock` acceso a los métodos y propiedades de `CObject`.
Variables miembro (Properties) `direction` un tipo de datos int que representa la dirección del bloque de orden. Lo utilizamos para indicar si el bloque de órdenes es alcista (1 es al alza) o bajista (-1 es a la baja). `time`: Representa el momento en que se formó o detectó el bloque de órdenes. Contiene la marca de tiempo del evento del bloque de orden. `high`: Representa el precio alto del bloque de órdenes (el límite superior de la zona). `low`: Representa el precio mínimo del bloque de órdenes (el límite inferior de la zona). Estas cuatro variables son los atributos clave de un bloque de órdenes (Order Block, OB).
A continuación, creamos una variable de cadena `objOB` para almacenar el nombre único del objeto rectángulo que representará el bloque de pedido en el gráfico. El nombre se genera utilizando el prefijo «OB REC» concatenado con la hora del bloque de orden (convertida a cadena utilizando `TimeToString()`). `ObjectCreate()`: Esta función crea un objeto rectángulo (`OBJ-RECTANGLE`) en el gráfico. `0`: El ID del gráfico (0 significa el gráfico actual) y `objOB` es el nombre del objeto rectángulo. `time, low`: Las coordenadas de la esquina inferior izquierda del rectángulo (el inicio del bloque de órdenes en el eje temporal y el nivel de precio del mínimo). `tmS, high`: Las coordenadas de la esquina superior derecha del rectángulo (la hora de cierre y el nivel de precio del máximo).
COrderBlock* OB; color OBClr; datetime T1; datetime T2;
- `COrderBlock* OB`: Un puntero a un objeto `Order Block`, que utilizaremos para gestionar y dibujar bloques de órdenes en el gráfico.
- `color OBClr`: Variable que contiene el color que se utilizará para el bloque de órdenes en función de si se trata de un bloque de órdenes alcista o bajista.
- `datetime T1`: Una variable que representa la hora de inicio del bloque de órdenes.
- `datetime T2`: Una variable que representa la hora de finalización del bloque de órdenes.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ trade.SetExpertMagicNumber(MagicNumber); return(INIT_SUCCEEDED); }
La función `OnInit()` se llama cuando el EA se carga por primera vez en un gráfico. Simplemente establecemos el número mágico del asesor experto, que es simplemente un identificador único para las operaciones realizadas por el EA.
const int len = 5; int left_bars, right_bars; int bar_Now = len; bool isSwingH = true, isSwingL = true;
- `len`: Establece el número de barras (velas) a la izquierda y a la derecha que se tendrán en cuenta a la hora de determinar si una barra es un punto de giro.
- `left-bars, right-bars`: Estas variables se utilizarán para almacenar los índices de las barras izquierda y derecha en relación con la barra actual (bar_Now).
- `bar_Now = len`: La barra actual que se está analizando se establece en len (en este caso, 5 barras atrás).
- `isSwingH, isSwingL`: Estas variables booleanas se inicializan con el valor «true» y se utilizarán para comprobar si la barra actual es un máximo o un mínimo del swing.
for(int i = 1; i <= len; i++){ right_bars = bar_Now - i; left_bars = bar_Now + i;
El bucle «for» recorre el rango de barras (len = 5), analizando tanto el lado izquierdo como el derecho de la barra actual (bar_Now).
- `right-bars = bar_Now - i`: Se refiere a las barras situadas a la derecha de la barra actual.
- `left-bars = bar_Now + i`: Se refiere a las barras situadas a la izquierda de la barra actual.
if((getHigh(bar_Now) <= getHigh(right_bars)) ||(getHigh(bar_Now) < getHigh(left_bars))){ isSwingH = false; }
Esta condición comprueba si el máximo de la barra actual (bar_Now) es menor o igual que el máximo de las barras circundantes (tanto a la izquierda como a la derecha). Si alguna barra de cualquiera de los dos lados tiene un máximo igual o superior, entonces la barra actual no es un máximo oscilante y `isSwingH` se establece en falso.
if((getLow(bar_Now) >= getLow(right_bars)) || getLow(bar_Now) > getLow(left_bars)){ isSwingL = false; }
De forma similar a la lógica del swing alto, esta condición comprueba si el mínimo de la barra actual es mayor o igual que el mínimo de las barras circundantes. Si alguna barra de cualquiera de los dos lados tiene un mínimo igual o inferior, entonces la barra actual no es un mínimo oscilante y `isSwingL` se establece en falso.
if(isSwingH){ Print("We have a swing high at index: ", bar_Now, "at price: ", getHigh(bar_Now)); fib_high = getHigh(bar_Now); fib_t1 = getTime(bar_Now); }
Si `isSwingH` sigue siendo verdadero, indica que se ha encontrado un máximo de oscilación. La función imprime el índice de la barra y el precio de oscilación. `fib-high` y `fib-t1` son variables globales que almacenan el precio máximo de la oscilación y el tiempo correspondiente. Estos valores se pasarán como parámetros al objeto FIBO.
if(isSwingL){ Print("We have a swing low at index: ", bar_Now," at price: ", getLow(bar_Now)); fib_low = getLow(bar_Now); fib_t2 = getTime(bar_Now); }
Del mismo modo, para gestionar la detección de mínimos oscilantes, la variable `isSwingL` permanece verdadera si se detecta un mínimo oscilante. La función imprime el índice de la barra y el precio mínimo de la oscilación. `fib-low` y `fib-t2` almacenan el precio mínimo y el tiempo de la oscilación. Estos valores se pasarán como parámetros al objeto FIBO.
//+------------------------------------------------------------------+ //| Function to find OB | //+------------------------------------------------------------------+ void getOrderB(){ static int prevDay = 0; MqlDateTime structTime; TimeCurrent(structTime); structTime.min = 0; structTime.sec = 0; structTime.hour = Time1Hstrt; datetime timestrt = StructToTime(structTime); structTime.hour = Time1Hend; datetime timend = StructToTime(structTime); if(TimeCurrent() >= timestrt && TimeCurrent() < timend){ if(prevDay != structTime.day_of_year){ delete OB; for(int i = 1; i < 100; i++){ if(getOpen(i) < getClose(i)){ // index is i since the loop starts from i which is = 1 "for(int i = 1)..." if(getOpen(i + 2) < getClose(i + 2)){ if(getOpen(i + 3) > getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){ Print("Bullish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES)); //isBullishOB = true; OB = new COrderBlock(); OB.direction = 1; OB.time = getTime(i + 3); OB.high = getHigh(i + 3); OB.low = getLow(i + 3); isBullishOB = true; OBClr = isBullishOB ? BullOB : BearOB; // specify strt time T1 = OB.time; // reset BULL OB flag isBullishOB = false; prevDay = structTime.day_of_year; break; delete OB; } } } if(getOpen(i) > getClose(i)){ if(getOpen(i + 2) > getClose(i + 2)){ if(getOpen(i + 3) < getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){ Print("Bearish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES)); //isBearishOB = true; OB = new COrderBlock(); OB.direction = -1; OB.time = getTime(i + 3); OB.high = getHigh(i + 3); OB.low = getLow(i + 3); isBearishOB = true; OBClr = isBearishOB ? BearOB : BullOB; T1 = OB.time; // reset the BEAR OB flag isBearishOB = false; prevDay = structTime.day_of_year; break; delete OB; } } } } } } }
La función busca bloques de órdenes alcistas y bajistas en los datos de precios dentro de un intervalo de tiempo específico (en este caso, desde «Time1Hstrt» hasta «Time1end»). Una vez identificado, crea un objeto «Bloque de órdenes» (COrderBlock) con atributos relevantes como dirección, hora, precios máximos y mínimos. Luego establece los colores y las banderas para la visualización y el procesamiento. `prevDay` es una variable estática que conserva sus valores entre llamadas de función. Asegura que la detección de bloqueos de órdenes se realice solo una vez al día.
Si la función ya ha procesado el día actual (`prevDay`), omite la detección para evitar recálculo de bloques de pedidos. Se reinicia una vez que cambia el día. La función verifica la acción del precio en busca de patrones de bloques de órdenes alcistas y bajistas.
- Condiciones: Se busca una serie de velas formando un patrón alcista. La primera vela es alcista (el precio de apertura es menor que el precio de cierre). La segunda vela también es alcista para confirmación. La tercera vela es bajista, pero su precio de apertura es menor que el cierre de la segunda vela.
- Si se cumplen todas las condiciones, se confirma un bloqueo de orden alcista.
- Se crea un nuevo objeto `COrderBlock` con propiedades como dirección (alcista), tiempo, precio máximo y mínimo.
- Se aplica una lógica similar para un bloque de orden bajista. La primera vela es bajista (el precio de apertura es más alto que el precio de cierre). La segunda vela también es bajista para confirmación. La tercera vela es alcista, pero su precio de apertura es menor que el cierre de la segunda vela.
- Cuando se cumplen las condiciones, se confirma un bloque de orden bajista.
- Después del procesamiento, el objeto 'OB' se elimina para liberar memoria.
- `pervDay` se actualiza para garantizar que la función se ejecute solo una vez al día.
bool isNewBar() { // Memorize the time of opening of the last bar in the static variable static datetime last_time = 0; // Get current time datetime lastbar_time = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE); // First call if (last_time == 0) { last_time = lastbar_time; return false; } // If the time differs (new bar) if (last_time != lastbar_time) { last_time = lastbar_time; return true; } // If no new bar, return false return false; }
Esta función verifica si ha aparecido una nueva barra en el gráfico, para realizar algunas funciones una vez por barra.
double getHigh(int index) { return iHigh(_Symbol, _Period, index); } double getLow(int index) { return iLow(_Symbol, _Period, index); } double getOpen(int index){ return iOpen(_Symbol, _Period, index); } double getClose(int index){ return iClose(_Symbol, _Period, index); } datetime getTime(int index) { return iTime(_Symbol, _Period, index); }
Esta sección del código proporciona un conjunto de funciones de utilidad para recuperar datos de precios específicos e información de tiempo para una barra (o vela) determinada en el "índice" proporcionado. Cada función accede al precio o valor de tiempo respectivo de un símbolo y período utilizando funciones MQL5 integradas como `iHigh()`, `iLow()`, `iOpen()`, `iClose()` y `iTime()`.
void OnTick(){ if(isNewBar()){ getOrderB(); getSwings(); double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(CheckPointer(OB) != POINTER_INVALID && OB.direction > 0 && Ask < OB.high){ double entry = Ask; double tp = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); double sl = NormalizeDouble(OB.low - Mgtn, _Digits); // double sl = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, 2,iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); ObjectCreate( 0, FIBO_OBJ, OBJ_FIBO, 0, fib_t1, fib_low, fib_t2, fib_high); double entLvl = fib_high - (fib_high - fib_low) * Fib_Trade_lvls / 100; // check this if non if(OB.high <= entLvl){ T2 = getTime(0); OB.draw(T1, T2, OBClr); trade.Buy(Lots, _Symbol, entry, sl, tp, "OB buy"); delete OB; }else{ delete OB; } } if(CheckPointer(OB) != POINTER_INVALID && OB.direction < 0 && Bid > OB.low){ double entry = Bid; double tp = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); double sl = NormalizeDouble(OB.high + Mgtn, _Digits); // double sl = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); ObjectCreate( 0, FIBO_OBJ, OBJ_FIBO, 0, fib_t2, fib_high, fib_t1, fib_low); double entLvl = fib_low + (fib_low - fib_high) * Fib_Trade_lvls / 100; if(OB.low >= entLvl){ T2 = getTime(0); OB.draw(T1, T2, OBClr); trade.Sell(Lots, _Symbol, entry, sl, tp, "OB sell"); delete OB; }else{ delete OB; } } ObjectSetInteger( 0, FIBO_OBJ, OBJPROP_COLOR, clrBlack); for(int i = 0; i < ObjectGetInteger( 0, FIBO_OBJ, OBJPROP_LEVELS); i++){ ObjectSetInteger( 0, FIBO_OBJ, OBJPROP_LEVELCOLOR, i, clrBlack); } } }
Dado que la función `OnTick()` se ejecuta cada vez que se produce un nuevo tick (actualización del precio), utilizamos la función `isNewBar()` para comprobar si se ha formado una nueva barra. La función `getOrderB()` identifica posibles bloques de órdenes alcistas o bajistas (zonas en las que los operadores institucionales colocan grandes órdenes de compra/venta). La función `getSwing()` identifica los puntos de oscilación (máximos y mínimos) en el movimiento del precio, que se utilizan para trazar los niveles de retroceso de Fibonacci.
Cuando se detecta el bloque de órdenes y el precio vuelve a retroceder hasta la zona del bloque de órdenes, primero comprobamos si el precio actual se encuentra dentro de esta zona. Si es así, procedemos a validar la configuración comprobando si el precio se ajusta al nivel de retroceso de Fibonacci del 61,8 %. Este nivel es crítico porque a menudo indica un punto de inflexión importante en las estrategias de negociación institucionales. Solo si se cumplen ambas condiciones (precio dentro del bloque de órdenes y alineación con el retroceso de Fibonacci del 61,8 %) procedemos a ejecutar una posición (compra o venta). De lo contrario, si alguna de las dos condiciones no se cumple, simplemente eliminamos el bloque de órdenes y evitamos entrar en la operación.
Bloqueo de orden alcista cuando se confirma:
Bloque de orden bajista cuando se confirma:
La lógica del sistema se basa en la dependencia entre el bloque de órdenes y los niveles de retroceso de Fibonacci. Cuando se detecta un bloque de orden, el sistema verifica si está alineado con el nivel de retroceso de Fibonacci del 61,8%. Para un bloque de orden alcista, el precio debe caer por debajo del nivel de retroceso del 61,8%, mientras que para un bloque de orden bajista, debe estar por encima del nivel del 61,8%. Si el bloque de orden no cumple estas condiciones de Fibonacci, no se ejecuta ninguna posición comercial. Sin embargo, el objeto Fibonacci todavía se dibuja en el gráfico para visualizar el nivel de retroceso, lo que ayuda al comerciante a monitorear la configuración potencial sin tomar una posición hasta que se cumplan las condiciones adecuadas.
Conclusión
En resumen, integramos conceptos clave de análisis técnico como bloques de órdenes, máximos y mínimos oscilantes y retroceso de Fibonacci para automatizar las decisiones comerciales. Creamos funciones para detectar bloques de órdenes alcistas y bajistas, que representan áreas donde los traders institucionales suelen colocar grandes órdenes de compra o venta. Al incorporar niveles de Fibonacci, el EA confirma si el retroceso de precios se alinea con zonas de alta probabilidad antes de ejecutar operaciones. La función `OnTick()` monitorea continuamente el mercado en busca de nuevas barras y evalúa si se cumplen las condiciones para abrir posiciones, estableciendo automáticamente niveles de entrada, stop loss y take profit en función de la acción del precio en tiempo real.
En conclusión, este Asesor Experto está diseñado para ayudar a los traders minoristas a alinear sus operaciones con el flujo de órdenes institucionales, brindándoles un enfoque sistemático para ingresar en operaciones de alta probabilidad. Al identificar y reaccionar ante estructuras de mercado clave, como bloques de órdenes y retrocesos de precios, el EA permite a los operadores operar de una manera que refleja los movimientos estratégicos de grandes instituciones financieras. Esta alineación puede mejorar la precisión comercial, reducir la toma de decisiones emocionales y, en última instancia, mejorar la rentabilidad de los traders minoristas.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/13396
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.





- 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
Creo que su archivo zip no funciona como se pretende, no veo gráficos, pero veo algunos mensajes de depuración acerca de un
swing high o loww.
"mgtn" se utiliza como margen de precio o buffer para colocar el stop loss por debajo del mínimo del bloque de órdenes (para operaciones de compra) o por encima del máximo del bloque de órdenes (para operaciones de venta).
El EA determina los máximos y mínimos de oscilación comparando la barra actual con un número determinado de barras a la izquierda y a la derecha (len = 5 en este caso). Una barra se marca como swing high si su máximo es mayor que el de las barras circundantes, y como swing low si su mínimo es menor que el de las barras circundantes. Dado que este método utiliza un número fijo de barras, detecta principalmente oscilaciones importantes de la estructura y puede que no siempre capte cambios menores de la estructura, a menos que reduzca el parámetro len.