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

//@version=5

// @description Collection of functions created for simplification/easy referencing. Includes variations of moving averages, length value oscillators, and a few other simple functions based upon HH/LL values.
library("TurntLibrary")

// @function Apply a moving average to a float value
// @param source Value to be used 
// @param length Number of bars to include in calculation
// @param type Moving average type to use ("SMA","EMA","RMA","WMA","VWAP","SWMA","LRC")
// @returns Smoothed value of initial float value
export ma(float source,simple int length,string type) =>
	switch type
        "SMA" => ta.sma(source, length)
        "EMA" => ta.ema(source, length)
        "RMA" => ta.rma(source, length)
        "WMA" => ta.wma(source, length)
        "VWAP"=> ta.vwap(source)
        "SWMA"=> ta.swma(source)
        "LRC" => ta.linreg(source,length,0)

// @function Exaggerates curves of a float value designed for use as an exit signal.
// @param src Initial value to curve
// @param len Number of bars to include in calculation
// @param lb1 (Default = 1) First lookback length 
// @param lb2 (Default = 2) Second lookback length 
// @returns Curvey Average
export curve(float src,int len,int lb1 = 1,int lb2 = 2)=>
    x=ta.linreg((ta.highest(src[len],len)-ta.lowest(src[len],len) > ta.highest(src,len)-ta.lowest(src,len))?
      ta.sma(math.avg(open,open[lb1],open[lb2])<math.avg(close,close[lb1],close[lb2])?ta.highest(src,math.round(math.avg(lb1,lb2))):ta.lowest(src,math.round(math.avg(lb1,lb2))),len)
      :ta.linreg(src,len ,0),len,0)
    avg=math.avg(x,ta.ema(src,math.round(len/2)))
    avg

// @function Average of a moving average and the previous value of the moving average   
// @param src Initial float value to use
// @param len Number of bars to include in calculation
// @param space Lookback integer for second half of average
// @param str Moving average type to use ("SMA","EMA","RMA","WMA","VWAP","SWMA","LRC")
// @returns Fragmented Average
export fragma(float src,simple int len,int space,string str)=>
    ma1=ma(src,len,str) 
    ma2=ma(src[space],len,str) 
    avg=ma(math.avg(ma1,ma2),len,str)
    avg

// @function Difference of 2 float values, subtracting the lowest from the highest
// @param x Value 1
// @param y Value 2
// @returns The +Difference between 2 float values
export maxmin(float x,float y)=>
    var float dif = 0.0
    dif := math.max(x,y)-math.min(x,y)
    dif
// @function Variable Length using a oscillator value and a corresponding slope shape ("Incline",Decline","Peak","Trough")
// @param val Oscillator Value to use 
// @param type Slope of length curve ("Incline",Decline","Peak","Trough")
// @returns Variable Length Integer
export oscLen(float val, string type)=>
	v=ta.min(val) >= 0 ? 100*val/ta.max(val):100*((0-ta.min(val))+val)/(ta.max(0-ta.min(val)+val))
	switch type
        "Incline" => v>98?98:v>96?96:v>94?94:v>92?92:v>90?90:
     	  v>88?88:v>86?86:v>84?84:v>82?82:v>80?80:
     	  v>78?78:v>76?76:v> 74?74:v>72?72:v>70?70:
     	  v>68?68:v>66?66:v>64?64:v>62?62:v>60?60:
     	  v>58?58:v>56?56:v>54?74:v>52?72:v>50?50:
     	  v>48?48:v>46?46:v>44?44:v>42?42:v>40?40:
     	  v>38?38:v>36?36:v>34?34:v>32?32:v>30?30:
     	  v>28?28:v>26?26:v>24?24:v>22?22:v>20?20:
     	  v>18?18:v>16?16:v>14?14:v>12?12:v>10?10:
     	  v>8?8:v>6?6:4
    	"Decline" => v>98?2:v>96?4:v>94?6:v>92?8:v>90?10:
      	  v>88?12:v>86?14:v>84?16:v>82?18:v>80?20:
      	  v>78?22:v>76?24:v>74?26:v>72?28:v>70?30:
      	  v>68?32:v>66?34:v>64?36:v>62?38:v>60?40:
      	  v>58?42:v>56?44:v>54?46:v>52?48:v>50?50:
      	  v>48?48:v>46?46:v>44?44:v>42?42:v>40?40:
      	  v>38?38:v>36?36:v>34?34:v>32?32:v>30?30:
      	  v>28?28:v>26?26:v>24?24:v>22?22:v>20?20:
      	  v>18?18:v>16?16:v>14?14:v>12?12:v>10?10:
      	  v>8?8:v>6?4:2
        "Peak" => v>98?32:v>96?36:v>94?40:v>92?44:v>90?48:
      	  v>88?52:v>86?56:v>84?60:v>82?64:v>80?68:
      	  v>78?72:v>76?76:v>74?80:v>72?84:v>70?88:
      	  v>68?92:v>66?96:v>64?100:v>62?104:v>60?108:
      	  v>58?112:v>56?116:v>54?120:v>52?124:v>50?128:
      	  v>48?124:v>46?120:v>44?116:v>42?112:v>40?108:
      	  v>38?104:v>36?100:v>34?96:v>32?92:v>30?88:
      	  v>28?84:v>26?80:v>24?76:v>22?72:v>20?68:
      	  v>18?64:v>16?60:v>14?56:v>12?52:v>10?48:
      	  v>8?44:v>6?40:v>4?36:32

		"Trough"=> v>98?98:v>96?96:v>94?94:v>92?92:v>90?90:
      	  v>88?88:v>86?86:v>84?84:v>82?82:v>80?80:
      	  v>78?78:v>76?76:v> 74?74:v>72?72:v>70?70:
      	  v>68?68:v>66?66:v>64?64:v>62?62:v>60?60:
      	  v>58?58:v>56?56:v>54?74:v>52?72:v>50?50:
      	  v>48?52:v>46?54:v>44?56:v>42?58:v>40?60:
      	  v>38?62:v>36?64:v>34?66:v>32?68:v>30?70:
      	  v>28?72:v>26?74:v>24?76:v>22?78:v>20?80:
      	  v>18?82:v>16?84:v>14?86:v>12?88:v>10?90:
      	  v>8?92:v>6?94:v>4?96:98

