Donchian-Channels-Trend/Donchian_Channels_Trend.mq4

302 lines
No EOL
22 KiB
MQL4

//╔════════════════════════════════════════════════════════════════════════╗
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
//╚═══════ 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")
*/