//╔════════════════════════════════════════════════════════════════════════╗ //║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║ //║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║ //║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║ //║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║ //║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║ //║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║ //╚═══════ Algorithms that observe ══════ Signals that speak ══════════════╝ // Indicador técnico SuperTrend // Basado en el concepto original de Olivier Seban. // Inspirado en la visualización popularizada por KivancOzbilgic. // Implementación para MetaTrader por Ulises Calderón Bautista. #property copyright "Exobeacon Labs" #property link "https://www.exobeacon.com/" #property version "1.3" #property description "SuperTrend — Adaptive Trend-Following Indicator" #property description "ATR-based dynamic support/resistance overlay that adapts to volatility in real time." #property description " " #property description "〰〰〰〰〰((👽))〰〰〰〰〰" #property description "🛸 mql5.com/en/users/ulisescalb" #property description "🛸 github.com/Exobeacon-Labs" #property indicator_chart_window #property indicator_buffers 4 #property indicator_plots 2 // Propiedades de las líneas #property indicator_label1 "SuperTrend Up" #property indicator_type1 DRAW_LINE #property indicator_color1 clrLime #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #property indicator_label2 "SuperTrend Down" #property indicator_type2 DRAW_LINE #property indicator_color2 clrRed #property indicator_style2 STYLE_SOLID #property indicator_width2 2 // Parámetros de entrada input int InpAtrPeriod = 10; // ATR Length input double InpFactor = 3.0; // Factor input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_MEDIAN; // Applied Price // Buffers del indicador double UpTrendBuffer[]; double DownTrendBuffer[]; double SuperTrendBuffer[]; double DirectionBuffer[]; // Handle del ATR int atrHandle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { // Validación de parámetros if(InpAtrPeriod <= 0) { Print("Error: ATR Period debe ser mayor que 0"); return(INIT_PARAMETERS_INCORRECT); } if(InpFactor <= 0) { Print("Error: Factor debe ser mayor que 0"); return(INIT_PARAMETERS_INCORRECT); } // Asignación de buffers SetIndexBuffer(0, UpTrendBuffer, INDICATOR_DATA); SetIndexBuffer(1, DownTrendBuffer, INDICATOR_DATA); SetIndexBuffer(2, SuperTrendBuffer, INDICATOR_CALCULATIONS); SetIndexBuffer(3, DirectionBuffer, INDICATOR_CALCULATIONS); // Configuración de valores vacíos PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0); // Inicializar arrays como series ArraySetAsSeries(UpTrendBuffer, true); ArraySetAsSeries(DownTrendBuffer, true); ArraySetAsSeries(SuperTrendBuffer, true); ArraySetAsSeries(DirectionBuffer, true); // Crear handle del ATR atrHandle = iATR(_Symbol, _Period, InpAtrPeriod); if(atrHandle == INVALID_HANDLE) { Print("Error al crear el indicador ATR"); return(INIT_FAILED); } // Nombre del indicador string priceLabel = ""; switch(InpAppliedPrice) { case PRICE_CLOSE: priceLabel = "Close"; break; case PRICE_OPEN: priceLabel = "Open"; break; case PRICE_HIGH: priceLabel = "High"; break; case PRICE_LOW: priceLabel = "Low"; break; case PRICE_MEDIAN: priceLabel = "Median"; break; case PRICE_TYPICAL: priceLabel = "Typical"; break; case PRICE_WEIGHTED: priceLabel = "Weighted"; break; } IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("SuperTrend(%d,%.2f,%s)", InpAtrPeriod, InpFactor, priceLabel)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(atrHandle != INVALID_HANDLE) IndicatorRelease(atrHandle); } //+------------------------------------------------------------------+ //| Función auxiliar para obtener el precio aplicado | //+------------------------------------------------------------------+ double GetAppliedPrice(const int pos, const double &open[], const double &high[], const double &low[], const double &close[]) { switch(InpAppliedPrice) { case PRICE_CLOSE: return close[pos]; case PRICE_OPEN: return open[pos]; case PRICE_HIGH: return high[pos]; case PRICE_LOW: return low[pos]; case PRICE_MEDIAN: return (high[pos] + low[pos]) / 2.0; case PRICE_TYPICAL: return (high[pos] + low[pos] + close[pos]) / 3.0; case PRICE_WEIGHTED: return (high[pos] + low[pos] + close[pos] + close[pos]) / 4.0; default: return (high[pos] + low[pos]) / 2.0; // Default a Median } } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if(rates_total < InpAtrPeriod) return(0); // Configurar arrays como series ArraySetAsSeries(open, true); ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); // Obtener valores del ATR double atr[]; ArraySetAsSeries(atr, true); int to_copy = rates_total - prev_calculated + InpAtrPeriod + 1; if(prev_calculated == 0) to_copy = rates_total; if(CopyBuffer(atrHandle, 0, 0, to_copy, atr) <= 0) { Print("Error al copiar datos del ATR"); return(0); } // Determinar desde dónde calcular int start; if(prev_calculated == 0) start = InpAtrPeriod; else start = prev_calculated - 1; // Calcular SuperTrend for(int i = start; i < rates_total; i++) { int pos = rates_total - 1 - i; // Calcular línea central usando el precio aplicado seleccionado double basePrice = GetAppliedPrice(pos, open, high, low, close); // Calcular bandas básicas double upperBand = basePrice + InpFactor * atr[pos]; double lowerBand = basePrice - InpFactor * atr[pos]; // Ajustar bandas según la barra anterior if(i > InpAtrPeriod) { int prevPos = pos + 1; // Ajustar banda superior if(upperBand < SuperTrendBuffer[prevPos] || close[prevPos] > SuperTrendBuffer[prevPos]) upperBand = upperBand; else upperBand = SuperTrendBuffer[prevPos]; // Ajustar banda inferior if(lowerBand > SuperTrendBuffer[prevPos] || close[prevPos] < SuperTrendBuffer[prevPos]) lowerBand = lowerBand; else lowerBand = SuperTrendBuffer[prevPos]; } // Determinar dirección y valor del SuperTrend if(i == InpAtrPeriod) { SuperTrendBuffer[pos] = upperBand; DirectionBuffer[pos] = 1; // Tendencia bajista } else { int prevPos = pos + 1; // Verificar cambio de tendencia if(DirectionBuffer[prevPos] == 1) // Estaba en tendencia bajista { if(close[pos] > SuperTrendBuffer[prevPos]) { // Cambio a tendencia alcista DirectionBuffer[pos] = -1; SuperTrendBuffer[pos] = lowerBand; } else { // Continúa bajista DirectionBuffer[pos] = 1; SuperTrendBuffer[pos] = upperBand; } } else // Estaba en tendencia alcista { if(close[pos] < SuperTrendBuffer[prevPos]) { // Cambio a tendencia bajista DirectionBuffer[pos] = 1; SuperTrendBuffer[pos] = upperBand; } else { // Continúa alcista DirectionBuffer[pos] = -1; SuperTrendBuffer[pos] = lowerBand; } } } // Asignar valores a los buffers de plot if(DirectionBuffer[pos] < 0) { // Tendencia alcista UpTrendBuffer[pos] = SuperTrendBuffer[pos]; DownTrendBuffer[pos] = 0.0; } else { // Tendencia bajista UpTrendBuffer[pos] = 0.0; DownTrendBuffer[pos] = SuperTrendBuffer[pos]; } } return(rates_total); } //+------------------------------------------------------------------+