BJorgum

Trading
mail@pastecode.io avatar
unknown
plain_text
2 years ago
45 kB
6
Indexable
Never
// █▀▀▄ ──▀ █▀▀█ █▀▀█ █▀▀▀ █──█ █▀▄▀█ 
// █▀▀▄ ──█ █──█ █▄▄▀ █─▀█ █──█ █─▀─█ 
// ▀▀▀─ █▄█ ▀▀▀▀ ▀─▀▀ ▀▀▀▀ ─▀▀▀ ▀───▀

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

//@version=5
indicator           ('Bjorgum Key Levels', 'Bj Key Levels', overlay= true, max_boxes_count= 500, max_labels_count= 500, max_lines_count=500)

import              Bjorgum/BjCandlePatterns/2 as bj

// ================================== //
// ------------> Tips <-------------- //
// ================================== //

leftTip         =   "Look left for swing high/low in x number of bars to form pivot. The higher the number, the higher the script looks to the left for the highest/lowest point before drawing pivot"        
rightTip        =   "Look right for swing high/low in x number of bars to form pivot. The higher the number, the higher the script looks to the right for the highest/lowest point before drawing pivot"       
nPivTip         =   "This sets the array size, or the number of pivots to track at a time (x highs, and x number of lows)" 
atrLenTip       =   "Number of bars to average. ATR is used to standardize zone width between assets and timeframes"     
multTip         =   "ATR multiplier to set zone width. Default is half of one ATR from box bottom to box top"     
perTip          =   "Max zone size as a percent of price. Some assets can be too volatile at low prices creating an unreasonably sized zone"
maxTip          =   "Number of boxes for candlestick patterns to track historically. Note: the higher the number the less pivot zones will be tracked when looking back in time due to the limitation on the number of box elements allowed at once"
futTip          =   "Number of bars to offset labels for price levels"
srcTip          =   "Source input for pivots. Default tracks the highest and lowest bodies of HA candles to average price action, which can result in a level that sits in the overlap of support and resistance"     
alignZonesTip   =   "Aligns recurring zones who's edges overlap an existing zone creating a zone that ages in time and intensifies visually"     
extendTip       =   "Extends current zones right"
lLabTip         =   "Show labels for price levels extended off Key Levels"

dhighsTip       =   "Disabling will prevent highs from being tracked"          
dlowsTip        =   "Disabling will prevent lows from being tracked"         
detectBOTip     =   "Show points that price action breaks above all pivots. An arrow from below is displayed"        
detectBDTip     =   "Show points that price action breaks below all pivots. An arrow from above is displayed"         
breakUpTip      =   "Show points that price action breaks above resistance. An arrow from below is displayed"         
breakDnTip      =   "Show points that price action breaks below support. An arrow from above is displayed"          
falseBullTip    =   "Show points that price action initially breaks below support before reversing. False moves can lead to fast moves in the opposite direction (bear trap). A large arrow from below is displayed"          
falseBearTip    =   "Show points that price action initially breaks above resistance before reversing. False moves can lead to fast moves in the opposite direction (bull trap). A large arrow from above is displayed"           
supPushTip      =   "Show up candles that are detected within a support zone. Can show points support is being respected. A triangle from below is displayed"          
resPushTip      =   "Show down candles that are detected within a resistance zone. Can show points resistance is being respected. A triangle from above is displayed"           
curlTip         =   "Show Bjorgum TSI 'curl' when candles are detected in the range of a key zone. Can show momentum shift at Key Levels. (Correlates to Bjorgum TSI indicator)" 

repaintTip      =   "Wait for candles end before detecting patterns. False will show potential patterns forming before they are confirmed."
labelsTip       =   "Show a label for detected candle patterns"
sBoxTip         =   "Show a box around detected candle patterns"
dTip            =   "Detect Doji candle patterns"      
beTip           =   "Detect Engulfing patterns"     
hsTip           =   "Detect Hammers and Shooting Star patterns"     
dgTip           =   "Detect Dragonfly Doji and Gravestone Doji patterns"     
twTip           =   "Detect Tweezer Top and Tweezer Bottom patterns"     
stTip           =   "Detect Spinning Top patterns"     
pcTip           =   "Detect Piercing and Dark Cloud Cover patterns"     
bhTip           =   "Detect Harami candle patterns"     
lsTip           =   "Detect Long Upper Shadow and Long Lower Shadow patterns"     

ecWickTip       =   "Determines if engulfing candles must engulf the wick or just the body of the preceding candle"     
colorMatchTip   =   "Determines if hammers must be up candles and shooting stars must be down candles"     
closeHalfTip    =   "Determines if Tweezer patterns must close beyond the half way point of the preceding candle"     
atrMaxTip       =   "Maximum size of setup candles (as a multiplier of the current ATR)"     
rejectWickTip   =   "The maximum wick size as a percentage of body size allowable for a rejection wick on the resolution candle of the pattern. 0 disables the filter"
hammerFibTip    =   "The relationship of body to candle size for hammers and stars. (ie. body is 33% of total candle size)."     
hsShadowPercTip =   "The maximum allowable opposing wick size as a percent of body size (ex. top wick for a hammer pattern etc.)"     
hammerSizeTip   =   "The minimum size of hammers, stars, or long shadows as a multiplier of ATR. (To filter out tiny setups)"     
dojiSizeTip     =   "The relationship of body to candle size (ie. body is 5% of total candle size)."     
dojiWickSizeTip =   "Maximum wick size comparative to the opposite wick. (eg. 2 = bottom wick must be less than or equal to 2x the top wick)."     
luRatioTip      =   "A relationship of the upper wick to the overall candle size expressed as a percent."     

