Beispiel #1
0
        public static RetCode Tan(decimal[] inReal, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx, out int outNbElement)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outReal == null)
            {
                return(RetCode.BadParam);
            }

            int outIdx = default;

            for (int i = startIdx; i <= endIdx; i++)
            {
                outReal[outIdx++] = DecimalMath.Tan(inReal[i]);
            }

            outBegIdx    = startIdx;
            outNbElement = outIdx;

            return(RetCode.Success);
        }
Beispiel #2
0
        private static void TA_INT_StdDevUsingPrecalcMA(decimal[] inReal, decimal[] inMovAvg, int inMovAvgBegIdx, int inMovAvgNbElement,
                                                        decimal[] outReal, int optInTimePeriod)
        {
            decimal tempReal;
            int     startSum     = inMovAvgBegIdx + 1 - optInTimePeriod;
            int     endSum       = inMovAvgBegIdx;
            decimal periodTotal2 = default;

            for (int outIdx = startSum; outIdx < endSum; outIdx++)
            {
                tempReal      = inReal[outIdx];
                tempReal     *= tempReal;
                periodTotal2 += tempReal;
            }

            for (var outIdx = 0; outIdx < inMovAvgNbElement; outIdx++, startSum++, endSum++)
            {
                tempReal      = inReal[endSum];
                tempReal     *= tempReal;
                periodTotal2 += tempReal;
                decimal meanValue2 = periodTotal2 / optInTimePeriod;

                tempReal      = inReal[startSum];
                tempReal     *= tempReal;
                periodTotal2 -= tempReal;

                tempReal    = inMovAvg[outIdx];
                tempReal   *= tempReal;
                meanValue2 -= tempReal;

                outReal[outIdx] = !TA_IsZeroOrNeg(meanValue2) ? DecimalMath.Sqrt(meanValue2) : Decimal.Zero;
            }
        }
        public static RetCode LinearRegAngle(decimal[] inReal, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx,
                                             out int outNbElement, int optInTimePeriod = 14)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outReal == null || optInTimePeriod < 2 || optInTimePeriod > 100000)
            {
                return(RetCode.BadParam);
            }

            int lookbackTotal = LinearRegAngleLookback(optInTimePeriod);

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                return(RetCode.Success);
            }

            int outIdx = default;
            int today  = startIdx;

            decimal sumX    = optInTimePeriod * (optInTimePeriod - 1) * 0.5m;
            decimal sumXSqr = optInTimePeriod * (optInTimePeriod - 1) * (optInTimePeriod * 2 - 1) / 6m;
            decimal divisor = sumX * sumX - optInTimePeriod * sumXSqr;

            while (today <= endIdx)
            {
                decimal sumXY = default;
                decimal sumY  = default;
                for (int i = optInTimePeriod; i != 0; i--)
                {
                    decimal tempValue1 = inReal[today - i];
                    sumY  += tempValue1;
                    sumXY += i * tempValue1;
                }

                decimal m = (optInTimePeriod * sumXY - sumX * sumY) / divisor;
                outReal[outIdx++] = DecimalMath.Atan(m) * 180m / DecimalMath.PI;
                today++;
            }

            outBegIdx    = startIdx;
            outNbElement = outIdx;

            return(RetCode.Success);
        }
Beispiel #4
0
        private static void TA_INT_StdDevUsingPrecalcMA(decimal[] inReal, decimal[] inMovAvg, int inMovAvgBegIdx, int inMovAvgNbElement,
                                                        int timePeriod, decimal[] output)
        {
            decimal tempReal;
            int     outIdx;
            int     startSum     = inMovAvgBegIdx + 1 - timePeriod;
            int     endSum       = inMovAvgBegIdx;
            decimal periodTotal2 = default;

            for (outIdx = startSum; outIdx < endSum; outIdx++)
            {
                tempReal      = inReal[outIdx];
                tempReal     *= tempReal;
                periodTotal2 += tempReal;
            }

            outIdx = 0;
            while (outIdx < inMovAvgNbElement)
            {
                tempReal      = inReal[endSum];
                tempReal     *= tempReal;
                periodTotal2 += tempReal;
                decimal meanValue2 = periodTotal2 / timePeriod;
                tempReal      = inReal[startSum];
                tempReal     *= tempReal;
                periodTotal2 -= tempReal;
                tempReal      = inMovAvg[outIdx];
                tempReal     *= tempReal;
                meanValue2   -= tempReal;
                if (meanValue2 >= 1E-08m)
                {
                    output[outIdx] = DecimalMath.Sqrt(meanValue2);
                }
                else
                {
                    output[outIdx] = Decimal.Zero;
                }

                outIdx++;
                startSum++;
                endSum++;
            }
        }
