public async Task CancelAsync(string assetPairId) { string walletId = _settingsService.GetWalletId(); if (string.IsNullOrEmpty(walletId)) { throw new ExchangeException("The wallet not set"); } var multiLimitOrder = new MultiLimitOrderModel { Id = Guid.NewGuid().ToString(), ClientId = walletId, AssetPairId = GetAssetPair(assetPairId), CancelPreviousOrders = true, Orders = new List <MultiOrderItemModel>(), CancelMode = CancelMode.BothSides }; _log.InfoWithDetails("Matching engine cancel multi limit order request", multiLimitOrder); MultiLimitOrderResponse response; try { response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiLimitOrder); } catch (Exception exception) { _log.ErrorWithDetails(exception, "An error occurred during cancelling limit orders", multiLimitOrder); throw new ExchangeException("Cannot cancel limit orders an unexpected error occurred", exception); } if (response == null) { throw new ExchangeException("Matching engine returned an empty response"); } _log.InfoWithDetails("Matching engine cancel multi limit order response", response); }
public async Task <IActionResult> CreateLimitOrder([FromBody] LimitOrderRequest order) { var orderId = Guid.NewGuid().ToString(); var mlm = new MultiLimitOrderModel() { AssetId = order.Instrument, ClientId = this.ClientId(), CancelMode = CancelMode.BothSides, CancelPreviousOrders = false, Id = Guid.NewGuid().ToString(), Orders = new List <MultiOrderItemModel> { new MultiOrderItemModel() { Id = orderId, OrderAction = order.TradeType == TradeType.Buy ? OrderAction.Buy : OrderAction.Sell, Fee = null, OldId = null, Price = (double)order.Price, Volume = (double)order.Volume } } }; var res = await _meclient.PlaceMultiLimitOrderAsync(mlm); var status = res.Statuses.Any() ? res.Statuses[0].Status : MeStatusCodes.BadRequest; if (status == MeStatusCodes.Ok) { var resp = new OrderIdResponse() { OrderId = orderId }; return(Ok(resp)); } return(BadRequest($"incorect result: {status}")); }
public async Task <ResponseModel <BulkOrderResponseModel> > PlaceBulkLimitOrderAsync(string clientId, AssetPair assetPair, IEnumerable <BulkOrderItemModel> items, bool cancelPrevious, CancelMode?cancelMode) { var requestId = GetNextRequestId(); var orders = new ConcurrentBag <MultiOrderItemModel>(); await items.ParallelForEachAsync(async item => { var subOrder = await ToMultiOrderItemModel(clientId, assetPair, item); orders.Add(subOrder); }); var order = new MultiLimitOrderModel { Id = requestId.ToString(), ClientId = clientId, AssetPairId = assetPair.Id, CancelPreviousOrders = cancelPrevious, Orders = orders.ToArray() }; if (cancelMode.HasValue) { order.CancelMode = cancelMode.Value.ToMeCancelModel(); } var response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new BulkOrderResponseModel { AssetPairId = assetPair.Id, Error = response.Status != MeStatusCodes.Ok ? ErrorCodeType.Rejected : default(ErrorCodeType?), Statuses = response.Statuses?.Select(ToBulkOrderItemStatusModel).ToArray() }; return(ConvertToApiModel(response.Status, result)); }
public async Task ApplyAsync(string assetPairId, IReadOnlyCollection <LimitOrder> limitOrders) { string walletId = _settingsService.GetWalletId(); if (string.IsNullOrEmpty(walletId)) { throw new ExchangeException("The wallet not set"); } var multiOrderItems = new List <MultiOrderItemModel>(); foreach (LimitOrder limitOrder in limitOrders) { var multiOrderItem = new MultiOrderItemModel { Id = limitOrder.Id, OrderAction = ToOrderAction(limitOrder.Type), Price = (double)limitOrder.Price, Volume = (double)Math.Abs(limitOrder.Volume) }; multiOrderItems.Add(multiOrderItem); } var multiLimitOrder = new MultiLimitOrderModel { Id = Guid.NewGuid().ToString(), ClientId = walletId, AssetPairId = GetAssetPair(assetPairId), CancelPreviousOrders = true, Orders = multiOrderItems, CancelMode = CancelMode.BothSides }; _log.InfoWithDetails("Matching engine place multi limit order request", multiLimitOrder); MultiLimitOrderResponse response; try { response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiLimitOrder); } catch (Exception exception) { _log.ErrorWithDetails(exception, "An error occurred during creating limit orders", multiLimitOrder); throw new ExchangeException("Cannot create limit orders an unexpected error occurred", exception); } if (response == null) { throw new ExchangeException("Matching engine returned an empty response"); } foreach (LimitOrderStatusModel orderStatus in response.Statuses) { LimitOrder limitOrder = limitOrders.SingleOrDefault(e => e.Id == orderStatus.Id); if (limitOrder != null) { limitOrder.Error = ToLimitOrderError(orderStatus.Status); limitOrder.ErrorMessage = limitOrder.Error != LimitOrderError.Unknown ? orderStatus.StatusReason : !string.IsNullOrEmpty(orderStatus.StatusReason) ? orderStatus.StatusReason : "Unknown error"; } else { _log.WarningWithDetails("Matching engine returned status for unknown limit order", new { LimitOrderId = orderStatus.Id }); } } string[] ignoredLimitOrders = response.Statuses .Select(x => x.Id) .Except(multiLimitOrder.Orders.Select(x => x.Id)) .ToArray(); if (ignoredLimitOrders.Any()) { _log.WarningWithDetails("Matching engine response not contains status of limit order", new { AssetPairId = assetPairId, LimitOrders = ignoredLimitOrders }); } _log.InfoWithDetails("Matching engine place multi limit order response", response); }
public async Task ApplyAsync(string assetPairId, IReadOnlyCollection <LimitOrder> limitOrders) { if (string.IsNullOrEmpty(_walletId)) { throw new Exception("WalletId is not set"); } var map = new Dictionary <string, LimitOrder>(); var multiOrderItems = new List <MultiOrderItemModel>(); foreach (LimitOrder limitOrder in limitOrders) { var multiOrderItem = new MultiOrderItemModel { Id = Guid.NewGuid().ToString("D"), OrderAction = limitOrder.TradeType.ToOrderAction(), Price = (double)limitOrder.Price, Volume = (double)limitOrder.Volume, }; map[multiOrderItem.Id] = limitOrder; multiOrderItems.Add(multiOrderItem); limitOrder.ExternalId = multiOrderItem.Id; } var multiLimitOrder = new MultiLimitOrderModel { Id = Guid.NewGuid().ToString(), ClientId = _walletId, AssetPairId = assetPairId, CancelPreviousOrders = true, Orders = multiOrderItems, CancelMode = CancelMode.BothSides }; _log.Info("ME place multi limit order request", new { request = $"data: {multiLimitOrder.ToJson()}" }); MultiLimitOrderResponse response; try { response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiLimitOrder, new CancellationTokenSource(Consts.MatchingEngineTimeout).Token); } catch (Exception exception) { _log.Error(exception, "An error occurred during creating limit orders", new { request = $"data: {multiLimitOrder.ToJson()}" }); throw; } if (response == null) { throw new Exception("ME response is null"); } if (response.Statuses.All(x => x.Status == MeStatusCodes.Ok)) { _log.Info("ME place multi limit order response", new { response = $"data: {response.ToJson()}" }); } else { _log.Warning("ME place multi limit order response. Some orders have unsuccessful codes.", context: new { response = $"data: {response.ToJson()}" }); } foreach (var orderStatus in response.Statuses) { if (map.TryGetValue(orderStatus.Id, out var limitOrder)) { limitOrder.Error = orderStatus.Status.ToOrderError(); limitOrder.ErrorMessage = limitOrder.Error != LimitOrderError.Unknown ? orderStatus.StatusReason : !string.IsNullOrEmpty(orderStatus.StatusReason) ? orderStatus.StatusReason : "Unknown error"; } } }
public async Task ApplyAsync(string assetPairId, IReadOnlyCollection <LimitOrder> limitOrders) { string walletId = await _settingsService.GetWalletIdAsync(); if (string.IsNullOrEmpty(walletId)) { throw new Exception("WalletId is not set"); } var map = new Dictionary <string, string>(); var multiOrderItems = new List <MultiOrderItemModel>(); foreach (LimitOrder limitOrder in limitOrders) { var multiOrderItem = new MultiOrderItemModel { Id = Guid.NewGuid().ToString("D"), OrderAction = limitOrder.Type.ToOrderAction(), Price = (double)limitOrder.Price, Volume = (double)Math.Abs(limitOrder.Volume) }; multiOrderItems.Add(multiOrderItem); map[multiOrderItem.Id] = limitOrder.Id; } var multiLimitOrder = new MultiLimitOrderModel { Id = Guid.NewGuid().ToString(), ClientId = walletId, AssetPairId = assetPairId, CancelPreviousOrders = true, Orders = multiOrderItems, CancelMode = CancelMode.BothSides }; _log.InfoWithDetails("ME place multi limit order request", multiLimitOrder); MultiLimitOrderResponse response; try { response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiLimitOrder); } catch (Exception exception) { _log.ErrorWithDetails(exception, "An error occurred during creating limit orders", multiLimitOrder); throw; } if (response == null) { throw new Exception("ME response is null"); } foreach (LimitOrderStatusModel orderStatus in response.Statuses) { if (map.TryGetValue(orderStatus.Id, out var limitOrderId)) { var limitOrder = limitOrders.Single(e => e.Id == limitOrderId); limitOrder.Error = orderStatus.Status.ToOrderError(); limitOrder.ErrorMessage = limitOrder.Error != LimitOrderError.Unknown ? orderStatus.StatusReason : !string.IsNullOrEmpty(orderStatus.StatusReason) ? orderStatus.StatusReason : "Unknown error"; } else { _log.Warning("ME returned status for order which is not in the request", context: $"order: {orderStatus.Id}"); } } string[] ignoredOrdersByMe = response.Statuses .Select(x => x.Id) .Except(multiLimitOrder.Orders.Select(x => x.Id)) .ToArray(); if (ignoredOrdersByMe.Any()) { _log.WarningWithDetails("ME didn't return status for orders", $"pair: {assetPairId}, orders: {string.Join(", ", ignoredOrdersByMe)}"); } _log.InfoWithDetails("ME place multi limit order response", response); }
public override async Task <BulkLimitOrderResponse> PlaceBulkLimitOrder(BulkLimitOrderRequest request, ServerCallContext context) { var walletId = context.GetHttpContext().User.GetWalletId(); var items = request.Orders?.ToArray() ?? Array.Empty <BulkOrder>(); var orders = new List <MultiOrderItemModel>(); foreach (var item in items) { var order = new MultiOrderItemModel { Id = Guid.NewGuid().ToString(), Price = Convert.ToDouble(item.Price), Volume = Convert.ToDouble(item.Volume), OrderAction = _mapper.Map <OrderAction>(item.Side), OldId = string.IsNullOrEmpty(item.OldId) ? null : item.OldId }; orders.Add(order); } var multiOrder = new MultiLimitOrderModel { Id = Guid.NewGuid().ToString(), ClientId = walletId, AssetPairId = request.AssetPairId, CancelPreviousOrders = request.CancelPreviousOrders, Orders = orders.ToArray() }; if (request.OptionalCancelModeCase != BulkLimitOrderRequest.OptionalCancelModeOneofCase.None) { multiOrder.CancelMode = _mapper.Map <Lykke.MatchingEngine.Connector.Models.Api.CancelMode>(request.CancelMode); } MultiLimitOrderResponse response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiOrder); if (response == null) { return(new BulkLimitOrderResponse { Error = new Error { Code = _mapper.Map <ErrorCode>(HftApiErrorCode.MeRuntime), Message = "ME not available" } }); } var bulkResponse = new BulkLimitOrderResponse { Payload = new BulkLimitOrderResponse.Types.BulkLimitOrderPayload { AssetPairId = request.AssetPairId } }; bulkResponse.Payload.Statuses.AddRange(response.Statuses?.Select(x => new BulkOrderItemStatus { Id = x.Id, Price = x.Price.ToString(CultureInfo.InvariantCulture), Volume = x.Volume.ToString(CultureInfo.InvariantCulture), Error = _mapper.Map <ErrorCode>(x.Status.ToHftApiError().code) })); return(bulkResponse); }