lookbackTip     =   "Number of candles that can be included in a false break signal"        
swingTip        =   "Swing detection is used to filter signals on breakout type signals. A higher number will mean more significant points, but less of them"        
reflectTip      =   "Filter to ensure a setup is a significant swing point. Look back this far"
offsetTip       =   "Candle pattern high/low distance from absolute swing high/low. Example: 0 would filter patterns that are only the highest/lowest, 1 filters second highest over the significant length, etc."

bullPivotTip    =   "Color of bullish Key Levels\n(border, background)"            
bearPivotTip    =   "Color of bearish Key Levels\n(border, background)"            
breakoutTip     =   "Color of breakout arrows\n(bull, bear,)"           
SnRTip          =   "Color of triangles for broken support or resistance\n(bull, bear)"   
falseBreakTip   =   "Color of arrows for false breaks\n(bull, bear, arrow max height in pixels)"            
moveTip         =   "Color of triangles for candles that are detected within zones\n(bull, bear)"    
patTip          =   "Color of boxes that wrap candestick patterns\nBackgrounds: (bull, neutral, bear)\nBorders: (bull, neutral, bear)"    
labTip          =   "Color of labels that mark candestick patterns\nText: (bull, neutral, bear)\nLabels: (bull, neutral, bear)"    
stratTip        =   "TSI speed control presets. Both speeds correlate to the Bjorgum TSI indicator"

// ================================== //
// ---------> User Input <----------- //
// ================================== //

left            =   input.int       (20     ,   "Look Left"                     ,   group= "Zones"                , tooltip= leftTip            )    
right           =   input.int       (15     ,   "Look Right"                    ,   group= "Zones"                , tooltip= rightTip           )    
nPiv            =   input.int       (4      ,   "Number of Pivots"              ,   group= "Zones"                , tooltip= nPivTip            )
atrLen          =   input.int       (30     ,   "ATR Length"                    ,   group= "Zones"                , tooltip= atrLenTip          )
mult            =   input.float     (0.5    ,   "Zone Width (ATR)"              ,   group= "Zones"                , tooltip= multTip            ,   step   = 0.1)
per             =   input.float     (5      ,   "Max Zone Percent"              ,   group= "Zones"                , tooltip= perTip             )
max             =   input.float     (10     ,   "Max Boxes for Patterns"        ,   group= "Zones"                , tooltip= maxTip             )
fut             =   input.int       (30     ,   "Offset For Labels"             ,   group= "Zones"                , tooltip= futTip             )
src             =   input.string    ("HA"   ,   "Source For Pivots"             ,   group= "Zones"                , tooltip= srcTip             ,   options= ["HA", "High/Low Body", "High/Low"])
alignZones      =   input.bool      (true   ,   "Align Zones"                   ,   group= "Zones"                , tooltip= alignZonesTip      )
extend          =   input.bool      (false  ,   "Extend Right"                  ,   group= "Zones"                , tooltip= extendTip          )
lLab            =   input.bool      (false  ,   "Show Level Labels"             ,   group= "Zones"                , tooltip= lLabTip            )

dhighs          =   input.bool      (true   ,   "Detect Pivot Highs"            ,   group= "Detection"            , tooltip= dhighsTip          )
dlows           =   input.bool      (true   ,   "Detect Pivot Lows"             ,   group= "Detection"            , tooltip= dlowsTip           )
detectBO        =   input.bool      (false  ,   "Detect Breakout"               ,   group= "Detection"            , tooltip= detectBOTip        )
detectBD        =   input.bool      (false  ,   "Detect Breakdown"              ,   group= "Detection"            , tooltip= detectBDTip        )
breakUp         =   input.bool      (false  ,   "Detect Resistance Break"       ,   group= "Detection"            , tooltip= breakUpTip         )
breakDn         =   input.bool      (false  ,   "Detect Support Break"          ,   group= "Detection"            , tooltip= breakDnTip         ) 
falseBull       =   input.bool      (false  ,   "Detect False Breakdown"        ,   group= "Detection"            , tooltip= falseBullTip       )
falseBear       =   input.bool      (false  ,   "Detect False Breakup"          ,   group= "Detection"            , tooltip= falseBearTip       ) 
supPush         =   input.bool      (false  ,   "Detect Moves Off Support"      ,   group= "Detection"            , tooltip= supPushTip         )
resPush         =   input.bool      (false  ,   "Detect Moves Off Resistance"   ,   group= "Detection"            , tooltip= resPushTip         ) 
curl            =   input.bool      (false  ,   "Detect TSI Curl"               ,   group= "Detection"            , tooltip= curlTip            ) 

