public async Task <MatchedOrderCollection> MatchOrderAsync(Order order, bool shouldOpenNewPosition, OrderModality modality = OrderModality.Regular) { List <(string source, decimal?price)> prices = null; if (!string.IsNullOrEmpty(_marginTradingSettings.DefaultExternalExchangeId)) { var quote = _quoteCacheService.GetQuote(order.AssetPairId); if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume)) { prices = new List <(string source, decimal?price)> { (_marginTradingSettings .DefaultExternalExchangeId, quote.GetPriceForOrderDirection(order.Direction)) }; } } if (prices == null) { prices = _externalOrderbookService.GetOrderedPricesForExecution(order.AssetPairId, order.Volume, shouldOpenNewPosition); if (prices == null || !prices.Any()) { return(new MatchedOrderCollection()); } } var assetPair = _assetPairsCache.GetAssetPairByIdOrDefault(order.AssetPairId); var externalAssetPair = assetPair?.BasePairId ?? order.AssetPairId; foreach (var(source, price) in prices .Where(x => string.IsNullOrEmpty(order.ExternalProviderId) || x.source == order.ExternalProviderId)) { var externalOrderModel = new OrderModel(); var orderType = order.OrderType == Core.Orders.OrderType.Limit || order.OrderType == Core.Orders.OrderType.TakeProfit ? Core.Orders.OrderType.Limit : Core.Orders.OrderType.Market; var isCancellationTrade = order.AdditionalInfo.IsCancellationTrade(out var cancellationTradeExternalId); var targetPrice = order.OrderType != Core.Orders.OrderType.Market || isCancellationTrade ? (double?)order.Price : (double?)price; try { externalOrderModel = new OrderModel( tradeType: order.Direction.ToType <TradeType>(), orderType: orderType.ToType <OrderType>(), timeInForce: TimeInForce.FillOrKill, volume: (double)Math.Abs(order.Volume), dateTime: _dateService.Now(), exchangeName: source, instrument: externalAssetPair, price: targetPrice, orderId: order.Id, modality: modality.ToType <TradeRequestModality>(), isCancellationTrade: isCancellationTrade, cancellationTradeExternalId: cancellationTradeExternalId); var cts = new CancellationTokenSource(); cts.CancelAfter(_marginTradingSettings.GavelTimeout); var executionResult = await _exchangeConnectorClient.ExecuteOrder(externalOrderModel, cts.Token); if (!executionResult.Success) { var ex = new Exception( $"External order was not executed. Status: {executionResult.ExecutionStatus}. Failure: {executionResult.FailureType}"); LogOrderExecutionException(order, externalOrderModel, ex); } else { var executedPrice = Math.Abs(executionResult.Price) > 0 ? (decimal)executionResult.Price : price.Value; if (executedPrice.EqualsZero()) { var ex = new Exception($"Have got execution price from Gavel equal to 0. Ignoring."); LogOrderExecutionException(order, externalOrderModel, ex); } else { var matchedOrders = new MatchedOrderCollection { new MatchedOrder { MarketMakerId = source, MatchedDate = _dateService.Now(), OrderId = executionResult.ExchangeOrderId, Price = CalculatePriceWithMarkups(assetPair, order.Direction, executedPrice), Volume = (decimal)executionResult.Volume, IsExternal = true } }; await _rabbitMqNotifyService.ExternalOrder(executionResult); _operationsLogService.AddLog("external order executed", order.AccountId, externalOrderModel.ToJson(), executionResult.ToJson()); return(matchedOrders); } } } catch (Exception ex) { LogOrderExecutionException(order, externalOrderModel, ex); throw new OrderExecutionTechnicalException(); } } return(new MatchedOrderCollection()); }
public async Task <MatchedOrderCollection> MatchOrderAsync(Order order, bool shouldOpenNewPosition, OrderModality modality = OrderModality.Regular) { List <(string source, decimal?price)> prices = null; if (!string.IsNullOrEmpty(_marginTradingSettings.DefaultExternalExchangeId)) { var quote = _quoteCacheService.GetQuote(order.AssetPairId); if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume)) { prices = new List <(string source, decimal?price)> { (_marginTradingSettings .DefaultExternalExchangeId, quote.GetPriceForOrderDirection(order.Direction)) }; } } if (prices == null) { prices = _externalOrderbookService.GetOrderedPricesForExecution(order.AssetPairId, order.Volume, shouldOpenNewPosition); if (prices == null || !prices.Any()) { return(new MatchedOrderCollection()); } } var assetPair = _assetPairsCache.GetAssetPairByIdOrDefault(order.AssetPairId); var externalAssetPair = assetPair?.BasePairId ?? order.AssetPairId; foreach (var(source, price) in prices .Where(x => string.IsNullOrEmpty(order.ExternalProviderId) || x.source == order.ExternalProviderId)) { var externalOrderModel = new OrderModel(); var orderType = order.OrderType == Core.Orders.OrderType.Limit || order.OrderType == Core.Orders.OrderType.TakeProfit ? OrderType.Limit : OrderType.Market; var targetPrice = order.OrderType == Core.Orders.OrderType.Market ? (double?)price : (double?)order.Price; try { externalOrderModel = new OrderModel( tradeType: order.Direction.ToType <TradeType>(), orderType: orderType, timeInForce: TimeInForce.FillOrKill, volume: (double)Math.Abs(order.Volume), dateTime: _dateService.Now(), exchangeName: source, instrument: externalAssetPair, price: targetPrice, orderId: order.Id, modality: modality.ToType <TradeRequestModality>()); var cts = new CancellationTokenSource(); cts.CancelAfter(_marginTradingSettings.GavelTimeout); var executionResult = await _exchangeConnectorService.CreateOrderAsync(externalOrderModel, cts.Token); if (!executionResult.Success) { throw new Exception( $"External order was not executed. Status: {executionResult.ExecutionStatus}. Failure: {executionResult.FailureType}"); } var executedPrice = Math.Abs(executionResult.Price) > 0 ? (decimal)executionResult.Price : price.Value; var matchedOrders = new MatchedOrderCollection { new MatchedOrder { MarketMakerId = source, MatchedDate = _dateService.Now(), OrderId = executionResult.ExchangeOrderId, Price = CalculatePriceWithMarkups(assetPair, order.Direction, executedPrice), Volume = (decimal)executionResult.Volume, IsExternal = true } }; await _rabbitMqNotifyService.ExternalOrder(executionResult); _operationsLogService.AddLog("external order executed", order.AccountId, externalOrderModel.ToJson(), executionResult.ToJson()); return(matchedOrders); } catch (Exception e) { var connector = _marginTradingSettings.ExchangeConnector == ExchangeConnectorType.FakeExchangeConnector ? "Fake" : _exchangeConnectorService.BaseUri.OriginalString; _log.WriteError( $"{nameof(StpMatchingEngine)}:{nameof(MatchOrderAsync)}:{connector}", $"Internal order: {order.ToJson()}, External order model: {externalOrderModel.ToJson()}", e); } } return(new MatchedOrderCollection()); }