Donchian-Channels-Trend/Donchian_Channels_Trend.mq5

278 lines
No EOL
12 KiB
MQL5

//╔════════════════════════════════════════════════════════════════════════╗
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
//╚═══════ Algorithms that observe ════ Signals that speak ════════════════╝
//+------------------------------------------------------------------+
//| Archivo: Donchian_Channels_Trend.mq5 |
//| Origen: Replicación del "Donchian Channels Trend" de TradingView |
//| Autor Original: holdon_to_profits |
//| Descripción: Indicador de canales con memoria de estado (FSM). |
//| Detecta la tendencia basándose en rupturas de la |
//| estructura previa y cambia de color dinámicamente. |
//+------------------------------------------------------------------+
#property copyright "Exobeacon Labs"
#property link "https://www.exobeacon.com/"
#property version "1.0"
#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 "Identifies directional bias and structural levels."
#property description " "
#property description "〰〰〰〰〰((👽))〰〰〰〰〰"
#property description "🛸 mql5.com/en/users/ulisescalb"
#property description "🛸 github.com/Exobeacon-Labs"
#property strict
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_plots 3
// --- Configuración Plot 1: Upper Band ---
#property indicator_label1 "Upper Band"
#property indicator_type1 DRAW_COLOR_LINE
#property indicator_color1 clrLime, clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
// --- Configuración Plot 2: Lower Band ---
#property indicator_label2 "Lower Band"
#property indicator_type2 DRAW_COLOR_LINE
#property indicator_color2 clrLime, clrRed
#property indicator_style2 STYLE_SOLID
#property indicator_width2 2
// --- Configuración Plot 3: Basis Line ---
#property indicator_label3 "Basis Line"
#property indicator_type3 DRAW_COLOR_LINE
#property indicator_color3 clrLime, clrRed
#property indicator_style3 STYLE_DASHDOT
#property indicator_width3 1
//+------------------------------------------------------------------+
//| ENTRADAS DEL USUARIO (Inputs) |
//+------------------------------------------------------------------+
input group "====== Donchian Settings ======"
input int InpLength = 20; // Lookback Period (Length)
input group "====== 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) |
//+------------------------------------------------------------------+
double BufferUpper[];
double BufferUpperColor[];
double BufferLower[];
double BufferLowerColor[];
double BufferBasis[];
double BufferBasisColor[];
double BufferTrend[]; // Búfer oculto para memoria de tendencia (1 = Bullish, -1 = Bearish)
//+------------------------------------------------------------------+
//| VARIABLES GLOBALES AUXILIARES |
//+------------------------------------------------------------------+
datetime g_lastAlertTime = 0; // Control de tiempo para evitar spam de alertas
//+------------------------------------------------------------------+
//| INIT FUNCTION |
//+------------------------------------------------------------------+
int OnInit()
{
// 1. Validación estricta de parámetros
if(InpLength < 1)
{
Print("Error: Lookback Period must be greater than 0.");
return INIT_PARAMETERS_INCORRECT;
}
// 2. Mapeo de búferes de indicador
SetIndexBuffer(0, BufferUpper, INDICATOR_DATA);
SetIndexBuffer(1, BufferUpperColor, INDICATOR_COLOR_INDEX);
SetIndexBuffer(2, BufferLower, INDICATOR_DATA);
SetIndexBuffer(3, BufferLowerColor, INDICATOR_COLOR_INDEX);
SetIndexBuffer(4, BufferBasis, INDICATOR_DATA);
SetIndexBuffer(5, BufferBasisColor, INDICATOR_COLOR_INDEX);
SetIndexBuffer(6, BufferTrend, INDICATOR_CALCULATIONS);
// 3. Inicialización de valores vacíos y arrays
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
ArrayInitialize(BufferUpper, EMPTY_VALUE);
ArrayInitialize(BufferLower, EMPTY_VALUE);
ArrayInitialize(BufferBasis, EMPTY_VALUE);
ArrayInitialize(BufferTrend, 1.0); // Asume tendencia alcista inicialmente
// 4. Configuración visual para la ventana del indicador
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
string short_name = StringFormat("Donchian Trend (%d)", InpLength);
IndicatorSetString(INDICATOR_SHORTNAME, short_name);
// Evitar renderizar basura visual en las primeras velas
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpLength);
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, InpLength);
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpLength);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| DEINIT FUNCTION |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Limpieza de objetos gráficos y comentarios si existieran
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(rates_total < InpLength) return 0;
// Determinar el índice de inicio optimizado
int limit = prev_calculated == 0 ? InpLength - 1 : prev_calculated - 1;
if (limit < InpLength - 1) limit = InpLength - 1;
// Iteración principal (dirección estándar MQL5: de antiguo a reciente)
for(int i = limit; i < rates_total; i++)
{
// 1. Encontrar Máximos y Mínimos en la ventana N
double highest = high[i];
double lowest = low[i];
for(int j = 0; j < InpLength; j++)
{
if(high[i - j] > highest) highest = high[i - j];
if(low[i - j] < lowest) lowest = low[i - j];
}
// 2. Asignación de datos matemáticos a los búferes
BufferUpper[i] = highest;
BufferLower[i] = lowest;
BufferBasis[i] = (highest + lowest) / 2.0;
// 3. Máquina de Estados (Trend Memory FSM)
int current_trend = 1; // Valor por defecto
if (i > InpLength - 1)
{
// Heredar el estado de la barra anterior (Memoria)
current_trend = (int)BufferTrend[i-1];
// Regla 1: Ruptura alcista contra el borde dinámico de la iteración previa
if(BufferUpper[i-1] != EMPTY_VALUE && high[i] >= BufferUpper[i-1])
{
current_trend = 1;
}
// Regla 2: Ruptura bajista contra el borde dinámico de la iteración previa
else if(BufferLower[i-1] != EMPTY_VALUE && low[i] <= BufferLower[i-1])
{
current_trend = -1;
}
}
// Guardar estado
BufferTrend[i] = current_trend;
// 4. Transformación Gráfica (Color Routing)
// color_idx 0 = clrLime, 1 = clrRed
int color_idx = (current_trend == 1) ? 0 : 1;
BufferUpperColor[i] = color_idx;
BufferLowerColor[i] = color_idx;
BufferBasisColor[i] = color_idx;
// 5. Sistema de Alertas (Evaluado solo en el cierre de la vela para evitar repintado)
if(InpEnableAlerts && i == rates_total - 2 && i > limit)
{
if(BufferTrend[i] != BufferTrend[i-1])
{
TriggerAlerts(current_trend, time[i]);
}
}
}
// Retornar número de barras calculadas para la siguiente iteración
return rates_total;
}
//+------------------------------------------------------------------+
//| FUNCIONES AUXILIARES |
//+------------------------------------------------------------------+
// Disparador multi-canal de alertas
void TriggerAlerts(int trend_state, datetime signal_time)
{
// Filtrado de seguridad: solo una alerta por vela
if(signal_time <= g_lastAlertTime) return;
g_lastAlertTime = signal_time;
// Preparación del mensaje (ASCII únicamente)
string trend_name = (trend_state == 1) ? "BULLISH" : "BEARISH";
string msg = StringFormat("[Donchian Trend] %s %s - Trend shifted to %s",
_Symbol, EnumToString((ENUM_TIMEFRAMES)_Period), trend_name);
// Ejecución de rutas de salida
if(InpAlertPopup) Alert(msg);
if(InpAlertSound) PlaySound("alert.wav");
if(InpAlertPush) SendNotification(msg);
if(InpAlertEmail) SendMail("Donchian Trend Breakout", msg);
// Registro en Journal
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")
*/