public async Task <ResponseModel <MarketOrderResponseModel> > PlaceMarketOrderAsync(string clientId, AssetPair assetPair, OrderAction orderAction, decimal volume, bool straight, double?reservedLimitVolume = null) { var fees = _calculateOrderFees ? await _feeCalculator.GetMarketOrderFees(clientId, assetPair, orderAction) : Array.Empty <MarketOrderFeeModel>(); var order = new MarketOrderModel { Id = GetNextRequestId().ToString(), AssetPairId = assetPair.Id, ClientId = clientId, ReservedLimitVolume = reservedLimitVolume, Straight = straight, Volume = (double)Math.Abs(volume), OrderAction = orderAction.ToMeOrderAction(), Fees = fees }; var response = await _matchingEngineClient.HandleMarketOrderAsync(order); CheckResponseAndThrowIfNull(response); var result = new MarketOrderResponseModel { Price = response.Price }; return(ConvertToApiModel(response.Status, result)); }
public async Task ModifyPosition(MarketOrderModel oldOrder, MarketOrderModel newOrder, long accountId, bool isLive) { VerifyConnection(); if (oldOrder.TradeData.TradeSide != newOrder.TradeSide) { await ClosePosition(oldOrder.Id, oldOrder.Volume, accountId, isLive); newOrder.Id = default; await CreateNewOrder(newOrder, accountId, isLive); } else { if (newOrder.Volume > oldOrder.Volume) { newOrder.Volume = newOrder.Volume - oldOrder.Volume; await CreateNewOrder(newOrder, accountId, isLive); } else { if (newOrder.StopLossInPips != oldOrder.StopLossInPips || newOrder.TakeProfitInPips != oldOrder.TakeProfitInPips) { var amendPositionRequestMessage = new ProtoOAAmendPositionSLTPReq { PositionId = oldOrder.Id, CtidTraderAccountId = accountId, GuaranteedStopLoss = oldOrder.GuaranteedStopLoss, }; if (newOrder.IsStopLossEnabled) { amendPositionRequestMessage.StopLoss = newOrder.StopLossInPrice; amendPositionRequestMessage.StopLossTriggerMethod = oldOrder.StopTriggerMethod; amendPositionRequestMessage.TrailingStopLoss = newOrder.IsTrailingStopLossEnabled; } if (newOrder.IsTakeProfitEnabled) { amendPositionRequestMessage.TakeProfit = newOrder.TakeProfitInPrice; } var client = GetClient(isLive); await client.SendMessage(amendPositionRequestMessage, ProtoOAPayloadType.ProtoOaAmendPositionSltpReq); } if (newOrder.Volume < oldOrder.Volume) { await ClosePosition(oldOrder.Id, oldOrder.Volume - newOrder.Volume, accountId, isLive); } } } }
public static MeMarketOrderModel ToMeModel(this MarketOrderModel model) { return(MeMarketOrderModel.Create( model.Id, model.ClientId, model.AssetPairId, model.OrderAction, model.Volume, model.Straight, model.ReservedLimitVolume, model.Fee?.ToMeModel(), model.Fees.Select(item => item.ToMeModel()).ToArray())); }
///<inheritdoc cref="IMatchingEngineClient"/> public Task <MarketOrderResponse> HandleMarketOrderAsync(MarketOrderModel model, CancellationToken cancellationToken = default) { return(SendData( model.ToMeModel(), _marketOrderTasksManager, x => new MarketOrderResponse { Price = x.Price, Status = (MeStatusCodes)x.Status }, _marketOrderResponsePolicy, cancellationToken, model.Id, $"{model.OrderAction} {model.AssetPairId}" )); }
public async Task <IActionResult> PlaceMarketOrder(PlaceMarketOrderRequest request) { var result = await _validationService.ValidateMarketOrderAsync(request.AssetPairId, request.Volume); if (result != null) { throw HftApiException.Create(result.Code, result.Message).AddField(result.FieldName); } var walletId = User.GetWalletId(); var order = new MarketOrderModel { Id = Guid.NewGuid().ToString(), AssetPairId = request.AssetPairId, ClientId = walletId, Volume = (double)request.Volume, OrderAction = request.Side, Straight = true }; var response = await _matchingEngineClient.HandleMarketOrderAsync(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 <MarketOrderResponse> .Ok(new MarketOrderResponse { OrderId = order.Id, Price = (decimal)response.Price }))); } throw HftApiException.Create(code, message); }
public override async Task <MarketOrderResponse> PlaceMarketOrder(MarketOrderRequest request, ServerCallContext context) { var walletId = context.GetHttpContext().User.GetWalletId(); var result = await _validationService.ValidateMarketOrderAsync(request.AssetPairId, Convert.ToDecimal(request.Volume)); if (result != null) { return(new MarketOrderResponse { Error = new Error { Code = (int)result.Code, Message = result.Message } }); } var order = new MarketOrderModel { Id = Guid.NewGuid().ToString(), AssetPairId = request.AssetPairId, ClientId = walletId, Volume = Math.Abs(Convert.ToDouble(request.Volume)), OrderAction = request.Side == Side.Buy ? OrderAction.Buy : OrderAction.Sell, Straight = true }; var response = await _matchingEngineClient.HandleMarketOrderAsync(order); if (response == null) { return(new MarketOrderResponse { Error = new Error { Code = (int)HftApiErrorCode.MeRuntime, Message = "ME not available" } }); } (HftApiErrorCode code, string message) = response.Status.ToHftApiError(); if (code == HftApiErrorCode.Success) { return new MarketOrderResponse { Payload = new MarketOrderResponse.Types.MarketOrderPayload { OrderId = order.Id, Price = response.Price.ToString(CultureInfo.InvariantCulture) } } } ; return(new MarketOrderResponse { Error = new Error { Code = (int)code, Message = message } }); }
public async Task <IActionResult> PlaceMarketOrder([FromBody] MarketOrderRequest request) { var clientId = _requestContext.ClientId; var pair = await _assetsServiceWithCache.TryGetAssetPairAsync(request.AssetPairId); if (pair == null) { return(NotFound()); } if (pair.IsDisabled) { return(BadRequest()); } var baseAsset = await _assetsServiceWithCache.TryGetAssetAsync(pair.BaseAssetId); if (baseAsset == null) { return(NotFound()); } var quotingAsset = await _assetsServiceWithCache.TryGetAssetAsync(pair.QuotingAssetId); if (quotingAsset == null) { return(BadRequest()); } if (request.AssetId != baseAsset.Id && request.AssetId != baseAsset.Name && request.AssetId != quotingAsset.Id && request.AssetId != quotingAsset.Name) { return(BadRequest()); } var straight = request.AssetId == baseAsset.Id || request.AssetId == baseAsset.Name; var volume = request.Volume.TruncateDecimalPlaces(straight ? baseAsset.Accuracy : quotingAsset.Accuracy); if (Math.Abs(volume) < double.Epsilon) { return(BadRequest(CreateErrorMessage("Required volume is less than asset accuracy"))); } var order = new MarketOrderModel { Id = Guid.NewGuid().ToString(), AssetPairId = pair.Id, ClientId = clientId, ReservedLimitVolume = null, Straight = straight, Volume = Math.Abs(volume), OrderAction = ToMeOrderAction(request.OrderAction) }; if (_baseSettings.EnableFees) { order.Fees = new[] { await GetMarketOrderFee(clientId, request.AssetPairId, request.AssetId, request.OrderAction) } } ; var response = await _matchingEngineClient.HandleMarketOrderAsync(order); if (response == null) { throw new Exception("ME unavailable"); } if (response.Status != MeStatusCodes.Ok) { return(BadRequest(CreateErrorMessage($"ME responded: {response.Status}"))); } return(Ok(order.Id)); }