public async Task <CommandHandlingResult> Handle(ProcessLimitOrderCommand command, IEventPublisher eventPublisher)
        {
            var clientId = command.LimitOrder.Order.ClientId;

            if (!_trusted.ContainsKey(clientId))
            {
                _trusted[clientId] = (await _clientAccountClient.IsTrustedAsync(clientId)).Value;
            }

            var isTrustedClient = _trusted[clientId];

            var limitOrderExecutedEvent = new LimitOrderExecutedEvent
            {
                IsTrustedClient = isTrustedClient,
                LimitOrder      = command.LimitOrder
            };

            var tradesWerePerformed = command.LimitOrder.Trades != null && command.LimitOrder.Trades.Any();

            if (!isTrustedClient)
            {
                // need previous order state for not trusted clients
                var prevOrderState = await _limitOrdersRepository.GetOrderAsync(command.LimitOrder.Order.ClientId, command.LimitOrder.Order.Id);

                var isImmediateTrade = tradesWerePerformed && command.LimitOrder.Trades.First().Timestamp == command.LimitOrder.Order.Registered;
                limitOrderExecutedEvent.HasPrevOrderState   = prevOrderState != null && !isImmediateTrade;
                limitOrderExecutedEvent.PrevRemainingVolume = prevOrderState?.RemainingVolume;

                limitOrderExecutedEvent.Aggregated = AggregateSwaps(limitOrderExecutedEvent.LimitOrder.Trades);
            }

            await _limitOrdersRepository.CreateOrUpdateAsync(command.LimitOrder.Order);

            var status = (OrderStatus)Enum.Parse(typeof(OrderStatus), command.LimitOrder.Order.Status);

            // workaround: ME sends wrong status
            if (status == OrderStatus.Processing && !tradesWerePerformed)
            {
                status = OrderStatus.InOrderBook;
            }
            else if (status == OrderStatus.PartiallyMatched && !tradesWerePerformed)
            {
                status = OrderStatus.Placed;
            }

            if (status == OrderStatus.Processing ||
                status == OrderStatus.PartiallyMatched || // new version of Processing
                status == OrderStatus.Matched ||
                status == OrderStatus.Cancelled)
            {
                limitOrderExecutedEvent.Trades = await CreateTrades(command.LimitOrder);
            }

            eventPublisher.PublishEvent(limitOrderExecutedEvent);

            return(CommandHandlingResult.Ok());
        }
        public async Task Handle(LimitOrderExecutedEvent evt, ICommandSender commandSender)
        {
            if (evt.IsTrustedClient)
            {
                return;
            }

            ChaosKitty.Meow();

            var cmd = new UpdateLimitOrdersCountCommand
            {
                ClientId        = evt.LimitOrder.Order.ClientId,
                IsTrustedClient = evt.IsTrustedClient
            };

            commandSender.SendCommand(cmd, "operations-history");
        }
Exemplo n.º 3
0
        public async Task <CommandHandlingResult> Handle(ProcessLimitOrderCommand command, IEventPublisher eventPublisher)
        {
            var sw = new Stopwatch();

            sw.Start();
            var stepWatch = new Stopwatch();

            stepWatch.Start();

            try
            {
                var clientId = command.LimitOrder.Order.ClientId;

                if (!_trusted.ContainsKey(clientId))
                {
                    _trusted[clientId] = (await _clientAccountClient.IsTrustedAsync(clientId)).Value;
                }

                _log.Info("LimitOrderProcessing", new { TxHandler = new { Step = "01. Check client account is trusted", Time = stepWatch.ElapsedMilliseconds } });
                stepWatch.Restart();

                var isTrustedClient = _trusted[clientId];

                var limitOrderExecutedEvent = new LimitOrderExecutedEvent
                {
                    IsTrustedClient = isTrustedClient,
                    LimitOrder      = command.LimitOrder
                };

                var tradesWerePerformed = command.LimitOrder.Trades != null && command.LimitOrder.Trades.Any();
                if (!isTrustedClient)
                {
                    // need previous order state for not trusted clients
                    var prevOrderState = await _limitOrdersRepository.GetOrderAsync(command.LimitOrder.Order.ClientId, command.LimitOrder.Order.Id);

                    var isImmediateTrade = tradesWerePerformed && command.LimitOrder.Trades.First().Timestamp == command.LimitOrder.Order.Registered;
                    limitOrderExecutedEvent.HasPrevOrderState   = prevOrderState != null && !isImmediateTrade;
                    limitOrderExecutedEvent.PrevRemainingVolume = prevOrderState?.RemainingVolume;

                    limitOrderExecutedEvent.Aggregated = AggregateSwaps(limitOrderExecutedEvent.LimitOrder.Trades);

                    _log.Info("LimitOrderProcessing", new { TxHandler = new { Step = "02. Get Previous order state for not trusted client", Time = stepWatch.ElapsedMilliseconds } });
                    stepWatch.Restart();
                }

                if (!isTrustedClient)
                {
                    await _limitOrdersRepository.CreateOrUpdateAsync(command.LimitOrder.Order);

                    _log.Info("LimitOrderProcessing", new { TxHandler = new { Step = "03. Upsert limit order for not trusted client", Time = stepWatch.ElapsedMilliseconds } });
                    stepWatch.Restart();
                }

                var status = (OrderStatus)Enum.Parse(typeof(OrderStatus), command.LimitOrder.Order.Status);

                // workaround: ME sends wrong status
                if (status == OrderStatus.Processing && !tradesWerePerformed)
                {
                    status = OrderStatus.InOrderBook;
                }
                else if (status == OrderStatus.PartiallyMatched && !tradesWerePerformed)
                {
                    status = OrderStatus.Placed;
                }

                if (status == OrderStatus.Processing ||
                    status == OrderStatus.PartiallyMatched ||  // new version of Processing
                    status == OrderStatus.Matched ||
                    status == OrderStatus.Cancelled)
                {
                    limitOrderExecutedEvent.Trades = await CreateTrades(command.LimitOrder);
                }

                _log.Info("LimitOrderProcessing", new { TxHandler = new { Step = "04. Create trades", Time = stepWatch.ElapsedMilliseconds } });
                stepWatch.Restart();

                eventPublisher.PublishEvent(limitOrderExecutedEvent);

                return(CommandHandlingResult.Ok());
            }
            finally
            {
                sw.Stop();
                _log.Info("Command execution time",
                          context: new { TxHandler = new { Handler = nameof(LimitOrderCommandHandler), Command = nameof(ProcessLimitOrderCommand),
                                                           Time    = sw.ElapsedMilliseconds } });
            }
        }
Exemplo n.º 4
0
        public async Task Handle(LimitOrderExecutedEvent evt)
        {
            var assetPairId = evt.LimitOrder.Order.AssetPairId;

            // Save trades
            if (evt.Trades != null && evt.Trades.Any())
            {
                var clientTrades = evt.Trades
                                   .Select(t => new ClientTrade
                {
                    Id                   = t.Id,
                    ClientId             = t.ClientId,
                    AssetId              = t.AssetId,
                    AssetPairId          = assetPairId,
                    Amount               = t.Amount,
                    DateTime             = t.DateTime,
                    Price                = t.Price,
                    LimitOrderId         = t.LimitOrderId,
                    OppositeLimitOrderId = t.OppositeLimitOrderId,
                    TransactionId        = t.TransactionId,
                    IsLimitOrderResult   = t.IsLimitOrderResult,
                    State                = t.State,
                    FeeSize              = t.FeeSize,
                    FeeType              = t.FeeType
                }).ToArray();

                await _clientTradesRepository.SaveAsync(clientTrades);

                _log.Info(nameof(OperationHistoryProjection), $"Client {evt.LimitOrder.Order.ClientId}. Limit trade {evt.LimitOrder.Order.Id}. Client trades saved", JsonConvert.SerializeObject(clientTrades, Formatting.Indented));
            }
            else
            {
                _log.Info(nameof(OperationHistoryProjection), $"Client {evt.LimitOrder.Order.ClientId}. Limit order {evt.LimitOrder.Order.Id}. Client trades are empty");
            }

            if (evt.IsTrustedClient)
            {
                return;
            }

            // Save context
            var contextData = await _transactionService.GetTransactionContext <SwapOffchainContextData>(evt.LimitOrder.Order.Id) ?? new SwapOffchainContextData();

            var aggregated = evt.Aggregated ?? new List <Handlers.AggregatedTransfer>();

            foreach (var operation in aggregated.Where(x => x.ClientId == evt.LimitOrder.Order.ClientId))
            {
                var trade = evt.Trades?.FirstOrDefault(x =>
                                                       x.ClientId == operation.ClientId &&
                                                       x.AssetId == operation.AssetId &&
                                                       Math.Abs(x.Amount - (double)operation.Amount) < 0.00000001);

                contextData.Operations.Add(new SwapOffchainContextData.Operation()
                {
                    TransactionId = operation.TransferId,
                    Amount        = operation.Amount,
                    ClientId      = operation.ClientId,
                    AssetId       = operation.AssetId,
                    ClientTradeId = trade?.Id
                });
            }

            await _transactionService.CreateOrUpdateAsync(evt.LimitOrder.Order.Id);

            await _transactionService.SetTransactionContext(evt.LimitOrder.Order.Id, contextData);

            _log.Info(nameof(LimitOrderExecutedEvent), $"Client {evt.LimitOrder.Order.ClientId}. Limit order {evt.LimitOrder.Order.Id}. Context updated.", JsonConvert.SerializeObject(contextData, Formatting.Indented));

            // Save limit trade events
            if (Enum.TryParse(typeof(OrderStatus), evt.LimitOrder.Order.Status, out var status))
            {
                switch (status)
                {
                case OrderStatus.InOrderBook:
                    await CreateEvent(evt.LimitOrder, OrderStatus.InOrderBook);

                    break;

                case OrderStatus.Cancelled:
                    if (!evt.HasPrevOrderState && evt.LimitOrder.Trades != null && evt.LimitOrder.Trades.Any())
                    {
                        await CreateEvent(evt.LimitOrder, OrderStatus.InOrderBook);
                    }
                    await CreateEvent(evt.LimitOrder, OrderStatus.Cancelled);

                    break;

                case OrderStatus.Processing:
                case OrderStatus.Matched:
                    if (!evt.HasPrevOrderState)
                    {
                        await CreateEvent(evt.LimitOrder, OrderStatus.InOrderBook);
                    }
                    break;

                default:
                    _log.Info(nameof(LimitOrderExecutedEvent), $"Client {evt.LimitOrder.Order.ClientId}. Order {evt.LimitOrder.Order.Id}: Rejected", JsonConvert.SerializeObject(evt.LimitOrder, Formatting.Indented));
                    break;
                }
            }
            else
            {
                _log.Warning(nameof(LimitOrderExecutedEvent), "Not supported order status by Lykke.Service.OperationsRepository.", context: evt.LimitOrder.Order.Status);
            }
        }