Alexey Kim před 2 týdny
rodič
revize
be24092263
1 změnil soubory, kde provedl 5989 přidání a 0 odebrání
  1. 5989 0
      talib.go

+ 5989 - 0
talib.go

@@ -0,0 +1,5989 @@
+package sentio
+
+/*
+Copyright 2016 Mark Chenoweth
+Licensed under terms of MIT license (see LICENSE)
+*/
+
+import (
+	"errors"
+	"math"
+)
+
+// MaType - Moving average type
+type MaType int
+
+type moneyFlow struct {
+	positive float64
+	negative float64
+}
+
+// Kinds of moving averages
+const (
+	SMA MaType = iota
+	EMA
+	WMA
+	DEMA
+	TEMA
+	TRIMA
+	KAMA
+	MAMA
+	T3MA
+)
+
+/* Overlap Studies */
+
+// BBands - Bollinger Bands
+// upperband, middleband, lowerband = BBands(close, timeperiod=5, nbdevup=2, nbdevdn=2, matype=0)
+func BBands(inReal []float64, inTimePeriod int, inNbDevUp float64, inNbDevDn float64, inMAType MaType) ([]float64, []float64, []float64) {
+
+	outRealUpperBand := make([]float64, len(inReal))
+	outRealMiddleBand := Ma(inReal, inTimePeriod, inMAType)
+	outRealLowerBand := make([]float64, len(inReal))
+
+	tempBuffer2 := StdDev(inReal, inTimePeriod, 1.0)
+
+	if inNbDevUp == inNbDevDn {
+
+		if inNbDevUp == 1.0 {
+			for i := 0; i < len(inReal); i++ {
+				tempReal := tempBuffer2[i]
+				tempReal2 := outRealMiddleBand[i]
+				outRealUpperBand[i] = tempReal2 + tempReal
+				outRealLowerBand[i] = tempReal2 - tempReal
+			}
+		} else {
+			for i := 0; i < len(inReal); i++ {
+				tempReal := tempBuffer2[i] * inNbDevUp
+				tempReal2 := outRealMiddleBand[i]
+				outRealUpperBand[i] = tempReal2 + tempReal
+				outRealLowerBand[i] = tempReal2 - tempReal
+			}
+		}
+	} else if inNbDevUp == 1.0 {
+		for i := 0; i < len(inReal); i++ {
+			tempReal := tempBuffer2[i]
+			tempReal2 := outRealMiddleBand[i]
+			outRealUpperBand[i] = tempReal2 + tempReal
+			outRealLowerBand[i] = tempReal2 - (tempReal * inNbDevDn)
+		}
+	} else if inNbDevDn == 1.0 {
+		for i := 0; i < len(inReal); i++ {
+			tempReal := tempBuffer2[i]
+			tempReal2 := outRealMiddleBand[i]
+			outRealLowerBand[i] = tempReal2 - tempReal
+			outRealUpperBand[i] = tempReal2 + (tempReal * inNbDevUp)
+		}
+	} else {
+		for i := 0; i < len(inReal); i++ {
+			tempReal := tempBuffer2[i]
+			tempReal2 := outRealMiddleBand[i]
+			outRealUpperBand[i] = tempReal2 + (tempReal * inNbDevUp)
+			outRealLowerBand[i] = tempReal2 - (tempReal * inNbDevDn)
+		}
+	}
+	return outRealUpperBand, outRealMiddleBand, outRealLowerBand
+}
+
+// Dema - Double Exponential Moving Average
+func Dema(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	firstEMA := Ema(inReal, inTimePeriod)
+	secondEMA := Ema(firstEMA[inTimePeriod-1:], inTimePeriod)
+
+	for outIdx, secondEMAIdx := (inTimePeriod*2)-2, inTimePeriod-1; outIdx < len(inReal); outIdx, secondEMAIdx = outIdx+1, secondEMAIdx+1 {
+		outReal[outIdx] = (2.0 * firstEMA[outIdx]) - secondEMA[secondEMAIdx]
+	}
+
+	return outReal
+}
+
+// Ema - Exponential Moving Average
+func ema(inReal []float64, inTimePeriod int, k1 float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	today := startIdx - lookbackTotal
+	i := inTimePeriod
+	tempReal := 0.0
+	for i > 0 {
+		tempReal += inReal[today]
+		today++
+		i--
+	}
+
+	prevMA := tempReal / float64(inTimePeriod)
+
+	for today <= startIdx {
+		prevMA = ((inReal[today] - prevMA) * k1) + prevMA
+		today++
+	}
+	outReal[startIdx] = prevMA
+	outIdx := startIdx + 1
+	for today < len(inReal) {
+		prevMA = ((inReal[today] - prevMA) * k1) + prevMA
+		outReal[outIdx] = prevMA
+		today++
+		outIdx++
+	}
+
+	return outReal
+}
+
+// Ema - Exponential Moving Average
+func Ema(inReal []float64, inTimePeriod int) []float64 {
+
+	k := 2.0 / float64(inTimePeriod+1)
+	outReal := ema(inReal, inTimePeriod, k)
+	return outReal
+}
+
+// HtTrendline - Hilbert Transform - Instantaneous Trendline (lookback=63)
+func HtTrendline(inReal []float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	smoothPriceIdx := 0
+	maxIdxSmoothPrice := (50 - 1)
+	smoothPrice := make([]float64, maxIdxSmoothPrice+1)
+	iTrend1 := 0.0
+	iTrend2 := 0.0
+	iTrend3 := 0.0
+	tempReal := math.Atan(1)
+	rad2Deg := 45.0 / tempReal
+	lookbackTotal := 63
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal = inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 34
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		//smoothedValue := periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 63
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	smoothPeriod := 0.0
+	q2 := 0.0
+	i2 := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue := periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		smoothPrice[smoothPriceIdx] = smoothedValue
+		if (today % 2) == 0 {
+			hilbertTempReal := a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+			hilbertTempReal := a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		smoothPeriod = (0.33 * period) + (0.67 * smoothPeriod)
+		DCPeriod := smoothPeriod + 0.5
+		DCPeriodInt := math.Floor(DCPeriod)
+		idx := today
+		tempReal = 0.0
+		for i := 0; i < int(DCPeriodInt); i++ {
+			tempReal += inReal[idx]
+			idx--
+		}
+		if DCPeriodInt > 0 {
+			tempReal = tempReal / (DCPeriodInt * 1.0)
+		}
+		tempReal2 = (4.0*tempReal + 3.0*iTrend1 + 2.0*iTrend2 + iTrend3) / 10.0
+		iTrend3 = iTrend2
+		iTrend2 = iTrend1
+		iTrend1 = tempReal
+		if today >= startIdx {
+			outReal[outIdx] = tempReal2
+			outIdx++
+		}
+		smoothPriceIdx++
+		if smoothPriceIdx > maxIdxSmoothPrice {
+			smoothPriceIdx = 0
+		}
+
+		today++
+	}
+	return outReal
+}
+
+// Kama - Kaufman Adaptive Moving Average
+func Kama(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	constMax := 2.0 / (30.0 + 1.0)
+	constDiff := 2.0/(2.0+1.0) - constMax
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	sumROC1 := 0.0
+	today := startIdx - lookbackTotal
+	trailingIdx := today
+	i := inTimePeriod
+	for i > 0 {
+		tempReal := inReal[today]
+		today++
+		tempReal -= inReal[today]
+		sumROC1 += math.Abs(tempReal)
+		i--
+	}
+	prevKAMA := inReal[today-1]
+	tempReal := inReal[today]
+	tempReal2 := inReal[trailingIdx]
+	trailingIdx++
+	periodROC := tempReal - tempReal2
+	trailingValue := tempReal2
+	if (sumROC1 <= periodROC) || (((-(0.00000000000001)) < sumROC1) && (sumROC1 < (0.00000000000001))) {
+		tempReal = 1.0
+	} else {
+		tempReal = math.Abs(periodROC / sumROC1)
+	}
+	tempReal = (tempReal * constDiff) + constMax
+	tempReal *= tempReal
+	prevKAMA = ((inReal[today] - prevKAMA) * tempReal) + prevKAMA
+	today++
+	for today <= startIdx {
+		tempReal = inReal[today]
+		tempReal2 = inReal[trailingIdx]
+		trailingIdx++
+		periodROC = tempReal - tempReal2
+		sumROC1 -= math.Abs(trailingValue - tempReal2)
+		sumROC1 += math.Abs(tempReal - inReal[today-1])
+		trailingValue = tempReal2
+		if (sumROC1 <= periodROC) || (((-(0.00000000000001)) < sumROC1) && (sumROC1 < (0.00000000000001))) {
+			tempReal = 1.0
+		} else {
+			tempReal = math.Abs(periodROC / sumROC1)
+		}
+		tempReal = (tempReal * constDiff) + constMax
+		tempReal *= tempReal
+		prevKAMA = ((inReal[today] - prevKAMA) * tempReal) + prevKAMA
+		today++
+	}
+	outReal[inTimePeriod] = prevKAMA
+	outIdx := inTimePeriod + 1
+	for today < len(inReal) {
+		tempReal = inReal[today]
+		tempReal2 = inReal[trailingIdx]
+		trailingIdx++
+		periodROC = tempReal - tempReal2
+		sumROC1 -= math.Abs(trailingValue - tempReal2)
+		sumROC1 += math.Abs(tempReal - inReal[today-1])
+		trailingValue = tempReal2
+		if (sumROC1 <= periodROC) || (((-(0.00000000000001)) < sumROC1) && (sumROC1 < (0.00000000000001))) {
+			tempReal = 1.0
+		} else {
+			tempReal = math.Abs(periodROC / sumROC1)
+		}
+		tempReal = (tempReal * constDiff) + constMax
+		tempReal *= tempReal
+		prevKAMA = ((inReal[today] - prevKAMA) * tempReal) + prevKAMA
+		today++
+		outReal[outIdx] = prevKAMA
+		outIdx++
+	}
+
+	return outReal
+}
+
+// Ma - Moving average
+func Ma(inReal []float64, inTimePeriod int, inMAType MaType) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod == 1 {
+		copy(outReal, inReal)
+		return outReal
+	}
+
+	switch inMAType {
+	case SMA:
+		outReal = Sma(inReal, inTimePeriod)
+	case EMA:
+		outReal = Ema(inReal, inTimePeriod)
+	case WMA:
+		outReal = Wma(inReal, inTimePeriod)
+	case DEMA:
+		outReal = Dema(inReal, inTimePeriod)
+	case TEMA:
+		outReal = Tema(inReal, inTimePeriod)
+	case TRIMA:
+		outReal = Trima(inReal, inTimePeriod)
+	case KAMA:
+		outReal = Kama(inReal, inTimePeriod)
+	case MAMA:
+		outReal, _ = Mama(inReal, 0.5, 0.05)
+	case T3MA:
+		outReal = T3(inReal, inTimePeriod, 0.7)
+	}
+	return outReal
+}
+
+// Mama - MESA Adaptive Moving Average (lookback=32)
+func Mama(inReal []float64, inFastLimit float64, inSlowLimit float64) ([]float64, []float64) {
+
+	outMAMA := make([]float64, len(inReal))
+	outFAMA := make([]float64, len(inReal))
+
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	rad2Deg := 180.0 / (4.0 * math.Atan(1))
+	lookbackTotal := 32
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal := inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 9
+	smoothedValue := 0.0
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+	hilbertIdx := 0
+	detrenderOdd[0] = 0.0
+	detrenderOdd[1] = 0.0
+	detrenderOdd[2] = 0.0
+	detrenderEven[0] = 0.0
+	detrenderEven[1] = 0.0
+	detrenderEven[2] = 0.0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+
+	q1Odd[0] = 0.0
+	q1Odd[1] = 0.0
+	q1Odd[2] = 0.0
+	q1Even[0] = 0.0
+	q1Even[1] = 0.0
+	q1Even[2] = 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+
+	jIOdd[0] = 0.0
+	jIOdd[1] = 0.0
+	jIOdd[2] = 0.0
+	jIEven[0] = 0.0
+	jIEven[1] = 0.0
+	jIEven[2] = 0.0
+	jI := 0.0
+	prevjIOdd := 0.0
+	prevjIEven := 0.0
+	prevjIInputOdd := 0.0
+	prevjIInputEven := 0.0
+
+	jQOdd[0] = 0.0
+	jQOdd[1] = 0.0
+	jQOdd[2] = 0.0
+	jQEven[0] = 0.0
+	jQEven[1] = 0.0
+	jQEven[2] = 0.0
+	jQ := 0.0
+	prevjQOdd := 0.0
+	prevjQEven := 0.0
+	prevjQInputOdd := 0.0
+	prevjQInputEven := 0.0
+
+	period := 0.0
+	outIdx := startIdx
+	previ2, prevq2 := 0.0, 0.0
+	Re, Im := 0.0, 0.0
+	mama, fama := 0.0, 0.0
+	i1ForOddPrev3, i1ForEvenPrev3 := 0.0, 0.0
+	i1ForOddPrev2, i1ForEvenPrev2 := 0.0, 0.0
+	prevPhase := 0.0
+	adjustedPrevPeriod := 0.0
+	todayValue := 0.0
+	hilbertTempReal := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod = (0.075 * period) + 0.54
+		todayValue = inReal[today]
+
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		q2, i2 := 0.0, 0.0
+		tempReal2 := 0.0
+		if (today % 2) == 0 {
+
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevjIEven
+			prevjIEven = b * prevjIInputEven
+			jI += prevjIEven
+			prevjIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevjQEven
+			prevjQEven = b * prevjQInputEven
+			jQ += prevjQEven
+			prevjQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+			if i1ForEvenPrev3 != 0.0 {
+				tempReal2 = (math.Atan(q1/i1ForEvenPrev3) * rad2Deg)
+			} else {
+				tempReal2 = 0.0
+			}
+		} else {
+
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevjIOdd
+			prevjIOdd = b * prevjIInputOdd
+			jI += prevjIOdd
+			prevjIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevjQOdd
+			prevjQOdd = b * prevjQInputOdd
+			jQ += prevjQOdd
+			prevjQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+			if i1ForOddPrev3 != 0.0 {
+				tempReal2 = (math.Atan(q1/i1ForOddPrev3) * rad2Deg)
+			} else {
+				tempReal2 = 0.0
+			}
+		}
+		tempReal = prevPhase - tempReal2
+		prevPhase = tempReal2
+		if tempReal < 1.0 {
+			tempReal = 1.0
+		}
+		if tempReal > 1.0 {
+			tempReal = inFastLimit / tempReal
+			if tempReal < inSlowLimit {
+				tempReal = inSlowLimit
+			}
+		} else {
+			tempReal = inFastLimit
+		}
+		mama = (tempReal * todayValue) + ((1 - tempReal) * mama)
+		tempReal *= 0.5
+		fama = (tempReal * mama) + ((1 - tempReal) * fama)
+		if today >= startIdx {
+			outMAMA[outIdx] = mama
+			outFAMA[outIdx] = fama
+			outIdx++
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 = 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		today++
+	}
+	return outMAMA, outFAMA
+}
+
+// MaVp - Moving average with variable period
+func MaVp(inReal []float64, inPeriods []float64, inMinPeriod int, inMaxPeriod int, inMAType MaType) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	startIdx := inMaxPeriod - 1
+	outputSize := len(inReal)
+
+	localPeriodArray := make([]float64, outputSize)
+	for i := startIdx; i < outputSize; i++ {
+		tempInt := int(inPeriods[i])
+		if tempInt < inMinPeriod {
+			tempInt = inMinPeriod
+		} else if tempInt > inMaxPeriod {
+			tempInt = inMaxPeriod
+		}
+		localPeriodArray[i] = float64(tempInt)
+	}
+
+	for i := startIdx; i < outputSize; i++ {
+		curPeriod := int(localPeriodArray[i])
+		if curPeriod != 0 {
+			localOutputArray := Ma(inReal, curPeriod, inMAType)
+			outReal[i] = localOutputArray[i]
+			for j := i + 1; j < outputSize; j++ {
+				if localPeriodArray[j] == float64(curPeriod) {
+					localPeriodArray[j] = 0
+					outReal[j] = localOutputArray[j]
+				}
+			}
+		}
+	}
+	return outReal
+}
+
+// MidPoint - MidPoint over period
+func MidPoint(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := inTimePeriod - 1
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+
+	for today < len(inReal) {
+		lowest := inReal[trailingIdx]
+		trailingIdx++
+		highest := lowest
+		for i := trailingIdx; i <= today; i++ {
+			tmp := inReal[i]
+			if tmp < lowest {
+				lowest = tmp
+			} else if tmp > highest {
+				highest = tmp
+			}
+		}
+		outReal[outIdx] = (highest + lowest) / 2.0
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// MidPrice - Midpoint Price over period
+func MidPrice(inHigh []float64, inLow []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := inTimePeriod - 1
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	for today < len(inHigh) {
+		lowest := inLow[trailingIdx]
+		highest := inHigh[trailingIdx]
+		trailingIdx++
+		for i := trailingIdx; i <= today; i++ {
+			tmp := inLow[i]
+			if tmp < lowest {
+				lowest = tmp
+			}
+			tmp = inHigh[i]
+			if tmp > highest {
+				highest = tmp
+			}
+		}
+		outReal[outIdx] = (highest + lowest) / 2.0
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// Sar - Parabolic SAR
+// real = Sar(high, low, acceleration=0, maximum=0)
+func Sar(inHigh []float64, inLow []float64, inAcceleration float64, inMaximum float64) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	af := inAcceleration
+	if af > inMaximum {
+		af, inAcceleration = inMaximum, inMaximum
+	}
+
+	epTemp := MinusDM(inHigh, inLow, 1)
+	isLong := 1
+	if epTemp[1] > 0 {
+		isLong = 0
+	}
+	startIdx := 1
+	outIdx := startIdx
+	todayIdx := startIdx
+	newHigh := inHigh[todayIdx-1]
+	newLow := inLow[todayIdx-1]
+	sar, ep := 0.0, 0.0
+	if isLong == 1 {
+		ep = inHigh[todayIdx]
+		sar = newLow
+	} else {
+		ep = inLow[todayIdx]
+		sar = newHigh
+	}
+	newLow = inLow[todayIdx]
+	newHigh = inHigh[todayIdx]
+	prevLow := 0.0
+	prevHigh := 0.0
+	for todayIdx < len(inHigh) {
+		prevLow = newLow
+		prevHigh = newHigh
+		newLow = inLow[todayIdx]
+		newHigh = inHigh[todayIdx]
+		todayIdx++
+		if isLong == 1 {
+			if newLow <= sar {
+				isLong = 0
+				sar = ep
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+				outReal[outIdx] = sar
+				outIdx++
+				af = inAcceleration
+				ep = newLow
+				sar = sar + af*(ep-sar)
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+			} else {
+				outReal[outIdx] = sar
+				outIdx++
+				if newHigh > ep {
+					ep = newHigh
+					af += inAcceleration
+					if af > inMaximum {
+						af = inMaximum
+					}
+				}
+				sar = sar + af*(ep-sar)
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+			}
+		} else {
+			if newHigh >= sar {
+				isLong = 1
+				sar = ep
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+				outReal[outIdx] = sar
+				outIdx++
+				af = inAcceleration
+				ep = newHigh
+				sar = sar + af*(ep-sar)
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+			} else {
+				outReal[outIdx] = sar
+				outIdx++
+				if newLow < ep {
+					ep = newLow
+					af += inAcceleration
+					if af > inMaximum {
+						af = inMaximum
+					}
+				}
+				sar = sar + af*(ep-sar)
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+			}
+		}
+	}
+	return outReal
+}
+
+// SarExt - Parabolic SAR - Extended
+// real = SAREXT(high, low, startvalue=0, offsetonreverse=0, accelerationinitlong=0, accelerationlong=0, accelerationmaxlong=0, accelerationinitshort=0, accelerationshort=0, accelerationmaxshort=0)
+func SarExt(inHigh []float64, inLow []float64,
+	inStartValue float64,
+	inOffsetOnReverse float64,
+	inAccelerationInitLong float64,
+	inAccelerationLong float64,
+	inAccelerationMaxLong float64,
+	inAccelerationInitShort float64,
+	inAccelerationShort float64,
+	inAccelerationMaxShort float64) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	startIdx := 1
+	afLong := inAccelerationInitLong
+	afShort := inAccelerationInitShort
+	if afLong > inAccelerationMaxLong {
+		afLong, inAccelerationInitLong = inAccelerationMaxLong, inAccelerationMaxLong
+	}
+
+	if inAccelerationLong > inAccelerationMaxLong {
+		inAccelerationLong = inAccelerationMaxLong
+	}
+
+	if afShort > inAccelerationMaxShort {
+		afShort, inAccelerationInitShort = inAccelerationMaxShort, inAccelerationMaxShort
+	}
+
+	if inAccelerationShort > inAccelerationMaxShort {
+		inAccelerationShort = inAccelerationMaxShort
+	}
+
+	isLong := 0
+	if inStartValue == 0 {
+		epTemp := MinusDM(inHigh, inLow, 1)
+		if epTemp[1] > 0 {
+			isLong = 0
+		} else {
+			isLong = 1
+		}
+	} else if inStartValue > 0 {
+		isLong = 1
+	}
+	outIdx := startIdx
+	todayIdx := startIdx
+	newHigh := inHigh[todayIdx-1]
+	newLow := inLow[todayIdx-1]
+	ep := 0.0
+	sar := 0.0
+	if inStartValue == 0 {
+		if isLong == 1 {
+			ep = inHigh[todayIdx]
+			sar = newLow
+		} else {
+			ep = inLow[todayIdx]
+			sar = newHigh
+		}
+	} else if inStartValue > 0 {
+		ep = inHigh[todayIdx]
+		sar = inStartValue
+	} else {
+		ep = inLow[todayIdx]
+		sar = math.Abs(inStartValue)
+	}
+	newLow = inLow[todayIdx]
+	newHigh = inHigh[todayIdx]
+	prevLow := 0.0
+	prevHigh := 0.0
+	for todayIdx < len(inHigh) {
+		prevLow = newLow
+		prevHigh = newHigh
+		newLow = inLow[todayIdx]
+		newHigh = inHigh[todayIdx]
+		todayIdx++
+		if isLong == 1 {
+			if newLow <= sar {
+				isLong = 0
+				sar = ep
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+				if inOffsetOnReverse != 0.0 {
+					sar += sar * inOffsetOnReverse
+				}
+				outReal[outIdx] = -sar
+				outIdx++
+				afShort = inAccelerationInitShort
+				ep = newLow
+				sar = sar + afShort*(ep-sar)
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+			} else {
+				outReal[outIdx] = sar
+				outIdx++
+				if newHigh > ep {
+					ep = newHigh
+					afLong += inAccelerationLong
+					if afLong > inAccelerationMaxLong {
+						afLong = inAccelerationMaxLong
+					}
+				}
+				sar = sar + afLong*(ep-sar)
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+			}
+		} else {
+			if newHigh >= sar {
+				isLong = 1
+				sar = ep
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+				if inOffsetOnReverse != 0.0 {
+					sar -= sar * inOffsetOnReverse
+				}
+				outReal[outIdx] = sar
+				outIdx++
+				afLong = inAccelerationInitLong
+				ep = newHigh
+				sar = sar + afLong*(ep-sar)
+				if sar > prevLow {
+					sar = prevLow
+				}
+				if sar > newLow {
+					sar = newLow
+				}
+			} else {
+				outReal[outIdx] = -sar
+				outIdx++
+				if newLow < ep {
+					ep = newLow
+					afShort += inAccelerationShort
+					if afShort > inAccelerationMaxShort {
+						afShort = inAccelerationMaxShort
+					}
+				}
+				sar = sar + afShort*(ep-sar)
+				if sar < prevHigh {
+					sar = prevHigh
+				}
+				if sar < newHigh {
+					sar = newHigh
+				}
+			}
+		}
+	}
+	return outReal
+}
+
+// Sma - Simple Moving Average
+func Sma(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	periodTotal := 0.0
+	trailingIdx := startIdx - lookbackTotal
+	i := trailingIdx
+	if inTimePeriod > 1 {
+		for i < startIdx {
+			periodTotal += inReal[i]
+			i++
+		}
+	}
+	outIdx := startIdx
+	for ok := true; ok; {
+		periodTotal += inReal[i]
+		tempReal := periodTotal
+		periodTotal -= inReal[trailingIdx]
+		outReal[outIdx] = tempReal / float64(inTimePeriod)
+		trailingIdx++
+		i++
+		outIdx++
+		ok = i < len(outReal)
+	}
+
+	return outReal
+}
+
+// T3 - Triple Exponential Moving Average (T3) (lookback=6*inTimePeriod)
+func T3(inReal []float64, inTimePeriod int, inVFactor float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := 6 * (inTimePeriod - 1)
+	startIdx := lookbackTotal
+	today := startIdx - lookbackTotal
+	k := 2.0 / (float64(inTimePeriod) + 1.0)
+	oneMinusK := 1.0 - k
+	tempReal := inReal[today]
+	today++
+	for i := inTimePeriod - 1; i > 0; i-- {
+		tempReal += inReal[today]
+		today++
+	}
+	e1 := tempReal / float64(inTimePeriod)
+	tempReal = e1
+	for i := inTimePeriod - 1; i > 0; i-- {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		tempReal += e1
+		today++
+	}
+	e2 := tempReal / float64(inTimePeriod)
+	tempReal = e2
+	for i := inTimePeriod - 1; i > 0; i-- {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		tempReal += e2
+		today++
+	}
+	e3 := tempReal / float64(inTimePeriod)
+	tempReal = e3
+	for i := inTimePeriod - 1; i > 0; i-- {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		e3 = (k * e2) + (oneMinusK * e3)
+		tempReal += e3
+		today++
+	}
+	e4 := tempReal / float64(inTimePeriod)
+	tempReal = e4
+	for i := inTimePeriod - 1; i > 0; i-- {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		e3 = (k * e2) + (oneMinusK * e3)
+		e4 = (k * e3) + (oneMinusK * e4)
+		tempReal += e4
+		today++
+	}
+	e5 := tempReal / float64(inTimePeriod)
+	tempReal = e5
+	for i := inTimePeriod - 1; i > 0; i-- {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		e3 = (k * e2) + (oneMinusK * e3)
+		e4 = (k * e3) + (oneMinusK * e4)
+		e5 = (k * e4) + (oneMinusK * e5)
+		tempReal += e5
+		today++
+	}
+	e6 := tempReal / float64(inTimePeriod)
+	for today <= startIdx {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		e3 = (k * e2) + (oneMinusK * e3)
+		e4 = (k * e3) + (oneMinusK * e4)
+		e5 = (k * e4) + (oneMinusK * e5)
+		e6 = (k * e5) + (oneMinusK * e6)
+		today++
+	}
+	tempReal = inVFactor * inVFactor
+	c1 := -(tempReal * inVFactor)
+	c2 := 3.0 * (tempReal - c1)
+	c3 := -6.0*tempReal - 3.0*(inVFactor-c1)
+	c4 := 1.0 + 3.0*inVFactor - c1 + 3.0*tempReal
+	outIdx := lookbackTotal
+	outReal[outIdx] = c1*e6 + c2*e5 + c3*e4 + c4*e3
+	outIdx++
+	for today < len(inReal) {
+		e1 = (k * inReal[today]) + (oneMinusK * e1)
+		e2 = (k * e1) + (oneMinusK * e2)
+		e3 = (k * e2) + (oneMinusK * e3)
+		e4 = (k * e3) + (oneMinusK * e4)
+		e5 = (k * e4) + (oneMinusK * e5)
+		e6 = (k * e5) + (oneMinusK * e6)
+		outReal[outIdx] = c1*e6 + c2*e5 + c3*e4 + c4*e3
+		outIdx++
+		today++
+	}
+
+	return outReal
+}
+
+// Tema - Triple Exponential Moving Average
+func Tema(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	firstEMA := Ema(inReal, inTimePeriod)
+	secondEMA := Ema(firstEMA[inTimePeriod-1:], inTimePeriod)
+	thirdEMA := Ema(secondEMA[inTimePeriod-1:], inTimePeriod)
+
+	outIdx := (inTimePeriod * 3) - 3
+	secondEMAIdx := (inTimePeriod * 2) - 2
+	thirdEMAIdx := inTimePeriod - 1
+
+	for outIdx < len(inReal) {
+		outReal[outIdx] = thirdEMA[thirdEMAIdx] + ((3.0 * firstEMA[outIdx]) - (3.0 * secondEMA[secondEMAIdx]))
+		outIdx++
+		secondEMAIdx++
+		thirdEMAIdx++
+	}
+
+	return outReal
+}
+
+// Trima - Triangular Moving Average
+func Trima(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	outIdx := inTimePeriod - 1
+	var factor float64
+
+	if inTimePeriod%2 == 1 {
+		i := inTimePeriod >> 1
+		factor = (float64(i) + 1.0) * (float64(i) + 1.0)
+		factor = 1.0 / factor
+		trailingIdx := startIdx - lookbackTotal
+		middleIdx := trailingIdx + i
+		todayIdx := middleIdx + i
+		numerator := 0.0
+		numeratorSub := 0.0
+		for i := middleIdx; i >= trailingIdx; i-- {
+			tempReal := inReal[i]
+			numeratorSub += tempReal
+			numerator += numeratorSub
+		}
+		numeratorAdd := 0.0
+		middleIdx++
+		for i := middleIdx; i <= todayIdx; i++ {
+			tempReal := inReal[i]
+			numeratorAdd += tempReal
+			numerator += numeratorAdd
+		}
+		outIdx = inTimePeriod - 1
+		tempReal := inReal[trailingIdx]
+		trailingIdx++
+		outReal[outIdx] = numerator * factor
+		outIdx++
+		todayIdx++
+		for todayIdx < len(inReal) {
+			numerator -= numeratorSub
+			numeratorSub -= tempReal
+			tempReal = inReal[middleIdx]
+			middleIdx++
+			numeratorSub += tempReal
+			numerator += numeratorAdd
+			numeratorAdd -= tempReal
+			tempReal = inReal[todayIdx]
+			todayIdx++
+			numeratorAdd += tempReal
+			numerator += tempReal
+			tempReal = inReal[trailingIdx]
+			trailingIdx++
+			outReal[outIdx] = numerator * factor
+			outIdx++
+		}
+
+	} else {
+
+		i := (inTimePeriod >> 1)
+		factor = float64(i) * (float64(i) + 1)
+		factor = 1.0 / factor
+		trailingIdx := startIdx - lookbackTotal
+		middleIdx := trailingIdx + i - 1
+		todayIdx := middleIdx + i
+		numerator := 0.0
+		numeratorSub := 0.0
+		for i := middleIdx; i >= trailingIdx; i-- {
+			tempReal := inReal[i]
+			numeratorSub += tempReal
+			numerator += numeratorSub
+		}
+		numeratorAdd := 0.0
+		middleIdx++
+		for i := middleIdx; i <= todayIdx; i++ {
+			tempReal := inReal[i]
+			numeratorAdd += tempReal
+			numerator += numeratorAdd
+		}
+		outIdx = inTimePeriod - 1
+		tempReal := inReal[trailingIdx]
+		trailingIdx++
+		outReal[outIdx] = numerator * factor
+		outIdx++
+		todayIdx++
+
+		for todayIdx < len(inReal) {
+			numerator -= numeratorSub
+			numeratorSub -= tempReal
+			tempReal = inReal[middleIdx]
+			middleIdx++
+			numeratorSub += tempReal
+			numeratorAdd -= tempReal
+			numerator += numeratorAdd
+			tempReal = inReal[todayIdx]
+			todayIdx++
+			numeratorAdd += tempReal
+			numerator += tempReal
+			tempReal = inReal[trailingIdx]
+			trailingIdx++
+			outReal[outIdx] = numerator * factor
+			outIdx++
+		}
+	}
+	return outReal
+}
+
+// Wma - Weighted Moving Average
+func Wma(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+
+	if inTimePeriod == 1 {
+		copy(outReal, inReal)
+		return outReal
+	}
+	divider := (inTimePeriod * (inTimePeriod + 1)) >> 1
+	outIdx := inTimePeriod - 1
+	trailingIdx := startIdx - lookbackTotal
+	periodSum, periodSub := 0.0, 0.0
+	inIdx := trailingIdx
+	i := 1
+	for inIdx < startIdx {
+		tempReal := inReal[inIdx]
+		periodSub += tempReal
+		periodSum += tempReal * float64(i)
+		inIdx++
+		i++
+	}
+	trailingValue := 0.0
+	for inIdx < len(inReal) {
+		tempReal := inReal[inIdx]
+		periodSub += tempReal
+		periodSub -= trailingValue
+		periodSum += tempReal * float64(inTimePeriod)
+		trailingValue = inReal[trailingIdx]
+		outReal[outIdx] = periodSum / float64(divider)
+		periodSum -= periodSub
+		inIdx++
+		trailingIdx++
+		outIdx++
+	}
+	return outReal
+}
+
+/* Momentum Indicators */
+
+// Adx - Average Directional Movement Index
+func Adx(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := (2 * inTimePeriod) - 1
+	startIdx := lookbackTotal
+	outIdx := inTimePeriod
+	prevMinusDM := 0.0
+	prevPlusDM := 0.0
+	prevTR := 0.0
+	today := startIdx - lookbackTotal
+	prevHigh := inHigh[today]
+	prevLow := inLow[today]
+	prevClose := inClose[today]
+	for i := inTimePeriod - 1; i > 0; i-- {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		} else if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR += tempReal
+		prevClose = inClose[today]
+	}
+	sumDX := 0.0
+	for i := inTimePeriod; i > 0; i-- {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		prevMinusDM -= prevMinusDM / inTimePeriodF
+		prevPlusDM -= prevPlusDM / inTimePeriodF
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		} else if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / inTimePeriodF) + tempReal
+		prevClose = inClose[today]
+		if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+			minusDI := (100.0 * (prevMinusDM / prevTR))
+			plusDI := (100.0 * (prevPlusDM / prevTR))
+			tempReal = minusDI + plusDI
+			if !(((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001))) {
+				sumDX += (100.0 * (math.Abs(minusDI-plusDI) / tempReal))
+			}
+		}
+	}
+	prevADX := (sumDX / inTimePeriodF)
+
+	outReal[startIdx] = prevADX
+	outIdx = startIdx + 1
+	today++
+	for today < len(inClose) {
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		prevMinusDM -= prevMinusDM / inTimePeriodF
+		prevPlusDM -= prevPlusDM / inTimePeriodF
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		} else if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / inTimePeriodF) + tempReal
+		prevClose = inClose[today]
+		if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+			minusDI := (100.0 * (prevMinusDM / prevTR))
+			plusDI := (100.0 * (prevPlusDM / prevTR))
+			tempReal = minusDI + plusDI
+			if !(((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001))) {
+				tempReal = (100.0 * (math.Abs(minusDI-plusDI) / tempReal))
+				prevADX = (((prevADX * (inTimePeriodF - 1)) + tempReal) / inTimePeriodF)
+			}
+		}
+		outReal[outIdx] = prevADX
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// AdxR - Average Directional Movement Index Rating
+func AdxR(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	startIdx := (2 * inTimePeriod) - 1
+	tmpadx := Adx(inHigh, inLow, inClose, inTimePeriod)
+	i := startIdx
+	j := startIdx + inTimePeriod - 1
+	for outIdx := startIdx + inTimePeriod - 1; outIdx < len(inClose); outIdx, i, j = outIdx+1, i+1, j+1 {
+		outReal[outIdx] = ((tmpadx[i] + tmpadx[j]) / 2.0)
+	}
+	return outReal
+}
+
+// Apo - Absolute Price Oscillator
+func Apo(inReal []float64, inFastPeriod int, inSlowPeriod int, inMAType MaType) []float64 {
+
+	if inSlowPeriod < inFastPeriod {
+		inSlowPeriod, inFastPeriod = inFastPeriod, inSlowPeriod
+	}
+	tempBuffer := Ma(inReal, inFastPeriod, inMAType)
+	outReal := Ma(inReal, inSlowPeriod, inMAType)
+	for i := inSlowPeriod - 1; i < len(inReal); i++ {
+		outReal[i] = tempBuffer[i] - outReal[i]
+	}
+
+	return outReal
+}
+
+// Aroon - Aroon
+// aroondown, aroonup = AROON(high, low, timeperiod=14)
+func Aroon(inHigh []float64, inLow []float64, inTimePeriod int) ([]float64, []float64) {
+
+	outAroonUp := make([]float64, len(inHigh))
+	outAroonDown := make([]float64, len(inHigh))
+
+	startIdx := inTimePeriod
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - inTimePeriod
+	lowestIdx := -1
+	highestIdx := -1
+	lowest := 0.0
+	highest := 0.0
+	factor := 100.0 / float64(inTimePeriod)
+	for today < len(inHigh) {
+		tmp := inLow[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inLow[lowestIdx]
+			i := lowestIdx
+			i++
+			for i <= today {
+				tmp = inLow[i]
+				if tmp <= lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+		}
+		tmp = inHigh[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inHigh[highestIdx]
+			i := highestIdx
+			i++
+			for i <= today {
+				tmp = inHigh[i]
+				if tmp >= highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+		}
+		outAroonUp[outIdx] = factor * float64(inTimePeriod-(today-highestIdx))
+		outAroonDown[outIdx] = factor * float64(inTimePeriod-(today-lowestIdx))
+		outIdx++
+		trailingIdx++
+		today++
+	}
+	return outAroonDown, outAroonUp
+}
+
+// AroonOsc - Aroon Oscillator
+func AroonOsc(inHigh []float64, inLow []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	startIdx := inTimePeriod
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - inTimePeriod
+	lowestIdx := -1
+	highestIdx := -1
+	lowest := 0.0
+	highest := 0.0
+	factor := 100.0 / float64(inTimePeriod)
+	for today < len(inHigh) {
+		tmp := inLow[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inLow[lowestIdx]
+			i := lowestIdx
+			i++
+			for i <= today {
+				tmp = inLow[i]
+				if tmp <= lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+		}
+		tmp = inHigh[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inHigh[highestIdx]
+			i := highestIdx
+			i++
+			for i <= today {
+				tmp = inHigh[i]
+				if tmp >= highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+		}
+		aroon := factor * float64(highestIdx-lowestIdx)
+		outReal[outIdx] = aroon
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	return outReal
+}
+
+// Bop - Balance Of Power
+func Bop(inOpen []float64, inHigh []float64, inLow []float64, inClose []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	for i := 0; i < len(inClose); i++ {
+		tempReal := inHigh[i] - inLow[i]
+		if tempReal < (0.00000000000001) {
+			outReal[i] = 0.0
+		} else {
+			outReal[i] = (inClose[i] - inOpen[i]) / tempReal
+		}
+	}
+
+	return outReal
+}
+
+// Cmo - Chande Momentum Oscillator
+func Cmo(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx
+	if inTimePeriod == 1 {
+		copy(outReal, inReal)
+		return outReal
+	}
+	today := startIdx - lookbackTotal
+	prevValue := inReal[today]
+	prevGain := 0.0
+	prevLoss := 0.0
+	today++
+	for i := inTimePeriod; i > 0; i-- {
+		tempValue1 := inReal[today]
+		tempValue2 := tempValue1 - prevValue
+		prevValue = tempValue1
+		if tempValue2 < 0 {
+			prevLoss -= tempValue2
+		} else {
+			prevGain += tempValue2
+		}
+		today++
+	}
+	prevLoss /= float64(inTimePeriod)
+	prevGain /= float64(inTimePeriod)
+	if today > startIdx {
+		tempValue1 := prevGain + prevLoss
+		if !(((-(0.00000000000001)) < tempValue1) && (tempValue1 < (0.00000000000001))) {
+			outReal[outIdx] = 100.0 * ((prevGain - prevLoss) / tempValue1)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	} else {
+		for today < startIdx {
+			tempValue1 := inReal[today]
+			tempValue2 := tempValue1 - prevValue
+			prevValue = tempValue1
+			prevLoss *= float64(inTimePeriod - 1)
+			prevGain *= float64(inTimePeriod - 1)
+			if tempValue2 < 0 {
+				prevLoss -= tempValue2
+			} else {
+				prevGain += tempValue2
+			}
+			prevLoss /= float64(inTimePeriod)
+			prevGain /= float64(inTimePeriod)
+			today++
+		}
+	}
+	for today < len(inReal) {
+		tempValue1 := inReal[today]
+		today++
+		tempValue2 := tempValue1 - prevValue
+		prevValue = tempValue1
+		prevLoss *= float64(inTimePeriod - 1)
+		prevGain *= float64(inTimePeriod - 1)
+		if tempValue2 < 0 {
+			prevLoss -= tempValue2
+		} else {
+			prevGain += tempValue2
+		}
+		prevLoss /= float64(inTimePeriod)
+		prevGain /= float64(inTimePeriod)
+		tempValue1 = prevGain + prevLoss
+		if !(((-(0.00000000000001)) < tempValue1) && (tempValue1 < (0.00000000000001))) {
+			outReal[outIdx] = 100.0 * ((prevGain - prevLoss) / tempValue1)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	}
+	return outReal
+}
+
+// Cci - Commodity Channel Index
+func Cci(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	circBufferIdx := 0
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	circBuffer := make([]float64, inTimePeriod)
+	maxIdxCircBuffer := (inTimePeriod - 1)
+	i := startIdx - lookbackTotal
+	if inTimePeriod > 1 {
+		for i < startIdx {
+			circBuffer[circBufferIdx] = (inHigh[i] + inLow[i] + inClose[i]) / 3
+			i++
+			circBufferIdx++
+			if circBufferIdx > maxIdxCircBuffer {
+				circBufferIdx = 0
+			}
+
+		}
+	}
+	outIdx := inTimePeriod - 1
+	for i < len(inClose) {
+		lastValue := (inHigh[i] + inLow[i] + inClose[i]) / 3
+		circBuffer[circBufferIdx] = lastValue
+		theAverage := 0.0
+		for j := 0; j < inTimePeriod; j++ {
+			theAverage += circBuffer[j]
+		}
+
+		theAverage /= float64(inTimePeriod)
+		tempReal2 := 0.0
+		for j := 0; j < inTimePeriod; j++ {
+			tempReal2 += math.Abs(circBuffer[j] - theAverage)
+		}
+		tempReal := lastValue - theAverage
+		if (tempReal != 0.0) && (tempReal2 != 0.0) {
+			outReal[outIdx] = tempReal / (0.015 * (tempReal2 / float64(inTimePeriod)))
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		{
+			circBufferIdx++
+			if circBufferIdx > maxIdxCircBuffer {
+				circBufferIdx = 0
+			}
+		}
+		outIdx++
+		i++
+	}
+
+	return outReal
+}
+
+// Dx - Directional Movement Index
+func Dx(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	lookbackTotal := 2
+	if inTimePeriod > 1 {
+		lookbackTotal = inTimePeriod
+	}
+	startIdx := lookbackTotal
+	outIdx := startIdx
+	prevMinusDM := 0.0
+	prevPlusDM := 0.0
+	prevTR := 0.0
+	today := startIdx - lookbackTotal
+	prevHigh := inHigh[today]
+	prevLow := inLow[today]
+	prevClose := inClose[today]
+	i := inTimePeriod - 1
+	for i > 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		} else if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR += tempReal
+		prevClose = inClose[today]
+	}
+
+	if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+		minusDI := (100.0 * (prevMinusDM / prevTR))
+		plusDI := (100.0 * (prevPlusDM / prevTR))
+		tempReal := minusDI + plusDI
+		if !(((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001))) {
+			outReal[outIdx] = (100.0 * (math.Abs(minusDI-plusDI) / tempReal))
+		} else {
+			outReal[outIdx] = 0.0
+		}
+	} else {
+		outReal[outIdx] = 0.0
+	}
+
+	outIdx = startIdx
+	for today < len(inClose)-1 {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		prevMinusDM -= prevMinusDM / float64(inTimePeriod)
+		prevPlusDM -= prevPlusDM / float64(inTimePeriod)
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		} else if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / float64(inTimePeriod)) + tempReal
+		prevClose = inClose[today]
+		if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+			minusDI := (100.0 * (prevMinusDM / prevTR))
+			plusDI := (100.0 * (prevPlusDM / prevTR))
+			tempReal = minusDI + plusDI
+			if !(((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001))) {
+				outReal[outIdx] = (100.0 * (math.Abs(minusDI-plusDI) / tempReal))
+			} else {
+				outReal[outIdx] = outReal[outIdx-1]
+			}
+		} else {
+			outReal[outIdx] = outReal[outIdx-1]
+		}
+		outIdx++
+	}
+	return outReal
+}
+
+// Macd - Moving Average Convergence/Divergence
+// unstable period ~= 100
+func Macd(inReal []float64, inFastPeriod int, inSlowPeriod int, inSignalPeriod int) ([]float64, []float64, []float64) {
+
+	if inSlowPeriod < inFastPeriod {
+		inSlowPeriod, inFastPeriod = inFastPeriod, inSlowPeriod
+	}
+
+	k1 := 0.0
+	k2 := 0.0
+	if inSlowPeriod != 0 {
+		k1 = 2.0 / float64(inSlowPeriod+1)
+	} else {
+		inSlowPeriod = 26
+		k1 = 0.075
+	}
+	if inFastPeriod != 0 {
+		k2 = 2.0 / float64(inFastPeriod+1)
+	} else {
+		inFastPeriod = 12
+		k2 = 0.15
+	}
+
+	lookbackSignal := inSignalPeriod - 1
+	lookbackTotal := lookbackSignal
+	lookbackTotal += (inSlowPeriod - 1)
+
+	fastEMABuffer := ema(inReal, inFastPeriod, k2)
+	slowEMABuffer := ema(inReal, inSlowPeriod, k1)
+	for i := 0; i < len(fastEMABuffer); i++ {
+		fastEMABuffer[i] = fastEMABuffer[i] - slowEMABuffer[i]
+	}
+
+	outMACD := make([]float64, len(inReal))
+	for i := lookbackTotal - 1; i < len(fastEMABuffer); i++ {
+		outMACD[i] = fastEMABuffer[i]
+	}
+	outMACDSignal := ema(outMACD, inSignalPeriod, (2.0 / float64(inSignalPeriod+1)))
+
+	outMACDHist := make([]float64, len(inReal))
+	for i := lookbackTotal; i < len(outMACDHist); i++ {
+		outMACDHist[i] = outMACD[i] - outMACDSignal[i]
+	}
+
+	return outMACD, outMACDSignal, outMACDHist
+}
+
+// MacdExt - MACD with controllable MA type
+// unstable period ~= 100
+func MacdExt(inReal []float64, inFastPeriod int, inFastMAType MaType, inSlowPeriod int, inSlowMAType MaType, inSignalPeriod int, inSignalMAType MaType) ([]float64, []float64, []float64) {
+
+	lookbackLargest := 0
+	if inFastPeriod < inSlowPeriod {
+		lookbackLargest = inSlowPeriod
+	} else {
+		lookbackLargest = inFastPeriod
+	}
+	lookbackTotal := (inSignalPeriod - 1) + (lookbackLargest - 1)
+
+	outMACD := make([]float64, len(inReal))
+	outMACDSignal := make([]float64, len(inReal))
+	outMACDHist := make([]float64, len(inReal))
+
+	slowMABuffer := Ma(inReal, inSlowPeriod, inSlowMAType)
+	fastMABuffer := Ma(inReal, inFastPeriod, inFastMAType)
+	tempBuffer1 := make([]float64, len(inReal))
+
+	for i := 0; i < len(slowMABuffer); i++ {
+		tempBuffer1[i] = fastMABuffer[i] - slowMABuffer[i]
+	}
+	tempBuffer2 := Ma(tempBuffer1, inSignalPeriod, inSignalMAType)
+
+	for i := lookbackTotal; i < len(outMACDHist); i++ {
+		outMACD[i] = tempBuffer1[i]
+		outMACDSignal[i] = tempBuffer2[i]
+		outMACDHist[i] = outMACD[i] - outMACDSignal[i]
+	}
+
+	return outMACD, outMACDSignal, outMACDHist
+}
+
+// MacdFix - MACD Fix 12/26
+// unstable period ~= 100
+func MacdFix(inReal []float64, inSignalPeriod int) ([]float64, []float64, []float64) {
+	return Macd(inReal, 0, 0, inSignalPeriod)
+}
+
+// MinusDI - Minus Directional Indicator
+func MinusDI(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	lookbackTotal := 1
+	if inTimePeriod > 1 {
+		lookbackTotal = inTimePeriod
+	}
+	startIdx := lookbackTotal
+	outIdx := startIdx
+
+	prevHigh := 0.0
+	prevLow := 0.0
+	prevClose := 0.0
+	if inTimePeriod <= 1 {
+		today := startIdx - 1
+		prevHigh = inHigh[today]
+		prevLow = inLow[today]
+		prevClose = inClose[today]
+		for today < len(inClose)-1 {
+			today++
+			tempReal := inHigh[today]
+			diffP := tempReal - prevHigh
+			prevHigh = tempReal
+			tempReal = inLow[today]
+			diffM := prevLow - tempReal
+			prevLow = tempReal
+			if (diffM > 0) && (diffP < diffM) {
+
+				tempReal = prevHigh - prevLow
+				tempReal2 := math.Abs(prevHigh - prevClose)
+				if tempReal2 > tempReal {
+					tempReal = tempReal2
+				}
+				tempReal2 = math.Abs(prevLow - prevClose)
+				if tempReal2 > tempReal {
+					tempReal = tempReal2
+				}
+
+				if ((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001)) {
+					outReal[outIdx] = 0.0
+				} else {
+					outReal[outIdx] = diffM / tempReal
+				}
+				outIdx++
+			} else {
+				outReal[outIdx] = 0.0
+				outIdx++
+			}
+			prevClose = inClose[today]
+		}
+		return outReal
+	}
+	prevMinusDM := 0.0
+	prevTR := 0.0
+	today := startIdx - lookbackTotal
+	prevHigh = inHigh[today]
+	prevLow = inLow[today]
+	prevClose = inClose[today]
+	i := inTimePeriod - 1
+
+	for i > 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR += tempReal
+		prevClose = inClose[today]
+	}
+	i = 1
+	for i != 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod)) + diffM
+		} else {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod))
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / float64(inTimePeriod)) + tempReal
+		prevClose = inClose[today]
+	}
+	if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+		outReal[startIdx] = (100.0 * (prevMinusDM / prevTR))
+	} else {
+		outReal[startIdx] = 0.0
+	}
+	outIdx = startIdx + 1
+	for today < len(inClose)-1 {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod)) + diffM
+		} else {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod))
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / float64(inTimePeriod)) + tempReal
+		prevClose = inClose[today]
+		if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+			outReal[outIdx] = (100.0 * (prevMinusDM / prevTR))
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	}
+
+	return outReal
+}
+
+// MinusDM - Minus Directional Movement
+func MinusDM(inHigh []float64, inLow []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	lookbackTotal := 1
+	if inTimePeriod > 1 {
+		lookbackTotal = inTimePeriod - 1
+	}
+	startIdx := lookbackTotal
+	outIdx := startIdx
+	today := startIdx
+	prevHigh := 0.0
+	prevLow := 0.0
+	if inTimePeriod <= 1 {
+		today = startIdx - 1
+		prevHigh = inHigh[today]
+		prevLow = inLow[today]
+		for today < len(inHigh)-1 {
+			today++
+			tempReal := inHigh[today]
+			diffP := tempReal - prevHigh
+			prevHigh = tempReal
+			tempReal = inLow[today]
+			diffM := prevLow - tempReal
+			prevLow = tempReal
+			if (diffM > 0) && (diffP < diffM) {
+				outReal[outIdx] = diffM
+			} else {
+				outReal[outIdx] = 0
+			}
+			outIdx++
+		}
+		return outReal
+	}
+	prevMinusDM := 0.0
+	today = startIdx - lookbackTotal
+	prevHigh = inHigh[today]
+	prevLow = inLow[today]
+	i := inTimePeriod - 1
+	for i > 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM += diffM
+		}
+	}
+	i = 0
+	for i != 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod)) + diffM
+		} else {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod))
+		}
+	}
+	outReal[startIdx] = prevMinusDM
+	outIdx = startIdx + 1
+	for today < len(inHigh)-1 {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffM > 0) && (diffP < diffM) {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod)) + diffM
+		} else {
+			prevMinusDM = prevMinusDM - (prevMinusDM / float64(inTimePeriod))
+		}
+		outReal[outIdx] = prevMinusDM
+		outIdx++
+	}
+	return outReal
+}
+
+// Mfi - Money Flow Index
+func Mfi(inHigh []float64, inLow []float64, inClose []float64, inVolume []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	mflowIdx := 0
+	maxIdxMflow := (50 - 1)
+	mflow := make([]moneyFlow, inTimePeriod)
+	maxIdxMflow = inTimePeriod - 1
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx
+	today := startIdx - lookbackTotal
+	prevValue := (inHigh[today] + inLow[today] + inClose[today]) / 3.0
+	posSumMF := 0.0
+	negSumMF := 0.0
+	today++
+	for i := inTimePeriod; i > 0; i-- {
+		tempValue1 := (inHigh[today] + inLow[today] + inClose[today]) / 3.0
+		tempValue2 := tempValue1 - prevValue
+		prevValue = tempValue1
+		tempValue1 *= inVolume[today]
+		today++
+		if tempValue2 < 0 {
+			(mflow[mflowIdx]).negative = tempValue1
+			negSumMF += tempValue1
+			(mflow[mflowIdx]).positive = 0.0
+		} else if tempValue2 > 0 {
+			(mflow[mflowIdx]).positive = tempValue1
+			posSumMF += tempValue1
+			(mflow[mflowIdx]).negative = 0.0
+		} else {
+			(mflow[mflowIdx]).positive = 0.0
+			(mflow[mflowIdx]).negative = 0.0
+		}
+		mflowIdx++
+		if mflowIdx > maxIdxMflow {
+			mflowIdx = 0
+		}
+
+	}
+	if today > startIdx {
+		tempValue1 := posSumMF + negSumMF
+		if tempValue1 < 1.0 {
+		} else {
+			outReal[outIdx] = 100.0 * (posSumMF / tempValue1)
+			outIdx++
+		}
+	} else {
+		for today < startIdx {
+			posSumMF -= mflow[mflowIdx].positive
+			negSumMF -= mflow[mflowIdx].negative
+			tempValue1 := (inHigh[today] + inLow[today] + inClose[today]) / 3.0
+			tempValue2 := tempValue1 - prevValue
+			prevValue = tempValue1
+			tempValue1 *= inVolume[today]
+			today++
+			if tempValue2 < 0 {
+				(mflow[mflowIdx]).negative = tempValue1
+				negSumMF += tempValue1
+				(mflow[mflowIdx]).positive = 0.0
+			} else if tempValue2 > 0 {
+				(mflow[mflowIdx]).positive = tempValue1
+				posSumMF += tempValue1
+				(mflow[mflowIdx]).negative = 0.0
+			} else {
+				(mflow[mflowIdx]).positive = 0.0
+				(mflow[mflowIdx]).negative = 0.0
+			}
+			mflowIdx++
+			if mflowIdx > maxIdxMflow {
+				mflowIdx = 0
+			}
+
+		}
+	}
+	for today < len(inClose) {
+		posSumMF -= (mflow[mflowIdx]).positive
+		negSumMF -= (mflow[mflowIdx]).negative
+		tempValue1 := (inHigh[today] + inLow[today] + inClose[today]) / 3.0
+		tempValue2 := tempValue1 - prevValue
+		prevValue = tempValue1
+		tempValue1 *= inVolume[today]
+		today++
+		if tempValue2 < 0 {
+			(mflow[mflowIdx]).negative = tempValue1
+			negSumMF += tempValue1
+			(mflow[mflowIdx]).positive = 0.0
+		} else if tempValue2 > 0 {
+			(mflow[mflowIdx]).positive = tempValue1
+			posSumMF += tempValue1
+			(mflow[mflowIdx]).negative = 0.0
+		} else {
+			(mflow[mflowIdx]).positive = 0.0
+			(mflow[mflowIdx]).negative = 0.0
+		}
+		tempValue1 = posSumMF + negSumMF
+		if tempValue1 < 1.0 {
+			outReal[outIdx] = 0.0
+		} else {
+			outReal[outIdx] = 100.0 * (posSumMF / tempValue1)
+		}
+		outIdx++
+		mflowIdx++
+		if mflowIdx > maxIdxMflow {
+			mflowIdx = 0
+		}
+	}
+	return outReal
+}
+
+// Mom - Momentum
+func Mom(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inIdx, outIdx, trailingIdx := inTimePeriod, inTimePeriod, 0
+	for inIdx < len(inReal) {
+		outReal[outIdx] = inReal[inIdx] - inReal[trailingIdx]
+		inIdx, outIdx, trailingIdx = inIdx+1, outIdx+1, trailingIdx+1
+	}
+
+	return outReal
+}
+
+// PlusDI - Plus Directional Indicator
+func PlusDI(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	lookbackTotal := 1
+	if inTimePeriod > 1 {
+		lookbackTotal = inTimePeriod
+	}
+	startIdx := lookbackTotal
+	outIdx := startIdx
+
+	prevHigh := 0.0
+	prevLow := 0.0
+	prevClose := 0.0
+	if inTimePeriod <= 1 {
+		today := startIdx - 1
+		prevHigh = inHigh[today]
+		prevLow = inLow[today]
+		prevClose = inClose[today]
+		for today < len(inClose)-1 {
+			today++
+			tempReal := inHigh[today]
+			diffP := tempReal - prevHigh
+			prevHigh = tempReal
+			tempReal = inLow[today]
+			diffM := prevLow - tempReal
+			prevLow = tempReal
+			if (diffP > 0) && (diffP > diffM) {
+
+				tempReal = prevHigh - prevLow
+				tempReal2 := math.Abs(prevHigh - prevClose)
+				if tempReal2 > tempReal {
+					tempReal = tempReal2
+				}
+				tempReal2 = math.Abs(prevLow - prevClose)
+				if tempReal2 > tempReal {
+					tempReal = tempReal2
+				}
+
+				if ((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001)) {
+					outReal[outIdx] = 0.0
+				} else {
+					outReal[outIdx] = diffP / tempReal
+				}
+				outIdx++
+			} else {
+				outReal[outIdx] = 0.0
+				outIdx++
+			}
+			prevClose = inClose[today]
+		}
+		return outReal
+	}
+	prevPlusDM := 0.0
+	prevTR := 0.0
+	today := startIdx - lookbackTotal
+	prevHigh = inHigh[today]
+	prevLow = inLow[today]
+	prevClose = inClose[today]
+	i := inTimePeriod - 1
+
+	for i > 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR += tempReal
+		prevClose = inClose[today]
+	}
+	i = 1
+	for i != 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod)) + diffP
+		} else {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod))
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / float64(inTimePeriod)) + tempReal
+		prevClose = inClose[today]
+	}
+	if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+		outReal[startIdx] = (100.0 * (prevPlusDM / prevTR))
+	} else {
+		outReal[startIdx] = 0.0
+	}
+	outIdx = startIdx + 1
+	for today < len(inClose)-1 {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod)) + diffP
+		} else {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod))
+		}
+		tempReal = prevHigh - prevLow
+		tempReal2 := math.Abs(prevHigh - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+		tempReal2 = math.Abs(prevLow - prevClose)
+		if tempReal2 > tempReal {
+			tempReal = tempReal2
+		}
+
+		prevTR = prevTR - (prevTR / float64(inTimePeriod)) + tempReal
+		prevClose = inClose[today]
+		if !(((-(0.00000000000001)) < prevTR) && (prevTR < (0.00000000000001))) {
+			outReal[outIdx] = (100.0 * (prevPlusDM / prevTR))
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	}
+
+	return outReal
+}
+
+// PlusDM - Plus Directional Movement
+func PlusDM(inHigh []float64, inLow []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+
+	lookbackTotal := 1
+	if inTimePeriod > 1 {
+		lookbackTotal = inTimePeriod - 1
+	}
+	startIdx := lookbackTotal
+	outIdx := startIdx
+	today := startIdx
+	prevHigh := 0.0
+	prevLow := 0.0
+	if inTimePeriod <= 1 {
+		today = startIdx - 1
+		prevHigh = inHigh[today]
+		prevLow = inLow[today]
+		for today < len(inHigh)-1 {
+			today++
+			tempReal := inHigh[today]
+			diffP := tempReal - prevHigh
+			prevHigh = tempReal
+			tempReal = inLow[today]
+			diffM := prevLow - tempReal
+			prevLow = tempReal
+			if (diffP > 0) && (diffP > diffM) {
+				outReal[outIdx] = diffP
+			} else {
+				outReal[outIdx] = 0
+			}
+			outIdx++
+		}
+		return outReal
+	}
+	prevPlusDM := 0.0
+	today = startIdx - lookbackTotal
+	prevHigh = inHigh[today]
+	prevLow = inLow[today]
+	i := inTimePeriod - 1
+	for i > 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM += diffP
+		}
+	}
+	i = 0
+	for i != 0 {
+		i--
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod)) + diffP
+		} else {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod))
+		}
+	}
+	outReal[startIdx] = prevPlusDM
+	outIdx = startIdx + 1
+	for today < len(inHigh)-1 {
+		today++
+		tempReal := inHigh[today]
+		diffP := tempReal - prevHigh
+		prevHigh = tempReal
+		tempReal = inLow[today]
+		diffM := prevLow - tempReal
+		prevLow = tempReal
+		if (diffP > 0) && (diffP > diffM) {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod)) + diffP
+		} else {
+			prevPlusDM = prevPlusDM - (prevPlusDM / float64(inTimePeriod))
+		}
+		outReal[outIdx] = prevPlusDM
+		outIdx++
+	}
+	return outReal
+}
+
+// Ppo - Percentage Price Oscillator
+func Ppo(inReal []float64, inFastPeriod int, inSlowPeriod int, inMAType MaType) []float64 {
+
+	if inSlowPeriod < inFastPeriod {
+		inSlowPeriod, inFastPeriod = inFastPeriod, inSlowPeriod
+	}
+	tempBuffer := Ma(inReal, inFastPeriod, inMAType)
+	outReal := Ma(inReal, inSlowPeriod, inMAType)
+
+	for i := inSlowPeriod - 1; i < len(inReal); i++ {
+		tempReal := outReal[i]
+		if !(((-(0.00000000000001)) < tempReal) && (tempReal < (0.00000000000001))) {
+			outReal[i] = ((tempBuffer[i] - tempReal) / tempReal) * 100.0
+		} else {
+			outReal[i] = 0.0
+		}
+	}
+
+	return outReal
+}
+
+// Rocp - Rate of change Percentage: (price-prevPrice)/prevPrice
+func Rocp(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 1 {
+		return outReal
+	}
+
+	startIdx := inTimePeriod
+	outIdx := startIdx
+	inIdx := startIdx
+	trailingIdx := startIdx - inTimePeriod
+	for inIdx < len(outReal) {
+		tempReal := inReal[trailingIdx]
+		if tempReal != 0.0 {
+			outReal[outIdx] = (inReal[inIdx] - tempReal) / tempReal
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		trailingIdx++
+		outIdx++
+		inIdx++
+	}
+
+	return outReal
+}
+
+// Roc - Rate of change : ((price/prevPrice)-1)*100
+func Roc(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	startIdx := inTimePeriod
+	outIdx := inTimePeriod
+	inIdx := startIdx
+	trailingIdx := startIdx - inTimePeriod
+
+	for inIdx < len(inReal) {
+		tempReal := inReal[trailingIdx]
+		if tempReal != 0.0 {
+			outReal[outIdx] = ((inReal[inIdx] / tempReal) - 1.0) * 100.0
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		trailingIdx++
+		outIdx++
+		inIdx++
+	}
+	return outReal
+}
+
+// Rocr - Rate of change ratio: (price/prevPrice)
+func Rocr(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	startIdx := inTimePeriod
+	outIdx := inTimePeriod
+	inIdx := startIdx
+	trailingIdx := startIdx - inTimePeriod
+
+	for inIdx < len(inReal) {
+		tempReal := inReal[trailingIdx]
+		if tempReal != 0.0 {
+			outReal[outIdx] = (inReal[inIdx] / tempReal)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		trailingIdx++
+		outIdx++
+		inIdx++
+	}
+	return outReal
+}
+
+// Rocr100 - Rate of change ratio 100 scale: (price/prevPrice)*100
+func Rocr100(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	startIdx := inTimePeriod
+	outIdx := inTimePeriod
+	inIdx := startIdx
+	trailingIdx := startIdx - inTimePeriod
+
+	for inIdx < len(inReal) {
+		tempReal := inReal[trailingIdx]
+		if tempReal != 0.0 {
+			outReal[outIdx] = (inReal[inIdx] / tempReal) * 100.0
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		trailingIdx++
+		outIdx++
+		inIdx++
+	}
+	return outReal
+}
+
+// Rsi - Relative strength index
+func Rsi(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 2 {
+		return outReal
+	}
+
+	// variable declarations
+	tempValue1 := 0.0
+	tempValue2 := 0.0
+	outIdx := inTimePeriod
+	today := 0
+	prevValue := inReal[today]
+	prevGain := 0.0
+	prevLoss := 0.0
+	today++
+
+	for i := inTimePeriod; i > 0; i-- {
+		tempValue1 = inReal[today]
+		today++
+		tempValue2 = tempValue1 - prevValue
+		prevValue = tempValue1
+		if tempValue2 < 0 {
+			prevLoss -= tempValue2
+		} else {
+			prevGain += tempValue2
+		}
+	}
+
+	prevLoss /= float64(inTimePeriod)
+	prevGain /= float64(inTimePeriod)
+
+	if today > 0 {
+
+		tempValue1 = prevGain + prevLoss
+		if !((-0.00000000000001 < tempValue1) && (tempValue1 < 0.00000000000001)) {
+			outReal[outIdx] = 100.0 * (prevGain / tempValue1)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+
+	} else {
+
+		for today < 0 {
+			tempValue1 = inReal[today]
+			tempValue2 = tempValue1 - prevValue
+			prevValue = tempValue1
+			prevLoss *= float64(inTimePeriod - 1)
+			prevGain *= float64(inTimePeriod - 1)
+			if tempValue2 < 0 {
+				prevLoss -= tempValue2
+			} else {
+				prevGain += tempValue2
+			}
+			prevLoss /= float64(inTimePeriod)
+			prevGain /= float64(inTimePeriod)
+			today++
+		}
+	}
+
+	for today < len(inReal) {
+
+		tempValue1 = inReal[today]
+		today++
+		tempValue2 = tempValue1 - prevValue
+		prevValue = tempValue1
+		prevLoss *= float64(inTimePeriod - 1)
+		prevGain *= float64(inTimePeriod - 1)
+		if tempValue2 < 0 {
+			prevLoss -= tempValue2
+		} else {
+			prevGain += tempValue2
+		}
+		prevLoss /= float64(inTimePeriod)
+		prevGain /= float64(inTimePeriod)
+		tempValue1 = prevGain + prevLoss
+		if !((-0.00000000000001 < tempValue1) && (tempValue1 < 0.00000000000001)) {
+			outReal[outIdx] = 100.0 * (prevGain / tempValue1)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	}
+
+	return outReal
+}
+
+// Stoch - Stochastic
+func Stoch(inHigh []float64, inLow []float64, inClose []float64, inFastKPeriod int, inSlowKPeriod int, inSlowKMAType MaType, inSlowDPeriod int, inSlowDMAType MaType) ([]float64, []float64) {
+
+	outSlowK := make([]float64, len(inClose))
+	outSlowD := make([]float64, len(inClose))
+
+	lookbackK := inFastKPeriod - 1
+	lookbackKSlow := inSlowKPeriod - 1
+	lookbackDSlow := inSlowDPeriod - 1
+	lookbackTotal := lookbackK + lookbackDSlow + lookbackKSlow
+	startIdx := lookbackTotal
+	outIdx := 0
+	trailingIdx := startIdx - lookbackTotal
+	today := trailingIdx + lookbackK
+	lowestIdx, highestIdx := -1, -1
+	diff, highest, lowest := 0.0, 0.0, 0.0
+	tempBuffer := make([]float64, len(inClose)-today+1)
+	for today < len(inClose) {
+		tmp := inLow[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inLow[lowestIdx]
+			i := lowestIdx + 1
+			for i <= today {
+
+				tmp := inLow[i]
+				if tmp < lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / 100.0
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+			diff = (highest - lowest) / 100.0
+		}
+		tmp = inHigh[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inHigh[highestIdx]
+			i := highestIdx + 1
+			for i <= today {
+				tmp := inHigh[i]
+				if tmp > highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / 100.0
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+			diff = (highest - lowest) / 100.0
+		}
+		if diff != 0.0 {
+			tempBuffer[outIdx] = (inClose[today] - lowest) / diff
+		} else {
+			tempBuffer[outIdx] = 0.0
+		}
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	tempBuffer1 := Ma(tempBuffer, inSlowKPeriod, inSlowKMAType)
+	tempBuffer2 := Ma(tempBuffer1, inSlowDPeriod, inSlowDMAType)
+	//for i, j := lookbackK, lookbackTotal; j < len(inClose); i, j = i+1, j+1 {
+	for i, j := lookbackDSlow+lookbackKSlow, lookbackTotal; j < len(inClose); i, j = i+1, j+1 {
+		outSlowK[j] = tempBuffer1[i]
+		outSlowD[j] = tempBuffer2[i]
+	}
+
+	return outSlowK, outSlowD
+}
+
+// StochF - Stochastic Fast
+func StochF(inHigh []float64, inLow []float64, inClose []float64, inFastKPeriod int, inFastDPeriod int, inFastDMAType MaType) ([]float64, []float64) {
+
+	outFastK := make([]float64, len(inClose))
+	outFastD := make([]float64, len(inClose))
+
+	lookbackK := inFastKPeriod - 1
+	lookbackFastD := inFastDPeriod - 1
+	lookbackTotal := lookbackK + lookbackFastD
+	startIdx := lookbackTotal
+	outIdx := 0
+	trailingIdx := startIdx - lookbackTotal
+	today := trailingIdx + lookbackK
+	lowestIdx, highestIdx := -1, -1
+	diff, highest, lowest := 0.0, 0.0, 0.0
+	tempBuffer := make([]float64, (len(inClose) - today + 1))
+
+	for today < len(inClose) {
+		tmp := inLow[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inLow[lowestIdx]
+			i := lowestIdx
+			i++
+			for i <= today {
+				tmp = inLow[i]
+				if tmp < lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / 100.0
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+			diff = (highest - lowest) / 100.0
+		}
+		tmp = inHigh[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inHigh[highestIdx]
+			i := highestIdx
+			i++
+			for i <= today {
+				tmp = inHigh[i]
+				if tmp > highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / 100.0
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+			diff = (highest - lowest) / 100.0
+		}
+		if diff != 0.0 {
+			tempBuffer[outIdx] = (inClose[today] - lowest) / diff
+
+		} else {
+			tempBuffer[outIdx] = 0.0
+		}
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	tempBuffer1 := Ma(tempBuffer, inFastDPeriod, inFastDMAType)
+	for i, j := lookbackFastD, lookbackTotal; j < len(inClose); i, j = i+1, j+1 {
+		outFastK[j] = tempBuffer[i]
+		outFastD[j] = tempBuffer1[i]
+	}
+
+	return outFastK, outFastD
+}
+
+// StochRsi - Stochastic Relative Strength Index
+func StochRsi(inReal []float64, inTimePeriod int, inFastKPeriod int, inFastDPeriod int, inFastDMAType MaType) ([]float64, []float64) {
+
+	outFastK := make([]float64, len(inReal))
+	outFastD := make([]float64, len(inReal))
+
+	lookbackSTOCHF := (inFastKPeriod - 1) + (inFastDPeriod - 1)
+	lookbackTotal := inTimePeriod + lookbackSTOCHF
+	startIdx := lookbackTotal
+	tempRSIBuffer := Rsi(inReal, inTimePeriod)
+	tempk, tempd := StochF(tempRSIBuffer, tempRSIBuffer, tempRSIBuffer, inFastKPeriod, inFastDPeriod, inFastDMAType)
+
+	for i := startIdx; i < len(inReal); i++ {
+		outFastK[i] = tempk[i]
+		outFastD[i] = tempd[i]
+	}
+
+	return outFastK, outFastD
+}
+
+// Trix - 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
+func Trix(inReal []float64, inTimePeriod int) []float64 {
+
+	tmpReal := Ema(inReal, inTimePeriod)
+	tmpReal = Ema(tmpReal[inTimePeriod-1:], inTimePeriod)
+	tmpReal = Ema(tmpReal[inTimePeriod-1:], inTimePeriod)
+	tmpReal = Roc(tmpReal, 1)
+
+	outReal := make([]float64, len(inReal))
+	for i, j := inTimePeriod, ((inTimePeriod-1)*3)+1; j < len(outReal); i, j = i+1, j+1 {
+		outReal[j] = tmpReal[i]
+	}
+
+	return outReal
+}
+
+// UltOsc - Ultimate Oscillator
+func UltOsc(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod1 int, inTimePeriod2 int, inTimePeriod3 int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	usedFlag := make([]int, 3)
+	periods := make([]int, 3)
+	sortedPeriods := make([]int, 3)
+
+	periods[0] = inTimePeriod1
+	periods[1] = inTimePeriod2
+	periods[2] = inTimePeriod3
+
+	for i := 0; i < 3; i++ {
+		longestPeriod := 0
+		longestIndex := 0
+		for j := 0; j < 3; j++ {
+			if (usedFlag[j] == 0) && (periods[j] > longestPeriod) {
+				longestPeriod = periods[j]
+				longestIndex = j
+			}
+		}
+		usedFlag[longestIndex] = 1
+		sortedPeriods[i] = longestPeriod
+	}
+	inTimePeriod1 = sortedPeriods[2]
+	inTimePeriod2 = sortedPeriods[1]
+	inTimePeriod3 = sortedPeriods[0]
+
+	lookbackTotal := 0
+	if inTimePeriod1 > inTimePeriod2 {
+		lookbackTotal = inTimePeriod1
+	}
+	if inTimePeriod3 > lookbackTotal {
+		lookbackTotal = inTimePeriod3
+	}
+	lookbackTotal++
+
+	startIdx := lookbackTotal - 1
+
+	a1Total := 0.0
+	b1Total := 0.0
+	for i := startIdx - inTimePeriod1 + 1; i < startIdx; i++ {
+
+		tempLT := inLow[i]
+		tempHT := inHigh[i]
+		tempCY := inClose[i-1]
+		trueLow := 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow := inClose[i] - trueLow
+		trueRange := tempHT - tempLT
+		tempDouble := math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a1Total += closeMinusTrueLow
+		b1Total += trueRange
+	}
+
+	a2Total := 0.0
+	b2Total := 0.0
+	for i := startIdx - inTimePeriod2 + 1; i < startIdx; i++ {
+
+		tempLT := inLow[i]
+		tempHT := inHigh[i]
+		tempCY := inClose[i-1]
+		trueLow := 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow := inClose[i] - trueLow
+		trueRange := tempHT - tempLT
+		tempDouble := math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a2Total += closeMinusTrueLow
+		b2Total += trueRange
+	}
+
+	a3Total := 0.0
+	b3Total := 0.0
+	for i := startIdx - inTimePeriod3 + 1; i < startIdx; i++ {
+
+		tempLT := inLow[i]
+		tempHT := inHigh[i]
+		tempCY := inClose[i-1]
+		trueLow := 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow := inClose[i] - trueLow
+		trueRange := tempHT - tempLT
+		tempDouble := math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a3Total += closeMinusTrueLow
+		b3Total += trueRange
+	}
+
+	//today := startIdx
+	//outIdx := startIdx
+	//trailingIdx1 := today - inTimePeriod1 + 1
+	//trailingIdx2 := today - inTimePeriod2 + 1
+	//trailingIdx3 := today - inTimePeriod3 + 1
+
+	today := startIdx
+	outIdx := startIdx
+	trailingIdx1 := today - inTimePeriod1 + 1
+	trailingIdx2 := today - inTimePeriod2 + 1
+	trailingIdx3 := today - inTimePeriod3 + 1
+
+	for today < len(inClose) {
+
+		tempLT := inLow[today]
+		tempHT := inHigh[today]
+		tempCY := inClose[today-1]
+		trueLow := 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow := inClose[today] - trueLow
+		trueRange := tempHT - tempLT
+		tempDouble := math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a1Total += closeMinusTrueLow
+		a2Total += closeMinusTrueLow
+		a3Total += closeMinusTrueLow
+		b1Total += trueRange
+		b2Total += trueRange
+		b3Total += trueRange
+		output := 0.0
+		if !(((-(0.00000000000001)) < b1Total) && (b1Total < (0.00000000000001))) {
+			output += 4.0 * (a1Total / b1Total)
+		}
+		if !(((-(0.00000000000001)) < b2Total) && (b2Total < (0.00000000000001))) {
+			output += 2.0 * (a2Total / b2Total)
+		}
+		if !(((-(0.00000000000001)) < b3Total) && (b3Total < (0.00000000000001))) {
+			output += a3Total / b3Total
+		}
+		tempLT = inLow[trailingIdx1]
+		tempHT = inHigh[trailingIdx1]
+		tempCY = inClose[trailingIdx1-1]
+		trueLow = 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow = inClose[trailingIdx1] - trueLow
+		trueRange = tempHT - tempLT
+		tempDouble = math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a1Total -= closeMinusTrueLow
+		b1Total -= trueRange
+		tempLT = inLow[trailingIdx2]
+		tempHT = inHigh[trailingIdx2]
+		tempCY = inClose[trailingIdx2-1]
+		trueLow = 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow = inClose[trailingIdx2] - trueLow
+		trueRange = tempHT - tempLT
+		tempDouble = math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a2Total -= closeMinusTrueLow
+		b2Total -= trueRange
+		tempLT = inLow[trailingIdx3]
+		tempHT = inHigh[trailingIdx3]
+		tempCY = inClose[trailingIdx3-1]
+		trueLow = 0.0
+		if tempLT < tempCY {
+			trueLow = tempLT
+		} else {
+			trueLow = tempCY
+		}
+		closeMinusTrueLow = inClose[trailingIdx3] - trueLow
+		trueRange = tempHT - tempLT
+		tempDouble = math.Abs(tempCY - tempHT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+		tempDouble = math.Abs(tempCY - tempLT)
+		if tempDouble > trueRange {
+			trueRange = tempDouble
+		}
+
+		a3Total -= closeMinusTrueLow
+		b3Total -= trueRange
+		outReal[outIdx] = 100.0 * (output / 7.0)
+		outIdx++
+		today++
+		trailingIdx1++
+		trailingIdx2++
+		trailingIdx3++
+	}
+	return outReal
+}
+
+// WillR - Williams' %R
+func WillR(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	nbInitialElementNeeded := (inTimePeriod - 1)
+	diff := 0.0
+	outIdx := inTimePeriod - 1
+	startIdx := inTimePeriod - 1
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	highestIdx := -1
+	lowestIdx := -1
+	highest := 0.0
+	lowest := 0.0
+	i := 0
+	for today < len(inClose) {
+		tmp := inLow[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inLow[lowestIdx]
+			i = lowestIdx
+			i++
+			for i <= today {
+				tmp = inLow[i]
+				if tmp < lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / (-100.0)
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+			diff = (highest - lowest) / (-100.0)
+		}
+		tmp = inHigh[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inHigh[highestIdx]
+			i = highestIdx
+			i++
+			for i <= today {
+				tmp = inHigh[i]
+				if tmp > highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+			diff = (highest - lowest) / (-100.0)
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+			diff = (highest - lowest) / (-100.0)
+		}
+		if diff != 0.0 {
+			outReal[outIdx] = (highest - inClose[today]) / diff
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+		trailingIdx++
+		today++
+	}
+	return outReal
+}
+
+/* Volume Indicators */
+
+// Ad - Chaikin A/D Line
+func Ad(inHigh []float64, inLow []float64, inClose []float64, inVolume []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	startIdx := 0
+	nbBar := len(inClose) - startIdx
+	currentBar := startIdx
+	outIdx := 0
+	ad := 0.0
+	for nbBar != 0 {
+		high := inHigh[currentBar]
+		low := inLow[currentBar]
+		tmp := high - low
+		close := inClose[currentBar]
+		if tmp > 0.0 {
+			ad += (((close - low) - (high - close)) / tmp) * (inVolume[currentBar])
+		}
+		outReal[outIdx] = ad
+		outIdx++
+		currentBar++
+		nbBar--
+	}
+	return outReal
+}
+
+// AdOsc - Chaikin A/D Oscillator
+func AdOsc(inHigh []float64, inLow []float64, inClose []float64, inVolume []float64, inFastPeriod int, inSlowPeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	if (inFastPeriod < 2) || (inSlowPeriod < 2) {
+		return outReal
+	}
+
+	slowestPeriod := 0
+	if inFastPeriod < inSlowPeriod {
+		slowestPeriod = inSlowPeriod
+	} else {
+		slowestPeriod = inFastPeriod
+	}
+	lookbackTotal := slowestPeriod - 1
+	startIdx := lookbackTotal
+	today := startIdx - lookbackTotal
+	ad := 0.0
+	fastk := (2.0 / (float64(inFastPeriod) + 1.0))
+	oneMinusfastk := 1.0 - fastk
+	slowk := (2.0 / (float64(inSlowPeriod) + 1.0))
+	oneMinusslowk := 1.0 - slowk
+	high := inHigh[today]
+	low := inLow[today]
+	tmp := high - low
+	close := inClose[today]
+	if tmp > 0.0 {
+		ad += (((close - low) - (high - close)) / tmp) * (inVolume[today])
+	}
+	today++
+	fastEMA := ad
+	slowEMA := ad
+
+	for today < startIdx {
+		high = inHigh[today]
+		low = inLow[today]
+		tmp = high - low
+		close = inClose[today]
+		if tmp > 0.0 {
+			ad += (((close - low) - (high - close)) / tmp) * (inVolume[today])
+		}
+		today++
+
+		fastEMA = (fastk * ad) + (oneMinusfastk * fastEMA)
+		slowEMA = (slowk * ad) + (oneMinusslowk * slowEMA)
+	}
+	outIdx := lookbackTotal
+	for today < len(inClose) {
+		high = inHigh[today]
+		low = inLow[today]
+		tmp = high - low
+		close = inClose[today]
+		if tmp > 0.0 {
+			ad += (((close - low) - (high - close)) / tmp) * (inVolume[today])
+		}
+		today++
+		fastEMA = (fastk * ad) + (oneMinusfastk * fastEMA)
+		slowEMA = (slowk * ad) + (oneMinusslowk * slowEMA)
+		outReal[outIdx] = fastEMA - slowEMA
+		outIdx++
+	}
+
+	return outReal
+}
+
+// Obv - On Balance Volume
+func Obv(inReal []float64, inVolume []float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	startIdx := 0
+	prevOBV := inVolume[startIdx]
+	prevReal := inReal[startIdx]
+	outIdx := 0
+	for i := startIdx; i < len(inReal); i++ {
+		tempReal := inReal[i]
+		if tempReal > prevReal {
+			prevOBV += inVolume[i]
+		} else if tempReal < prevReal {
+			prevOBV -= inVolume[i]
+		}
+		outReal[outIdx] = prevOBV
+		prevReal = tempReal
+		outIdx++
+	}
+	return outReal
+}
+
+/* Volatility Indicators */
+
+// Atr - Average True Range
+func Atr(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	inTimePeriodF := float64(inTimePeriod)
+
+	if inTimePeriod < 1 {
+		return outReal
+	}
+
+	if inTimePeriod <= 1 {
+		return TRange(inHigh, inLow, inClose)
+	}
+
+	outIdx := inTimePeriod
+	today := inTimePeriod + 1
+
+	tr := TRange(inHigh, inLow, inClose)
+	prevATRTemp := Sma(tr, inTimePeriod)
+	prevATR := prevATRTemp[inTimePeriod]
+	outReal[inTimePeriod] = prevATR
+
+	for outIdx = inTimePeriod + 1; outIdx < len(inClose); outIdx++ {
+		prevATR *= inTimePeriodF - 1.0
+		prevATR += tr[today]
+		prevATR /= inTimePeriodF
+		outReal[outIdx] = prevATR
+		today++
+	}
+
+	return outReal
+}
+
+// Natr - Normalized Average True Range
+func Natr(inHigh []float64, inLow []float64, inClose []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	if inTimePeriod < 1 {
+		return outReal
+	}
+
+	if inTimePeriod <= 1 {
+		return TRange(inHigh, inLow, inClose)
+	}
+
+	inTimePeriodF := float64(inTimePeriod)
+	outIdx := inTimePeriod
+	today := inTimePeriod
+
+	tr := TRange(inHigh, inLow, inClose)
+	prevATRTemp := Sma(tr, inTimePeriod)
+	prevATR := prevATRTemp[inTimePeriod]
+
+	tempValue := inClose[today]
+	if tempValue != 0.0 {
+		outReal[outIdx] = (prevATR / tempValue) * 100.0
+	} else {
+		outReal[outIdx] = 0.0
+	}
+
+	for outIdx = inTimePeriod + 1; outIdx < len(inClose); outIdx++ {
+		today++
+		prevATR *= inTimePeriodF - 1.0
+		prevATR += tr[today]
+		prevATR /= inTimePeriodF
+		tempValue = inClose[today]
+		if tempValue != 0.0 {
+			outReal[outIdx] = (prevATR / tempValue) * 100.0
+		} else {
+			outReal[0] = 0.0
+		}
+	}
+
+	return outReal
+}
+
+// TRange - True Range
+func TRange(inHigh []float64, inLow []float64, inClose []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+
+	startIdx := 1
+	outIdx := startIdx
+	today := startIdx
+	for today < len(inClose) {
+		tempLT := inLow[today]
+		tempHT := inHigh[today]
+		tempCY := inClose[today-1]
+		greatest := tempHT - tempLT
+		val2 := math.Abs(tempCY - tempHT)
+		if val2 > greatest {
+			greatest = val2
+		}
+		val3 := math.Abs(tempCY - tempLT)
+		if val3 > greatest {
+			greatest = val3
+		}
+		outReal[outIdx] = greatest
+		outIdx++
+		today++
+	}
+
+	return outReal
+}
+
+/* Price Transform */
+
+// AvgPrice - Average Price (o+h+l+c)/4
+func AvgPrice(inOpen []float64, inHigh []float64, inLow []float64, inClose []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	outIdx := 0
+	startIdx := 0
+
+	for i := startIdx; i < len(inClose); i++ {
+		outReal[outIdx] = (inHigh[i] + inLow[i] + inClose[i] + inOpen[i]) / 4
+		outIdx++
+	}
+	return outReal
+}
+
+// MedPrice - Median Price (h+l)/2
+func MedPrice(inHigh []float64, inLow []float64) []float64 {
+
+	outReal := make([]float64, len(inHigh))
+	outIdx := 0
+	startIdx := 0
+
+	for i := startIdx; i < len(inHigh); i++ {
+		outReal[outIdx] = (inHigh[i] + inLow[i]) / 2.0
+		outIdx++
+	}
+	return outReal
+}
+
+// TypPrice - Typical Price (h+l+c)/3
+func TypPrice(inHigh []float64, inLow []float64, inClose []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	outIdx := 0
+	startIdx := 0
+
+	for i := startIdx; i < len(inClose); i++ {
+		outReal[outIdx] = (inHigh[i] + inLow[i] + inClose[i]) / 3.0
+		outIdx++
+	}
+	return outReal
+}
+
+// WclPrice - Weighted Close Price
+func WclPrice(inHigh []float64, inLow []float64, inClose []float64) []float64 {
+
+	outReal := make([]float64, len(inClose))
+	outIdx := 0
+	startIdx := 0
+
+	for i := startIdx; i < len(inClose); i++ {
+		outReal[outIdx] = (inHigh[i] + inLow[i] + (inClose[i] * 2.0)) / 4.0
+		outIdx++
+	}
+	return outReal
+}
+
+/* Cycle Indicators */
+
+// HtDcPeriod - Hilbert Transform - Dominant Cycle Period (lookback=32)
+func HtDcPeriod(inReal []float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	rad2Deg := 180.0 / (4.0 * math.Atan(1))
+	lookbackTotal := 32
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal := inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 9
+	smoothedValue := 0.0
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 32
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i2 := 0.0
+	q2 := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	smoothPeriod := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		hilbertTempReal := 0.0
+		if (today % 2) == 0 {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		smoothPeriod = (0.33 * period) + (0.67 * smoothPeriod)
+		if today >= startIdx {
+			outReal[outIdx] = smoothPeriod
+			outIdx++
+		}
+		today++
+	}
+	return outReal
+}
+
+// HtDcPhase - Hilbert Transform - Dominant Cycle Phase (lookback=63)
+func HtDcPhase(inReal []float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	smoothPriceIdx := 0
+	maxIdxSmoothPrice := (50 - 1)
+	smoothPrice := make([]float64, maxIdxSmoothPrice+1)
+	tempReal := math.Atan(1)
+	rad2Deg := 45.0 / tempReal
+	constDeg2RadBy360 := tempReal * 8.0
+	lookbackTotal := 63
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal = inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 34
+	smoothedValue := 0.0
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 0
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	smoothPeriod := 0.0
+	dcPhase := 0.0
+	q2 := 0.0
+	i2 := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		hilbertTempReal := 0.0
+		smoothPrice[smoothPriceIdx] = smoothedValue
+		if (today % 2) == 0 {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		smoothPeriod = (0.33 * period) + (0.67 * smoothPeriod)
+		DCPeriod := smoothPeriod + 0.5
+		DCPeriodInt := math.Floor(DCPeriod)
+		realPart := 0.0
+		imagPart := 0.0
+		idx := smoothPriceIdx
+		for i := 0; i < int(DCPeriodInt); i++ {
+			tempReal = (float64(i) * constDeg2RadBy360) / (DCPeriodInt * 1.0)
+			tempReal2 = smoothPrice[idx]
+			realPart += math.Sin(tempReal) * tempReal2
+			imagPart += math.Cos(tempReal) * tempReal2
+			if idx == 0 {
+				idx = 50 - 1
+			} else {
+				idx--
+			}
+		}
+		tempReal = math.Abs(imagPart)
+		if tempReal > 0.0 {
+			dcPhase = math.Atan(realPart/imagPart) * rad2Deg
+		} else if tempReal <= 0.01 {
+			if realPart < 0.0 {
+				dcPhase -= 90.0
+			} else if realPart > 0.0 {
+				dcPhase += 90.0
+			}
+		}
+		dcPhase += 90.0
+		dcPhase += 360.0 / smoothPeriod
+		if imagPart < 0.0 {
+			dcPhase += 180.0
+		}
+		if dcPhase > 315.0 {
+			dcPhase -= 360.0
+		}
+		if today >= startIdx {
+			outReal[outIdx] = dcPhase
+			outIdx++
+		}
+		smoothPriceIdx++
+		if smoothPriceIdx > maxIdxSmoothPrice {
+			smoothPriceIdx = 0
+		}
+
+		today++
+	}
+	return outReal
+}
+
+// HtPhasor - Hibert Transform - Phasor Components (lookback=32)
+func HtPhasor(inReal []float64) ([]float64, []float64) {
+
+	outInPhase := make([]float64, len(inReal))
+	outQuadrature := make([]float64, len(inReal))
+
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	rad2Deg := 180.0 / (4.0 * math.Atan(1))
+	lookbackTotal := 32
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal := inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 9
+	smoothedValue := 0.0
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 32
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	i2 := 0.0
+	q2 := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		hilbertTempReal := 0.0
+		if (today % 2) == 0 {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+
+			if today >= startIdx {
+				outQuadrature[outIdx] = q1
+				outInPhase[outIdx] = i1ForEvenPrev3
+				outIdx++
+			}
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			if today >= startIdx {
+				outQuadrature[outIdx] = q1
+				outInPhase[outIdx] = i1ForOddPrev3
+				outIdx++
+			}
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		today++
+	}
+	return outInPhase, outQuadrature
+}
+
+// HtSine - Hilbert Transform - SineWave (lookback=63)
+func HtSine(inReal []float64) ([]float64, []float64) {
+
+	outSine := make([]float64, len(inReal))
+	outLeadSine := make([]float64, len(inReal))
+
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	smoothPriceIdx := 0
+	maxIdxSmoothPrice := (50 - 1)
+	smoothPrice := make([]float64, maxIdxSmoothPrice+1)
+	tempReal := math.Atan(1)
+	rad2Deg := 45.0 / tempReal
+	deg2Rad := 1.0 / rad2Deg
+	constDeg2RadBy360 := tempReal * 8.0
+	lookbackTotal := 63
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal = inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 34
+	smoothedValue := 0.0
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 63
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	smoothPeriod := 0.0
+	dcPhase := 0.0
+	hilbertTempReal := 0.0
+	q2 := 0.0
+	i2 := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		smoothPrice[smoothPriceIdx] = smoothedValue
+		if (today % 2) == 0 {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		smoothPeriod = (0.33 * period) + (0.67 * smoothPeriod)
+		DCPeriod := smoothPeriod + 0.5
+		DCPeriodInt := math.Floor(DCPeriod)
+		realPart := 0.0
+		imagPart := 0.0
+		idx := smoothPriceIdx
+		for i := 0; i < int(DCPeriodInt); i++ {
+			tempReal = (float64(i) * constDeg2RadBy360) / (DCPeriodInt * 1.0)
+			tempReal2 = smoothPrice[idx]
+			realPart += math.Sin(tempReal) * tempReal2
+			imagPart += math.Cos(tempReal) * tempReal2
+			if idx == 0 {
+				idx = 50 - 1
+			} else {
+				idx--
+			}
+		}
+		tempReal = math.Abs(imagPart)
+		if tempReal > 0.0 {
+			dcPhase = math.Atan(realPart/imagPart) * rad2Deg
+		} else if tempReal <= 0.01 {
+			if realPart < 0.0 {
+				dcPhase -= 90.0
+			} else if realPart > 0.0 {
+				dcPhase += 90.0
+			}
+		}
+		dcPhase += 90.0
+		dcPhase += 360.0 / smoothPeriod
+		if imagPart < 0.0 {
+			dcPhase += 180.0
+		}
+		if dcPhase > 315.0 {
+			dcPhase -= 360.0
+		}
+		if today >= startIdx {
+			outSine[outIdx] = math.Sin(dcPhase * deg2Rad)
+			outLeadSine[outIdx] = math.Sin((dcPhase + 45) * deg2Rad)
+			outIdx++
+		}
+		smoothPriceIdx++
+		if smoothPriceIdx > maxIdxSmoothPrice {
+			smoothPriceIdx = 0
+		}
+
+		today++
+	}
+	return outSine, outLeadSine
+}
+
+// HtTrendMode - Hilbert Transform - Trend vs Cycle Mode (lookback=63)
+func HtTrendMode(inReal []float64) []float64 {
+
+	outReal := make([]float64, len(inReal))
+	a := 0.0962
+	b := 0.5769
+	detrenderOdd := make([]float64, 3)
+	detrenderEven := make([]float64, 3)
+	q1Odd := make([]float64, 3)
+	q1Even := make([]float64, 3)
+	jIOdd := make([]float64, 3)
+	jIEven := make([]float64, 3)
+	jQOdd := make([]float64, 3)
+	jQEven := make([]float64, 3)
+	smoothPriceIdx := 0
+	maxIdxSmoothPrice := (50 - 1)
+	smoothPrice := make([]float64, maxIdxSmoothPrice+1)
+	iTrend1 := 0.0
+	iTrend2 := 0.0
+	iTrend3 := 0.0
+	daysInTrend := 0
+	prevdcPhase := 0.0
+	dcPhase := 0.0
+	prevSine := 0.0
+	sine := 0.0
+	prevLeadSine := 0.0
+	leadSine := 0.0
+	tempReal := math.Atan(1)
+	rad2Deg := 45.0 / tempReal
+	deg2Rad := 1.0 / rad2Deg
+	constDeg2RadBy360 := tempReal * 8.0
+	lookbackTotal := 63
+	startIdx := lookbackTotal
+	trailingWMAIdx := startIdx - lookbackTotal
+	today := trailingWMAIdx
+	tempReal = inReal[today]
+	today++
+	periodWMASub := tempReal
+	periodWMASum := tempReal
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 2.0
+	tempReal = inReal[today]
+	today++
+	periodWMASub += tempReal
+	periodWMASum += tempReal * 3.0
+	trailingWMAValue := 0.0
+	i := 34
+
+	for ok := true; ok; {
+		tempReal = inReal[today]
+		today++
+		periodWMASub += tempReal
+		periodWMASub -= trailingWMAValue
+		periodWMASum += tempReal * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		//smoothedValue := periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+		i--
+		ok = i != 0
+	}
+
+	hilbertIdx := 0
+	detrender := 0.0
+	prevDetrenderOdd := 0.0
+	prevDetrenderEven := 0.0
+	prevDetrenderInputOdd := 0.0
+	prevDetrenderInputEven := 0.0
+	q1 := 0.0
+	prevq1Odd := 0.0
+	prevq1Even := 0.0
+	prevq1InputOdd := 0.0
+	prevq1InputEven := 0.0
+	jI := 0.0
+	prevJIOdd := 0.0
+	prevJIEven := 0.0
+	prevJIInputOdd := 0.0
+	prevJIInputEven := 0.0
+	jQ := 0.0
+	prevJQOdd := 0.0
+	prevJQEven := 0.0
+	prevJQInputOdd := 0.0
+	prevJQInputEven := 0.0
+	period := 0.0
+	outIdx := 63
+	previ2 := 0.0
+	prevq2 := 0.0
+	Re := 0.0
+	Im := 0.0
+	i1ForOddPrev3 := 0.0
+	i1ForEvenPrev3 := 0.0
+	i1ForOddPrev2 := 0.0
+	i1ForEvenPrev2 := 0.0
+	smoothPeriod := 0.0
+	dcPhase = 0.0
+	smoothedValue := 0.0
+	hilbertTempReal := 0.0
+	q2 := 0.0
+	i2 := 0.0
+	for today < len(inReal) {
+		adjustedPrevPeriod := (0.075 * period) + 0.54
+		todayValue := inReal[today]
+		periodWMASub += todayValue
+		periodWMASub -= trailingWMAValue
+		periodWMASum += todayValue * 4.0
+		trailingWMAValue = inReal[trailingWMAIdx]
+		trailingWMAIdx++
+		smoothedValue = periodWMASum * 0.1
+		periodWMASum -= periodWMASub
+
+		smoothPrice[smoothPriceIdx] = smoothedValue
+		if (today % 2) == 0 {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderEven[hilbertIdx]
+			detrenderEven[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderEven
+			prevDetrenderEven = b * prevDetrenderInputEven
+			detrender += prevDetrenderEven
+			prevDetrenderInputEven = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Even[hilbertIdx]
+			q1Even[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Even
+			prevq1Even = b * prevq1InputEven
+			q1 += prevq1Even
+			prevq1InputEven = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForEvenPrev3
+			jI = -jIEven[hilbertIdx]
+			jIEven[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIEven
+			prevJIEven = b * prevJIInputEven
+			jI += prevJIEven
+			prevJIInputEven = i1ForEvenPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQEven[hilbertIdx]
+			jQEven[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQEven
+			prevJQEven = b * prevJQInputEven
+			jQ += prevJQEven
+			prevJQInputEven = q1
+			jQ *= adjustedPrevPeriod
+			hilbertIdx++
+			if hilbertIdx == 3 {
+				hilbertIdx = 0
+			}
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForEvenPrev3 - jQ)) + (0.8 * previ2)
+			i1ForOddPrev3 = i1ForOddPrev2
+			i1ForOddPrev2 = detrender
+		} else {
+			hilbertTempReal = a * smoothedValue
+			detrender = -detrenderOdd[hilbertIdx]
+			detrenderOdd[hilbertIdx] = hilbertTempReal
+			detrender += hilbertTempReal
+			detrender -= prevDetrenderOdd
+			prevDetrenderOdd = b * prevDetrenderInputOdd
+			detrender += prevDetrenderOdd
+			prevDetrenderInputOdd = smoothedValue
+			detrender *= adjustedPrevPeriod
+			hilbertTempReal = a * detrender
+			q1 = -q1Odd[hilbertIdx]
+			q1Odd[hilbertIdx] = hilbertTempReal
+			q1 += hilbertTempReal
+			q1 -= prevq1Odd
+			prevq1Odd = b * prevq1InputOdd
+			q1 += prevq1Odd
+			prevq1InputOdd = detrender
+			q1 *= adjustedPrevPeriod
+			hilbertTempReal = a * i1ForOddPrev3
+			jI = -jIOdd[hilbertIdx]
+			jIOdd[hilbertIdx] = hilbertTempReal
+			jI += hilbertTempReal
+			jI -= prevJIOdd
+			prevJIOdd = b * prevJIInputOdd
+			jI += prevJIOdd
+			prevJIInputOdd = i1ForOddPrev3
+			jI *= adjustedPrevPeriod
+			hilbertTempReal = a * q1
+			jQ = -jQOdd[hilbertIdx]
+			jQOdd[hilbertIdx] = hilbertTempReal
+			jQ += hilbertTempReal
+			jQ -= prevJQOdd
+			prevJQOdd = b * prevJQInputOdd
+			jQ += prevJQOdd
+			prevJQInputOdd = q1
+			jQ *= adjustedPrevPeriod
+			q2 = (0.2 * (q1 + jI)) + (0.8 * prevq2)
+			i2 = (0.2 * (i1ForOddPrev3 - jQ)) + (0.8 * previ2)
+			i1ForEvenPrev3 = i1ForEvenPrev2
+			i1ForEvenPrev2 = detrender
+		}
+		Re = (0.2 * ((i2 * previ2) + (q2 * prevq2))) + (0.8 * Re)
+		Im = (0.2 * ((i2 * prevq2) - (q2 * previ2))) + (0.8 * Im)
+		prevq2 = q2
+		previ2 = i2
+		tempReal = period
+		if (Im != 0.0) && (Re != 0.0) {
+			period = 360.0 / (math.Atan(Im/Re) * rad2Deg)
+		}
+		tempReal2 := 1.5 * tempReal
+		if period > tempReal2 {
+			period = tempReal2
+		}
+		tempReal2 = 0.67 * tempReal
+		if period < tempReal2 {
+			period = tempReal2
+		}
+		if period < 6 {
+			period = 6
+		} else if period > 50 {
+			period = 50
+		}
+		period = (0.2 * period) + (0.8 * tempReal)
+		smoothPeriod = (0.33 * period) + (0.67 * smoothPeriod)
+		prevdcPhase = dcPhase
+		DCPeriod := smoothPeriod + 0.5
+		DCPeriodInt := math.Floor(DCPeriod)
+		realPart := 0.0
+		imagPart := 0.0
+		idx := smoothPriceIdx
+		for i := 0; i < int(DCPeriodInt); i++ {
+			tempReal = (float64(i) * constDeg2RadBy360) / (DCPeriodInt * 1.0)
+			tempReal2 = smoothPrice[idx]
+			realPart += math.Sin(tempReal) * tempReal2
+			imagPart += math.Cos(tempReal) * tempReal2
+			if idx == 0 {
+				idx = 50 - 1
+			} else {
+				idx--
+			}
+		}
+		tempReal = math.Abs(imagPart)
+		if tempReal > 0.0 {
+			dcPhase = math.Atan(realPart/imagPart) * rad2Deg
+		} else if tempReal <= 0.01 {
+			if realPart < 0.0 {
+				dcPhase -= 90.0
+			} else if realPart > 0.0 {
+				dcPhase += 90.0
+			}
+		}
+		dcPhase += 90.0
+		dcPhase += 360.0 / smoothPeriod
+		if imagPart < 0.0 {
+			dcPhase += 180.0
+		}
+		if dcPhase > 315.0 {
+			dcPhase -= 360.0
+		}
+		prevSine = sine
+		prevLeadSine = leadSine
+		sine = math.Sin(dcPhase * deg2Rad)
+		leadSine = math.Sin((dcPhase + 45) * deg2Rad)
+		DCPeriod = smoothPeriod + 0.5
+		DCPeriodInt = math.Floor(DCPeriod)
+		idx = today
+		tempReal = 0.0
+		for i := 0; i < int(DCPeriodInt); i++ {
+			tempReal += inReal[idx]
+			idx--
+		}
+		if DCPeriodInt > 0 {
+			tempReal = tempReal / (DCPeriodInt * 1.0)
+		}
+		trendline := (4.0*tempReal + 3.0*iTrend1 + 2.0*iTrend2 + iTrend3) / 10.0
+		iTrend3 = iTrend2
+		iTrend2 = iTrend1
+		iTrend1 = tempReal
+		trend := 1
+		if ((sine > leadSine) && (prevSine <= prevLeadSine)) || ((sine < leadSine) && (prevSine >= prevLeadSine)) {
+			daysInTrend = 0
+			trend = 0
+		}
+		daysInTrend++
+		if float64(daysInTrend) < (0.5 * smoothPeriod) {
+			trend = 0
+		}
+		tempReal = dcPhase - prevdcPhase
+		if (smoothPeriod != 0.0) && ((tempReal > (0.67 * 360.0 / smoothPeriod)) && (tempReal < (1.5 * 360.0 / smoothPeriod))) {
+			trend = 0
+		}
+		tempReal = smoothPrice[smoothPriceIdx]
+		if (trendline != 0.0) && (math.Abs((tempReal-trendline)/trendline) >= 0.015) {
+			trend = 1
+		}
+		if today >= startIdx {
+			outReal[outIdx] = float64(trend)
+			outIdx++
+		}
+		smoothPriceIdx++
+		if smoothPriceIdx > maxIdxSmoothPrice {
+			smoothPriceIdx = 0
+		}
+
+		today++
+	}
+	return outReal
+}
+
+/* Statistic Functions */
+
+// Beta - Beta
+func Beta(inReal0 []float64, inReal1 []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal0))
+
+	x := 0.0
+	y := 0.0
+	sSS := 0.0
+	sXY := 0.0
+	sX := 0.0
+	sY := 0.0
+	tmpReal := 0.0
+	n := 0.0
+	nbInitialElementNeeded := inTimePeriod
+	startIdx := nbInitialElementNeeded
+	trailingIdx := startIdx - nbInitialElementNeeded
+	trailingLastPriceX := inReal0[trailingIdx]
+	lastPriceX := trailingLastPriceX
+	trailingLastPriceY := inReal1[trailingIdx]
+	lastPriceY := trailingLastPriceY
+	trailingIdx++
+	i := trailingIdx
+	for i < startIdx {
+		tmpReal := inReal0[i]
+		x := 0.0
+		if !((-0.00000000000001 < lastPriceX) && (lastPriceX < 0.00000000000001)) {
+			x = (tmpReal - lastPriceX) / lastPriceX
+		}
+		lastPriceX = tmpReal
+		tmpReal = inReal1[i]
+		i++
+		y := 0.0
+		if !((-0.00000000000001 < lastPriceY) && (lastPriceY < 0.00000000000001)) {
+			y = (tmpReal - lastPriceY) / lastPriceY
+		}
+		lastPriceY = tmpReal
+		sSS += x * x
+		sXY += x * y
+		sX += x
+		sY += y
+	}
+	outIdx := inTimePeriod
+	n = float64(inTimePeriod)
+	for ok := true; ok; {
+		tmpReal = inReal0[i]
+		if !((-0.00000000000001 < lastPriceX) && (lastPriceX < 0.00000000000001)) {
+			x = (tmpReal - lastPriceX) / lastPriceX
+		} else {
+			x = 0.0
+		}
+		lastPriceX = tmpReal
+		tmpReal = inReal1[i]
+		i++
+		if !((-0.00000000000001 < lastPriceY) && (lastPriceY < 0.00000000000001)) {
+			y = (tmpReal - lastPriceY) / lastPriceY
+		} else {
+			y = 0.0
+		}
+		lastPriceY = tmpReal
+		sSS += x * x
+		sXY += x * y
+		sX += x
+		sY += y
+		tmpReal = inReal0[trailingIdx]
+		if !(((-(0.00000000000001)) < trailingLastPriceX) && (trailingLastPriceX < (0.00000000000001))) {
+			x = (tmpReal - trailingLastPriceX) / trailingLastPriceX
+		} else {
+			x = 0.0
+		}
+		trailingLastPriceX = tmpReal
+		tmpReal = inReal1[trailingIdx]
+		trailingIdx++
+		if !(((-(0.00000000000001)) < trailingLastPriceY) && (trailingLastPriceY < (0.00000000000001))) {
+			y = (tmpReal - trailingLastPriceY) / trailingLastPriceY
+		} else {
+			y = 0.0
+		}
+		trailingLastPriceY = tmpReal
+		tmpReal = (n * sSS) - (sX * sX)
+		if !(((-(0.00000000000001)) < tmpReal) && (tmpReal < (0.00000000000001))) {
+			outReal[outIdx] = ((n * sXY) - (sX * sY)) / tmpReal
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+		sSS -= x * x
+		sXY -= x * y
+		sX -= x
+		sY -= y
+		ok = i < len(inReal0)
+	}
+
+	return outReal
+}
+
+// Correl - Pearson's Correlation Coefficient (r)
+func Correl(inReal0 []float64, inReal1 []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal0))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	trailingIdx := startIdx - lookbackTotal
+	sumXY, sumX, sumY, sumX2, sumY2 := 0.0, 0.0, 0.0, 0.0, 0.0
+	today := trailingIdx
+	for today = trailingIdx; today <= startIdx; today++ {
+		x := inReal0[today]
+		sumX += x
+		sumX2 += x * x
+		y := inReal1[today]
+		sumXY += x * y
+		sumY += y
+		sumY2 += y * y
+	}
+	trailingX := inReal0[trailingIdx]
+	trailingY := inReal1[trailingIdx]
+	trailingIdx++
+	tempReal := (sumX2 - ((sumX * sumX) / inTimePeriodF)) * (sumY2 - ((sumY * sumY) / inTimePeriodF))
+	if !(tempReal < 0.00000000000001) {
+		outReal[inTimePeriod-1] = (sumXY - ((sumX * sumY) / inTimePeriodF)) / math.Sqrt(tempReal)
+	} else {
+		outReal[inTimePeriod-1] = 0.0
+	}
+	outIdx := inTimePeriod
+	for today < len(inReal0) {
+		sumX -= trailingX
+		sumX2 -= trailingX * trailingX
+		sumXY -= trailingX * trailingY
+		sumY -= trailingY
+		sumY2 -= trailingY * trailingY
+		x := inReal0[today]
+		sumX += x
+		sumX2 += x * x
+		y := inReal1[today]
+		today++
+		sumXY += x * y
+		sumY += y
+		sumY2 += y * y
+		trailingX = inReal0[trailingIdx]
+		trailingY = inReal1[trailingIdx]
+		trailingIdx++
+		tempReal = (sumX2 - ((sumX * sumX) / inTimePeriodF)) * (sumY2 - ((sumY * sumY) / inTimePeriodF))
+		if !(tempReal < (0.00000000000001)) {
+			outReal[outIdx] = (sumXY - ((sumX * sumY) / inTimePeriodF)) / math.Sqrt(tempReal)
+		} else {
+			outReal[outIdx] = 0.0
+		}
+		outIdx++
+	}
+	return outReal
+}
+
+// LinearReg - Linear Regression
+func LinearReg(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx - 1
+	today := startIdx - 1
+	sumX := inTimePeriodF * (inTimePeriodF - 1) * 0.5
+	sumXSqr := inTimePeriodF * (inTimePeriodF - 1) * (2*inTimePeriodF - 1) / 6
+	divisor := sumX*sumX - inTimePeriodF*sumXSqr
+	//initialize values of sumY and sumXY over first (inTimePeriod) input values
+	sumXY := 0.0
+	sumY := 0.0
+	i := inTimePeriod
+	for i != 0 {
+		i--
+		tempValue1 := inReal[today-i]
+		sumY += tempValue1
+		sumXY += float64(i) * tempValue1
+	}
+	for today < len(inReal) {
+		//sumX and sumXY are already available for first output value
+		if today > startIdx-1 {
+			tempValue2 := inReal[today-inTimePeriod]
+			sumXY += sumY - inTimePeriodF*tempValue2
+			sumY += inReal[today] - tempValue2
+		}
+		m := (inTimePeriodF*sumXY - sumX*sumY) / divisor
+		b := (sumY - m*sumX) / inTimePeriodF
+		outReal[outIdx] = b + m*(inTimePeriodF-1)
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// LinearRegAngle - Linear Regression Angle
+func LinearRegAngle(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx - 1
+	today := startIdx - 1
+	sumX := inTimePeriodF * (inTimePeriodF - 1) * 0.5
+	sumXSqr := inTimePeriodF * (inTimePeriodF - 1) * (2*inTimePeriodF - 1) / 6
+	divisor := sumX*sumX - inTimePeriodF*sumXSqr
+	//initialize values of sumY and sumXY over first (inTimePeriod) input values
+	sumXY := 0.0
+	sumY := 0.0
+	i := inTimePeriod
+	for i != 0 {
+		i--
+		tempValue1 := inReal[today-i]
+		sumY += tempValue1
+		sumXY += float64(i) * tempValue1
+	}
+	for today < len(inReal) {
+		//sumX and sumXY are already available for first output value
+		if today > startIdx-1 {
+			tempValue2 := inReal[today-inTimePeriod]
+			sumXY += sumY - inTimePeriodF*tempValue2
+			sumY += inReal[today] - tempValue2
+		}
+		m := (inTimePeriodF*sumXY - sumX*sumY) / divisor
+		outReal[outIdx] = math.Atan(m) * (180.0 / math.Pi)
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// LinearRegIntercept - Linear Regression Intercept
+func LinearRegIntercept(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx - 1
+	today := startIdx - 1
+	sumX := inTimePeriodF * (inTimePeriodF - 1) * 0.5
+	sumXSqr := inTimePeriodF * (inTimePeriodF - 1) * (2*inTimePeriodF - 1) / 6
+	divisor := sumX*sumX - inTimePeriodF*sumXSqr
+	//initialize values of sumY and sumXY over first (inTimePeriod) input values
+	sumXY := 0.0
+	sumY := 0.0
+	i := inTimePeriod
+	for i != 0 {
+		i--
+		tempValue1 := inReal[today-i]
+		sumY += tempValue1
+		sumXY += float64(i) * tempValue1
+	}
+	for today < len(inReal) {
+		//sumX and sumXY are already available for first output value
+		if today > startIdx-1 {
+			tempValue2 := inReal[today-inTimePeriod]
+			sumXY += sumY - inTimePeriodF*tempValue2
+			sumY += inReal[today] - tempValue2
+		}
+		m := (inTimePeriodF*sumXY - sumX*sumY) / divisor
+		outReal[outIdx] = (sumY - m*sumX) / inTimePeriodF
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// LinearRegSlope - Linear Regression Slope
+func LinearRegSlope(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx - 1
+	today := startIdx - 1
+	sumX := inTimePeriodF * (inTimePeriodF - 1) * 0.5
+	sumXSqr := inTimePeriodF * (inTimePeriodF - 1) * (2*inTimePeriodF - 1) / 6
+	divisor := sumX*sumX - inTimePeriodF*sumXSqr
+	//initialize values of sumY and sumXY over first (inTimePeriod) input values
+	sumXY := 0.0
+	sumY := 0.0
+	i := inTimePeriod
+	for i != 0 {
+		i--
+		tempValue1 := inReal[today-i]
+		sumY += tempValue1
+		sumXY += float64(i) * tempValue1
+	}
+	for today < len(inReal) {
+		//sumX and sumXY are already available for first output value
+		if today > startIdx-1 {
+			tempValue2 := inReal[today-inTimePeriod]
+			sumXY += sumY - inTimePeriodF*tempValue2
+			sumY += inReal[today] - tempValue2
+		}
+		outReal[outIdx] = (inTimePeriodF*sumXY - sumX*sumY) / divisor
+		outIdx++
+		today++
+	}
+	return outReal
+}
+
+// StdDev - Standard Deviation
+func StdDev(inReal []float64, inTimePeriod int, inNbDev float64) []float64 {
+
+	outReal := Var(inReal, inTimePeriod)
+
+	if inNbDev != 1.0 {
+		for i := 0; i < len(inReal); i++ {
+			tempReal := outReal[i]
+			if !(tempReal < 0.00000000000001) {
+				outReal[i] = math.Sqrt(tempReal) * inNbDev
+			} else {
+				outReal[i] = 0.0
+			}
+		}
+	} else {
+		for i := 0; i < len(inReal); i++ {
+			tempReal := outReal[i]
+			if !(tempReal < 0.00000000000001) {
+				outReal[i] = math.Sqrt(tempReal)
+			} else {
+				outReal[i] = 0.0
+			}
+		}
+	}
+	return outReal
+}
+
+// Tsf - Time Series Forecast
+func Tsf(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	inTimePeriodF := float64(inTimePeriod)
+	lookbackTotal := inTimePeriod
+	startIdx := lookbackTotal
+	outIdx := startIdx - 1
+	today := startIdx - 1
+	sumX := inTimePeriodF * (inTimePeriodF - 1.0) * 0.5
+	sumXSqr := inTimePeriodF * (inTimePeriodF - 1) * (2*inTimePeriodF - 1) / 6
+	divisor := sumX*sumX - inTimePeriodF*sumXSqr
+	//initialize values of sumY and sumXY over first (inTimePeriod) input values
+	sumXY := 0.0
+	sumY := 0.0
+	i := inTimePeriod
+	for i != 0 {
+		i--
+		tempValue1 := inReal[today-i]
+		sumY += tempValue1
+		sumXY += float64(i) * tempValue1
+	}
+	for today < len(inReal) {
+		//sumX and sumXY are already available for first output value
+		if today > startIdx-1 {
+			tempValue2 := inReal[today-inTimePeriod]
+			sumXY += sumY - inTimePeriodF*tempValue2
+			sumY += inReal[today] - tempValue2
+		}
+		m := (inTimePeriodF*sumXY - sumX*sumY) / divisor
+		b := (sumY - m*sumX) / inTimePeriodF
+		outReal[outIdx] = b + m*inTimePeriodF
+		today++
+		outIdx++
+	}
+	return outReal
+}
+
+// Var - Variance
+func Var(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	periodTotal1 := 0.0
+	periodTotal2 := 0.0
+	trailingIdx := startIdx - nbInitialElementNeeded
+	i := trailingIdx
+	if inTimePeriod > 1 {
+		for i < startIdx {
+			tempReal := inReal[i]
+			periodTotal1 += tempReal
+			tempReal *= tempReal
+			periodTotal2 += tempReal
+			i++
+		}
+	}
+	outIdx := startIdx
+	for ok := true; ok; {
+		tempReal := inReal[i]
+		periodTotal1 += tempReal
+		tempReal *= tempReal
+		periodTotal2 += tempReal
+		meanValue1 := periodTotal1 / float64(inTimePeriod)
+		meanValue2 := periodTotal2 / float64(inTimePeriod)
+		tempReal = inReal[trailingIdx]
+		periodTotal1 -= tempReal
+		tempReal *= tempReal
+		periodTotal2 -= tempReal
+		outReal[outIdx] = meanValue2 - meanValue1*meanValue1
+		i++
+		trailingIdx++
+		outIdx++
+		ok = i < len(inReal)
+	}
+	return outReal
+}
+
+/* Math Transform Functions */
+
+// Acos - Vector Trigonometric ACOS
+func Acos(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Acos(inReal[i])
+	}
+	return outReal
+}
+
+// Asin - Vector Trigonometric ASIN
+func Asin(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Asin(inReal[i])
+	}
+	return outReal
+}
+
+// Atan - Vector Trigonometric ATAN
+func Atan(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Atan(inReal[i])
+	}
+	return outReal
+}
+
+// Ceil - Vector CEIL
+func Ceil(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Ceil(inReal[i])
+	}
+	return outReal
+}
+
+// Cos - Vector Trigonometric COS
+func Cos(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Cos(inReal[i])
+	}
+	return outReal
+}
+
+// Cosh - Vector Trigonometric COSH
+func Cosh(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Cosh(inReal[i])
+	}
+	return outReal
+}
+
+// Exp - Vector atrithmetic EXP
+func Exp(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Exp(inReal[i])
+	}
+	return outReal
+}
+
+// Floor - Vector FLOOR
+func Floor(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Floor(inReal[i])
+	}
+	return outReal
+}
+
+// Ln - Vector natural log LN
+func Ln(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Log(inReal[i])
+	}
+	return outReal
+}
+
+// Log10 - Vector LOG10
+func Log10(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Log10(inReal[i])
+	}
+	return outReal
+}
+
+// Sin - Vector Trigonometric SIN
+func Sin(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Sin(inReal[i])
+	}
+	return outReal
+}
+
+// Sinh - Vector Trigonometric SINH
+func Sinh(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Sinh(inReal[i])
+	}
+	return outReal
+}
+
+// Sqrt - Vector SQRT
+func Sqrt(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Sqrt(inReal[i])
+	}
+	return outReal
+}
+
+// Tan - Vector Trigonometric TAN
+func Tan(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Tan(inReal[i])
+	}
+	return outReal
+}
+
+// Tanh - Vector Trigonometric TANH
+func Tanh(inReal []float64) []float64 {
+	outReal := make([]float64, len(inReal))
+	for i := 0; i < len(inReal); i++ {
+		outReal[i] = math.Tanh(inReal[i])
+	}
+	return outReal
+}
+
+/* Math Operator Functions */
+
+// Add - Vector arithmetic addition
+func Add(inReal0 []float64, inReal1 []float64) []float64 {
+	outReal := make([]float64, len(inReal0))
+	for i := 0; i < len(inReal0); i++ {
+		outReal[i] = inReal0[i] + inReal1[i]
+	}
+	return outReal
+}
+
+// Div - Vector arithmetic division
+func Div(inReal0 []float64, inReal1 []float64) []float64 {
+	outReal := make([]float64, len(inReal0))
+	for i := 0; i < len(inReal0); i++ {
+		outReal[i] = inReal0[i] / inReal1[i]
+	}
+	return outReal
+}
+
+// Max - Highest value over a period
+func Max(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 2 {
+		return outReal
+	}
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	highestIdx := -1
+	highest := 0.0
+
+	for today < len(outReal) {
+
+		tmp := inReal[today]
+
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inReal[highestIdx]
+			i := highestIdx + 1
+			for i <= today {
+				tmp = inReal[i]
+				if tmp > highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+		}
+		outReal[outIdx] = highest
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	return outReal
+}
+
+// MaxIndex - Index of highest value over a specified period
+func MaxIndex(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 2 {
+		return outReal
+	}
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	highestIdx := -1
+	highest := 0.0
+	for today < len(inReal) {
+		tmp := inReal[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inReal[highestIdx]
+			i := highestIdx + 1
+			for i <= today {
+				tmp := inReal[i]
+				if tmp > highest {
+					highestIdx = i
+					highest = tmp
+				}
+				i++
+			}
+		} else if tmp >= highest {
+			highestIdx = today
+			highest = tmp
+		}
+		outReal[outIdx] = float64(highestIdx)
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	return outReal
+}
+
+// Min - Lowest value over a period
+func Min(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 2 {
+		return outReal
+	}
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	lowestIdx := -1
+	lowest := 0.0
+	for today < len(outReal) {
+
+		tmp := inReal[today]
+
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inReal[lowestIdx]
+			i := lowestIdx + 1
+			for i <= today {
+				tmp = inReal[i]
+				if tmp < lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+		}
+		outReal[outIdx] = lowest
+		outIdx++
+		trailingIdx++
+		today++
+	}
+
+	return outReal
+}
+
+// MinIndex - Index of lowest value over a specified period
+func MinIndex(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	if inTimePeriod < 2 {
+		return outReal
+	}
+
+	nbInitialElementNeeded := inTimePeriod - 1
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	lowestIdx := -1
+	lowest := 0.0
+	for today < len(inReal) {
+		tmp := inReal[today]
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inReal[lowestIdx]
+			i := lowestIdx + 1
+			for i <= today {
+				tmp = inReal[i]
+				if tmp < lowest {
+					lowestIdx = i
+					lowest = tmp
+				}
+				i++
+			}
+		} else if tmp <= lowest {
+			lowestIdx = today
+			lowest = tmp
+		}
+		outReal[outIdx] = float64(lowestIdx)
+		outIdx++
+		trailingIdx++
+		today++
+	}
+	return outReal
+}
+
+// MinMax - Lowest and highest values over a specified period
+func MinMax(inReal []float64, inTimePeriod int) ([]float64, []float64) {
+
+	outMin := make([]float64, len(inReal))
+	outMax := make([]float64, len(inReal))
+
+	nbInitialElementNeeded := (inTimePeriod - 1)
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	highestIdx := -1
+	highest := 0.0
+	lowestIdx := -1
+	lowest := 0.0
+	for today < len(inReal) {
+		tmpLow, tmpHigh := inReal[today], inReal[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inReal[highestIdx]
+			i := highestIdx
+			i++
+			for i <= today {
+				tmpHigh = inReal[i]
+				if tmpHigh > highest {
+					highestIdx = i
+					highest = tmpHigh
+				}
+				i++
+			}
+		} else if tmpHigh >= highest {
+			highestIdx = today
+			highest = tmpHigh
+		}
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inReal[lowestIdx]
+			i := lowestIdx
+			i++
+			for i <= today {
+				tmpLow = inReal[i]
+				if tmpLow < lowest {
+					lowestIdx = i
+					lowest = tmpLow
+				}
+				i++
+			}
+		} else if tmpLow <= lowest {
+			lowestIdx = today
+			lowest = tmpLow
+		}
+		outMax[outIdx] = highest
+		outMin[outIdx] = lowest
+		outIdx++
+		trailingIdx++
+		today++
+	}
+	return outMin, outMax
+}
+
+// MinMaxIndex - Indexes of lowest and highest values over a specified period
+func MinMaxIndex(inReal []float64, inTimePeriod int) ([]float64, []float64) {
+
+	outMinIdx := make([]float64, len(inReal))
+	outMaxIdx := make([]float64, len(inReal))
+
+	nbInitialElementNeeded := (inTimePeriod - 1)
+	startIdx := nbInitialElementNeeded
+	outIdx := startIdx
+	today := startIdx
+	trailingIdx := startIdx - nbInitialElementNeeded
+	highestIdx := -1
+	highest := 0.0
+	lowestIdx := -1
+	lowest := 0.0
+	for today < len(inReal) {
+		tmpLow, tmpHigh := inReal[today], inReal[today]
+		if highestIdx < trailingIdx {
+			highestIdx = trailingIdx
+			highest = inReal[highestIdx]
+			i := highestIdx
+			i++
+			for i <= today {
+				tmpHigh = inReal[i]
+				if tmpHigh > highest {
+					highestIdx = i
+					highest = tmpHigh
+				}
+				i++
+			}
+		} else if tmpHigh >= highest {
+			highestIdx = today
+			highest = tmpHigh
+		}
+		if lowestIdx < trailingIdx {
+			lowestIdx = trailingIdx
+			lowest = inReal[lowestIdx]
+			i := lowestIdx
+			i++
+			for i <= today {
+				tmpLow = inReal[i]
+				if tmpLow < lowest {
+					lowestIdx = i
+					lowest = tmpLow
+				}
+				i++
+			}
+		} else if tmpLow <= lowest {
+			lowestIdx = today
+			lowest = tmpLow
+		}
+		outMaxIdx[outIdx] = float64(highestIdx)
+		outMinIdx[outIdx] = float64(lowestIdx)
+		outIdx++
+		trailingIdx++
+		today++
+	}
+	return outMinIdx, outMaxIdx
+}
+
+// Mult - Vector arithmetic multiply
+func Mult(inReal0 []float64, inReal1 []float64) []float64 {
+	outReal := make([]float64, len(inReal0))
+	for i := 0; i < len(inReal0); i++ {
+		outReal[i] = inReal0[i] * inReal1[i]
+	}
+	return outReal
+}
+
+// Sub - Vector arithmetic subtraction
+func Sub(inReal0 []float64, inReal1 []float64) []float64 {
+	outReal := make([]float64, len(inReal0))
+	for i := 0; i < len(inReal0); i++ {
+		outReal[i] = inReal0[i] - inReal1[i]
+	}
+	return outReal
+}
+
+// Sum - Vector summation
+func Sum(inReal []float64, inTimePeriod int) []float64 {
+
+	outReal := make([]float64, len(inReal))
+
+	lookbackTotal := inTimePeriod - 1
+	startIdx := lookbackTotal
+	periodTotal := 0.0
+	trailingIdx := startIdx - lookbackTotal
+	i := trailingIdx
+	if inTimePeriod > 1 {
+		for i < startIdx {
+			periodTotal += inReal[i]
+			i++
+		}
+	}
+	outIdx := startIdx
+	for i < len(inReal) {
+		periodTotal += inReal[i]
+		tempReal := periodTotal
+		periodTotal -= inReal[trailingIdx]
+		outReal[outIdx] = tempReal
+		i++
+		trailingIdx++
+		outIdx++
+	}
+
+	return outReal
+}
+
+// HeikinashiCandles - from candle values extracts heikinashi candle values.
+//
+// Returns highs, opens, closes and lows of the heikinashi candles (in this order).
+//
+//	NOTE: The number of Heikin-Ashi candles will always be one less than the number of provided candles, due to the fact
+//	      that a previous candle is necessary to calculate the Heikin-Ashi candle, therefore the first provided candle is not considered
+//	      as "current candle" in the algorithm, but only as "previous candle".
+func HeikinashiCandles(highs []float64, opens []float64, closes []float64, lows []float64) ([]float64, []float64, []float64, []float64) {
+	N := len(highs)
+
+	heikinHighs := make([]float64, N)
+	heikinOpens := make([]float64, N)
+	heikinCloses := make([]float64, N)
+	heikinLows := make([]float64, N)
+
+	for currentCandle := 1; currentCandle < N; currentCandle++ {
+		previousCandle := currentCandle - 1
+
+		heikinHighs[currentCandle] = math.Max(highs[currentCandle], math.Max(opens[currentCandle], closes[currentCandle]))
+		heikinOpens[currentCandle] = (opens[previousCandle] + closes[previousCandle]) / 2
+		heikinCloses[currentCandle] = (highs[currentCandle] + opens[currentCandle] + closes[currentCandle] + lows[currentCandle]) / 4
+		heikinLows[currentCandle] = math.Min(highs[currentCandle], math.Min(opens[currentCandle], closes[currentCandle]))
+	}
+
+	return heikinHighs, heikinOpens, heikinCloses, heikinLows
+}
+
+// Hlc3 returns the Hlc3 values
+//
+//	NOTE: Every Hlc item is defined as follows : (high + low + close) / 3
+//	      It is used as AvgPrice candle.
+func Hlc3(highs []float64, lows []float64, closes []float64) []float64 {
+	N := len(highs)
+	result := make([]float64, N)
+	for i := range highs {
+		result[i] = (highs[i] + lows[i] + closes[i]) / 3
+	}
+
+	return result
+}
+
+// Crossover returns true if series1 is crossing over series2.
+//
+//	NOTE: Usually this is used with Media Average Series to check if it crosses for buy signals.
+//	      It assumes first values are the most recent.
+//	      The crossover function does not use most recent value, since usually it's not a complete candle.
+//	      The second recent values and the previous are used, instead.
+func Crossover(series1 []float64, series2 []float64) bool {
+	if len(series1) < 3 || len(series2) < 3 {
+		return false
+	}
+
+	N := len(series1)
+
+	return series1[N-2] <= series2[N-2] && series1[N-1] > series2[N-1]
+}
+
+// Crossunder returns true if series1 is crossing under series2.
+//
+//	NOTE: Usually this is used with Media Average Series to check if it crosses for sell signals.
+func Crossunder(series1 []float64, series2 []float64) bool {
+	if len(series1) < 3 || len(series2) < 3 {
+		return false
+	}
+
+	N := len(series1)
+
+	return series1[N-1] <= series2[N-1] && series1[N-2] > series2[N-2]
+}
+
+// GroupCandles groups a set of candles in another set of candles, basing on a grouping factor.
+//
+// This is pretty useful if you want to transform, for example, 15min candles into 1h candles using same data.
+//
+// This avoid calling multiple times the exchange for multiple contexts.
+//
+// Example:
+//
+//	To transform 15 minute candles in 30 minutes candles you have a grouping factor = 2
+//
+//	To transform 15 minute candles in 1 hour candles you have a grouping factor = 4
+//
+//	To transform 30 minute candles in 1 hour candles you have a grouping factor = 2
+func GroupCandles(highs []float64, opens []float64, closes []float64, lows []float64, groupingFactor int) ([]float64, []float64, []float64, []float64, error) {
+	N := len(highs)
+	if groupingFactor == 0 {
+		return nil, nil, nil, nil, errors.New("Grouping factor must be > 0")
+	} else if groupingFactor == 1 {
+		return highs, opens, closes, lows, nil // no need to group in this case, return the parameters.
+	}
+	if N%groupingFactor > 0 {
+		return nil, nil, nil, nil, errors.New("Cannot group properly, need a groupingFactor which is a factor of the number of candles")
+	}
+
+	groupedN := N / groupingFactor
+
+	groupedHighs := make([]float64, groupedN)
+	groupedOpens := make([]float64, groupedN)
+	groupedCloses := make([]float64, groupedN)
+	groupedLows := make([]float64, groupedN)
+
+	lastOfCurrentGroup := groupingFactor - 1
+
+	k := 0
+	for i := 0; i < N; i += groupingFactor { // scan all param candles
+		groupedOpens[k] = opens[i]
+		groupedCloses[k] = closes[i+lastOfCurrentGroup]
+
+		groupedHighs[k] = highs[i]
+		groupedLows[k] = lows[i]
+
+		endOfCurrentGroup := i + lastOfCurrentGroup
+		for j := i + 1; j <= endOfCurrentGroup; j++ { // group high lows candles here
+			if lows[j] < groupedLows[k] {
+				groupedLows[k] = lows[j]
+			}
+			if highs[j] > groupedHighs[k] {
+				groupedHighs[k] = highs[j]
+			}
+		}
+		k++
+	}
+	return groupedHighs, groupedOpens, groupedCloses, groupedLows, nil
+}