예제 #1
0
        // EXPONENTIAL MOVING AVERAGE
        public static IEnumerable <EmaResult> GetEma(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // initialize results
            List <EmaResult> results = new List <EmaResult>();

            // initialize EMA
            decimal k       = 2 / (decimal)(lookbackPeriod + 1);
            decimal lastEma = history
                              .Where(x => x.Index < lookbackPeriod)
                              .Select(x => x.Close)
                              .Average();

            // roll through history
            foreach (Quote h in history)
            {
                EmaResult result = new EmaResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    result.Ema = lastEma + k * (h.Close - lastEma);
                    lastEma    = (decimal)result.Ema;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #2
0
        // RATE OF CHANGE (ROC)
        public static IEnumerable <RocResult> GetRoc(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateRoc(history, lookbackPeriod);

            // initialize
            List <RocResult> results = new List <RocResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                RocResult result = new RocResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index > lookbackPeriod)
                {
                    Quote back = historyList[(int)h.Index - lookbackPeriod - 1];
                    result.Roc = 100 * (h.Close - back.Close) / back.Close;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #3
0
        // RATE OF CHANGE (ROC)
        public static IEnumerable <RocResult> GetRoc(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateRoc(history, lookbackPeriod);

            // initialize
            List <RocResult> results = new List <RocResult>();

            // roll through history
            foreach (Quote h in history)
            {
                RocResult result = new RocResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index > lookbackPeriod)
                {
                    Quote back = history
                                 .Where(x => x.Index == h.Index - lookbackPeriod)
                                 .FirstOrDefault();

                    result.Roc = 100 * (h.Close - back.Close) / back.Close;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #4
0
        // BETA COEFFICIENT
        public static IEnumerable <BetaResult> GetBeta(
            IEnumerable <Quote> historyMarket, IEnumerable <Quote> historyEval, int lookbackPeriod)
        {
            // clean quotes
            historyMarket = Cleaners.PrepareHistory(historyMarket);
            historyEval   = Cleaners.PrepareHistory(historyEval);

            // initialize results
            List <BetaResult> results = new List <BetaResult>();

            // get prerequisite data
            IEnumerable <CorrResult> correlation = GetCorrelation(historyMarket, historyEval, lookbackPeriod);

            // roll through history for interim data
            foreach (Quote e in historyEval)
            {
                BetaResult result = new BetaResult
                {
                    Index = (int)e.Index,
                    Date  = e.Date
                };

                // calculate beta, if available
                CorrResult c = correlation.Where(x => x.Date == e.Date).FirstOrDefault();

                if (c.Covariance != null && c.VarianceA != null && c.VarianceA != 0)
                {
                    result.Beta = c.Covariance / c.VarianceA;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #5
0
        // SIMPLE MOVING AVERAGE
        public static IEnumerable <SmaResult> GetSma(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // initialize results
            List <SmaResult> results = new List <SmaResult>();

            // roll through history
            foreach (Quote h in history)
            {
                SmaResult result = new SmaResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <decimal> period = history
                                                   .Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod))
                                                   .Select(x => x.Close);

                    result.Sma = period.Average();
                }

                results.Add(result);
            }

            return(results);
        }
예제 #6
0
        // WILLIAM %R OSCILLATOR
        public static IEnumerable <WilliamResult> GetWilliamR(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateWilliam(history, lookbackPeriod);

            // initialize
            List <WilliamResult>      results = new List <WilliamResult>();
            IEnumerable <StochResult> stoch   = GetStoch(history, lookbackPeriod, 1, 1); // fast variant

            // convert Stochastic to William %R
            foreach (StochResult s in stoch)
            {
                WilliamResult result = new WilliamResult
                {
                    Index        = s.Index,
                    Date         = s.Date,
                    WilliamR     = s.Oscillator - 100,
                    IsIncreasing = s.IsIncreasing
                };
                results.Add(result);
            }

            return(results);
        }
예제 #7
0
        // CORRELATION COEFFICIENT
        public static IEnumerable <CorrResult> GetCorrelation(
            IEnumerable <Quote> historyA, IEnumerable <Quote> historyB, int lookbackPeriod)
        {
            // clean quotes
            historyA = Cleaners.PrepareHistory(historyA);
            historyB = Cleaners.PrepareHistory(historyB);

            // check exceptions
            int qtyHistory = historyA.Count();
            int minHistory = lookbackPeriod;

            if (qtyHistory < minHistory)
            {
                throw new BadHistoryException("Insufficient history provided for Correlation.  " +
                                              string.Format("You provided {0} periods of history when {1} is required.", qtyHistory, minHistory));
            }

            // initialize
            List <CorrResult> results = new List <CorrResult>();


            // roll through history for interim data
            foreach (Quote a in historyA)
            {
                Quote b = historyB.Where(x => x.Date == a.Date).FirstOrDefault();
                if (b == null)
                {
                    throw new BadHistoryException("Correlation requires matching dates in provided histories.  {0} not found in historyB.");
                }

                CorrResult result = new CorrResult
                {
                    Index  = (int)a.Index,
                    Date   = a.Date,
                    PriceA = a.Close,
                    PriceB = b.Close
                             // other values calculated in class properties
                };
                results.Add(result);
            }

            // compute correlation
            foreach (CorrResult r in results.Where(x => x.Index >= lookbackPeriod))
            {
                IEnumerable <CorrResult> period = results.Where(x => x.Index > (r.Index - lookbackPeriod) && x.Index <= r.Index);

                decimal avgA  = period.Select(x => x.PriceA).Average();
                decimal avgB  = period.Select(x => x.PriceB).Average();
                decimal avgA2 = period.Select(x => x.PriceA2).Average();
                decimal avgB2 = period.Select(x => x.PriceB2).Average();
                decimal avgAB = period.Select(x => x.PriceAB).Average();

                r.VarianceA   = avgA2 - avgA * avgA;
                r.VarianceB   = avgB2 - avgB * avgB;
                r.Covariance  = avgAB - avgA * avgB;
                r.Correlation = r.Covariance / (decimal)Math.Sqrt((double)(r.VarianceA * r.VarianceB));
            }

            return(results);
        }
예제 #8
0
        // Standard Deviation
        public static IEnumerable <StdDevResult> GetStdDev(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // initialize results
            List <StdDevResult> results = new List <StdDevResult>();


            // roll through history and compute lookback standard deviation
            foreach (Quote h in history)
            {
                StdDevResult result = new StdDevResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <double> period = history
                                                  .Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod))
                                                  .Select(x => (double)x.Close);

                    result.StdDev = (decimal)Functions.StdDev(period);
                }

                results.Add(result);
            }

            return(results);
        }
예제 #9
0
        // SIMPLE MOVING AVERAGE of VOLUME
        public static IEnumerable <VolSmaResult> GetVolSma(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes and initialize results
            List <VolSmaResult> results = Cleaners.PrepareHistory(history)
                                          .Select(x => new VolSmaResult
            {
                Index  = (int)x.Index,
                Date   = x.Date,
                Volume = x.Volume
            })
                                          .ToList();

            // check parameters
            ValidateVolSma(history, lookbackPeriod);

            // roll through history
            for (int i = lookbackPeriod - 1; i < results.Count; i++)
            {
                VolSmaResult h = results[i];

                decimal sumVolSma = 0m;
                for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++)
                {
                    VolSmaResult q = results[p];
                    sumVolSma += q.Volume;
                }

                h.VolSma = sumVolSma / lookbackPeriod;
            }

            return(results);
        }
예제 #10
0
        // MOVING AVERAGE CONVERGENCE/DIVERGENCE (MACD) OSCILLATOR
        public static IEnumerable <MacdResult> GetMacd(IEnumerable <Quote> history, int fastPeriod = 12, int slowPeriod = 26, int signalPeriod = 9)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateMacd(history, fastPeriod, slowPeriod, signalPeriod);

            // initialize
            List <Quote>     historyList = history.ToList();
            List <EmaResult> emaFast     = GetEma(history, fastPeriod).ToList();
            List <EmaResult> emaSlow     = GetEma(history, slowPeriod).ToList();

            List <BasicData>  emaDiff = new List <BasicData>();
            List <MacdResult> results = new List <MacdResult>();

            for (int i = 0; i < historyList.Count; i++)
            {
                Quote     h  = historyList[i];
                EmaResult df = emaFast[i];
                EmaResult ds = emaSlow[i];

                MacdResult result = new MacdResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (df?.Ema != null && ds?.Ema != null)
                {
                    decimal macd = (decimal)df.Ema - (decimal)ds.Ema;
                    result.Macd = macd;

                    // temp data for interim EMA of macd
                    BasicData diff = new BasicData
                    {
                        Index = h.Index - slowPeriod + 1,
                        Date  = h.Date,
                        Value = macd
                    };

                    emaDiff.Add(diff);
                }

                results.Add(result);
            }

            // add signal and histogram to result
            List <EmaResult> emaSignal = CalcEma(emaDiff, signalPeriod).ToList();

            foreach (MacdResult r in results.Where(x => x.Index >= slowPeriod))
            {
                EmaResult ds = emaSignal[r.Index - slowPeriod];

                r.Signal    = ds.Ema;
                r.Histogram = r.Macd - r.Signal;
            }

            return(results);
        }
