Пример #1
0
 public void PollForEventActionsToStop()
 {
     using (var db = new PoloniexContext())
     {
         _EventActionsToStop = db.EventActions.Where(x => x.EventActionStatus == EventActionStatus.RequestToStop).ToList();
     }
 }
Пример #2
0
        public void StartEventActions()
        {
            foreach (var ea in _EventActionsToStart)
            {
                switch (ea.EventActionType)
                {
                case EventActionType.MovingAverage:
                    MovingAverageManager.InitEmaBySma(ea.EventActionId);
                    ea.Action = MovingAverageManager.UpdateEma;
                    break;

                case EventActionType.TradeSignal:
                    var currencyPair             = ea.TradeSignalEventAction.CurrencyPair;
                    var tradeSignalConfiguration = ea.TradeSignalEventAction.TradeSignalConfiguration;
                    TradeSignalManager.InitProcessEmaCrossOverSignal(currencyPair, tradeSignalConfiguration);
                    ea.Action = TradeSignalManager.ProcessEmaCrossOverSignal;
                    break;

                case EventActionType.ProcessTradeOrder:
                    ea.Action = TradeOrderManager.ProcessTradeOrders;
                    break;
                }
                var globalStateEvent = _globalStateManager.GetTaskLoop(ea.TaskId);
                var eventActions     = globalStateEvent.Item3;
                ea.EventActionStatus = EventActionStatus.Started;
                using (var db = new PoloniexContext())
                {
                    db.Entry(ea).State = EntityState.Modified;
                    db.SaveChanges();
                }
                eventActions.Add(ea);
                Logger.Write($"Started {ea.EventActionType} with eventActionId: {ea.EventActionId}", Logger.LogType.ServiceLog);
            }
        }
Пример #3
0
 public void StopTasks()
 {
     foreach (var taskLoop in _tasksToStop)
     {
         switch (taskLoop.Task.TaskType)
         {
         case "GatherTask":
             var tuple = _globalStateManager.RemoveTaskLoop(taskLoop.TaskId);
             tuple.Item2.Stop();     // stop timer (Item2 is timer)
             using (var db = new PoloniexContext())
             {
                 taskLoop.LoopStatus      = LoopStatus.Stopped;
                 db.Entry(taskLoop).State = EntityState.Modified;
                 db.SaveChanges();
             }
             var eventActions = tuple.Item3;
             foreach (var ea in eventActions)
             {
                 ea.EventActionStatus = EventActionStatus.Stopped;
                 using (var db = new PoloniexContext())
                 {
                     db.Entry(ea).State = EntityState.Modified;
                     db.SaveChanges();
                 }
                 Logger.Write($"Stopped {ea.EventActionType} with eventActionId: {ea.EventActionId}", Logger.LogType.ServiceLog);
             }
             Logger.Write($"Stopped {taskLoop.Task.TaskType} with taskId: {taskLoop.TaskId}", Logger.LogType.ServiceLog);
             break;
         }
     }
 }
Пример #4
0
 public void PollForTasksToStop()
 {
     using (var db = new PoloniexContext())
     {
         _tasksToStop = db.TaskLoops.Where(x => x.LoopStatus == LoopStatus.RequestToStop).Include(x => x.Task.GatherTask).ToList();
     }
 }
Пример #5
0
 public void StartTasks()
 {
     foreach (var taskLoop in _tasksToStart)
     {
         switch (taskLoop.Task.TaskType)
         {
         case "GatherTask":
             System.Threading.Tasks.Task.Run(() =>
             {
                 try
                 {
                     GatherTaskManager.BackFillGatherTaskData(6, taskLoop.Task.GatherTask.CurrencyPair, null, DateTime.Parse("01/01/1970"));
                 }
                 catch (Exception exception)
                 {
                     Logger.WriteException(exception);
                 }
             });
             var eventActions = new List <EventAction>();
             _globalStateManager.AddTaskLoop(taskLoop, GatherTaskManager.GetGatherTaskTimer(taskLoop.TaskId, eventActions), eventActions);
             using (var db = new PoloniexContext())
             {
                 taskLoop.LoopStatus          = LoopStatus.Started;
                 taskLoop.LoopStartedDateTime = DateTime.UtcNow;
                 db.Entry(taskLoop).State     = EntityState.Modified;
                 db.SaveChanges();
             }
             Logger.Write($"Started {taskLoop.Task.TaskType} with taskId: {taskLoop.TaskId}", Logger.LogType.ServiceLog);
             break;
         }
     }
 }
