Example #1
0
    // AROON OSCILLATOR
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <AroonResult> GetAroon <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 25)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateAroon(lookbackPeriods);

        // initialize
        List <AroonResult> results = new(quotesList.Count);

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            AroonResult result = new()
            {
                Date = q.Date
            };

            // add aroons
            if (index > lookbackPeriods)
            {
                double lastHighPrice = 0;
                double lastLowPrice  = double.MaxValue;
                int    lastHighIndex = 0;
                int    lastLowIndex  = 0;

                for (int p = index - lookbackPeriods - 1; p < index; p++)
                {
                    QuoteD d = quotesList[p];

                    if (d.High > lastHighPrice)
                    {
                        lastHighPrice = d.High;
                        lastHighIndex = p + 1;
                    }

                    if (d.Low < lastLowPrice)
                    {
                        lastLowPrice = d.Low;
                        lastLowIndex = p + 1;
                    }
                }

                result.AroonUp    = 100 * (decimal)(lookbackPeriods - (index - lastHighIndex)) / lookbackPeriods;
                result.AroonDown  = 100 * (decimal)(lookbackPeriods - (index - lastLowIndex)) / lookbackPeriods;
                result.Oscillator = result.AroonUp - result.AroonDown;
            }

            results.Add(result);
        }

        return(results);
    }
Example #2
0
    // ON-BALANCE VOLUME
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <ObvResult> GetObv <TQuote>(
        this IEnumerable <TQuote> quotes,
        int?smaPeriods = null)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateObv(smaPeriods);

        // initialize
        List <ObvResult> results = new(quotesList.Count);

        double?prevClose = null;
        double obv       = 0;

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            if (prevClose == null || q.Close == prevClose)
            {
                // no change to OBV
            }
            else if (q.Close > prevClose)
            {
                obv += q.Volume;
            }
            else if (q.Close < prevClose)
            {
                obv -= q.Volume;
            }

            ObvResult result = new()
            {
                Date = q.Date,
                Obv  = obv
            };
            results.Add(result);

            prevClose = q.Close;

            // optional SMA
            if (smaPeriods != null && index > smaPeriods)
            {
                double sumSma = 0;
                for (int p = index - (int)smaPeriods; p < index; p++)
                {
                    sumSma += results[p].Obv;
                }

                result.ObvSma = sumSma / smaPeriods;
            }
        }

        return(results);
    }
Example #3
0
    // COMMODITY CHANNEL INDEX
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <CciResult> GetCci <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 20)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateCci(lookbackPeriods);

        // initialize
        List <CciResult> results = new(quotesList.Count);

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            CciResult result = new()
            {
                Date = q.Date,
                Tp   = (q.High + q.Low + q.Close) / 3
            };
            results.Add(result);

            if (index >= lookbackPeriods)
            {
                // average TP over lookback
                double avgTp = 0;
                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    CciResult d = results[p];
                    avgTp += (double)d.Tp;
                }

                avgTp /= lookbackPeriods;

                // average Deviation over lookback
                double avgDv = 0;
                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    CciResult d = results[p];
                    avgDv += Math.Abs(avgTp - (double)d.Tp);
                }

                avgDv /= lookbackPeriods;

                result.Cci = (avgDv == 0) ? null
                    : (result.Tp - avgTp) / (0.015 * avgDv);
            }
        }

        return(results);
    }
Example #4
0
    // VOLUME WEIGHTED AVERAGE PRICE
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <VwapResult> GetVwap <TQuote>(
        this IEnumerable <TQuote> quotes,
        DateTime?startDate = null)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateVwap(quotesList, startDate);

        // initialize
        int length = quotesList.Count;
        List <VwapResult> results = new(length);

        if (length == 0)
        {
            return(results);
        }

        startDate = (startDate == null) ? quotesList[0].Date : startDate;

        double?cumVolume   = 0;
        double?cumVolumeTP = 0;

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q = quotesList[i];
            double?v = q.Volume;
            double?h = q.High;
            double?l = q.Low;
            double?c = q.Close;

            VwapResult r = new()
            {
                Date = q.Date
            };

            if (q.Date >= startDate)
            {
                cumVolume   += v;
                cumVolumeTP += v * (h + l + c) / 3;

                r.Vwap = (cumVolume != 0) ? (decimal?)(cumVolumeTP / cumVolume) : null;
            }

            results.Add(r);
        }

        return(results);
    }
Example #5
0
    // ACCUMULATION/DISTRIBUTION LINE
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <AdlResult> GetAdl <TQuote>(
        this IEnumerable <TQuote> quotes,
        int?smaPeriods = null)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateAdl(smaPeriods);

        // initialize
        List <AdlResult> results = new(quotesList.Count);
        double           prevAdl = 0;

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            double mfm = (q.High == q.Low) ? 0 : (q.Close - q.Low - (q.High - q.Close)) / (q.High - q.Low);
            double mfv = mfm * q.Volume;
            double adl = mfv + prevAdl;

            AdlResult result = new()
            {
                Date = q.Date,
                MoneyFlowMultiplier = mfm,
                MoneyFlowVolume     = mfv,
                Adl = adl
            };
            results.Add(result);

            prevAdl = adl;

            // optional SMA
            if (smaPeriods != null && index >= smaPeriods)
            {
                double sumSma = 0;
                for (int p = index - (int)smaPeriods; p < index; p++)
                {
                    sumSma += results[p].Adl;
                }

                result.AdlSma = sumSma / smaPeriods;
            }
        }

        return(results);
    }
Example #6
0
    // VOLUME WEIGHTED MOVING AVERAGE
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <VwmaResult> GetVwma <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateVwma(lookbackPeriods);

        // initialize
        int length = quotesList.Count;
        List <VwmaResult> results = new(length);

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            VwmaResult result = new()
            {
                Date = q.Date
            };

            if (index >= lookbackPeriods)
            {
                double?sumCl = 0;
                double?sumVl = 0;
                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    QuoteD d = quotesList[p];
                    double?c = d.Close;
                    double?v = d.Volume;

                    sumCl += c * v;
                    sumVl += v;
                }

                result.Vwma = sumVl != 0 ? (decimal?)(sumCl / sumVl) : null;
            }

            results.Add(result);
        }

        return(results);
    }
Example #7
0
    // CHANDELIER EXIT
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <ChandelierResult> GetChandelier <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 22,
        double multiplier   = 3,
        ChandelierType type = ChandelierType.Long)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateChandelier(lookbackPeriods, multiplier);

        // initialize
        List <ChandelierResult> results   = new(quotesList.Count);
        List <AtrResult>        atrResult = GetAtr(quotes, lookbackPeriods).ToList(); // uses ATR

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            ChandelierResult result = new()
            {
                Date = q.Date
            };

            // add exit values
            if (index >= lookbackPeriods)
            {
                double?atr = (double?)atrResult[i].Atr;

                switch (type)
                {
                case ChandelierType.Long:

                    double maxHigh = 0;
                    for (int p = index - lookbackPeriods; p < index; p++)
                    {
                        QuoteD d = quotesList[p];
                        if (d.High > maxHigh)
                        {
                            maxHigh = d.High;
                        }
                    }

                    result.ChandelierExit = (decimal?)(maxHigh - (atr * multiplier));
                    break;

                case ChandelierType.Short:

                    double minLow = double.MaxValue;
                    for (int p = index - lookbackPeriods; p < index; p++)
                    {
                        QuoteD d = quotesList[p];
                        if (d.Low < minLow)
                        {
                            minLow = d.Low;
                        }
                    }

                    result.ChandelierExit = (decimal?)(minLow + (atr * multiplier));
                    break;

                default:
                    break;
                }
            }

            results.Add(result);
        }

        return(results);
    }