예제 #11
0
        // ON-BALANCE VOLUME
        public static IEnumerable <AdlResult> GetAdl(IEnumerable <Quote> history)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidateAdl(history);

            // initialize
            List <AdlResult> results = new List <AdlResult>();
            decimal          prevAdl = 0;

            // get money flow multiplier
            foreach (Quote h in history)
            {
                decimal mfm = (h.High == h.Low) ? 0 : ((h.Close - h.Low) - (h.High - h.Close)) / (h.High - h.Low);
                decimal mfv = mfm * h.Volume;
                decimal adl = mfv + prevAdl;

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

                prevAdl = adl;
            }

            return(results);
        }
예제 #12
0
        // CHANDELIER EXIT
        public static IEnumerable <ChandelierResult> GetChandelier(
            IEnumerable <Quote> history, int lookbackPeriod = 22,
            decimal multiplier = 3.0m, ChandelierType type = ChandelierType.Long)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // validate inputs
            ValidateChandelier(history, lookbackPeriod, multiplier);

            // initialize
            List <Quote>            historyList = history.ToList();
            List <ChandelierResult> results     = new List <ChandelierResult>();
            List <AtrResult>        atrResult   = GetAtr(history, lookbackPeriod).ToList(); // uses ATR

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                ChandelierResult result = new ChandelierResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                // add exit values
                if (h.Index >= lookbackPeriod)
                {
                    List <Quote> period = historyList
                                          .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                          .ToList();

                    decimal atr = (decimal)atrResult[i].Atr;

                    switch (type)
                    {
                    case ChandelierType.Long:

                        decimal maxHigh = period.Select(x => x.High).Max();
                        result.ChandelierExit = maxHigh - atr * multiplier;
                        break;

                    case ChandelierType.Short:

                        decimal minLow = period.Select(x => x.Low).Min();
                        result.ChandelierExit = minLow + atr * multiplier;
                        break;

                    default:
                        break;
                    }
                }

                results.Add(result);
            }

            return(results);
        }
예제 #13
0
        // STOCHASTIC RSI
        public static IEnumerable <StochRsiResult> GetStochRsi(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check exceptions
            int qtyHistory = history.Count();
            int minHistory = 2 * lookbackPeriod;

            if (qtyHistory < minHistory)
            {
                throw new BadHistoryException("Insufficient history provided for Stochastic RSI.  " +
                                              string.Format("You provided {0} periods of history when {1} is required.", qtyHistory, minHistory));
            }

            // initialize
            List <StochRsiResult>   results    = new List <StochRsiResult>();
            IEnumerable <RsiResult> rsiResults = GetRsi(history, lookbackPeriod);


            // calculate
            foreach (Quote h in history)
            {
                StochRsiResult result = new StochRsiResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date,
                };

                if (h.Index >= 2 * lookbackPeriod)
                {
                    IEnumerable <RsiResult> period = rsiResults.Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod));
                    float?rsi     = period.Where(x => x.Index == h.Index).FirstOrDefault().Rsi;
                    float?rsiHigh = period.Select(x => x.Rsi).Max();
                    float?rsiLow  = period.Select(x => x.Rsi).Min();

                    result.StochRsi = (rsi - rsiLow) / (rsiHigh - rsiLow);
                }

                results.Add(result);
            }


            // add direction
            float?lastRSI = 0;

            foreach (StochRsiResult r in results.Where(x => x.Index >= 2 * lookbackPeriod).OrderBy(d => d.Index))
            {
                if (r.Index >= lookbackPeriod)
                {
                    r.IsIncreasing = (r.StochRsi >= lastRSI) ? true : false;
                }

                lastRSI = r.StochRsi;
            }

            return(results);
        }
