Smart Money Concepts by WeloTrades

WeloTrades · study · 1776 行 · 点赞 9,232 · TradingView 原页

本页源码来自 TradingView 公开发布的开源脚本,版权归原作者所有, 请遵循其原始许可(Pine 脚本常见 CC BY-NC-SA / MPL-2.0 / MIT)。 本项目仅用于研究检索与许可范围内的移植。

Pine Script

//              ▓▓▓▓  ▓▓▓▓  ▓▓██  ▓▓██                      
//              ▓▓▒▒▓▓▒▒▒▒▓▓▒▒▒▒▓▓▒▒▓▓                      
//              ▓▓▒▒▒▒▒▒░░░░░░▒▒▒▒▒▒▓▓                      
//                ▓▓▒▒▒▒░░░░░░▒▒▒▒▓▓                        
//                 ▓▓▒▒░░░░░░▒▒▓▓                          
//                   ▓▓▒▒▒▒▒▒██   
//                   ▓▓▓▓▓▓▓▓▓▓              
//               ▓▓▓▓▒▒▒▒▒▒▒▒▒▒▓▓▓▓                              ████████ 
//             ▓▓▒▒░░░░▒▒▒▒▒▒▒▒▒▒▒▒▓▓                           ██████████         
//           ▓▓▒▒░░▒▒▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒▓▓                        ██        ██                       
//         ▓▓▒▒░░▒▒▒▒░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓                      ██▄▄▄▄▄▄▄▄▄█         
//       ▓▓▒▒░░▒▒▒▒░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓                    ██▀███ ███▀█        
//     ▓▓▒▒░░▒▒▒▒░░░░░░░░██░░░░░░░░▒▒▒▒▒▒▒▒▓▓    █             ▀█        █▀        
//     ▓▓░░▒▒▒▒▒▒░░░░░░██████░░░░░░▒▒▒▒▒▒▒▒▓▓    ██                  █              
//   ▓▓▒▒░░▒▒▒▒░░░░░░██░░░░░░██░░░░░░▒▒▒▒▒▒▒▒▓▓   █              ██     ██                                                                                  
//   ▓▓░░▒▒▒▒▒▒░░░░░░██░░░░░░██░░░░░░▒▒▒▒▒▒▒▒▓▓ /█▄            ████─██──████                                                                                   
// ▓▓▒▒░░▒▒▒▒░░░░░░░░░░██░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓ ▄███████████████──██──██████                                                                                
// ▓▓░░▒▒▒▒▒▒░░░░░░░░░░░░██░░░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓    █████████████──██──█████████                                                                             
// ▓▓░░▒▒▒▒▒▒░░░░░░░░░░░░░░██░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓             ████──██─█████  ███                                                                              
// ▓▓▒▒▒▒▒▒▒▒░░░░░░░░██░░░░░░██░░░░░░░░▒▒▒▒▒▒▒▒▓▓              ███──██─█████  ███                                                                             
// ▓▓▒▒▒▒▒▒▒▒░░░░░░░░██░░░░░░██░░░░░░░░▒▒▒▒▒▒▒▒▓▓              ███─────█████████                                                                           
//   ▓▓▒▒▒▒▒▒▒▒░░░░░░░░██████░░░░░░░░▒▒▒▒▒▒▒▒▓▓                ██─────████████▀                                                                            
//   ▓▓▒▒▒▒▒▒▒▒░░░░░░░░░░██░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓                  ██████████                                                                                 
//    ▓▓▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓                   ██████████                                                                                
//    ▓▓▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▓▓                     ████████                                                                               
//    ▓▓▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▓▓                      ██████████▄▄                                                                        
//    ▓▓▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▓▓                      █████████▀                                                                           
//      ▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓                           ███   ███                                                                          
//        ▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▓▓                             ███   ███                                                                                 
//            ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓                                ██████   ▀                                                                                   
//             ▓▓░░░░░░▓▓░░░░░░░░▓▓░░                               ▀▄▄▄▄▀                                                                          
//                             
// ██╗    ██╗███████╗██╗      ██████╗ ████████╗██████╗  █████╗ ██████╗ ███████╗███████╗ 
// ██║    ██║██╔════╝██║     ██╔═══██╗╚══██╔══╝██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝ 
// ██║ █╗ ██║█████╗  ██║     ██║   ██║   ██║   ██████╔╝███████║██║  ██║█████╗  ███████╗ 
// ██║███╗██║██╔══╝  ██║     ██║   ██║   ██║   ██╔══██╗██╔══██║██║  ██║██╔══╝  ╚════██║ 
// ╚███╔███╔╝███████╗███████╗╚██████╔╝   ██║   ██║  ██║██║  ██║██████╔╝███████╗███████║ 
//  ╚══╝╚══╝ ╚══════╝╚══════╝ ╚═════╝    ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═════╝ ╚══════╝╚══════╝ 
 
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © WeloTrades
 
//@version=5
indicator(title = 'Smart Money Concepts by WeloTrades', shorttitle = 'SMC {WeloTrades}', overlay = true, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 500, max_bars_back = 500, max_polylines_count = 100)
 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////      INPUTS      ///////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////////////////