// @function Average of HH,LL with variable lengths based on the slope shape ("Incline","Decline","Trough") value relative to highest and lowest 
// @param val Source Value to use 
// @param Highest Length value to use
// @param Lowest Length value to use 
// @param Shape of length curve ("Incline","Decline","Trough")
// @param include Add "val" to the averaging process, instead of more weight to highest or lowest value  
// @returns Variable Length Average of Highest Lowest "val" 
export hlAverage(float val, int smooth, int max,int min, string type,bool include = false)=>
    minmax= (max-min)/20
    lengthH= min
    lengthL= min
	x1  =type == "Incline"? 1  :type == "Decline"?20:type == "Trough"?10*2:na//type == "Peak"?1 *1.5
	x2  =type == "Incline"? 2  :type == "Decline"?19:type == "Trough"?9 *2:na//type == "Peak"?2 *1.5
	x3  =type == "Incline"? 3  :type == "Decline"?18:type == "Trough"?8 *2:na//type == "Peak"?3 *1.5
	x4  =type == "Incline"? 4  :type == "Decline"?17:type == "Trough"?7 *2:na//type == "Peak"?4 *1.5
	x5  =type == "Incline"? 5  :type == "Decline"?16:type == "Trough"?6 *2:na//type == "Peak"?5 *1.5
	x6  =type == "Incline"? 6  :type == "Decline"?15:type == "Trough"?5 *2:na//type == "Peak"?6 *1.5
	x7  =type == "Incline"? 7  :type == "Decline"?14:type == "Trough"?4 *2:na//type == "Peak"?7 *1.5
	x8  =type == "Incline"? 8  :type == "Decline"?13:type == "Trough"?3 *2:na//type == "Peak"?8 *1.5
	x9  =type == "Incline"? 9  :type == "Decline"?12:type == "Trough"?2 *2:na//type == "Peak"?9 *1.5
	x10 =type == "Incline"? 10 :type == "Decline"?11:type == "Trough"?1 *2:na//type == "Peak"?10*1.5
	x11 =type == "Incline"? 11 :type == "Decline"?10:type == "Trough"?1 *2:na//type == "Peak"?10*1.5
	x12 =type == "Incline"? 12 :type == "Decline"? 9:type == "Trough"?2 *2:na//type == "Peak"?9 *1.5
	x13 =type == "Incline"? 13 :type == "Decline"? 8:type == "Trough"?3 *2:na//type == "Peak"?8 *1.5
	x14 =type == "Incline"? 14 :type == "Decline"? 7:type == "Trough"?4 *2:na//type == "Peak"?7 *1.5
	x15 =type == "Incline"? 15 :type == "Decline"? 6:type == "Trough"?5 *2:na//type == "Peak"?6 *1.5
	x16 =type == "Incline"? 16 :type == "Decline"? 5:type == "Trough"?6 *2:na//type == "Peak"?5 *1.5
	x17 =type == "Incline"? 17 :type == "Decline"? 4:type == "Trough"?7 *2:na//type == "Peak"?4 *1.5
	x18 =type == "Incline"? 18 :type == "Decline"? 3:type == "Trough"?8 *2:na//type == "Peak"?3 *1.5
	x19 =type == "Incline"? 19 :type == "Decline"? 2:type == "Trough"?9 *2:na//type == "Peak"?2 *1.5
	x20 =type == "Incline"? 20 :type == "Decline"? 1:type == "Trough"?10*2:na//type == "Peak"?1 *1.5
	dif_h=ta.highest(val,max) - val
	dif_l=val - ta.lowest (val,max)
	dif_hl=ta.highest(val,max)-ta.lowest(val,max)
	ratio_h=(100*dif_h)/dif_hl
	ratio_l=(100*dif_l)/dif_hl
    
    lengthH:=math.round(math.max(ratio_h<=5?max-(x1*minmax)
      :ratio_h<=10?min+ (x2 *minmax)
      :ratio_h<=15?min+ (x3 *minmax)
      :ratio_h<=20?min+ (x4 *minmax)
      :ratio_h<=25?min+ (x5 *minmax)
      :ratio_h<=30?min+ (x6 *minmax)
      :ratio_h<=35?min+ (x7 *minmax)
      :ratio_h<=40?min+ (x8 *minmax)
      :ratio_h<=45?min+ (x9 *minmax)
      :ratio_h<=50?min+ (x10*minmax)
      :ratio_h<=55?min+ (x11*minmax)
      :ratio_h<=60?min+ (x12*minmax)
      :ratio_h<=65?min+ (x13*minmax)
      :ratio_h<=70?min+ (x14*minmax)
      :ratio_h<=75?min+ (x15*minmax)
      :ratio_h<=80?min+ (x16*minmax)
      :ratio_h<=85?min+ (x17*minmax)
      :ratio_h<=90?min+ (x18*minmax)
      :ratio_h<=95?min+ (x19*minmax)  
      :min+ (x20*minmax),min))
    
    
    lengthL:=math.round(math.max(ratio_l<=5?max-(x1*minmax)
      :ratio_l<=10?max-(x2 *minmax)
      :ratio_l<=15?max-(x3 *minmax)
      :ratio_l<=20?max-(x4 *minmax)
      :ratio_l<=25?max-(x5 *minmax)
      :ratio_l<=30?max-(x6 *minmax)
      :ratio_l<=35?max-(x7 *minmax)
      :ratio_l<=40?max-(x8 *minmax)
      :ratio_l<=45?max-(x9 *minmax)
      :ratio_l<=50?max-(x10*minmax)
      :ratio_l<=55?max-(x11*minmax)
      :ratio_l<=60?max-(x12*minmax)
      :ratio_l<=65?max-(x13*minmax)
      :ratio_l<=70?max-(x14*minmax)
      :ratio_l<=75?max-(x15*minmax)
      :ratio_l<=80?max-(x16*minmax)
      :ratio_l<=85?max-(x17*minmax)
      :ratio_l<=90?max-(x18*minmax)
      :ratio_l<=95?max-(x19*minmax)
      :max-(x20*minmax),min))
    avglen=nz(math.round(ta.median(math.avg(lengthH,lengthL),max)),8)
    average=ta.ema(ta.linreg(math.avg(ta.highest(close,lengthH),ta.lowest(close,lengthL),(include?close:close>ta.vwap(close)?ta.highest(high,min):ta.lowest(low,min))),smooth,0),smooth )
    average