Пример #6
0
        public static Timer GetGatherTaskTimer(Guid taskId, List <EventAction> eventActions)
        {
            GatherTask gatherTask;

            using (var db = new PoloniexContext())
            {
                gatherTask = db.GatherTasks.Include(x => x.Task.TaskLoop).Single(x => x.TaskId == taskId);
            }

            return(GetGatherTaskTimer(gatherTask.CurrencyPair, gatherTask.Task.TaskLoop.SecondsPerTick, eventActions, true));
        }
Пример #7
0
 public static void Terminate()
 {
     using (var db = new PoloniexContext())
     {
         var taskLoops = db.TaskLoops.Where(x => x.LoopStatus == LoopStatus.Started || x.LoopStatus == LoopStatus.RequestToStop).ToList();
         taskLoops.ForEach(x =>
         {
             x.LoopStatus = LoopStatus.Stopped;
         });
         db.SaveChanges();
     }
 }
Пример #8
0
 public void PollForEventActionsToStart()
 {
     using (var db = new PoloniexContext())
     {
         _EventActionsToStart =
             db.EventActions
             .Where(x =>
                    x.EventActionStatus == EventActionStatus.RequestToStart &&
                    x.Task.TaskLoop.LoopStatus == LoopStatus.Started)
             .Include(x => x.MovingAverageEventAction)
             .Include(x => x.TradeSignalEventAction.TradeSignalConfiguration)
             .Include(x => x.TradeOrderEventAction)
             .ToList();
     }
 }
Пример #9
0
        public static void ProcessTradeOrders(Guid eventActionId)
        {
            using (var db = new PoloniexContext())
            {
                var currencyPair = db.EventActions.Single(x => x.EventActionId == eventActionId).TradeOrderEventAction.CurrencyPair;

                // get oldest uncompleted order
                var oldest = db.TradeSignalOrders
                             .Where(x =>
                                    x.CurrencyPair == currencyPair &&
                                    !x.IsProcessed)
                             .OrderBy(x => x.OrderRequestedDateTime)
                             .FirstOrDefault();

                if (oldest != null)
                {
                    Logger.Write($"Processing TradeSignalOrderId: {oldest.TradeSignalOrderId} for eventActionId: {eventActionId}", Logger.LogType.TransactionLog);

                    oldest.IsProcessed     = true;
                    oldest.InProgress      = true;
                    db.Entry(oldest).State = EntityState.Modified;
                    db.SaveChanges();

                    if (oldest.TradeOrderType == TradeOrderType.Buy)
                    {
                        TradeManager.BuyCurrencyFromUsdt(currencyPair, ref oldest);
                    }
                    else
                    {
                        TradeManager.SellCurrencyToUsdt(currencyPair, ref oldest);
                    }

                    oldest.OrderCompletedDateTime   = DateTime.UtcNow;
                    oldest.InProgress               = false;
                    oldest.ProcessedByEventActionId = eventActionId;
                    db.Entry(oldest).State          = EntityState.Modified;
                    db.SaveChanges();
                }
            };
        }
Пример #10
0
        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();
                }
            }
        }
Пример #11
0
        public static void InitEmaBySma(Guid eventActionId)
        {
            using (var db = new PoloniexContext())
            {
                var eventAction = db.EventActions.Include(x => x.MovingAverageEventAction).Single(x => x.EventActionId == eventActionId);

                try
                {
                    var beginDateTime = DateTime.UtcNow.AddMilliseconds(333);
                    var endDateTime   = beginDateTime.AddMinutes(-(eventAction.MovingAverageEventAction.Interval * eventAction.MovingAverageEventAction.MinutesPerInterval));

                    var currencyPair       = eventAction.MovingAverageEventAction.CurrencyPair;
                    var interval           = eventAction.MovingAverageEventAction.Interval;
                    var minutesPerInterval = eventAction.MovingAverageEventAction.MinutesPerInterval;

                    BackFillEma(currencyPair, interval, minutesPerInterval, beginDateTime, endDateTime);
                }
                catch (Exception exception)
                {
                    Logger.WriteException(exception);
                }
            }
        }