Beispiel #5
0
        public static RetCode StdDev(decimal[] inReal, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx, out int outNbElement,
                                     int optInTimePeriod = 5, decimal optInNbDev = 1m)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outReal == null || optInTimePeriod < 2 || optInTimePeriod > 100000)
            {
                return(RetCode.BadParam);
            }

            RetCode retCode = TA_INT_VAR(inReal, startIdx, endIdx, outReal, out outBegIdx, out outNbElement, optInTimePeriod);

            if (retCode != RetCode.Success)
            {
                return(retCode);
            }

            if (optInNbDev != Decimal.One)
            {
                for (var i = 0; i < outNbElement; i++)
                {
                    decimal tempReal = outReal[i];
                    outReal[i] = !TA_IsZeroOrNeg(tempReal) ? DecimalMath.Sqrt(tempReal) * optInNbDev : Decimal.Zero;
                }
            }
            else
            {
                for (var i = 0; i < outNbElement; i++)
                {
                    decimal tempReal = outReal[i];
                    outReal[i] = !TA_IsZeroOrNeg(tempReal) ? DecimalMath.Sqrt(tempReal) : Decimal.Zero;
                }
            }

            return(RetCode.Success);
        }
Beispiel #6
0
        public static RetCode Cos(int startIdx, int endIdx, decimal[] inReal, ref int outBegIdx, ref int outNBElement, decimal[] outReal)
        {
            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return RetCode.OutOfRangeStartIndex;
            }

            if (inReal == null || outReal == null)
            {
                return RetCode.BadParam;
            }

            int outIdx = default;
            for (int i = startIdx; i <= endIdx; i++)
            {
                outReal[outIdx++] = DecimalMath.Cos(inReal[i]);
            }

            outNBElement = outIdx;
            outBegIdx = startIdx;

            return RetCode.Success;
        }
        public static RetCode Correl(decimal[] inReal0, decimal[] inReal1, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx,
                                     out int outNbElement, int optInTimePeriod = 30)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal0 == null || inReal1 == null || outReal == null || optInTimePeriod < 1 || optInTimePeriod > 100000)
            {
                return(RetCode.BadParam);
            }

            int lookbackTotal = CorrelLookback(optInTimePeriod);

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                return(RetCode.Success);
            }

            outBegIdx = startIdx;
            int trailingIdx = startIdx - lookbackTotal;

            decimal sumX, sumY, sumX2, sumY2;
            decimal sumXY = sumX = sumY = sumX2 = sumY2 = default;
            int     today;

            for (today = trailingIdx; today <= startIdx; today++)
            {
                decimal x = inReal0[today];
                sumX  += x;
                sumX2 += x * x;

                decimal y = inReal1[today];
                sumXY += x * y;
                sumY  += y;
                sumY2 += y * y;
            }

            decimal trailingX = inReal0[trailingIdx];
            decimal trailingY = inReal1[trailingIdx++];
            decimal tempReal  = (sumX2 - sumX * sumX / optInTimePeriod) * (sumY2 - sumY * sumY / optInTimePeriod);

            outReal[0] = !TA_IsZeroOrNeg(tempReal) ? (sumXY - sumX * sumY / optInTimePeriod) / DecimalMath.Sqrt(tempReal) : Decimal.Zero;

            int outIdx = 1;

            while (today <= endIdx)
            {
                sumX  -= trailingX;
                sumX2 -= trailingX * trailingX;

                sumXY -= trailingX * trailingY;
                sumY  -= trailingY;
                sumY2 -= trailingY * trailingY;

                decimal x = inReal0[today];
                sumX  += x;
                sumX2 += x * x;

                decimal y = inReal1[today++];
                sumXY += x * y;
                sumY  += y;
                sumY2 += y * y;

                trailingX         = inReal0[trailingIdx];
                trailingY         = inReal1[trailingIdx++];
                tempReal          = (sumX2 - sumX * sumX / optInTimePeriod) * (sumY2 - sumY * sumY / optInTimePeriod);
                outReal[outIdx++] = !TA_IsZeroOrNeg(tempReal)
                    ? (sumXY - sumX * sumY / optInTimePeriod) / DecimalMath.Sqrt(tempReal)
                    : Decimal.Zero;
            }

            outNbElement = outIdx;

            return(RetCode.Success);
        }
