Пример #1
0
        public async Task <IActionResult> PlaceBulkOrder([FromBody] PlaceBulkLimitOrderRequest request)
        {
            var walletId = User.GetWalletId();

            var items = request.Orders?.ToArray() ?? Array.Empty <BulkOrderItemModel>();

            var orders = new List <MultiOrderItemModel>();

            foreach (var item in items)
            {
                var order = new MultiOrderItemModel
                {
                    Id          = Guid.NewGuid().ToString(),
                    Price       = (double)item.Price,
                    Volume      = (double)item.Volume,
                    OrderAction = item.OrderAction,
                    OldId       = 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.CancelMode.HasValue)
            {
                multiOrder.CancelMode = request.CancelMode.Value;
            }

            MultiLimitOrderResponse response = await _matchingEngineClient.PlaceMultiLimitOrderAsync(multiOrder);

            if (response == null)
            {
                throw HftApiException.Create(HftApiErrorCode.MeRuntime, "ME not available");
            }

            var bulkResponse = new BulkLimitOrderResponse
            {
                AssetPairId = request.AssetPairId,
                Error       = response.Status.ToHftApiError().code,
                Statuses    = response.Statuses?.Select(x => new BulkOrderItemStatusModel
                {
                    Id     = x.Id,
                    Price  = (decimal)x.Price,
                    Volume = (decimal)x.Volume,
                    Error  = x.Status.ToHftApiError().code
                }).ToArray()
            };

            return(Ok(ResponseModel <BulkLimitOrderResponse> .Ok(bulkResponse)));
        }
Пример #2
0
        private async Task <MultiOrderItemModel> ToMultiOrderItemModel(string clientId, AssetPair assetPair, BulkOrderItemModel item)
        {
            var requestId = GetNextRequestId();
            var fees      = _calculateOrderFees
                ? await _feeCalculator.GetLimitOrderFees(clientId, assetPair, item.OrderAction)
                : Array.Empty <LimitOrderFeeModel>();

            var model = new MultiOrderItemModel
            {
                Id          = requestId.ToString(),
                Price       = (double)item.Price,
                Volume      = (double)item.Volume,
                OrderAction = item.OrderAction.ToMeOrderAction(),
                Fee         = fees.FirstOrDefault()
            };

            if (!string.IsNullOrWhiteSpace(item.OldId))
            {
                model.OldId = item.OldId;
            }

            return(model);
        }
        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);
        }
Пример #4
0
        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";
                }
            }
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }