Beispiel #1
0
        // SLOPE AND LINEAR REGRESSION
        public static IEnumerable <SlopeResult> GetSlope(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // validate parameters
            ValidateSlope(history, lookbackPeriod);

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

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

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

                results.Add(r);

                // skip initialization period
                if (h.Index < lookbackPeriod)
                {
                    continue;
                }

                // get averages for period
                decimal sumX = 0m;
                decimal sumY = 0m;

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

                    sumX += (decimal)d.Index;
                    sumY += d.Close;
                }

                decimal avgX = sumX / lookbackPeriod;
                decimal avgY = sumY / lookbackPeriod;

                // least squares method
                decimal sumSqX  = 0m;
                decimal sumSqY  = 0m;
                decimal sumSqXY = 0m;

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

                    decimal devX = ((decimal)d.Index - avgX);
                    decimal devY = (d.Close - avgY);

                    sumSqX  += devX * devX;
                    sumSqY  += devY * devY;
                    sumSqXY += devX * devY;
                }

                r.Slope     = sumSqXY / sumSqX;
                r.Intercept = avgY - r.Slope * avgX;

                // calculate Standard Deviation and R-Squared
                double stdDevX = Math.Sqrt((double)sumSqX / lookbackPeriod);
                double stdDevY = Math.Sqrt((double)sumSqY / lookbackPeriod);
                r.StdDev = stdDevY;

                if (stdDevX * stdDevY != 0)
                {
                    double R = ((double)sumSqXY / (stdDevX * stdDevY)) / lookbackPeriod;
                    r.RSquared = R * R;
                }
            }

            // add last Line (y = mx + b)
            SlopeResult last = results[historyList.Count - 1];

            for (int p = last.Index - lookbackPeriod; p < last.Index; p++)
            {
                SlopeResult d = results[p];
                d.Line = last.Slope * d.Index + last.Intercept;
            }

            return(results);
        }
Beispiel #2
0
        // RATE OF CHANGE (PMO)
        public static IEnumerable <PmoResult> GetPmo(
            IEnumerable <Quote> history,
            int timePeriod      = 35,
            int smoothingPeriod = 20,
            int signalPeriod    = 10)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidatePmo(history, timePeriod, smoothingPeriod, signalPeriod);

            // initialize
            List <PmoResult> results = new List <PmoResult>();
            List <RocResult> roc     = GetRoc(history, 1).ToList();

            int     startIndex          = 0;
            decimal smoothingMultiplier = 2m / timePeriod;
            decimal smoothingConstant   = 2m / smoothingPeriod;
            decimal signalConstant      = 2m / (signalPeriod + 1);
            decimal?lastRocEma          = null;
            decimal?lastPmo             = null;
            decimal?lastSignal          = null;

            // get ROC EMA variant
            startIndex = timePeriod + 1;

            for (int i = 0; i < roc.Count; i++)
            {
                RocResult r = roc[i];

                PmoResult result = new PmoResult
                {
                    Index = r.Index,
                    Date  = r.Date
                };

                if (r.Index > startIndex)
                {
                    result.RocEma = r.Roc * smoothingMultiplier + lastRocEma * (1 - smoothingMultiplier);
                }
                else if (r.Index == startIndex)
                {
                    result.RocEma = roc
                                    .Where(x => x.Index > r.Index - timePeriod && x.Index <= r.Index)
                                    .ToList()
                                    .Select(x => x.Roc)
                                    .Average();
                }

                lastRocEma     = result.RocEma;
                result.RocEma *= 10;
                results.Add(result);
            }

            // calculate PMO
            startIndex = timePeriod + smoothingPeriod;

            for (int i = startIndex - 1; i < results.Count; i++)
            {
                PmoResult p = results[i];

                if (p.Index > startIndex)
                {
                    p.Pmo = (p.RocEma - lastPmo) * smoothingConstant + lastPmo;
                }
                else if (p.Index == startIndex)
                {
                    p.Pmo = results
                            .Where(x => x.Index > p.Index - smoothingPeriod && x.Index <= p.Index)
                            .ToList()
                            .Select(x => x.RocEma)
                            .Average();
                }

                lastPmo = p.Pmo;
            }

            // add Signal
            startIndex = timePeriod + smoothingPeriod + signalPeriod - 1;

            for (int i = startIndex - 1; i < results.Count; i++)
            {
                PmoResult p = results[i];

                if (p.Index > startIndex)
                {
                    p.Signal = (p.Pmo - lastSignal) * signalConstant + lastSignal;
                }
                else if (p.Index == startIndex)
                {
                    p.Signal = results
                               .Where(x => x.Index > p.Index - signalPeriod && x.Index <= p.Index)
                               .ToList()
                               .Select(x => x.Pmo)
                               .Average();
                }

                lastSignal = p.Signal;
            }

            return(results);
        }
