public async Task <ResponseModel <LimitOrderResponseModel> > PlaceLimitOrderAsync(string clientId, AssetPair assetPair, OrderAction orderAction, decimal volume, decimal price, bool cancelPreviousOrders = false) { var requestId = GetNextRequestId(); var fees = _calculateOrderFees ? await _feeCalculator.GetLimitOrderFees(clientId, assetPair, orderAction) : Array.Empty <LimitOrderFeeModel>(); var order = new LimitOrderModel { Id = requestId.ToString(), AssetPairId = assetPair.Id, ClientId = clientId, Price = (double)price, CancelPreviousOrders = cancelPreviousOrders, Volume = (double)Math.Abs(volume), OrderAction = orderAction.ToMeOrderAction(), Fees = fees }; var response = await _matchingEngineClient.PlaceLimitOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new LimitOrderResponseModel { Id = requestId }; return(ConvertToApiModel(response.Status, result)); }
public async Task PlaceRegularLimitOrder() { var client = CreateConnection(Url); var model = new LimitOrderModel { Id = GenerateUid(), ClientId = ClientId, CancelPreviousOrders = true, AssetPairId = "LKKCHF", OrderAction = OrderAction.Buy, Price = 0.005, Volume = 10 }; // Check that valid request is accepted var response = await client.Retry(x => x.PlaceLimitOrderAsync(model)); ValidateResponse(response, MeStatusCodes.Ok); // Check that resend results in duplicate response = await client.Retry(x => x.PlaceLimitOrderAsync(model)); ValidateResponse(response, MeStatusCodes.Duplicate); // Check that missing price gives InvalidPrice model.Id = GenerateUid(); model.Price = 0; response = await client.Retry(x => x.PlaceLimitOrderAsync(model)); ValidateResponse(response, MeStatusCodes.InvalidPrice); }
public static MeNewLimitOrderModel ToNewMeModel(this LimitOrderModel model) { return(MeNewLimitOrderModel.CreateMeLimitOrder( model.Id, model.ClientId, model.AssetPairId, model.OrderAction, model.Volume, model.Price, model.CancelPreviousOrders, model.Fee?.ToMeModel(), model.Fees?.Select(item => item.ToMeModel()).ToArray())); }
public async Task PlaceLimitOrderAsync(LimitOrder limitOrder) { var model = new LimitOrderModel { AssetPairId = limitOrder.AssetPairId, CancelPreviousOrders = false, ClientId = _walletId, Id = Guid.NewGuid().ToString(), OrderAction = limitOrder.TradeType.ToOrderAction(), Price = (double)limitOrder.Price, Volume = (double)limitOrder.Volume, }; limitOrder.ExternalId = model.Id; MeResponseModel response; try { response = await _matchingEngineClient.PlaceLimitOrderAsync(model, new CancellationTokenSource(Consts.MatchingEngineTimeout).Token); } catch (Exception exception) { _log.Error(exception, "An error occurred during creating limit orders", new { request = $"data: {model.ToJson()}" }); throw; } if (response == null) { throw new Exception("ME response is null"); } if (response.Status == MeStatusCodes.Ok) { _log.Info("ME place limit order response", new { response = $"data: {response.ToJson()}" }); limitOrder.Error = LimitOrderError.None; } else { _log.Warning("ME place limit order response unsuccessful code.", context: new { response = $"data: {response.ToJson()}" }); limitOrder.Error = response.Status.ToOrderError(); limitOrder.ErrorMessage = limitOrder.Error != LimitOrderError.Unknown ? response.Message : !string.IsNullOrEmpty(response.Message) ? response.Message : "Unknown error"; } }
///<inheritdoc cref="IMatchingEngineClient"/> public Task <MeResponseModel> PlaceLimitOrderAsync(LimitOrderModel model, CancellationToken cancellationToken = default) { if (model == null) { throw new ArgumentNullException(nameof(model)); } return(SendData( model.ToNewMeModel(), _newTasksManager, x => x.ToDomainModel(), _meResponsePolicy, cancellationToken, model.Id, $"{model.OrderAction} {model.AssetPairId}" )); }
public async Task <IActionResult> PlaceLimitOrder(PlaceLimitOrderRequest request) { var walletId = User.GetWalletId(); var result = await _validationService.ValidateLimitOrderAsync(walletId, request.AssetPairId, request.Side, request.Price, request.Volume); if (result != null) { throw HftApiException.Create(result.Code, result.Message).AddField(result.FieldName); } var order = new LimitOrderModel { Id = Guid.NewGuid().ToString(), AssetPairId = request.AssetPairId, ClientId = walletId, Price = (double)request.Price, CancelPreviousOrders = false, Volume = (double)Math.Abs(request.Volume), OrderAction = request.Side }; MeResponseModel response = await _matchingEngineClient.PlaceLimitOrderAsync(order); if (response == null) { throw HftApiException.Create(HftApiErrorCode.MeRuntime, "ME not available"); } (HftApiErrorCode code, string message) = response.Status.ToHftApiError(); if (code == HftApiErrorCode.Success) { return(Ok(ResponseModel <LimitOrderResponse> .Ok(new LimitOrderResponse { OrderId = response.TransactionId }))); } throw HftApiException.Create(code, message); }
public override async Task <LimitOrderResponse> PlaceLimitOrder(LimitOrderRequest request, ServerCallContext context) { var walletId = context.GetHttpContext().User.GetWalletId(); var result = await _validationService.ValidateLimitOrderAsync(request.AssetPairId, Convert.ToDecimal(request.Price), Convert.ToDecimal(request.Volume)); if (result != null) { return(new LimitOrderResponse { Error = new Error { Code = (int)result.Code, Message = result.Message } }); } var order = new LimitOrderModel { Id = Guid.NewGuid().ToString(), AssetPairId = request.AssetPairId, ClientId = walletId, Price = Convert.ToDouble(request.Price), CancelPreviousOrders = false, Volume = Math.Abs(Convert.ToDouble(request.Volume)), OrderAction = request.Side == Side.Buy ? OrderAction.Buy : OrderAction.Sell }; MeResponseModel response = await _matchingEngineClient.PlaceLimitOrderAsync(order); if (response == null) { return(new LimitOrderResponse { Error = new Error { Code = (int)HftApiErrorCode.MeRuntime, Message = "ME not available" } }); } (HftApiErrorCode code, string message) = response.Status.ToHftApiError(); if (code == HftApiErrorCode.Success) { return new LimitOrderResponse { Payload = new LimitOrderResponse.Types.LimitOrderPayload { OrderId = response.TransactionId } } } ; return(new LimitOrderResponse { Error = new Error { Code = (int)code, Message = message } }); }
public async Task <IActionResult> PlaceLimitOrder([FromBody] LimitOrderRequest order) { var clientId = _requestContext.ClientId; var pair = await _assetsServiceWithCache.TryGetAssetPairAsync(order.AssetPairId); if (pair == null) { return(NotFound()); } if (pair.IsDisabled) { return(BadRequest()); } var asset = await _assetsServiceWithCache.TryGetAssetAsync(pair.BaseAssetId); if (asset == null || asset.IsDisabled) { return(BadRequest()); } var volume = order.Volume.TruncateDecimalPlaces(asset.Accuracy); if (Math.Abs(volume) < double.Epsilon) { return(BadRequest()); } var id = Guid.NewGuid().ToString(); var price = order.Price.TruncateDecimalPlaces(pair.Accuracy); var request = new LimitOrderCreateRequest { AssetPairId = pair.Id, ClientId = clientId, CreatedAt = DateTime.Now, Id = id, Price = price, Volume = Math.Abs(volume) * (order.OrderAction == Models.Orders.OrderAction.Buy ? 1 : -1), Straight = true, }; await _limitOrdersRepository.AddAsync(request); try { var limitOrderModel = new LimitOrderModel { AssetPairId = pair.Id, ClientId = clientId, Id = id, Price = price, Volume = Math.Abs(volume), OrderAction = ToMeOrderAction(order.OrderAction), }; if (_baseSettings.EnableFees) { limitOrderModel.Fee = await GetLimitOrderFee(clientId, pair, order.OrderAction); } var response = await _matchingEngineClient.PlaceLimitOrderAsync(limitOrderModel); if (response == null) { throw new Exception("ME unavailable"); } if (response.Status != MeStatusCodes.Ok) { var status = MeStatusCodeToOperationsRepositoryOrderStatus(response.Status); await _limitOrdersRepository.FinalizeAsync( new LimitOrderFinalizeRequest { OrderId = id, OrderStatus = status }); return(BadRequest(CreateErrorMessage($"ME responded: {response.Status}"))); } } catch (Exception) { await _limitOrdersRepository.RemoveAsync(clientId, id); throw; } return(Ok(id)); }