Example #8
0
    // ULTIMATE OSCILLATOR
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <UltimateResult> GetUltimate <TQuote>(
        this IEnumerable <TQuote> quotes,
        int shortPeriods  = 7,
        int middlePeriods = 14,
        int longPeriods   = 28)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateUltimate(shortPeriods, middlePeriods, longPeriods);

        // initialize
        int length = quotesList.Count;
        List <UltimateResult> results = new(length);

        double[] bp = new double[length]; // buying pressure
        double[] tr = new double[length]; // true range

        double priorClose = 0;

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            UltimateResult r = new()
            {
                Date = q.Date
            };
            results.Add(r);

            if (i > 0)
            {
                bp[i] = q.Close - Math.Min(q.Low, priorClose);
                tr[i] = Math.Max(q.High, priorClose) - Math.Min(q.Low, priorClose);
            }

            if (index >= longPeriods + 1)
            {
                double sumBP1 = 0;
                double sumBP2 = 0;
                double sumBP3 = 0;

                double sumTR1 = 0;
                double sumTR2 = 0;
                double sumTR3 = 0;

                for (int p = index - longPeriods; p < index; p++)
                {
                    int pIndex = p + 1;

                    // short aggregate
                    if (pIndex > index - shortPeriods)
                    {
                        sumBP1 += bp[p];
                        sumTR1 += tr[p];
                    }

                    // middle aggregate
                    if (pIndex > index - middlePeriods)
                    {
                        sumBP2 += bp[p];
                        sumTR2 += tr[p];
                    }

                    // long aggregate
                    sumBP3 += bp[p];
                    sumTR3 += tr[p];
                }

                double?avg1 = (sumTR1 == 0) ? null : sumBP1 / sumTR1;
                double?avg2 = (sumTR2 == 0) ? null : sumBP2 / sumTR2;
                double?avg3 = (sumTR3 == 0) ? null : sumBP3 / sumTR3;

                r.Ultimate = (decimal?)(100d * ((4d * avg1) + (2d * avg2) + avg3) / 7d);
            }

            priorClose = q.Close;
        }

        return(results);
    }
Example #9
0
    // MONEY FLOW INDEX
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <MfiResult> GetMfi <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 14)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateMfi(lookbackPeriods);

        // initialize
        int length = quotesList.Count;
        List <MfiResult> results = new(length);

        double[] tp        = new double[length]; // true price
        double[] mf        = new double[length]; // raw MF value
        int[]    direction = new int[length];    // direction

        double?prevTP = null;

        // roll through quotes, to get preliminary data
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q = quotesList[i];

            MfiResult result = new()
            {
                Date = q.Date
            };

            // true price
            tp[i] = (q.High + q.Low + q.Close) / 3;

            // raw money flow
            mf[i] = tp[i] * q.Volume;

            // direction
            if (prevTP == null || tp[i] == prevTP)
            {
                direction[i] = 0;
            }
            else if (tp[i] > prevTP)
            {
                direction[i] = 1;
            }
            else if (tp[i] < prevTP)
            {
                direction[i] = -1;
            }

            results.Add(result);

            prevTP = tp[i];
        }

        // add money flow index
        for (int i = lookbackPeriods; i < results.Count; i++)
        {
            MfiResult r     = results[i];
            int       index = i + 1;

            double sumPosMFs = 0;
            double sumNegMFs = 0;

            for (int p = index - lookbackPeriods; p < index; p++)
            {
                if (direction[p] == 1)
                {
                    sumPosMFs += mf[p];
                }
                else if (direction[p] == -1)
                {
                    sumNegMFs += mf[p];
                }
            }

            // handle no negative case
            if (sumNegMFs == 0)
            {
                r.Mfi = 100;
                continue;
            }

            // calculate MFI normally
            decimal mfRatio = (decimal)(sumPosMFs / sumNegMFs);

            r.Mfi = 100 - (100 / (1 + mfRatio));
        }

        return(results);
    }