Beispiel #3
0
        // STOCHASTIC OSCILLATOR
        public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod);

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

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

                if (h.Index >= lookbackPeriod)
                {
                    decimal lowLow = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                     .Select(v => v.Low)
                                     .Min();

                    decimal highHigh = history.Where(x => x.Index > (h.Index - lookbackPeriod) && x.Index <= h.Index)
                                       .Select(v => v.High)
                                       .Max();

                    if (lowLow != highHigh)
                    {
                        result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow));
                    }
                    else
                    {
                        result.Oscillator = 0;
                    }
                }
                results.Add(result);
            }


            // smooth the oscillator
            if (smoothPeriod > 1)
            {
                results = SmoothOscillator(results, lookbackPeriod, smoothPeriod);
            }


            // signal and period direction info
            decimal?lastOsc          = null;
            bool?   lastIsIncreasing = null;

            foreach (StochResult r in results
                     .Where(x => x.Index >= (lookbackPeriod + smoothPeriod - 1))
                     .OrderBy(x => x.Index))
            {
                // add signal
                if (r.Index >= lookbackPeriod + smoothPeriod + signalPeriod - 2)
                {
                    r.Signal = results.Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index)
                               .Select(v => v.Oscillator)
                               .Average();
                }

                // add direction
                if (lastOsc != null)
                {
                    if (r.Oscillator > lastOsc)
                    {
                        r.IsIncreasing = true;
                    }
                    else if (r.Oscillator < lastOsc)
                    {
                        r.IsIncreasing = false;
                    }
                    else
                    {
                        // no change, keep trend
                        r.IsIncreasing = lastIsIncreasing;
                    }
                }

                lastOsc          = (decimal)r.Oscillator;
                lastIsIncreasing = r.IsIncreasing;
            }

            return(results);
        }
Beispiel #4
0
        // CONNORS RSI
        public static IEnumerable <ConnorsRsiResult> GetConnorsRsi(
            IEnumerable <Quote> history, int rsiPeriod = 3, int streakPeriod = 2, int rankPeriod = 100)
        {
            // convert history to basic format
            IEnumerable <BasicData> bd = Cleaners.ConvertHistoryToBasic(history, "C");

            // check parameters
            ValidateConnorsRsi(bd, rsiPeriod, streakPeriod, rankPeriod);

            // initialize
            List <ConnorsRsiResult> results    = new List <ConnorsRsiResult>();
            IEnumerable <RsiResult> rsiResults = CalcRsi(bd, rsiPeriod);
            int startPeriod = Math.Max(rsiPeriod, Math.Max(streakPeriod, rankPeriod)) + 2;

            decimal?lastClose = null;
            decimal streak    = 0;

            // compose interim results
            foreach (BasicData h in bd)
            {
                ConnorsRsiResult result = new ConnorsRsiResult
                {
                    Index    = (int)h.Index,
                    Date     = h.Date,
                    RsiClose = rsiResults.Where(x => x.Index == h.Index).FirstOrDefault().Rsi
                };

                // bypass for first record
                if (lastClose == null)
                {
                    lastClose = h.Value;
                    results.Add(result);
                    continue;
                }

                // streak of up or down
                if (h.Value == lastClose)
                {
                    streak = 0;
                }
                else if (h.Value > lastClose)
                {
                    if (streak >= 0)
                    {
                        streak++;
                    }
                    else
                    {
                        streak = 1;
                    }
                }
                else // h.Value < lastClose
                {
                    if (streak <= 0)
                    {
                        streak--;
                    }
                    else
                    {
                        streak = -1;
                    }
                }

                result.Streak = streak;

                // percentile rank
                result.PeriodGain = (decimal)((lastClose <= 0) ? null : (h.Value - lastClose) / lastClose);

                if (h.Index > rankPeriod)
                {
                    IEnumerable <ConnorsRsiResult> period = results
                                                            .Where(x => x.Index >= (h.Index - rankPeriod) && x.Index < h.Index);

                    result.PercentRank = (decimal)100 * period
                                         .Where(x => x.PeriodGain < result.PeriodGain).Count() / rankPeriod;
                }

                results.Add(result);
                lastClose = h.Value;
            }

            // RSI of streak
            List <BasicData> bdStreak = results
                                        .Where(x => x.Streak != null)
                                        .Select(x => new BasicData {
                Index = null, Date = x.Date, Value = (decimal)x.Streak
            })
                                        .ToList();

            IEnumerable <RsiResult> rsiStreakResults = CalcRsi(bdStreak, streakPeriod);

            // compose final results
            foreach (ConnorsRsiResult r in results.Where(x => x.Index >= streakPeriod + 2))
            {
                r.RsiStreak = rsiStreakResults
                              .Where(x => x.Index == r.Index - 1)
                              .FirstOrDefault()
                              .Rsi;

                if (r.Index >= startPeriod)
                {
                    r.ConnorsRsi = (r.RsiClose + r.RsiStreak + r.PercentRank) / 3;
                }
            }

            return(results);
        }
