public static void UpdateEma(Guid eventActionId)
        {
            using (var db = new PoloniexContext())
            {
                var eventAction = db.EventActions.Include(x => x.MovingAverageEventAction).Single(x => x.EventActionId == eventActionId);

                var closingValue = db.CurrencyDataPoints
                                   .Where(x => x.CurrencyPair == eventAction.MovingAverageEventAction.CurrencyPair)
                                   .OrderByDescending(x => x.ClosingDateTime)
                                   .First();

                var prevEma = db.MovingAverages
                              .Where(x =>
                                     x.MovingAverageType == eventAction.MovingAverageEventAction.MovingAverageType &&
                                     x.CurrencyPair == eventAction.MovingAverageEventAction.CurrencyPair &&
                                     x.Interval == eventAction.MovingAverageEventAction.Interval &&
                                     x.MinutesPerInterval == eventAction.MovingAverageEventAction.MinutesPerInterval)
                              .OrderByDescending(x => x.ClosingDateTime)
                              .First();

                // -15 seconds to account for timer skew
                if (closingValue.ClosingDateTime >= prevEma.ClosingDateTime.AddSeconds(-15).AddMinutes(prevEma.MinutesPerInterval))
                {
                    var curEma = new MovingAverage()
                    {
                        MovingAverageType  = MovingAverageType.ExponentialMovingAverage,
                        CurrencyPair       = eventAction.MovingAverageEventAction.CurrencyPair,
                        Interval           = eventAction.MovingAverageEventAction.Interval,
                        MinutesPerInterval = eventAction.MovingAverageEventAction.MinutesPerInterval,
                        ClosingDateTime    = DateTime.UtcNow,
                        MovingAverageValue = MovingAverageCalculations.CalculateEma(closingValue.ClosingValue, prevEma.MovingAverageValue, eventAction.MovingAverageEventAction.Interval),
                        LastClosingValue   = closingValue.ClosingValue
                    };

                    db.MovingAverages.Add(curEma);
                    db.SaveChanges();
                }
            }
        }
        /* additional helpers */

        public static void BackFillEma(string currencyPair, int interval, int minutesPerInterval, DateTime beginDateTime, DateTime endDateTime, decimal?prevEmaSeed = null)
        {
            // add time buffer to guarantee beginDate inclusive / endDate exclusive
            var delEndDateTime   = endDateTime.AddSeconds(30);
            var delBeginDateTime = beginDateTime.AddSeconds(30);

            List <CurrencyDataPoint> dataPoints;
            List <decimal>           smaInput;
            decimal prevEma;

            using (var db = new PoloniexContext())
            {
                var delMovingAverages = db.MovingAverages
                                        .Where(x =>
                                               x.CurrencyPair == currencyPair &&
                                               x.Interval == interval &&
                                               x.MinutesPerInterval == minutesPerInterval &&
                                               x.ClosingDateTime <= delBeginDateTime &&
                                               x.ClosingDateTime >= delEndDateTime);
                db.MovingAverages.RemoveRange(delMovingAverages);
                db.SaveChanges();

                dataPoints = db.CurrencyDataPoints
                             .Where(x =>
                                    x.CurrencyPair == currencyPair &&
                                    x.ClosingDateTime <= beginDateTime &&
                                    x.ClosingDateTime >= endDateTime)
                             .ToList();

                if (prevEmaSeed == null)
                {
                    smaInput = db.CurrencyDataPoints
                               .Where(x =>
                                      x.CurrencyPair == currencyPair &&
                                      x.ClosingDateTime < endDateTime)
                               .OrderBy(x => x.ClosingDateTime)
                               .Select(x => x.ClosingValue)
                               .Take(interval)
                               .ToList();

                    prevEma = MovingAverageCalculations.CalculateSma(smaInput);
                }
                else
                {
                    prevEma = prevEmaSeed.Value;
                }
            }

            // Begin calculating
            List <MovingAverage> movingAveragesData = new List <MovingAverage>();

            for (int i = 0; i < dataPoints.Count; i++)
            {
                if (i % minutesPerInterval == 0)
                {
                    var newMovingAverage = new MovingAverage()
                    {
                        MovingAverageType  = MovingAverageType.ExponentialMovingAverage,
                        CurrencyPair       = currencyPair,
                        Interval           = interval,
                        MinutesPerInterval = minutesPerInterval,
                        ClosingDateTime    = dataPoints[i].ClosingDateTime,
                        MovingAverageValue = MovingAverageCalculations.CalculateEma(dataPoints[i].ClosingValue, prevEma, interval),
                        LastClosingValue   = dataPoints[i].ClosingValue
                    };
                    movingAveragesData.Add(newMovingAverage);
                    prevEma = newMovingAverage.MovingAverageValue;
                }
            }
            BulkInsertMovingAverages(movingAveragesData);
        }