Example #10
0
    // STOCHASTIC MOMENTUM INDEX
    /// <include file='./info.xml' path='indicator/type[@name="Main"]/*' />
    ///
    public static IEnumerable <SmiResult> GetSmi <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods,
        int firstSmoothPeriods,
        int secondSmoothPeriods,
        int signalPeriods = 3)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateSmi(
            lookbackPeriods,
            firstSmoothPeriods,
            secondSmoothPeriods,
            signalPeriods);

        // initialize
        int length = quotesList.Count;
        List <SmiResult> results = new(length);

        double k1 = 2d / (firstSmoothPeriods + 1);
        double k2 = 2d / (secondSmoothPeriods + 1);
        double kS = 2d / (signalPeriods + 1);

        double lastSmEma1 = 0;
        double lastSmEma2 = 0;
        double lastHlEma1 = 0;
        double lastHlEma2 = 0;
        double lastSignal = 0;

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            SmiResult r = new()
            {
                Date = q.Date
            };

            if (index >= lookbackPeriods)
            {
                double hH = double.MinValue;
                double lL = double.MaxValue;

                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    QuoteD x = quotesList[p];

                    if (x.High > hH)
                    {
                        hH = x.High;
                    }

                    if (x.Low < lL)
                    {
                        lL = x.Low;
                    }
                }

                double sm = q.Close - (0.5d * (hH + lL));
                double hl = hH - lL;

                // initialize last EMA values
                if (index == lookbackPeriods)
                {
                    lastSmEma1 = sm;
                    lastSmEma2 = lastSmEma1;
                    lastHlEma1 = hl;
                    lastHlEma2 = lastHlEma1;
                }

                // first smoothing
                double smEma1 = lastSmEma1 + (k1 * (sm - lastSmEma1));
                double hlEma1 = lastHlEma1 + (k1 * (hl - lastHlEma1));

                // second smoothing
                double smEma2 = lastSmEma2 + (k2 * (smEma1 - lastSmEma2));
                double hlEma2 = lastHlEma2 + (k2 * (hlEma1 - lastHlEma2));

                // stochastic momentum index
                double smi = 100 * (smEma2 / (0.5 * hlEma2));
                r.Smi = (decimal)smi;

                // initialize signal line
                if (index == lookbackPeriods)
                {
                    lastSignal = smi;
                }

                // signal line
                double signal = lastSignal + (kS * (smi - lastSignal));
                r.Signal = (decimal)signal;

                // carryover values
                lastSmEma1 = smEma1;
                lastSmEma2 = smEma2;
                lastHlEma1 = hlEma1;
                lastHlEma2 = hlEma2;
                lastSignal = signal;
            }

            results.Add(r);
        }

        return(results);
    }
Example #11
0
    // KLINGER VOLUME OSCILLATOR
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <KvoResult> GetKvo <TQuote>(
        this IEnumerable <TQuote> quotes,
        int fastPeriods   = 34,
        int slowPeriods   = 55,
        int signalPeriods = 13)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateKlinger(fastPeriods, slowPeriods, signalPeriods);

        // initialize
        int length = quotesList.Count;
        List <KvoResult> results = new(length);

        double[]  hlc       = new double[length];   // trend basis
        double[]  t         = new double[length];   // trend direction
        double[]  dm        = new double[length];   // daily measurement
        double[]  cm        = new double[length];   // cumulative measurement
        double?[] vf        = new double?[length];  // volume force (VF)
        double?[] vfFastEma = new double?[length];  // EMA of VF (short-term)
        double?[] vfSlowEma = new double?[length];  // EMA of VP (long-term)

        // EMA multipliers
        double kFast   = 2d / (fastPeriods + 1);
        double kSlow   = 2d / (slowPeriods + 1);
        double kSignal = 2d / (signalPeriods + 1);

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            KvoResult r = new()
            {
                Date = q.Date
            };
            results.Add(r);

            // trend basis comparator
            hlc[i] = q.High + q.Low + q.Close;

            // daily measurement
            dm[i] = q.High - q.Low;

            if (i <= 0)
            {
                continue;
            }

            // trend direction
            t[i] = (hlc[i] > hlc[i - 1]) ? 1 : -1;

            if (i <= 1)
            {
                cm[i] = 0;
                continue;
            }

            // cumulative measurement
            cm[i] = (t[i] == t[i - 1]) ?
                    (cm[i - 1] + dm[i]) : (dm[i - 1] + dm[i]);

            // volume force (VF)
            vf[i] = (dm[i] == cm[i] || q.Volume == 0) ? 0
                : (dm[i] == 0) ? q.Volume * 2d * t[i] * 100d
                : (cm[i] != 0) ? q.Volume * Math.Abs(2d * ((dm[i] / cm[i]) - 1)) * t[i] * 100d
                : vf[i - 1];

            // fast-period EMA of VF
            if (index > fastPeriods + 2)
            {
                vfFastEma[i] = (vf[i] * kFast) + (vfFastEma[i - 1] * (1 - kFast));
            }
            else if (index == fastPeriods + 2)
            {
                double?sum = 0;
                for (int p = 2; p <= i; p++)
                {
                    sum += vf[p];
                }

                vfFastEma[i] = sum / fastPeriods;
            }

            // slow-period EMA of VF
            if (index > slowPeriods + 2)
            {
                vfSlowEma[i] = (vf[i] * kSlow) + (vfSlowEma[i - 1] * (1 - kSlow));
            }
            else if (index == slowPeriods + 2)
            {
                double?sum = 0;
                for (int p = 2; p <= i; p++)
                {
                    sum += vf[p];
                }

                vfSlowEma[i] = sum / slowPeriods;
            }

            // Klinger Oscillator
            if (index >= slowPeriods + 2)
            {
                r.Oscillator = vfFastEma[i] - vfSlowEma[i];

                // Signal
                if (index > slowPeriods + signalPeriods + 1)
                {
                    r.Signal = (r.Oscillator * kSignal)
                               + (results[i - 1].Signal * (1 - kSignal));
                }
                else if (index == slowPeriods + signalPeriods + 1)
                {
                    double?sum = 0;
                    for (int p = slowPeriods + 1; p <= i; p++)
                    {
                        sum += results[p].Oscillator;
                    }

                    r.Signal = sum / signalPeriods;
                }
            }
        }

        return(results);
    }
