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"); }
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 } }); } }
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); } }