NUNA/Logs/Indicators/Downloads/Pinbar Detector.mq5
2026-01-06 05:44:21 +00:00

237 lines
No EOL
12 KiB
MQL5

#property indicator_chart_window
#property indicator_buffers 4 // Utilizes 4 buffers (2 for data, 2 for colors)
#property indicator_plots 2 // Two plots: one for upward pinbars, one for downward pinbars
// Plot for Upward Pinbar (Upward Arrow)
#property indicator_type1 DRAW_COLOR_ARROW
#property indicator_color1 clrLime
#property indicator_width1 2
#property indicator_label1 "Upward Pinbar"
// Plot for Downward Pinbar (Downward Arrow)
#property indicator_type2 DRAW_COLOR_ARROW
#property indicator_color2 clrRed
#property indicator_width2 2
#property indicator_label2 "Downward Pinbar"
input int BarCount = 0; // BarCount - number of bars to process, 0 = all bars.
input int ArrowOffset = 5; // ArrowOffset - larger values increase distance from arrows to candles.
input bool EnableAlerts = true; // Enable Alerts
input bool EnableEmailAlerts = false; // Enable Email Alerts (set up SMTP in Tools->Options->Emails)
input bool EnablePushNotifications = false; // Enable Push Notifications (set up in Tools->Options->Notifications)
input bool UseCustomConfig = false; // Use Custom Configuration - if true, apply parameters below:
input double CustomMaxTailBodyRatio = 0.33; // Max ratio of tail body to candle length
input double CustomTailBodyPlacement = 0.4; // Position of body in tail candle (e.g., top/bottom 40%)
input bool CustomPrevCandleOpposite = true; // true = Previous candle direction opposes pattern
input bool CustomTailSameDirection = false; // true = Tail candle direction matches pattern
input bool CustomTailBodyWithinPrevBody = false; // true = Tail body is within previous candle body
input double CustomPrevCandleMinBodyRatio = 0.1; // Min ratio of previous candle body to its length
input double CustomTailProtrusion = 0.5; // Min protrusion of tail candle relative to its length
input double CustomTailBodyToPrevBody = 1; // Max ratio of tail body to previous candle body
input double CustomTailLengthToPrevLength = 0; // Min ratio of tail candle length to previous candle length
input double CustomPrevCandleDepth = 0.1; // Min depth of previous candle relative to its length
input int CustomMinTailLength = 1; // Minimum length of tail candle in points
// Indicator buffers
double UpwardPinbar[];
double UpwardColor[];
double DownwardPinbar[];
double DownwardColor[];
// Global variables
int LastProcessedBars = 0;
double MaxTailBodyRatio = 0.33;
double TailBodyPlacement = 0.4;
bool PrevCandleOpposite = true;
bool TailSameDirection = false;
bool TailBodyWithinPrevBody = false;
double PrevCandleMinBodyRatio = 0.1;
double TailProtrusion = 0.5;
double TailBodyToPrevBody = 1;
double TailLengthToPrevLength = 0;
double PrevCandleDepth = 0.1;
int MinCandleLength = 1;
void OnInit()
{
// Configure buffers
SetIndexBuffer(0, UpwardPinbar, INDICATOR_DATA);
SetIndexBuffer(1, UpwardColor, INDICATOR_COLOR_INDEX);
SetIndexBuffer(2, DownwardPinbar, INDICATOR_DATA);
SetIndexBuffer(3, DownwardColor, INDICATOR_COLOR_INDEX);
ArraySetAsSeries(UpwardPinbar, true);
ArraySetAsSeries(UpwardColor, true);
ArraySetAsSeries(DownwardPinbar, true);
ArraySetAsSeries(DownwardColor, true);
// Set up Upward Pinbar plot (Up Arrow, code 233)
PlotIndexSetInteger(0, PLOT_ARROW, 233);
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetString(0, PLOT_LABEL, "Upward Pinbar");
// Set up Downward Pinbar plot (Down Arrow, code 234)
PlotIndexSetInteger(1, PLOT_ARROW, 234);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetString(1, PLOT_LABEL, "Downward Pinbar");
if (UseCustomConfig)
{
MaxTailBodyRatio = CustomMaxTailBodyRatio;
TailBodyPlacement = CustomTailBodyPlacement;
PrevCandleOpposite = CustomPrevCandleOpposite;
TailSameDirection = CustomTailSameDirection;
PrevCandleMinBodyRatio = CustomPrevCandleMinBodyRatio;
TailProtrusion = CustomTailProtrusion;
TailBodyToPrevBody = CustomTailBodyToPrevBody;
TailLengthToPrevLength = CustomTailLengthToPrevLength;
PrevCandleDepth = CustomPrevCandleDepth;
MinCandleLength = CustomMinTailLength;
}
}
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 &tickvolume[],
const long &volume[],
const int &spread[])
{
int BarsToProcess;
double TailLength, TailBody, PrevCandleBody, PrevCandleLength;
ArraySetAsSeries(Open, true);
ArraySetAsSeries(High, true);
ArraySetAsSeries(Low, true);
ArraySetAsSeries(Close, true);
if (LastProcessedBars == rates_total) return rates_total;
BarsToProcess = rates_total - LastProcessedBars;
if ((BarCount > 0) && (BarsToProcess > BarCount)) BarsToProcess = BarCount;
LastProcessedBars = rates_total;
if (BarsToProcess == rates_total) BarsToProcess--;
// Initialize buffers
UpwardPinbar[0] = EMPTY_VALUE;
DownwardPinbar[0] = EMPTY_VALUE;
for (int i = BarsToProcess; i >= 1; i--)
{
// Reset buffers for each bar
UpwardPinbar[i] = EMPTY_VALUE;
DownwardPinbar[i] = EMPTY_VALUE;
// Skip if no previous candle exists for the leftmost bar
if (i == rates_total - 1) continue;
// Parameters for tail and previous candles
TailLength = High[i] - Low[i];
if (TailLength < MinCandleLength * _Point) continue; // Tail candle too short
if (TailLength == 0) TailLength = _Point;
PrevCandleLength = High[i + 1] - Low[i + 1];
if (PrevCandleLength == 0) PrevCandleLength = _Point;
TailBody = MathAbs(Open[i] - Close[i]);
if (TailBody == 0) TailBody = _Point;
PrevCandleBody = MathAbs(Open[i + 1] - Close[i + 1]);
if (PrevCandleBody == 0) PrevCandleBody = _Point;
// Downward Pinbar
if (High[i] - High[i + 1] >= TailLength * TailProtrusion) // Tail protrusion check
{
if (TailBody / TailLength <= MaxTailBodyRatio) // Body-to-candle length ratio
{
if (1 - (High[i] - MathMax(Open[i], Close[i])) / TailLength < TailBodyPlacement) // Body in lower part
{
if (!PrevCandleOpposite || Close[i + 1] > Open[i + 1]) // Previous candle bullish if required
{
if (!TailSameDirection || Close[i] < Open[i]) // Tail bearish if required
{
if (PrevCandleBody / PrevCandleLength >= PrevCandleMinBodyRatio) // Previous candle body ratio
{
if ((MathMax(Open[i], Close[i]) <= High[i + 1]) && (MathMin(Open[i], Close[i]) >= Low[i + 1])) // Tail body within previous candle
{
if (TailBody / PrevCandleBody <= TailBodyToPrevBody) // Tail body to previous body ratio
{
if (TailLength / PrevCandleLength >= TailLengthToPrevLength) // Tail length to previous length ratio
{
if (Low[i] - Low[i + 1] >= PrevCandleLength * PrevCandleDepth) // Previous candle depth check
{
if (!TailBodyWithinPrevBody || ((MathMax(Open[i], Close[i]) <= MathMax(Open[i + 1], Close[i + 1])) && (MathMin(Open[i], Close[i]) >= MathMin(Open[i + 1], Close[i + 1])))) // Tail body within previous body
{
DownwardPinbar[i] = High[i] + ArrowOffset * _Point + TailLength / 5;
DownwardColor[i] = 0; // Use first color (clrRed)
if (i == 1) SendAlert("Downward"); // Alert for latest complete bar
}
}
}
}
}
}
}
}
}
}
}
// Upward Pinbar
if (Low[i + 1] - Low[i] >= TailLength * TailProtrusion) // Tail protrusion check
{
if (TailBody / TailLength <= MaxTailBodyRatio) // Body-to-candle length ratio
{
if (1 - (MathMin(Open[i], Close[i]) - Low[i]) / TailLength < TailBodyPlacement) // Body in upper part
{
if (!PrevCandleOpposite || Close[i + 1] < Open[i + 1]) // Previous candle bearish if required
{
if (!TailSameDirection || Close[i] > Open[i]) // Tail bullish if required
{
if (PrevCandleBody / PrevCandleLength >= PrevCandleMinBodyRatio) // Previous candle body ratio
{
if ((MathMax(Open[i], Close[i]) <= High[i + 1]) && (MathMin(Open[i], Close[i]) >= Low[i + 1])) // Tail body within previous candle
{
if (TailBody / PrevCandleBody <= TailBodyToPrevBody) // Tail body to previous body ratio
{
if (TailLength / PrevCandleLength >= TailLengthToPrevLength) // Tail length to previous length ratio
{
if (High[i + 1] - High[i] >= PrevCandleLength * PrevCandleDepth) // Previous candle height check
{
if (!TailBodyWithinPrevBody || ((MathMax(Open[i], Close[i]) <= MathMax(Open[i + 1], Close[i + 1])) && (MathMin(Open[i], Close[i]) >= MathMin(Open[i + 1], Close[i + 1])))) // Tail body within previous body
{
UpwardPinbar[i] = Low[i] - ArrowOffset * _Point - TailLength / 5;
UpwardColor[i] = 0; // Use first color (clrLime)
if (i == 1) SendAlert("Upward"); // Alert for latest complete bar
}
}
}
}
}
}
}
}
}
}
}
}
return rates_total;
}
string TimeframeToString(ENUM_TIMEFRAMES P)
{
return StringSubstr(EnumToString(P), 7);
}
void SendAlert(string direction)
{
string period = TimeframeToString(_Period);
if (EnableAlerts)
{
Alert(direction + " Pinbar detected on ", _Symbol, " @ ", period);
PlaySound("alert.wav");
}
if (EnableEmailAlerts)
SendMail(_Symbol + " @ " + period + " - " + direction + " Pinbar", direction + " Pinbar detected on " + _Symbol + " @ " + period + " as of " + TimeToString(TimeCurrent()));
if (EnablePushNotifications)
SendNotification(direction + " Pinbar detected on " + _Symbol + " @ " + period + " as of " + TimeToString(TimeCurrent()));
}
//+------------------------------------------------------------------+