PinBar Detector [Mr_Zed]
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © MR_zed

// This PineScript indicator is based on the original MQ4 indicator from EarnForex (https://www.earnforex.com/metatrader-indicators/Pinbar-Detector/). 
// The indicator has been converted and optimized for use in PineScript for use on trading platforms such as TradingView.
// While the core logic remains the same, some modifications have been made to improve the performance and functionality of the indicator.
// Please note that the original strategy and its code are property of EarnForex and protected 

//@version=5
indicator(title="PinBar Detector [Mr_Zed]",overlay = true)


//============================================================================
//                      Settings
//===========================================================================

UseAlerts = input(true, "UseAlerts (default = true) ",tooltip=" tells the indicator to issue platform alert with sound on Pinbar detection.")
UseCustomSettings = input(false, "UseCustomSettings (default = false) ",tooltip=" tells the indicator to use custom Pinbar detection parameters described below.")
CustomMaxNoseBodySize = input(0.33, "CustomMaxNoseBodySize (default = 0.33) ",tooltip=" maximum allowed body/length ratio for the Nose bar.")
CustomNoseBodyPosition = input(0.4, "CustomNoseBodyPosition (default = 0.4) ",tooltip=" Nose body should be positioned in the top (bottom for bearish pattern) part of the Nose bar.")
CustomLeftEyeOppositeDirection = input(true, "CustomLeftEyeOppositeDirection (default = true) ",tooltip=" tells the indicator that the Left Eye bar should be bearish for bullish Pinbar, and bullish for bearish Pinbar.")
CustomNoseSameDirection = input(false, "CustomNoseSameDirection (default = true) ",tooltip=" tells the indicator that the Nose bar should be of the same direction as the pattern itself.")
CustomNoseBodyInsideLeftEyeBody = input(false, "CustomNoseBodyInsideLeftEyeBody (default = false) ",tooltip=" tells the indicator that the Nose body should be inside the Left Eye body.")
CustomLeftEyeMinBodySize = input(0.1, "CustomLeftEyeMinBodySize (default = 0.1) ",tooltip=" minimum size of the Left Eye body relative to the bar length.")
CustomNoseProtruding = input(0.5, "CustomNoseProtruding (default = 0.5) ",tooltip=" minimum protrusion of the Nose bar relative to the bar length.")
CustomNoseBodyToLeftEyeBody = input(1, "CustomNoseBodyToLeftEyeBody (default = 1) ",tooltip=" maximum size of the Nose body relative to the Left eye body.")
CustomNoseLengthToLeftEyeLength = input(0, "CustomNoseLengthToLeftEyeLength (default = 0) ",tooltip=" minimum Nose length relative to the Left Eye length.")
CustomLeftEyeDepth = input(0.1, "CustomLeftEyeDepth (default = 0.1) ",tooltip=" minimum depth of the Left Eye relative to its length. Depth is difference with Nose's back.")
CustomMinimumNoseLength = input(1, "CustomMinimumNoseLength (default = 1) ",tooltip=" Minimum nose candlestick length in points.")

//============================================================================
//                      Consts
//===========================================================================

int    LastBars = 0
float MaxNoseBodySize = 0.33
float NoseBodyPosition = 0.4
bool   LeftEyeOppositeDirection = true
bool   NoseSameDirection = false
bool   NoseBodyInsideLeftEyeBody = false
float LeftEyeMinBodySize = 0.1
float NoseProtruding = 0.5
float NoseBodyToLeftEyeBody = 1
float NoseLengthToLeftEyeLength = 0
float LeftEyeDepth = 0.1
float    MinimumCandlestickLength = 1

BearishPinbar = false
BullishPinbar = false

if UseCustomSettings
    MaxNoseBodySize := CustomMaxNoseBodySize
    NoseBodyPosition := CustomNoseBodyPosition
    LeftEyeOppositeDirection := CustomLeftEyeOppositeDirection
    NoseSameDirection := CustomNoseSameDirection
    LeftEyeMinBodySize := CustomLeftEyeMinBodySize
    NoseProtruding := CustomNoseProtruding
    NoseBodyToLeftEyeBody := CustomNoseBodyToLeftEyeBody
    NoseLengthToLeftEyeLength := CustomNoseLengthToLeftEyeLength
    LeftEyeDepth := CustomLeftEyeDepth
    MinimumCandlestickLength := CustomMinimumNoseLength