Beispiel #5
0
        // ZIG ZAG
        public static IEnumerable <ZigZagResult> GetZigZag(
            IEnumerable <Quote> history, ZigZagType type = ZigZagType.Close, decimal percentChange = 5)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidateZigZag(history, percentChange);

            // initialize
            List <Quote>        historyList     = history.ToList();
            List <ZigZagResult> results         = new List <ZigZagResult>();
            decimal             changeThreshold = percentChange / 100m;
            Quote      firstQuote = historyList[0];
            ZigZagEval eval       = GetZigZagEval(type, firstQuote);

            ZigZagPoint lastPoint = new ZigZagPoint
            {
                Index     = eval.Index,
                Value     = firstQuote.Close,
                PointType = "U"
            };

            ZigZagPoint lastHighPoint = new ZigZagPoint
            {
                Index     = eval.Index,
                Value     = eval.High,
                PointType = "H"
            };

            ZigZagPoint lastLowPoint = new ZigZagPoint
            {
                Index     = eval.Index,
                Value     = eval.Low,
                PointType = "L"
            };

            int finalPointIndex = historyList.Select(x => (int)x.Index).Max();

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

                eval = GetZigZagEval(type, h);
                decimal changeUp = (eval.High - lastLowPoint.Value) / lastLowPoint.Value;
                decimal changeDn = (lastHighPoint.Value - eval.Low) / lastHighPoint.Value;

                if (changeUp >= changeThreshold && changeUp > changeDn)
                {
                    lastPoint.Index     = lastLowPoint.Index;
                    lastPoint.Value     = lastLowPoint.Value;
                    lastPoint.PointType = lastLowPoint.PointType;
                    break;
                }

                if (changeDn >= changeThreshold && changeDn > changeUp)
                {
                    lastPoint.Index     = lastHighPoint.Index;
                    lastPoint.Value     = lastHighPoint.Value;
                    lastPoint.PointType = lastHighPoint.PointType;
                    break;
                }
            }

            // add first point to results
            ZigZagResult firstResult = new ZigZagResult
            {
                Index = (int)firstQuote.Index,
                Date  = firstQuote.Date
            };

            results.Add(firstResult);

            // find and draw lines
            while (lastPoint.Index < finalPointIndex)
            {
                ZigZagPoint nextPoint     = EvaluateNextPoint(historyList, type, changeThreshold, lastPoint);
                string      lastDirection = lastPoint.PointType;

                // draw line (and reset last point)
                DrawZigZagLine(results, historyList, lastPoint, nextPoint);

                // draw retrace line (and reset last high/low point)
                DrawRetraceLine(results, lastDirection, lastLowPoint, lastHighPoint, nextPoint);
            }

            return(results);
        }
Beispiel #6
0
        // SIMPLE MOVING AVERAGE
        public static IEnumerable <SmaResult> GetSma(
            IEnumerable <Quote> history, int lookbackPeriod, bool extended = false)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidateSma(history, lookbackPeriod);

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

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

                SmaResult result = new SmaResult
                {
                    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();

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

                    // add optional extended values
                    if (extended)
                    {
                        // 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);
        }
Beispiel #7
0
        private static IEnumerable <RsiResult> CalcRsi(IEnumerable <BasicData> basicData, int lookbackPeriod = 14)
        {
            // clean data
            List <BasicData> bdList = Cleaners.PrepareBasicData(basicData).ToList();

            // check parameters
            ValidateRsi(basicData, lookbackPeriod);

            // initialize
            decimal          lastValue = bdList[0].Value;
            List <RsiResult> results   = new List <RsiResult>();

            // load gain data
            for (int i = 0; i < bdList.Count; i++)
            {
                BasicData h = bdList[i];

                RsiResult result = new RsiResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date,
                    Gain  = (h.Value > lastValue) ? h.Value - lastValue : 0,
                    Loss  = (h.Value < lastValue) ? lastValue - h.Value : 0
                };
                results.Add(result);

                lastValue = h.Value;
            }

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

            // initial first record
            decimal lastRSI = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100;

            RsiResult first = results.Where(x => x.Index == lookbackPeriod + 1).FirstOrDefault();

            first.Rsi = lastRSI;

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

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

                lastRSI = (decimal)r.Rsi;
            }

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

            // validate parameters
            ValidateAtr(history, lookbackPeriod);

            // 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;
                    result.Atrp = (h.Close == 0) ? null : (result.Atr / h.Close) * 100;
                    prevAtr     = (decimal)result.Atr;
                }
                else if (h.Index == lookbackPeriod)
                {
                    // initialize ATR
                    sumTr      += tr;
                    result.Atr  = sumTr / lookbackPeriod;
                    result.Atrp = (h.Close == 0) ? null : (result.Atr / h.Close) * 100;
                    prevAtr     = (decimal)result.Atr;
                }
                else
                {
                    // only used for periods before ATR initialization
                    sumTr += tr;
                }

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

            return(results);
        }
