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

//@version=5

// @description This utility function contains the general functions used in our indicators
library("DiddlyUtility")

//*****************************
// Zone Maintainance Functions*
//*****************************

export CheckZoneRelativeStateToPrice(int _lineType, bool _IsBroken, int _lineExceptionLevel, float _closePrice, float _lineUpperPrice, float _lineLowerPrice, int _zoneIndex, int _closedWithinZoneIndex, int _nearestResistanceZoneAboveIndex, float _nearestResistanceZoneAboveDistance, int _nearestBuyersZoneAboveIndex, float _nearestBuyersZoneAboveDistance, int _nearestSupportZoneBelowIndex, float _nearestSupportZoneBelowDistance, int _nearestSellersZoneBelowIndex, float _nearestSellersZoneBelowDistance) =>

	int closedWithinZoneIndex = _closedWithinZoneIndex
	int nearestResistanceZoneAboveIndex = _nearestResistanceZoneAboveIndex
	float nearestResistanceZoneAboveDistance = _nearestResistanceZoneAboveDistance
	int nearestBuyersZoneAboveIndex = _nearestBuyersZoneAboveIndex
	float nearestBuyersZoneAboveDistance = _nearestBuyersZoneAboveDistance

	int nearestSupportZoneBelowIndex = _nearestSupportZoneBelowIndex
	float nearestSupportZoneBelowDistance = _nearestSupportZoneBelowDistance
	int nearestSellersZoneBelowIndex = _nearestSellersZoneBelowIndex
	float nearestSellersZoneBelowDistance = _nearestSellersZoneBelowDistance

	
	if _lineExceptionLevel >= 2 or _lineExceptionLevel <= -2// and (_lineMethod == 1 or _lineMethod == 3)

		// Check whether Candle has closed in the zone, if so we can mark the temp active index. It will ultimately take the most recent (maybe need to change to an array at somepoint)
		if _lineLowerPrice <= _closePrice and _lineUpperPrice >= _closePrice 
			closedWithinZoneIndex := _zoneIndex

		else
			// now we want to see whether this zone is the closest from above or below of price

			// Check those Above
			if (_lineLowerPrice > _closePrice)
				if na(_nearestResistanceZoneAboveIndex) and not _IsBroken and _lineType == -1 // This is a resistance level - Null Check
					// No prevsious nearest to set this one
					nearestResistanceZoneAboveIndex := _zoneIndex
					nearestResistanceZoneAboveDistance := (_lineLowerPrice - _closePrice)

				else if na(_nearestBuyersZoneAboveIndex) and _lineType == 1 // This is a failed buyers block - Null Check
					// No prevsious nearest to set this one
					nearestBuyersZoneAboveIndex := _zoneIndex
					nearestBuyersZoneAboveDistance := (_lineLowerPrice - _closePrice)

				else if not na(_nearestResistanceZoneAboveIndex) and not _IsBroken and _lineType == -1 and (_lineLowerPrice - _closePrice) <= _nearestResistanceZoneAboveDistance // This is a resistance level - Where Previous Exists
					// Check whether this zone is closest than the previous closest. Need to ensure that this zone is above price
					nearestResistanceZoneAboveDistance := (_lineLowerPrice - _closePrice)
					nearestResistanceZoneAboveIndex := _zoneIndex

				else if not na(_nearestBuyersZoneAboveIndex) and _lineType == 1 and (_lineLowerPrice - _closePrice) <= _nearestBuyersZoneAboveDistance // This is a failed buyers block - Where Previous Exists

					nearestBuyersZoneAboveIndex := _zoneIndex
					nearestResistanceZoneAboveDistance := (_lineLowerPrice - _closePrice)

				// End Section
			//

			// Check those Below
			if (_closePrice > _lineUpperPrice)

				if na(_nearestSupportZoneBelowIndex) and not _IsBroken and _lineType == 1 // This is a support level - Null Check
					// No prevsious nearest to set this one
					nearestSupportZoneBelowIndex := _zoneIndex
					nearestSupportZoneBelowDistance := (_closePrice - _lineUpperPrice)

				else if na(nearestSellersZoneBelowIndex) and _lineType == -1 // This is a failed sellers block - Null Check
					// No prevsious nearest to set this one
					nearestSellersZoneBelowIndex := _zoneIndex
					nearestSellersZoneBelowDistance := (_closePrice - _lineUpperPrice)


				else if not na(_nearestSupportZoneBelowIndex) and not _IsBroken and _lineType == 1 and (_closePrice - _lineUpperPrice) <= _nearestSupportZoneBelowDistance // Get the closest below
					// Check whether this zone is closest than the previous closest. Need to ensure that this zone is above price
					nearestSupportZoneBelowDistance := (_closePrice - _lineUpperPrice)
					nearestSupportZoneBelowIndex := _zoneIndex

				else if not na(nearestSellersZoneBelowIndex) and _lineType == -1 and (_closePrice - _lineUpperPrice) <= nearestSellersZoneBelowDistance // This is a failed sellers block - Where Previous Exists
					nearestSellersZoneBelowIndex := _zoneIndex
					nearestSellersZoneBelowDistance := (_closePrice - _lineUpperPrice)


				// End Section
			//
		//			
	// End Condition

	[closedWithinZoneIndex, nearestResistanceZoneAboveIndex, nearestResistanceZoneAboveDistance, nearestBuyersZoneAboveIndex, nearestBuyersZoneAboveDistance, nearestSupportZoneBelowIndex, nearestSupportZoneBelowDistance, nearestSellersZoneBelowIndex, nearestSellersZoneBelowDistance]

// End Logic

export completeZoneRelativeAnalysis(int _closedWithinZoneIndex, int _nearestResistanceZoneAboveIndex, float _nearestResistanceZoneAboveDistance, int _nearestBuyersZoneAboveIndex, float _nearestBuyersZoneAboveDistance, int _nearestSupportZoneBelowIndex, float _nearestSupportZoneBelowDistance, int _nearestSellersZoneBelowIndex, float _nearestSellersZoneBelowDistance) =>

	int _activeZoneIndex = na
	int _activeResistanceAboveZone = na
	float _activeResistanceAboveZoneDistance = na
	int _activeSupportBelowZone = na
	float _activeSupportBelowZoneDistance = na

	int _activeBuyersAboveZone = na
	float _activeBuyersAboveZoneDistance = na
	int _activeSellersBelowZone = na
	float _activeSellersBelowZoneDistance = na

	//if _hasHTFclosed or _barstateConfirmed

	_activeZoneIndex := _closedWithinZoneIndex
	_activeResistanceAboveZone := _nearestResistanceZoneAboveIndex
	_activeResistanceAboveZoneDistance := _nearestResistanceZoneAboveDistance
	_activeSupportBelowZone := _nearestSupportZoneBelowIndex
	_activeSupportBelowZoneDistance := _nearestSupportZoneBelowDistance

	_activeBuyersAboveZone := _nearestBuyersZoneAboveIndex
	_activeBuyersAboveZoneDistance := _nearestBuyersZoneAboveDistance
	_activeSellersBelowZone := _nearestSellersZoneBelowIndex
	_activeSellersBelowZoneDistance := _nearestSellersZoneBelowDistance

	// End Logic

	[_activeZoneIndex, _activeResistanceAboveZone, _activeResistanceAboveZoneDistance, _activeBuyersAboveZone, _activeBuyersAboveZoneDistance, _activeSupportBelowZone, _activeSupportBelowZoneDistance, _activeSellersBelowZone, _activeSellersBelowZoneDistance]

// End Function

export addLabel (int _boxEnd, float _yPos, string _text, string _toolTip, color _textColor) =>

	label uiLabel = na
	
	if not na(_text) and str.length(_text) > 0 
		uiLabel := label.new(x=_boxEnd, y=_yPos, xloc=xloc.bar_time, style=label.style_none, size=size.small, textcolor=_textColor, text=_text)//, textalign=text.align_left)
		if not na(_toolTip)
			label.set_tooltip(uiLabel, _toolTip)
	uiLabel

export buidZoneUI (int _time, float _top, float _bottom, int _zoneMethod, int _zoneType1, int _exceptionLevel1, bool _zoneType1DisplayLabel, int _zoneType2, int _exceptionLevel2, bool _zoneType2DisplayLabel, int _boxEnd, string _border_style, string _text, string _toolTip, color _textColor, color _zoneColourBull1, color _zoneColourBull2, color _zoneColourBull3, color _zoneColourBull4, color _zoneColourBear1, color _zoneColourBear2, color _zoneColourBear3, color _zoneColourBear4, color _zoneLineColourBull1, color _zoneLineColourBull2, color _zoneLineColourBull3, color _zoneLineColourBull4, color _zoneLineColourBear1, color _zoneLineColourBear2, color _zoneLineColourBear3, color _zoneLineColourBear4, int _borderWidthActive) =>

	box uiBox = na

	if _zoneMethod == 1

		if _zoneType1 == 1 //Bullish Zones
			uiBox := switch _exceptionLevel1
				4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull4, bgcolor= _zoneColourBull4, border_style= _border_style, border_width=_borderWidthActive)
				3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull3, bgcolor= _zoneColourBull3, border_style= _border_style, border_width=_borderWidthActive)
				2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull2, bgcolor= _zoneColourBull2, border_style= _border_style, border_width=_borderWidthActive)
				1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull1, bgcolor= _zoneColourBull1, border_style= _border_style, border_width=_borderWidthActive)
				=> na
			
		else if _zoneType1 == -1 //Bearish Zones
			uiBox := switch _exceptionLevel1
				-4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear4, bgcolor= _zoneColourBear4, border_style= _border_style, border_width=_borderWidthActive)
				-3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear3, bgcolor= _zoneColourBear3, border_style= _border_style, border_width=_borderWidthActive)
				-2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear2, bgcolor= _zoneColourBear2, border_style= _border_style, border_width=_borderWidthActive)
				-1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear1, bgcolor= _zoneColourBear1, border_style= _border_style, border_width=_borderWidthActive)
				=> na

	else if _zoneMethod == 2
		if _zoneType2 == 1 //Bullish Zones
			uiBox := switch _exceptionLevel2
				4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull4, bgcolor= _zoneColourBull4, border_style= _border_style, border_width=_borderWidthActive)
				3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull3, bgcolor= _zoneColourBull3, border_style= _border_style, border_width=_borderWidthActive)
				2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull2, bgcolor= _zoneColourBull2, border_style= _border_style, border_width=_borderWidthActive)
				1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull1, bgcolor= _zoneColourBull1, border_style= _border_style, border_width=_borderWidthActive)
				=> na
			
		else if _zoneType2 == -1 //Bearish Zones
			uiBox := switch _exceptionLevel2
				-4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear4, bgcolor= _zoneColourBear4, border_style= _border_style, border_width=_borderWidthActive)
				-3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear3, bgcolor= _zoneColourBear3, border_style= _border_style, border_width=_borderWidthActive)
				-2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear2, bgcolor= _zoneColourBear2, border_style= _border_style, border_width=_borderWidthActive)
				-1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear1, bgcolor= _zoneColourBear1, border_style= _border_style, border_width=_borderWidthActive)
				=> na

	else if _zoneMethod == 3

		// because we are a combined signal we need to see the highest exception level to see which was the driving force
		int zoneType = na
		int exceptionLevel = na

		if _zoneType1 == 1 and _zoneType2 == 1
			// Both Signals in same direction
			zoneType := 1
			if _exceptionLevel1 >= _exceptionLevel2
				exceptionLevel := _exceptionLevel1
			else
				exceptionLevel := _exceptionLevel2
			//
		else if _zoneType1 == -1 and _zoneType2 == -1
			// Both Signals in same direction
			zoneType := -1
			if _exceptionLevel1 <= _exceptionLevel2
				exceptionLevel := _exceptionLevel1
			else
				exceptionLevel := _exceptionLevel2
			//
		else
			// Signals are in different directions
			if _exceptionLevel1 < 0
				if _exceptionLevel2 < _exceptionLevel1 /-1 
					exceptionLevel := _exceptionLevel1
					zoneType := _zoneType1
				else
					exceptionLevel := _exceptionLevel2
					zoneType := _zoneType2
				//
			else if _exceptionLevel2 < 0
				if _exceptionLevel2/-1 < _exceptionLevel1 /-1 
					exceptionLevel := _exceptionLevel1
					zoneType := _zoneType1
				else
					exceptionLevel := _exceptionLevel2
					zoneType := _zoneType2
				//
			//
		//
		if zoneType == 1 //Bullish Zones
			uiBox := switch exceptionLevel
				4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull4, bgcolor= _zoneColourBull4, border_style= _border_style, border_width=_borderWidthActive)
				3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull3, bgcolor= _zoneColourBull3, border_style= _border_style, border_width=_borderWidthActive)
				2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull2, bgcolor= _zoneColourBull2, border_style= _border_style, border_width=_borderWidthActive)
				1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBull1, bgcolor= _zoneColourBull1, border_style= _border_style, border_width=_borderWidthActive)
				=> na
			
		else if zoneType == -1 //Bearish Zones
			uiBox := switch exceptionLevel
				-4 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear4, bgcolor= _zoneColourBear4, border_style= _border_style, border_width=_borderWidthActive)
				-3 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear3, bgcolor= _zoneColourBear3, border_style= _border_style, border_width=_borderWidthActive)
				-2 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear2, bgcolor= _zoneColourBear2, border_style= _border_style, border_width=_borderWidthActive)
				-1 => uiBox := box.new(_time, _top, _boxEnd, _bottom, xloc=xloc.bar_time, border_color =_zoneLineColourBear1, bgcolor= _zoneColourBear1, border_style= _border_style, border_width=_borderWidthActive)
				=> na

	// Add any label
	label uiLabel = na
	
	if _zoneType1DisplayLabel and (_zoneMethod == 1 or _zoneMethod == 3)
		uiLabel := addLabel (_boxEnd, _bottom + (_top - _bottom), _text, _toolTip, _textColor)
	else if _zoneType2DisplayLabel and _zoneMethod == 2
		uiLabel := addLabel (_boxEnd, _bottom + (_top - _bottom), _text, _toolTip, _textColor)


	[uiBox, uiLabel]


export setZoneColour (box _uiBox, int _zoneMethod, int _zoneType1, bool _isBroken, int _type1ExceptionLevel, int _zoneType2, int _type2ExceptionLevel, bool _isTrapZone, color _zoneTrapBullColour, color _zoneTrapBearColour, color _zoneColourBull1, color _zoneColourBull2, color _zoneColourBull3, color _zoneColourBull4, color _zoneColourBear1, color _zoneColourBear2, color _zoneColourBear3, color _zoneColourBear4) =>

	if not na(_uiBox)
		if _isBroken
			if _zoneMethod == 1 or _zoneMethod == 3
				if _zoneType1 == 1 //Bullish Zones
					if _isTrapZone
						switch _type1ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull4,98)), box.set_border_color(_uiBox, color.new(_zoneColourBull4,95))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull3,98)), box.set_border_color(_uiBox, color.new(_zoneColourBull3,95))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull2,100)), box.set_border_color(_uiBox, color.new(_zoneColourBull2,100))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull1,100)), box.set_border_color(_uiBox, color.new(_zoneColourBull1,100))
					else
						switch _type1ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull4,95)), box.set_border_color(_uiBox, color.new(_zoneColourBull4,90))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull3,95)), box.set_border_color(_uiBox, color.new(_zoneColourBull3,90))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull2,99)), box.set_border_color(_uiBox, color.new(_zoneColourBull2,95))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull1,99)), box.set_border_color(_uiBox, color.new(_zoneColourBull1,95))
					
				else if _zoneType1 == -1 //Bearish Zones
					if _isTrapZone
						switch _type1ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear4,98)), box.set_border_color(_uiBox, color.new(_zoneColourBear4,95))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear3,98)), box.set_border_color(_uiBox, color.new(_zoneColourBear3,95))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear2,100)), box.set_border_color(_uiBox, color.new(_zoneColourBear2,100))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear1,100)), box.set_border_color(_uiBox, color.new(_zoneColourBear1,100))
					else
						switch _type1ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear4,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear4,90))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear3,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear3,90))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear2,99)), box.set_border_color(_uiBox, color.new(_zoneColourBear2,95))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear1,99)), box.set_border_color(_uiBox, color.new(_zoneColourBear1,95))

			else if _zoneMethod == 2
				if _zoneType2 == 1 //Bullish Zones
					if _isTrapZone
						switch _type2ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull4,98)), box.set_border_color(_uiBox, color.new(_zoneColourBull4,95))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull3,98)), box.set_border_color(_uiBox, color.new(_zoneColourBull3,95))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull2,100)), box.set_border_color(_uiBox, color.new(_zoneColourBull2,100))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull1,100)), box.set_border_color(_uiBox, color.new(_zoneColourBull1,100))
					else
						switch _type2ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull4,95)), box.set_border_color(_uiBox, color.new(_zoneColourBull4,90))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull3,95)), box.set_border_color(_uiBox, color.new(_zoneColourBull3,90))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull2,99)), box.set_border_color(_uiBox, color.new(_zoneColourBull2,95))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBull1,99)), box.set_border_color(_uiBox, color.new(_zoneColourBull1,95))
					
				else if _zoneType2 == -1 //Bearish Zones
					if _isTrapZone
						switch _type2ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear4,98)), box.set_border_color(_uiBox, color.new(_zoneColourBear4,95))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear3,98)), box.set_border_color(_uiBox, color.new(_zoneColourBear3,95))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear2,100)), box.set_border_color(_uiBox, color.new(_zoneColourBear2,100))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear1,100)), box.set_border_color(_uiBox, color.new(_zoneColourBear1,100))
					else
						switch _type2ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear4,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear4,90))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear3,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear3,90))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear2,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear2,95))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneColourBear1,95)), box.set_border_color(_uiBox, color.new(_zoneColourBear1,95))

		else // Not Broken

			if _zoneMethod == 1 or _zoneMethod == 3
				if _zoneType1 == 1 //Bullish Zones
					if _isTrapZone
						switch _type1ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,20))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,40))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,60))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,80))
					else
						switch _type1ExceptionLevel
							4 => box.set_bgcolor(_uiBox, _zoneColourBull4), box.set_border_color(_uiBox, _zoneColourBull4)
							3 => box.set_bgcolor(_uiBox, _zoneColourBull3), box.set_border_color(_uiBox, _zoneColourBull3)
							2 => box.set_bgcolor(_uiBox, _zoneColourBull2), box.set_border_color(_uiBox, _zoneColourBull2)
							1 => box.set_bgcolor(_uiBox, _zoneColourBull1), box.set_border_color(_uiBox, _zoneColourBull1)
					
				else if _zoneType1 == -1 //Bearish Zones
					if _isTrapZone
						switch _type1ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,20))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,40))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,60))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,80))
					else
						switch _type1ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, _zoneColourBear4), box.set_border_color(_uiBox, _zoneColourBear4)
							-3 => box.set_bgcolor(_uiBox, _zoneColourBear3), box.set_border_color(_uiBox, _zoneColourBear3)
							-2 => box.set_bgcolor(_uiBox, _zoneColourBear2), box.set_border_color(_uiBox, _zoneColourBear2)
							-1 => box.set_bgcolor(_uiBox, _zoneColourBear1), box.set_border_color(_uiBox, _zoneColourBear1)

			else if _zoneMethod == 2
				if _zoneType2 == 1 //Bullish Zones
					if _isTrapZone
						switch _type2ExceptionLevel
							4 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,20))
							3 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,40))
							2 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,60))
							1 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBullColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBullColour,80))
					else
						switch _type2ExceptionLevel
							4 => box.set_bgcolor(_uiBox, _zoneColourBull4), box.set_border_color(_uiBox, _zoneColourBull4)
							3 => box.set_bgcolor(_uiBox, _zoneColourBull3), box.set_border_color(_uiBox, _zoneColourBull3)
							2 => box.set_bgcolor(_uiBox, _zoneColourBull2), box.set_border_color(_uiBox, _zoneColourBull2)
							1 => box.set_bgcolor(_uiBox, _zoneColourBull1), box.set_border_color(_uiBox, _zoneColourBull1)
					
				else if _zoneType2 == -1 //Bearish Zones
					if _isTrapZone
						switch _type2ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,20))
							-3 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,85)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,40))
							-2 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,60))
							-1 => box.set_bgcolor(_uiBox, color.new(_zoneTrapBearColour,99)), box.set_border_color(_uiBox, color.new(_zoneTrapBearColour,80))
					else
						switch _type2ExceptionLevel
							-4 => box.set_bgcolor(_uiBox, _zoneColourBear4), box.set_border_color(_uiBox, _zoneColourBear4)
							-3 => box.set_bgcolor(_uiBox, _zoneColourBear3), box.set_border_color(_uiBox, _zoneColourBear3)
							-2 => box.set_bgcolor(_uiBox, _zoneColourBear2), box.set_border_color(_uiBox, _zoneColourBear2)
							-1 => box.set_bgcolor(_uiBox, _zoneColourBear1), box.set_border_color(_uiBox, _zoneColourBear1)


export amendBrokenLevelUI (box _uiBox, int _zoneMethod, int _zoneType1, int _type1ExceptionLevel, int _zoneType2, int _type2ExceptionLevel, int _boxEnd, string _border_style, bool _isTrapZone, color _zoneTrapBullColour, color _zoneTrapBearColour, color _zoneColourBull1, color _zoneColourBull2, color _zoneColourBull3, color _zoneColourBull4, color _zoneColourBear1, color _zoneColourBear2, color _zoneColourBear3, color _zoneColourBear4, int _borderWidth) =>

	if not na(_uiBox)
		setZoneColour (_uiBox, _zoneMethod, _zoneType1, true, _type1ExceptionLevel, _zoneType2, _type2ExceptionLevel, _isTrapZone, _zoneTrapBullColour,  _zoneTrapBearColour,  _zoneColourBull1,  _zoneColourBull2,  _zoneColourBull3,  _zoneColourBull4, _zoneColourBear1, _zoneColourBear2, _zoneColourBear3, _zoneColourBear4)
		box.set_right(_uiBox, _boxEnd)
		box.set_border_style(_uiBox, _border_style)
		box.set_border_width(_uiBox, _borderWidth)


export manageZoneInformation(label _label, int _textElement, string _text) =>

	if not na(_label)
		if _textElement == 1
			label.set_text(_label, _text)
		else if _textElement == 2
			label.set_tooltip(_label, _text)