Пример #12
0
 public void StopEventActions()
 {
     foreach (var ea in _EventActionsToStop)
     {
         var globalStateEvent = _globalStateManager.GetTaskLoop(ea.TaskId);
         var eventActions     = globalStateEvent.Item3;
         for (int i = 0; i < eventActions.Count; i++)
         {
             if (eventActions[i].EventActionId == ea.EventActionId)
             {
                 eventActions.RemoveAt(i);
                 break;
             }
         }
         ea.EventActionStatus = EventActionStatus.Stopped;
         using (var db = new PoloniexContext())
         {
             db.Entry(ea).State = EntityState.Modified;
             db.SaveChanges();
         }
         Logger.Write($"Stopped {ea.EventActionType} with eventActionId: {ea.EventActionId}", Logger.LogType.ServiceLog);
     }
 }
Пример #13
0
        /* 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);
        }
Пример #14
0
        /* additional helpers */

        public static void BackFillGatherTaskData(int numberOfQuarterDays, string currencyPair, DateTime?inputDateTime = null, DateTime?markerDate = null)
        {
            markerDate = markerDate ?? DateTime.Parse("01/01/1970"); // marker date is for setting CreatedDateTime (useful for knowing which data was prepopulated)

            var totalTimeToGoBack = numberOfQuarterDays * 21600;

            var curDateTime = inputDateTime ?? DateTime.UtcNow;

            // add 30 seconds for possible processing delay from gatherers (maintains begin inclusive and end exclusive)
            var delBeginDateTime = curDateTime.AddSeconds(30);
            var delEndDateTime   = curDateTime.AddSeconds(-totalTimeToGoBack).AddSeconds(30);

            using (var db = new PoloniexContext())
            {
                var del =
                    db.CurrencyDataPoints
                    .Where(x => x.ClosingDateTime <= delBeginDateTime && x.ClosingDateTime >= delEndDateTime && x.CurrencyPair == currencyPair).ToList();
                db.CurrencyDataPoints.RemoveRange(del);
                db.SaveChanges();
            }

            var currencyDataPoints = new List <CurrencyDataPoint>();

            // 2678400 seconds = 31 days
            // 21600 seconds = 6 hours
            //for (int i = 2678400; i > 0; i = i - 21600)
            for (int i = totalTimeToGoBack; i > 0; i = i - 21600)
            {
                var intervalBeginningDateTime = curDateTime.AddSeconds(-i);
                var intervalEndDateTime       = curDateTime.AddSeconds(-(i - 21600));

                var poloniexData = PoloniexExchangeService.Instance.ReturnTradeHistory(currencyPair, intervalBeginningDateTime, intervalEndDateTime);

                poloniexData = poloniexData.OrderBy(x => x.date).ToList();

                decimal rate = poloniexData.First().rate;

                // how many minute intervals in 21600 seconds ... 360
                for (int j = 0; j < 360; j++)
                {
                    int pos = 0;

                    var currencyDataPoint = new CurrencyDataPoint
                    {
                        CurrencyPair    = currencyPair,
                        ClosingDateTime = intervalBeginningDateTime.AddSeconds((j + 1) * 60),
                        CreatedDateTime = markerDate.Value // notify was populated by backfill
                    };

                    bool isAnyData = false;
                    while (pos < poloniexData.Count && poloniexData[pos].date < currencyDataPoint.ClosingDateTime)
                    {
                        isAnyData = true;
                        pos++;
                    }
                    if (pos == poloniexData.Count)
                    {
                        pos--;
                    }

                    if (isAnyData)
                    {
                        rate = poloniexData[pos].rate;
                    }

                    currencyDataPoint.ClosingValue = rate;

                    currencyDataPoints.Add(currencyDataPoint);
                }
                if (currencyDataPoints.Count > 25000)
                {
                    BulkInsertCurrencyDataPoints(currencyDataPoints);
                    currencyDataPoints = new List <CurrencyDataPoint>();
                }
            }
            BulkInsertCurrencyDataPoints(currencyDataPoints);

            return;
        }