Beispiel #9
0
        // HULL MOVING AVERAGE
        public static IEnumerable <HmaResult> GetHma(IEnumerable <Quote> history, int lookbackPeriod)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidateHma(history, lookbackPeriod);

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

            List <WmaResult> wmaN1 = GetWma(history, lookbackPeriod).ToList();
            List <WmaResult> wmaN2 = GetWma(history, lookbackPeriod / 2).ToList();

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

                Quote sh = new Quote
                {
                    Date = h.Date
                };

                WmaResult w1 = wmaN1[i];
                WmaResult w2 = wmaN2[i];

                if (w1.Wma != null && w2.Wma != null)
                {
                    sh.Close = (decimal)(w2.Wma * 2m - w1.Wma);
                    synthHistory.Add(sh);
                }
            }

            // initialize results, add back truncated null results
            int sqN      = (int)Math.Sqrt(lookbackPeriod);
            int shiftQty = lookbackPeriod - 1;

            List <HmaResult> results = historyList
                                       .Select(x => new HmaResult
            {
                Index = (int)x.Index,
                Date  = x.Date
            })
                                       .Where(x => x.Index <= shiftQty)
                                       .ToList();

            // calculate final HMA = WMA with period SQRT(n)
            List <HmaResult> hmaResults = GetWma(synthHistory, sqN)
                                          .Select(x => new HmaResult
            {
                Index = x.Index + shiftQty,
                Date  = x.Date,
                Hma   = x.Wma
            })
                                          .ToList();

            // add WMA to results
            results.AddRange(hmaResults);
            results = results.OrderBy(x => x.Index).ToList();

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

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

            // initialize
            List <Quote>          historyList = history.ToList();
            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
                if (h.Index >= signalPeriod)
                {
                    List <Quote> tenkanPeriod = historyList
                                                .Where(x => x.Index > (h.Index - signalPeriod) && x.Index <= h.Index)
                                                .ToList();

                    decimal max = tenkanPeriod.Select(x => x.High).Max();
                    decimal min = tenkanPeriod.Select(x => x.Low).Min();

                    result.TenkanSen = (min + max) / 2;
                }

                // kijun-sen base line
                if (h.Index >= shortSpanPeriod)
                {
                    List <Quote> kijunPeriod = historyList
                                               .Where(x => x.Index > (h.Index - shortSpanPeriod) && x.Index <= h.Index)
                                               .ToList();

                    decimal max = kijunPeriod.Select(x => x.High).Max();
                    decimal min = kijunPeriod.Select(x => x.Low).Min();

                    result.KijunSen = (min + max) / 2;
                }

                // 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
                if (h.Index >= shortSpanPeriod + longSpanPeriod)
                {
                    List <Quote> senkauPeriod = historyList
                                                .Where(x => x.Index > (h.Index - shortSpanPeriod - longSpanPeriod) &&
                                                       x.Index <= h.Index - shortSpanPeriod)
                                                .ToList();

                    decimal max = senkauPeriod.Select(x => x.High).Max();
                    decimal min = senkauPeriod.Select(x => x.Low).Min();

                    result.SenkauSpanB = (min + max) / 2;
                }

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

            return(results);
        }
Beispiel #11
0
        private static IEnumerable <RsiResult> CalcRsi(IEnumerable <BasicData> basicData, int lookbackPeriod = 14)
        {
            // clean data
            basicData = Cleaners.PrepareBasicData(basicData);

            // check parameters
            ValidateRsi(basicData, lookbackPeriod);

            // initialize
            decimal          lastValue = basicData.First().Value;
            List <RsiResult> results   = new List <RsiResult>();

            // load gain data
            foreach (BasicData h in basicData)
            {
                RsiResult result = new RsiResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date,
                    Gain  = (h.Value > lastValue) ? h.Value - lastValue : 0,
                    Loss  = (h.Value < lastValue) ? lastValue - h.Value : 0
                };
                results.Add(result);

                lastValue = h.Value;
            }

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

            // initial first record
            decimal lastRSI          = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100;
            bool?   lastIsIncreasing = null;

            RsiResult first = results.Where(x => x.Index == lookbackPeriod + 1).FirstOrDefault();

            first.Rsi = lastRSI;

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

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

                if (r.Rsi > lastRSI)
                {
                    r.IsIncreasing = true;
                }
                else if (r.Rsi < lastRSI)
                {
                    r.IsIncreasing = false;
                }
                else
                {
                    // no change, keep trend
                    r.IsIncreasing = lastIsIncreasing;
                }

                lastRSI          = (decimal)r.Rsi;
                lastIsIncreasing = r.IsIncreasing;
            }

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

            // validate parameters
            ValidateStochRsi(history, lookbackPeriod);

            // 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;
            bool? lastIsIncreasing = null;

            foreach (StochRsiResult r in results.Where(x => x.Index >= 2 * lookbackPeriod).OrderBy(d => d.Index))
            {
                if (r.Index >= 2 * lookbackPeriod + 1)
                {
                    if (r.StochRsi > lastRSI)
                    {
                        r.IsIncreasing = true;
                    }
                    else if (r.StochRsi < lastRSI)
                    {
                        r.IsIncreasing = false;
                    }
                    else
                    {
                        // no change, keep trend
                        r.IsIncreasing = lastIsIncreasing;
                    }
                }

                lastRSI          = r.StochRsi;
                lastIsIncreasing = r.IsIncreasing;
            }

            return(results);
        }
