Пример #1
0
        private async Task <bool> GetOrders(TradeTask tt)
        {
            foreach (var job in tt.FinishedJobs.Where(IsActiveJob))
            {
                var result = await GetOrder(job);

                job.ExchangeOrder = result;
                result.Fills.ForEach(x => tt.RegisterTrade(x));
            }

            if (tt.LastGetOrder.AddSeconds(5) <= DateTime.Now)
            {
                foreach (var job in tt.Jobs.Where(IsActiveJob))
                {
                    var result = await GetOrder(job);

                    if (job.ExchangeOrder == null || result.Updated > job.ExchangeOrder?.Updated)
                    {
                        job.ExchangeOrder = result;
                        tt.Updated        = DateTime.Now;
                        TradeTaskViewModel.SerializeModel(tt);
                        var ttvm = TradeTasksList.SingleOrDefault(x => x.Model == tt);
                        ttvm.Status = BuildStatusString(tt, job);
                        result.Fills.ForEach(x => tt.RegisterTrade(x));
                    }
                    tt.LastGetOrder = DateTime.Now;
                }
            }
            return(true);
        }
Пример #2
0
        private async Task DoLifecycleImpl(TradeTask task)
        {
            if (task == null || task.IsBusy)
            {
                return;
            }

            try
            {
                await task.locker.WaitAsync();

                var pt     = GetPriceTicker(task.Symbol);
                var result = await GetOrders(task);

                if (task.Status == TradeTaskStatus.Running)
                {
                    if (result)
                    {
                        await Lifecycle(task, pt);
                    }
                }
                else
                {
                    var ttvm = TradeTasksList.SingleOrDefault(x => x.Model == task);
                    ttvm.Status = BuildStatusString(task.Status);
                }
            }
            catch (ApiException ex)
            {
                var ttvm = TradeTasksList.SingleOrDefault(x => x.Model == task);
                if (ttvm != null)
                {
                    ttvm.LastError = ex.Error;
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                task.locker.Release();
            }
        }
Пример #3
0
        // before running the lifecycle, update ALL task orders
        // with status = ACTIVE | PARTIALLY_FILLED.

        private async Task Lifecycle(TradeTask tt, PriceTicker ticker)
        {
            if (!tt.Jobs.Any())
            {
                // Shutdown the task.
                tt.Status  = TradeTaskStatus.Finished;
                tt.Updated = DateTime.Now;
                tt.Events.Add(tt.Updated, "Task finished.");
                TradeTaskViewModel.SerializeModel(tt);
                return;
            }

            bool isLimitOrdersAllowed = true;

            // NOTE: this routine relies on condition that
            // LIMIT orders are always on TOP of MARKET orders in list of jobs.
            foreach (var job in tt.Jobs.ToList())
            {
                if (job.ExchangeOrder != null)
                {
                    switch (job.ExchangeOrder.Status)
                    {
                    case OrderStatus.Cancelled:
                        tt.Status  = TradeTaskStatus.Stopped;
                        tt.Updated = DateTime.Now;
                        tt.Events.Add(tt.Updated, "Task stopped due to order was cancelled outside.");
                        TradeTaskViewModel.SerializeModel(tt);
                        return;

                    case OrderStatus.Filled:
                        if (job.Kind == OrderKind.StopLoss)
                        {
                            // Shutdown the task.
                            tt.Status  = TradeTaskStatus.Finished;
                            tt.Updated = DateTime.Now;
                            tt.Events.Add(tt.Updated, "Task finished by stop loss.");
                        }
                        else if (job.Kind == OrderKind.PanicSell)
                        {
                            tt.Status  = TradeTaskStatus.PanicSell;
                            tt.Updated = DateTime.Now;
                            tt.Events.Add(tt.Updated, "Task stopped by panic sell.");
                        }
                        tt.FinishedJobs.Enqueue(job);
                        tt.Jobs.Remove(job);
                        TradeTaskViewModel.SerializeModel(tt);
                        return;

                    case OrderStatus.Active:
                    case OrderStatus.PartiallyFilled:
                        // THIS STATE IS ONLY POSSIBLE FOR LIMIT ORDERS OR PANIC SELL!
                        // so allow ONLY MARKET order to check conditions and execute
                        isLimitOrdersAllowed = false;
                        break;
                    }
                }
                else
                {
                    bool applicable   = false;
                    bool isLimitOrder = (job.Type == OrderType.LIMIT || job.Type == OrderType.STOP_LIMIT);
                    // check condition
                    if (job.Kind == OrderKind.Buy)
                    {
                        applicable = (tt.StopLoss.Price < ticker.Ask) && (ticker.Ask < tt.TakeProfit.First().Price);
                        if (!applicable)
                        {
                            var ttvm = TradeTasksList.SingleOrDefault(x => x.Model == tt);
                            ttvm.Status = "Цена вне зоны покупки";
                        }
                    }
                    else if (job.Kind == OrderKind.PanicSell)
                    {
                        applicable = true;
                    }
                    else
                    {
                        applicable = (job.Type != OrderType.MARKET && job.Type != OrderType.TRAILING) || (ticker.Bid >= job.Price); // NOTE: last part is wrong -- could be market STOP_LOSS, so ticker.Bid <= job.Price is valid for this case
                    }
                    // !!!ALLOW ONLY 1 LIMIT ORDER AT A TIME FOR NOW!!!
                    if (applicable && (isLimitOrdersAllowed || !isLimitOrder) && (tt.Qty > 0 || job.Side == TradeSide.Buy))
                    {
                        var result = await CancellAllOrders(tt);

                        if (job.Side == TradeSide.Sell)
                        {
                            // Do not sell more then you have :D
                            job.Quantity = Math.Min(tt.Qty, job.Quantity);
                        }

                        job.ExchangeOrder = await ExecuteOrder(job);

                        job.OrderId = job.ExchangeOrder.OrderId;
                        tt.Updated  = DateTime.Now;
                        tt.Events.Add(tt.Updated, $"Created order {job.OrderId}.");
                        TradeTaskViewModel.SerializeModel(tt);
                        job.ExchangeOrder.Fills.ForEach(x => tt.RegisterTrade(x));

                        var ttvm = TradeTasksList.SingleOrDefault(x => x.Model == tt);
                        ttvm.Status = BuildStatusString(tt, job);
                    }
                    return; // exit for
                }
            }
        }