181 lines
6.7 KiB
Plaintext
181 lines
6.7 KiB
Plaintext
#property copyright "Your Name"
|
|
#property link "https://www.yourwebsite.com"
|
|
#property version "1.02"
|
|
#property indicator_chart_window
|
|
#property indicator_buffers 2
|
|
#property indicator_plots 2
|
|
|
|
//--- Input parameters
|
|
input int atr_period = 14; // ATR Period
|
|
input double atr_threshold = 0.0005; // ATR Threshold for Consolidation (e.g., 0.0005 for EURUSD, 5.0 for XAUUSD)
|
|
input int range_period = 20; // Period to check price range
|
|
input double range_multiplier = 2.0; // Price range multiplier (relative to ATR)
|
|
input bool enable_alerts = true; // Enable breakout alerts
|
|
input bool draw_rectangles = true; // Draw rectangles for consolidation zones
|
|
|
|
//--- Indicator buffers
|
|
double UpperBuffer[];
|
|
double LowerBuffer[];
|
|
|
|
//--- Global variables
|
|
int atr_handle = INVALID_HANDLE;
|
|
int zone_count = 0; // For unique rectangle names
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Set indicator buffers
|
|
SetIndexBuffer(0, UpperBuffer, INDICATOR_DATA);
|
|
SetIndexBuffer(1, LowerBuffer, INDICATOR_DATA);
|
|
PlotIndexSetString(0, PLOT_LABEL, "Upper Consolidation");
|
|
PlotIndexSetString(1, PLOT_LABEL, "Lower Consolidation");
|
|
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_LINE);
|
|
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_LINE);
|
|
PlotIndexSetInteger(0, PLOT_LINE_STYLE, STYLE_SOLID);
|
|
PlotIndexSetInteger(1, PLOT_LINE_STYLE, STYLE_SOLID);
|
|
PlotIndexSetInteger(0, PLOT_LINE_COLOR, clrRed);
|
|
PlotIndexSetInteger(1, PLOT_LINE_COLOR, clrBlue);
|
|
|
|
//--- Create ATR handle
|
|
atr_handle = iATR(_Symbol, _Period, atr_period);
|
|
if(atr_handle == INVALID_HANDLE)
|
|
{
|
|
Print("Failed to create ATR handle, error: ", GetLastError());
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Check available bars
|
|
int available_bars = Bars(_Symbol, _Period);
|
|
if(available_bars < range_period + atr_period)
|
|
{
|
|
Print("Insufficient bars: ", available_bars, ", required: ", range_period + atr_period);
|
|
return(INIT_FAILED);
|
|
}
|
|
|
|
//--- Log initialization
|
|
Print("Indicator initialized. Symbol: ", _Symbol, ", Timeframe: ", Period(),
|
|
", ATR Period: ", atr_period, ", Range Period: ", range_period);
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
if(atr_handle != INVALID_HANDLE)
|
|
IndicatorRelease(atr_handle);
|
|
ObjectsDeleteAll(0, "Consolidation_"); // Remove all rectangles
|
|
Print("Indicator deinitialized, reason: ", reason);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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[])
|
|
{
|
|
//--- Ensure enough bars
|
|
if(rates_total < range_period + atr_period)
|
|
{
|
|
Print("Not enough bars: ", rates_total, ", required: ", range_period + atr_period);
|
|
return(0);
|
|
}
|
|
|
|
//--- Set arrays as series
|
|
ArraySetAsSeries(high, true);
|
|
ArraySetAsSeries(low, true);
|
|
ArraySetAsSeries(close, true);
|
|
ArraySetAsSeries(time, true);
|
|
ArraySetAsSeries(UpperBuffer, true);
|
|
ArraySetAsSeries(LowerBuffer, true);
|
|
|
|
//--- Calculate ATR
|
|
double atr[];
|
|
ArraySetAsSeries(atr, true);
|
|
ArrayResize(atr, rates_total);
|
|
if(CopyBuffer(atr_handle, 0, 0, rates_total, atr) <= 0)
|
|
{
|
|
Print("Failed to copy ATR buffer, error: ", GetLastError());
|
|
return(0);
|
|
}
|
|
|
|
//--- Initialize buffers for first calculation
|
|
if(prev_calculated == 0)
|
|
{
|
|
ArrayInitialize(UpperBuffer, EMPTY_VALUE);
|
|
ArrayInitialize(LowerBuffer, EMPTY_VALUE);
|
|
}
|
|
|
|
//--- Loop through bars
|
|
int start = prev_calculated == 0 ? range_period : MathMax(range_period, prev_calculated - 1);
|
|
for(int i = start; i < rates_total && !IsStopped(); i++)
|
|
{
|
|
//--- Calculate range over range_period
|
|
int max_idx = ArrayMaximum(high, i - range_period + 1, range_period);
|
|
int min_idx = ArrayMinimum(low, i - range_period + 1, range_period);
|
|
if(max_idx == -1 || min_idx == -1)
|
|
{
|
|
Print("Error: Invalid array index at bar ", i);
|
|
continue;
|
|
}
|
|
double max_high = high[max_idx];
|
|
double min_low = low[min_idx];
|
|
double price_range = max_high - min_low;
|
|
|
|
//--- Log values for debugging
|
|
if(i == rates_total - 1) // Log only for the latest bar
|
|
{
|
|
Print("Bar ", i, ": ATR = ", DoubleToString(atr[i], _Digits),
|
|
", Price Range = ", DoubleToString(price_range, _Digits),
|
|
", Threshold = ", DoubleToString(atr_threshold, _Digits),
|
|
", Range Limit = ", DoubleToString(atr[i] * range_multiplier, _Digits));
|
|
}
|
|
|
|
//--- Check for consolidation
|
|
if(atr[i] < atr_threshold && price_range < atr[i] * range_multiplier)
|
|
{
|
|
UpperBuffer[i] = max_high;
|
|
LowerBuffer[i] = min_low;
|
|
|
|
//--- Draw rectangle for the consolidation zone
|
|
if(draw_rectangles && i >= range_period)
|
|
{
|
|
string obj_name = "Consolidation_" + IntegerToString(zone_count++) + "_" + TimeToString(time[i]);
|
|
ObjectCreate(0, obj_name, OBJ_RECTANGLE, 0, time[i], max_high, time[i - range_period + 1], min_low);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_COLOR, clrRed);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_STYLE, STYLE_SOLID);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_WIDTH, 1);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_FILL, false);
|
|
ObjectSetInteger(0, obj_name, OBJPROP_BACK, false);
|
|
}
|
|
|
|
//--- Check for breakout (on latest bar only)
|
|
if(enable_alerts && i == rates_total - 1)
|
|
{
|
|
if(close[i] > UpperBuffer[i] && (i == 0 || close[i-1] <= UpperBuffer[i-1]))
|
|
Alert("Breakout Up at ", TimeToString(time[i]), ": Price = ", DoubleToString(close[i], _Digits));
|
|
if(close[i] < LowerBuffer[i] && (i == 0 || close[i-1] >= LowerBuffer[i-1]))
|
|
Alert("Breakout Down at ", TimeToString(time[i]), ": Price = ", DoubleToString(close[i], _Digits));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpperBuffer[i] = EMPTY_VALUE;
|
|
LowerBuffer[i] = EMPTY_VALUE;
|
|
}
|
|
}
|
|
|
|
return(rates_total);
|
|
} |