repaint         =   input.bool      (true   ,   "Wait For Confirmed Bar"        ,   group= "Candle Patterns"      , tooltip= repaintTip         )
labels          =   input.bool      (false  ,   "Show Label"                    ,   group= "Candle Patterns"      , tooltip= labelsTip          )
sBox            =   input.bool      (false  ,   "Show Boxes Around Patterns"    ,   group= "Candle Patterns"      , tooltip= sBoxTip            )
d_              =   input.bool      (false  ,   "Detect Doji"                   ,   group= "Candle Patterns"      , tooltip= dTip               )
be_             =   input.bool      (false  ,   "Detect Engulfing"              ,   group= "Candle Patterns"      , tooltip= beTip              )
hs_             =   input.bool      (false  ,   "Detect Hammers and Stars"      ,   group= "Candle Patterns"      , tooltip= hsTip              )
dg_             =   input.bool      (false  ,   "Detect Dragons and Graves"     ,   group= "Candle Patterns"      , tooltip= dgTip              )
tw_             =   input.bool      (false  ,   "Detect Tweezers"               ,   group= "Candle Patterns"      , tooltip= twTip              )
st_             =   input.bool      (false  ,   "Detect Spinning Top"           ,   group= "Candle Patterns"      , tooltip= stTip              )
pc_             =   input.bool      (false  ,   "Detect Piercing and Clouds"    ,   group= "Candle Patterns"      , tooltip= pcTip              )
bh_             =   input.bool      (false  ,   "Detect Harami"                 ,   group= "Candle Patterns"      , tooltip= bhTip              )
ls_             =   input.bool      (false  ,   "Detect Long Shadows"           ,   group= "Candle Patterns"      , tooltip= lsTip              )

alertMode       =   input.string    (alert.freq_once_per_bar_close              ,   "Alerts Mode"                 , group  = "Alert Frequency"  ,   options= [alert.freq_once_per_bar, alert.freq_once_per_bar_close]) 

ecWick          =   input.bool      (false  ,   "Engulfing Must Engulf Wick"    ,   group= "Candle Filters"       , tooltip= ecWickTip          )
colorMatch      =   input.bool      (false  ,   "H&S Must Match Color"          ,   group= "Candle Filters"       , tooltip= colorMatchTip      )
closeHalf       =   input.bool      (false  ,   "Tweezer Close Over Half"       ,   group= "Candle Filters"       , tooltip= closeHalfTip       )
atrMax          =   input.float     (0.0    ,   "Max Candle Size (× ATR)"       ,   group= "Candle Filters"       , tooltip= atrMaxTip          ,   step= 0.1 )
rejectWickMax   =   input.float     (0.0    ,   "[EC] Max Reject Wick Size"     ,   group= "Candle Filters"       , tooltip= rejectWickTip      ,   step= 1   )  
hammerFib       =   input.float     (33     ,   "[HS] H&S Ratio (%)"            ,   group= "Candle Filters"       , tooltip= hammerFibTip       ,   step= 1   ) 
hsShadowPerc    =   input.float     (5      ,   "[HS] H&S Opposing Shadow (%)"  ,   group= "Candle Filters"       , tooltip= hsShadowPercTip    ,   step= 1   ) 
hammerSize      =   input.float     (0.1    ,   "[HS] H&S Min Size (× ATR)"     ,   group= "Candle Filters"       , tooltip= hammerSizeTip      ,   step= 0.1 ) 
dojiSize        =   input.float     (5      ,   "[DJ] Doji Size (%)"            ,   group= "Candle Filters"       , tooltip= dojiSizeTip        ,   step= 1   )
dojiWickSize    =   input.float     (2      ,   "[DJ] Max Doji Wick Size"       ,   group= "Candle Filters"       , tooltip= dojiWickSizeTip    ,   step= 1   )
luRatio         =   input.float     (75     ,   "[LS] Long Shadow (%)"          ,   group= "Candle Filters"       , tooltip= luRatioTip         ,   step= 1   ) 

lookback        =   input.int       (2      ,   "Lookback For Breaks"           ,   group= "Lookback"             , tooltip= lookbackTip        )
swing           =   input.int       (5      ,   "swing High/Low"                ,   group= "Lookback"             , tooltip= swingTip           )
reflect         =   input.int       (10     ,   "Significant High/Low"          ,   group= "Lookback"             , tooltip= reflectTip         )
offset          =   input.int       (1      ,   "Consider Bar From High/Low"    ,   group= "Lookback"             , tooltip= offsetTip          )

