655 lines
No EOL
59 KiB
MQL4
655 lines
No EOL
59 KiB
MQL4
//╔════════════════════════════════════════════════════════════════════════╗
|
|
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
|
|
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
|
|
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
|
|
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
|
|
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
|
|
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
|
|
//╚═══════ Algorithms that observe ══════ Signals that speak ══════════════╝
|
|
//+------------------------------------------------------------------+
|
|
//| Bollinger_RSI_Double_Strategy_v11.mq4 |
|
|
//| Basado en: ChartArt - TradingView (Pine Script v2) |
|
|
//| https://www.tradingview.com/script/uCV8I4xA/ |
|
|
//+------------------------------------------------------------------+
|
|
//| Réplica fiel del indicador "Bollinger + RSI, Double Strategy |
|
|
//| (by ChartArt) v1.1" originalmente publicado en TradingView. |
|
|
//| |
|
|
//| Lógica central: |
|
|
//| BUY = crossover(RSI, 50) AND crossover(close, BB Lower) |
|
|
//| SELL = crossunder(RSI, 50) AND crossunder(close, BB Upper) |
|
|
//| |
|
|
//| Particularidades del original: |
|
|
//| - RSI periodo 6 con umbral 50 (filtro de momentum, no extremo) |
|
|
//| - Bollinger Bands SMA 200, multiplicador 2 |
|
|
//| - RSIoverSold = RSIoverBought = 50 (hardcoded) |
|
|
//| - Coloreo de velas y fondo como confirmación visual |
|
|
//+------------------------------------------------------------------+
|
|
|
|
#property copyright "Exobeacon Labs"
|
|
#property link "https://www.exobeacon.com/"
|
|
#property version "1.1"
|
|
#property description "Bollinger + RSI, Double Strategy (by ChartArt) v1.1"
|
|
#property description "Buy/Sell signals based on RSI(6)@50 + BB(200,2) confluence"
|
|
#property description " "
|
|
#property description "BUY: RSI crosses above 50 AND price crosses above BB Lower"
|
|
#property description "SELL: RSI crosses below 50 AND price crosses below BB Upper"
|
|
#property description " "
|
|
#property description "———————————————————————"
|
|
#property description "mql5.com/en/users/ulisescalb"
|
|
#property description "github.com/Exobeacon-Labs"
|
|
|
|
#property strict
|
|
|
|
//--- Dibujar en la ventana principal del gráfico (overlay=true en Pine Script)
|
|
#property indicator_chart_window
|
|
|
|
//--- Número total de buffers
|
|
#property indicator_buffers 5
|
|
|
|
//--- Colores por defecto de los plots
|
|
#property indicator_color1 clrAqua // BB Basis
|
|
#property indicator_color2 clrSilver // BB Upper
|
|
#property indicator_color3 clrSilver // BB Lower
|
|
#property indicator_color4 clrLime // Buy Arrow
|
|
#property indicator_color5 clrRed // Sell Arrow
|
|
|
|
//--- Anchos
|
|
#property indicator_width1 2
|
|
#property indicator_width2 1
|
|
#property indicator_width3 1
|
|
#property indicator_width4 2
|
|
#property indicator_width5 2
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Parámetros de entrada |
|
|
//+------------------------------------------------------------------+
|
|
//| Mapeados desde el Pine Script original: |
|
|
//| input(6, "RSI Period Length") → InpRSIPeriod |
|
|
//| input(200, "Bollinger Period") → InpBBPeriod |
|
|
//| input(true, "Enable Bar Color?") → InpEnableBarColor |
|
|
//| input(true, "Enable BG Color?") → InpEnableBGColor |
|
|
//| |
|
|
//| Parámetros hardcoded en el original ahora expuestos como input: |
|
|
//| BBmult = 2 → InpBBMultiplier |
|
|
//| RSIoverSold = RSIoverBought = 50 → InpRSILevel |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//--- RSI Settings
|
|
extern int InpRSIPeriod = 6; // RSI Period Length
|
|
extern int InpRSILevel = 50; // RSI Crossover Level (original=50)
|
|
|
|
//--- Bollinger Bands Settings
|
|
extern int InpBBPeriod = 200; // Bollinger Period Length
|
|
extern double InpBBMultiplier = 2.0; // BB Std Deviation Multiplier (original=2)
|
|
|
|
//--- Visual Settings
|
|
extern bool InpEnableBarColor = true; // Enable Bar Color?
|
|
extern bool InpEnableBGColor = true; // Enable Background Color?
|
|
extern int InpArrowOffset = 10; // Arrow Offset (points from candle)
|
|
extern color InpBuyColor = clrLime; // Buy Signal Color
|
|
extern color InpSellColor = clrRed; // Sell Signal Color
|
|
extern color InpBasisColor = clrAqua; // BB Basis Color
|
|
extern color InpBandColor = clrSilver; // BB Band Color
|
|
|
|
//--- Alert Settings
|
|
extern bool InpEnableAlerts = false; // Enable Alerts?
|
|
extern bool InpAlertPopup = true; // Alert: Popup
|
|
extern bool InpAlertSound = true; // Alert: Sound
|
|
extern bool InpAlertPush = false; // Alert: Push Notification
|
|
extern bool InpAlertEmail = false; // Alert: Email
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Buffers del indicador |
|
|
//+------------------------------------------------------------------+
|
|
double bufBasis[]; // [0] Línea central SMA de Bollinger
|
|
double bufUpper[]; // [1] Banda superior de Bollinger
|
|
double bufLower[]; // [2] Banda inferior de Bollinger
|
|
double bufBuyArrow[]; // [3] Flechas de señal de compra
|
|
double bufSellArrow[]; // [4] Flechas de señal de venta
|
|
|
|
//--- Control de barras mínimas necesarias
|
|
int g_minBars;
|
|
|
|
//--- Tracking de última alerta para evitar duplicados
|
|
datetime g_lastAlertTime = 0;
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Validación de parámetros de entrada
|
|
if(InpRSIPeriod < 1)
|
|
{
|
|
Print("Error: RSI Period debe ser >= 1. Valor actual: ", InpRSIPeriod);
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
if(InpBBPeriod < 1)
|
|
{
|
|
Print("Error: Bollinger Period debe ser >= 1. Valor actual: ", InpBBPeriod);
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
if(InpBBMultiplier <= 0)
|
|
{
|
|
Print("Error: BB Multiplier debe ser > 0. Valor actual: ", DoubleToStr(InpBBMultiplier, 1));
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
if(InpRSILevel < 0 || InpRSILevel > 100)
|
|
{
|
|
Print("Error: RSI Level debe estar entre 0 y 100. Valor actual: ", InpRSILevel);
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
|
|
//--- Barras mínimas necesarias
|
|
g_minBars = MathMax(InpBBPeriod, InpRSIPeriod) + 2;
|
|
|
|
//--- Asignación de buffers
|
|
SetIndexBuffer(0, bufBasis);
|
|
SetIndexBuffer(1, bufUpper);
|
|
SetIndexBuffer(2, bufLower);
|
|
SetIndexBuffer(3, bufBuyArrow);
|
|
SetIndexBuffer(4, bufSellArrow);
|
|
|
|
//--- Estilos de los plots
|
|
//--- Plot 0: BB Basis (línea aqua)
|
|
SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2, InpBasisColor);
|
|
SetIndexLabel(0, "BB Basis (SMA)");
|
|
|
|
//--- Plot 1: BB Upper (línea plateada)
|
|
SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 1, InpBandColor);
|
|
SetIndexLabel(1, "BB Upper");
|
|
|
|
//--- Plot 2: BB Lower (línea plateada)
|
|
SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, 1, InpBandColor);
|
|
SetIndexLabel(2, "BB Lower");
|
|
|
|
//--- Plot 3: Flecha de compra (233 = flecha arriba ▲)
|
|
SetIndexStyle(3, DRAW_ARROW, EMPTY, 2, InpBuyColor);
|
|
SetIndexArrow(3, 233);
|
|
SetIndexLabel(3, "Buy Signal");
|
|
|
|
//--- Plot 4: Flecha de venta (234 = flecha abajo ▼)
|
|
SetIndexStyle(4, DRAW_ARROW, EMPTY, 2, InpSellColor);
|
|
SetIndexArrow(4, 234);
|
|
SetIndexLabel(4, "Sell Signal");
|
|
|
|
//--- Valores vacíos para flechas
|
|
SetIndexEmptyValue(3, EMPTY_VALUE);
|
|
SetIndexEmptyValue(4, EMPTY_VALUE);
|
|
|
|
//--- Configurar inicio de dibujo
|
|
SetIndexDrawBegin(0, InpBBPeriod);
|
|
SetIndexDrawBegin(1, InpBBPeriod);
|
|
SetIndexDrawBegin(2, InpBBPeriod);
|
|
SetIndexDrawBegin(3, g_minBars);
|
|
SetIndexDrawBegin(4, g_minBars);
|
|
|
|
//--- Nombre corto del indicador
|
|
string shortName = StringConcatenate("CA_RSI(", InpRSIPeriod, ")_BB(",
|
|
InpBBPeriod, ",", DoubleToStr(InpBBMultiplier, 1),
|
|
") v1.1");
|
|
IndicatorShortName(shortName);
|
|
|
|
//--- Precisión de dígitos
|
|
IndicatorDigits(Digits);
|
|
|
|
Print("Bollinger + RSI Double Strategy v1.1 (MQL4) inicializado correctamente.");
|
|
Print("Configuración: RSI(", InpRSIPeriod, ")@", InpRSILevel,
|
|
" + BB(", InpBBPeriod, ", ", DoubleToStr(InpBBMultiplier, 1), ")");
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//--- Limpiar objetos gráficos del coloreo de fondo
|
|
ObjectsDeleteAll(0, "BRDS_BG_");
|
|
|
|
//--- Limpiar comentarios del gráfico
|
|
Comment("");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function |
|
|
//+------------------------------------------------------------------+
|
|
//| En MQL4, las series temporales tienen indexación inversa: |
|
|
//| Índice 0 = barra actual (más reciente) |
|
|
//| Índice N = barra más antigua |
|
|
//| Los buffers de indicador siguen la misma convención. |
|
|
//+------------------------------------------------------------------+
|
|
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[])
|
|
{
|
|
//--- Verificar que hay suficientes barras
|
|
if(rates_total < g_minBars)
|
|
return(0);
|
|
|
|
//--- Determinar el rango de cálculo
|
|
// En MQL4 con indexación inversa: 0=actual, rates_total-1=más antigua
|
|
// counted_bars = prev_calculated; si es 0, calcular todo
|
|
int limit;
|
|
if(prev_calculated <= 0)
|
|
limit = rates_total - g_minBars - 1;
|
|
else
|
|
limit = rates_total - prev_calculated + 1;
|
|
|
|
//--- Asegurar que limit no exceda el rango válido
|
|
if(limit > rates_total - g_minBars - 1)
|
|
limit = rates_total - g_minBars - 1;
|
|
if(limit < 0)
|
|
limit = 0;
|
|
|
|
//--- Bucle principal de cálculo
|
|
// En MQL4, iteramos de la barra más antigua a la más reciente
|
|
// (de índice alto a bajo) para respetar la convención de series
|
|
for(int i = limit; i >= 0; i--)
|
|
{
|
|
//=== 1. OBTENER VALORES DE INDICADORES VÍA FUNCIONES NATIVAS MQL4 ===
|
|
// En MQL4, iRSI/iMA/iStdDev acceden directamente a los valores
|
|
// sin necesidad de handles ni CopyBuffer.
|
|
//
|
|
// Mapeo desde Pine Script:
|
|
// rsi(close, 6) → iRSI(NULL, 0, 6, PRICE_CLOSE, i)
|
|
// sma(close, 200) → iMA(NULL, 0, 200, 0, MODE_SMA, PRICE_CLOSE, i)
|
|
// stdev(close, 200) → iStdDev(NULL, 0, 200, 0, MODE_SMA, PRICE_CLOSE, i)
|
|
|
|
//--- RSI actual y anterior
|
|
double rsiCurr = iRSI(NULL, 0, InpRSIPeriod, PRICE_CLOSE, i);
|
|
double rsiPrev = iRSI(NULL, 0, InpRSIPeriod, PRICE_CLOSE, i + 1);
|
|
|
|
//--- SMA (base de Bollinger) actual y anterior
|
|
double basis = iMA(NULL, 0, InpBBPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
|
|
double basisPrev = iMA(NULL, 0, InpBBPeriod, 0, MODE_SMA, PRICE_CLOSE, i + 1);
|
|
|
|
//--- Desviación estándar actual y anterior
|
|
// Nota: iStdDev en MQL4 calcula desviación poblacional (÷N),
|
|
// idéntico a stdev() de Pine Script v2
|
|
double stdCurr = iStdDev(NULL, 0, InpBBPeriod, 0, MODE_SMA, PRICE_CLOSE, i);
|
|
double stdPrev = iStdDev(NULL, 0, InpBBPeriod, 0, MODE_SMA, PRICE_CLOSE, i + 1);
|
|
|
|
//=== 2. CALCULAR BANDAS DE BOLLINGER ===
|
|
// Pine Script:
|
|
// BBbasis = sma(price, BBlength)
|
|
// BBdev = BBmult * stdev(price, BBlength)
|
|
// BBupper = BBbasis + BBdev
|
|
// BBlower = BBbasis - BBdev
|
|
|
|
double dev = InpBBMultiplier * stdCurr;
|
|
double devPrev = InpBBMultiplier * stdPrev;
|
|
double upper = basis + dev;
|
|
double lower = basis - dev;
|
|
double upperPrev = basisPrev + devPrev;
|
|
double lowerPrev = basisPrev - devPrev;
|
|
|
|
//--- Almacenar en buffers de dibujo
|
|
bufBasis[i] = basis;
|
|
bufUpper[i] = upper;
|
|
bufLower[i] = lower;
|
|
|
|
//--- Precios de cierre actual y anterior
|
|
double closeCurr = Close[i];
|
|
double closePrev = Close[i + 1];
|
|
|
|
//--- Inicializar señales como vacías
|
|
bufBuyArrow[i] = EMPTY_VALUE;
|
|
bufSellArrow[i] = EMPTY_VALUE;
|
|
|
|
//=== 3. DETECTAR SEÑALES (CONFLUENCIA RSI + BB) ===
|
|
// Pine Script original:
|
|
// if (crossover(vrsi, RSIoverSold) and crossover(source, BBlower))
|
|
// → LONG
|
|
// if (crossunder(vrsi, RSIoverBought) and crossunder(source, BBupper))
|
|
// → SHORT
|
|
//
|
|
// crossover(a, b) = a[1] < b[1] AND a[0] >= b[0]
|
|
// crossunder(a, b) = a[1] > b[1] AND a[0] <= b[0]
|
|
//
|
|
// Para nivel fijo: crossover(vrsi, 50) = vrsi[1] < 50 AND vrsi >= 50
|
|
|
|
//--- Señal LONG: RSI cruza arriba de 50 + Precio cruza arriba de BB Lower
|
|
bool rsiCrossUp = (rsiPrev < InpRSILevel && rsiCurr >= InpRSILevel);
|
|
bool priceCrossUp = (closePrev < lowerPrev && closeCurr >= lower);
|
|
bool longSignal = rsiCrossUp && priceCrossUp;
|
|
|
|
//--- Señal SHORT: RSI cruza abajo de 50 + Precio cruza abajo de BB Upper
|
|
bool rsiCrossDown = (rsiPrev > InpRSILevel && rsiCurr <= InpRSILevel);
|
|
bool priceCrossDown = (closePrev > upperPrev && closeCurr <= upper);
|
|
bool shortSignal = rsiCrossDown && priceCrossDown;
|
|
|
|
//--- Dibujar flechas de señal
|
|
if(longSignal)
|
|
{
|
|
bufBuyArrow[i] = Low[i] - InpArrowOffset * Point;
|
|
}
|
|
|
|
if(shortSignal)
|
|
{
|
|
bufSellArrow[i] = High[i] + InpArrowOffset * Point;
|
|
}
|
|
|
|
//=== 4. COLOREO DE VELAS (TrendColor del original) ===
|
|
// Pine Script original:
|
|
// TrendColor = RSIoverBought and (price[1] > BBupper and price < BBupper)
|
|
// and BBbasis < BBbasis[1] ? red
|
|
// : RSIoverSold and (price[1] < BBlower and price > BBlower)
|
|
// and BBbasis > BBbasis[1] ? green
|
|
// : na
|
|
//
|
|
// RSIoverBought=50 y RSIoverSold=50 son truthy en Pine v2, simplificando:
|
|
// ROJO: close[1] > BBupper[1] AND close < BBupper AND basis < basis[1]
|
|
// VERDE: close[1] < BBlower[1] AND close > BBlower AND basis > basis[1]
|
|
|
|
bool trendBearish = (closePrev > upperPrev && closeCurr < upper && basis < basisPrev);
|
|
bool trendBullish = (closePrev < lowerPrev && closeCurr > lower && basis > basisPrev);
|
|
|
|
//--- Aplicar color a las velas del gráfico
|
|
if(InpEnableBarColor && i < 200)
|
|
{
|
|
string candleObj = "BRDS_CANDLE_" + IntegerToString(i);
|
|
|
|
if(trendBullish)
|
|
ColorCandle(i, InpBuyColor);
|
|
else if(trendBearish)
|
|
ColorCandle(i, InpSellColor);
|
|
}
|
|
|
|
//--- Crear rectángulos de fondo (simula bgcolor de Pine Script)
|
|
if(InpEnableBGColor)
|
|
{
|
|
string bgName = "BRDS_BG_" + TimeToStr(Time[i], TIME_DATE | TIME_MINUTES);
|
|
|
|
if(trendBearish)
|
|
DrawBackground(bgName, Time[i], High[i], Low[i], InpSellColor);
|
|
else if(trendBullish)
|
|
DrawBackground(bgName, Time[i], High[i], Low[i], InpBuyColor);
|
|
else
|
|
{
|
|
//--- Eliminar fondo si no hay señal de color
|
|
if(ObjectFind(0, bgName) >= 0)
|
|
ObjectDelete(0, bgName);
|
|
}
|
|
}
|
|
|
|
//=== 5. ALERTAS (solo en la barra más reciente cerrada) ===
|
|
if(InpEnableAlerts && i == 1 && Time[i] != g_lastAlertTime)
|
|
{
|
|
if(longSignal)
|
|
{
|
|
SendAlertNotification("BUY Signal: RSI crossed above " +
|
|
IntegerToString(InpRSILevel) +
|
|
" + Price crossed above BB Lower");
|
|
g_lastAlertTime = Time[i];
|
|
}
|
|
else if(shortSignal)
|
|
{
|
|
SendAlertNotification("SELL Signal: RSI crossed below " +
|
|
IntegerToString(InpRSILevel) +
|
|
" + Price crossed below BB Upper");
|
|
g_lastAlertTime = Time[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return(rates_total);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Colorear una vela individual del gráfico |
|
|
//+------------------------------------------------------------------+
|
|
//| MQL4 no tiene DRAW_COLOR_CANDLES nativo como MQL5. La forma |
|
|
//| más directa de colorear velas es usando objetos OBJ_RECTANGLE |
|
|
//| o modificando el esquema de colores. Aquí usamos un approach |
|
|
//| con objetos que simula el barcolor() de Pine Script. |
|
|
//+------------------------------------------------------------------+
|
|
void ColorCandle(int shift, color candleColor)
|
|
{
|
|
if(shift < 0 || shift >= Bars)
|
|
return;
|
|
|
|
string objBody = "BRDS_BODY_" + IntegerToString(shift);
|
|
string objWickH = "BRDS_WICK_H_" + IntegerToString(shift);
|
|
string objWickL = "BRDS_WICK_L_" + IntegerToString(shift);
|
|
|
|
datetime t1 = Time[shift];
|
|
|
|
//--- Calcular el ancho de la vela (mitad del período entre velas)
|
|
datetime halfPeriod = 0;
|
|
if(shift < Bars - 1)
|
|
halfPeriod = (Time[shift] - Time[shift + 1]) / 3;
|
|
else
|
|
halfPeriod = PeriodSeconds() / 3;
|
|
|
|
datetime tLeft = t1 - halfPeriod;
|
|
datetime tRight = t1 + halfPeriod;
|
|
|
|
double bodyTop = MathMax(Open[shift], Close[shift]);
|
|
double bodyBottom = MathMin(Open[shift], Close[shift]);
|
|
|
|
//--- Cuerpo de la vela
|
|
if(ObjectFind(0, objBody) < 0)
|
|
ObjectCreate(0, objBody, OBJ_RECTANGLE, 0, tLeft, bodyTop, tRight, bodyBottom);
|
|
else
|
|
{
|
|
ObjectMove(0, objBody, 0, tLeft, bodyTop);
|
|
ObjectMove(0, objBody, 1, tRight, bodyBottom);
|
|
}
|
|
ObjectSetInteger(0, objBody, OBJPROP_COLOR, candleColor);
|
|
ObjectSetInteger(0, objBody, OBJPROP_FILL, true);
|
|
ObjectSetInteger(0, objBody, OBJPROP_BACK, true);
|
|
ObjectSetInteger(0, objBody, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, objBody, OBJPROP_HIDDEN, true);
|
|
|
|
//--- Mecha superior
|
|
if(ObjectFind(0, objWickH) < 0)
|
|
ObjectCreate(0, objWickH, OBJ_TREND, 0, t1, High[shift], t1, bodyTop);
|
|
else
|
|
{
|
|
ObjectMove(0, objWickH, 0, t1, High[shift]);
|
|
ObjectMove(0, objWickH, 1, t1, bodyTop);
|
|
}
|
|
ObjectSetInteger(0, objWickH, OBJPROP_COLOR, candleColor);
|
|
ObjectSetInteger(0, objWickH, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(0, objWickH, OBJPROP_RAY, false);
|
|
ObjectSetInteger(0, objWickH, OBJPROP_BACK, true);
|
|
ObjectSetInteger(0, objWickH, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, objWickH, OBJPROP_HIDDEN, true);
|
|
|
|
//--- Mecha inferior
|
|
if(ObjectFind(0, objWickL) < 0)
|
|
ObjectCreate(0, objWickL, OBJ_TREND, 0, t1, bodyBottom, t1, Low[shift]);
|
|
else
|
|
{
|
|
ObjectMove(0, objWickL, 0, t1, bodyBottom);
|
|
ObjectMove(0, objWickL, 1, t1, Low[shift]);
|
|
}
|
|
ObjectSetInteger(0, objWickL, OBJPROP_COLOR, candleColor);
|
|
ObjectSetInteger(0, objWickL, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(0, objWickL, OBJPROP_RAY, false);
|
|
ObjectSetInteger(0, objWickL, OBJPROP_BACK, true);
|
|
ObjectSetInteger(0, objWickL, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, objWickL, OBJPROP_HIDDEN, true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Dibujar rectángulo de fondo (simula bgcolor de Pine Script) |
|
|
//+------------------------------------------------------------------+
|
|
void DrawBackground(string objName, datetime barTime,
|
|
double priceHigh, double priceLow,
|
|
color bgColor)
|
|
{
|
|
datetime timeEnd = barTime + PeriodSeconds();
|
|
|
|
if(ObjectFind(0, objName) < 0)
|
|
{
|
|
ObjectCreate(0, objName, OBJ_RECTANGLE, 0,
|
|
barTime, priceHigh, timeEnd, priceLow);
|
|
}
|
|
else
|
|
{
|
|
ObjectMove(0, objName, 0, barTime, priceHigh);
|
|
ObjectMove(0, objName, 1, timeEnd, priceLow);
|
|
}
|
|
|
|
ObjectSetInteger(0, objName, OBJPROP_COLOR, bgColor);
|
|
ObjectSetInteger(0, objName, OBJPROP_FILL, true);
|
|
ObjectSetInteger(0, objName, OBJPROP_BACK, true);
|
|
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false);
|
|
ObjectSetInteger(0, objName, OBJPROP_HIDDEN, true);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Enviar alertas multi-canal |
|
|
//+------------------------------------------------------------------+
|
|
void SendAlertNotification(string message)
|
|
{
|
|
string prefix = "BB+RSI v1.1 [" + Symbol() + " " +
|
|
GetPeriodString() + "]: ";
|
|
string fullMsg = prefix + message;
|
|
|
|
if(InpAlertPopup)
|
|
Alert(fullMsg);
|
|
|
|
if(InpAlertSound)
|
|
PlaySound("alert.wav");
|
|
|
|
if(InpAlertPush)
|
|
SendNotification(fullMsg);
|
|
|
|
if(InpAlertEmail)
|
|
SendMail("BB+RSI Signal", fullMsg);
|
|
|
|
Print(fullMsg);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Obtener string del período actual |
|
|
//+------------------------------------------------------------------+
|
|
string GetPeriodString()
|
|
{
|
|
switch(Period())
|
|
{
|
|
case PERIOD_M1: return("M1");
|
|
case PERIOD_M5: return("M5");
|
|
case PERIOD_M15: return("M15");
|
|
case PERIOD_M30: return("M30");
|
|
case PERIOD_H1: return("H1");
|
|
case PERIOD_H4: return("H4");
|
|
case PERIOD_D1: return("D1");
|
|
case PERIOD_W1: return("W1");
|
|
case PERIOD_MN1: return("MN1");
|
|
default: return("??");
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//| ═══════════════════════════════════════════════════════════ |
|
|
//| NOTAS DE IMPLEMENTACIÓN MQL4 vs MQL5 |
|
|
//| ═══════════════════════════════════════════════════════════ |
|
|
//| |
|
|
//| Diferencias clave con la versión MQL5: |
|
|
//| |
|
|
//| 1. ACCESO A INDICADORES: |
|
|
//| MQL5: Usa handles (iRSI→handle) + CopyBuffer() |
|
|
//| MQL4: Acceso directo iRSI(NULL,0,period,price,shift) |
|
|
//| Sin handles ni buffers intermedios. |
|
|
//| |
|
|
//| 2. INDEXACIÓN DE SERIES: |
|
|
//| MQL5: Por defecto 0=más antiguo (configurable con |
|
|
//| ArraySetAsSeries) |
|
|
//| MQL4: Siempre 0=barra actual (más reciente) |
|
|
//| Los buffers se indexan igual automáticamente. |
|
|
//| |
|
|
//| 3. ARRAYS DE PRECIOS: |
|
|
//| MQL5: Recibidos como parámetros en OnCalculate() |
|
|
//| MQL4: Accesibles vía arrays predefinidos: |
|
|
//| Open[], High[], Low[], Close[], Time[], Volume[] |
|
|
//| |
|
|
//| 4. COLOREO DE VELAS: |
|
|
//| MQL5: DRAW_COLOR_CANDLES con buffers OHLC + color index |
|
|
//| MQL4: No hay DRAW_COLOR_CANDLES nativo. Se simula con |
|
|
//| objetos gráficos (OBJ_RECTANGLE + OBJ_TREND). |
|
|
//| |
|
|
//| 5. FUNCIONES DE INDICADOR: |
|
|
//| MQL5: SetIndexBuffer(idx, buf, INDICATOR_DATA) |
|
|
//| MQL4: SetIndexBuffer(idx, buf) + SetIndexStyle() |
|
|
//| |
|
|
//| 6. FIDELIDAD NUMÉRICA: |
|
|
//| Ambos usan RSI de Wilder (RMA/SMMA) y desviación estándar |
|
|
//| poblacional (÷N). Los resultados numéricos son idénticos |
|
|
//| entre MQL4 y MQL5 con los mismos datos de entrada. |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//| ═══════════════════════════════════════════════════════════ |
|
|
//| REFERENCIA: PINE SCRIPT ORIGINAL v1.1 (ChartArt) |
|
|
//| ═══════════════════════════════════════════════════════════ |
|
|
//| |
|
|
//| //@version=2 |
|
|
//| strategy("Bollinger + RSI, Double Strategy (by ChartArt) v1.1", |
|
|
//| shorttitle="CA_-_RSI_Bol_Strat_1.1", overlay=true) |
|
|
//| |
|
|
//| ///////////// RSI |
|
|
//| RSIlength = input(6,title="RSI Period Length") |
|
|
//| RSIoverSold = 50 |
|
|
//| RSIoverBought = 50 |
|
|
//| price = close |
|
|
//| vrsi = rsi(price, RSIlength) |
|
|
//| |
|
|
//| ///////////// Bollinger Bands |
|
|
//| BBlength = input(200, minval=1,title="Bollinger Period Length") |
|
|
//| BBmult = 2 |
|
|
//| BBbasis = sma(price, BBlength) |
|
|
//| BBdev = BBmult * stdev(price, BBlength) |
|
|
//| BBupper = BBbasis + BBdev |
|
|
//| BBlower = BBbasis - BBdev |
|
|
//| source = close |
|
|
//| buyEntry = crossover(source, BBlower) |
|
|
//| sellEntry = crossunder(source, BBupper) |
|
|
//| plot(BBbasis, color=aqua,title="BB SMA Basis Line") |
|
|
//| p1 = plot(BBupper, color=silver,title="BB Upper Line") |
|
|
//| p2 = plot(BBlower, color=silver,title="BB Lower Line") |
|
|
//| fill(p1, p2) |
|
|
//| |
|
|
//| ///////////// Colors |
|
|
//| switch1=input(true, title="Enable Bar Color?") |
|
|
//| switch2=input(true, title="Enable Background Color?") |
|
|
//| TrendColor = RSIoverBought and (price[1] > BBupper and |
|
|
//| price < BBupper) and BBbasis < BBbasis[1] ? red |
|
|
//| : RSIoverSold and (price[1] < BBlower and |
|
|
//| price > BBlower) and BBbasis > BBbasis[1] ? green |
|
|
//| : na |
|
|
//| barcolor(switch1?TrendColor:na) |
|
|
//| bgcolor(switch2?TrendColor:na,transp=50) |
|
|
//| |
|
|
//| ///////////// RSI + Bollinger Bands Strategy |
|
|
//| if (not na(vrsi)) |
|
|
//| if (crossover(vrsi, RSIoverSold) and |
|
|
//| crossover(source, BBlower)) |
|
|
//| strategy.entry("RSI_BB_L", strategy.long, |
|
|
//| stop=BBlower, oca_type=...cancel, |
|
|
//| comment="RSI_BB_L") |
|
|
//| else |
|
|
//| strategy.cancel(id="RSI_BB_L") |
|
|
//| if (crossunder(vrsi, RSIoverBought) and |
|
|
//| crossunder(source, BBupper)) |
|
|
//| strategy.entry("RSI_BB_S", strategy.short, |
|
|
//| stop=BBupper, oca_type=...cancel, |
|
|
//| comment="RSI_BB_S") |
|
|
//| else |
|
|
//| strategy.cancel(id="RSI_BB_S") |
|
|
//| |
|
|
//+------------------------------------------------------------------+ |