Beispiel #13
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
            IEnumerable <EmaResult> emaFast = GetEma(history, fastPeriod);
            IEnumerable <EmaResult> emaSlow = GetEma(history, slowPeriod);

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

            foreach (Quote h in history)
            {
                EmaResult df = emaFast.Where(x => x.Date == h.Date).FirstOrDefault();
                EmaResult ds = emaSlow.Where(x => x.Date == h.Date).FirstOrDefault();

                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
                    Quote diff = new Quote
                    {
                        Date  = h.Date,
                        Index = h.Index - slowPeriod,
                        Close = macd
                    };

                    emaDiff.Add(diff);
                }

                results.Add(result);
            }

            IEnumerable <EmaResult> emaSignal = GetEma(emaDiff, signalPeriod);
            decimal?prevMacd   = null;
            decimal?prevSignal = null;


            // add signal, histogram to result
            foreach (MacdResult r in results)
            {
                EmaResult ds = emaSignal.Where(x => x.Date == r.Date).FirstOrDefault();

                if (ds?.Ema == null)
                {
                    continue;
                }

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

                // trend and divergence
                if (prevMacd != null && prevSignal != null)
                {
                    r.IsBullish   = (r.Macd > r.Signal);
                    r.IsDiverging = (Math.Abs((decimal)r.Macd - (decimal)r.Signal)
                                     > Math.Abs((decimal)prevMacd - (decimal)prevSignal));
                }

                // store for next iteration
                prevMacd   = r.Macd;
                prevSignal = r.Signal;
            }

            return(results);
        }
Beispiel #14
0
        // Money Flow Index
        public static IEnumerable <MfiResult> GetMfi(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateMfi(history, lookbackPeriod);

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

            decimal?prevTP = null;

            // preliminary data
            for (int i = 0; i < historyList.Count; i++)
            {
                Quote h = historyList[i];

                MfiResult result = new MfiResult
                {
                    Index     = (int)h.Index,
                    Date      = h.Date,
                    TruePrice = (h.High + h.Low + h.Close) / 3
                };

                // raw money flow
                result.RawMF = result.TruePrice * h.Volume;

                // direction
                if (prevTP == null || result.TruePrice == prevTP)
                {
                    result.Direction = 0;
                }
                else if (result.TruePrice > prevTP)
                {
                    result.Direction = 1;
                }
                else if (result.TruePrice < prevTP)
                {
                    result.Direction = -1;
                }

                results.Add(result);

                prevTP = result.TruePrice;
            }

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

                decimal sumPosMFs = 0;
                decimal sumNegMFs = 0;

                for (int p = r.Index - lookbackPeriod; p < r.Index; p++)
                {
                    MfiResult d = results[p];

                    if (d.Direction == 1)
                    {
                        sumPosMFs += d.RawMF;
                    }
                    else if (d.Direction == -1)
                    {
                        sumNegMFs += d.RawMF;
                    }
                }

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

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

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

            return(results);
        }
        // CORRELATION COEFFICIENT
        public static IEnumerable <CorrResult> GetCorrelation(
            IEnumerable <Quote> historyA, IEnumerable <Quote> historyB, int lookbackPeriod)
        {
            // clean quotes
            List <Quote> historyListA = Cleaners.PrepareHistory(historyA).ToList();
            List <Quote> historyListB = Cleaners.PrepareHistory(historyB).ToList();

            // validate parameters
            ValidateCorrelation(historyA, historyB, lookbackPeriod);

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


            // roll through history for interim data
            for (int i = 0; i < historyListA.Count; i++)
            {
                Quote a = historyListA[i];
                Quote b = historyListB[i];

                if (a.Date != b.Date)
                {
                    throw new BadHistoryException(
                              "Date sequence does not match.  Correlation requires matching dates in provided histories.");
                }

                CorrResult r = new CorrResult
                {
                    Index   = (int)a.Index,
                    Date    = a.Date,
                    PriceA  = a.Close,
                    PriceB  = b.Close,
                    PriceA2 = a.Close * a.Close,
                    PriceB2 = b.Close * b.Close,
                    PriceAB = a.Close * b.Close
                };

                results.Add(r);

                // compute correlation
                if (i + 1 >= lookbackPeriod)
                {
                    decimal sumPriceA  = 0m;
                    decimal sumPriceB  = 0m;
                    decimal sumPriceA2 = 0m;
                    decimal sumPriceB2 = 0m;
                    decimal sumPriceAB = 0m;

                    for (int p = r.Index - lookbackPeriod; p < r.Index; p++)
                    {
                        CorrResult d = results[p];

                        sumPriceA  += d.PriceA;
                        sumPriceB  += d.PriceB;
                        sumPriceA2 += d.PriceA2;
                        sumPriceB2 += d.PriceB2;
                        sumPriceAB += d.PriceAB;
                    }

                    decimal avgA  = sumPriceA / lookbackPeriod;
                    decimal avgB  = sumPriceB / lookbackPeriod;
                    decimal avgA2 = sumPriceA2 / lookbackPeriod;
                    decimal avgB2 = sumPriceB2 / lookbackPeriod;
                    decimal avgAB = sumPriceAB / lookbackPeriod;

                    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));
                    r.RSquared    = r.Correlation * r.Correlation;
                }
            }

            return(results);
        }
        // ULTIMATE OSCILLATOR
        public static IEnumerable <UltimateResult> GetUltimate(
            IEnumerable <Quote> history, int shortPeriod = 7, int middlePeriod = 14, int longPeriod = 28)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateUltimate(history, shortPeriod, middlePeriod, longPeriod);

            // initialize
            List <UltimateResult> results = new List <UltimateResult>();
            decimal priorClose            = 0;

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

                UltimateResult r = new UltimateResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date
                };
                results.Add(r);

                if (i > 0)
                {
                    r.Bp = h.Close - Math.Min(h.Low, priorClose);
                    r.Tr = Math.Max(h.High, priorClose) - Math.Min(h.Low, priorClose);
                }

                if (h.Index >= longPeriod + 1)
                {
                    decimal sumBP1 = 0m;
                    decimal sumBP2 = 0m;
                    decimal sumBP3 = 0m;

                    decimal sumTR1 = 0m;
                    decimal sumTR2 = 0m;
                    decimal sumTR3 = 0m;

                    for (int p = (int)h.Index - longPeriod; p < h.Index; p++)
                    {
                        UltimateResult pr = results[p];

                        // short aggregate
                        if (pr.Index > h.Index - shortPeriod)
                        {
                            sumBP1 += (decimal)pr.Bp;
                            sumTR1 += (decimal)pr.Tr;
                        }

                        // middle aggregate
                        if (pr.Index > h.Index - middlePeriod)
                        {
                            sumBP2 += (decimal)pr.Bp;
                            sumTR2 += (decimal)pr.Tr;
                        }

                        // long aggregate
                        sumBP3 += (decimal)pr.Bp;
                        sumTR3 += (decimal)pr.Tr;
                    }

                    decimal avg1 = sumBP1 / sumTR1;
                    decimal avg2 = sumBP2 / sumTR2;
                    decimal avg3 = sumBP3 / sumTR3;

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

                priorClose = h.Close;
            }

            return(results);
        }