Example #12
0
    /// <include file='./info.xml' path='indicator/type[@name="Extended"]/*' />
    ///
    public static IEnumerable <StochResult> GetStoch <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods,
        int signalPeriods,
        int smoothPeriods,
        decimal kFactor,
        decimal dFactor,
        MaType movingAverageType)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateStoch(
            lookbackPeriods, signalPeriods, smoothPeriods,
            kFactor, dFactor, movingAverageType);

        // initialize
        int length = quotesList.Count;
        List <StochResult> results = new(length);

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            StochResult result = new()
            {
                Date = q.Date
            };

            if (index >= lookbackPeriods)
            {
                double?highHigh = double.MinValue;
                double?lowLow   = double.MaxValue;

                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    QuoteD x = quotesList[p];

                    if (x.High > highHigh)
                    {
                        highHigh = x.High;
                    }

                    if (x.Low < lowLow)
                    {
                        lowLow = x.Low;
                    }
                }

                result.Oscillator = lowLow != highHigh
                    ? 100 * (decimal?)((q.Close - lowLow) / (highHigh - lowLow))
                    : 0;
            }

            results.Add(result);
        }

        // smooth the oscillator
        if (smoothPeriods > 1)
        {
            results = SmoothOscillator(
                results, length, lookbackPeriods, smoothPeriods, movingAverageType);
        }

        // handle insufficient length
        if (length < lookbackPeriods - 1)
        {
            return(results);
        }

        // signal (%D) and %J
        int    signalIndex = lookbackPeriods + smoothPeriods + signalPeriods - 2;
        double?s           = (double?)results[lookbackPeriods - 1].Oscillator;

        for (int i = lookbackPeriods - 1; i < length; i++)
        {
            StochResult r     = results[i];
            int         index = i + 1;

            // add signal

            if (signalPeriods <= 1)
            {
                r.Signal = r.Oscillator;
            }

            // SMA case
            else if (index >= signalIndex && movingAverageType is MaType.SMA)
            {
                double?sumOsc = 0;
                for (int p = index - signalPeriods; p < index; p++)
                {
                    StochResult x = results[p];
                    sumOsc += (double?)x.Oscillator;
                }

                r.Signal = (decimal?)(sumOsc / signalPeriods);
            }

            // SMMA case
            else if (i >= lookbackPeriods - 1 && movingAverageType is MaType.SMMA)
            {
                s = (s == null) ? (double?)results[i].Oscillator : s; // reset if null

                s        = ((s * (signalPeriods - 1)) + (double?)results[i].Oscillator) / signalPeriods;
                r.Signal = (decimal?)s;
            }

            // %J
            r.PercentJ = (kFactor * r.Oscillator) - (dFactor * r.Signal);
        }

        return(results);
    }