float NoseLength = 0.0
float NoseBody = 0.0
float LeftEyeBody = 0.0
float LeftEyeLength = 0.0
//============================================================================
//                      Functions
//===========================================================================

SendAlert(message) => 
    if UseAlerts
        alert(message,alert.freq_once_per_bar_close)

//============================================================================
//                      Pin Bar Detection
//===========================================================================

_Point = syminfo.pointvalue

// Left Eye and Nose bars' parameters.
NoseLength := high - low

if (NoseLength == 0) 
    NoseLength := _Point

LeftEyeLength := high[1] - low[1]

if (LeftEyeLength == 0) 
    LeftEyeLength := _Point

NoseBody := math.abs(open - close)

if (NoseBody == 0) 
    NoseBody := _Point

LeftEyeBody := math.abs(open[1] - close[1])

if (LeftEyeBody == 0) 
    LeftEyeBody := _Point


// Bearish Pinbar
if (high - high[1] >= NoseLength * NoseProtruding) // Nose protrusion
	if (NoseBody / NoseLength <= MaxNoseBodySize) // Nose body to candle length ratio
		if (1 - (high - math.max(open, close)) / NoseLength < NoseBodyPosition) // Nose body position in bottom part of the bar
			if ((not LeftEyeOppositeDirection) or (close[1] > open[1])) // Left Eye bullish if required
				if ((not NoseSameDirection) or (close < open)) // Nose bearish if required
					if (LeftEyeBody / LeftEyeLength  >= LeftEyeMinBodySize) // Left eye body to candle length ratio
						if ((math.max(open, close) <= high[1]) and (math.min(open, close) >= low[1])) // Nose body inside Left Eye bar
							if (NoseBody / LeftEyeBody <= NoseBodyToLeftEyeBody) // Nose body to Left Eye body ratio
								if (NoseLength / LeftEyeLength >= NoseLengthToLeftEyeLength) // Nose length to Left Eye length ratio
									if (low - low[1] >= LeftEyeLength * LeftEyeDepth)  // Left Eye low is low enough
										if ((not NoseBodyInsideLeftEyeBody) or ((math.max(open, close) <= math.max(open[1], close[1])) and (math.min(open, close) >= math.min(open[1], close[1])))) // Nose body inside Left Eye body if required
                                            BearishPinbar := true
                                            SendAlert("Bearish")
// Bullish Pinbar
if (low[1] - low >= NoseLength * NoseProtruding) // Nose protrusion
    if (NoseBody / NoseLength <= MaxNoseBodySize) // Nose body to candle length ratio
        if (1 - (math.min(open, close) - low) / NoseLength < NoseBodyPosition) // Nose body position in top part of the bar
            if ((not LeftEyeOppositeDirection) or (close[1] < open[1])) // Left Eye bearish if required
                if ((not NoseSameDirection) or (close > open)) // Nose bullish if required
                    if (LeftEyeBody / LeftEyeLength >= LeftEyeMinBodySize) // Left eye body to candle length ratio
                        if ((math.max(open, close) <= high[1]) and (math.min(open, close) >= low[1])) // Nose body inside Left Eye bar
                            if (NoseBody / LeftEyeBody <= NoseBodyToLeftEyeBody) // Nose body to Left Eye body ratio
                                if (NoseLength / LeftEyeLength >= NoseLengthToLeftEyeLength) // Nose length to Left Eye length ratio
                                    if (high[1] - high >= LeftEyeLength * LeftEyeDepth) // Left Eye high is high enough
                                        if ((not NoseBodyInsideLeftEyeBody) or ((math.max(open, close) <= math.max(open[1], close[1])) and (math.min(open, close) >= math.min(open[1], close[1])))) // Nose body inside Left Eye body if required
                                            BullishPinbar := true
                                            SendAlert("Bullish")
            

plotshape(BearishPinbar, location=location.abovebar, style=shape.triangledown, size=size.normal, color=color.rgb(255, 0, 0),display=display.all)
plotshape(BullishPinbar, location=location.belowbar, style=shape.triangleup, size=size.normal, color=color.green,display=display.all)