//

export getZoneName(int _zoneType) =>

	name = switch _zoneType
		1 => "Bull Zone"
		-1 => "Bear Zone"
		=> "Not Classified"
	name
// End

export getZoneSetupType(int _setupType) =>

	name = switch _setupType
		1 => "Trap Move"
		2 => "Trade Away"
		=> "Not Classified"
	name
// End

//***************************
// General Utility Functions*
//***************************

// Function to deal with whether the session is due to be open soon within the next minute
//export isTimeComingUptoSessionOpen(int lastResetTime, string london_ssth, string london_sstm, string ny_ssth, string ny_sstm) =>

// Reimported functions from watchlist utility
export getCurrentDayOfWeek() =>

    fullDate =  str.format("{0,date, full}",time)

    pos = str.pos(fullDate, ",")
    retDay = str.substring(fullDate, 0, pos)

    retDay

export isInUSstockOpenMarket() => 
 
    // Time check are in UCT - so not sure what happens when summer time
    bool ret = na
    currentTimeHour =  str.tonumber(str.format("{0,date, HH}",time))
    currentTimeMin =  str.tonumber(str.format("{0,date, mm}",time))

    // Check the hour time window
    if currentTimeHour >= 13 and currentTimeHour <= 19 
        
        if currentTimeHour == 13 and currentTimeMin <= 29 
            ret := false
        else
            ret := true
    else
        ret := false
    
    // Just check we are not on a weekend
    if ret
        checkDay = getCurrentDayOfWeek()
        if checkDay == "Saturday" or checkDay == "Sunday"
            ret := false        
    ret


export isInUSstockPostMarket() => 

    // Time check are in UCT - so not sure what happens when summer time
    bool ret = na
    currentTimeHour =  str.tonumber(str.format("{0,date, HH}",time))
    currentTimeMin =  str.tonumber(str.format("{0,date, mm}",time))

    // Check the hour time window
    if (currentTimeHour >= 20) or (currentTimeHour < 8) 
        ret := true
    else
        ret := false
    
    // Just check we are not on a weekend
    if ret
        checkDay = getCurrentDayOfWeek()
        if checkDay == "Saturday" or checkDay == "Sunday"
            ret := false        
    ret