Пример #15
0
        public static void GatherTaskElapsed(object sender, string currencyPair, int interval, Timer t, List <EventAction> eventActions)
        {
            t.Interval = TimerUtility.GetAdjustedInterval(interval);
            t.Start();

            System.Threading.Tasks.Task.Run(() =>
            {
                try
                {
                    DateTime dateTimeNow  = DateTime.UtcNow;
                    DateTime dateTimePast = dateTimeNow.AddSeconds(-(60 * 4));

                    var result = PoloniexExchangeService.Instance.ReturnTradeHistory(currencyPair, dateTimePast, dateTimeNow);
                    result     = result.OrderBy(x => x.date).ToList();

                    var dataPoint = new CurrencyDataPoint
                    {
                        CurrencyPair    = currencyPair,
                        ClosingDateTime = dateTimeNow,
                    };

                    if (result.Any())
                    {
                        var curRate            = result.Last().rate;
                        dataPoint.ClosingValue = curRate;
                    }
                    else
                    {
                        using (var db = new PoloniexContext())
                        {
                            dataPoint.ClosingValue = db.CurrencyDataPoints
                                                     .Where(x => x.CurrencyPair == dataPoint.CurrencyPair)
                                                     .OrderByDescending(x => x.ClosingDateTime)
                                                     .First().ClosingValue;
                        }
                    }

                    using (var db = new PoloniexContext())
                    {
                        dataPoint.CreatedDateTime = DateTime.UtcNow;
                        db.CurrencyDataPoints.Add(dataPoint);
                        db.SaveChanges();
                    }

                    if (eventActions != null)
                    {
                        var sortedActions = eventActions.OrderBy(x => x.Priority).ToList();
                        for (int i = 0; i < sortedActions.Count(); i++)
                        {
                            Logger.Write($"{sortedActions[i].EventActionId}: Executing action {i + 1} of {sortedActions.Count()} - {sortedActions[i].EventActionType}", Logger.LogType.ServiceLog);
                            var threadEventAction = sortedActions[i];
                            threadEventAction.Action(threadEventAction.EventActionId);
                        }
                    }
                }
                catch (Exception exception)
                {
                    Logger.WriteException(exception);
                }
            });
        }