예제 #14
0
        // BOLLINGER BANDS
        public static IEnumerable <BollingerBandsResult> GetBollingerBands(IEnumerable <Quote> history, int lookbackPeriod = 20, decimal standardDeviations = 2)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check exceptions
            int qtyHistory = history.Count();
            int minHistory = lookbackPeriod;

            if (qtyHistory < minHistory)
            {
                throw new BadHistoryException("Insufficient history provided for Bollinger Bands.  " +
                                              string.Format("You provided {0} periods of history when {1} is required.", qtyHistory, minHistory));
            }

            // initialize
            List <BollingerBandsResult> results = new List <BollingerBandsResult>();
            IEnumerable <SmaResult>     sma     = GetSma(history, lookbackPeriod);
            decimal?prevUpperBand = null;
            decimal?prevLowerBand = null;

            // roll through history
            foreach (Quote h in history)
            {
                BollingerBandsResult result = new BollingerBandsResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <double> periodClose = history
                                                       .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                                       .Select(x => (double)x.Close);

                    double stdDev = Functions.StdDev(periodClose);

                    result.Sma       = sma.Where(x => x.Date == h.Date).Select(x => x.Sma).FirstOrDefault();
                    result.UpperBand = result.Sma + standardDeviations * (decimal)stdDev;
                    result.LowerBand = result.Sma - standardDeviations * (decimal)stdDev;

                    if (prevUpperBand != null && prevLowerBand != null)
                    {
                        result.IsDiverging = ((decimal)result.UpperBand - (decimal)result.LowerBand) > ((decimal)prevUpperBand - (decimal)prevLowerBand) ? true : false;
                    }

                    // for next iteration
                    prevUpperBand = result.UpperBand;
                    prevLowerBand = result.LowerBand;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #15
0
        // AROON OSCILLATOR
        public static IEnumerable <AroonResult> GetAroon(IEnumerable <Quote> history, int lookbackPeriod = 25)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // validate parameters
            ValidateAroon(history, lookbackPeriod);

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

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                AroonResult result = new AroonResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                // add aroons
                if (h.Index > lookbackPeriod)
                {
                    decimal lastHighPrice = 0;
                    decimal lastLowPrice  = decimal.MaxValue;
                    int     lastHighIndex = 0;
                    int     lastLowIndex  = 0;

                    for (int p = (int)h.Index - lookbackPeriod - 1; p < h.Index; p++)
                    {
                        Quote d = historyList[p];

                        if (d.High > lastHighPrice)
                        {
                            lastHighPrice = d.High;
                            lastHighIndex = (int)d.Index;
                        }

                        if (d.Low < lastLowPrice)
                        {
                            lastLowPrice = d.Low;
                            lastLowIndex = (int)d.Index;
                        }
                    }

                    result.AroonUp    = 100 * (decimal)(lookbackPeriod - (h.Index - lastHighIndex)) / lookbackPeriod;
                    result.AroonDown  = 100 * (decimal)(lookbackPeriod - (h.Index - lastLowIndex)) / lookbackPeriod;
                    result.Oscillator = result.AroonUp - result.AroonDown;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #16
0
        // STOCHASTIC RSI
        public static IEnumerable <StochRsiResult> GetStochRsi(IEnumerable <Quote> history,
                                                               int rsiPeriod, int stochPeriod, int signalPeriod, int smoothPeriod = 1)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateStochRsi(history, rsiPeriod, stochPeriod, signalPeriod, smoothPeriod);

            // initialize
            List <StochRsiResult> results = new List <StochRsiResult>();

            // get RSI
            IEnumerable <RsiResult> rsiResults = GetRsi(history, rsiPeriod);

            // convert rsi to quote format
            List <Quote> rsiQuotes = rsiResults
                                     .Where(x => x.Rsi != null)
                                     .Select(x => new Quote
            {
                Index = null,
                Date  = x.Date,
                High  = (decimal)x.Rsi,
                Low   = (decimal)x.Rsi,
                Close = (decimal)x.Rsi
            })
                                     .ToList();

            // get Stochastic of RSI
            IEnumerable <StochResult> stoResults = GetStoch(rsiQuotes, stochPeriod, signalPeriod, smoothPeriod);

            // compose
            foreach (RsiResult r in rsiResults)
            {
                StochRsiResult result = new StochRsiResult
                {
                    Index = r.Index,
                    Date  = r.Date
                };

                if (r.Index >= rsiPeriod + stochPeriod)
                {
                    StochResult sto = stoResults
                                      .Where(x => x.Index == r.Index - stochPeriod)
                                      .FirstOrDefault();

                    result.StochRsi     = sto.Oscillator;
                    result.Signal       = sto.Signal;
                    result.IsIncreasing = sto.IsIncreasing;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #17
0
        // AVERAGE TRUE RANGE
        public static IEnumerable <AtrResult> GetAtr(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // initialize results
            List <AtrResult> results            = new List <AtrResult>();
            decimal          prevAtr            = 0;
            decimal          prevClose          = 0;
            decimal          highMinusPrevClose = 0;
            decimal          lowMinusPrevClose  = 0;
            decimal          sumTr = 0;

            // roll through history
            foreach (Quote h in history)
            {
                AtrResult result = new AtrResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index > 1)
                {
                    highMinusPrevClose = Math.Abs(h.High - prevClose);
                    lowMinusPrevClose  = Math.Abs(h.Low - prevClose);
                }

                decimal tr = Math.Max((h.High - h.Low), Math.Max(highMinusPrevClose, lowMinusPrevClose));
                result.Tr = tr;

                if (h.Index > lookbackPeriod)
                {
                    // calculate ATR
                    result.Atr = (prevAtr * (lookbackPeriod - 1) + tr) / lookbackPeriod;
                    prevAtr    = (decimal)result.Atr;
                }
                else if (h.Index == lookbackPeriod)
                {
                    // initialize ATR
                    sumTr     += tr;
                    result.Atr = sumTr / lookbackPeriod;
                    prevAtr    = (decimal)result.Atr;
                }
                else
                {
                    // only used for periods before ATR initialization
                    sumTr += tr;
                }

                results.Add(result);
                prevClose = h.Close;
            }

            return(results);
        }
예제 #18
0
        // AROON OSCILLATOR
        public static IEnumerable <AroonResult> GetAroon(IEnumerable <Quote> history, int lookbackPeriod = 25)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateAroon(history, lookbackPeriod);

            // initialize
            List <Quote>       historyList = history.ToList();
            List <AroonResult> results     = new List <AroonResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                AroonResult result = new AroonResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                // add aroons
                if (h.Index >= lookbackPeriod)
                {
                    List <Quote> period = historyList
                                          .Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod))
                                          .ToList();

                    decimal lastHighPrice = period.Select(x => x.High).Max();
                    decimal lastLowPrice  = period.Select(x => x.Low).Min();

                    int lastHighIndex = period
                                        .Where(x => x.High == lastHighPrice)
                                        .OrderBy(x => x.Index) // implies "new" high, so not picking new tie for high
                                        .Select(x => (int)x.Index)
                                        .FirstOrDefault();

                    int lastLowIndex = period
                                       .Where(x => x.Low == lastLowPrice)
                                       .OrderBy(x => x.Index)
                                       .Select(x => (int)x.Index)
                                       .FirstOrDefault();

                    result.AroonUp    = 100 * (decimal)(lookbackPeriod - (h.Index - lastHighIndex)) / lookbackPeriod;
                    result.AroonDown  = 100 * (decimal)(lookbackPeriod - (h.Index - lastLowIndex)) / lookbackPeriod;
                    result.Oscillator = result.AroonUp - result.AroonDown;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #19
0
        // DONCHIAN CHANNEL
        public static IEnumerable <DonchianResult> GetDonchian(
            IEnumerable <Quote> history, int lookbackPeriod = 20)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // validate parameters
            ValidateDonchian(history, lookbackPeriod);

            // initialize
            List <DonchianResult> results = new List <DonchianResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                DonchianResult result = new DonchianResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    decimal highHigh = 0;
                    decimal lowLow   = decimal.MaxValue;

                    for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++)
                    {
                        Quote d = historyList[p];

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

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

                    result.UpperBand  = highHigh;
                    result.LowerBand  = lowLow;
                    result.Centerline = (result.UpperBand + result.LowerBand) / 2;
                    result.Width      = (result.Centerline == 0) ? null : (result.UpperBand - result.LowerBand) / result.Centerline;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #20
0
        // ULCER INDEX (UI)
        public static IEnumerable <UlcerIndexResult> GetUlcerIndex(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // exceptions
            int qtyHistory = history.Count();
            int minHistory = lookbackPeriod;

            if (qtyHistory < minHistory)
            {
                throw new BadHistoryException("Insufficient history provided for Ulcer Index.  " +
                                              string.Format("You provided {0} periods of history when {1} is required.", qtyHistory, minHistory));
            }

            // initialize
            List <UlcerIndexResult> results = new List <UlcerIndexResult>();

            // preliminary data
            foreach (Quote h in history)
            {
                UlcerIndexResult result = new UlcerIndexResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <Quote> period = history
                                                 .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index);

                    double sumSquared = 0;

                    foreach (Quote p in period)
                    {
                        decimal maxClose = period
                                           .Where(x => x.Index <= p.Index)
                                           .Select(x => x.Close)
                                           .Max();

                        decimal percentDrawdown = 100 * (p.Close - maxClose) / maxClose;

                        sumSquared += (double)(percentDrawdown * percentDrawdown);
                    }

                    result.UI = (decimal)Math.Sqrt(sumSquared / lookbackPeriod);
                }
                results.Add(result);
            }


            return(results);
        }
        // BOLLINGER BANDS
        public static IEnumerable <BollingerBandsResult> GetBollingerBands(
            IEnumerable <Quote> history, int lookbackPeriod = 20, decimal standardDeviations = 2)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // validate parameters
            ValidateBollingerBands(history, lookbackPeriod, standardDeviations);

            // initialize
            List <BollingerBandsResult> results = new List <BollingerBandsResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                BollingerBandsResult r = new BollingerBandsResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    double[] periodClose = new double[lookbackPeriod];
                    decimal  sum         = 0m;
                    int      n           = 0;

                    for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++)
                    {
                        Quote d = historyList[p];
                        periodClose[n] = (double)d.Close;
                        sum           += d.Close;
                        n++;
                    }

                    decimal periodAvg = sum / lookbackPeriod;
                    decimal stdDev    = (decimal)Functions.StdDev(periodClose);

                    r.Sma       = periodAvg;
                    r.UpperBand = periodAvg + standardDeviations * stdDev;
                    r.LowerBand = periodAvg - standardDeviations * stdDev;

                    r.PercentB = (h.Close - r.LowerBand) / (r.UpperBand - r.LowerBand);
                    r.ZScore   = (stdDev == 0) ? null : (h.Close - r.Sma) / stdDev;
                    r.Width    = (r.Sma == 0) ? null : (r.UpperBand - r.LowerBand) / r.Sma;
                }

                results.Add(r);
            }

            return(results);
        }