bullBorder      =   input.color     (color.new  (#64b5f6, 60), "", inline= "0"  ,   group= "Pivot Color"                                        )
bullBgCol       =   input.color     (color.new  (#64b5f6, 95), "", inline= "0"  ,   group= "Pivot Color"          , tooltip= bullPivotTip       )
bearBorder      =   input.color     (color.new  (#ffeb3b, 60), "", inline= "1"  ,   group= "Pivot Color"                                        )   
bearBgCol       =   input.color     (color.new  (#ffeb3b, 95), "", inline= "1"  ,   group= "Pivot Color"          , tooltip= bearPivotTip       )

upCol           =   input.color     (color.new  (#ff6d00, 25), "", inline= "2"  ,   group= "Breakout Color"                                     )
dnCol           =   input.color     (color.new  (#ff00ff, 25), "", inline= "2"  ,   group= "Breakout Color"       , tooltip= breakoutTip        ) 

supCol          =   input.color     (color.new  (#17ff00, 25), "", inline= "3"  ,   group= "S&R Break Color"                                    )
resCol          =   input.color     (color.new  (#ff0000, 25), "", inline= "3"  ,   group= "S&R Break Color"      , tooltip= SnRTip             ) 

fBull           =   input.color     (color.new  (#17ff00, 25), "", inline= "4"  ,   group= "False Break Color"                                  )
fBear           =   input.color     (color.new  (#ff0000, 25), "", inline= "4"  ,   group= "False Break Color"                                  )
arrowMax        =   input.int       (75                      , "", inline= "4"  ,   group= "False Break Color"    , tooltip= falseBreakTip      )

moveBullCol     =   input.color     (color.new  (#64b5f6, 25), "", inline= "5"  ,   group= "Moves From S&R Color"                               )
moveBearCol     =   input.color     (color.new  (#ffeb3b, 25), "", inline= "5"  ,   group= "Moves From S&R Color" , tooltip= moveTip            ) 

curlBullCol     =   input.color     (color.new  (#17ff00, 40), "", inline= "6"  ,   group= "Momentum Curl Color"                                )
curlBearCol     =   input.color     (color.new  (#f3ff00, 40), "", inline= "6"  ,   group= "Momentum Curl Color"  , tooltip= curlTip            ) 

patBullBg       =   input.color     (color.new  (#17ff00, 90), "", inline= "7"  ,   group= "Pattern Box Color"                                  )
patNeutBg       =   input.color     (color.new  (#b2b5be, 90), "", inline= "7"  ,   group= "Pattern Box Color"                                  )
patBearBg       =   input.color     (color.new  (#ff0000, 90), "", inline= "7"  ,   group= "Pattern Box Color"                                  )
patBullBo       =   input.color     (color.new  (#17ff00, 80), "", inline= "8"  ,   group= "Pattern Box Color"                                  )
patNeutBo       =   input.color     (color.new  (#b2b5be, 80), "", inline= "8"  ,   group= "Pattern Box Color"                                  )
patBearBo       =   input.color     (color.new  (#ff0000, 80), "", inline= "8"  ,   group= "Pattern Box Color"    , tooltip= patTip             ) 

textBullCol     =   input.color     (color.new  (#17ff00,  0), "", inline= "9"  ,   group= "Label Color (Text/Bg)"                              )
textNeutCol     =   input.color     (color.new  (#b2b5be,  0), "", inline= "9"  ,   group= "Label Color (Text/Bg)"                              )
textBearCol     =   input.color     (color.new  (#ff0000,  0), "", inline= "9"  ,   group= "Label Color (Text/Bg)"                              )
labBullCol      =   input.color     (color.new  (#17ff00, 80), "", inline= "10" ,   group= "Label Color (Text/Bg)"                              )
labNeutCol      =   input.color     (color.new  (#b2b5be, 80), "", inline= "10" ,   group= "Label Color (Text/Bg)"                              )
labBearCol      =   input.color     (color.new  (#ff0000, 80), "", inline= "10" ,   group= "Label Color (Text/Bg)", tooltip= labTip             ) 

strat           =   input.string    ("Fast" ,   "Select a Speed"                ,   group= "TSI Speed Control"    , tooltip= stratTip           ,   options= ["Fast", "Slow"])
    
longf           =   input.int       (25     ,   "Long Length"                   ,   group= "TSI Fast Settings"                                  )
shortf          =   input.int       (5      ,   "Short Length"                  ,   group= "TSI Fast Settings"                                  )
signalf         =   input.int       (14     ,   "Signal Length"                 ,   group= "TSI Fast Settings"                                  )

longs           =   input.int       (25     ,   "Long Length"                   ,   group= "TSI Slow Settings"                                  )
shorts          =   input.int       (13     ,   "Short Length"                  ,   group= "TSI Slow Settings"                                  )
signals         =   input.int       (13     ,   "Signal Length"                 ,   group= "TSI Slow Settings"                                  )

// ================================== //
// -----> Immutable Constants <------ //
// ================================== //    
 
sync            =   bar_index
labUp           =   label.style_label_up
labDn           =   label.style_label_down
confirmed       =   barstate.isconfirmed
extrap          =   extend ?        extend.right  : extend.none

var pivotHigh   =   array.new_box   (nPiv)
var pivotLows   =   array.new_box   (nPiv)  
var highBull    =   array.new_bool  (nPiv)
var lowsBull    =   array.new_bool  (nPiv)
var boxes       =   array.new_box   ()

haSrc           =   src    ==       "HA"    
hiLoSrc         =   src    ==       "High/Low"
tsifast         =   strat  ==       "Fast"
tsislow         =   strat  ==       "Slow"

// ================================== //
// ---> Functional Declarations <---- //
// ================================== //

atr             =   ta.atr          (atrLen)
perMax          =   close*          0.02
min             =   math.min        (perMax, atr*0.3)

_haBody()       =>
    haClose     =   (open + high  +  low  + close)    / 4
    haOpen      =   float(na)
    haOpen      :=  na(haOpen[1]) ? (open + close)    / 2 : 
                   (nz(haOpen[1]) + nz(haClose[1]))   / 2
    
    [haOpen, haClose]
    
_extend(_x) =>
    for i = 0 to               array.size       (_x)-1
        box.set_right          (array.get       (_x, i), sync)
        
_arrayLoad(_x, _max, _val) =>  
    array.unshift                               (_x,   _val)   
    if  array.size                              (_x) > _max
        array.pop                               (_x)

_arrayBox(_x, _max, _val) =>  
    array.unshift                               (_x,   _val)   
    if       array.size                         (_x) > _max
        _b = array.pop                          (_x)
        if extend
            box.set_extend                      (_b, extend.none)

_arrayWrap(_x, _max, _val) =>  
    array.unshift                               (_x,   _val)   
    if  array.size                              (_x) > _max
        box.delete(array.pop                    (_x))

_delLab(_x)     =>
    if array.size(_x) > 0 
        label.delete           (array.pop       (_x))

_delLine(_x)    =>
    if array.size(_x) > 0 
        line.delete            (array.pop       (_x))

_delLevels(_x, _y)  =>
    for i = 0 to array.size                     (_x)-1
        _delLab                                 (_x)
        _delLine                                (_y)

_box(_x1, _t, _r, _b, _boCol, _bgCol, _e) =>
    box.new(                   _x1, _t, _r, _b  , 
     xloc        =             xloc.bar_index   ,
     extend      =             _e               ,
     border_color=             _boCol           ,   
     bgcolor     =             _bgCol           ) 

_wrap(_cond, _x, _bb, _bc, _bgc) =>
    _t           =             ta.highest       (high, _bb) + min
    _b           =             ta.lowest        (low , _bb) - min
    _l           =             bar_index -      _bb
    _r           =             bar_index +      1
    if  _cond
        _arrayWrap            (_x, max, _box    (_l, _t, _r, _b, _bc, _bgc, extend.none)) 

_getBox(_x,_i)   =>
    _box         =             array.get        (_x,_i)
    _t           =             box.get_top      (_box)
    _b           =             box.get_bottom   (_box)
    [_t, _b]
    
_align(_x,_y)    =>
    for i = 0 to               array.size       (_x) -1
        [_T, _B] =             _getBox          (_y, 0)
        [_t, _b] =             _getBox          (_x, i)
        if _T > _b and         _T < _t or 
           _B < _t and         _B > _b or 
           _T > _t and         _B < _b or 
           _B > _b and         _T < _t
            box.set_top        (array.get       (_y, 0), _t)
            box.set_bottom     (array.get       (_y, 0), _b)
 
_color(_x, _y)     =>
    var int _track = nPiv
    for i = 0 to               array.size       (_x) -1
        [t_, b_] =             _getBox          (_x, i)
        _isBull  =             array.get        (_y, i)
        if close > t_ and not  _isBull
            box.set_extend(    array.get        (_x, i), extend.none)
            array.set(_x, i,   _box             (sync  , t_, sync, b_, bullBorder, bullBgCol, extrap))
            array.set(_y, i,   true)
            _track += 1
        if close < b_ and _isBull
            box.set_extend(    array.get        (_x, i), extend.none)
            array.set(_x, i,   _box             (sync  , t_, sync, b_, bearBorder, bearBgCol, extrap))
            array.set(_y, i,   false)
            _track -= 1
    _track

_detect(_x,_y)      =>
    int  _i         = 0
    bool _found     = false
    bool _isBull    = na
    while (not _found and _i < array.size       (_x)  )
        [t_, b_] =             _getBox          (_x,_i)
        if low < t_ and high > b_
            _isBull :=         array.get        (_y,_i)
            _found  :=         true
        _i          +=         1
    [_found, _isBull]

_falseBreak(_l)     =>       
    bool _d         = false
    bool _u         = false
    for i = 1 to lookback
        if _l[i] < _l and _l[i+1] >= _l and _l[1] < _l 
            _d      := true
        if _l[i] > _l and _l[i+1] <= _l and _l[1] > _l 
            _u      := true
    [_d, _u]

_numLevel(_x,_y)    =>
    int _above      = 0
    int _fill       = 0
    for i = 0 to               array.size       (_x)-1
        _isBull     =          array.get        (_x,i)
        if  _isBull
            _above += 1
        if  not na(_isBull)
            _fill  += 1
    for i = 0 to               array.size       (_y)-1
        _isBull     =          array.get        (_y,i)
        if  _isBull
            _above += 1
        if  not na(_isBull)
            _fill  += 1
    [_above, _fill]  

_check(_src,_l)     =>
    bool _check     = false
    for i = 0 to _l
        if _src[i]
            _check := true
    _check

_count(_src, _l)    =>
    int _result     = 0
    for i = 0 to _l
        if _src > _src[i]
            _result += 1
    _result

_label(_x, _y, y, _s, _col1, _col2) =>
    transp = math.min   (color.t(_col1),  color.t(_col2))
    array.unshift       (_x,   label.new (sync+fut,   y                                        , 
                                          text      = str.tostring(math.round_to_mintick(y)   ), 
                                          color     = color.new(_col1, transp)                 , 
                                          style     = _s                                       , 
                                          textcolor = color.white                             ))
    if not extend and fut > 0
        array.unshift   (_y,   line.new  (sync, y, sync+fut, y, color= color.new(_col1, transp)))

_level(_x, _y)          =>
    var label [] lab    =      array.new_label  (nPiv)
    var line  [] lines  =      array.new_line   (nPiv)
    if barstate.islast and lLab
        _delLevels             (lab, lines)
        for i = 0 to           array.size       (_x)-1
            [_t, _b]    =      _getBox          (_x,i)
            _isBull     =      array.get        (_y,i)
            _col1        =     _isBull ?        bullBgCol  : bearBgCol
            _col2        =     _isBull ?        bullBorder : bearBorder
            if close >  _t 
                _label  (lab, lines, _t, labUp, _col1, _col2)
            if close <  _b 
                _label  (lab, lines, _b, labDn, _col1, _col2)
            if close <  _t and close >   _b
                _label  (lab, lines, _t, labDn, _col1, _col2)
                _label  (lab, lines, _b, labUp, _col1, _col2)

_alert(_x, _y) =>
    if _x
        alert   (_y + timeframe.period + ' chart. Price is ' + str.tostring(close), alertMode)
        
// ================================== //
// ----> Variable Calculations <----- //
// ================================== //

shortvar        =   tsifast ?           shortf  :       shorts   
longvar         =   tsifast ?           longf   :       longs    
signalvar       =   tsifast ?           signalf :       signals 

tsi             =   ta.tsi              (close,         shortvar,   longvar)
tsl             =   ta.ema              (tsi,           signalvar)

highest         =   close ==            ta.highest      (close,     right)
lowest          =   close ==            ta.lowest       (close,     right)

closeLows       =   ta.lowest           (close,         swing)
closeHigh       =   ta.highest          (close,         swing)

numLows         =   _count              (low,           reflect)
numHigh         =   _count              (high,          reflect)

[open_, close_] =   _haBody             ()

hiHaBod         =   math.max            (close_,        open_)
loHaBod         =   math.min            (close_,        open_)

hiBod           =   math.max            (close,         open)
loBod           =   math.min            (close,         open)

srcHigh         =   haSrc ?             hiHaBod :       hiLoSrc ?   high :      hiBod
srcLow          =   haSrc ?             loHaBod :       hiLoSrc ?   low  :      loBod

pivot_high      =   ta.pivothigh        (srcHigh,       left,       right)
pivot_low       =   ta.pivotlow         (srcLow,        left,       right)

perc            =   close*              (per/100)

band            =   math.min            (atr*mult,      perc)       [right]     /2

HH              =   pivot_high+         band
HL              =   pivot_high-         band

LH              =   pivot_low+          band
LL              =   pivot_low-          band

coDiff          =   close -             open

// ================================== //
// --------> Logical Order <--------- //
// ================================== //

if pivot_high and   dhighs and  confirmed
    _arrayLoad      (highBull , nPiv,   false)      
    _arrayBox       (pivotHigh, nPiv,   _box(sync[right], HH, sync, HL, bearBorder, bearBgCol, extrap))

if pivot_low  and   dlows and   confirmed
    _arrayLoad      (lowsBull , nPiv,   true)      
    _arrayBox       (pivotLows, nPiv,   _box(sync[right], LH, sync, LL, bullBorder, bullBgCol, extrap))

if alignZones
    _align          (pivotHigh,         pivotHigh)
    _align          (pivotHigh,         pivotLows)    
    _align          (pivotLows,         pivotLows)
    _align          (pivotLows,         pivotHigh)

_extend             (pivotHigh)
_extend             (pivotLows)

trackHigh       =   _color              (pivotHigh,     highBull)
trackLows       =   _color              (pivotLows,     lowsBull)

// ================================== //
// ----> Conditional Parameters <---- //
// ================================== //

isLows          =   closeLows      ==   close
isHigh          =   closeHigh      ==   close

wasLows         =   _check              (isLows,        lookback)
wasHigh         =   _check              (isHigh,        lookback)

[above, total]  =   _numLevel           (highBull,      lowsBull)

moveAbove       =   trackHigh       >   trackHigh[1]
moveBelow       =   trackLows       <   trackLows[1]

resBreak        =   (trackLows      >   trackLows[1]    or  moveAbove) 
supBreak        =   (trackHigh      <   trackHigh[1]    or  moveBelow) 

breakOut        =   moveAbove     and   highest and     above == total             
breakDwn        =   moveBelow     and   lowest  and     above == 0         

[dh, uh]        =   _falseBreak         (trackHigh) 
[dl, ul]        =   _falseBreak         (trackLows) 

falseBreakBull  =   wasLows       and   (dh or dl)
falseBreakBear  =   wasHigh       and   (uh or ul)

[fh,hb]         =   _detect             (pivotHigh,     highBull)
[fl,lb]         =   _detect             (pivotLows,     lowsBull)

bull            =   (fh or fl) and      (hb or lb)
bear            =   (fh or fl) and not  (hb or lb)

bullCheck       =   not resBreak  and   not resBreak[1] and (fh or fl) and  close > open and     (hb or lb)
bearCheck       =   not supBreak  and   not supBreak[1] and (fh or fl) and  close < open and not (hb or lb)

highrange       =   reflect-offset
lowsrange       =   offset

sigLows         =   numLows        <=   lowsrange  
sigHigh         =   numHigh        >=   highrange 

isBull1         =   sigLows       and   bull
isBear1         =   sigHigh       and   bear 

isBull2         =   (sigLows       or   sigLows[1]) and         (bull or bull[1])
isBear2         =   (sigHigh       or   sigHigh[1]) and         (bear or bear[1])

data            =   tsi > tsi[1]  and   tsi < tsl 
dtat            =   tsi < tsi[1]  and   tsi > tsl 

hMatch          =   not colorMatch or   close > open
sMatch          =   not colorMatch or   close < open

hsFilter        =   bj.barRange()  >=   hammerSize * atr
atrMaxSize      =   bj.barRange()  <=   atrMax     * atr or     atrMax == 0.0

rp              =   confirmed  or not   repaint

// ================================== //
// -----> Pattern Recognition <------ //
// ================================== //

dw              =   isBull1 and rp and d_  and atrMaxSize and bj.doji              (dojiSize           = dojiSize,         dojiWickSize    = dojiWickSize)
db              =   isBear1 and rp and d_  and atrMaxSize and bj.doji              (dojiSize           = dojiSize,         dojiWickSize    = dojiWickSize)
bew             =   isBull2 and rp and be_ and atrMaxSize and bj.bullEngulf        (maxRejectWick      = rejectWickMax,    mustEngulfWick  = ecWick) 
beb             =   isBear2 and rp and be_ and atrMaxSize and bj.bearEngulf        (maxRejectWick      = rejectWickMax,    mustEngulfWick  = ecWick)
h               =   isBull1 and rp and hs_ and atrMaxSize and bj.hammer            (ratio              = hammerFib,        shadowPercent   = hsShadowPerc) and hsFilter and hMatch
ss              =   isBear1 and rp and hs_ and atrMaxSize and bj.star              (ratio              = hammerFib,        shadowPercent   = hsShadowPerc) and hsFilter and sMatch
dd              =   isBull1 and rp and dg_ and atrMaxSize and bj.dragonflyDoji     ()
gd              =   isBear1 and rp and dg_ and atrMaxSize and bj.gravestoneDoji    ()
tb              =   isBull2 and rp and tw_ and atrMaxSize and bj.tweezerBottom     (closeUpperHalf     = closeHalf)
tt              =   isBear2 and rp and tw_ and atrMaxSize and bj.tweezerTop        (closeLowerHalf     = closeHalf)
stw             =   isBull1 and rp and st_ and atrMaxSize and bj.spinningTop       ()
stb             =   isBear1 and rp and st_ and atrMaxSize and bj.spinningTop       ()
p               =   isBull1 and rp and pc_ and atrMaxSize and bj.piercing          ()
dcc             =   isBear1 and rp and pc_ and atrMaxSize and bj.darkCloudCover    ()
bhw             =   isBull1 and rp and bh_ and atrMaxSize and bj.haramiBull        ()  
bhb             =   isBear1 and rp and bh_ and atrMaxSize and bj.haramiBear        ()
ll              =   isBull1 and rp and ls_ and atrMaxSize and bj.lls               (ratio              = luRatio)          and hsFilter
lu              =   isBear1 and rp and ls_ and atrMaxSize and bj.lus               (ratio              = luRatio)          and hsFilter

// ================================== //
// ------> Graphical Display <------- //
// ================================== //

plotFalseDn     =   falseBull     and   falseBreakBull
plotFalseUp     =   falseBear     and   falseBreakBear

falseUpCol      =   plotFalseUp     ?   upCol       :   na
falseDnCol      =   plotFalseDn     ?   dnCol       :   na

plotBreakOut    =   breakOut      and   detectBO    and not     plotFalseDn
plotBreakDn     =   breakDwn      and   detectBD    and not     plotFalseUp

plotResBreak    =   resBreak      and   breakUp     and not     (plotBreakOut or plotFalseDn)
plotSupBreak    =   supBreak      and   breakDn     and not     (plotBreakDn  or plotFalseUp)

plotBullCheck   =   bullCheck     and   supPush
plotBearCheck   =   bearCheck     and   resPush

plotCurlBull    =   curl and data and   bull
plotCurlBear    =   curl and dtat and   bear

plotarrow           (plotFalseUp    ?   coDiff      :   na      ,   colorup  = fBull          ,     colordown=      fBear ,         maxheight=      arrowMax)
plotarrow           (plotFalseDn    ?   coDiff      :   na      ,   colorup  = fBull          ,     colordown=      fBear ,         maxheight=      arrowMax)

plotshape           (plotBreakOut   ,   style=shape.arrowup     ,   location=location.belowbar,     color=          upCol ,         size=           size.small)
plotshape           (plotBreakDn    ,   style=shape.arrowdown   ,   location=location.abovebar,     color=          dnCol ,         size=           size.small)

plotshape           (plotResBreak   ,   style=shape.arrowup     ,   location=location.belowbar,     color=          supCol,         size=           size.small)
plotshape           (plotSupBreak   ,   style=shape.arrowdown   ,   location=location.abovebar,     color=          resCol,         size=           size.small)

plotshape           (plotBullCheck  ,   style=shape.triangleup  ,   location=location.belowbar,     color=          moveBullCol)
plotshape           (plotBearCheck  ,   style=shape.triangledown,   location=location.abovebar,     color=          moveBearCol)

plotshape           (plotCurlBull   ,   style=shape.triangleup  ,   location=location.belowbar,     color=          curlBullCol)
plotshape           (plotCurlBear   ,   style=shape.triangledown,   location=location.abovebar,     color=          curlBearCol)

bj.dLab             (dw  and labels, labNeutCol, textNeutCol), _wrap (dw  and sBox, boxes, 1, patNeutBo, patNeutBg)
bj.bewLab           (bew and labels, labBullCol, textBullCol), _wrap (bew and sBox, boxes, 2, patBullBo, patBullBg)
bj.hLab             (h   and labels, labBullCol, textBullCol), _wrap (h   and sBox, boxes, 1, patBullBo, patBullBg)
bj.ddLab            (dd  and labels, labBullCol, textBullCol), _wrap (dd  and sBox, boxes, 1, patBullBo, patBullBg)
bj.tbLab            (tb  and labels, labBullCol, textBullCol), _wrap (tb  and sBox, boxes, 2, patBullBo, patBullBg)
bj.stwLab           (stw and labels, labNeutCol, textNeutCol), _wrap (stw and sBox, boxes, 1, patBullBo, patNeutBg)
bj.pLab             (p   and labels, labBullCol, textBullCol), _wrap (p   and sBox, boxes, 2, patBullBo, patBullBg)
bj.hwLab            (bhw and labels, labBullCol, textBullCol), _wrap (bhw and sBox, boxes, 2, patBullBo, patBullBg)
bj.llsLab           (ll  and labels, labBullCol, textBullCol), _wrap (ll  and sBox, boxes, 1, patBullBo, patBullBg)

bj.dLab             (db  and labels, labNeutCol, textNeutCol), _wrap (db  and sBox, boxes, 1, patNeutBo, patNeutBg)
bj.bebLab           (beb and labels, labBearCol, textBearCol), _wrap (beb and sBox, boxes, 2, patBearBo, patBearBg)
bj.ssLab            (ss  and labels, labBearCol, textBearCol), _wrap (ss  and sBox, boxes, 1, patBearBo, patBearBg)
bj.gdLab            (gd  and labels, labBearCol, textBearCol), _wrap (gd  and sBox, boxes, 1, patBearBo, patBearBg)
bj.ttLab            (tt  and labels, labBearCol, textBearCol), _wrap (tt  and sBox, boxes, 2, patBearBo, patBearBg)
bj.stbLab           (stb and labels, labNeutCol, textNeutCol), _wrap (stb and sBox, boxes, 1, patBearBo, patBearBg)
bj.dccLab           (dcc and labels, labBearCol, textBearCol), _wrap (dcc and sBox, boxes, 2, patBearBo, patBearBg)
bj.hbLab            (bhb and labels, labBearCol, textBearCol), _wrap (bhb and sBox, boxes, 2, patBearBo, patBearBg)
bj.lusLab           (lu  and labels, labBearCol, textBearCol), _wrap (lu  and sBox, boxes, 1, patBearBo, patBearBg)

_level              (pivotHigh, highBull)
_level              (pivotLows, lowsBull)

// ================================== //
// -----> Alert Functionality <------ //
// ================================== //

alertcondition      (resBreak       ,   'Resistance break'                      ,   'Resistance broke on {{interval}} chart. Price is {{close}}'                    )
alertcondition      (supBreak       ,   'Support break'                         ,   'Support broke on {{interval}} chart. Price is {{close}}'                       )
alertcondition      (bullCheck      ,   'Found support'                         ,   'Pushing Off Key Level Support on {{interval}} chart. Price is {{close}}'       )
alertcondition      (bearCheck      ,   'Found resistance'                      ,   'Pushing Off Key Level Resistance on {{interval}} chart. Price is {{close}}'    )
alertcondition      (falseBreakBull ,   'False break down'                      ,   'False Break Down on {{interval}} chart. Price is {{close}}'                    )
alertcondition      (falseBreakBear ,   'False break up'                        ,   'False Break Up on {{interval}} chart. Price is {{close}}'                      )
alertcondition      (breakOut       ,   'Breakout'                              ,   'Breakout on {{interval}} chart. Price is {{close}}'                            )
alertcondition      (breakDwn       ,   'Breakdown'                             ,   'Breakdown on {{interval}} chart. Price is {{close}}'                           )

_alert              (plotResBreak   ,   'Resistance broke on '                  )
_alert              (plotSupBreak   ,   'Support break '                        )
_alert              (plotBullCheck  ,   'Pushing off key level support on '     )
_alert              (plotBearCheck  ,   'Pushing off key level resistance on '  )
_alert              (plotFalseDn    ,   'False break down on '                  )
_alert              (plotFalseUp    ,   'False break up on '                    )
_alert              (plotBreakOut   ,   'Breakout on '                          )
_alert              (plotBreakDn    ,   'Breakdown on '                         )

_alert              (dw             ,   'Doji at support on '                   )
_alert              (db             ,   'Doji at resistance on '                )
_alert              (bew            ,   'Bullish Engulfing on '                 )
_alert              (beb            ,   'Bearish Engulfing on '                 )
_alert              (h              ,   'Hammer candle on '                     )
_alert              (ss             ,   'Shooting star on '                     )
_alert              (dd             ,   'Dragonfly Doji on '                    )
_alert              (gd             ,   'Gravestone Doji on '                   )
_alert              (tb             ,   'Tweezer Bottom on '                    )
_alert              (tt             ,   'Tweezer Top on '                       )
_alert              (stw            ,   'White Spinning Top on '                )
_alert              (stb            ,   'Black Spinning Top on '                )
_alert              (p              ,   'Piercing on '                          )
_alert              (dcc            ,   'Dark Cloud Cover on '                  )
_alert              (bhw            ,   'Bullish Harami on '                    )
_alert              (bhb            ,   'Bearish Harami on '                    )
_alert              (ll             ,   'Long Lower Shadow on '                 )
_alert              (lu             ,   'Long Upper Shadow on '                 )

//  ____  __ _  ____ 
// (  __)(  ( \(    \
//  ) _) /    / ) D (
// (____)\_)__)(____/