private async Task ProcessMessageAsync(LimitOrders arg)
        {
            try
            {
                var start = DateTime.UtcNow;

                var trades = await _tradesConverter.ConvertAsync(arg);

                if (trades == null || trades.Count == 0)
                {
                    return;
                }

                await _tradesPublisher.PublishAsync(trades);

                if (DateTime.UtcNow.Subtract(start) > TimeSpan.FromSeconds(10))
                {
                    await _log.WriteWarningAsync(
                        nameof(LimitOrdersSubscriberForPublishing),
                        nameof(ProcessMessageAsync),
                        $"Long processing: {arg.ToJson()}");
                }
            }
            catch (Exception ex)
            {
                await _log.WriteErrorAsync(nameof(LimitOrdersSubscriberForPublishing), nameof(ProcessMessageAsync), ex);

                throw;
            }
        }
コード例 #2
0
 private void HandleDeletedLimitOrder(ILimitOrder order)
 {
     order.UnRegisterDeleteNotificationHandler(HandleDeletedLimitOrder);
     order.UnRegisterFilledNotification(HandleDeletedLimitOrder);
     LimitOrders.Remove(order.ExchangeOrderId);
     ClientOrders[order.ClientId].Remove(order);
 }
コード例 #3
0
 void client_LimitOrderAccepted(object sender, LimitOrderDto e)
 {
     UiDispatcher.Dispatcher.Invoke(() =>
     {
         LimitOrders.Add(new LimitOrderViewModel(e, client));
     });
 }
コード例 #4
0
        public void HandleMessage(LimitOrders message)
        {
            lock (_gate)
            {
                foreach (var order in message.Orders)
                {
                    if (order.Order == null)
                    {
                        continue;
                    }

                    if (!_instrumentIndex.ContainsKey(order.Order.AssetPairId))
                    {
                        _instrumentIndex[order.Order.AssetPairId] = new Stat(order.Order.AssetPairId);
                    }
                    UpdateStat(_instrumentIndex[order.Order.AssetPairId], order);

                    if (!_clientIndex.ContainsKey(order.Order.ClientId))
                    {
                        _clientIndex[order.Order.ClientId] = new Stat(order.Order.ClientId);
                    }
                    UpdateStat(_clientIndex[order.Order.ClientId], order);
                }
            }
        }
コード例 #5
0
        public ILimitOrder TryGetLimitOrder(uint exchangeOrderId)
        {
            if (!LimitOrders.ContainsKey(exchangeOrderId))
            {
                return(null);
            }

            return(LimitOrders[exchangeOrderId]);
        }
コード例 #6
0
        void client_LimitOrderDeleted(object sender, LimitOrderDto e)
        {
            UiDispatcher.Dispatcher.Invoke(() =>
            {
                var order = LimitOrders.FirstOrDefault(a => a.OrderId == e.ExchangeOrderId);
                if (order == null)
                {
                    return;
                }

                LimitOrders.Remove(order);
                order.Dispose();
            });
        }
コード例 #7
0
        void client_LimitOrderSnapshot(object sender, System.Collections.Generic.List <LimitOrderDto> e)
        {
            UiDispatcher.Dispatcher.Invoke(() =>
            {
                LimitOrders.Clear();
                foreach (var limitOrderViewModel in LimitOrders)
                {
                    LimitOrders.Remove(limitOrderViewModel);
                    limitOrderViewModel.Dispose();
                }

                foreach (var limitOrder in e)
                {
                    LimitOrders.Add(new LimitOrderViewModel(limitOrder, client));
                }
            });
        }
コード例 #8
0
        private async Task ProcessMessageAsync(LimitOrders limitOrders)
        {
            try
            {
                if (limitOrders.Orders == null || limitOrders.Orders.Count == 0)
                {
                    return;
                }

                string walletId = _settingsService.GetWalletId();

                if (string.IsNullOrEmpty(walletId))
                {
                    return;
                }

                if (limitOrders.Orders.Any(o => o.Order?.ClientId == walletId))
                {
                    _log.Info("Message received", context: $"data: {limitOrders.ToJson()}");
                }

                List <LimitOrderWithTrades> clientLimitOrders = limitOrders.Orders
                                                                .Where(o => o.Order?.ClientId == walletId)
                                                                .Where(o => o.Trades?.Count > 0)
                                                                .ToList();

                if (!clientLimitOrders.Any())
                {
                    return;
                }

                _log.Info("LimitOrders received", context: $"{clientLimitOrders.ToJson()}");


                IReadOnlyCollection <Trade> trades = ExtractTrades(clientLimitOrders);

                if (trades.Any())
                {
                    await _lykkeTradeService.HandleAsync(trades);
                }
            }
            catch (Exception exception)
            {
                _log.Error(exception, "An error occurred during processing trades", limitOrders);
            }
        }
