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

//@version=5

// @description The library consists of three sections:
// @Technical Analysis Functions - A collection of tools commonly used by day traders
// @Trading Setup Filters Functions - A number of filters that help day traders to screen trading signals
// @Candlestick Pattern Detection Functions - To detect different candelstick patterns that are used in day trading setups
// \nNote that this would have been not possible without the help of @ZenAndTheArtOfTrading as I build-up this library after completing his pine script mastery course so big thanks to him
library("AbdulLibrary")

// --- BEGIN Technical Analysis Functions {

// @function Calculates Daily Pivot Point and Fibonacci Key Levels
// @param preDayClose The previous day candle close
// @param preDayHigh The previous day candle high
// @param preDayLow The previous day candle low
// @returns Returns Daily Pivot Point and Fibonacci Key Levels as a tuple
export fibLevels(float preDayClose, float preDayHigh, float preDayLow) =>
    dPP = (preDayHigh + preDayLow + preDayClose) / 3
    r1 = (2 * dPP) - preDayLow
    r2 = dPP + (preDayHigh - preDayLow)
    r3 = dPP + (2 * (preDayHigh - preDayLow))
    s1 = (2* dPP) - preDayHigh
    s2 = dPP - (preDayHigh - preDayLow)
    s3 = dPP - (2 * (preDayHigh - preDayLow))
    // returns the dPP, r1, r2, r3, s1, s2 and s3 as a tuple
    [dPP, r1, r2, r3, s1, s2, s3]
    
// @function Calculates Fibonacci Levels in Bullish move
// @param canHigh The high of the move
// @param canLow The low of the move
// @param fibLevel The Fib level as % you want to calculate
// @returns Returns The Fib level for the Bullish move
export bullishFib(float moveHigh, float moveLow, float fibLevel = 0.382) =>
    (moveLow - moveHigh) * fibLevel + moveHigh
    
// @function Calculates Fibonacci Levels in Bearish move
// @param canHigh The high of the move
// @param canLow The low of the move
// @param fibLevel The Fib level as % you want to calculate
// @returns Returns The Fib level for the Bearish move
export bearishFib(float moveHigh, float moveLow, float fibLevel = 0.382) =>
    (moveHigh - moveLow) * fibLevel + moveLow
    
// Originalky this is an indicator created by @DavidBrunet and modified by @FX365_Thailand, but I optimized it into shorter code
// @function Plot Horizontal line at round number
// @param market The markets the user is trading
// @param numRoundNumbers How many round numbers to be plotted above and below current price
// @returns Returns Na - Plot horizontal line at round number
export plotRoundNumber(string market, int numRoundNumbers) =>
    // Define the steps based on the market you trade ie Forex, USOIL, Gold Crypto etc...
    var step = switch market
        "Forex"     => syminfo.mintick*500
        "Crypto"    => syminfo.mintick*500
        "XAUUSD"    => syminfo.mintick*5000
        "XAGUSD"    => syminfo.mintick*50000
        "USOIL"     => syminfo.mintick*5000
        "Gold"      => syminfo.mintick*500
        "Silver"    => syminfo.mintick*500
        => syminfo.mintick*500
        
    // Drawing RN lines based on user inputs of market and number of lines required
    if barstate.islast
        for counter = 0 to numRoundNumbers -1
            stepUp = math.ceil(close / step) * step + (counter * step)
            line.new(bar_index, stepUp, bar_index - 1, stepUp, xloc=xloc.bar_index, extend=extend.both, style = line.style_dotted, color = color.gray)
            stepDown = math.floor(close / step) * step - (counter * step)
            line.new(bar_index, stepDown, bar_index - 1, stepDown, xloc=xloc.bar_index, extend=extend.both, style = line.style_dotted, color = color.gray)
    
// @function Calculates the size of candle (high - low) in points
// @returns Returns candle size in points
export getCandleSize() =>
    math.abs(high - low) / syminfo.mintick
    
// @function Calculates the size of candle (close - open) in points
// @returns Returns candle body size in points
export getCandleBodySize() =>
    math.abs(close - open) / syminfo.mintick
    
// @function Calculates the high wick size of candle in points
// @returns Returns The high wick size of candle in points
export getHighWickSize() =>
    math.abs(high  - (close > open ? close : open)) / syminfo.mintick
    
// @function Calculates the low wick size of candle in points
// @returns Returns The low wick size of candle in points
export getLowWickSize() =>
    math.abs((close > open ? open : close) - low) / syminfo.mintick
    
// @function Calculates the candle body size as % of overall candle size 
// @returns Returns The candle body size as % of overall candle size
export getBodyPercentage() =>
    getCandleBodySize() / getCandleSize()
    

// } END Technical Analysis Functions

// --- BEGIN Trading Setup Filters Functions {
    
// @function Checks if the price has created new swing high over a period of time
// @param period The lookback time we want to check for swing high
// @returns Returns True if the current candle or the previous candle is a swing high
export isSwingHigh(int period) =>
    swingHigh = high == ta.highest(high, period) or high[1] == ta.highest(high, period)
    
// @function Checks if the price has created new swing low over a period of time
// @param period The lookback time we want to check for swing low
// @returns Returns True if the current candle or the previous candle is a swing low
export isSwingLow(int period) =>
    swingLow = low == ta.lowest(low, period) or low[1] == ta.lowest(low, period)

// @function Checks if a doji is a swing high over a period of time
// @param period The lookback time we want to check for swing high
// @returns Returns True if the doji is a swing high
export isDojiSwingHigh(int period) =>
    dojiSwinghigh = high == ta.highest(high, period)