Beispiel #17
0
        // SIMPLE MOVING AVERAGE
        public static IEnumerable <SmaResult> GetSma(
            IEnumerable <Quote> history, int lookbackPeriod, bool extended = false)
        {
            // clean quotes
            List <Quote> historyList = Cleaners.PrepareHistory(history).ToList();

            // check parameters
            ValidateSma(history, lookbackPeriod);

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

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

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

                if (h.Index >= lookbackPeriod)
                {
                    decimal sumSma = 0m;
                    for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++)
                    {
                        Quote d = historyList[p];
                        sumSma += d.Close;
                    }

                    result.Sma = sumSma / lookbackPeriod;

                    // add optional extended values
                    if (extended)
                    {
                        decimal sumMad  = 0m;
                        decimal sumMse  = 0m;
                        decimal sumMape = 0m;

                        for (int p = (int)h.Index - lookbackPeriod; p < h.Index; p++)
                        {
                            Quote d = historyList[p];
                            sumMad  += Math.Abs(d.Close - (decimal)result.Sma);
                            sumMse  += (d.Close - (decimal)result.Sma) * (d.Close - (decimal)result.Sma);
                            sumMape += Math.Abs(d.Close - (decimal)result.Sma) / d.Close;
                        }

                        // mean absolute deviation
                        result.Mad = sumMad / lookbackPeriod;

                        // mean squared error
                        result.Mse = sumMse / lookbackPeriod;

                        // mean absolute percent error
                        result.Mape = sumMape / lookbackPeriod;
                    }
                }

                results.Add(result);
            }

            return(results);
        }