//OB INPUT SETTINGS//
////////////////////
// INPUT OB & BB SETTINGS
timeframe1Enabled = input.bool(true, "TF #1🕑:", inline = '1', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
timeframe1 = input.timeframe("", "", inline = '1', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
timeframe2Enabled = input.bool(false, "TF #2🕑:", inline = '2_', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
timeframe2 = input.timeframe("D", "", inline = '2_', group = "++++++++++++++ OB SETTINGS ++++++++++++++", tooltip="⏩Toggle to enable or disable the Timeframes and select which Timeframes. ❓:(DEFAULT) ➖ (HIGHER TF CHART & LOWER TF SETTING) ➖ (LOWER TF CHART & HIGHER TF SETTING)")
 
showOBs           = input.bool(true, "OB (Length)📏:", inline = '2', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
swingLengthOption = input.string("LONG", "", options = ["SHORT", "MID", "LONG", "CUSTOM"], inline = '2', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
swingLength       = input.int(5, '🔧custom:', minval = 3, inline = '2', group = "++++++++++++++ OB SETTINGS ++++++++++++++", display = display.none, tooltip="⏩:Toggle to enable or disable the display of Order Blocks. ⏩:dropdown to select the swing length option (SHORT, MID, LONG, CUSTOM). ⏩:An integer input for specifying a custom swing length, which is hidden by default and likely shown only when swingLengthOption is set to (CUSTOM) ❓:Lengths are set as default (SHORT=10) ➖ (MID=28) ➖ (LONG=50) ")
 
showBBs     = input.bool(true, "BB (Method)📛:", inline = '4', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
obEndMethod = input.string("Close", "", options = ["Wick", "Close"], inline = '4', group = "++++++++++++++ OB SETTINGS ++++++++++++++", display = display.none, tooltip="⏩:Toggle to enable or disable the display of Breaker Blocks. ⏩:Dropdown to select the method for determining the end of a Breaker Block (Wick or Close) ❓:(Wicks: OB is mitigated when the price wicks through the OB Level.) ➖ (Close: OB is mitigated when the closing price is within the OB Level.)")
 
zoneCountBullish      = input.string("2", '🔍Max Bullish:', options = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], inline = '5', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
zoneCountBearish      = input.string("2", '🔍Max Bearish:', options = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], inline = '6', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
bullOrderBlockColor   = input.color(color.rgb(0, 126, 0, 50), '', inline = '5', group = '++++++++++++++ OB SETTINGS ++++++++++++++', display = display.none)
bearOrderBlockColor   = input.color(color.rgb(128, 0, 11, 50), '', inline = '6', group = '++++++++++++++ OB SETTINGS ++++++++++++++', display = display.none)
bullOrderBlockinColor = input.color(color.rgb(0, 126, 0, 50), '', inline = '5', group = '++++++++++++++ OB SETTINGS ++++++++++++++', display = display.none, tooltip="⏩:Set the maximum number of Bullish OB to display & select color and internal color. ❓:Don't see a OB or BB where supposed to?(Try increasing the max count)➖(It counts OB & BB togheter even OB or BB display is disabled)")
bearOrderBlockinColor = input.color(color.rgb(128, 0, 11, 50), '', inline = '6', group = '++++++++++++++ OB SETTINGS ++++++++++++++', display = display.none, tooltip="⏩:Set the maximum number of Bearish OB to display & select color and internal color. ❓:Don't see a OB or BB where supposed to?(Try increasing the max count)➖(It counts OB & BB togheter even OB or BB display is disabled)")
 
obBoxLengthOption = input.string("CUSTOM", "↔ OB & BB Range:", options = ["RANGE", "CUSTOM"], inline = '7', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
adjustableLength  = input.int(22000, "🔧Custom:", minval = 1000, maxval = 500000, step = 100, inline = '7', group = "++++++++++++++ OB SETTINGS ++++++++++++++", tooltip="⏩:Select how far the OB or BB should go. ❓:(Range=Current price) ➖ (CUSTOM=Adjustable Range)")
 
textSizeOption  = input.string("M", "💬Text Options:", options = ["XS", "S", "M", "L", "XL"], inline = '8', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
textColor       = input.color(color.rgb(255, 255, 255), "", inline = '8', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
showTimeframeOB = input.bool(true, "Text", inline = '8', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
showVolume      = input.bool(true, "Volume", inline = '8', group = "++++++++++++++ OB SETTINGS ++++++++++++++")
showPercentage  = input.bool(true, "%", inline = '8', group = "++++++++++++++ OB SETTINGS ++++++++++++++", tooltip= "⏩:Set Text Size & Color for OB & BB ⏩:Toggle to enable or disable the display of (TEXT) ➖ (VOLUME) ➖ (%)")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////////////////////////////////
// LIQUIDITY LEVELS INPUT SETTINGS //
////////////////////////////////////
// INPUT LIQUIDITY SETTINGS
currentTF             = input.bool(true, title = "TF #1🕑:", inline = "1", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
htfTF                 = input.timeframe("", title = "", inline = "1", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
 
liquidityLengthOption = input.string("LONG", title = "📏Liquidity Length:", inline = "_1_", options = ["SHORT", "MID", "LONG" , "CUSTOM"], group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
liquidityswingLength  = input.int(5, '🔧custom:', minval = 3, inline = '_1_', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', display = display.none, tooltip="⏩:Select the length for liquidity levels. ❓:(SHORT: Short-term:10) ➖ (MID: Medium-term:28) ➖ (LONG: Long-term:50) ➖ (CUSTOM: Custom length) ⏩:(For CUSTOM) select the custom length for Pivot calculation. ❓:(select length you prefer)")
 
_candleType           = input.string("Close", title = "📛Mitigation (Method):", options = ["Close", "Wick"], inline = '4', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
mitiOptions           = input.string("Remove", title = "-", inline = "4", options = ["Remove", "Show"], group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', tooltip="⏩:Select to display or hide mitigated levels. ❓:(Remove: Hide mitigated levels) ➖ (Show: Display mitigated levels). ⏩:Select option mitigation method. ❓:Wicks: Level is mitigated when the price wicks through the level.) ➖ (Close: Level is mitigated when the closing price is within the level.)")
 
displayLimitBuy       = input.int(3, title = "🔍Max Buy Side Liquidity:", minval = 0, maxval = 50 , inline = "2", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
highLineColorHTF      = input.color(color.rgb(0, 19, 129, 50), "", inline = "2", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', tooltip="⏩:Set the maximum number of Buy Side Liquidity Levels to display. ❓:(Default: 5) ➖ (Min: 1) ➖ (Max: 50). ⏩:Select color for Buy Side Liquidity Levels. ❗:Don't see a Liquidity level where supposed to?(Try increasing the max count)➖(It counts Liquidity levels & recent Mitigated Liquidity Levels)")
highBoxBorderColorHTF = color.new(highLineColorHTF, 90)
 
displayLimitSell      = input.int(3, title = "🔍Max Sell Side Liquidity:", minval = 0, maxval = 50 , inline = "3", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
lowLineColorHTF       = input.color(color.rgb(255, 0, 0, 50), "", inline = "3", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', tooltip="⏩:Set the maximum number of Sell Side Liquidity Levels to display. ❓:(Default: 5) ➖ (Min: 1) ➖ (Max: 50). ⏩:Select color for Sell Side Liquidity Levels. ❗:Don't see a Liquidity level where supposed to?(Try increasing the max count)➖(It counts Liquidity levels & recent Mitigated Liquidity Levels)")
lowBoxBorderColorHTF  = color.new(lowLineColorHTF, 90)
 
box_width             = input.float(-5, title = "✂ Box Style (↕):", minval = -50, maxval = 50, step = 0.5, inline = "5", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
length_extend_liq     = input.int(defval = 20, title = "(↔):", minval = 0, maxval = 500, inline = "5", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
extentionMax          = input.bool(false, title = "Extend ⏭", inline = "5", group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', tooltip="⏩:Set the box width for liquidity levels. ❓:(Default: -5) ➖ (Range: -50 to 50). ⏩:Set the box length of Liquidity Levels. ❓:(Default: 20) ➖ (Min: 0) ➖ (Max: 500). ⏩:Toggle to extend Liquidity Levels. ❓:(Extend liquidity levels beyond the current range)")
_highLineStyleHTF     = "Solid"
highLineStyleHTF      = _highLineStyleHTF == "Solid" ? line.style_solid : _highLineStyleHTF == "Dashed" ? line.style_dashed : line.style_dotted
lineWidthHTF          = 2
textSize              = input.string("S", "💬 Text Options:", options=["XS", "S", "M", "L", "XL"], inline = '6', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
liquidity_text_color  = input.color(#ffffff, '', inline = '6', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
show_text             = input.bool(true, "Text", inline = '6', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
show_volume           = input.bool(true, "Volume", inline = '6', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++')
show_percent          = input.bool(true, "%", inline = '6', group = '++++++++++++++ LIQUIDITY LEVELS ++++++++++++++', tooltip="⏩:Select text size for liquidity levels. ❓:(XS: Extra Small) ➖ (S: Small) ➖ (M: Medium) ➖ (L: Large) ➖ (XL: Extra Large) ⏩:Select text color for liquidity levels. ⏩:Toggle to display text, volume, percentage for liquidity levels.")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
/////////////////////////////////////
// FAIR VALUE GAPS INPUT SETTINGS //
///////////////////////////////////
// INPUT SETTINGS FAIR VALUE GAPS
show_fvg             = input(true, 'TF #1🕑:' , inline = 'tf' , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
i_tf                 = input.timeframe("", "" , inline = 'tf' , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩Toggle to enable or disable the Timeframes and select which Timeframes. ❓:(DEFAULT) ➖ (HIGHER TF CHART & LOWER TF SETTING) ➖ (LOWER TF CHART & HIGHER TF SETTING)")
 
mittigation_filt_fvg = input.string('Wicks', '📛FVG Break (Method):',options = ['Touch','Wicks','Close','Average'] , inline = "m1" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
show_mitigated_fvg   = input.bool(false, 'show', inline = 'm1' , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
fvg_color_fill       = input.bool(true,"Fill" , inline = "m1" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
fvg_shade_fill       = input.bool(false,"Shade" , inline = "m1" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Select the method Break FVG & Toggle visibility of FVG Breaks (fill FVG &/or shade FVG). ❓:(Touch: FVG is mitigated when the price touches the gap.) ➖ (Wicks: FVG is mitigated when the price wicks through the gap.) ➖ (Close: FVG is mitigated when the closing price is within the gap.) ➖ (Average: FVG is mitigated when the average price (average of high and low) is within the gap.)")
 
max_bullish_fvg      = input.int(defval = 5, title = "🔍Max Bullish FVG:", minval = 0, maxval = 50 , inline = "O1" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
max_bearish_fvg      = input.int(defval = 5, title = "🔍Max Bearish FVG:", minval = 0, maxval = 50 , inline = "O1_" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
i_mtfbearishfvgcolor = input.color(color.rgb(255, 166, 0, 75) , "" , inline = "O1_" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Set the maximum number of Bearish FVG to display & select color. ❓:Don't see a FVG where supposed to?(Try increasing the max count)➖(It counts FVG & FVG Breaks)")
i_mtfbullishfvgcolor = input.color(color.rgb(255, 255, 255, 75), "" , inline = "O1" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Set the maximum number of Bullish FVG to display & select color. ❓:Don't see a FVG where supposed to?(Try increasing the max count)➖(It counts FVG & FVG Breaks)")
 
length_extend        = input.int(defval = 20,title = "↔ FVG Range:", minval = 0, maxval = 100 , inline = "O2" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
fvg_extend           = input.bool(false,"Extend⏭" , inline = "O2" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
fvg_extend_B         = input.bool(true,"Range⏯ " , inline = "O2" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Select how far the FVG should go. ❓:(Adjustable length only works when both RANGE & EXTEND display OFF) ➖ (Range=current price) ➖ (Extend=Full Range)")
 
max_width_fvg        = input.float(2.5, '↕ Max Width:', minval = 0, maxval = 5.0, step = 0.1 , inline = 'width' , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
remove_small         = input.bool(false,"Filter FVG ♻" , inline = "width" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Set the maximum width of FVG as a percentage of the price range. ❓:FVGs wider than this value will be ignored. ⏩:Toggle to filter out small FVGs. ❓:When set to true, FVGs smaller than the max_width_fvg value will be ignored.")
 
mid_style            = input.string('Dotted', '➖Mid Line Style:', ['Solid', 'Dashed', 'Dotted'] , inline="mid" , group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++')
i_midPointColor      = input.color(color.rgb(255, 255, 255), "" , inline="mid", group = '++++++++++++++ FAIR VALUE GAPS ++++++++++++++', tooltip="⏩:Select mid line style for FVG & Color.")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
////////////////////////////////
// TRENDLINES INPUT SETTINGS //
//////////////////////////////
// INPUT TRENDLINES SETTINGS
showTrendlines          = input.bool(true, "Trendlines & Trendlines Difference(%) ↕:", group="++++++++++ TRENDLINES ++++++++++", inline="TLlength")
percent_from_first_line = input.float(1.5, title="", minval=-10.0, maxval=10.0, step=0.1, group="++++++++++ TRENDLINES ++++++++++", inline="TLlength", tooltip="⏩: Enable or disable trendlines and set the percentage difference from the first trendline. ❓: Set the percentage to determine the second trendline distance.")
lengthOption            = input.string("SHORT", "📏Trendline Length:", options=["SHORT", "MID", "LONG", "CUSTOM"], group="++++++++++ TRENDLINES ++++++++++", inline="TLlength2")
lengthCustom            = input.int(5, "🔧custom:", minval=5, maxval=1000, group="++++++++++ TRENDLINES ++++++++++", inline="TLlength2", tooltip="⏩: Select the trendline length option and specify custom length if CUSTOM is selected. ❓: (SHORT=50, MID=100, LONG=200) ➖ (CUSTOM=Specify length)")
 
maxBearishCountOption = input.string("2", "🔍Max Trendlines Bearish:", options=["2","4","6","8","10","12","14","16","18","20"], group="++++++++++ TRENDLINES ++++++++++", inline="count")
dnCss                 = input.color(color.rgb(10, 130, 0), '', group="++++++++++ TRENDLINES ++++++++++", inline="count", tooltip="⏩: Set the maximum number of bearish trendlines and their color. ❓: Adjust to control how many bearish trendlines are displayed.")
maxBullishCountOption = input.string("2", "🔍Max Trendlines Bullish:", options=["2","4","6","8","10","12","14","16","18","20"], group="++++++++++ TRENDLINES ++++++++++", inline="count2")
upCss                 = input.color(color.rgb(130, 0, 10), '', group="++++++++++ TRENDLINES ++++++++++", inline="count2", tooltip="⏩: Set the maximum number of bullish trendlines and their color. ❓: Adjust to control how many bullish trendlines are displayed.")
 
showA            = input.bool(true, '📐Degrees ° (💬 Size):', group="++++++++++ TRENDLINES ++++++++++", inline="Degrees")
textSizeOptionTL = input.string("M", "", options=["XS", "S", "M", "L", "XL"], group="++++++++++ TRENDLINES ++++++++++", inline="Degrees")
angleTextColor   = input.color(color.rgb(255, 255, 255), "", group="++++++++++ TRENDLINES ++++++++++", inline="Degrees", tooltip="⏩: Enable or disable degrees text and set its size and color. ❓: Select the size from XS, S, M, L, XL.")
 
useAngleFilter = input.bool(false, '♻ Filter Degrees °:', group="++++++++++ TRENDLINES ++++++++++", inline="angleFilter")
anglA          = input.float(10, '', minval=0.1, group="++++++++++ TRENDLINES ++++++++++", inline="angleFilter") 
anglB          = input.float(90, '-', minval=0.1, group="++++++++++ TRENDLINES ++++++++++", inline="angleFilter", tooltip="⏩: Enable or disable angle filtering and set the angle range. ❓: Angles outside this range will be filtered out.")
 
LineStyle1    = input.string("SOLID", "➖Style #1 & #2:", options=["SOLID", "DASHED", "DOTTED"], group="++++++++++ TRENDLINES ++++++++++", inline="linestyle")
LineStyle2    = input.string("DOTTED", "-", options=["SOLID", "DASHED", "DOTTED"], group="++++++++++ TRENDLINES ++++++++++", inline="linestyle")
lineThickness = input.int(2, ":", minval=1, maxval=5, group="++++++++++ TRENDLINES ++++++++++", inline="linestyle", tooltip="⏩: Select the line style and thickness for the trendlines. ❓: Choose from SOLID, DASHED, DOTTED for both primary and secondary lines.")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//////////////////////////////////////////////////
// BOS & CHOCH MARKET STRUCTURE INPUT SETTINGS //
////////////////////////////////////////////////
// INPUT SETTINGS MARKET STRUCTURE
length_option         = input.string("ALL", title="📏Market Structure:", options=["INTERNAL", "EXTERNAL", "ALL", "CUSTOM", "NONE"], group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Select the market structure length option. ❓:(INTERNAL: Only internal structure) ➖ (EXTERNAL: Only external structure) ➖ (ALL: Both internal and external structures) ➖ (CUSTOM: Custom lengths) ➖ (NONE: No structure)")
internalLength        = length_option == "INTERNAL" or length_option == "ALL" ? 10 : length_option == "CUSTOM" ? input.int(10, title="🔧Custom Internal:", inline="2_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++") : na
label_sizes_Internal_ = input.string("S", options=["XS", "S", "M", "L", "XL"], title="💬", inline="2_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
internalBullColor     = input.color(color.rgb(0, 135, 0), title="", inline="2_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
internalBearColor     = input.color(color.rgb(135, 0, 0), title="", inline="2_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Set custom length, label size, and colors for internal market structure. ❓:(XS: Extra Small) ➖ (S: Small) ➖ (M: Medium) ➖ (L: Large) ➖ (XL: Extra Large)")
label_size_Internal_s = label_sizes_Internal_ == "XS" ? size.tiny : label_sizes_Internal_ == "S" ? size.small : label_sizes_Internal_ == "M" ? size.normal : label_sizes_Internal_ == "L" ? size.large : size.huge
label_size_Internal   = label_size_Internal_s
 
externalLength        = length_option == "EXTERNAL" or length_option == "ALL" ? 50 : length_option == "CUSTOM" ? input.int(50, title="🔧Custom External:", inline="3_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++") : na
label_sizes_External_ = input.string("M", options=["XS", "S", "M", "L", "XL"], title="💬", inline="3_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
externalBullColor     = input.color(color.rgb(0, 255, 0), title="", inline="3_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
externalBearColor     = input.color(color.rgb(255, 0, 0), title="", inline="3_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Set custom length, label size, and colors for external market structure. ❓:(XS: Extra Small) ➖ (S: Small) ➖ (M: Medium) ➖ (L: Large) ➖ (XL: Extra Large)")
label_size_External_s = label_sizes_External_ == "XS" ? size.tiny : label_sizes_External_ == "S" ? size.small : label_sizes_External_ == "M" ? size.normal : label_sizes_External_ == "L" ? size.large : size.huge
label_size_External   = label_size_External_s
 
show_equal_highlow = input(true, 'EQL & EQH📐:', inline='4', group='++++++++++++++ MARKET STRUCTURE ++++++++++++++')
eq_threshold       = input.float(0.3, '', minval=0, maxval=10, step=0.1, inline='4', group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
label_size_Equal_  = input.string("S", options=["XS", "S", "M", "L", "XL"], title="💬", inline="4", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
eq_bull_color      = input.color(color.rgb(0, 255, 0), '', inline="4", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
eq_bear_color      = input.color(color.rgb(255, 0, 0), '', inline="4", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Toggle visibility, set threshold, label size, and colors for equal highs and lows. ❓:(XS: Extra Small) ➖ (S: Small) ➖ (M: Medium) ➖ (L: Large) ➖ (XL: Extra Large)")
label_size_Equal_s = label_size_Equal_ == "XS" ? size.tiny : label_size_Equal_ == "S" ? size.small : label_size_Equal_ == "M" ? size.normal : label_size_Equal_ == "L" ? size.large : size.huge
label_size_Equal   = label_size_Equal_s
 
showSwing          = input.bool(true, title="Swing Points📏:", inline="1", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
swing_option       = input.string("SHORT", title="", options=["SHORT", "MID", "LONG", "CUSTOM"], inline="1", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
label_sizes_swing_ = input.string("M", options=["XS", "S", "M", "L", "XL"], title="💬", inline="1", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++")
swingColor         = input.color(color.rgb(255, 255, 255), '', inline="1", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Toggle visibility, set length, label size, and color for swing points. ❓:(SHORT:10) ➖ (MID:28) ➖ (LONG:50) ➖ (CUSTOM:Adjustable length custom) ❓:(XS: Extra Small) ➖ (S: Small) ➖ (M: Medium) ➖ (L: Large) ➖ (XL: Extra Large)")
 
swingSize_swing    = swing_option == "SHORT" ? 10 : swing_option == "MID" ? 28 : swing_option == "LONG" ? 50 : input.int(10, title="🔧Custom Swings:", inline="1_", group="++++++++++++++ MARKET STRUCTURE ++++++++++++++", tooltip="⏩:Set custom length for swing points. ❓:(Minimum value: 1)")
swingSize          = 5
length_eqh         = 5
color CLEAR        = color.rgb(0, 0, 0, 100)
label_size_swing_s = label_sizes_swing_ == "XS" ? size.tiny : label_sizes_swing_ == "S" ? size.small : label_sizes_swing_ == "M" ? size.normal : label_sizes_swing_ == "L" ? size.large : size.huge
label_size_swing   = label_size_swing_s
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////      CALCULATIONS / FUNCTIONS      /////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      GLOBAL VARIABLES      -----------------------------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
 
// GLOBAL VARIABLES FUNCTIONS // 
showInvalidated = true
OBsEnabled = true
const bool DEBUG = false
combineOBs = DEBUG ? input.bool(true,display = display.none) : true
maxATRMult = DEBUG ? input.float(3.5) : 3.5
bullishOrderBlocks = str.tonumber(zoneCountBullish)
bearishOrderBlocks = str.tonumber(zoneCountBearish)
extendZonesBy = DEBUG ? input.int(15) : 15
mirrorVolumeBars = DEBUG ? input.bool(true) : true
volumeBarsPlace = DEBUG ? input.string("Left") : "Left"
volumeBarsLeftSide = (volumeBarsPlace == "Left")
extendZonesByTime = extendZonesBy * timeframe.in_seconds(timeframe.period) * 1000
atr = ta.atr(10)
style             = 'Colored'
color transparent = #ffffff00
length            = 50
is_newbar(res)    =>
    t             = time(res)
    not na(t) and (na(t[1]) or t > t[1])
 
Show_MS(x, y, txt, css, dashed, down, lbl_size)=>
    label.new(int(math.avg(x, bar_index)), y, txt, color = transparent, textcolor = css, style = down ? label.style_label_down : label.style_label_up, size = lbl_size)
    line.new(x, y, bar_index, y, color = css, style = dashed ? line.style_dashed : line.style_solid)
 
f_barssince(_cond, _count) =>
    _barssince = bar_index - ta.valuewhen(_cond, bar_index, _count)
    _barssince
 
var t_MS = 0, var int_t_MS = 0
var internal_y_up = 0., var internal_x_up = 0, var internal_y_dn = 0., var internal_x_dn = 0
var y_up = 0., var x_up = 0 , var y_dn = 0., var x_dn = 0
var crossed_up = true,  var crossed_down = true
var internal_up_broke = true, var internal_dn_broke = true
var up_trailing = high, var down_trailing = low
var up_trailing_x = 0,  var down_trailing_x = 0
var high_text = '',  var low_text = ''
bullish_OB_Break = false 
bearish_OB_Break = false
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      OB CALCULATIONS & FUNCTIONS      ------------------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
type orderBlockInfo
    float top
    float bottom
    float obVolume
    string obType
    int startTime
    float bbVolume
    float obLowVolume
    float obHighVolume
    bool breaker
    int breakTime
    string timeframeStr
    bool disabled = false
    string combinedTimeframesStr = na
    bool combined = false
 
type orderBlock
    orderBlockInfo info
    bool isRendered = false
 
    box orderBox = na
    box breakerBox = na
 
    line orderBoxLineTop = na
    line orderBoxLineBottom = na
    line breakerBoxLineTop = na
    line breakerBoxLineBottom = na
    
    box orderBoxText = na
    box orderBoxPositive = na
    box orderBoxNegative = na
 
    line orderSeperator = na
    line orderTextSeperator = na
 
createOrderBlock (orderBlockInfo orderBlockInfoF) =>
    orderBlock newOrderBlock = orderBlock.new(orderBlockInfoF)
    newOrderBlock
 
safeDeleteOrderBlock (orderBlock orderBlockF) =>
    orderBlockF.isRendered := false
 
    box.delete(orderBlockF.orderBox)
    box.delete(orderBlockF.breakerBox)
    box.delete(orderBlockF.orderBoxText)
    box.delete(orderBlockF.orderBoxPositive)
    box.delete(orderBlockF.orderBoxNegative)
 
    line.delete(orderBlockF.orderBoxLineTop)
    line.delete(orderBlockF.orderBoxLineBottom)
    line.delete(orderBlockF.breakerBoxLineTop)
    line.delete(orderBlockF.breakerBoxLineBottom)
    line.delete(orderBlockF.orderSeperator)
    line.delete(orderBlockF.orderTextSeperator)
 
type timeframeInfo
    int index = na
    string timeframeStr = na
    bool isEnabled = false
 
    orderBlockInfo[] bullishOrderBlocksList = na
    orderBlockInfo[] bearishOrderBlocksList = na
 
newTimeframeInfo (index, timeframeStr, isEnabled) =>
    newTFInfo = timeframeInfo.new()
    newTFInfo.index := index
    newTFInfo.isEnabled := isEnabled
    newTFInfo.timeframeStr := timeframeStr
 
    newTFInfo
 
type obSwing
    int x = na    
    float y = na
    float swingVolume = na
    bool crossed = false
 
const float overlapThresholdPercentage = 0
const int maxDistanceToLastBar = 1750 
const int maxOrderBlocks = 30
 
var timeframeInfo[] timeframeInfos = array.from(newTimeframeInfo(1, timeframe1, timeframe1Enabled), newTimeframeInfo(2, timeframe2, timeframe2Enabled))
var bullishOrderBlocksList = array.new<orderBlockInfo>(0)
var bearishOrderBlocksList = array.new<orderBlockInfo>(0)
var allOrderBlocksList = array.new<orderBlock>(0)
 
moveLine(_line, _x, _y, _x2) =>
    line.set_xy1(_line, _x,  _y)
    line.set_xy2(_line, _x2, _y)
 
moveBox (_box, _topLeftX, _topLeftY, _bottomRightX, _bottomRightY) =>
    box.set_lefttop(_box, _topLeftX, _topLeftY)
    box.set_rightbottom(_box, _bottomRightX, _bottomRightY)
 
isTimeframeLower (timeframe1F, timeframe2F) =>
    timeframe.in_seconds(timeframe1F) < timeframe.in_seconds(timeframe2F)
 
getMinTimeframe (timeframe1F, timeframe2F) =>
    if isTimeframeLower(timeframe1F, timeframe2F)
        timeframe1F
    else
        timeframe2F
 
getMaxTimeframe (timeframe1F, timeframe2F) =>
    if isTimeframeLower(timeframe1F, timeframe2F)
        timeframe2F
    else
        timeframe1F
 
formatTimeframeString (formatTimeframe) =>
    timeframeF = formatTimeframe == "" ? timeframe.period : formatTimeframe
    
    if str.contains(timeframeF, "D") or str.contains(timeframeF, "W") or str.contains(timeframeF, "S") or str.contains(timeframeF, "M")
        timeframeF
    else
        seconds = timeframe.in_seconds(timeframeF)
        if seconds >= 3600
            hourCount = int(seconds / 3600)
            str.tostring(hourCount) + " Hour" + (hourCount > 1 ? "s" : "")
        else
            timeframeF + " Min"
 
betterCross(s1, s2) =>
    string ret = na
    if s1 >= s2 and s1[1] < s2
        ret := "Bull"
    if s1 < s2 and s1[1] >= s2
        ret := "Bear"
    ret
 
colorWithTransparency (colorF, transparencyX) =>
    color.new(colorF, color.t(colorF) * transparencyX)
 
createOBBox (boxColor, textSize, transparencyX = 1.0, xlocType = xloc.bar_time) =>
    box.new(na, na, na, na, text_size = textSize, xloc = xlocType, extend = extend.none, bgcolor = colorWithTransparency(boxColor, transparencyX), text_color = textColor, text_halign = text.align_center, border_color = #00000000)
 
getTextSize(textSizeOption) =>
    if textSizeOption == "XS"
        size.tiny
    else if textSizeOption == "S"
        size.small
    else if textSizeOption == "M"
        size.normal    
    else if textSizeOption == "L"
        size.large
    else if textSizeOption == "XL"
        size.huge    
 
renderOrderBlock (orderBlock ob) =>
    orderBlockInfo info = ob.info
    ob.isRendered := true
    orderColor = ob.info.obType == "Bull" ? bullOrderBlockColor : bearOrderBlockColor
 
    // Check if OBs or BBs should be displayed
    showOB = not info.breaker and showOBs
    showBB = info.breaker and showBBs
 
    if OBsEnabled and (showOB or showBB) and not (not showInvalidated and info.breaker)
        textSize = getTextSize(textSizeOption)
        ob.orderBox := createOBBox(orderColor, textSize, 1.5)
        if ob.info.combined
            ob.orderBox.set_bgcolor(colorWithTransparency(orderColor, 1.1))
        ob.orderBoxText := createOBBox(color.new(color.white, 100), textSize)
        if showVolume or showPercentage
            ob.orderBoxPositive := createOBBox(bullOrderBlockinColor, textSize)
            ob.orderBoxNegative := createOBBox(bearOrderBlockinColor, textSize)
            ob.orderSeperator := line.new(na,na,na,na,xloc.bar_time,extend.none,textColor,line.style_dashed,1)
            ob.orderTextSeperator := line.new(na,na,na,na,xloc.bar_time,extend.none,textColor,line.style_solid,1)
 
        zoneSize = if obBoxLengthOption == "RANGE"
            time - info.startTime 
        else if obBoxLengthOption == "CUSTOM"
            time - info.startTime + adjustableLength * timeframe.in_seconds(timeframe.period)
        else
            extendZonesByTime
        
        startX = volumeBarsLeftSide ? info.startTime : info.startTime + zoneSize - zoneSize / 3
        maxEndX = volumeBarsLeftSide ? info.startTime + zoneSize / 3 : info.startTime + zoneSize
 
        moveBox(ob.orderBox, info.startTime, info.top, info.startTime + zoneSize, info.bottom)
        moveBox(ob.orderBoxText, volumeBarsLeftSide ? maxEndX : info.startTime, info.top, volumeBarsLeftSide ? info.startTime + zoneSize : startX, info.bottom)
 
        percentage = int((math.min(info.obHighVolume, info.obLowVolume) / math.max(info.obHighVolume, info.obLowVolume)) * 100.0)
        OBText = (na(ob.info.combinedTimeframesStr) ? formatTimeframeString(ob.info.timeframeStr) : ob.info.combinedTimeframesStr) + " " + (info.breaker ? "BB" : "OB")
        textToDisplay = ""
        if showTimeframeOB
            textToDisplay += OBText + " "
        if showVolume
            textToDisplay += str.tostring(ob.info.obVolume, format.volume) + " "
        if showPercentage
            textToDisplay += "(" + str.tostring(percentage) + "%)"
 
        box.set_text(ob.orderBoxText, textToDisplay)
 
        if showVolume or showPercentage
            showHighLowBoxText = false
 
            curEndXHigh = int(math.ceil((info.obHighVolume / info.obVolume) * (maxEndX - startX) + startX))
            curEndXLow = int(math.ceil((info.obLowVolume / info.obVolume) * (maxEndX - startX) + startX))
 
            moveBox(ob.orderBoxPositive, mirrorVolumeBars ? startX : curEndXLow, info.top, mirrorVolumeBars ? curEndXHigh : maxEndX, (info.bottom + info.top) / 2)
            box.set_text(ob.orderBoxPositive, showHighLowBoxText ? str.tostring(info.obHighVolume, format.volume) : "")
 
            moveBox(ob.orderBoxNegative, mirrorVolumeBars ? startX : curEndXHigh, info.bottom, mirrorVolumeBars ? curEndXLow : maxEndX, (info.bottom + info.top) / 2)
            box.set_text(ob.orderBoxNegative, showHighLowBoxText ? str.tostring(info.obLowVolume, format.volume) : "")
 
            moveLine(ob.orderSeperator, volumeBarsLeftSide ? startX : maxEndX, (info.bottom + info.top) / 2, volumeBarsLeftSide ? maxEndX : startX)
 
            line.set_xy1(ob.orderTextSeperator, volumeBarsLeftSide ? maxEndX : startX, info.top)
            line.set_xy2(ob.orderTextSeperator, volumeBarsLeftSide ? maxEndX : startX, info.bottom)
 
findOBSwings(len) =>
    var swingType = 0
    var obSwing top = obSwing.new(na, na)
    var obSwing bottom = obSwing.new(na, na)
    
    upper = ta.highest(len)
    lower = ta.lowest(len)
 
    swingType := high[len] > upper ? 0 : low[len] < lower ? 1 : swingType
 
    if swingType == 0 and swingType[1] != 0
        top := obSwing.new(bar_index[len], high[len], volume[len])
    
    if swingType == 1 and swingType[1] != 1
        bottom := obSwing.new(bar_index[len], low[len], volume[len])
 
    [top, bottom]
 
findOrderBlocks (length) =>
    if bar_index > last_bar_index - maxDistanceToLastBar
        [top, btm] = findOBSwings(length)
        useBody = false
        max = useBody ? math.max(close, open) : high
        min = useBody ? math.min(close, open) : low
 
        // Bullish Order Block
        bullishBreaked = 0
 
        if array.size(bullishOrderBlocksList) > 0
            for i = array.size(bullishOrderBlocksList) - 1 to 0
                currentOB = array.get(bullishOrderBlocksList, i)
            
                if not na(currentOB) and not currentOB.breaker 
                    if (obEndMethod == "Wick" ? low : math.min(open, close)) < currentOB.bottom
                        currentOB.breaker := true
                        currentOB.breakTime := time
                        currentOB.bbVolume := volume
                else
                    if not na(currentOB) and high > currentOB.top
                        array.remove(bullishOrderBlocksList, i)
                    else if not na(currentOB) and i < bullishOrderBlocks and top.y < currentOB.top and top.y > currentOB.bottom 
                        bullishBreaked := 1
 
        if close > top.y and not top.crossed
            top.crossed := true
 
            boxBtm = max[1]
            boxTop = min[1]
            boxLoc = time[1]
 
            for i = 1 to (bar_index - top.x) - 1
                boxBtm := math.min(min[i], boxBtm)
                boxTop := boxBtm == min[i] ? max[i] : boxTop
                boxLoc := boxBtm == min[i] ? time[i] : boxLoc
 
            newOrderBlockInfo = orderBlockInfo.new(boxTop, boxBtm, volume + volume[1] + volume[2], "Bull", boxLoc)
            newOrderBlockInfo.obLowVolume := volume[2]
            newOrderBlockInfo.obHighVolume := volume + volume[1]
            
            obSize = math.abs(newOrderBlockInfo.top - newOrderBlockInfo.bottom)
            if obSize <= atr * maxATRMult
                array.unshift(bullishOrderBlocksList, newOrderBlockInfo)
                if array.size(bullishOrderBlocksList) > maxOrderBlocks
                    array.pop(bullishOrderBlocksList)
 
        // Bearish Order Block
        bearishBreaked = 0
 
        if array.size(bearishOrderBlocksList) > 0
            for i = array.size(bearishOrderBlocksList) - 1 to 0
                currentOB = array.get(bearishOrderBlocksList, i)
 
                if not na(currentOB) and not currentOB.breaker 
                    if (obEndMethod == "Wick" ? high : math.max(open, close)) > currentOB.top
                        currentOB.breaker := true
                        currentOB.breakTime := time
                        currentOB.bbVolume := volume
                else
                    if not na(currentOB) and low < currentOB.bottom
                        array.remove(bearishOrderBlocksList, i)
                    else if not na(currentOB) and i < bearishOrderBlocks and btm.y > currentOB.bottom and btm.y < currentOB.top 
                        bearishBreaked := 1
 
        if close < btm.y and not btm.crossed
            btm.crossed := true
 
            boxBtm = min[1]
            boxTop = max[1]
            boxLoc = time[1]
 
            for i = 1 to (bar_index - btm.x) - 1
                boxTop := math.max(max[i], boxTop)
                boxBtm := boxTop == max[i] ? min[i] : boxBtm
                boxLoc := boxTop == max[i] ? time[i] : boxLoc
 
            newOrderBlockInfo = orderBlockInfo.new(boxTop, boxBtm, volume + volume[1] + volume[2], "Bear", boxLoc)
            newOrderBlockInfo.obLowVolume := volume + volume[1]
            newOrderBlockInfo.obHighVolume := volume[2]
 
            obSize = math.abs(newOrderBlockInfo.top - newOrderBlockInfo.bottom)
            if obSize <= atr * maxATRMult
                array.unshift(bearishOrderBlocksList, newOrderBlockInfo)
                if array.size(bearishOrderBlocksList) > maxOrderBlocks
                    array.pop(bearishOrderBlocksList)
    true
 
areaOfOB (orderBlockInfo OBInfoF) =>
    float XA1 = OBInfoF.startTime
    float XA2 = na(OBInfoF.breakTime) ? time + 1 : OBInfoF.breakTime
    float YA1 = OBInfoF.top
    float YA2 = OBInfoF.bottom
    float edge1 = math.sqrt((XA2 - XA1) * (XA2 - XA2) + (YA2 - YA2) * (YA2 - YA2))
    float edge2 = math.sqrt((XA2 - XA2) * (XA2 - XA2) + (YA2 - YA1) * (YA2 - YA1))
    float totalArea = edge1 * edge2
    totalArea
 
doOBsTouch (orderBlockInfo OBInfo1, orderBlockInfo OBInfo2) =>
    float XA1 = OBInfo1.startTime
    float XA2 = na(OBInfo1.breakTime) ? time + 1 : OBInfo1.breakTime
    float YA1 = OBInfo1.top
    float YA2 = OBInfo1.bottom
 
    float XB1 = OBInfo2.startTime
    float XB2 = na(OBInfo2.breakTime) ? time + 1 : OBInfo2.breakTime
    float YB1 = OBInfo2.top
    float YB2 = OBInfo2.bottom
    float intersectionArea = math.max(0, math.min(XA2, XB2) - math.max(XA1, XB1)) * math.max(0, math.min(YA1, YB1) - math.max(YA2, YB2))
    float unionArea = areaOfOB(OBInfo1) + areaOfOB(OBInfo2) - intersectionArea
    
    float overlapPercentage = (intersectionArea / unionArea) * 100.0
 
    if overlapPercentage > overlapThresholdPercentage
        true
    else
        false
 
isOBValid (orderBlockInfo OBInfo) =>
    valid = true
    if OBInfo.disabled
        valid := false
    valid
 
combineOBsFunc () =>
    if array.size(allOrderBlocksList) > 0
        lastCombinations = 999
        while lastCombinations > 0
            lastCombinations := 0
            for i = 0 to array.size(allOrderBlocksList) - 1
                curOB1 = array.get(allOrderBlocksList, i)
                for j = 0 to array.size(allOrderBlocksList) - 1
                    curOB2 = array.get(allOrderBlocksList, j)
                    if i == j
                        continue
                    if not isOBValid(curOB1.info) or not isOBValid(curOB2.info)
                        continue
                    if curOB1.info.obType != curOB2.info.obType
                        continue
                    if doOBsTouch(curOB1.info, curOB2.info)
                        curOB1.info.disabled := true
                        curOB2.info.disabled := true
                        orderBlock newOB = createOrderBlock(orderBlockInfo.new(math.max(curOB1.info.top, curOB2.info.top), math.min(curOB1.info.bottom, curOB2.info.bottom), curOB1.info.obVolume + curOB2.info.obVolume, curOB1.info.obType))
                        newOB.info.startTime := math.min(curOB1.info.startTime, curOB2.info.startTime)
                        newOB.info.breakTime := math.max(nz(curOB1.info.breakTime), nz(curOB2.info.breakTime))
                        newOB.info.breakTime := newOB.info.breakTime == 0 ? na : newOB.info.breakTime
                        newOB.info.timeframeStr := curOB1.info.timeframeStr
 
                        newOB.info.obVolume := curOB1.info.obVolume + curOB2.info.obVolume
                        newOB.info.obLowVolume := curOB1.info.obLowVolume + curOB2.info.obLowVolume
                        newOB.info.obHighVolume := curOB1.info.obHighVolume + curOB2.info.obHighVolume
                        newOB.info.bbVolume := nz(curOB1.info.bbVolume, 0) + nz(curOB2.info.bbVolume, 0)
                        newOB.info.breaker := curOB1.info.breaker or curOB2.info.breaker
                        
                        newOB.info.combined := true
                        if timeframe.in_seconds(curOB1.info.timeframeStr) != timeframe.in_seconds(curOB2.info.timeframeStr)
                            newOB.info.combinedTimeframesStr := (na(curOB1.info.combinedTimeframesStr) ? formatTimeframeString(curOB1.info.timeframeStr) : curOB1.info.combinedTimeframesStr) + " & " + (na(curOB2.info.combinedTimeframesStr) ? formatTimeframeString(curOB2.info.timeframeStr) : curOB2.info.combinedTimeframesStr)
                        array.unshift(allOrderBlocksList, newOB)
                        lastCombinations += 1
 
reqSeq (timeframeStr) =>
    [bullishOrderBlocksListF, bearishOrderBlocksListF] = request.security(syminfo.tickerid, timeframeStr, [bullishOrderBlocksList, bearishOrderBlocksList])
    [bullishOrderBlocksListF, bearishOrderBlocksListF]
 
getTFData (timeframeInfo timeframeInfoF, timeframeStr) =>
    if timeframeInfoF.isEnabled
        [bullishOrderBlocksListF, bearishOrderBlocksListF] = reqSeq(timeframeStr)
        if na(bullishOrderBlocksListF) or na(bearishOrderBlocksListF)
            [array.new<orderBlockInfo>(0), array.new<orderBlockInfo>(0)]
        else
            [bullishOrderBlocksListF, bearishOrderBlocksListF]
    else
        [array.new<orderBlockInfo>(0), array.new<orderBlockInfo>(0)]
 
handleTimeframeInfo (timeframeInfo timeframeInfoF, bullishOrderBlocksListF, bearishOrderBlocksListF) =>
    if timeframeInfoF.isEnabled
        if not na(bullishOrderBlocksListF)
            timeframeInfoF.bullishOrderBlocksList := bullishOrderBlocksListF
        else
            timeframeInfoF.bullishOrderBlocksList := array.new<orderBlockInfo>(0)
        if not na(bearishOrderBlocksListF)
            timeframeInfoF.bearishOrderBlocksList := bearishOrderBlocksListF
        else
            timeframeInfoF.bearishOrderBlocksList := array.new<orderBlockInfo>(0)
 
handleOrderBlocksFinal () =>
    if DEBUG
        log.info("Bullish OB Count " + str.tostring(array.size(bullishOrderBlocksList)))
        log.info("Bearish OB Count " + str.tostring(array.size(bearishOrderBlocksList)))
 
    if array.size(allOrderBlocksList) > 0
        for i = 0 to array.size(allOrderBlocksList) - 1
            safeDeleteOrderBlock(array.get(allOrderBlocksList, i))
    array.clear(allOrderBlocksList)    
 
    for i = 0 to array.size(timeframeInfos) - 1
        curTimeframe = array.get(timeframeInfos, i)
        if not curTimeframe.isEnabled
            continue
        if not na(curTimeframe.bullishOrderBlocksList) and array.size(curTimeframe.bullishOrderBlocksList) > 0
            for j = 0 to math.min(array.size(curTimeframe.bullishOrderBlocksList) - 1, bullishOrderBlocks - 1)
                orderBlockInfoF = array.get(curTimeframe.bullishOrderBlocksList, j)
                orderBlockInfoF.timeframeStr := curTimeframe.timeframeStr
                array.unshift(allOrderBlocksList, createOrderBlock(orderBlockInfo.copy(orderBlockInfoF)))
 
        if not na(curTimeframe.bearishOrderBlocksList) and array.size(curTimeframe.bearishOrderBlocksList) > 0
            for j = 0 to math.min(array.size(curTimeframe.bearishOrderBlocksList) - 1, bearishOrderBlocks - 1)
                orderBlockInfoF = array.get(curTimeframe.bearishOrderBlocksList, j)
                orderBlockInfoF.timeframeStr := curTimeframe.timeframeStr
                array.unshift(allOrderBlocksList, createOrderBlock(orderBlockInfo.copy(orderBlockInfoF)))
 
    if combineOBs
        combineOBsFunc()    
 
    if array.size(allOrderBlocksList) > 0
        for i = 0 to array.size(allOrderBlocksList) - 1
            curOB = array.get(allOrderBlocksList, i)
            if isOBValid(curOB.info)
                renderOrderBlock(curOB)
 
if showOBs or showBBs
    swingLength = switch swingLengthOption
        "SHORT" => 10
        "MID" => 28
        "LONG" => 50
        "CUSTOM" => swingLength
 
    findOrderBlocks(swingLength)
 
[bullishOrderBlocksListTimeframe1, bearishOrderBlocksListTimeframe1] = getTFData(array.get(timeframeInfos, 0), timeframe1)
[bullishOrderBlocksListTimeframe2, bearishOrderBlocksListTimeframe2] = getTFData(array.get(timeframeInfos, 1), timeframe2)
 
if barstate.isconfirmed
    handleTimeframeInfo(array.get(timeframeInfos, 0), bullishOrderBlocksListTimeframe1, bearishOrderBlocksListTimeframe1)
    handleTimeframeInfo(array.get(timeframeInfos, 1), bullishOrderBlocksListTimeframe2, bearishOrderBlocksListTimeframe2)
    handleOrderBlocksFinal()
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      LIQUIDITY LEVELS CALCULATIONS & FUNCTIONS     -----------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
liquidityLength = switch liquidityLengthOption
    "SHORT" => 10
    "MID"   => 28
    "LONG"  => 50
    "CUSTOM" => liquidityswingLength
 
// Function to adjust the leftBars based on the timeframe to avoid exceeding the max_bars_back
adjustedLeftBars(tf, baseLeftBars) =>
    tf_seconds = timeframe.in_seconds(tf)
    if tf_seconds <= 60  // If the timeframe is 1 minute or less
        10
    else if tf_seconds <= 300  // If the timeframe is 5 minutes or less
        20
    else
        baseLeftBars
 
leftBars = adjustedLeftBars(htfTF, liquidityLength)
 
 
displayStyle_liq      = "Boxes"
timediff          = (time[1] - time[101]) / 100
highLineColor      = highLineColorHTF
lowLineColor       = lowLineColorHTF
highBoxBgColor     = highLineColorHTF
highBoxBorderColor = highBoxBorderColorHTF
lowBoxBgColor      = lowLineColorHTF
lowBoxBorderColor  = lowBoxBorderColorHTF
atr_liq            = ta.atr(300)
float thold_liq    = atr_liq * (box_width / 10)
 
tf_multi(tf) =>
    ts       = timeframe.in_seconds("")
    htfs     = timeframe.in_seconds(tf)
    htfs     / ts
 
display_limit_lines(_array, _limit) =>
    while array.size(_array) > _limit
        line.delete(array.shift(_array))
 
display_limit_boxes(_array, _limit) =>
    while array.size(_array) > _limit
        box.delete(array.shift(_array))
 
remove_mitigated_lines(_array, _hl, _candleType, _mitiOptions, _lineColor, _lineStyle, _lineWidth) =>
    if array.size(_array) > 0      
        for i = array.size(_array) - 1 to 0 by 1
            l = array.get(_array, i)
            hh = _candleType == "Close" ? close[1] : high
            ll = _candleType == "Close" ? close[1] : low
            if _hl == "High" and hh > line.get_y1(l)
                array.remove(_array, i)
                if _mitiOptions == "Show"
                    line.new(line.get_x1(l), line.get_y1(l), time, line.get_y1(l), xloc = xloc.bar_time, color = _lineColor, style = _lineStyle, width = _lineWidth)
                line.delete(l)
            if _hl == "Low" and ll < line.get_y1(l)
                array.remove(_array, i)
                if _mitiOptions == "Show"
                    line.new(line.get_x1(l), line.get_y1(l), time, line.get_y1(l), xloc = xloc.bar_time, color = _lineColor, style = _lineStyle, width = _lineWidth)
                line.delete(l)
 
remove_mitigated_boxes(_array, _hl, _candleType, _mitiOptions, _bgColor, _borderColor, _lineStyle, _lineWidth) =>
    if array.size(_array) > 0
        for i = array.size(_array) - 1 to 0 by 1
            b = array.get(_array, i)
            hh = _candleType == "Close" ? close[1] : high
            ll = _candleType == "Close" ? close[1] : low
            if _hl == "High" and hh > box.get_top(b)
                array.remove(_array, i)
                if _mitiOptions == "Show"
                    box.new(box.get_left(b), box.get_top(b), time, box.get_bottom(b), xloc = xloc.bar_time, bgcolor = color.new(_bgColor, 90), border_color = color.new(_borderColor, 90), border_style = _lineStyle, border_width = _lineWidth)
                box.delete(b)
            if _hl == "Low" and ll < box.get_top(b)
                array.remove(_array, i)
                if _mitiOptions == "Show"
                    box.new(box.get_left(b), box.get_top(b), time, box.get_bottom(b), xloc = xloc.bar_time, bgcolor = color.new(_bgColor, 90), border_color = color.new(_borderColor, 90), border_style = _lineStyle, border_width = _lineWidth)
                box.delete(b)
 
extend_line_to_current(lineArray, _length_extend, _timediff) =>
    if array.size(lineArray) > 0
        for i = array.size(lineArray) - 1 to 0 by 1
            l = array.get(lineArray, i)
            timeExt = timenow + ((_timediff) * _length_extend)
            line.set_x2(l, timeExt)
 
extend_box_to_current(boxArray, _length_extend, _timediff) =>
    if array.size(boxArray) > 0
        for i = array.size(boxArray) - 1 to 0 by 1
            b = array.get(boxArray, i)
            timeExt = timenow + ((_timediff) * _length_extend)
            box.set_right(b, timeExt)
 
var highLineArrayHTF = array.new_line()
var lowLineArrayHTF  = array.new_line()  
var highBoxArrayHTF  = array.new_box()
var lowBoxArrayHTF   = array.new_box()
 
 
[_time, _open, _high, _low, _close, vol] = request.security(syminfo.tickerid, htfTF, [time, open, high, low, close, volume])
 
pivotHighHTF  = ta.pivothigh(_high, leftBars, leftBars)
pivotLowHTF   = ta.pivotlow(_low, leftBars, leftBars)
 
timeExt      = time + ((time[1] - time[2]) * 10)
dis          = leftBars
 
 
 
label_size_external = switch textSize
    "XS"   => size.tiny
    "S"  => size.small
    "M" => size.normal
    "L"  => size.large
    "XL"   => size.huge
 
highest_volume    = ta.highest(vol, 300)
volume_percentage = (vol / highest_volume) * 100
 
format_volume(vol) =>
    vol >= 1000000000 ? str.tostring(vol / 1000000000, '#.##') + "B" : vol >= 1000000 ? str.tostring(vol / 1000000, '#.##') + "M" : str.tostring(vol / 1000, '#.##') + "K"
 
format_tf(tf) =>
    tf == "1" ? "1Min" :tf == "2" ? "2Min" : tf == "3" ? "3Min" : tf == "5" ? "5Min" : tf == "10" ? "10Min" : tf == "15" ? "15Min" : tf == "30" ? "30Min" : tf == "45" ? "45Min" : tf == "60" ? "1H" : tf == "120" ? "2H" : tf == "180" ? "3H" : tf == "240" ? "4H" :  tf == "D" ? "1D" : tf == "W" ? "1W" : tf == "M" ? "1M" :  tf == "M" ? "3M" :tf == "M" ? "6M" : tf == "Y" ? "1Y" : tf
 
if currentTF
    if pivotHighHTF
        if displayStyle_liq == "Lines"
            array.push(highLineArrayHTF, line.new(_time[dis], _high[dis], _time[+1], _high[dis], color = highLineColorHTF, style = highLineStyleHTF, xloc = xloc.bar_time, extend = extentionMax ? extend.right : extend.none, width = lineWidthHTF))
        else
            y1 = _high[dis] - thold_liq
            volume_text = show_text ? (htfTF == "" ? "" : "(" + format_tf(htfTF) + ") ") + "Buy Side 💲" : ""
            if show_volume
                volume_text := volume_text + format_volume(vol)
            if show_percent
                volume_text := volume_text + " (" + str.tostring(volume_percentage, '#.##') + "%)"
            array.push(highBoxArrayHTF, box.new(_time[dis], _high[dis], _time[+1], y1, bgcolor = highLineColorHTF, border_color = highBoxBorderColorHTF, xloc = xloc.bar_time, border_style = highLineStyleHTF, extend = extentionMax ? extend.right : extend.none, border_width = lineWidthHTF, text = volume_text, text_halign = text.align_center, text_color = liquidity_text_color, text_size = label_size_external))
            alert("Buy Side Liquidity Detected: {{ticker}}, Price = {{close}}, Volume = {{volume}}", alert.freq_once_per_bar)
 
    if pivotLowHTF
        if displayStyle_liq == "Lines"
            array.push(lowLineArrayHTF, line.new(_time[dis], _low[dis], _time[+1], _low[dis], color = lowLineColorHTF, style = highLineStyleHTF, xloc = xloc.bar_time, extend = extentionMax ? extend.right : extend.none, width = lineWidthHTF))
        else
            y1 = _low[dis] + thold_liq
            volume_text = show_text ? (htfTF == "" ? "" : "(" + format_tf(htfTF) + ") ") + "Sell Side 💲" : ""
            if show_volume
                volume_text := volume_text + format_volume(vol)
            if show_percent
                volume_text := volume_text + " (" + str.tostring(volume_percentage, '#.##') + "%)"
            array.push(lowBoxArrayHTF, box.new(_time[dis], _low[dis], _time[+1], y1, bgcolor = lowLineColorHTF, border_color = lowBoxBorderColorHTF, xloc = xloc.bar_time, border_style = highLineStyleHTF, extend = extentionMax ? extend.right : extend.none, border_width = lineWidthHTF, text = volume_text, text_halign = text.align_center, text_color = liquidity_text_color, text_size = label_size_external))
            alert("Sell Side Liquidity Detected: {{ticker}}, Price = {{close}}, Volume = {{volume}}", alert.freq_once_per_bar)
 
remove_mitigated_lines(highLineArrayHTF, "High", _candleType, mitiOptions, highLineColorHTF, highLineStyleHTF, lineWidthHTF)
remove_mitigated_boxes(highBoxArrayHTF, "High", _candleType, mitiOptions, highBoxBgColor, highBoxBorderColorHTF, highLineStyleHTF, lineWidthHTF)
remove_mitigated_lines(lowLineArrayHTF, "Low", _candleType, mitiOptions, lowLineColorHTF, highLineStyleHTF, lineWidthHTF)
remove_mitigated_boxes(lowBoxArrayHTF, "Low", _candleType, mitiOptions, lowBoxBgColor, lowBoxBorderColorHTF, highLineStyleHTF, lineWidthHTF)
display_limit_boxes(highBoxArrayHTF, displayLimitBuy)
display_limit_boxes(lowBoxArrayHTF, displayLimitSell)
 
extend_line_to_current(highLineArrayHTF, length_extend_liq, timediff)
extend_line_to_current(lowLineArrayHTF, length_extend_liq, timediff)
extend_box_to_current(highBoxArrayHTF, length_extend_liq, timediff)
extend_box_to_current(lowBoxArrayHTF, length_extend_liq, timediff)
 
tf1_buy_side_liquidity_break = array.size(highLineArrayHTF) > 0 ? close > line.get_y1(array.get(highLineArrayHTF, array.size(highLineArrayHTF) - 1)) : na
tf1_sell_side_liquidity_break = array.size(lowLineArrayHTF) > 0 ? close < line.get_y1(array.get(lowLineArrayHTF, array.size(lowLineArrayHTF) - 1)) : na
tf1_buy_side_liquidity_touch = array.size(highLineArrayHTF) > 0 ? high >= line.get_y1(array.get(highLineArrayHTF, array.size(highLineArrayHTF) - 1)) : na
tf1_sell_side_liquidity_touch = array.size(lowLineArrayHTF) > 0 ? low <= line.get_y1(array.get(lowLineArrayHTF, array.size(lowLineArrayHTF) - 1)) : na
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      FAIR VALUE GAPS CALCULATIONS & FUNCTIONS     ------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
// Define missing variables
i_tfos            = 10
i_mtfos           = 50
i_fillByMid       = true
i_bullishfvgcolor = #ffc40041
i_bearishfvgcolor = #ffc4003f
i_textColor       = #ffffff
i_deleteonfill    = true
i_mtf             = "HTF"
 
// Variables for high and low of the current timeframe
var float htfH = na
var float htfL = na
 
// Variables for security function requests
var float sClose = na
var float sHighP2 = na
var float sLowP2 = na
var float sOpen = na
var float sBar = na
 
var float sClose2 = na
var float sHighP22 = na
var float sLowP22 = na
var float sOpen2 = na
var float sBar2 = na
 
// Variables for FVG management
var bullishgapholder = array.new_box(0)
var bearishgapholder = array.new_box(0)
var bullishgapholder_fill = array.new_box(0)
var bearishgapholder_fill = array.new_box(0)
var bullish_high_holder = array.new_line(0)
var bearish_high_holder = array.new_line(0)
var bullish_low_holder  = array.new_line(0)
var bearish_low_holder  = array.new_line(0)
var bullishmidholder    = array.new_line(0)
var bearishmidholder    = array.new_line(0)
var bullishlabelholder  = array.new_label(0)
var bearishlabelholder  = array.new_label(0)
 
var bullishgapholder2 = array.new_box(0)
var bearishgapholder2 = array.new_box(0)
var bullishgapholder_fill2 = array.new_box(0)
var bearishgapholder_fill2 = array.new_box(0)
var bullish_high_holder2 = array.new_line(0)
var bearish_high_holder2 = array.new_line(0)
var bullish_low_holder2  = array.new_line(0)
var bearish_low_holder2  = array.new_line(0)
var bullishmidholder2    = array.new_line(0)
var bearishmidholder2    = array.new_line(0)
var bullishlabelholder2  = array.new_label(0)
var bearishlabelholder2  = array.new_label(0)
 
var transparentcolor    = color.new(color.white,100)
var fvg_apper=false
var fvg_break=false
fvg_apper:=false
fvg_break:=false
 
lineStyle(x) =>
    switch x
        'Solid' => line.style_solid
        'Dashed' => line.style_dashed
        'Dotted' => line.style_dotted
 
create_fvg_func(_upperlimit,_lowerlimit,_midlimit,_bar,_boxholder,_boxholder_fill,_midholder,_highholder,_lowholder,_labelholder,_boxcolor,_mtfboxcolor, _htf)=>
    timeholder = str.tostring(i_tf)
    offset = i_mtfos
    boxbgcolor = _mtfboxcolor
    bg_color = color.new(_mtfboxcolor,90)
    if _htf == false
        timeholder := str.tostring(timeframe.period)
        offset := i_tfos
        boxbgcolor := _boxcolor
    array.push(_boxholder,box.new(_bar,_upperlimit,_bar+(timediff)*length_extend,_lowerlimit,border_color=fvg_color_fill? bg_color : na,bgcolor = fvg_color_fill? bg_color : na, extend = fvg_extend ? extend.right:extend.none,xloc = xloc.bar_time,text='',text_color=#787b86,text_halign=text.align_right,text_size=size.small))
    array.push(_boxholder_fill,box.new(_bar,_upperlimit,_bar+(timediff)*length_extend,_lowerlimit,border_color=fvg_color_fill? bg_color : na ,bgcolor = fvg_color_fill? bg_color : na, extend = fvg_extend ? extend.right:extend.none,xloc = xloc.bar_time))
    array.push(_midholder,line.new(_bar,(_lowerlimit+_upperlimit)/2.0,_bar+(timediff)*length_extend,_midlimit,color = i_midPointColor, extend = fvg_extend ? extend.right:extend.none,style=lineStyle(mid_style),width=1,xloc = xloc.bar_time))
    array.push(_lowholder,line.new(_bar,_lowerlimit,_bar+(timediff)*length_extend,_lowerlimit,color = i_fillByMid?boxbgcolor:na, extend = fvg_extend ? extend.right:extend.none,width=1,xloc = xloc.bar_time))
    array.push(_highholder,line.new(_bar,_upperlimit,_bar+(timediff)*length_extend,_upperlimit,color = i_fillByMid?boxbgcolor:na, extend = fvg_extend ? extend.right:extend.none,width=1,xloc = xloc.bar_time))
 
check_fvg_func(_close,_high,_highp2,_low,_lowp2,_open,_bar,_htf)=>
    gap=0
    thold_ = (ta.highest(_high,300) - ta.lowest(_low,300)) * math.max(max_width_fvg, 0.1) / 100.
    if _open > _close // red
        if _lowp2>_high
            if not(remove_small) or math.abs(_lowp2 -_high) > thold_
                upperlimit = _high
                lowerlimit = _lowp2
                midlimit = lowerlimit + ((upperlimit - lowerlimit) / 2.)
                gap:=1
                create_fvg_func(upperlimit,lowerlimit,midlimit,_bar,bullishgapholder,bullishgapholder_fill,bullishmidholder,bullish_high_holder,bullish_low_holder,bullishlabelholder,i_bullishfvgcolor,i_mtfbearishfvgcolor,_htf)
    else
        if _low>_highp2
            if not(remove_small) or math.abs(_low - _highp2) > thold_
                upperlimit = _low
                lowerlimit = _highp2
                midlimit = lowerlimit + ((upperlimit - lowerlimit) / 2.)
                gap:=-1
                create_fvg_func(upperlimit,lowerlimit,midlimit,_bar,bearishgapholder,bearishgapholder_fill,bearishmidholder,bearish_high_holder,bearish_low_holder,bearishlabelholder,i_bearishfvgcolor,i_mtfbullishfvgcolor,_htf)
    gap
 
delete_fvg_func(_currentgap,_currentgap_fill,_i,_boxholder,_boxholder_fill,_midholder,_highholder,_lowholder,_labelholder)=>
    if show_mitigated_fvg
        currentmid=array.get(_midholder,_i)
        currenthigh=array.get(_highholder,_i)
        currentlow=array.get(_lowholder,_i)
        if i_deleteonfill
            line.delete(currentmid)
            line.delete(currenthigh)
            line.delete(currentlow)
        else
            line.set_extend(currentmid, extend.none)
            line.set_x2(currentmid,time)
            line.set_extend(currenthigh, extend.none)
            line.set_x2(currenthigh,time)
            line.set_extend(currentlow, extend.none)
            line.set_x2(currentlow,time)
        if i_deleteonfill
            box.set_extend(_currentgap, extend.none)
            box.set_right(_currentgap, time)
            box.set_extend(_currentgap_fill, extend.none)
            box.set_right(_currentgap_fill, time)
        else
            array.push(_boxholder, _currentgap)
            array.push(_boxholder_fill, _currentgap_fill)
    else
        array.remove(_boxholder, _i)
        array.remove(_boxholder_fill, _i)
        currentmid=array.get(_midholder,_i)
        currenthigh=array.get(_highholder,_i)
        currentlow=array.get(_lowholder,_i)
        array.remove(_midholder,_i)
        array.remove(_highholder,_i)
        array.remove(_lowholder,_i)
        if i_deleteonfill
            line.delete(currentmid)
            line.delete(currenthigh)
            line.delete(currentlow)
        else
            line.set_extend(currentmid, extend.none)
            line.set_x2(currentmid,time)
            line.set_extend(currenthigh, extend.none)
            line.set_x2(currenthigh,time)
            line.set_extend(currentlow, extend.none)
            line.set_x2(currentlow,time)
        if i_deleteonfill
            box.delete(_currentgap)
            box.delete(_currentgap_fill)
        else
            box.set_extend(_currentgap,extend.none)
            box.set_right(_currentgap,time)
 
validate_fvg_func(_high,_low,_bearishgapholder,_bullishgapholder,_bearishgapholder_fill,_bullishgapholder_fill,_bearishmidholder,_bullishmidholder,_bearish_high_holder,_bullish_high_holder,_bearish_low_holder,_bullish_low_holder)=>
    fvg_removed=0
    if array.size(bullishgapholder) > 0
        for i = array.size(bullishgapholder)-1 to 0
            if fvg_extend_B
                currentgap_fill = array.get(bullishgapholder_fill,i)
                currentgap = array.get(bullishgapholder,i)
                cmid = array.get(bullishmidholder,i)
                chigh = array.get(bullish_high_holder,i)
                clow = array.get(bullish_low_holder,i)
                line.set_x2(cmid,timenow+(timediff)*length_extend)
                line.set_x2(chigh,timenow+(timediff)*length_extend)
                line.set_x2(clow,timenow+(timediff)*length_extend)
                box.set_right(currentgap_fill,timenow+(timediff)*length_extend)
                box.set_right(currentgap,timenow+(timediff)*length_extend)
            if mittigation_filt_fvg=='Touch'
                currentgap_fill = array.get(bullishgapholder_fill,i)
                currentgap = array.get(bullishgapholder,i)
                currentmid = array.get(bullishmidholder,i)
                currenthigh = array.get(bullish_high_holder,i)
                currentlow = array.get(bullish_low_holder,i)
                currenttop = box.get_top(currentgap)
                if high > currenttop
                    fvg_removed:=1
                    delete_fvg_func(currentgap,currentgap_fill,i,bullishgapholder,bullishgapholder_fill,bullishmidholder,bullish_high_holder,bullish_low_holder,bullishlabelholder)
            if mittigation_filt_fvg=='Wicks'
                currentgap_fill = array.get(bullishgapholder_fill,i)
                currentgap = array.get(bullishgapholder,i)
                currentmid = array.get(bullishmidholder,i)
                currenthigh = array.get(bullish_high_holder,i)
                currentlow = array.get(bullish_low_holder,i)
                currenttop = box.get_bottom(currentgap)
                currentbottom = box.get_top(currentgap_fill)
                if high > currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bullishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,high)
                    else
                        box.set_bottom(currentgap_f,math.max(cur_bottom,high))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if high > currenttop
                    fvg_removed:=1
                    delete_fvg_func(currentgap,currentgap_fill,i,bullishgapholder,bullishgapholder_fill,bullishmidholder,bullish_high_holder,bullish_low_holder,bullishlabelholder)
            if mittigation_filt_fvg=='Close'
                currentgap_fill = array.get(bullishgapholder_fill,i)
                currentgap = array.get(bullishgapholder,i)
                currentmid = array.get(bullishmidholder,i)
                currenthigh = array.get(bullish_high_holder,i)
                currentlow = array.get(bullish_low_holder,i)
                currenttop = box.get_bottom(currentgap)
                currentbottom = box.get_top(currentgap_fill)
                if high > currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bullishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,high)
                    else
                        box.set_bottom(currentgap_f,math.max(cur_bottom,high))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if close > currenttop
                    fvg_removed:=1
                    delete_fvg_func(currentgap,currentgap_fill,i,bullishgapholder,bullishgapholder_fill,bullishmidholder,bullish_high_holder,bullish_low_holder,bullishlabelholder)
            if mittigation_filt_fvg=='Average'
                currentgap_fill = array.get(bullishgapholder_fill,i)
                currentgap = array.get(bullishgapholder,i)
                currentmid = array.get(bullishmidholder,i)
                currenthigh = array.get(bullish_high_holder,i)
                currentlow = array.get(bullish_low_holder,i)
                currenttop = line.get_y1(currentmid)
                currentbottom = box.get_top(currentgap_fill)
                if high > currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bullishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,high)
                    else
                        box.set_bottom(currentgap_f,math.max(cur_bottom,high))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if high > currenttop
                    fvg_removed:=1
                    delete_fvg_func(currentgap,currentgap_fill,i,bullishgapholder,bullishgapholder_fill,bullishmidholder,bullish_high_holder,bullish_low_holder,bullishlabelholder)
    if array.size(bearishgapholder) > 0
        for i = array.size(bearishgapholder)-1 to 0
            if fvg_extend_B
                currentgap_fill = array.get(bearishgapholder_fill,i)
                currentgap = array.get(bearishgapholder,i)
                cmid = array.get(bearishmidholder,i)
                chigh = array.get(bearish_high_holder,i)
                clow = array.get(bearish_low_holder,i)
                line.set_x2(cmid,timenow+(timediff)*length_extend)
                line.set_x2(chigh,timenow+(timediff)*length_extend)
                line.set_x2(clow,timenow+(timediff)*length_extend)
                box.set_right(currentgap_fill,timenow+(timediff)*length_extend)
                box.set_right(currentgap,timenow+(timediff)*length_extend)
            if mittigation_filt_fvg=='Touch'
                currentgap_fill = array.get(bearishgapholder_fill,i)
                currentgap = array.get(bearishgapholder,i)
                currenttop = box.get_top(currentgap)
                currentmid = array.get(bearishmidholder,i)
                currenthigh = array.get(bearish_high_holder,i)
                currentlow = array.get(bearish_low_holder,i)
                if low < currenttop
                    fvg_removed:=-1
                    delete_fvg_func(currentgap,currentgap_fill,i,bearishgapholder,bearishgapholder_fill,bearishmidholder,bearish_high_holder,bearish_low_holder,bearishlabelholder)
            if mittigation_filt_fvg=='Wicks'
                currentgap_fill = array.get(bearishgapholder_fill,i)
                currentgap = array.get(bearishgapholder,i)
                currenttop = box.get_bottom(currentgap)
                currentmid = array.get(bearishmidholder,i)
                currenthigh = array.get(bearish_high_holder,i)
                currentlow = array.get(bearish_low_holder,i)
                currentbottom = box.get_top(currentgap_fill)
                if low < currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bearishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,low)
                    else
                        box.set_bottom(currentgap_f,math.min(cur_bottom,low))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if low < currenttop
                    fvg_removed:=-1
                    delete_fvg_func(currentgap,currentgap_fill,i,bearishgapholder,bearishgapholder_fill,bearishmidholder,bearish_high_holder,bearish_low_holder,bearishlabelholder)
            if mittigation_filt_fvg=='Close'
                currentgap_fill = array.get(bearishgapholder_fill,i)
                currentgap = array.get(bearishgapholder,i)
                currenttop = box.get_bottom(currentgap)
                currentmid = array.get(bearishmidholder,i)
                currenthigh = array.get(bearish_high_holder,i)
                currentlow = array.get(bearish_low_holder,i)
                currentbottom = box.get_top(currentgap_fill)
                if low < currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bearishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,low)
                    else
                        box.set_bottom(currentgap_f,math.min(cur_bottom,low))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if close < currenttop
                    fvg_removed:=-1
                    delete_fvg_func(currentgap,currentgap_fill,i,bearishgapholder,bearishgapholder_fill,bearishmidholder,bearish_high_holder,bearish_low_holder,bearishlabelholder)
            if mittigation_filt_fvg=='Average'
                currentgap_fill = array.get(bearishgapholder_fill,i)
                currentgap = array.get(bearishgapholder,i)
                currentmid = array.get(bearishmidholder,i)
                currenttop = line.get_y1(currentmid)
                currenthigh = array.get(bearish_high_holder,i)
                currentlow = array.get(bearish_low_holder,i)
                currentbottom = box.get_top(currentgap_fill)
                if low < currentbottom and fvg_shade_fill
                    currentgap_f = array.get(bearishgapholder_fill,i)
                    cur_bottom=box.get_bottom(currentgap_f)
                    _bottom=box.get_bottom(currentgap)
                    if _bottom==cur_bottom
                        box.set_bottom(currentgap_f,low)
                    else
                        box.set_bottom(currentgap_f,math.min(cur_bottom,low))
                    box.set_bgcolor(currentgap_f,#787b865e)
                if low < currenttop
                    fvg_removed:=-1
                    delete_fvg_func(currentgap,currentgap_fill,i,bearishgapholder,bearishgapholder_fill,bearishmidholder,bearish_high_holder,bearish_low_holder,bearishlabelholder)
    fvg_removed
 
// Request security functions
sClose  := request.security(ticker.standard(syminfo.tickerid), i_tf, close[1], barmerge.gaps_off, barmerge.lookahead_on)
sHighP2 := request.security(ticker.standard(syminfo.tickerid), i_tf, high[2], barmerge.gaps_off, barmerge.lookahead_on)
sLowP2  := request.security(ticker.standard(syminfo.tickerid), i_tf, low[2], barmerge.gaps_off, barmerge.lookahead_on)
sOpen   := request.security(ticker.standard(syminfo.tickerid), i_tf, open[1], barmerge.gaps_off, barmerge.lookahead_on)
sBar    := request.security(ticker.standard(syminfo.tickerid), i_tf, bar_index, barmerge.gaps_off, barmerge.lookahead_on)
 
if is_newbar(i_tf)
    htfH := high
    htfL := low
 
fvg_gap=0
 
validate_and_shift_fvg(_fvg_holder, _fvg_fill_holder, _mid_holder, _high_holder, _low_holder, _label_holder, max_fvg) =>
    if array.size(_fvg_holder) > max_fvg
        d_box=array.shift(_fvg_holder)
        box.delete(d_box)
    if array.size(_fvg_fill_holder) > max_fvg
        d_box=array.shift(_fvg_fill_holder)
        box.delete(d_box)
    if array.size(_mid_holder) > max_fvg
        d_line=array.shift(_mid_holder)
        line.delete(d_line)
    if array.size(_high_holder) > max_fvg
        d_line=array.shift(_high_holder)
        line.delete(d_line)
    if array.size(_low_holder) > max_fvg
        d_line=array.shift(_low_holder)
        line.delete(d_line)
 
validate_and_shift_fvg(bullishgapholder, bullishgapholder_fill, bullishmidholder, bullish_high_holder, bullish_low_holder, bullishlabelholder, max_bearish_fvg)
validate_and_shift_fvg(bearishgapholder, bearishgapholder_fill, bearishmidholder, bearish_high_holder, bearish_low_holder, bearishlabelholder, max_bullish_fvg)
 
fvg_removed=validate_fvg_func(high,low, bearishgapholder,bullishgapholder, bearishgapholder_fill, bullishgapholder_fill, bearishmidholder, bullishmidholder, bearish_high_holder, bullish_high_holder, bearish_low_holder, bullish_low_holder)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      TRENDLINES CALCULATIONS & FUNCTIONS     -----------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
// Linestyle options
get_line_style(style) =>
    switch style
        "SOLID" => line.style_solid
        "DASHED" => line.style_dashed
        "DOTTED" => line.style_dotted
 
LineStyleEnum1 = get_line_style(LineStyle1)
LineStyleEnum2 = get_line_style(LineStyle2)
 
get_max_count(option) =>
    switch option
        "2" => 2
        "4" => 4
        "6" => 6
        "8" => 8
        "10" => 10
        "12" => 12
        "14" => 14
        "16" => 16
        "18" => 18
        "20" => 20
        
maxBearishCount = get_max_count(maxBearishCountOption)
maxBullishCount = get_max_count(maxBullishCountOption)
 
lengthTL = switch lengthOption
    "SHORT" => 50
    "MID" => 100
    "LONG" => 200
    "CUSTOM" => lengthCustom
 
get_text_size(option) =>
    switch option
        "XS" => size.tiny
        "S" => size.small
        "M" => size.normal
        "L" => size.large
        "XL" => size.huge
 
textSizeTL = get_text_size(textSizeOptionTL)
 
var float bs_H = na
var float bs_L = na
var int future_bars = 500 // Limit for future bars
 
// Variables
// Downtrendline
var int phx1 = na
var float phslope = na
var float phy1 = na
var float upper = na
var float plotH = na
var bool isOnH = false
var float secondUpper = na
 
var line[] bearishSolidLines = array.new_line()
var line[] bearishDottedLines = array.new_line()
var label[] bearishLabels = array.new_label()
 
// Uptrendline
var int plx1 = na
var float plslope = na
var float ply1 = na
var float lower = na
var float plotL = na
var bool isOnL = false
var float secondLower = na
 
var line[] bullishSolidLines = array.new_line()
var line[] bullishDottedLines = array.new_line()
var label[] bullishLabels = array.new_label()
 
var line testLine = line.new(na, na, na, na, color=color.rgb(255, 255, 255, 100))
 
// Variables to hold the lines for filling
var line bearishSolidLine1 = na
var line bearishSolidLine2 = na
var line bullishSolidLine1 = na
var line bullishSolidLine2 = na
 
// Calculations
n = bar_index
ph = ta.pivothigh(lengthTL, lengthTL)
pl = ta.pivotlow(lengthTL, lengthTL)
bars = 500 
height = bars / 1 
Xaxis = math.min(math.max(1, n), bars)
Yaxis = ta.highest(Xaxis) - ta.lowest(Xaxis)
 
// Function
calculate_slope(x1, x2, y1, y2) => 
    diffX = x2 - x1
    diffY = y2 - y1
    diffY_to_Yaxis = Yaxis / diffY
    normalised_slope = (height / diffY_to_Yaxis) / diffX
    slope = diffY / diffX
    angle = math.round(math.atan(normalised_slope) * 180 / math.pi, 2)
    [normalised_slope, slope, angle]
 
add_trendline(line[] lines_array, line new_line, int max_count) =>
    array.unshift(lines_array, new_line)
    if array.size(lines_array) > max_count
        line.delete(array.pop(lines_array))
 
add_label(label[] labels_array, label new_label, int max_count) =>
    array.unshift(labels_array, new_label)
    if array.size(labels_array) > max_count
        label.delete(array.pop(labels_array))
 
draw_trendlines(line[] solid_lines, line[] dotted_lines, label[] labels_array) =>
    for i = 0 to array.size(solid_lines) - 1
        line solid_line = array.get(solid_lines, i)
        line.set_xy1(solid_line, line.get_x1(solid_line), line.get_y1(solid_line))
        line.set_xy2(solid_line, line.get_x2(solid_line), line.get_y2(solid_line))
        if i < array.size(dotted_lines)
            line dotted_line = array.get(dotted_lines, i)
            line.set_xy1(dotted_line, line.get_x1(dotted_line), line.get_y1(dotted_line))
            line.set_xy2(dotted_line, line.get_x2(dotted_line), line.get_y2(dotted_line))
        if showA and i < array.size(labels_array)
            label degree_label = array.get(labels_array, i)
            label.set_xy(degree_label, line.get_x1(solid_line), line.get_y1(solid_line))
 
// Function to extend trendlines
extend_trendline(start_x, start_y, slope, color, style, width) =>
    var int remaining_bars = future_bars
    var int curr_x = start_x
    var float curr_y = start_y
    while remaining_bars > 0
        end_x = curr_x + future_bars
        end_y = curr_y + slope * future_bars
        line.new(curr_x, curr_y, end_x, end_y, color=color, style=style, width=width)
        curr_x := end_x
        curr_y := end_y
        remaining_bars -= future_bars
 
// Execution
if not na(ph)
    if ph < phy1
        [normalised_slope, slope, angle] = calculate_slope(phx1, n-lengthTL, phy1, ph)
        testLine.set_xy1(phx1, phy1)
        testLine.set_xy2(n, ph + slope * lengthTL)
        src = close
        max_bars_back(src, 2000)
        isOnH := false
        broken = false
        if not useAngleFilter or (math.abs(angle) > anglA and math.abs(angle) < anglB)
            if not broken        
                phslope := slope
                isOnH := true
                upper := ph + slope * lengthTL
                secondUpper := upper * (1 + percent_from_first_line / 100)
                if showTrendlines
                    solid_end_x = n
                    solid_end_y = upper
                    dotted_end_x = solid_end_x + future_bars
                    dotted_end_y = solid_end_y + phslope * future_bars
                    bearish_solid_line = line.new(phx1, phy1, solid_end_x, solid_end_y, color=dnCss, style=LineStyleEnum1, width=lineThickness)
                    bearish_dotted_line = line.new(solid_end_x, solid_end_y, dotted_end_x, dotted_end_y, color=dnCss, style=LineStyleEnum2, width=lineThickness)
                    add_trendline(bearishSolidLines, bearish_solid_line, maxBearishCount)
                    add_trendline(bearishDottedLines, bearish_dotted_line, maxBearishCount)
                    extend_trendline(solid_end_x, solid_end_y, phslope, dnCss, LineStyleEnum2, lineThickness)
                    bearishSolidLine1 := bearish_solid_line
                    if showA
                        degree_label = label.new(phx1, phy1, text=str.tostring(angle) + "°", style=label.style_label_down, size=textSizeTL, color=color.rgb(255, 255, 255, 100), textcolor=angleTextColor)
                        add_label(bearishLabels, degree_label, maxBearishCount)
 
        if not useAngleFilter or (math.abs(angle) > anglA and math.abs(angle) < anglB)
            if showTrendlines
                second_solid_line = line.new(phx1, phy1 * (1 + percent_from_first_line / 100), n, secondUpper, color=dnCss, style=LineStyleEnum1, width=lineThickness)
                second_dotted_line = line.new(n, secondUpper, n + future_bars, secondUpper + phslope * future_bars, color=dnCss, style=LineStyleEnum2, width=lineThickness)
                add_trendline(bearishSolidLines, second_solid_line, maxBearishCount)
                add_trendline(bearishDottedLines, second_dotted_line, maxBearishCount)
                extend_trendline(n, secondUpper, phslope, dnCss, LineStyleEnum2, lineThickness)
                bearishSolidLine2 := second_solid_line
                if showA
                    degree_label = label.new(phx1, phy1 * (1 + percent_from_first_line / 100), text=str.tostring(angle) + "°", style=label.style_label_down, size=textSizeTL, color=color.rgb(255, 255, 255, 100), textcolor=color.rgb(255, 255, 255, 100))
                    add_label(bearishLabels, degree_label, maxBearishCount)
 
    phy1 := ph
    phx1 := n - lengthTL
 
upper += phslope
plotH := not na(ph) and ta.change(phslope) ? na : close[1] > upper[1] ? na : upper 
bs_H := ta.barssince(na(plotH))
 
if not na(pl)
    if pl > ply1
        [normalised_slope, slope, angle] = calculate_slope(plx1, n-lengthTL, ply1, pl)
        testLine.set_xy1(plx1, ply1)
        testLine.set_xy2(n, pl + slope * lengthTL)
        src = close 
        max_bars_back(src, 2000)
        isOnL := false
        broken = false
        if not useAngleFilter or (angle > anglA and angle < anglB)
            if not broken
                plslope := slope
                isOnL := true
                lower := pl + slope * lengthTL
                secondLower := lower * (1 - percent_from_first_line / 100)
                if showTrendlines
                    solid_end_x = n
                    solid_end_y = lower
                    dotted_end_x = solid_end_x + future_bars
                    dotted_end_y = solid_end_y + plslope * future_bars
                    bullish_solid_line = line.new(plx1, ply1, solid_end_x, solid_end_y, color=upCss, style=LineStyleEnum1, width=lineThickness)
                    bullish_dotted_line = line.new(solid_end_x, solid_end_y, dotted_end_x, dotted_end_y, color=upCss, style=LineStyleEnum2, width=lineThickness)
                    add_trendline(bullishSolidLines, bullish_solid_line, maxBullishCount)
                    add_trendline(bullishDottedLines, bullish_dotted_line, maxBullishCount)
                    extend_trendline(solid_end_x, solid_end_y, plslope, upCss, LineStyleEnum2, lineThickness)
                    bullishSolidLine1 := bullish_solid_line
                    if showA            
                        degree_label = label.new(plx1, ply1, text=str.tostring(angle) + "°", style=label.style_label_up, size=textSizeTL, color=color.rgb(255, 255, 255, 100), textcolor=angleTextColor)
                        add_label(bullishLabels, degree_label, maxBullishCount)
 
        if not useAngleFilter or (angle > anglA and angle < anglB)
            if showTrendlines
                second_solid_line = line.new(plx1, ply1 * (1 - percent_from_first_line / 100), n, secondLower, color=upCss, style=LineStyleEnum1, width=lineThickness)
                second_dotted_line = line.new(n, secondLower, n + future_bars, secondLower + plslope * future_bars, color=upCss, style=LineStyleEnum2, width=lineThickness)
                add_trendline(bullishSolidLines, second_solid_line, maxBullishCount)
                add_trendline(bullishDottedLines, second_dotted_line, maxBullishCount)
                extend_trendline(n, secondLower, plslope, upCss, LineStyleEnum2, lineThickness)
                bullishSolidLine2 := second_solid_line
                if showA
                    degree_label = label.new(plx1, ply1 * (1 - percent_from_first_line / 100), text=str.tostring(angle) + "°", style=label.style_label_up, size=textSizeTL, color=color.rgb(255, 255, 255, 100), textcolor=color.rgb(255, 255, 255, 100))
                    add_label(bullishLabels, degree_label, maxBullishCount)
 
    ply1 := pl
    plx1 := n - lengthTL
 
lower += plslope
plotL := not na(pl) and ta.change(plslope) ? na : close[1] < lower[1] ? na : lower
bs_L := ta.barssince(na(plotL))
 
if array.size(bearishSolidLines) > 0 and array.size(bearishDottedLines) > 0
    draw_trendlines(bearishSolidLines, bearishDottedLines, bearishLabels)
 
if array.size(bullishSolidLines) > 0 and array.size(bullishDottedLines) > 0
    draw_trendlines(bullishSolidLines, bullishDottedLines, bullishLabels)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------      MARKET STRUCTURE CALCULATIONS & FUNCTION     ------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------//
// Market Structure Function
internalLength := na(internalLength) ? 10 : internalLength
externalLength := na(externalLength) ? 50 : externalLength
 
showInternalMS = (length_option == "INTERNAL" or length_option == "ALL" or length_option == "CUSTOM") and length_option != "NONE"
showExternalMS = (length_option == "EXTERNAL" or length_option == "ALL" or length_option == "CUSTOM") and length_option != "NONE"
 
calculate_swing_points(length)=>
    var prev = 0
    prev := high[length] > ta.highest(length) ? 0 : low[length] < ta.lowest(length) ? 1 : prev[1]
    t = prev == 0 and prev[1] != 0 ? high[length] : 0
    b = prev == 1 and prev[1] != 1 ? low[length] : 0
    [t, b]
 
 
 
bosConfType = 'Candle High'
CHOCH = true
 
pivot_high_found = ta.pivothigh(high, swingSize_swing, swingSize_swing)
pivot_low_found = ta.pivotlow(low, swingSize_swing, swingSize_swing)
 
var float prevHigh_s = na, var float prevLow_s = na, var int prevHighIndex_s = na, var int prevLowIndex_s = na
bool higher_highs = false, bool lower_highs = false, bool higher_lows = false, bool lower_lows = false
 
var int prevSwing_s = 0
 
if not na(pivot_high_found)
    if na(prevHigh_s) or pivot_high_found > prevHigh_s
        higher_highs := true
        lower_highs := false
        prevSwing_s := 2
    else
        higher_highs := false
        lower_highs := true
        prevSwing_s := 1
    prevHigh_s := pivot_high_found
    prevHighIndex_s := bar_index - swingSize_swing
 
if not na(pivot_low_found)
    if na(prevLow_s) or pivot_low_found < prevLow_s
        higher_lows := false
        lower_lows := true
        prevSwing_s := -2
    else
        higher_lows := true
        lower_lows := false
        prevSwing_s := -1
    prevLow_s := pivot_low_found
    prevLowIndex_s := bar_index - swingSize_swing
 
if higher_highs and showSwing
    label.new(bar_index - swingSize_swing, pivot_high_found, 'HH', color=CLEAR, style=label.style_label_down, textcolor=swingColor, size=label_size_swing)
if lower_highs and showSwing
    label.new(bar_index - swingSize_swing, pivot_high_found, 'LH', color=CLEAR, style=label.style_label_down, textcolor=swingColor, size=label_size_swing)
if higher_lows and showSwing
    label.new(bar_index - swingSize_swing, pivot_low_found, 'HL', color=CLEAR, style=label.style_label_up, textcolor=swingColor, size=label_size_swing)
if lower_lows and showSwing
    label.new(bar_index - swingSize_swing, pivot_low_found, 'LL', color=CLEAR, style=label.style_label_up, textcolor=swingColor, size=label_size_swing)
 
// EQH & EQL //
atrEQ = ta.atr(200)
var float high_eqh = na, var float low_eqh = na
var high_eqh_pre = 0., var eq_top_x = 0, var low_eqh_pre = 0., var eq_btm_x = 0
 
if show_equal_highlow
    high_eqh := ta.pivothigh(length_eqh, length_eqh)
    low_eqh := ta.pivotlow(length_eqh, length_eqh)
    if not na(low_eqh)
        if math.min(low_eqh, low_eqh_pre) > math.max(low_eqh, low_eqh_pre) - atrEQ * eq_threshold
            eql_line = line.new(eq_btm_x, low_eqh_pre, n-length_eqh, low_eqh, color=eq_bull_color, style=line.style_dotted)
            eql_lbl = label.new(int(math.avg(n-length_eqh, eq_btm_x)), low_eqh, 'EQL', color=#00000000, textcolor=eq_bull_color, style=label.style_label_up, size=label_size_Equal)
            alert("EQL found at " + str.tostring(low_eqh), alert.freq_once_per_bar)
        low_eqh_pre := low_eqh
        eq_btm_x := n-length_eqh
    if not na(high_eqh)
        if math.max(high_eqh, high_eqh_pre) < math.min(high_eqh, high_eqh_pre) + atrEQ * eq_threshold
            eqh_line = line.new(eq_top_x, high_eqh_pre, n-length_eqh, high_eqh, color=eq_bear_color, style=line.style_dotted)
            eqh_lbl = label.new(int(math.avg(n-length_eqh, eq_top_x)), high_eqh, 'EQH', color=#00000000, textcolor=eq_bear_color, style=label.style_label_down, size=label_size_Equal)
            alert("EQH found at " + str.tostring(high_eqh), alert.freq_once_per_bar)
        high_eqh_pre := high_eqh
        eq_top_x := n-length_eqh
 
[high_ms, low_ms] = calculate_swing_points(externalLength)
n := bar_index
 
// HL OUTPUT FUNCTION //
hl() => [high, low]
var float thold = (ta.highest(300) - ta.lowest(300)) * math.max(0.5, 0.1) / 100.
[int_high_ms, int_low_ms] = calculate_swing_points(internalLength)
if low_ms
    crossed_down := true
    y_dn := low_ms
    x_dn := n - externalLength
if high_ms
    crossed_up := true
    y_up := high_ms
    x_up := n - externalLength
if int_low_ms
    internal_dn_broke := true
    internal_y_dn := int_low_ms
    internal_x_dn := n - internalLength
if int_high_ms
    internal_up_broke := true
    internal_y_up := int_high_ms
    internal_x_up := n - internalLength
bull_CHOCH = false, bull_CHOCH_ = false, bull_bos = false, bull_bos_ = false, bear_CHOCH = false, bear_CHOCH_ = false, bear_bos = false, bear_bos_ = false
if ta.crossover(close, internal_y_up) and internal_up_broke and y_up != internal_y_up
    bool MSS = na
    CHOCH := int_t_MS < 0
    internal_up_broke := false
    int_t_MS := 1
    bull_CHOCH := CHOCH ? true : false
    bull_bos := CHOCH ? false : true
    if showInternalMS
        Show_MS(internal_x_up, internal_y_up, CHOCH ? 'CHOCH' : 'BOS', internalBullColor, true, true, label_size_Internal_s)
if ta.crossunder(close, internal_y_dn) and internal_dn_broke and y_dn != internal_y_dn
    bool MSS = false
    CHOCH := int_t_MS > 0
    internal_dn_broke := false
    int_t_MS := -1
    bear_CHOCH := CHOCH ? true : false
    bear_bos := CHOCH ? false : true
    if showInternalMS
        Show_MS(internal_x_dn, internal_y_dn, CHOCH ? 'CHOCH' : 'BOS', internalBearColor, true, false, label_size_Internal_s)
 
if ta.crossover(close, y_up) and crossed_up
    bool MSS = na
    MSS := t_MS < 0
    crossed_up := false
    t_MS := 1
    bull_CHOCH_ := MSS ? true : false
    bull_bos_ := MSS ? false : true
    if showExternalMS
        Show_MS(x_up, y_up, MSS ? 'CHOCH+' : 'BOS+', externalBullColor, false, true, label_size_External_s)
if ta.crossunder(close, y_dn) and crossed_down
    bool MSS = na
    MSS := t_MS > 0
    crossed_down := false
    t_MS := -1
    bear_CHOCH_ := MSS ? true : false
    bear_bos_ := MSS ? false : true
    if showExternalMS
        Show_MS(x_dn, y_dn, MSS ? 'CHOCH+' : 'BOS+', externalBearColor, false, false, label_size_External_s)
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
//------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------       ALERTS     ---------------------------------------------------------------------//
//------------------------------------------------------------------------------------------------------------------------------------------------------///
// ALERTS OB & BB
// Predefined alert messages with placeholders
const string bullishOBMessage = "{{exchange}}:{{ticker}} New Bullish Order Block detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bearishOBMessage = "{{exchange}}:{{ticker}} New Bearish Order Block detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bullishBBMessage = "{{exchange}}:{{ticker}} New Bullish Breaker Block detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bearishBBMessage = "{{exchange}}:{{ticker}} New Bearish Breaker Block detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bullishOBTouchedMessage = "{{exchange}}:{{ticker}} Bullish Order Block Touched detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bearishOBTouchedMessage = "{{exchange}}:{{ticker}} Bearish Order Block Touched detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bullishBBTouchedMessage = "{{exchange}}:{{ticker}} Bullish Breaker Block Touched detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
const string bearishBBTouchedMessage = "{{exchange}}:{{ticker}} Bearish Breaker Block Touched detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}"
 
// Alert for new bullish order block
alertcondition(condition = bullish_OB_Break, title = "New Bullish Order Block", message = bullishOBMessage)
// Alert for new bearish order block
alertcondition(condition = bearish_OB_Break, title = "New Bearish Order Block", message = bearishOBMessage)
 
// Detecting bullish and bearish breaker blocks
bullishBreakerCreated = ta.crossover(high, ta.highest(high, 10))
bearishBreakerCreated = ta.crossunder(low, ta.lowest(low, 10))
// Alert for new bullish breaker block
alertcondition(condition = bullishBreakerCreated, title = "New Bullish Breaker Block", message = bullishBBMessage)
// Alert for new bearish breaker block
alertcondition(condition = bearishBreakerCreated, title = "New Bearish Breaker Block", message = bearishBBMessage)
 
// Conditions for touching OBs and BBs
bullishOBTouched = ta.crossover(close, high)
bearishOBTouched = ta.crossunder(close, low)
// Alert for bullish order block touched
alertcondition(condition = bullishOBTouched, title = "Bullish Order Block Touched", message = bullishOBTouchedMessage)
// Alert for bearish order block touched
alertcondition(condition = bearishOBTouched, title = "Bearish Order Block Touched", message = bearishOBTouchedMessage)
 
// Conditions for touching BBs
bullishBBTouched = ta.crossover(close, high)
bearishBBTouched = ta.crossunder(close, low)
// Alert for bullish breaker block touched
alertcondition(condition = bullishBBTouched, title = "Bullish Breaker Block Touched", message = bullishBBTouchedMessage)
// Alert for bearish breaker block touched
alertcondition(condition = bearishBBTouched, title = "Bearish Breaker Block Touched", message = bearishBBTouchedMessage)
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ALERTS Liquidity Levels
alertcondition(pivotHighHTF, title="TF #1 Buy Side 💲 Detected", message="{{exchange}}:{{ticker}}, Buy Side 💲 Detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(pivotLowHTF, title="TF #1 Sell Side 💲 Detected", message="{{exchange}}:{{ticker}}, Sell Side 💲 Detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
 
alertcondition(tf1_buy_side_liquidity_break, title="TF #1 Buy Side 💲 Break", message="{{exchange}}:{{ticker}}, Buy Side 💲 Break on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(tf1_sell_side_liquidity_break, title="TF #1 Sell Side 💲 Break", message="{{exchange}}:{{ticker}}, Sell Side 💲 Break on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
 
alertcondition(tf1_buy_side_liquidity_touch, title="TF #1 Buy Side 💲 Touch", message="{{exchange}}:{{ticker}}, Buy Side 💲 Touch on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(tf1_sell_side_liquidity_touch, title="TF #1 Sell Side 💲 Touch", message="{{exchange}}:{{ticker}}, Sell Side 💲 Touch on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FVG ALERTS
if show_fvg and is_newbar(i_tf) and (i_mtf == "Current + HTF" or i_mtf == "HTF") and barstate.isconfirmed
    fvg_gap:=check_fvg_func(sClose,htfH,sHighP2,htfL,sLowP2,sOpen,time[2],true)
 
// Alerts for bullish FVG detection
alertcondition(fvg_gap == 1, title="Bullish FVG Detected", message="{{exchange}}:{{ticker}}, Bullish FVG Detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
// Alerts for bearish FVG detection
alertcondition(fvg_gap == -1, title="Bearish FVG Detected", message="{{exchange}}:{{ticker}}, Bearish FVG Detected on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
 
// Alerts for bullish FVG break
alertcondition(fvg_removed == 1, title="Bullish FVG Break", message="{{exchange}}:{{ticker}}, Bullish FVG Break on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
// Alerts for bearish FVG break
alertcondition(fvg_removed == -1, title="Bearish FVG Break", message="{{exchange}}:{{ticker}}, Bearish FVG Break on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
 
// Alerts for bullish FVG touch
alertcondition(fvg_gap == 1 and (mittigation_filt_fvg == 'Touch' or mittigation_filt_fvg == 'Wicks' or mittigation_filt_fvg == 'Close' or mittigation_filt_fvg == 'Average'), title="Bullish FVG Touch", message="{{exchange}}:{{ticker}}, Bullish FVG Touch on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
// Alerts for bearish FVG touch
alertcondition(fvg_gap == -1 and (mittigation_filt_fvg == 'Touch' or mittigation_filt_fvg == 'Wicks' or mittigation_filt_fvg == 'Close' or mittigation_filt_fvg == 'Average'), title="Bearish FVG Touch", message="{{exchange}}:{{ticker}}, Bearish FVG Touch on SMC by WeloTrades, price = {{close}}, volume = {{volume}}, FVG Indicator")
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ALERTS TRENDLINES
const string bearishTrendlineMadeMessage = "{{exchange}}:{{ticker}}, (Bearish Trendline Made) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
const string bullishTrendlineMadeMessage = "{{exchange}}:{{ticker}}, (Bullish Trendline Made) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
const string bearishTrendlineBrokenMessage = "{{exchange}}:{{ticker}}, (Bearish Trendline Broken) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
const string bullishTrendlineBrokenMessage = "{{exchange}}:{{ticker}}, (Bullish Trendline Broken) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
const string bearishTrendlineTouchedMessage = "{{exchange}}:{{ticker}}, (Bearish Trendline Touched) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
const string bullishTrendlineTouchedMessage = "{{exchange}}:{{ticker}}, (Bullish Trendline Touched) on: Trend Lines By WeloTrades! price = {{close}}, volume = {{volume}}"
 
// Alert conditions for trendlines made
alertcondition(not na(ph), title="Bearish Trendline Made", message=bearishTrendlineMadeMessage)
alertcondition(not na(pl), title="Bullish Trendline Made", message=bullishTrendlineMadeMessage)
 
// Alert conditions for trendlines broken
alertcondition(ta.cross(close, plotH), title="Bearish Trendline Broken", message=bearishTrendlineBrokenMessage)
alertcondition(ta.cross(close, plotL), title="Bullish Trendline Broken", message=bullishTrendlineBrokenMessage)
 
// Alert conditions for trendlines touched
bearishTrendlineTouched = not na(ta.valuewhen(ta.cross(close, plotH), close, 0))
bullishTrendlineTouched = not na(ta.valuewhen(ta.cross(close, plotL), close, 0))
 
alertcondition(bearishTrendlineTouched, title="Bearish Trendline Touched", message=bearishTrendlineTouchedMessage)
alertcondition(bullishTrendlineTouched, title="Bullish Trendline Touched", message=bullishTrendlineTouchedMessage)
 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Alerts for Market Structure Changes
alertcondition(bull_CHOCH, "Bullish CHOCH", "{{exchange}}:{{ticker}}, 'Bullish CHOCH' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bear_CHOCH, "Bearish CHOCH", "{{exchange}}:{{ticker}}, 'Bearish CHOCH' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bull_CHOCH_, "Bullish CHOCH+", "{{exchange}}:{{ticker}}, 'Bullish CHOCH+' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bear_CHOCH_, "Bearish CHOCH+", "{{exchange}}:{{ticker}}, 'Bearish CHOCH+' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bull_bos, "Bullish BOS", "{{exchange}}:{{ticker}}, 'Bullish BOS' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bear_bos, "Bearish BOS", "{{exchange}}:{{ticker}}, 'Bearish BOS' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bear_bos_, "Bearish BOS+", "{{exchange}}:{{ticker}}, 'Bearish BOS+' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(bull_bos_, "Bullish BOS+", "{{exchange}}:{{ticker}}, 'Bullish BOS+' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
 
// Alerts for EQH & EQL
alertcondition(not na(high_eqh), "Equal Highs", "{{exchange}}:{{ticker}}, 'EQH' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(not na(low_eqh), "Equal Lows", "{{exchange}}:{{ticker}}, 'EQL' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
 
// Alerts for Swing Points
alertcondition(higher_highs and showSwing , "Higher High (HH)", "{{exchange}}:{{ticker}}, 'HH' found on on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(lower_highs and showSwing , "Lower High (LH)", "{{exchange}}:{{ticker}}, 'LH' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(higher_lows and showSwing , "Higher Low (HL)", "{{exchange}}:{{ticker}}, 'HL' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
alertcondition(lower_lows and showSwing , "Lower Low (LL)", "{{exchange}}:{{ticker}}, 'LL' found on SMC by WeloTrades, price = {{close}}, volume = {{volume}}")
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

← 返回列表