Bollinger-RSI-Double-Strategy/Bollinger_RSI_Double_Strategy.mq4

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") |
//| |
//+------------------------------------------------------------------+