//| DarkPoint_MQL4.mq4 |
//| VERSIÓN SIN REPAINTING CORREGIDA|
//+------------------------------------------------------------------+
#property copyright "Dark Point No-Repaint"
#property link ""
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2
//--- Plot Buy Point
#property indicator_label1 "Buy Signal"
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrAqua
#property indicator_style1 STYLE_SOLID
#property indicator_width1 3
//--- Plot Sell Point
#property indicator_label2 "Sell Signal"
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_style2 STYLE_SOLID
#property indicator_width2 3
//--- Input Parameters
input string InpObjectsPrefix = "DP_";
input int InpDarkPointPeriod = 50;
input int InpVolatilityFactor = 3;
input double InpSensitivityMultiplier = 1.0;
input int InpATRPeriods = 18;
input bool InpEnableTP1 = true;
input double InpTP1Multiplier = 0.4;
input bool InpEnableTP2 = true;
input double InpTP2Multiplier = 1.0;
input bool InpEnableTP3 = true;
input double InpTP3Multiplier = 3.2;
input bool InpEnableSL1 = true;
input double InpSL1Multiplier = 1.6;
input bool InpEnableSL2 = true;
input double InpSL2Multiplier = 3.2;
input int InpLinesLength = 10;
//--- Indicator Buffers
double BuySignalBuffer[];
double SellSignalBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, BuySignalBuffer);
SetIndexBuffer(1, SellSignalBuffer);
SetIndexArrow(0, 233);
SetIndexArrow(1, 234);
SetIndexEmptyValue(0, EMPTY_VALUE);
SetIndexEmptyValue(1, EMPTY_VALUE);
SetIndexLabel(0, "Buy Signal");
SetIndexLabel(1, "Sell Signal");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, InpObjectsPrefix);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration 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[])
{
if(rates_total < InpDarkPointPeriod + InpATRPeriods)
return(0);
//--- Calculate ATR manualmente
double atrBuffer[];
ArrayResize(atrBuffer, rates_total);
ArraySetAsSeries(atrBuffer, true);
for(int i = 0; i < rates_total; i++)
{
if(i < InpATRPeriods)
{
atrBuffer = 0;
continue;
}
double sum = 0;
for(int j = 0; j < InpATRPeriods; j++)
{
double tr = high[i-j] - low[i-j];
sum += tr;
}
atrBuffer = sum / InpATRPeriods;
}
//--- Calculate base price (SMA of typical price)
double basePrice[];
ArrayResize(basePrice, rates_total);
ArraySetAsSeries(basePrice, true);
for(int i = 0; i < rates_total; i++)
{
if(i < InpDarkPointPeriod)
{
basePrice = 0;
continue;
}
double sum = 0;
for(int j = 0; j < InpDarkPointPeriod; j++)
{
double typicalPrice = (high[i-j] + low[i-j] + close[i-j]) / 3.0;
sum += typicalPrice;
}
basePrice = sum / InpDarkPointPeriod;
}
//--- Calculate bands and detect signals
// EMPEZAR desde prev_calculated-1 para no recalcular todo, pero SIN incluir la vela actual
int start = MathMax(prev_calculated - 1, InpDarkPointPeriod);
// IMPORTANTE: Solo procesar hasta rates_total-1 (excluir la vela actual i=0)
for(int i = start; i < rates_total - 1; i++) // <--- AQUÍ ESTÁ LA CLAVE: rates_total - 1
{
BuySignalBuffer = EMPTY_VALUE;
SellSignalBuffer = EMPTY_VALUE;
if(basePrice == 0 || atrBuffer == 0)
continue;
double range = InpVolatilityFactor * atrBuffer * InpSensitivityMultiplier;
double upperBand = basePrice + range;
double lowerBand = basePrice[i] - range;
// Verificar cruce con la vela ANTERIOR (i+1) para evitar repainting
if(i + 1 < rates_total)
{
double prevHigh = high[i + 1];
double prevLow = low[i + 1];
// Buy Signal: Price touches or crosses lower band
if(prevLow >= lowerBand && low[i] <= lowerBand)
{
BuySignalBuffer[i] = low[i] - (atrBuffer[i] * 0.5);
DrawTPLines(close[i], atrBuffer[i], "BUY", time[i], i, time, rates_total);
}
// Sell Signal: Price touches or crosses upper band
if(prevHigh <= upperBand && high[i] >= upperBand)
{
SellSignalBuffer[i] = high[i] + (atrBuffer[i] * 0.5);
DrawTPLines(close[i], atrBuffer[i], "SELL", time[i], i, time, rates_total);
}
}
}
// Limpiar la vela actual (i=0) para que nunca tenga señal
BuySignalBuffer[0] = EMPTY_VALUE;
SellSignalBuffer[0] = EMPTY_VALUE;
return(rates_total);
}
//+------------------------------------------------------------------+
//| Draw TP/SL Lines (hacia atrás) |
//+------------------------------------------------------------------+
void DrawTPLines(double price, double atrValue, string signalType, datetime signalTime, int signalIndex, const datetime &time[], int rates_total)
{
string prefix = InpObjectsPrefix;
color buyColor = clrLime;
color sellColor = clrRed;
string timeStr = TimeToString(signalTime, TIME_DATE|TIME_MINUTES);
// Calcular tiempo de inicio (10 velas hacia atrás desde la señal)
int startIndex = signalIndex + InpLinesLength;
if(startIndex >= rates_total) startIndex = rates_total - 1;
datetime startTime = time[startIndex];
if(signalType == "BUY")
{
if(InpEnableTP1)
DrawTrendLine(prefix + "TP1_" + timeStr, startTime, price + (atrValue * InpTP1Multiplier), signalTime, price + (atrValue * InpTP1Multiplier), buyColor, "TP 1");
if(InpEnableTP2)
DrawTrendLine(prefix + "TP2_" + timeStr, startTime, price + (atrValue * InpTP2Multiplier), signalTime, price + (atrValue * InpTP2Multiplier), buyColor, "TP 2");
if(InpEnableTP3)
DrawTrendLine(prefix + "TP3_" + timeStr, startTime, price + (atrValue * InpTP3Multiplier), signalTime, price + (atrValue * InpTP3Multiplier), buyColor, "TP 3");
if(InpEnableSL1)
DrawTrendLine(prefix + "SL1_" + timeStr, startTime, price - (atrValue * InpSL1Multiplier), signalTime, price - (atrValue * InpSL1Multiplier), sellColor, "SL 1");
if(InpEnableSL2)
DrawTrendLine(prefix + "SL2_" + timeStr, startTime, price - (atrValue * InpSL2Multiplier), signalTime, price - (atrValue * InpSL2Multiplier), sellColor, "SL 2");
}
else
{
if(InpEnableTP1)
DrawTrendLine(prefix + "TP1_" + timeStr, startTime, price - (atrValue * InpTP1Multiplier), signalTime, price - (atrValue * InpTP1Multiplier), buyColor, "TP 1");
if(InpEnableTP2)
DrawTrendLine(prefix + "TP2_" + timeStr, startTime, price - (atrValue * InpTP2Multiplier), signalTime, price - (atrValue * InpTP2Multiplier), buyColor, "TP 2");
if(InpEnableTP3)
DrawTrendLine(prefix + "TP3_" + timeStr, startTime, price - (atrValue * InpTP3Multiplier), signalTime, price - (atrValue * InpTP3Multiplier), buyColor, "TP 3");
if(InpEnableSL1)
DrawTrendLine(prefix + "SL1_" + timeStr, startTime, price + (atrValue * InpSL1Multiplier), signalTime, price + (atrValue * InpSL1Multiplier), sellColor, "SL 1");
if(InpEnableSL2)
DrawTrendLine(prefix + "SL2_" + timeStr, startTime, price + (atrValue * InpSL2Multiplier), signalTime, price + (atrValue * InpSL2Multiplier), sellColor, "SL 2");
}
}
//+------------------------------------------------------------------+
//| Draw Trend Line - MQL4 |
//+------------------------------------------------------------------+
void DrawTrendLine(string name, datetime time1, double price1, datetime time2, double price2, color clr, string label)
{
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, OBJ_TREND, 0, time1, price1, time2, price2);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(0, name, OBJPROP_RAY_LEFT, false);
ObjectSetString(0, name, OBJPROP_TEXT, label);
}
else
{
ObjectSetInteger(0, name, OBJPROP_TIME, 0, (long)time1);
ObjectSetInteger(0, name, OBJPROP_TIME, 1, (long)time2);
ObjectSetDouble(0, name, OBJPROP_PRICE, 0, price1);
ObjectSetDouble(0, name, OBJPROP_PRICE, 1, price2);
}
}
//+-----------------------------------------------------------------