Beispiel #18
0
        // STOCHASTIC OSCILLATOR
        public static IEnumerable <StochResult> GetStoch(IEnumerable <Quote> history, int lookbackPeriod = 14, int signalPeriod = 3, int smoothPeriod = 3)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // validate parameters
            ValidateStoch(history, lookbackPeriod, signalPeriod, smoothPeriod);

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

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

                StochResult result = new StochResult
                {
                    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();

                    decimal lowLow   = period.Select(v => v.Low).Min();
                    decimal highHigh = period.Select(v => v.High).Max();

                    if (lowLow != highHigh)
                    {
                        result.Oscillator = 100 * ((h.Close - lowLow) / (highHigh - lowLow));
                    }
                    else
                    {
                        result.Oscillator = 0;
                    }
                }
                results.Add(result);
            }


            // smooth the oscillator
            if (smoothPeriod > 1)
            {
                results = SmoothOscillator(results, lookbackPeriod, smoothPeriod);
            }


            // signal and period direction info
            int stochIndex = lookbackPeriod + smoothPeriod - 1;

            foreach (StochResult r in results.Where(x => x.Index >= stochIndex))
            {
                // add signal
                int signalIndex = lookbackPeriod + smoothPeriod + signalPeriod - 2;

                if (signalPeriod <= 1)
                {
                    r.Signal = r.Oscillator;
                }
                else if (r.Index >= signalIndex)
                {
                    r.Signal = results
                               .Where(x => x.Index > (r.Index - signalPeriod) && x.Index <= r.Index)
                               .ToList()
                               .Select(v => v.Oscillator)
                               .Average();
                }
            }

            return(results);
        }
        // PARABOLIC SAR
        public static IEnumerable <ParabolicSarResult> GetParabolicSar(
            IEnumerable <Quote> history,
            decimal accelerationStep      = (decimal)0.02,
            decimal maxAccelerationFactor = (decimal)0.2)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // check parameters
            ValidateParabolicSar(history, accelerationStep, maxAccelerationFactor);

            // initialize
            List <Quote> historyList          = history.ToList();
            List <ParabolicSarResult> results = new List <ParabolicSarResult>();
            Quote first = historyList[0];

            decimal accelerationFactor = accelerationStep;
            decimal extremePoint       = first.High;
            decimal priorSar           = first.Low;
            bool    isRising           = true; // initial guess

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

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

                // skip first one
                if (h.Index == 1)
                {
                    results.Add(result);
                    continue;
                }

                // was rising
                if (isRising)
                {
                    decimal currentSar = priorSar + accelerationFactor * (extremePoint - priorSar);

                    // turn down
                    if (h.Low < currentSar)
                    {
                        result.IsReversal = true;
                        result.Sar        = extremePoint;

                        isRising           = false;
                        accelerationFactor = accelerationStep;
                        extremePoint       = h.Low;
                    }

                    // continue rising
                    else
                    {
                        result.IsReversal = false;
                        result.Sar        = currentSar;

                        // SAR cannot be higher than last two lows
                        if (i >= 2)
                        {
                            decimal minLastTwo = Math.Min(historyList[i - 1].Low, historyList[i - 2].Low);

                            result.Sar = Math.Min((decimal)result.Sar, minLastTwo);
                        }
                        else
                        {
                            result.Sar = (decimal)result.Sar;
                        }

                        if (h.High > extremePoint)
                        {
                            extremePoint       = h.High;
                            accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor);
                        }
                    }
                }

                // was falling
                else
                {
                    decimal currentSar = priorSar - accelerationFactor * (priorSar - extremePoint);

                    // turn up
                    if (h.High > currentSar)
                    {
                        result.IsReversal = true;
                        result.Sar        = extremePoint;

                        isRising           = true;
                        accelerationFactor = accelerationStep;
                        extremePoint       = h.High;
                    }

                    // continue falling
                    else
                    {
                        result.IsReversal = false;
                        result.Sar        = currentSar;

                        // SAR cannot be lower than last two highs
                        if (i >= 2)
                        {
                            decimal maxLastTwo = Math.Max(historyList[i - 1].High, historyList[i - 2].High);

                            result.Sar = Math.Max((decimal)result.Sar, maxLastTwo);
                        }
                        else
                        {
                            result.Sar = (decimal)result.Sar;
                        }

                        if (h.Low < extremePoint)
                        {
                            extremePoint       = h.Low;
                            accelerationFactor = Math.Min(accelerationFactor += accelerationStep, maxAccelerationFactor);
                        }
                    }
                }

                priorSar = (decimal)result.Sar;

                results.Add(result);
            }

            // remove first trend to reversal, since it is an invalid guess
            ParabolicSarResult firstReversal = results
                                               .Where(x => x.IsReversal == true)
                                               .OrderBy(x => x.Index)
                                               .FirstOrDefault();

            if (firstReversal != null)
            {
                foreach (ParabolicSarResult r in results.Where(x => x.Index <= firstReversal.Index))
                {
                    r.Sar        = null;
                    r.IsReversal = null;
                }
            }

            return(results);
        }