예제 #22
0
        // ON-BALANCE VOLUME
        public static IEnumerable <ObvResult> GetObv(IEnumerable <Quote> history, int?smaPeriod = null)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateObv(history, smaPeriod);

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

            decimal?prevClose = null;
            decimal obv       = 0;

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

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

                prevClose = h.Close;

                // optional SMA
                if (smaPeriod != null && h.Index > smaPeriod)
                {
                    decimal sumSma = 0m;
                    for (int p = (int)h.Index - (int)smaPeriod; p < h.Index; p++)
                    {
                        sumSma += results[p].Obv;
                    }

                    result.Sma = sumSma / smaPeriod;
                }
            }

            return(results);
        }
예제 #23
0
        // BOLLINGER BANDS
        public static IEnumerable <BollingerBandsResult> GetBollingerBands(
            IEnumerable <Quote> history, int lookbackPeriod = 20, decimal standardDeviations = 2)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateBollingerBands(history, lookbackPeriod, standardDeviations);

            // initialize
            List <BollingerBandsResult> results = new List <BollingerBandsResult>();
            decimal?prevUpperBand = null;
            decimal?prevLowerBand = null;

            // roll through history
            foreach (Quote h in history)
            {
                BollingerBandsResult result = new BollingerBandsResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <double> periodClose = history
                                                       .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                                       .Select(x => (double)x.Close);

                    double stdDev = Functions.StdDev(periodClose);

                    result.Sma       = (decimal)periodClose.Average();
                    result.UpperBand = result.Sma + standardDeviations * (decimal)stdDev;
                    result.LowerBand = result.Sma - standardDeviations * (decimal)stdDev;

                    result.ZScore = (stdDev == 0) ? null : (h.Close - result.Sma) / (decimal)stdDev;
                    result.Width  = (result.Sma == 0) ? null : (result.UpperBand - result.LowerBand) / result.Sma;

                    if (prevUpperBand != null && prevLowerBand != null)
                    {
                        result.IsDiverging = ((decimal)result.UpperBand - (decimal)result.LowerBand)
                                             > ((decimal)prevUpperBand - (decimal)prevLowerBand);
                    }

                    // for next iteration
                    prevUpperBand = result.UpperBand;
                    prevLowerBand = result.LowerBand;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #24
0
        // RELATIVE STRENGTH INDEX
        public static IEnumerable <RsiResult> GetRsi(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // initialize
            decimal          lastClose = history.First().Close;
            List <RsiResult> results   = new List <RsiResult>();

            // load gain data
            foreach (Quote h in history)
            {
                RsiResult result = new RsiResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date,
                    Gain  = (lastClose < h.Close) ? (float)(h.Close - lastClose) : 0,
                    Loss  = (lastClose > h.Close) ? (float)(lastClose - h.Close) : 0
                };
                results.Add(result);

                lastClose = h.Close;
            }

            // initialize average gain
            float avgGain = results.Where(x => x.Index <= lookbackPeriod).Select(g => g.Gain).Average();
            float avgLoss = results.Where(x => x.Index <= lookbackPeriod).Select(g => g.Loss).Average();

            // initial RSI for trend analysis
            float lastRSI = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100;


            // calculate RSI
            foreach (RsiResult r in results.Where(x => x.Index >= lookbackPeriod).OrderBy(d => d.Index))
            {
                avgGain = (avgGain * (lookbackPeriod - 1) + r.Gain) / lookbackPeriod;
                avgLoss = (avgLoss * (lookbackPeriod - 1) + r.Loss) / lookbackPeriod;

                if (avgLoss > 0)
                {
                    float rs = avgGain / avgLoss;
                    r.Rsi = 100 - (100 / (1 + rs));
                }
                else
                {
                    r.Rsi = 100;
                }

                r.IsIncreasing = (r.Rsi >= lastRSI) ? true : false;
                lastRSI        = (float)r.Rsi;
            }

            return(results);
        }