コード例 #9
0
        public ILimitOrder NewLimitOrder(string symbol, int clientId, double price, int quantity, WayEnum way)
        {
            if (!ClientOrders.ContainsKey(clientId))
            {
                ClientOrders.Add(clientId, new EditableList <ILimitOrder>());
            }

            ILimitOrder toReturn = new LimitOrder(symbol, quantity, price, way, clientId);

            toReturn.SetExchangeOrderId(globalItemCounter);

            LimitOrders.Add(toReturn.ExchangeOrderId, toReturn);
            ClientOrders[clientId].Add(toReturn);
            toReturn.RegisterDeleteNotificationHandler(HandleDeletedLimitOrder);
            toReturn.RegisterFilledNotification(HandleDeletedLimitOrder);

            globalItemCounter++;
            return(toReturn);
        }
コード例 #10
0
        private static bool MatchedWithMarketOrder(LimitOrders orders)
        {
            var result = false;

            foreach (var order in orders.Orders)
            {
                if (order.Trades == null || order.Trades.Count == 0)
                {
                    continue;
                }

                if (orders.Orders.All(
                        x =>
                        x.Trades == null ||
                        x.Trades.Count == 0 ||
                        x.Trades.All(y => y.OppositeOrderId != order.Order.Id)))
                {
                    result = true;
                }
            }

            return(result);
        }
コード例 #11
0
        public async Task Publish(LimitOrders limitOrders)
        {
            if (limitOrders?.Orders == null || !limitOrders.Orders.Any())
            {
                return;
            }

            var idsMappings     = new Dictionary <string, string>();
            var ordersByClients = new Dictionary <string, List <LimitOrderWithTrades> >();

            foreach (var order in limitOrders.Orders)
            {
                var walletId = order.Order.ClientId;

                if (!idsMappings.ContainsKey(walletId))
                {
                    idsMappings[walletId] = await _clientAccountClient.GetClientByWalletAsync(walletId);
                }

                var clientId = idsMappings[walletId];

                if (!ordersByClients.ContainsKey(clientId))
                {
                    ordersByClients[clientId] = new List <LimitOrderWithTrades>();
                }

                ordersByClients[clientId].Add(order);
            }

            foreach (var clientId in ordersByClients.Keys)
            {
                var orders = await ordersByClients[clientId].SelectAsync(async x =>
                                                                         await _ordersConverter.ConvertAsync(x.Order, x.Trades.Any()));

                PublishOrdersToClient(clientId, orders.ToArray());
            }
        }