Example #13
0
    // VORTEX INDICATOR
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <VortexResult> GetVortex <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateVortex(lookbackPeriods);

        // initialize
        int length = quotesList.Count;
        List <VortexResult> results = new(length);

        double[] tr  = new double[length];
        double[] pvm = new double[length];
        double[] nvm = new double[length];

        double prevHigh  = 0;
        double prevLow   = 0;
        double prevClose = 0;

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            VortexResult result = new()
            {
                Date = q.Date
            };

            // skip first period
            if (index == 1)
            {
                results.Add(result);
                prevHigh  = q.High;
                prevLow   = q.Low;
                prevClose = q.Close;
                continue;
            }

            // trend information
            double highMinusPrevClose = Math.Abs(q.High - prevClose);
            double lowMinusPrevClose  = Math.Abs(q.Low - prevClose);

            tr[i]  = Math.Max(q.High - q.Low, Math.Max(highMinusPrevClose, lowMinusPrevClose));
            pvm[i] = Math.Abs(q.High - prevLow);
            nvm[i] = Math.Abs(q.Low - prevHigh);

            prevHigh  = q.High;
            prevLow   = q.Low;
            prevClose = q.Close;

            // vortex indicator
            if (index > lookbackPeriods)
            {
                double sumTr  = 0;
                double sumPvm = 0;
                double sumNvm = 0;

                for (int p = index - lookbackPeriods; p < index; p++)
                {
                    sumTr  += tr[p];
                    sumPvm += pvm[p];
                    sumNvm += nvm[p];
                }

                if (sumTr is not 0)
                {
                    result.Pvi = sumPvm / sumTr;
                    result.Nvi = sumNvm / sumTr;
                }
            }

            results.Add(result);
        }

        return(results);
    }
Example #14
0
    // FORCE INDEX
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <ForceIndexResult> GetForceIndex <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateForceIndex(lookbackPeriods);

        // initialize
        int length = quotesList.Count;
        List <ForceIndexResult> results = new(length);
        double?prevClose = null, prevFI = null, sumRawFI = 0;
        double k = 2d / (lookbackPeriods + 1);

        // roll through quotes
        for (int i = 0; i < length; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            ForceIndexResult r = new()
            {
                Date = q.Date
            };
            results.Add(r);

            // skip first period
            if (i == 0)
            {
                prevClose = q.Close;
                continue;
            }

            // raw Force Index
            double?rawFI = q.Volume * (q.Close - prevClose);
            prevClose = q.Close;

            // calculate EMA
            if (index > lookbackPeriods + 1)
            {
                r.ForceIndex = prevFI + (k * (rawFI - prevFI));
            }

            // initialization period
            else
            {
                sumRawFI += rawFI;

                // first EMA value
                if (index == lookbackPeriods + 1)
                {
                    r.ForceIndex = sumRawFI / lookbackPeriods;
                }
            }

            prevFI = r.ForceIndex;
        }

        return(results);
    }
Example #15
0
    // SUPERTREND
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <SuperTrendResult> GetSuperTrend <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 10,
        double multiplier   = 3)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateSuperTrend(lookbackPeriods, multiplier);

        // initialize
        List <SuperTrendResult> results    = new(quotesList.Count);
        List <AtrResult>        atrResults = GetAtr(quotes, lookbackPeriods).ToList();

        bool   isBullish = true;
        double?upperBand = null;
        double?lowerBand = null;

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q = quotesList[i];

            SuperTrendResult r = new()
            {
                Date = q.Date
            };

            if (i >= lookbackPeriods - 1)
            {
                double mid       = (q.High + q.Low) / 2;
                double atr       = (double)atrResults[i].Atr;
                double prevClose = quotesList[i - 1].Close;

                // potential bands
                double upperEval = mid + (multiplier * atr);
                double lowerEval = mid - (multiplier * atr);

                // initial values
                if (i == lookbackPeriods - 1)
                {
                    isBullish = q.Close >= mid;

                    upperBand = upperEval;
                    lowerBand = lowerEval;
                }

                // new upper band
                if (upperEval < upperBand || prevClose > upperBand)
                {
                    upperBand = upperEval;
                }

                // new lower band
                if (lowerEval > lowerBand || prevClose < lowerBand)
                {
                    lowerBand = lowerEval;
                }

                // supertrend
                if (q.Close <= (isBullish ? lowerBand : upperBand))
                {
                    r.SuperTrend = (decimal?)upperBand;
                    r.UpperBand  = (decimal?)upperBand;
                    isBullish    = false;
                }
                else
                {
                    r.SuperTrend = (decimal?)lowerBand;
                    r.LowerBand  = (decimal?)lowerBand;
                    isBullish    = true;
                }
            }

            results.Add(r);
        }

        return(results);
    }