예제 #25
0
        // DONCHIAN CHANNEL
        public static IEnumerable <DonchianResult> GetDonchian(
            IEnumerable <Quote> history, int lookbackPeriod = 20)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateDonchian(history, lookbackPeriod);

            // initialize
            List <DonchianResult> results = new List <DonchianResult>();
            decimal?prevWidth             = null;

            // roll through history
            foreach (Quote h in history)
            {
                DonchianResult result = new DonchianResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <Quote> period = history
                                                 .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index);

                    result.UpperBand  = period.Select(h => h.High).Max();
                    result.LowerBand  = period.Select(l => l.Low).Min();
                    result.Centerline = (result.UpperBand + result.LowerBand) / 2;
                    result.Width      = (result.Centerline == 0) ? null : (result.UpperBand - result.LowerBand) / result.Centerline;

                    if (prevWidth != null)
                    {
                        if (result.Width == prevWidth)
                        {
                            result.IsDiverging = null;
                        }
                        else
                        {
                            result.IsDiverging = (result.Width > prevWidth);
                        }
                    }

                    // for next iteration
                    prevWidth = result.Width;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #26
0
        // ICHIMOKU CLOUD
        public static IEnumerable <IchimokuResult> GetIchimoku(IEnumerable <Quote> history,
                                                               int signalPeriod = 9, int shortSpanPeriod = 26, int longSpanPeriod = 52)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateIchimoku(history, signalPeriod, shortSpanPeriod, longSpanPeriod);

            // initialize
            List <IchimokuResult> results = new List <IchimokuResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                IchimokuResult result = new IchimokuResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                // tenkan-sen conversion line
                CalcIchimokuTenkanSen(historyList, result, h, signalPeriod);

                // kijun-sen base line
                CalcIchimokuKijunSen(historyList, result, h, shortSpanPeriod);

                // senkou span A
                if (h.Index >= 2 * shortSpanPeriod)
                {
                    IchimokuResult skq = results[(int)h.Index - shortSpanPeriod - 1];

                    if (skq != null && skq.TenkanSen != null && skq.KijunSen != null)
                    {
                        result.SenkouSpanA = (skq.TenkanSen + skq.KijunSen) / 2;
                    }
                }

                // senkou span B
                CalcIchimokuSenkouB(historyList, result, h, shortSpanPeriod, longSpanPeriod);

                // chikou line
                if (h.Index + shortSpanPeriod <= historyList.Count)
                {
                    result.ChikouSpan = historyList[(int)h.Index + shortSpanPeriod - 1].Close;
                }
                results.Add(result);
            }

            return(results);
        }