// @function Geometric average of midpoint and value with an additional modifier
// @param src = Value to use in calculation
// @param length # of bars to include in calculation
// @param offset LRC offset
// @param atr ATR length to use
// @returns a Geometric Average of a modified Geometric Average 
export geoma(float src,simple int length,simple int offset, simple int atr = 4)=> 
    lrc=ta.linreg(src, length, offset)
    avg=math.avg(ta.highest(high,length),ta.lowest(low,length))
    sqrt=math.sqrt(lrc*avg)
    hl=ta.ema(src,8)>sqrt?ta.linreg(high,length,0)+ta.atr(atr):ta.linreg(low,length,0)-ta.atr(atr)
    sqrt:=ta.ema(math.sqrt(hl*sqrt),length/8)
    sqrt


// @function Midpoint between Highest and Lowest using variable lookback
// @param src = Value to use in calculation
// @param length # of bars to include in calculation
// @param offset LRC offset
// @param up Slope of length curve to use ("Incline","Decline","Peak","Trough")
// @param dn Slope of length curve to use ("Incline","Decline","Peak","Trough")
// @returns Dynamic Relative Strength Average 
export rsma(float src,simple int length,simple int offset,string up="Peak", string dn = "Trough")=> 
    lrc=ta.linreg(ta.vwap(src), length, offset)
    rsi=ta.rsi(hl2,length)

    rup=oscLen(rsi,up)
    rdn=oscLen(rsi,dn)
    avg=math.avg(ta.highest(high,math.round(rup)),ta.lowest(low,math.round(rdn)))

    sqrt=math.sqrt(lrc*avg)
    hl=ta.ema(avg,math.round(length/2))<lrc?ta.linreg(high+ta.atr(length),rup,0):ta.linreg(low-ta.atr(length),rdn,0)
    sqrt:=ta.ema(math.sqrt(hl*sqrt),length/2)
    sqrt


// @function Midpoint using dynamic lengths with Incline/Decline Slopes 
// @param src = Value to use in calculation
// @param length # of bars to include in calculation
// @param offset LRC offset
// @returns Incline Decline MA
export yma(float src,simple int length,simple int offset)=>
    hI=oscLen(ta.rsi(ta.barssince(ta.highest(src[1],length)==src[1]  and ta.highest(src,length)!=src)*-1,length),'Incline')
    hD=oscLen(ta.rsi(ta.barssince(ta.highest(src[1],length)==src[1]  and ta.highest(src,length)!=src)*-1,length),'Decline')
    lI=oscLen(ta.rsi(ta.barssince(ta.lowest(src[1],length)==src[1]  and ta.lowest(src,length)!=src)     ,length),'Incline')
    lD=oscLen(ta.rsi(ta.barssince(ta.lowest(src[1],length)==src[1]  and ta.lowest(src,length)!=src)     ,length),'Decline')
    avg=ta.rsi(ta.ema(math.avg(hI,lI,hD,lD),length*2),length)

    hi=ta.highest(high,nz(math.max(math.round(length/2),math.round(avg)),1))
    lo=ta.lowest(low,nz(math.max(math.round(length/2),math.round(avg)),1))
    avghl=ta.linreg(math.avg(hi,lo),length*2,offset)
    avghl


// @function Midpoint using dynamic lengths with Peak Trough Slopes 
// @param src = Value to use in calculation
// @param length # of bars to include in calculation
// @param offset LRC offset
// @returns Peak Trough MA
export xma(float src,simple int length,simple int offset)=>
    hP=oscLen(ta.rsi(ta.barssince(ta.highest(src[1],length)==src[1]  and ta.highest(src,length)!=src)*-1,length),'Peak')
    hT=oscLen(ta.rsi(ta.barssince(ta.highest(src[1],length)==src[1]  and ta.highest(src,length)!=src)*-1,length),'Trough')
    lP=oscLen(ta.rsi(ta.barssince(ta.lowest(src[1],length)==src[1]  and ta.lowest(src,length)!=src)     ,length),'Peak')
    lT=oscLen(ta.rsi(ta.barssince(ta.lowest(src[1],length)==src[1]  and ta.lowest(src,length)!=src)     ,length),'Trough')
    avg=ta.rsi(ta.ema(math.avg(hP,lP,hT,lT),length*2),length)

    hi=ta.highest(high,nz(math.max(math.round(length/2),math.round(avg)),1))
    lo=ta.lowest(low,nz(math.max(math.round(length/2),math.round(avg)),1))
    avghl=ta.linreg(math.avg(hi,lo),length*2,offset)
    avghl


// @function Gravitational Moving Average, Adds weight to lowest highest or center point based upon the current value in relation to the highest/lowest values.
// @param src = Value to use in calculation
// @param length # of bars to include in calculation
// @param offset LRC offset
// @returns Gravitational MA
export gma(float src,simple int length,simple int mult = 4,  string type = "Trough")=>
    h=ta.highest(src,length*mult)
    hdif=ta.highest(src,length*mult)-src
    l=ta.lowest(src,length*mult)
    ldif=src-ta.lowest(src,length*mult)
    dif=h-l
    lgrav=ldif<0.1*dif?math.avg(l,src):ldif<0.2*dif?math.avg(l,l,src):ldif<0.3*dif?math.avg(l,l,l,src):math.avg(l,src+0.5*hdif,src-0.5*ldif)
    hgrav=hdif<0.1*dif?math.avg(h,src):hdif<0.2*dif?math.avg(h,h,src):hdif<0.3*dif?math.avg(h,h,h,src):math.avg(h,src+0.5*hdif,src-0.5*ldif)
    grav=ta.ema(ta.linreg((ldif<0.4*dif?lgrav:ldif>0.4*dif and hdif > 0.4*dif? math.avg(hgrav,lgrav):hgrav),oscLen((ta.rsi(math.min(ldif,hdif)/math.max(ldif,hdif),length)),type),0),length)
    grav


// @function Convert a positive float / price to a percentage of it's highest value on record
// @param val Value To convert to a percentage of it's highest value ever 
// @returns Percentage 
export pct(float val)=>
	percent=100*val/ta.max(val)
	percent



// @function Difference between Highest High and Lowest Low of float value
// @param x Value to use in calculation
// @param len Number of bars to include in calculation
// @returns Difference 
export hlrange(float x, int len)=>
	span=ta.highest(x,len)-ta.lowest(x,len)
	span



// @function The average value of the float's Highest High and Lowest Low in a number of bars
// @param x Value to use in calculation 
// @param l Number of bars to include in calculation
// @param smooth (Default=na) Optional smoothing type to use ("SMA","EMA","RMA","WMA","VWAP","SWMA","LRC")
// @returns Midpoint  
export midpoint(float x,simple int len,string smooth = na)=>
	h=ta.highest(x,len)
	l=ta.lowest(x,len)
	avg=math.avg(h,l)
	switch smooth
        "SMA" => ta.sma(avg,len)
        "EMA" => ta.ema(avg,len)
        "RMA" => ta.rma(avg,len)
        "WMA" => ta.wma(avg,len)
        "VWAP"=> ta.vwap(avg)
        "SWMA"=> ta.swma(avg)
        "LRC" => ta.linreg(avg,len,0)
		=>avg



// @function RSI based momentum oscillator
// @param src Source value to use
// @param len Length value to use throughout calculation
// @param lookback (Default = 1) Lookback value 
// @param pow (Default = 2) Power to use on counters 
// @returns A curvey rsi based momentum oscillator 
export wave(float src,simple int len,int lookback = 1,float pow = 2)=>
    rsi=ta.rsi(src,len)
    h=ta.rsi(math.pow(ta.barssince(ta.highest(src[lookback],len*4)==src[lookback] and rsi>70 and ta.highest(src,len*4)!=src),pow)*-1,len)
    l=ta.rsi(math.pow(ta.barssince(ta.lowest(src[lookback],len*4)==src[lookback] and rsi<30 and ta.lowest(src,len*4)!=src),pow),len)
    avg=ta.ema(math.avg(h,l),len*2)
    avg




//////////////////PLOTS  
//plot(hlAverage(close,32,128,32,"Incline"),color=#ff0000)
//plot(hlAverage(close,8,64,12,"Trough"),color=#ee6600)
plot(curve(close,16))
//plot(hlAverage(close,32,128,32,"Decline"),color=#acfb00)


line1=geoma(close,24,0)
line2=rsma(close,24,0)
line3=yma(close,24,0)
line4=xma(close,24,0)
line5=gma(close,16)

avg=ta.linreg(math.avg(line1,line2,line3,line4,line5),16,0)


//plot(line1,color=#00ee33)
//plot(line2,color=#ee6600)
//plot(line3,color=#ff0000)
//plot(line4,color=#fff000)
//plot(line5,color=#a619c9)

plot(avg,color=#ff0000)