Example #16
0
    // AVERAGE DIRECTIONAL INDEX
    /// <include file='./info.xml' path='indicator/*' />
    ///
    public static IEnumerable <AdxResult> GetAdx <TQuote>(
        this IEnumerable <TQuote> quotes,
        int lookbackPeriods = 14)
        where TQuote : IQuote
    {
        // convert quotes
        List <QuoteD> quotesList = quotes.ConvertToList();

        // check parameter arguments
        ValidateAdx(lookbackPeriods);

        // initialize
        List <AdxResult> results = new(quotesList.Count);
        List <AtrResult> atr     = GetAtr(quotes, lookbackPeriods).ToList(); // get True Range info

        double prevHigh = 0;
        double prevLow  = 0;
        double prevTrs  = 0; // smoothed
        double prevPdm  = 0;
        double prevMdm  = 0;
        double prevAdx  = 0;

        double sumTr  = 0;
        double sumPdm = 0;
        double sumMdm = 0;
        double sumDx  = 0;

        // roll through quotes
        for (int i = 0; i < quotesList.Count; i++)
        {
            QuoteD q     = quotesList[i];
            int    index = i + 1;

            AdxResult result = new()
            {
                Date = q.Date
            };
            results.Add(result);

            // skip first period
            if (index == 1)
            {
                prevHigh = q.High;
                prevLow  = q.Low;
                continue;
            }

            double tr = (double)atr[i].Tr;

            double pdm1 = (q.High - prevHigh) > (prevLow - q.Low) ?
                          Math.Max(q.High - prevHigh, 0) : 0;

            double mdm1 = (prevLow - q.Low) > (q.High - prevHigh) ?
                          Math.Max(prevLow - q.Low, 0) : 0;

            prevHigh = q.High;
            prevLow  = q.Low;

            // initialization period
            if (index <= lookbackPeriods + 1)
            {
                sumTr  += tr;
                sumPdm += pdm1;
                sumMdm += mdm1;
            }

            // skip DM initialization period
            if (index <= lookbackPeriods)
            {
                continue;
            }

            // smoothed true range and directional movement
            double trs;
            double pdm;
            double mdm;

            if (index == lookbackPeriods + 1)
            {
                trs = sumTr;
                pdm = sumPdm;
                mdm = sumMdm;
            }
            else
            {
                trs = prevTrs - (prevTrs / lookbackPeriods) + tr;
                pdm = prevPdm - (prevPdm / lookbackPeriods) + pdm1;
                mdm = prevMdm - (prevMdm / lookbackPeriods) + mdm1;
            }

            prevTrs = trs;
            prevPdm = pdm;
            prevMdm = mdm;

            if (trs == 0)
            {
                continue;
            }

            // directional increments
            double pdi = 100 * pdm / trs;
            double mdi = 100 * mdm / trs;

            result.Pdi = pdi;
            result.Mdi = mdi;

            if (pdi + mdi == 0)
            {
                continue;
            }

            // calculate ADX
            double dx = 100 * Math.Abs(pdi - mdi) / (pdi + mdi);
            double adx;

            if (index > 2 * lookbackPeriods)
            {
                adx        = ((prevAdx * (lookbackPeriods - 1)) + dx) / lookbackPeriods;
                result.Adx = adx;

                double?priorAdx = results[index - lookbackPeriods].Adx;

                result.Adxr = (adx + priorAdx) / 2;
                prevAdx     = adx;
            }

            // initial ADX
            else if (index == 2 * lookbackPeriods)
            {
                sumDx     += dx;
                adx        = sumDx / lookbackPeriods;
                result.Adx = adx;
                prevAdx    = adx;
            }

            // ADX initialization period
            else
            {
                sumDx += dx;
            }
        }

        return(results);
    }