예제 #27
0
        // CHAIKIN MONEY FLOW
        public static IEnumerable <CmfResult> GetCmf(IEnumerable <Quote> history, int lookbackPeriod = 20)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateCmf(history, lookbackPeriod);

            // initialize
            List <CmfResult> results    = new List <CmfResult>();
            List <AdlResult> adlResults = GetAdl(history).ToList();

            // roll through history
            for (int i = 0; i < adlResults.Count; i++)
            {
                AdlResult r = adlResults[i];

                CmfResult result = new CmfResult
                {
                    Index = r.Index,
                    Date  = r.Date,
                    MoneyFlowMultiplier = r.MoneyFlowMultiplier,
                    MoneyFlowVolume     = r.MoneyFlowVolume
                };

                if (r.Index >= lookbackPeriod)
                {
                    decimal sumMfv = 0;
                    decimal sumVol = 0;

                    for (int p = r.Index - lookbackPeriod; p < r.Index; p++)
                    {
                        Quote h = historyList[p];
                        sumVol += h.Volume;

                        AdlResult d = adlResults[p];
                        sumMfv += d.MoneyFlowVolume;
                    }

                    decimal avgMfv = sumMfv / lookbackPeriod;
                    decimal avgVol = sumVol / lookbackPeriod;

                    if (avgVol != 0)
                    {
                        result.Cmf = avgMfv / avgVol;
                    }
                }

                results.Add(result);
            }

            return(results);
        }