Beispiel #8
0
        public static RetCode HtDcPhase(decimal[] inReal, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx, out int outNbElement)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return RetCode.OutOfRangeStartIndex;
            }

            if (inReal == null || outReal == null)
            {
                return RetCode.BadParam;
            }

            int lookbackTotal = HtDcPhaseLookback();

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                return RetCode.Success;
            }

            const int smoothPriceSize = 50;
            var smoothPrice = new decimal[smoothPriceSize];

            const decimal rad2Deg = 180m / DecimalMath.PI;
            const decimal constDeg2RadBy360 = 2m * DecimalMath.PI;

            outBegIdx = startIdx;
            int trailingWMAIdx = startIdx - lookbackTotal;
            int today = trailingWMAIdx;

            decimal tempReal = inReal[today++];
            decimal periodWMASub = tempReal;
            decimal periodWMASum = tempReal;
            tempReal = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 2m;
            tempReal = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 3m;

            decimal trailingWMAValue = default;
            var i = 34;
            do
            {
                tempReal = inReal[today++];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, tempReal, out _);
            } while (--i != 0);

            int hilbertIdx = default;
            int smoothPriceIdx = default;

            var hilbertVariables = InitHilbertVariables<decimal>();

            int outIdx = default;

            decimal prevI2, prevQ2, re, im, i1ForOddPrev3, i1ForEvenPrev3, i1ForOddPrev2, i1ForEvenPrev2, smoothPeriod, dcPhase;
            decimal period = prevI2 = prevQ2 =
                re = im = i1ForOddPrev3 = i1ForEvenPrev3 = i1ForOddPrev2 = i1ForEvenPrev2 = smoothPeriod = dcPhase = default;
            while (today <= endIdx)
            {
                decimal i2;
                decimal q2;

                decimal adjustedPrevPeriod = 0.075m * period + 0.54m;

                decimal todayValue = inReal[today];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue,
                    todayValue, out var smoothedValue);

                smoothPrice[smoothPriceIdx] = smoothedValue;
                if (today % 2 == 0)
                {
                    DoHilbertEven(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;
                    i1ForOddPrev3 = i1ForOddPrev2;
                    i1ForOddPrev2 = hilbertVariables["detrender"];
                }
                else
                {
                    DoHilbertOdd(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jI", i1ForOddPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForOddPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForEvenPrev3 = i1ForEvenPrev2;
                    i1ForEvenPrev2 = hilbertVariables["detrender"];
                }

                re = 0.2m * (i2 * prevI2 + q2 * prevQ2) + 0.8m * re;
                im = 0.2m * (i2 * prevQ2 - q2 * prevI2) + 0.8m * im;
                prevQ2 = q2;
                prevI2 = i2;
                tempReal = period;
                if (im != Decimal.Zero && re != Decimal.Zero)
                {
                    period = 360m / (DecimalMath.Atan(im / re) * rad2Deg);
                }

                decimal tempReal2 = 1.5m * tempReal;
                if (period > tempReal2)
                {
                    period = tempReal2;
                }

                tempReal2 = 0.67m * tempReal;
                if (period < tempReal2)
                {
                    period = tempReal2;
                }

                if (period < 6m)
                {
                    period = 6m;
                }
                else if (period > 50m)
                {
                    period = 50m;
                }

                period = 0.2m * period + 0.8m * tempReal;

                smoothPeriod = 0.33m * period + 0.67m * smoothPeriod;

                decimal dcPeriod = smoothPeriod + 0.5m;
                int dcPeriodInt = (int) dcPeriod;
                decimal realPart = default;
                decimal imagPart = default;

                int idx = smoothPriceIdx;
                for (i = 0; i < dcPeriodInt; i++)
                {
                    tempReal = i * constDeg2RadBy360 / dcPeriodInt;
                    tempReal2 = smoothPrice[idx];
                    realPart += DecimalMath.Sin(tempReal) * tempReal2;
                    imagPart += DecimalMath.Cos(tempReal) * tempReal2;
                    if (idx == 0)
                    {
                        idx = smoothPriceSize - 1;
                    }
                    else
                    {
                        idx--;
                    }
                }

                tempReal = Math.Abs(imagPart);
                if (tempReal > Decimal.Zero)
                {
                    dcPhase = DecimalMath.Atan(realPart / imagPart) * rad2Deg;
                }
                else if (tempReal <= 0.01m)
                {
                    if (realPart < Decimal.Zero)
                    {
                        dcPhase -= 90m;
                    }
                    else if (realPart > Decimal.Zero)
                    {
                        dcPhase += 90m;
                    }
                }

                dcPhase += 90m;

                dcPhase += 360m / smoothPeriod;
                if (imagPart < Decimal.Zero)
                {
                    dcPhase += 180m;
                }

                if (dcPhase > 315m)
                {
                    dcPhase -= 360m;
                }

                if (today >= startIdx)
                {
                    outReal[outIdx++] = dcPhase;
                }

                if (++smoothPriceIdx > smoothPriceSize - 1)
                {
                    smoothPriceIdx = 0;
                }

                today++;
            }

            outNbElement = outIdx;

            return RetCode.Success;
        }
Beispiel #9
0
        public static RetCode Mama(decimal[] inReal, int startIdx, int endIdx, decimal[] outMama, decimal[] outFama, out int outBegIdx,
                                   out int outNbElement, decimal optInFastLimit = 0.5m, decimal optInSlowLimit = 0.05m)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outMama == null || outFama == null || optInFastLimit < 0.01m || optInFastLimit > 0.99m ||
                optInSlowLimit < 0.01m || optInSlowLimit > 0.99m)
            {
                return(RetCode.BadParam);
            }

            int lookbackTotal = MamaLookback();

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                return(RetCode.Success);
            }

            const decimal rad2Deg = 180m / DecimalMath.PI;

            outBegIdx = startIdx;

            int trailingWMAIdx = startIdx - lookbackTotal;
            int today          = trailingWMAIdx;

            decimal tempReal     = inReal[today++];
            decimal periodWMASub = tempReal;
            decimal periodWMASum = tempReal;

            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 2m;
            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 3m;

            decimal trailingWMAValue = default;
            int     i = 9;

            do
            {
                tempReal = inReal[today];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, tempReal, out _);
            } while (--i != 0);

            int hilbertIdx       = default;
            var hilbertVariables = InitHilbertVariables <decimal>();

            int outIdx = default;

            decimal prevI2, prevQ2, re, im, mama, fama, i1ForOddPrev3, i1ForEvenPrev3, i1ForOddPrev2, i1ForEvenPrev2, prevPhase;
            decimal period = prevI2 = prevQ2
                                          = re = im = mama = fama = i1ForOddPrev3 = i1ForEvenPrev3 = i1ForOddPrev2 = i1ForEvenPrev2 = prevPhase = default;

            while (today <= endIdx)
            {
                decimal tempReal2;
                decimal i2;
                decimal q2;

                decimal adjustedPrevPeriod = 0.075m * period + 0.54m;

                decimal todayValue = inReal[today];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue,
                           todayValue, out var smoothedValue);
                if (today % 2 == 0)
                {
                    DoHilbertEven(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForOddPrev3 = i1ForOddPrev2;
                    i1ForOddPrev2 = hilbertVariables["detrender"];

                    if (i1ForEvenPrev3 != Decimal.Zero)
                    {
                        tempReal2 = DecimalMath.Atan(hilbertVariables["q1"] / i1ForEvenPrev3) * rad2Deg;
                    }
                    else
                    {
                        tempReal2 = Decimal.Zero;
                    }
                }
                else
                {
                    DoHilbertOdd(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jI", i1ForOddPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForOddPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForEvenPrev3 = i1ForEvenPrev2;
                    i1ForEvenPrev2 = hilbertVariables["detrender"];
                    if (i1ForOddPrev3 != Decimal.Zero)
                    {
                        tempReal2 = DecimalMath.Atan(hilbertVariables["q1"] / i1ForOddPrev3) * rad2Deg;
                    }
                    else
                    {
                        tempReal2 = Decimal.Zero;
                    }
                }

                tempReal  = prevPhase - tempReal2;
                prevPhase = tempReal2;
                if (tempReal < Decimal.One)
                {
                    tempReal = Decimal.One;
                }

                if (tempReal > Decimal.One)
                {
                    tempReal = optInFastLimit / tempReal;
                    if (tempReal < optInSlowLimit)
                    {
                        tempReal = optInSlowLimit;
                    }
                }
                else
                {
                    tempReal = optInFastLimit;
                }

                mama      = tempReal * todayValue + (Decimal.One - tempReal) * mama;
                tempReal *= 0.5m;
                fama      = tempReal * mama + (Decimal.One - tempReal) * fama;
                if (today >= startIdx)
                {
                    outMama[outIdx] = mama;
                    outFama[outIdx] = fama;
                    outIdx++;
                }

                re       = 0.2m * (i2 * prevI2 + q2 * prevQ2) + 0.8m * re;
                im       = 0.2m * (i2 * prevQ2 - q2 * prevI2) + 0.8m * im;
                prevQ2   = q2;
                prevI2   = i2;
                tempReal = period;
                if (im != Decimal.Zero && re != Decimal.Zero)
                {
                    period = 360m / (DecimalMath.Atan(im / re) * rad2Deg);
                }

                tempReal2 = 1.5m * tempReal;
                if (period > tempReal2)
                {
                    period = tempReal2;
                }

                tempReal2 = 0.67m * tempReal;
                if (period < tempReal2)
                {
                    period = tempReal2;
                }

                if (period < 6m)
                {
                    period = 6m;
                }
                else if (period > 50m)
                {
                    period = 50m;
                }

                period = 0.2m * period + 0.8m * tempReal;
                today++;
            }

            outNbElement = outIdx;

            return(RetCode.Success);
        }
