예제 #1
0
        protected async Task <bool> PanicSell(TradeTask tt)
        {
            try
            {
                await tt.locker.WaitAsync();

                // there could be BUY or SL orders running. cancell all them first.
                var result = await CancellAllOrders(tt);

                tt.Jobs.ForEach(x => tt.FinishedJobs.Enqueue(x));
                tt.Jobs.Clear();
                if (tt.Qty > 0)
                {
                    var sellJob = new OrderTask()
                    {
                        Symbol   = tt.Symbol,
                        Type     = OrderType.MARKET,
                        Kind     = OrderKind.PanicSell,
                        Side     = TradeSide.Sell,
                        Quantity = tt.Qty
                    };
                    tt.Jobs.Insert(0, sellJob);
                }
                TradeTaskViewModel.SerializeModel(tt);
                return(result);
            }
            finally
            {
                tt.locker.Release();
            }
        }
예제 #2
0
        // Покупка 123 XRP по 0.00123 выставлена
        // Стоп-лосс 123 XRP по 0.0100 выставлен
        // Тейк-профит 60 XRP по 0.00140 выставлен
        // Завершено
        // Остановлено
        // Паник селл

        private string BuildStatusString(TradeTask tt, OrderTask job)
        {
            string action = "Остановлено";

            switch (job.Kind)
            {
            case OrderKind.Buy:
                action = "Покупка";
                break;

            case OrderKind.StopLoss:
                action = "Стоп лосс";
                break;

            case OrderKind.TakeProfit:
                action = "Тейк профит";
                break;

            case OrderKind.PanicSell:
                action = "Паник селл";
                break;
            }
            var si = GetSymbolInformation(tt.Symbol);

            return($"{action} {job.Quantity} {si.BaseAsset} по {job.Price} {si.QuoteAsset} {OrderStatusToDisplayStringRus(job.ExchangeOrder.Status)}");
        }
예제 #3
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);
        }
예제 #4
0
        public TradeTaskViewModel(SymbolInformation si, string exchangeName)
        {
            Model               = new TradeTask();
            Model.Id            = Guid.NewGuid();
            Model.Symbol        = si.Symbol;
            Model.Exchange      = exchangeName;
            SymbolInformation   = si;
            QuoteBalance        = si.QuoteAssetBalance.Free;
            QuoteBalancePercent = 0.05;
            Buy = new OrderTaskViewModel(this)
            {
                Price = si.PriceTicker.Ask.GetValueOrDefault()
            };
            StopLoss = new OrderTaskViewModel(this)
            {
                Price = si.ClampPrice(Buy.Price * 0.95m)
            };
            TakeProfit = new ObservableCollection <TakeProfitViewModel>();
            var DEF_TAKE_PRCNTS = new double[] { 0.6, 0.4 };

            for (int ind = 1; ind <= 2; ++ind)
            {
                var tp = new TakeProfitViewModel(this, DEF_TAKE_PRCNTS[ind - 1], ind > 1 ? TakeProfit[ind - 2] : null)
                {
                    Price = Math.Round(Buy.Price * (1.05m + 0.05m * ind), si.PriceDecimals), Caption = $"Тейк {ind}"
                };
                TakeProfit.Add(tp);
            }
            LastPrice            = Buy.Price;
            AddTakeProfitCommand = ReactiveCommand.Create <object>(AddTakeProfitExecute);
            SubmitCommand        = ReactiveCommand.CreateFromTask <string, bool>(SubmitImpl);
            ConnectTrades(edit: true);
        }
예제 #5
0
        public TradeTask LoadFromJson(string json)
        {
            var tt = new TradeTask();

            JsonConvert.PopulateObject(json, tt);
            //Trades.Edit(innerList => innerList.AddOrUpdate(Buy.ExchangeOrder.Fills));
            //Trades.Edit(innerList => innerList.AddOrUpdate(StopLoss.ExchangeOrder.Fills));
            //foreach (var ot in TakeProfit)
            //    Trades.Edit(innerList => innerList.AddOrUpdate(ot.ExchangeOrder.Fills));
            return(tt);
        }
예제 #6
0
        private async Task <bool> CancellAllOrders(TradeTask tt)
        {
            var result = false;

            foreach (var job in tt.Jobs.Where(IsActiveJob).ToList())
            {
                result = await CancelOrder(job);

                tt.FinishedJobs.Enqueue(job);
                tt.Jobs.Remove(job);
                TradeTaskViewModel.SerializeModel(tt);
            }
            return(result);
        }
예제 #7
0
 public TradeTaskViewModel(SymbolInformation si, TradeTask model)
 {
     SymbolInformation = si;
     Model             = model;
     Buy        = new OrderTaskViewModel(this, model.Buy);
     StopLoss   = new OrderTaskViewModel(this, model.StopLoss);
     TakeProfit = new ObservableCollection <TakeProfitViewModel>();
     for (int ind = 1; ind <= model.TakeProfit.Count(); ++ind)
     {
         var tp = new TakeProfitViewModel(this, model.TakeProfit[ind - 1], ind > 1 ? TakeProfit[ind - 2] : null);
         TakeProfit.Add(tp);
     }
     LastPrice = si.PriceTicker.LastPrice.GetValueOrDefault();
     ConnectTrades();
 }
예제 #8
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();
            }
        }
예제 #9
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
                }
            }
        }
예제 #10
0
 public static void Delete(TradeTask model)
 {
     File.Delete(Path.ChangeExtension(model.Id.ToString(), ".json"));
 }
예제 #11
0
        public static void SerializeModel(TradeTask model)
        {
            var json = JsonConvert.SerializeObject(model, Formatting.Indented);

            File.WriteAllText(Path.ChangeExtension(model.Id.ToString(), ".json"), json);
        }