[VWMA] Net Volume Library
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TheKaoticS

//@version=5

// @description TODO: add library description here
library("VWMANetVolume")

// ————— Types
//@type				Contains 7 bands of net volume data points
//@field h2			Highest positive band
//@field h1			Higher positive band
//@field h			High positive band
//@field n			Normal neutral band
//@field l			Low negative band
//@field l1			Lower negative band
//@field l2			Lowest negative band
export type nvPoint
	float h2		= na
	float h1		= na
	float h			= na
	float n			= na
	float l			= na
	float l1		= na
	float l2		= na

// @function					Gets the VWMA Net Volume or just pure Net Volume value
// @param src					(float) The source price value
// @param length				(int) The lookback length
// @param useVwma				(bool) To use VWMA in the calculation or not
// @returns						The VMWA smoothed or pure net volume value
method getNv(
  float 		    src, 
  int 			    length, 
  bool 			    useVwma
  ) =>
	srcChange           = ta.change(src)
	srcPositive         = srcChange > 0
	srcNegative         = srcChange < 0
	netVolume           = srcPositive ? volume : (srcNegative ? -volume : 0)
	vwmaNetVolume       = ta.vwma(netVolume, length)
	
	useVwma ? vwmaNetVolume : netVolume

// @function					Gets the ALMA point part value for a band in the nvPoint object
// @param nv					(float) The current net volume value
// @param length				(int) The current net volume lookback length
// @param offset				(float) The ALMA offset value
// @param sigma					(int) The ALMA sigma value
// @param mult					(float) The current multiplier value
// @param direction				(int) The multiplier direction of the band (bearish, bullish, or neutral)
// @returns						The ALMA smoothed value for the net volume given a multiplier and direction
method getAlmaPointPart(
  float 		    nv, 
  int 			    length, 
  simple float 	offset, 
  simple int 	  sigma, 
  simple float 	mult, 
  int 			    direction
  ) =>
	int almaLength = na

	switch direction
		1 	=> almaLength := math.floor(length * mult)
		0 	=> almaLength := length
		-1 	=> almaLength := math.ceil(length / mult)

	ta.alma(nv, almaLength, offset, sigma)

// @function					Get the current net volume band values at current point
// @param nv					(float) The current net volume value
// @param length				(int) The current net volume lookback length
// @param offset				(float) The ALMA offset value
// @param sigma					(int) The ALMA sigma value
// @param multHigh				(float) The multiplier high band
// @param multMed				(float) The multiplier medium band
// @param multLow				(float) The multiplier low band
// @returns						Returns a nvPoint object that contains the values of each of the seven net volume bands
method getNvPoint(
  float 		    nv, 
  int 			    length, 
  simple float	offset, 
  simple int 	  sigma, 
  simple float 	multHigh, 
  simple float 	multMed, 
  simple float 	multLow
  ) =>
	nvPoint nvp 	= nvPoint.new()

	nvp.l2 			        := getAlmaPointPart(nv, length, offset, sigma, multHigh, 	-1)
	nvp.l1			        := getAlmaPointPart(nv, length, offset, sigma, multMed, 	-1)
	nvp.l			          := getAlmaPointPart(nv, length, offset, sigma, multLow, 	-1)
	nvp.n			          := getAlmaPointPart(nv, length, offset, sigma, 1, 			  0 )
	nvp.h			          := getAlmaPointPart(nv, length, offset, sigma, multLow, 	1 )
	nvp.h1			        := getAlmaPointPart(nv, length, offset, sigma, multMed, 	1 )
	nvp.h2			        := getAlmaPointPart(nv, length, offset, sigma, multHigh, 	1 )

	nvp

// ————— Methods
// @function                    Gets the band color based on a positive or negative alma value
// @param value                 (float) The value to pass in to check against
// @param transp                (int) The transparency value. Ex: 0 = solid, 100 = fully opaque
// @param negative              (color) The color to show when result is below but not equal to 0
// @param positive              (color) The color to show when result is above but not equal to 0
// @returns                     (color) The color that matches the result of being above or below 0
export method getBandColor(
  float 		    value, 
  int 			    transp 		    = 0, 
  color 		    negative 	    = color.red, 
  color 		    positive 	    = color.yellow
  ) =>
  color.new(value < 0 ? negative : positive, transp)

// @function
// @param src					(float) The source price value
// @param length				(int) The lookback length
// @param useVwma				(bool) To use VWMA in the calculation or not
// @param offset				(float) The ALMA offset value
// @param sigma					(int) The ALMA sigma value
// @param multHigh				(float) The multiplier high band
// @param multMed				(float) The multiplier medium band
// @param multLow				(float) The multiplier low band
// @returns						Returns the calculated net volume for each band in an nvPoint object
export method nv(
  float 		    src 	    = close, 
  int 			    length 		= 60, 
  bool 			    useVwma 	= false, 
  simple float 	offset 		= 0.85, 
  simple int 	  sigma 		= 6, 
  simple float 	multHigh 	= 2.00, 
  simple float 	multMed 	= 1.50, 
  simple float 	multLow 	= 1.25
  ) =>
  getNvPoint(getNv(src, length, useVwma), length, offset, sigma, multHigh, multMed, multLow)