Beispiel #10
0
        public static RetCode HtPhasor(int startIdx, int endIdx, decimal[] inReal, ref int outBegIdx, ref int outNBElement,
                                       decimal[] outInPhase, decimal[] outQuadrature)
        {
            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outInPhase == null || outQuadrature == null)
            {
                return(RetCode.BadParam);
            }

            int lookbackTotal = HtPhasorLookback();

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                outBegIdx    = 0;
                outNBElement = 0;
                return(RetCode.Success);
            }

            const decimal rad2Deg = 180m / DecimalMath.PI;

            outBegIdx = startIdx;
            int trailingWMAIdx = startIdx - lookbackTotal;
            int today          = trailingWMAIdx;

            decimal tempReal     = inReal[today++];
            decimal periodWMASub = tempReal;
            decimal periodWMASum = tempReal;

            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 2m;
            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 3m;

            decimal trailingWMAValue = default;
            int     i = 9;

            do
            {
                tempReal = inReal[today++];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, out var _, tempReal);
            } while (--i != 0);

            int hilbertIdx = default;

            var hilbertVariables = InitHilbertVariables <decimal>();

            int outIdx = default;

            decimal prevI2, prevQ2, re, im, i1ForOddPrev3, i1ForEvenPrev3, i1ForOddPrev2, i1ForEvenPrev2, smoothPeriod;
            decimal period = prevI2 = prevQ2 =
                re = im = i1ForOddPrev3 = i1ForEvenPrev3 = i1ForOddPrev2 = i1ForEvenPrev2 = smoothPeriod = default;

            while (today <= endIdx)
            {
                decimal i2;
                decimal q2;

                decimal adjustedPrevPeriod = 0.075m * period + 0.54m;

                decimal todayValue = inReal[today];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, out var smoothedValue,
                           todayValue);
                if (today % 2 == 0)
                {
                    DoHilbertEven(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    if (today >= startIdx)
                    {
                        outQuadrature[outIdx] = hilbertVariables["q1"];
                        outInPhase[outIdx++]  = i1ForEvenPrev3;
                    }

                    DoHilbertEven(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);
                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2            = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2            = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;
                    i1ForOddPrev3 = i1ForOddPrev2;
                    i1ForOddPrev2 = hilbertVariables["detrender"];
                }
                else
                {
                    DoHilbertOdd(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    if (today >= startIdx)
                    {
                        outQuadrature[outIdx] = hilbertVariables["q1"];
                        outInPhase[outIdx++]  = i1ForOddPrev3;
                    }

                    DoHilbertOdd(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);
                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2             = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2             = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;
                    i1ForEvenPrev3 = i1ForEvenPrev2;
                    i1ForEvenPrev2 = hilbertVariables["detrender"];
                }

                re       = 0.2m * (i2 * prevI2 + q2 * prevQ2) + 0.8m * re;
                im       = 0.2m * (i2 * prevQ2 - q2 * prevI2) + 0.8m * im;
                prevQ2   = q2;
                prevI2   = i2;
                tempReal = period;
                if (im != Decimal.Zero && re != Decimal.Zero)
                {
                    period = 360m / (DecimalMath.Atan(im / re) * rad2Deg);
                }

                decimal tempReal2 = 1.5m * tempReal;
                if (period > tempReal2)
                {
                    period = tempReal2;
                }

                tempReal2 = 0.67m * tempReal;
                if (period < tempReal2)
                {
                    period = tempReal2;
                }

                if (period < 6m)
                {
                    period = 6m;
                }
                else if (period > 50m)
                {
                    period = 50m;
                }

                period = 0.2m * period + 0.8m * tempReal;
                today++;
            }

            outNBElement = outIdx;

            return(RetCode.Success);
        }
        public static RetCode HtTrendline(decimal[] inReal, int startIdx, int endIdx, decimal[] outReal, out int outBegIdx,
                                          out int outNbElement)
        {
            outBegIdx = outNbElement = 0;

            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outReal == null)
            {
                return(RetCode.BadParam);
            }

            int lookbackTotal = HtTrendlineLookback();

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                return(RetCode.Success);
            }

            const int smoothPriceSize = 50;
            var       smoothPrice     = new decimal[smoothPriceSize];

            decimal       iTrend2, iTrend1;
            decimal       iTrend3 = iTrend2 = iTrend1 = default;
            const decimal rad2Deg = 180m / DecimalMath.PI;

            outBegIdx = startIdx;

            int trailingWMAIdx = startIdx - lookbackTotal;
            int today          = trailingWMAIdx;

            decimal tempReal     = inReal[today++];
            decimal periodWMASub = tempReal;
            decimal periodWMASum = tempReal;

            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 2m;
            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 3m;

            decimal trailingWMAValue = default;

            var i = 34;

            do
            {
                tempReal = inReal[today++];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, tempReal, out _);
            } while (--i != 0);

            int hilbertIdx     = default;
            int smoothPriceIdx = default;

            var hilbertVariables = InitHilbertVariables <decimal>();

            int outIdx = default;

            decimal prevI2, prevQ2, re, im, i1ForOddPrev3, i1ForEvenPrev3, i1ForOddPrev2, i1ForEvenPrev2, smoothPeriod;
            decimal period = prevI2 = prevQ2 =
                re = im = i1ForOddPrev3 = i1ForEvenPrev3 = i1ForOddPrev2 = i1ForEvenPrev2 = smoothPeriod = default;

            while (today <= endIdx)
            {
                decimal i2;
                decimal q2;

                decimal adjustedPrevPeriod = 0.075m * period + 0.54m;

                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, inReal[today],
                           out var smoothedValue);

                smoothPrice[smoothPriceIdx] = smoothedValue;
                if (today % 2 == 0)
                {
                    DoHilbertEven(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForOddPrev3 = i1ForOddPrev2;
                    i1ForOddPrev2 = hilbertVariables["detrender"];
                }
                else
                {
                    DoHilbertOdd(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jI", i1ForOddPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForOddPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForEvenPrev3 = i1ForEvenPrev2;
                    i1ForEvenPrev2 = hilbertVariables["detrender"];
                }

                re       = 0.2m * (i2 * prevI2 + q2 * prevQ2) + 0.8m * re;
                im       = 0.2m * (i2 * prevQ2 - q2 * prevI2) + 0.8m * im;
                prevQ2   = q2;
                prevI2   = i2;
                tempReal = period;
                if (im != Decimal.Zero && re != Decimal.Zero)
                {
                    period = 360m / (DecimalMath.Atan(im / re) * rad2Deg);
                }

                decimal tempReal2 = 1.5m * tempReal;
                if (period > tempReal2)
                {
                    period = tempReal2;
                }

                tempReal2 = 0.67m * tempReal;
                if (period < tempReal2)
                {
                    period = tempReal2;
                }

                if (period < 6m)
                {
                    period = 6m;
                }
                else if (period > 50m)
                {
                    period = 50m;
                }

                period = 0.2m * period + 0.8m * tempReal;

                smoothPeriod = 0.33m * period + 0.67m * smoothPeriod;

                decimal dcPeriod    = smoothPeriod + 0.5m;
                var     dcPeriodInt = (int)dcPeriod;

                int idx = today;
                tempReal = default;
                for (i = 0; i < dcPeriodInt; i++)
                {
                    tempReal += inReal[idx--];
                }

                if (dcPeriodInt > 0)
                {
                    tempReal /= dcPeriodInt;
                }

                tempReal2 = (4m * tempReal + 3m * iTrend1 + 2m * iTrend2 + iTrend3) / 10m;
                iTrend3   = iTrend2;
                iTrend2   = iTrend1;
                iTrend1   = tempReal;

                if (today >= startIdx)
                {
                    outReal[outIdx++] = tempReal2;
                }

                if (++smoothPriceIdx > smoothPriceSize - 1)
                {
                    smoothPriceIdx = 0;
                }

                today++;
            }

            outNbElement = outIdx;

            return(RetCode.Success);
        }
        public static RetCode HtTrendMode(int startIdx, int endIdx, decimal[] inReal, ref int outBegIdx, ref int outNBElement,
                                          int[] outInteger)
        {
            if (startIdx < 0 || endIdx < 0 || endIdx < startIdx)
            {
                return(RetCode.OutOfRangeStartIndex);
            }

            if (inReal == null || outInteger == null)
            {
                return(RetCode.BadParam);
            }

            const int smoothPriceSize = 50;
            var       smoothPrice     = new decimal[smoothPriceSize];

            const decimal rad2Deg           = 180m / DecimalMath.PI;
            const decimal deg2Rad           = Decimal.One / rad2Deg;
            const decimal constDeg2RadBy360 = 2m * DecimalMath.PI;

            decimal iTrend3     = default;
            decimal iTrend2     = iTrend3;
            decimal iTrend1     = iTrend2;
            int     daysInTrend = default;
            decimal sine        = default;
            decimal leadSine    = default;

            int lookbackTotal = HtTrendModeLookback();

            if (startIdx < lookbackTotal)
            {
                startIdx = lookbackTotal;
            }

            if (startIdx > endIdx)
            {
                outBegIdx    = 0;
                outNBElement = 0;
                return(RetCode.Success);
            }

            outBegIdx = startIdx;
            int     trailingWMAIdx = startIdx - lookbackTotal;
            int     today          = trailingWMAIdx;
            decimal tempReal       = inReal[today++];
            decimal periodWMASub   = tempReal;
            decimal periodWMASum   = tempReal;

            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 2m;
            tempReal      = inReal[today++];
            periodWMASub += tempReal;
            periodWMASum += tempReal * 3m;
            decimal trailingWMAValue = default;
            int     i = 34;

            do
            {
                tempReal = inReal[today++];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, out var _, tempReal);
            } while (--i != 0);

            int hilbertIdx     = default;
            int smoothPriceIdx = default;

            var hilbertVariables = InitHilbertVariables <decimal>();

            int outIdx = default;

            decimal prevI2, prevQ2, re, im, i1ForOddPrev3, i1ForEvenPrev3, i1ForOddPrev2, i1ForEvenPrev2, smoothPeriod, dcPhase;
            decimal period = prevI2 = prevQ2 =
                re = im = i1ForOddPrev3 = i1ForEvenPrev3 = i1ForOddPrev2 = i1ForEvenPrev2 = smoothPeriod = dcPhase = default;

            while (today <= endIdx)
            {
                decimal i2;
                decimal q2;

                decimal adjustedPrevPeriod = 0.075m * period + 0.54m;

                decimal todayValue = inReal[today];
                DoPriceWma(inReal, ref trailingWMAIdx, ref periodWMASub, ref periodWMASum, ref trailingWMAValue, out var smoothedValue,
                           todayValue);

                smoothPrice[smoothPriceIdx] = smoothedValue;
                if (today % 2 == 0)
                {
                    DoHilbertEven(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jI", i1ForEvenPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertEven(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    if (++hilbertIdx == 3)
                    {
                        hilbertIdx = 0;
                    }

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForEvenPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForOddPrev3 = i1ForOddPrev2;
                    i1ForOddPrev2 = hilbertVariables["detrender"];
                }
                else
                {
                    DoHilbertOdd(hilbertVariables, "detrender", smoothedValue, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "q1", hilbertVariables["detrender"], hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jI", i1ForOddPrev3, hilbertIdx, adjustedPrevPeriod);
                    DoHilbertOdd(hilbertVariables, "jQ", hilbertVariables["q1"], hilbertIdx, adjustedPrevPeriod);

                    q2 = 0.2m * (hilbertVariables["q1"] + hilbertVariables["jI"]) + 0.8m * prevQ2;
                    i2 = 0.2m * (i1ForOddPrev3 - hilbertVariables["jQ"]) + 0.8m * prevI2;

                    i1ForEvenPrev3 = i1ForEvenPrev2;
                    i1ForEvenPrev2 = hilbertVariables["detrender"];
                }

                re       = 0.2m * (i2 * prevI2 + q2 * prevQ2) + 0.8m * re;
                im       = 0.2m * (i2 * prevQ2 - q2 * prevI2) + 0.8m * im;
                prevQ2   = q2;
                prevI2   = i2;
                tempReal = period;
                if (im != Decimal.Zero && re != Decimal.Zero)
                {
                    period = 360m / (DecimalMath.Atan(im / re) * rad2Deg);
                }

                decimal tempReal2 = 1.5m * tempReal;
                if (period > tempReal2)
                {
                    period = tempReal2;
                }

                tempReal2 = 0.67m * tempReal;
                if (period < tempReal2)
                {
                    period = tempReal2;
                }

                if (period < 6m)
                {
                    period = 6m;
                }
                else if (period > 50m)
                {
                    period = 50m;
                }

                period = 0.2m * period + 0.8m * tempReal;

                smoothPeriod = 0.33m * period + 0.67m * smoothPeriod;

                decimal prevDCPhase = dcPhase;
                decimal dcPeriod    = smoothPeriod + 0.5m;
                int     dcPeriodInt = (int)dcPeriod;
                decimal realPart    = default;
                decimal imagPart    = default;

                int idx = smoothPriceIdx;
                for (i = 0; i < dcPeriodInt; i++)
                {
                    tempReal  = i * constDeg2RadBy360 / dcPeriodInt;
                    tempReal2 = smoothPrice[idx];
                    realPart += DecimalMath.Sin(tempReal) * tempReal2;
                    imagPart += DecimalMath.Cos(tempReal) * tempReal2;
                    if (idx == 0)
                    {
                        idx = smoothPriceSize - 1;
                    }
                    else
                    {
                        idx--;
                    }
                }

                tempReal = Math.Abs(imagPart);
                if (tempReal > Decimal.Zero)
                {
                    dcPhase = DecimalMath.Atan(realPart / imagPart) * rad2Deg;
                }
                else if (tempReal <= 0.01m)
                {
                    if (realPart < Decimal.Zero)
                    {
                        dcPhase -= 90m;
                    }
                    else if (realPart > Decimal.Zero)
                    {
                        dcPhase += 90m;
                    }
                }

                dcPhase += 90m;
                dcPhase += 360m / smoothPeriod;
                if (imagPart < Decimal.Zero)
                {
                    dcPhase += 180m;
                }

                if (dcPhase > 315m)
                {
                    dcPhase -= 360m;
                }

                decimal prevSine     = sine;
                decimal prevLeadSine = leadSine;
                sine     = DecimalMath.Sin(dcPhase * deg2Rad);
                leadSine = DecimalMath.Sin((dcPhase + 45m) * deg2Rad);

                dcPeriod    = smoothPeriod + 0.5m;
                dcPeriodInt = (int)dcPeriod;

                idx      = today;
                tempReal = default;
                for (i = 0; i < dcPeriodInt; i++)
                {
                    tempReal += inReal[idx--];
                }

                if (dcPeriodInt > 0)
                {
                    tempReal /= dcPeriodInt;
                }

                decimal trendline = (4m * tempReal + 3m * iTrend1 + 2m * iTrend2 + iTrend3) / 10m;
                iTrend3 = iTrend2;
                iTrend2 = iTrend1;
                iTrend1 = tempReal;

                int trend = 1;

                if (sine > leadSine && prevSine <= prevLeadSine || sine < leadSine && prevSine >= prevLeadSine)
                {
                    daysInTrend = 0;
                    trend       = 0;
                }

                if (++daysInTrend < 0.5m * smoothPeriod)
                {
                    trend = 0;
                }

                tempReal = dcPhase - prevDCPhase;
                if (smoothPeriod != Decimal.Zero && tempReal > 0.67m * 360m / smoothPeriod && tempReal < 1.5m * 360m / smoothPeriod)
                {
                    trend = 0;
                }

                tempReal = smoothPrice[smoothPriceIdx];
                if (trendline != Decimal.Zero && Math.Abs((tempReal - trendline) / trendline) >= 0.015m)
                {
                    trend = 1;
                }

                if (today >= startIdx)
                {
                    outInteger[outIdx++] = trend;
                }

                if (++smoothPriceIdx > smoothPriceSize - 1)
                {
                    smoothPriceIdx = 0;
                }

                today++;
            }

            outNBElement = outIdx;

            return(RetCode.Success);
        }