Beispiel #20
0
        // AVERAGE DIRECTIONAL INDEX
        public static IEnumerable <AdxResult> GetAdx(IEnumerable <Quote> history, int lookbackPeriod = 14)
        {
            // clean quotes
            Cleaners.PrepareHistory(history);

            // verify parameters
            ValidateAdx(history, lookbackPeriod);

            // initialize results and working variables
            List <Quote>     historyList = history.ToList();
            List <AdxResult> results     = new List <AdxResult>();
            List <AtrResult> atrResults  = GetAtr(history, lookbackPeriod).ToList(); // uses True Range value

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

            decimal sumTr  = 0;
            decimal sumPdm = 0;
            decimal sumMdm = 0;
            decimal sumDx  = 0;

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

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

                // skip first period
                if (h.Index == 1)
                {
                    results.Add(result);
                    prevHigh = h.High;
                    prevLow  = h.Low;
                    continue;
                }

                decimal tr   = (decimal)atrResults[i].Tr;
                decimal pdm1 = (h.High - prevHigh) > (prevLow - h.Low) ? Math.Max(h.High - prevHigh, 0) : 0;
                decimal mdm1 = (prevLow - h.Low) > (h.High - prevHigh) ? Math.Max(prevLow - h.Low, 0) : 0;

                prevHigh = h.High;
                prevLow  = h.Low;

                // initialization period
                if (h.Index <= lookbackPeriod + 1)
                {
                    sumTr  += tr;
                    sumPdm += pdm1;
                    sumMdm += mdm1;
                }

                // skip DM initialization period
                if (h.Index <= lookbackPeriod)
                {
                    results.Add(result);
                    continue;
                }


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

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

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


                // directional increments
                decimal pdi = 100 * pdm / trs;
                decimal mdi = 100 * mdm / trs;
                decimal dx  = 100 * Math.Abs(pdi - mdi) / (pdi + mdi);

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


                // calculate ADX
                decimal adx;

                if (h.Index > 2 * lookbackPeriod)
                {
                    adx        = (prevAdx * (lookbackPeriod - 1) + dx) / lookbackPeriod;
                    result.Adx = adx;
                    prevAdx    = adx;
                }

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

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

                results.Add(result);
            }

            return(results);
        }
Beispiel #21
0
        // HEIKIN-ASHI
        public static IEnumerable <HeikinAshiResult> GetHeikinAshi(IEnumerable <Quote> history)
        {
            // clean quotes
            history = Cleaners.PrepareHistory(history);

            // check parameters
            ValidateHeikinAshi(history);

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

            decimal?prevOpen  = null;
            decimal?prevClose = null;
            bool    prevTrend = false;

            foreach (Quote h in history)
            {
                // close
                decimal close = (h.Open + h.High + h.Low + h.Close) / 4;

                // open
                decimal open = (prevOpen == null) ? (h.Open + h.Close) / 2 : (decimal)(prevOpen + prevClose) / 2;

                // high
                decimal[] arrH = { h.High, open, close };
                decimal   high = arrH.Max();

                // low
                decimal[] arrL = { h.Low, open, close };
                decimal   low  = arrL.Min();

                // trend (bullish (buy / green), bearish (sell / red)
                // strength (size of directional shadow / no shadow is strong)
                bool    trend;
                decimal strength;

                if (close > open)
                {
                    trend    = true;
                    strength = open - low;
                }
                else if (close < open)
                {
                    trend    = false;
                    strength = high - open;
                }
                else
                {
                    trend    = prevTrend;
                    strength = high - low;
                }

                HeikinAshiResult result = new HeikinAshiResult
                {
                    Index     = (int)h.Index,
                    Date      = h.Date,
                    Open      = open,
                    High      = high,
                    Low       = low,
                    Close     = close,
                    IsBullish = trend,
                    Weakness  = strength,
                };
                results.Add(result);

                // save for next iteration
                prevOpen  = open;
                prevClose = close;
                prevTrend = trend;
            }

            return(results);
        }
Beispiel #22
0
        private static IEnumerable <RsiResult> CalcRsi(IEnumerable <BasicData> basicData, int lookbackPeriod = 14)
        {
            // clean data
            List <BasicData> bdList = Cleaners.PrepareBasicData(basicData).ToList();

            // check parameters
            ValidateRsi(basicData, lookbackPeriod);

            // initialize
            decimal          lastValue = bdList[0].Value;
            decimal          avgGain   = 0m;
            decimal          avgLoss   = 0m;
            List <RsiResult> results   = new List <RsiResult>();

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

                RsiResult r = new RsiResult
                {
                    Index = (int)h.Index,
                    Date  = h.Date,
                    Gain  = (h.Value > lastValue) ? h.Value - lastValue : 0,
                    Loss  = (h.Value < lastValue) ? lastValue - h.Value : 0
                };
                results.Add(r);
                lastValue = h.Value;

                // calculate RSI
                if (h.Index > lookbackPeriod + 1)
                {
                    avgGain = (avgGain * (lookbackPeriod - 1) + r.Gain) / lookbackPeriod;
                    avgLoss = (avgLoss * (lookbackPeriod - 1) + r.Loss) / lookbackPeriod;

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

                // initialize average gain
                else if (h.Index == lookbackPeriod + 1)
                {
                    decimal sumGain = 0;
                    decimal sumLoss = 0;

                    for (int p = 0; p < lookbackPeriod; p++)
                    {
                        RsiResult d = results[p];
                        sumGain += d.Gain;
                        sumLoss += d.Loss;
                    }
                    avgGain = sumGain / lookbackPeriod;
                    avgLoss = sumLoss / lookbackPeriod;

                    r.Rsi = (avgLoss > 0) ? 100 - (100 / (1 + (avgGain / avgLoss))) : 100;
                }
            }

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

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

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

            // 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);
        }