//╔════════════════════════════════════════════════════════════════════════╗ //║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║ //║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║ //║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║ //║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║ //║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║ //║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║ //╚═══════ Algorithms that observe ════ Signals that speak ════════════════╝ //+------------------------------------------------------------------+ //| Archivo: Donchian_Channels_Trend.mq4 | //| Origen: Replicación del "Donchian Channels Trend" de TradingView | //| Autor Original: holdon_to_profits | //| Descripción: Indicador de canales con memoria de estado (FSM). | //| Reescrito nativamente para MQL4 respetando el | //| ecosistema y la paleta de Exobeacon Labs. | //+------------------------------------------------------------------+ #property copyright "Exobeacon Labs" #property link "https://www.exobeacon.com" #property version "1.00" #property description "Donchian Channels Trend (holdon_to_profits) v1.0" #property description "Trend-following breakout indicator." #property description "Dynamic coloring based on trend state memory." #property description "---------------------------------------" #property description "mql5.com/en/users/ulisescalb" #property description "github.com/Exobeacon-Labs" #property strict #property indicator_chart_window #property indicator_buffers 8 // --- Mapeo de Colores del Ecosistema Exobeacon (Corregido a paleta definitiva) --- // Upper/Lower Bullish Main (clrDeepSkyBlue) #property indicator_color1 clrDeepSkyBlue #property indicator_color2 clrDeepSkyBlue // Upper/Lower Bearish Main (clrDeepPink) #property indicator_color3 clrDeepPink #property indicator_color4 clrDeepPink // Basis Line Neutral (clrSilver) #property indicator_color5 clrSilver // Buffers 6, 7 y 8 seran ocultos (DRAW\_NONE) //+------------------------------------------------------------------+ //| ENTRADAS DEL USUARIO (Inputs) | //+------------------------------------------------------------------+ input string s1 = "=== Donchian Settings ==="; input int InpLength = 20; // Lookback Period (Length) input string s2 = "=== Alert Settings ==="; input bool InpEnableAlerts = false; // Enable All Alerts input bool InpAlertPopup = true; // Popup Alerts input bool InpAlertSound = true; // Sound Alerts input bool InpAlertPush = false; // Push Notifications input bool InpAlertEmail = false; // Email Alerts //+------------------------------------------------------------------+ //| BÚFERES GLOBALES (Buffers) | //+------------------------------------------------------------------+ // Búferes visuales (separados por color para simular línea dinámica en MQL4) double ExtUpperBull[]; // Índice 0 double ExtLowerBull[]; // Índice 1 double ExtUpperBear[]; // Índice 2 double ExtLowerBear[]; // Índice 3 double ExtBasis[]; // Índice 4 // Búferes ocultos lógicos (DRAW\_NONE obligatorio) double ExtTrend[]; // Índice 5: Memoria de tendencia (1 = Bull, -1 = Bear) double ExtRawUpper[]; // Índice 6: Canal crudo superior double ExtRawLower[]; // Índice 7: Canal crudo inferior //+------------------------------------------------------------------+ //| VARIABLES GLOBALES AUXILIARES | //+------------------------------------------------------------------+ datetime g_lastAlertTime = 0; //+------------------------------------------------------------------+ //| INIT FUNCTION | //+------------------------------------------------------------------+ int OnInit() { // 1. Validación estricta de parámetros if(InpLength < 1) { Print("[Exobeacon] Error: Lookback Period must be greater than 0."); return INIT_PARAMETERS_INCORRECT; } // 2. Mapeo de búferes de indicador SetIndexBuffer(0, ExtUpperBull); SetIndexBuffer(1, ExtLowerBull); SetIndexBuffer(2, ExtUpperBear); SetIndexBuffer(3, ExtLowerBear); SetIndexBuffer(4, ExtBasis); SetIndexBuffer(5, ExtTrend); SetIndexBuffer(6, ExtRawUpper); SetIndexBuffer(7, ExtRawLower); // 3. Estilos explícitos (Crucial en MQL4 para evitar líneas negras basura) SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2); SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 2); SetIndexStyle(3, DRAW_LINE, STYLE_SOLID, 2); SetIndexStyle(4, DRAW_LINE, STYLE_DASHDOT, 1); // Búferes de cálculo ocultos SetIndexStyle(5, DRAW_NONE); SetIndexStyle(6, DRAW_NONE); SetIndexStyle(7, DRAW_NONE); // 4. Configuración de valores vacíos y etiquetas for(int i = 0; i < 8; i++) { SetIndexEmptyValue(i, EMPTY_VALUE); } SetIndexLabel(0, "Upper Bullish"); SetIndexLabel(1, "Lower Bullish"); SetIndexLabel(2, "Upper Bearish"); SetIndexLabel(3, "Lower Bearish"); SetIndexLabel(4, "Basis Neutral"); // Nombres cortos de ventana string short_name = StringFormat("Donchian Trend (%d)", InpLength); IndicatorShortName(short_name); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| DEINIT FUNCTION | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Limpieza estricta de recursos Comment(""); } //+------------------------------------------------------------------+ //| CALCULATION 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[]) { // Evitar cálculos si no hay suficientes barras if(Bars <= InpLength) return 0; // Lógica de barras a procesar en MQL4 (Indexación inversa) int counted_bars = IndicatorCounted(); if(counted_bars < 0) return -1; if(counted_bars > 0) counted_bars--; int limit = Bars - counted_bars - 1; // Límite de seguridad para el lookback if(limit > Bars - InpLength - 1) limit = Bars - InpLength - 1; // Iteración principal (dirección MQL4: de pasado a presente, índice disminuye) for(int i = limit; i >= 0; i--) { // 1. Encontrar Máximos y Mínimos en la ventana N usando funciones nativas // Nota: iHighest/iLowest retorna el índice de la barra (shift) int highest_idx = iHighest(NULL, 0, MODE_HIGH, InpLength, i); int lowest_idx = iLowest(NULL, 0, MODE_LOW, InpLength, i); // Manejo seguro por si falla iHighest/iLowest if(highest_idx == -1 || lowest_idx == -1) continue; double upper_val = High[highest_idx]; double lower_val = Low[lowest_idx]; // Guardar valores crudos para referenciarlos en la siguiente vela [i+1] ExtRawUpper[i] = upper_val; ExtRawLower[i] = lower_val; ExtBasis[i] = (upper_val + lower_val) / 2.0; // 2. Máquina de Estados (Trend Memory FSM) int current_trend = 1; // Asumir alcista por defecto al inicio // Si no estamos en la barra más antigua, heredar memoria de la barra anterior (i+1) if(i < Bars - 1) { current_trend = (int)ExtTrend[i+1]; // Regla 1: Ruptura alcista contra el borde dinámico de la vela pasada if(ExtRawUpper[i+1] != EMPTY_VALUE && High[i] >= ExtRawUpper[i+1]) { current_trend = 1; } // Regla 2: Ruptura bajista contra el borde dinámico de la vela pasada else if(ExtRawLower[i+1] != EMPTY_VALUE && Low[i] <= ExtRawLower[i+1]) { current_trend = -1; } } // Guardar estado en el búfer oculto ExtTrend[i] = current_trend; // 3. Ruteo de Colores (Transformación visual en múltiples búferes) // MQL4 no permite coloreado dinámico por segmento fácilmente sin dividir búferes if(current_trend == 1) // Estado Alcista { ExtUpperBull[i] = upper_val; ExtLowerBull[i] = lower_val; ExtUpperBear[i] = EMPTY_VALUE; ExtLowerBear[i] = EMPTY_VALUE; } else // Estado Bajista { ExtUpperBull[i] = EMPTY_VALUE; ExtLowerBull[i] = EMPTY_VALUE; ExtUpperBear[i] = upper_val; ExtLowerBear[i] = lower_val; } // 4. Sistema de Alertas Estructuradas (Evaluado al cierre de la vela index 1) if(InpEnableAlerts && i == 1) { // Detectar cambio de estado entre vela recién cerrada (1) y la anterior (2) if(ExtTrend[1] != ExtTrend[2] && ExtTrend[2] != EMPTY_VALUE) { TriggerAlerts((int)ExtTrend[1], Time[1], Close[1]); } } } return rates_total; } //+------------------------------------------------------------------+ //| FUNCIONES AUXILIARES | //+------------------------------------------------------------------+ // Disparador multi-canal de alertas y logs estructurados en ASCII puro void TriggerAlerts(int trend_state, datetime signal_time, double close_price) { // Filtrado estricto anti-repintado: solo una alerta por vela cerrada if(signal_time <= g_lastAlertTime) return; g_lastAlertTime = signal_time; // Formateo de strings (ASCII únicamente para evitar problemas en log/MQL Market) string trend_name = (trend_state == 1) ? "BUY" : "SELL"; // Log Estructurado Exobeacon string msg = StringFormat("[Exobeacon] Signal=%s | Symbol=%s | TF=%d | Price=%s", trend_name, Symbol(), Period(), DoubleToString(close_price, Digits)); // Distribución a canales habilitados if(InpAlertPopup) Alert(msg); if(InpAlertSound) PlaySound("alert.wav"); if(InpAlertPush) SendNotification(msg); if(InpAlertEmail) SendMail("Exobeacon Breakout", msg); Print(msg); } //+------------------------------------------------------------------+ //| REFERENCIA ORIGINAL PINE SCRIPT (DOCUMENTACIÓN INTERNA) | //+------------------------------------------------------------------+ /* //@version=5 indicator("Donchian Channels Trend", overlay=true) // --- Inputs --- length = input.int(20, title="Length") // --- Core Calculations --- upper = ta.highest(high, length) lower = ta.lowest(low, length) basis = math.avg(upper, lower) // --- State Machine --- var int trend = 1 if high >= upper[1] trend := 1 else if low <= lower[1] trend := -1 // --- Coloring Output --- col = trend == 1 ? color.lime : color.red plot(upper, color=col, linewidth=2, title="Upper Band") plot(lower, color=col, linewidth=2, title="Lower Band") plot(basis, color=col, style=plot.style_dashdot, title="Basis Line") */