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 }