HammerCandleIndicator
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Wpkenpachi


// @description A hammer candle indicator having the possibility to configure parameters
// @version=5
indicator("HammerCandleIndicator", overlay=true)

float max_candle_body   = input.float(30, 'Max Candle Body Heigh Percent', minval=1, maxval=100)
float max_lowest_shadow = input.float(35, 'Max Loewst Shadow Heigh Percent', minval=1, maxval=100)

// @function                Get how many percent of the first passed value is the second passed value
// @param hundred_percent   float the hundred percent value
// @param value             float the value to discover how many percent is of the first argument
// @returns                 return a float with the percentagem
getIsHowManyPercentOf(float hundred_percent_value, float value) =>
    float result = (value * 100) / hundred_percent_value
    math.round(result, 2)

// @function                Get the candle body range
// @param _open             series float open
// @param _close            series float close
// @returns                 return the range in points
getCandleBodyRange(series float _open = open, series float _close = close) =>
    math.round(math.abs(open - close), 2)

// @function                Get the candle max range
// @param _high             series float _high
// @param _low              series float _low
// @returns                 return the range in points
getCandleMaxRange(series float _high = high, series float _low = low) =>
    math.round(_high - _low, 2)

// @function                Get the candle type (Bullish or bearish)
// @param _open             series float open
// @param _close            series float close
// @returns                 return 1 for Bullish and -1 for Bearish
CandleType(series float _open = open, series float _close = close) =>
    _close > _open ? 1 : -1
    
// @function                This function will say if the hammer is a valid hammer. A hammer cannot have the same height to the shadow at both sides (up and down)
// @param _open             series float open
// @param _close            series float close
// @param _high             series float _high
// @param _low              series float _low
// @returns                 return true if is a valid hammer and false if its not
isValidHammer(series float _open = open, series float _close = close, series float _high = high, series float _low = low) =>
    float shadow_true_height = getCandleMaxRange(_high, _low) - getCandleBodyRange(_open, _close)
    
    float bullish_up_shadow         = _high - _close
    float bullish_down_shadow       = _close - _low
    bool  is_bullish_up_percent     = getIsHowManyPercentOf(shadow_true_height, bullish_up_shadow) <= max_lowest_shadow
    bool  is_bullish_down_percent   = getIsHowManyPercentOf(shadow_true_height, bullish_down_shadow) <= max_lowest_shadow
    
    float bearish_up_shadow     = _high - _open
    float bearish_down_shadow   = _open - _low
    bool  is_bearish_up_percent     = getIsHowManyPercentOf(shadow_true_height, bearish_up_shadow) <= max_lowest_shadow
    bool  is_bearish_down_percent   = getIsHowManyPercentOf(shadow_true_height, bearish_down_shadow) <= max_lowest_shadow
    
    (is_bullish_up_percent or is_bullish_down_percent) or (is_bearish_up_percent or is_bearish_down_percent) ? true : false


// Getting current candle body height
body_range                              = getCandleBodyRange()
// getting candle total range
candle_total_range                      = getCandleMaxRange()
// Check if the candle is a valid hammer in body range and in shadow ranges
is_valid_hammer     = isValidHammer() and (getIsHowManyPercentOf(candle_total_range, body_range) <= max_candle_body)

if is_valid_hammer
    label.new(bar_index, high)