Пример #16
0
        public static void ProcessEmaCrossOverSignal(Guid eventActionId)
        {
            using (var db = new PoloniexContext())
            {
                var tradeSignalEventAction = db.TradeSignalEventActions
                                             .Single(x => x.EventActionId == eventActionId);

                var currencyPair = tradeSignalEventAction.CurrencyPair;

                var latestShorterMovingAverage = db.MovingAverages
                                                 .Where(x =>
                                                        x.CurrencyPair == tradeSignalEventAction.CurrencyPair &&
                                                        x.Interval == tradeSignalEventAction.ShorterMovingAverageInterval)
                                                 .OrderByDescending(x => x.ClosingDateTime)
                                                 .First();

                var latestLongerMovingAverage = db.MovingAverages
                                                .Where(x =>
                                                       x.CurrencyPair == tradeSignalEventAction.CurrencyPair &&
                                                       x.Interval == tradeSignalEventAction.LongerMovingAverageInterval)
                                                .OrderByDescending(x => x.ClosingDateTime)
                                                .First();

                var lastClosingValue = db.CurrencyDataPoints
                                       .Where(x => x.CurrencyPair == tradeSignalEventAction.CurrencyPair)
                                       .OrderByDescending(x => x.ClosingDateTime)
                                       .First().ClosingValue;

                Signals[currencyPair].IsBullish = latestShorterMovingAverage.MovingAverageValue - latestLongerMovingAverage.MovingAverageValue >= 0;

                if (!Signals[currencyPair].Init)
                {
                    if (!Signals[currencyPair].WasBullish && Signals[currencyPair].IsBullish && !Signals[currencyPair].HasHoldings)
                    {
                        // BUY
                        Signals[currencyPair].ShouldBuy = true;
                        Signals[currencyPair].BuyValue  = lastClosingValue;
                    }

                    if (Signals[currencyPair].HasHoldings)
                    {
                        decimal high;
                        decimal low;

                        high = Signals[currencyPair].BuyValue * (1M + Configurations[currencyPair].StopLossPercentageUpper);
                        low  = Signals[currencyPair].BuyValue * (1M - Configurations[currencyPair].StopLossPercentageLower);

                        if (Configurations[currencyPair].IsStopLossTailing)
                        {
                            if (lastClosingValue >= high)
                            {
                                Signals[currencyPair].BuyValue = high * (1M + Configurations[currencyPair].StopLossPercentageUpper);
                            }
                            if (lastClosingValue <= low)
                            {
                                Signals[currencyPair].ShouldSell = true;
                            }
                        }
                        else
                        {
                            if (lastClosingValue >= high || lastClosingValue <= low)
                            {
                                Signals[currencyPair].ShouldSell = true;
                            }
                        }
                    }

                    if (Signals[currencyPair].ShouldBuy)
                    {
                        var buyTradeSignalOrder = new TradeSignalOrder()
                        {
                            CurrencyPair           = currencyPair,
                            TradeOrderType         = TradeOrderType.Buy,
                            LastValueAtRequest     = latestShorterMovingAverage.LastClosingValue,
                            IsProcessed            = false,
                            InProgress             = false,
                            OrderRequestedDateTime = DateTime.UtcNow,
                            CreatedByEventActionId = eventActionId
                        };
                        db.TradeSignalOrders.Add(buyTradeSignalOrder);
                        db.SaveChanges();
                        Signals[currencyPair].HasHoldings = true;
                    }

                    if (Signals[currencyPair].ShouldSell)
                    {
                        var sellTradeSignalOrder = new TradeSignalOrder()
                        {
                            CurrencyPair           = currencyPair,
                            TradeOrderType         = TradeOrderType.Sell,
                            LastValueAtRequest     = latestShorterMovingAverage.LastClosingValue,
                            IsProcessed            = false,
                            InProgress             = false,
                            OrderRequestedDateTime = DateTime.UtcNow,
                            CreatedByEventActionId = eventActionId
                        };
                        db.TradeSignalOrders.Add(sellTradeSignalOrder);
                        db.SaveChanges();
                        Signals[currencyPair].HasHoldings = false;
                    }

                    Logger.Write($"currencyPair: {currencyPair}, wasBullish: {Signals[currencyPair].WasBullish}, isBullish: {Signals[currencyPair].IsBullish}, hasHolding: {Signals[currencyPair].HasHoldings}, shouldBuy: {Signals[currencyPair].ShouldBuy}, shouldSell: {Signals[currencyPair].ShouldSell}", Logger.LogType.TransactionLog);
                    Signals[currencyPair].ShouldBuy  = false;
                    Signals[currencyPair].ShouldSell = false;
                }
                else
                {
                    Logger.Write($"TradeTask init for {currencyPair}, evenActionId: {eventActionId} (see TransactionLog)", Logger.LogType.ServiceLog);
                    Signals[currencyPair].Init = false;
                }

                Signals[currencyPair].WasBullish = Signals[currencyPair].IsBullish;
            }
        }