예제 #28
0
        // SIMPLE MOVING AVERAGE
        public static IEnumerable <ChaikinOscResult> GetChaikinOsc(
            IEnumerable <Quote> history,
            int fastPeriod = 3,
            int slowPeriod = 10)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateChaikinOsc(history, fastPeriod, slowPeriod);

            // initialize
            List <ChaikinOscResult> results    = new List <ChaikinOscResult>();
            IEnumerable <AdlResult> adlResults = GetAdl(history);


            // EMA of ADL
            IEnumerable <BasicData> adlBasicData = adlResults
                                                   .Select(x => new BasicData {
                Index = x.Index, Date = x.Date, Value = x.Adl
            });

            IEnumerable <EmaResult> adlEmaSlow = CalcEma(adlBasicData, slowPeriod);
            IEnumerable <EmaResult> adlEmaFast = CalcEma(adlBasicData, fastPeriod);


            // roll through history
            foreach (AdlResult r in adlResults)
            {
                ChaikinOscResult result = new ChaikinOscResult
                {
                    Index = r.Index,
                    Date  = r.Date,
                    MoneyFlowMultiplier = r.MoneyFlowMultiplier,
                    MoneyFlowVolume     = r.MoneyFlowVolume,
                    Adl = r.Adl
                };

                // add Oscillator
                if (r.Index >= slowPeriod)
                {
                    EmaResult f = adlEmaFast.Where(x => x.Index == r.Index).FirstOrDefault();
                    EmaResult s = adlEmaSlow.Where(x => x.Index == r.Index).FirstOrDefault();

                    result.Oscillator = f.Ema - s.Ema;
                }

                results.Add(result);
            }

            return(results);
        }
예제 #29
0
        // SIMPLE MOVING AVERAGE
        public static IEnumerable <SmaResult> GetSma(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateSma(history, lookbackPeriod);

            // initialize
            List <SmaResult> results = new List <SmaResult>();

            // roll through history
            foreach (Quote h in history)
            {
                SmaResult result = new SmaResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    IEnumerable <Quote> period = history
                                                 .Where(x => x.Index <= h.Index && x.Index > (h.Index - lookbackPeriod));

                    // simple moving average
                    result.Sma = period
                                 .Select(x => x.Close)
                                 .Average();

                    // mean absolute deviation
                    result.Mad = period
                                 .Select(x => Math.Abs(x.Close - (decimal)result.Sma))
                                 .Average();

                    // mean squared error
                    result.Mse = period
                                 .Select(x => (x.Close - (decimal)result.Sma) * (x.Close - (decimal)result.Sma))
                                 .Average();

                    // mean absolute percent error
                    result.Mape = period
                                  .Where(x => x.Close != 0)
                                  .Select(x => Math.Abs(x.Close - (decimal)result.Sma) / x.Close)
                                  .Average();
                }

                results.Add(result);
            }

            return(results);
        }
예제 #30
0
        // ULCER INDEX (UI)
        public static IEnumerable <UlcerIndexResult> GetUlcerIndex(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateUlcer(history, lookbackPeriod);

            // initialize
            List <Quote>            historyList = history.ToList();
            List <UlcerIndexResult> results     = new List <UlcerIndexResult>();

            // roll through history
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                UlcerIndexResult result = new UlcerIndexResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };

                if (h.Index >= lookbackPeriod)
                {
                    List <Quote> period = historyList
                                          .Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                          .ToList();

                    double sumSquared = 0;

                    foreach (Quote p in period)
                    {
                        decimal maxClose = period
                                           .Where(x => x.Index <= p.Index)
                                           .Select(x => x.Close)
                                           .Max();

                        decimal percentDrawdown = 100 * (p.Close - maxClose) / maxClose;

                        sumSquared += (double)(percentDrawdown * percentDrawdown);
                    }

                    result.UI = (decimal)Math.Sqrt(sumSquared / lookbackPeriod);
                }
                results.Add(result);
            }


            return(results);
        }