コード例 #12
0
        public async Task LimitOrderBuy() // and CancelLimitOrder
        {
            AccountEntity testAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount);
            BalanceDTO accountBalance = testAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.NotNull(accountBalance);

            string limitOrderID    = Guid.NewGuid().ToString();
            string badLimitOrderID = Guid.NewGuid().ToString();

            double amount = 0.01;
            double price  = Helpers.Random.NextDouble() / 100;

            //Attempt bad buy
            MeResponseModel badOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                badLimitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Buy, accountBalance.Balance + 10, 2);

            Assert.False(badOrderResponse.Status == MeStatusCodes.Ok);

            LimitOrdersResponse badMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds"));

            Assert.NotNull(badMessage);

            LimitOrders badSubMessage = badMessage.orders.Where(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds").FirstOrDefault();

            Assert.NotNull(badSubMessage);
            Assert.True(badSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(badSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(badSubMessage.order.volume == accountBalance.Balance + 10);
            //Assert.True(badSubMessage.order.price == price);


            //Attempt buy stored in order book
            MeResponseModel LimitOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                limitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Buy, amount, price);

            Assert.True(LimitOrderResponse.Status == MeStatusCodes.Ok);

            AccountEntity checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance.Reserved, this.AssetPrecission) == Math.Round(accountBalance.Reserved + amount, this.AssetPrecission));

            LimitOrdersResponse message = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook"));

            Assert.NotNull(message);

            LimitOrders subMessage = message.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook").FirstOrDefault();

            Assert.NotNull(subMessage);
            Assert.True(subMessage.order.clientId == this.TestAccountId1);
            Assert.True(subMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(subMessage.order.volume == amount);
            Assert.True(subMessage.order.price == price);


            //Cancel proper buy
            MeResponseModel LimitOrderCancelResponse = await this.Consumer.Client.CancelLimitOrderAsync(limitOrderID);

            Assert.True(LimitOrderCancelResponse.Status == MeStatusCodes.Ok);

            checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.True(checkAccountBalance.Reserved == accountBalance.Reserved);

            LimitOrdersResponse cancelMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled"));

            Assert.NotNull(cancelMessage);

            LimitOrders cancelSubMessage = cancelMessage.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled").FirstOrDefault();

            Assert.NotNull(cancelSubMessage);
            Assert.True(cancelSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(cancelSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(cancelSubMessage.order.volume == amount);
            Assert.True(cancelSubMessage.order.price == price);
        }
コード例 #13
0
        public async Task LimitOrderSell() // and CancelLimitOrder
        {
            AccountEntity testAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount);
            BalanceDTO accountBalance = testAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance);

            string limitOrderID    = Guid.NewGuid().ToString();
            string badLimitOrderID = Guid.NewGuid().ToString();

            double amount       = 0.2;
            double price        = Helpers.Random.Next(100, 999);
            double matchedPrice = Helpers.Random.NextDouble();

            //Attempt bad sell
            MeResponseModel badOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                badLimitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Sell, accountBalance.Balance + 10, price);

            Assert.False(badOrderResponse.Status == MeStatusCodes.Ok);

            LimitOrdersResponse badMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds"));

            Assert.NotNull(badMessage);

            LimitOrders badSubMessage = badMessage.orders.Where(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds").FirstOrDefault();

            Assert.NotNull(badSubMessage);
            Assert.True(badSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(badSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(badSubMessage.order.volume == (accountBalance.Balance + 10) * -1);
            Assert.True(badSubMessage.order.price == price);

            //Attempt sell stored in order book
            MeResponseModel LimitOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                limitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Sell, amount, price);

            Assert.True(LimitOrderResponse.Status == MeStatusCodes.Ok);

            AccountEntity checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance.Reserved, this.AssetPrecission) == Math.Round(accountBalance.Reserved + amount, this.AssetPrecission));


            LimitOrdersResponse message = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook"));

            Assert.NotNull(message);

            LimitOrders subMessage = message.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook").FirstOrDefault();

            Assert.NotNull(subMessage);
            Assert.True(subMessage.order.clientId == this.TestAccountId1);
            Assert.True(subMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(subMessage.order.volume == amount * -1);
            Assert.True(subMessage.order.price == price);


            //LimitOrderEntity limitOrderFromDB = (LimitOrderEntity)await fixture.LimitOrdersRepository.TryGetAsync("Active_" + fixture.TestAccountId1, subMessage.order.id);
            //Assert.NotNull(limitOrderFromDB);
            //Assert.True(limitOrderFromDB.AssetPairId == fixture.TestAssetPair.Id);
            //Assert.True(limitOrderFromDB.Price == subMessage.order.price);
            //Assert.True(limitOrderFromDB.Status == subMessage.order.status);
            //Assert.True(limitOrderFromDB.Volume == amount);
            //Assert.True(limitOrderFromDB.RemainingVolume == subMessage.order.remainingVolume);
            //Assert.True(limitOrderFromDB.Straight == );
            //Assert.True(limitOrderFromDB.MatchingId == subMessage.order.);

            //Cancel the proper sell
            MeResponseModel LimitOrderCancelResponse = await this.Consumer.Client.CancelLimitOrderAsync(limitOrderID);

            Assert.True(LimitOrderCancelResponse.Status == MeStatusCodes.Ok);

            checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(checkAccountBalance.Reserved == accountBalance.Reserved);

            LimitOrdersResponse cancelMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled"));

            Assert.NotNull(cancelMessage);

            LimitOrders cancelSubMessage = cancelMessage.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled").FirstOrDefault();

            Assert.NotNull(cancelSubMessage);
            Assert.True(cancelSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(cancelSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(cancelSubMessage.order.volume == amount * -1);
            Assert.True(cancelSubMessage.order.price == price);
        }
コード例 #14
0
        public async Task <List <Trade> > ConvertAsync(LimitOrders orders)
        {
            var result = new List <Trade>();

            if (orders?.Orders == null || orders.Orders.Count == 0)
            {
                return(result);
            }

            var matchedWithMarketOrder = MatchedWithMarketOrder(orders);

            foreach (var order in orders.Orders)
            {
                if (order.Trades == null || order.Trades.Count == 0)
                {
                    continue;
                }

                foreach (var trade in order.Trades)
                {
                    if (result.Any(x => x.Id == trade.TradeId))
                    {
                        continue;
                    }

                    var assetPair = await _assetsServiceWrapper.TryGetAssetPairAsync(trade.Asset, trade.OppositeAsset);

                    var baseAsset = await _assetsServiceWrapper.TryGetAssetAsync(assetPair.BaseAssetId);

                    var volume =
                        assetPair != null
                            ? (assetPair.BaseAssetId == trade.Asset
                                    ? trade.Volume
                                    : trade.OppositeVolume)
                            : 0;

                    TradeAction action;

                    if (matchedWithMarketOrder)
                    {
                        action = order.Order.Volume > 0 ? TradeAction.Sell : TradeAction.Buy;
                    }
                    else
                    {
                        var oppositeOrder = orders.Orders.FirstOrDefault(x => x.Order.Id == trade.OppositeOrderId);

                        var latestOrder = oppositeOrder.Order.CreatedAt <= order.Order.CreatedAt
                            ? order.Order
                            : oppositeOrder.Order;

                        action = latestOrder.Volume > 0 ? TradeAction.Buy : TradeAction.Sell;
                    }

                    result.Add(new Trade
                    {
                        Id          = trade.TradeId,
                        DateTime    = trade.Timestamp,
                        Price       = trade.Price,
                        AssetPairId = assetPair?.Id,
                        Volume      = volume.Normalize(baseAsset),
                        Index       = trade.Index,
                        Action      = action
                    });
                }
            }

            return(result);
        }
コード例 #15
0
 private async Task ProcessMessageAsync(LimitOrders orders)
 {
     _ordersPublisher.Publish(orders);
 }
コード例 #16
0
        private async Task ProcessMessageAsync(LimitOrders arg)
        {
            _messageStatistic.HandleMessage(arg);

            await Task.CompletedTask;
        }