Пример #17
0
        public static void Test()
        {
            var currencyPairsStr = ConfigurationManager.AppSettings["currencyPairs"];
            var currencyPairs    = currencyPairsStr.Split(',').ToList();

            for (int counter = 1; counter <= 4; counter++)
            {
                foreach (var currencyPair in currencyPairs)
                {
                    /* inclusive latest date */
                    var dt = DateTime.UtcNow.AddDays(0);
                    // trim to start of hour (begin)
                    dt = dt.AddMilliseconds(-dt.Millisecond);
                    dt = dt.AddSeconds(-dt.Second);
                    dt = dt.AddMinutes(-dt.Minute);
                    //dt = dt.AddHours(-dt.Hour);
                    //dt = dt.AddDays(-dt.Day + 1);
                    // trim to start of hour (end)

                    var numberOfDays = 45;

                    int quarterDaysToGoBack = (int)(4 * (double)numberOfDays);

                    var shorterInterval = 12;
                    var longerInterval  = 26;

                    var minutesPerInterval = 15 * counter;

                    dt = dt.AddMinutes(-(2 * minutesPerInterval));

                    //var currencyPair = CurrencyPairConstants.USDT_BTC; // 15
                    //var currencyPair = CurrencyPairConstants.USDT_DASH; // 30 // 45
                    //var currencyPair = CurrencyPairConstants.USDT_ETH; // 15
                    //var currencyPair = CurrencyPairConstants.USDT_LTC; // 30 // 45
                    //var currencyPair = CurrencyPairConstants.USDT_ZEC; // 30 // 45

                    // ################################################################

                    var secondsBack = quarterDaysToGoBack * 21600;
                    quarterDaysToGoBack++;

                    // ################################################################

                    var window = numberOfDays;
                    //var window = 30;
                    //var window = 60;
                    //var window = 120;
                    var numberOfTimesToShift = numberOfDays / window;

                    DateTime startDateTime = dt;
                    DateTime endDateTime   = dt.AddSeconds(-secondsBack);

                    bool backFillCurrencyDataPoints = false;

                    backFillCurrencyDataPoints = counter == 1;//true;
                    if (backFillCurrencyDataPoints)
                    {
                        //GatherTaskManager.BackFillGatherTaskData(quarterDaysToGoBack, currencyPair, dt, DateTime.Parse("1970-01-01 00:00:00.000"));

                        // only need to backfill 6 quarter days if AutoLoader is used.
                        GatherTaskManager.BackFillGatherTaskData(6, currencyPair, dt, DateTime.Parse("1970-01-01 00:00:00.000"));
                    }

                    // ################################################################
                    if (ForceIntervalForRegression != null && ForceIntervalForRegression[currencyPair] != minutesPerInterval)
                    {
                        continue;
                    }
                    // ################################################################

                    bool backFillMovingAverages = false;

                    backFillMovingAverages = true;
                    if (backFillMovingAverages)
                    {
                        MovingAverageManager.BackFillEma(currencyPair, shorterInterval, minutesPerInterval, dt, dt.AddSeconds(-secondsBack), null);
                        MovingAverageManager.BackFillEma(currencyPair, longerInterval, minutesPerInterval, dt, dt.AddSeconds(-secondsBack), null);
                    }

                    // ################################################################

                    // start manipulations
                    startDateTime = endDateTime.AddDays(window);
                    List <RegressionResults> results = new List <RegressionResults>();

                    for (int looper = 0; looper < numberOfTimesToShift; looper++)
                    {
                        ProfitAnalyzer.ResetMemory();
                        ProfitAnalyzer.ResetStats();

                        List <MovingAverage> shorterMovingAverages;
                        List <MovingAverage> longerMovingAverages;
                        using (var db = new PoloniexContext())
                        {
                            shorterMovingAverages = db.MovingAverages
                                                    .Where(x =>
                                                           x.Interval == shorterInterval &&
                                                           x.MinutesPerInterval == minutesPerInterval &&
                                                           x.CurrencyPair == currencyPair &&
                                                           x.ClosingDateTime >= endDateTime &&
                                                           x.ClosingDateTime <= startDateTime)
                                                    .OrderBy(x => x.ClosingDateTime)
                                                    .ToList();

                            longerMovingAverages = db.MovingAverages
                                                   .Where(x =>
                                                          x.Interval == longerInterval &&
                                                          x.MinutesPerInterval == minutesPerInterval &&
                                                          x.CurrencyPair == currencyPair &&
                                                          x.ClosingDateTime >= endDateTime &&
                                                          x.ClosingDateTime <= startDateTime)
                                                   .OrderBy(x => x.ClosingDateTime)
                                                   .ToList();
                        }

                        //ProfitAnalyzer.MacdEma = shorterMovingAverages[0].MovingAverageValue - longerMovingAverages[0].MovingAverageValue;
                        for (int i = 0; i < shorterMovingAverages.Count; i++)
                        {
                            //ProfitAnalyzer.ProcessMacdMovingAverageSignals(shorterMovingAverages[i].MovingAverageValue, longerMovingAverages[i].MovingAverageValue, shorterMovingAverages[i].LastClosingValue, shorterMovingAverages[i].ClosingDateTime);
                            ProfitAnalyzer.Process(shorterMovingAverages[i].MovingAverageValue, longerMovingAverages[i].MovingAverageValue, shorterMovingAverages[i].LastClosingValue, shorterMovingAverages[i].ClosingDateTime);
                        }
                        ProfitAnalyzer.CloseOpenPosition();

                        var inputBalance = 500M;

                        ProfitAnalyzer.CalculateProfit(inputBalance);

                        var dataMin    = ProfitAnalyzer.Data_GetMin();
                        var dataMax    = ProfitAnalyzer.Data_GetMax();
                        var dataMean   = ProfitAnalyzer.Data_GetMean();
                        var dataMedian = ProfitAnalyzer.Data_GetMedian();
                        var dataStd    = (decimal)Math.Sqrt((double)ProfitAnalyzer.Data_GetVariance());

                        var profitMin    = ProfitAnalyzer.Profit_GetMin();
                        var profitMax    = ProfitAnalyzer.Profit_GetMax();
                        var profitMean   = ProfitAnalyzer.Profit_GetMean();
                        var profitMedian = ProfitAnalyzer.Profit_GetMedian();
                        var profitStd    = (decimal)Math.Sqrt((double)ProfitAnalyzer.Profit_GetVariance());
                        var totalProfit  = ProfitAnalyzer.GetTotalProfit();

                        //Console.WriteLine($"CurrencyPair: {currencyPair}");
                        //Console.WriteLine($"Data-Min: {dataMin}");
                        //Console.WriteLine($"Data-Max: {dataMax}");
                        //Console.WriteLine($"Data-Mean: {dataMean}");
                        //Console.WriteLine($"Data-Median: {dataMedian}");
                        //Console.WriteLine($"Data-Std: {dataStd}");
                        //Console.WriteLine($"Profit-Min: {profitMin}");
                        //Console.WriteLine($"Profit-Max: {profitMax}");
                        //Console.WriteLine($"Profit-Mean: {profitMean}");
                        //Console.WriteLine($"Profit-Median: {profitMedian}");
                        //Console.WriteLine($"Profit-Std: {profitStd}");
                        //Console.WriteLine($"TotalProfit: {totalProfit}");


                        results.Add(new RegressionResults
                        {
                            CurrencyPair       = currencyPair,
                            MinutesPerInterval = minutesPerInterval,
                            StartDateTime      = startDateTime,
                            EndDateTime        = endDateTime,
                            DataMin            = dataMin,
                            DataMax            = dataMax,
                            DataMean           = dataMean,
                            DataMedian         = dataMedian,
                            DataStd            = dataStd,
                            ProfitMin          = profitMin,
                            ProfitMax          = profitMax,
                            ProfitMean         = profitMean,
                            ProfitMedian       = profitMedian,
                            ProfitStd          = profitStd,
                            PercentageChange   = (totalProfit) / inputBalance,
                            TotalProfit        = totalProfit
                        });

                        startDateTime = startDateTime.AddDays(window);
                        endDateTime   = endDateTime.AddDays(window);
                    }

                    foreach (var item in results)
                    {
                        Console.WriteLine(item.ToString());
                        Console.WriteLine("################################################################");
                    }

                    if (!_regressionResults.ContainsKey(currencyPair) || _regressionResults[currencyPair].TotalProfit < results[0].TotalProfit)
                    {
                        if (_regressionResults.ContainsKey(currencyPair))
                        {
                            _regressionResults[currencyPair] = results[0];
                        }
                        else
                        {
                            _regressionResults.Add(currencyPair, results[0]);
                        }
                    }
                }
            }

            foreach (var item in _regressionResults.OrderByDescending(x => x.Value.TotalProfit))
            {
                Console.WriteLine("XxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXx");
                Console.WriteLine($"key: {item.Key}\nvalue: {item.Value.ToString()}");
                Console.WriteLine("-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_");
            }
        }