// @function Checks if a doji is a swing low over a period of time
// @param period The lookback time we want to check for swing low
// @returns Returns True if the doji is a swing low
export isDojiSwingLow(int period) =>
    dojiSwingLow = low == ta.lowest(low, period)
    
// @function Checks if a candle has big body compared to ATR
// @param atrFilter Check if user wants to use ATR to filter candle-setup signals
// @param atr The ATR value to be used to compare candle body size
// @param candleBodySize The candle body size 
// @param multiplier The multiplier to be used to compare candle body size
// @returns Returns Boolean true if the candle setup is big
export isBigBody(bool atrFilter = false, float atr, float candleBodySize, float multiplier = 1.0) =>
    if atrFilter
        candleBodySize >= atr * multiplier
    else
        true

// @function Checks if a candle has small body compared to ATR
// @param atrFilter Check if user wants to use ATR to filter candle-setup signals
// @param atr The ATR value to be used to compare candle body size
// @param candleBodySize The candle body size 
// @param multiplier The multiplier to be used to compare candle body size
// @returns Returns Boolean true if the candle setup is small
export isSmallBody(bool atrFilter = false, float atr, float candleBodySize, float multiplier = 0.15) =>
    if atrFilter
        candleBodySize <= atr * multiplier
    else
        true

// } END Trading Setup Filters Functions

// --- BEGIN Candlestick Pattern Detection Functions {
    
// @function Checks if a candle is a hammer based on user input parameters and candle conditions
// @param fibLevel Fib level to base candle body on
// @param colorMatch Checks if user needs for the candel to be green
// @returns Returns Boolean -  True if the candle setup is hammer
export isHammer(float fibLevel = 0.236, bool colorFilter = false) =>
    // Checks if candle body is above specified fib level
    bullFib = bullishFib(high, low, fibLevel)
    // Determine which price source closes or opens lowest
    lowestBody  = close < open ? close : open
    // Determine if we have a valid hammer or shooting star candle
    hammer = lowestBody >= bullFib and (not colorFilter or close > open)
    
// @function Checks if a candle is a shooting star based on user input parameters and candle conditions
// @param fibLevel Fib level to base candle body on
// @param colorMatch Checks if user needs for the candel to be red
// @returns Returns Boolean -  True if the candle setup is star
export isShootingStar(float fibLevel = 0.236, bool colorFilter = false) =>
    // Checks if candle body is above specified fib level
    bearFib = bearishFib(high, low, fibLevel)
    // Determine which price source closes or opens highest
    highestBody = close > open ? close : open
    // Determine if we have a valid shooting star candle
    shootingStar = highestBody <= bearFib and (not colorFilter or close < open)
    
// @function Check if a candle is a bullish engulfing candle
// @param allowance How many points the candle open is allowed to be off (To allow for gaps)
// @param period The lookback period for swing low check
// @returns Boolean - True only if the candle is a bullish engulfing candle 
export isBullEngCan(float allowance = 1.0) =>
    check = getCandleBodySize()[0] > getCandleBodySize()[1] and close[1] < open[1] and open <= (close[1] + allowance) and close >= (open[1] + allowance)
    bullEngCan = check
    
// @function Check if a candle is a bearish engulfing candle
// @param allowance How many points the candle open is allowed to be off (To allow for gaps)
// @param period The lookback period for swing high check
// @returns Boolean - True only if the candle is a bearish engulfing candle 
export isBearEngCan(float allowance = 1.0) =>
    check = getCandleBodySize()[0] > getCandleBodySize()[1] and close[1] > open[1] and open >= (close[1] - allowance) and close <= (open[1] - allowance)
    bearEngCan = check
    
// @function Check if a candle is a bullish doji candle
// @param maxSize Maximum candle body size as % of total candle size to be considered as doji
// @param wickLimit Maximum wick size of one wick compared to the other wick
// @param colorFilter Checks if the doji is green
// @returns Boolean - True if the candle is a bullish doji
export isBullDoji(float maxSize = 0.2, float wicksLimit = 2, bool colorFilter = false) =>
    doji = getHighWickSize() <= getLowWickSize() * wicksLimit and getLowWickSize() <= getHighWickSize() * wicksLimit and getBodyPercentage() <= maxSize and (not colorFilter or close > open)
    
// @function Check if a candle is a bearish doji candle
// @param maxSize Maximum candle body size as % of total candle size to be considered as doji
// @param wickLimit Maximum wick size of one wick compared to the other wick
// @param colorFilter Checks if the doji is red
// @returns Boolean - True if the candle is a bearish doji
export isBearDoji(float maxSize = 0.2, float wicksLimit = 2,bool colorFilter = false) =>
    doji = getHighWickSize() <= getLowWickSize() * wicksLimit and getLowWickSize() <= getHighWickSize() * wicksLimit and getBodyPercentage() <= maxSize and (not colorFilter or close < open)
    
// @function Check if a candle is a bullish outside bar
// @returns Boolean - True if the candle is a bullish outside bar
export isBullOutBar() =>
    check = getCandleSize()[0] > getCandleSize()[1] and close[1] < open[1] and high > high[1] and low < low[1]
    bullOutBar = check

// @function Check if a candle is a bearish outside bar
// @returns Boolean - True if the candle is a bearish outside bar
isBearOutBar() =>
    // check if current candle size is bigger than previous candle size
    check = getCandleSize()[0] > getCandleSize()[1] and close[1] > open[1] and high > high[1] and low < low[1]
    bearOutBar = check

// @function Check if a candle is an inside bar
// @returns Returns Boolean - True if a candle is an inside bar
export isInsideBar() =>
    high < high[1] and low > low[1]
    
// } END Candlestick Pattern Detection Functions