export isInUSstockPreMarket() => 

    // Time check are in UCT - so not sure what happens when summer time
    bool ret = na
    currentTimeHour =  str.tonumber(str.format("{0,date, HH}",time))
    currentTimeMin =  str.tonumber(str.format("{0,date, mm}",time))

    // Check the hour time window
    if currentTimeHour >= 8 and currentTimeHour <= 13 
        
        if currentTimeHour == 13 and currentTimeMin >= 30 
            ret := false
        else
            ret := true
    else
        ret := false
    
    // Just check we are not on a weekend
    if ret
        checkDay = getCurrentDayOfWeek()
        if checkDay == "Saturday" or checkDay == "Sunday"
            ret := false        
    ret
// End Utility Functions



export getStringTimeMinus1Minute(string london_ssth, string london_sstm) =>


    //
    // Get the session start times as integers
    london_start_session_hour_int = london_ssth == "00" ? 0 : london_ssth == "01" ? 1 : london_ssth == "02" ? 2 : london_ssth == "03" ? 3 : london_ssth == "04" ? 4 : london_ssth == "05" ? 5 : london_ssth == "06" ? 6 : london_ssth == "07" ? 7 : london_ssth == "08" ? 8 : london_ssth == "09" ? 9 : london_ssth == "10" ? 10 : london_ssth == "11" ? 11 : london_ssth == "12" ? 12 : london_ssth == "13" ? 13 : london_ssth == "14" ? 14 : london_ssth == "15" ? 15 : london_ssth == "16" ? 16 : london_ssth == "17" ? 17 : london_ssth == "18" ? 18 : london_ssth == "19" ? 19 : london_ssth == "20" ? 20 : london_ssth == "21" ? 21 : london_ssth == "22" ? 22 : london_ssth == "23" ? 23 : 0
    london_start_session_minute_int = london_sstm == "00" ? 0 : london_sstm == "15" ? 15 : london_sstm == "30" ? 30 : london_sstm == "45" ? 45 : 0
    
    string checkFirstSessionTime = ""
    

    
    // Make sure the last reset time was greater than 5 mins away
    // London Time - 1 min before open
    if london_start_session_minute_int == 0
        if london_start_session_hour_int == 0
            checkFirstSessionTime := "2359"
        else
            if london_start_session_hour_int <= 10
                checkFirstSessionTime := "0" + str.tostring(london_start_session_hour_int - 1) + "59"
            else
                checkFirstSessionTime := str.tostring(london_start_session_hour_int - 1) + "59"
    else
        if london_start_session_hour_int == 0
            checkFirstSessionTime := "23" + str.tostring(london_start_session_minute_int - 1)
        else
            if london_start_session_hour_int <= 9
                checkFirstSessionTime := "0" + str.tostring(london_start_session_hour_int) + "" + str.tostring(london_start_session_minute_int - 1)
            else
                checkFirstSessionTime := str.tostring(london_start_session_hour_int) + "" + str.tostring(london_start_session_minute_int - 1)
            



    checkFirstSessionTime
    
// End Function


// Functions used in combination to a ladder arrays, where by a price is used to dermine the size of the range steps
// eg. price 5.65 would have a step range of 0.10, where as 15k price a 5 range may be better

// Function to determine what size should be used for a ladder array that will enable a value to be held at each index
// so if a symbol was 10 USD, then to easily store information at each price point, there would need to be 10 x 100 indexes = 1000
// which in this case may be to many to store when considering that the price could increase by 1000 percent in one session
// also consider assets like the dax or dow which are trading at 30k odd. 
// so we need a function that is called on startup that will determine the best way to size such and array and the start and end points. 
// as example for the dax we may want to start the index at 14k and have the upper range at 16k, so we can caputre a range of 2000.
// so we would may not want to track values at each tick by rather for a range ie. every 10 euros on the dax.

export getLadderStepIncrement(float _price) =>
    
    float ladderStep = 5.0

    if (_price < 1)
        ladderStep := 0.05    
    else if (_price < 10)
        ladderStep := 0.10    
    else if (_price < 100)
        ladderStep := 0.20    
    else if (_price < 1000)
        ladderStep := 0.30
    else if (_price < 5000)
        ladderStep := 0.5
    else if (_price < 10000)
        ladderStep := 1.0
    else if (_price < 20000)
        ladderStep := 2.0
    else if (_price < 40000)
        ladderStep := 10.0
    else 
        ladderStep := 20.0
    
    ladderStep
// End 

// Get the index for the range of the current price 
export getLadderIndexForPrice(float _price, float _ladderRange) =>

    // so example price is 10.47 - how do we get the range it is within if the priceLadderPriceRange = 0.10
    float startPriceRange = (math.round(math.floor((_price * 100) / (_ladderRange * 100))) * (_ladderRange * 100) / 100)
    
    int ladderIndex = int(math.round(startPriceRange / _ladderRange)) - 1 // 10 here needs to be an calc variable / the minus 1 is due to indexes starting at 0 and not 1
    ladderIndex

// End 

// Get the lower price for the range of the current price 
export getLadderStartPriceRange(float _price, float _ladderRange) =>

    // so example price is 10.47 - how do we get the range it is within if the priceLadderPriceRange = 0.10
    float startPriceRange = ((math.floor((_price * 100) / (_ladderRange * 100))) * (_ladderRange * 100) / 100)
    
    startPriceRange

// End 


// End Ladder Functions


// Volumne functions section. These probably could do with another library at some point



// Format the display of volume figures
export get_volume_string(float _volume) =>
    string _volume_string = na
    if _volume >= 1000000000
        _volume_digits = math.round(_volume / 1000000000 * 100) / 100
        _volume_string := str.tostring(_volume_digits) + 'B'
        _volume_string
    else if _volume >= 1000000
        _volume_digits = math.round(_volume / 1000000 * 100) / 100
        _volume_string := str.tostring(_volume_digits) + 'M'
        _volume_string
    else if _volume >= 1000
        _volume_digits = math.round(_volume / 1000 * 100) / 100
        _volume_string := str.tostring(_volume_digits) + 'K'
        _volume_string
    else
        _volume_string := str.tostring(math.round(_volume * 100) / 100)
        _volume_string
    _volume_string
// End 


//

export floorDown(float number, int decimals) =>
    factor = math.pow(10, decimals)
    float floorValue = math.floor(number * factor) / factor
    floorValue

// Counts the number of digits before a decimal point
export countDigitsBeforeDecimal(float n) =>
    int c=1
    c:=n==0?1:1+math.floor(math.log10(math.abs(n)))
    c
//

// Counts the number of digits after a decimal point
export countDigitsAfterDecimal(float n) =>
    int c=0
    d=0.0
    d:=math.abs(n)
    d:=d-math.floor(d)
    for i=0 to 42
        if ( d==0 )
            break
        d:=d*10
        d:=d-math.floor(math.round(d))
        c:=c+1
    c
//

// Get the lower price for the range of the current price 
export getChartTimePeriodAsSeconds(string _chartPeriod) =>

    int chartPeriodSecounds = 0
    
    if (_chartPeriod == 'S')
        chartPeriodSecounds := 1

    else if (_chartPeriod == '5S')
        chartPeriodSecounds := 5

    else if (_chartPeriod == '15S')
        chartPeriodSecounds := 15

    else if (_chartPeriod == '30S')
        chartPeriodSecounds := 30

    else if (_chartPeriod == '1')
        chartPeriodSecounds := 60

    else if (_chartPeriod == '3')
        chartPeriodSecounds := 60 * 3

    else if (_chartPeriod == '5')
        chartPeriodSecounds := 60 * 5

    else if (_chartPeriod == '15')
        chartPeriodSecounds := 60 * 15

    else if (_chartPeriod == '30')
        chartPeriodSecounds := 60 * 30

    else if (_chartPeriod == '45')
        chartPeriodSecounds := 60 * 45

    else if (_chartPeriod == '60')
        chartPeriodSecounds := 60 * 60

    else if (_chartPeriod == '120')
        chartPeriodSecounds := 60 * 120

    else if (_chartPeriod == '180')
        chartPeriodSecounds := 60 * 180

    else if (_chartPeriod == '240')
        chartPeriodSecounds := 60 * 240

    else if (_chartPeriod == 'D')
        chartPeriodSecounds := 60 * 60 * 24

    else if (_chartPeriod == '5D')
        chartPeriodSecounds := 60 * 60 * 24 * 5

    else if (_chartPeriod == 'W')
        chartPeriodSecounds := 60 * 60 * 24 * 7

    chartPeriodSecounds

// End 

export debug(string _txt) => var _lbl = label(na), label.delete(_lbl), _lbl := label.new(time + (time-time[1])*3, high, _txt, xloc.bar_time, yloc.price, size = size.large)

