示例#1
0
        public async Task <ResponseModel <IMarginTradingWatchList> > AddWatchList([FromBody] WatchList model)
        {
            var clientId = User.GetClaim(ClaimTypes.NameIdentifier);

            if (clientId == null)
            {
                return(ResponseModel <IMarginTradingWatchList> .CreateFail(ResponseModel.ErrorCodeType.NoAccess, "Wrong token"));
            }

            var result = new ResponseModel <IMarginTradingWatchList>();

            if (model.AssetIds == null || model.AssetIds.Count == 0)
            {
                return(ResponseModel <IMarginTradingWatchList> .CreateInvalidFieldError("AssetIds", "AssetIds should not be empty"));
            }

            var addResult = await _watchListService.AddAsync(model.Id, clientId, model.Name, model.AssetIds);

            switch (addResult.Status)
            {
            case WatchListStatus.AssetNotFound:
                return(ResponseModel <IMarginTradingWatchList> .CreateFail(ResponseModel.ErrorCodeType.AssetNotFound, $"Asset '{addResult.Message}' is not found or not allowed"));

            case WatchListStatus.ReadOnly:
                return(ResponseModel <IMarginTradingWatchList> .CreateFail(ResponseModel.ErrorCodeType.InconsistentData, "This watch list is readonly"));
            }

            result.Result = addResult.Result;

            return(result);
        }
        public async Task <ResponseModel> Post(PinSecurityChangeModel data)
        {
            if (string.IsNullOrEmpty(data.Pin))
            {
                return(ResponseModel.CreateInvalidFieldError("pin", Phrases.FieldShouldNotBeEmpty));
            }

            if (!data.Pin.IsOnlyDigits())
            {
                return(ResponseModel.CreateInvalidFieldError("pin", Phrases.PinShouldContainsDigitsOnly));
            }

            if (data.Pin.Length < 4)
            {
                return(ResponseModel.CreateInvalidFieldError("pin", Phrases.MinLengthIs4Digits));
            }

            var clientId = this.GetClientId();

            if (string.IsNullOrEmpty(clientId))
            {
                return(ResponseModel <PinSecurityCheckResultModel> .CreateFail(ResponseModel.ErrorCodeType.NotAuthenticated, Phrases.NotAuthenticated));
            }
            await _puPinSecurityRepository.SaveAsync(clientId, data.Pin);

            return(ResponseModel.CreateOk());
        }
示例#3
0
        public async Task <ResponseModel <AuthenticateResponseModel> > Post(AuthenticateModel model)
        {
            if (string.IsNullOrEmpty(model.Email))
            {
                return(ResponseModel <AuthenticateResponseModel> .CreateInvalidFieldError("email", Phrases.FieldShouldNotBeEmpty));
            }

            if (!model.Email.IsValidEmail())
            {
                return(ResponseModel <AuthenticateResponseModel> .CreateInvalidFieldError("email", Phrases.InvalidEmailFormat));
            }

            if (string.IsNullOrEmpty(model.Password))
            {
                return(ResponseModel <AuthenticateResponseModel> .CreateInvalidFieldError("passowrd", Phrases.FieldShouldNotBeEmpty));
            }

            var client = await _clientAccountsRepository.AuthenticateAsync(model.Email, model.Password);

            if (client == null)
            {
                return(ResponseModel <AuthenticateResponseModel> .CreateInvalidFieldError("passowrd", Phrases.InvalidUsernameOrPassword));
            }

            this.AuthenticateUserViaOwin(client);

            return(ResponseModel <AuthenticateResponseModel> .CreateOk(new AuthenticateResponseModel
            {
                KycStatus = (await _kycRepository.GetKycStatusAsync(client.Id)).ToString(),
                PinIsEntered = await _pinSecurityRepository.IsPinEntered(client.Id)
            }));
        }
示例#4
0
        public async Task <ResponseModel> Post(KycDocumentsModel model)
        {
            if (string.IsNullOrEmpty(model.Type))
            {
                return(ResponseModel.CreateInvalidFieldError("type", Phrases.FieldShouldNotBeEmpty));
            }


            if (!KycDocumentTypes.HasDocumentType(model.Type))
            {
                return(ResponseModel.CreateInvalidFieldError("type", Phrases.InvalidDocumentType));
            }

            if (string.IsNullOrEmpty(model.Ext))
            {
                return(ResponseModel.CreateInvalidFieldError("ext", Phrases.FieldShouldNotBeEmpty));
            }

            if (string.IsNullOrEmpty(model.Data))
            {
                return(ResponseModel.CreateInvalidFieldError("data", Phrases.FieldShouldNotBeEmpty));
            }


            byte[] data;
            try
            {
                data = Convert.FromBase64String(model.Data);
            }
            catch (Exception)
            {
                return(ResponseModel.CreateInvalidFieldError("data", "Base64 format expected"));
            }

            var clientId = this.GetClientId();

            if (string.IsNullOrEmpty(clientId))
            {
                return(ResponseModel.CreateFail(ResponseModel.ErrorCodeType.NotAuthenticated, Phrases.NotAuthenticated));
            }

            var status = await _kycRepository.GetKycStatusAsync(clientId);

            if (status != KycStatus.NeedToFillData)
            {
                return(ResponseModel.CreateFail(ResponseModel.ErrorCodeType.InconsistentData, Phrases.OperationCanNotBePerformed));
            }


            var fileName = "myFile" + model.Ext.AddFirstSymbolIfNotExists('.');
            var mimeType = MimeMapping.GetMimeMapping(fileName);

            await
            _srvKycDocumentsManager.UploadDocument(clientId, model.Type, fileName, mimeType, data);

            return(ResponseModel.CreateOk());
        }
        /// <summary>
        /// Validate requested price.
        /// </summary>
        public bool ValidatePrice(decimal price, out ResponseModel model, string name = "Price")
        {
            if (price <= 0)
            {
                model = ResponseModel.CreateInvalidFieldError(name, "Price must be greater than asset accuracy.");
                return(false);
            }

            model = null;
            return(true);
        }
        /// <summary>
        /// Validate requested asset.
        /// </summary>
        public bool ValidateAsset(AssetPair assetPair, string assetId,
                                  Asset baseAsset, Asset quotingAsset, out ResponseModel model)
        {
            if (assetId != baseAsset.Id && assetId != baseAsset.DisplayId && assetId != quotingAsset.Id && assetId != quotingAsset.DisplayId)
            {
                model = ResponseModel.CreateInvalidFieldError("Asset", $"Asset <{assetId}> is not valid for asset pair <{assetPair.Id}>.");
                return(false);
            }

            model = null;
            return(true);
        }
        public async Task <ResponseModel> Post(AccountRegistrationModel model)
        {
            if (string.IsNullOrEmpty(model.Email))
            {
                return(ResponseModel.CreateInvalidFieldError("email", Phrases.FieldShouldNotBeEmpty));
            }

            if (!model.Email.IsValidEmail())
            {
                return(ResponseModel.CreateInvalidFieldError("email", Phrases.InvalidEmailFormat));
            }

            if (string.IsNullOrEmpty(model.FirstName))
            {
                return(ResponseModel.CreateInvalidFieldError("firstname", Phrases.FieldShouldNotBeEmpty));
            }

            if (string.IsNullOrEmpty(model.LastName))
            {
                return(ResponseModel.CreateInvalidFieldError("lastname", Phrases.FieldShouldNotBeEmpty));
            }

            if (string.IsNullOrEmpty(model.ContactPhone))
            {
                return(ResponseModel.CreateInvalidFieldError("contactphone", Phrases.FieldShouldNotBeEmpty));
            }

            if (await _clientAccountsRepository.IsTraderWithEmailExistsAsync(model.Email))
            {
                return(ResponseModel.CreateInvalidFieldError("email", Phrases.ClientWithEmailIsRegistered));
            }

            if (string.IsNullOrEmpty(model.Password))
            {
                return(ResponseModel.CreateInvalidFieldError("passowrd", Phrases.FieldShouldNotBeEmpty));
            }

            try
            {
                var user = await _srvClientManager.RegisterClientAsync(model.Email, model.FirstName, model.LastName, model.ContactPhone, model.Password);

                this.AuthenticateUserViaOwin(user);
                return(ResponseModel.CreateOk());
            }
            catch (Exception ex)
            {
                return(ResponseModel.CreateInvalidFieldError("email", ex.StackTrace));
            }
        }
        public async Task <ResponseModel <AccountExistResultModel> > Get(string email)
        {
            if (string.IsNullOrEmpty(email))
            {
                return(ResponseModel <AccountExistResultModel> .CreateInvalidFieldError("email", Phrases.FieldShouldNotBeEmpty));
            }

            if (!email.IsValidEmail())
            {
                return(ResponseModel <AccountExistResultModel> .CreateInvalidFieldError("email", Phrases.InvalidEmailFormat));
            }

            return(ResponseModel <AccountExistResultModel> .CreateOk(
                       new AccountExistResultModel { IsEmailRegistered = await _clientAccountsRepository.IsTraderWithEmailExistsAsync(email) }));
        }
        /// <summary>
        /// Validate requested asset pair.
        /// </summary>
        public bool ValidateAssetPair(string assetPairId, AssetPair assetPair, out ResponseModel model)
        {
            if (assetPair == null)
            {
                model = ResponseModel.CreateInvalidFieldError("AssetPairId", $"AssetPair {assetPairId} is unknown");
                return(false);
            }
            if (IsAssetPairDisabled(assetPair))
            {
                model = ResponseModel.CreateInvalidFieldError("AssetPairId", $"AssetPair {assetPairId} is temporarily disabled");
                return(false);
            }

            model = null;
            return(true);
        }
        public static ResponseModel <int> ValidateAndGetValue(this int?paramValue, string parameter, int maxValue, int defaultValue)
        {
            var value = paramValue.GetValueOrDefault(defaultValue);

            if (value > maxValue)
            {
                return(ResponseModel <int> .CreateInvalidFieldError(parameter, $"{parameter} '{value}' is too big, maximum is '{maxValue}'."));
            }

            if (value < 0)
            {
                return(ResponseModel <int> .CreateInvalidFieldError(parameter, $"{parameter} cannot be less than zero."));
            }

            if (value == 0)
            {
                value = defaultValue;
            }

            return(ResponseModel <int> .CreateOk(value));
        }
        public async Task <IActionResult> GetOrders(OrderStatusQuery?status = null, int?take = 100, OrderType orderType = OrderType.Unknown)
        {
            var toTake = take.ValidateAndGetValue(nameof(take), MaxPageSize, 100);

            if (toTake.Error != null)
            {
                return(BadRequest(toTake.Error));
            }

            if (!status.HasValue)
            {
                status = OrderStatusQuery.All;
            }

            var walletId   = Guid.Parse(User.GetUserId());
            var orderTypes = orderType == OrderType.Unknown
                ? new History.Contracts.Enums.OrderType[0]
                : new[] { (History.Contracts.Enums.OrderType)orderType };

            IEnumerable <OrderModel> orders = new List <OrderModel>();

            try
            {
                switch (status)
                {
                case OrderStatusQuery.All:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new History.Contracts.Enums.OrderStatus[0],
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Open:
                    orders = await _historyClient.OrdersApi.GetActiveOrdersByWalletAsync(walletId, 0,
                                                                                         toTake.Result);

                    break;

                case OrderStatusQuery.InOrderBook:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.Placed },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Processing:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.PartiallyMatched },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Matched:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.Matched },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Replaced:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.Replaced },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Cancelled:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.Cancelled },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                case OrderStatusQuery.Rejected:
                    orders = await _historyClient.OrdersApi.GetOrdersByWalletAsync(
                        walletId,
                        new[] { History.Contracts.Enums.OrderStatus.Rejected },
                        orderTypes,
                        0,
                        toTake.Result);

                    break;

                default:
                    return(BadRequest(
                               ResponseModel.CreateInvalidFieldError("status", $"Invalid status: <{status}>")));
                }
            }
            catch (Exception ex)
            {
                _log.Warning("Error getting orders", ex, context: new { walletId = walletId, status, orderType, take = toTake.Result }.ToJson());
            }

            return(Ok(orders.Select(ToModel)));
        }
        public async Task <IActionResult> PlaceStopLimitOrder([FromBody] PlaceStopLimitOrderModel order)
        {
            var assetPair = _assetPairsReadModel.TryGetIfEnabled(order.AssetPairId);

            if (assetPair == null)
            {
                return(NotFound($"Asset-pair {order.AssetPairId} could not be found or is disabled."));
            }

            if (!_requestValidator.ValidateAssetPair(order.AssetPairId, assetPair, out var badRequestModel))
            {
                return(BadRequest(badRequestModel));
            }

            var asset = _assetsReadModel.TryGetIfEnabled(assetPair.BaseAssetId);

            if (asset == null)
            {
                throw new InvalidOperationException($"Base asset '{assetPair.BaseAssetId}' for asset pair '{assetPair.Id}' not found.");
            }


            var lowerPrice = order.LowerPrice;

            if (lowerPrice.HasValue && !_requestValidator.ValidatePrice(lowerPrice.Value, out badRequestModel, nameof(PlaceStopLimitOrderModel.LowerPrice)))
            {
                return(BadRequest(badRequestModel));
            }

            var lowerLimitPrice = order.LowerLimitPrice;

            if (lowerLimitPrice.HasValue && !_requestValidator.ValidatePrice(lowerLimitPrice.Value, out badRequestModel, nameof(PlaceStopLimitOrderModel.LowerLimitPrice)))
            {
                return(BadRequest(badRequestModel));
            }

            if ((lowerPrice.HasValue && !lowerLimitPrice.HasValue) ||
                (!lowerPrice.HasValue && lowerLimitPrice.HasValue))
            {
                return(BadRequest(ResponseModel.CreateInvalidFieldError(nameof(order.LowerPrice), "When lower price is send then also lower limit price is required and vice versa.")));
            }

            var upperPrice = order.UpperPrice;

            if (upperPrice.HasValue && !_requestValidator.ValidatePrice(upperPrice.Value, out badRequestModel, nameof(PlaceStopLimitOrderModel.UpperPrice)))
            {
                return(BadRequest(badRequestModel));
            }

            var upperLimitPrice = order.UpperLimitPrice;

            if (upperLimitPrice.HasValue && !_requestValidator.ValidatePrice(upperLimitPrice.Value, out badRequestModel, nameof(PlaceStopLimitOrderModel.UpperLimitPrice)))
            {
                return(BadRequest(badRequestModel));
            }

            if ((upperPrice.HasValue && !upperLimitPrice.HasValue) ||
                (!upperPrice.HasValue && upperLimitPrice.HasValue))
            {
                return(BadRequest(ResponseModel.CreateInvalidFieldError(nameof(order.UpperPrice), "When upper price is send then also upper limit price is required and vice versa.")));
            }

            if (new[] { lowerPrice, lowerLimitPrice, upperPrice, upperLimitPrice }.All(x => !x.HasValue))
            {
                return(BadRequest(ResponseModel.CreateFail(ErrorCodeType.Rejected,
                                                           "At least lower or upper prices are needed for a stop order.")));
            }

            var volume    = order.Volume;
            var minVolume = assetPair.MinVolume;

            if (!_requestValidator.ValidateVolume(volume, minVolume, asset.DisplayId, out badRequestModel))
            {
                return(BadRequest(badRequestModel));
            }

            var walletId = User.GetUserId();
            var response = await _matchingEngineAdapter.PlaceStopLimitOrderAsync(
                clientId : walletId,
                assetPair : assetPair,
                orderAction : order.OrderAction,
                volume : volume,
                lowerPrice : lowerPrice,
                lowerLimitPrice : lowerLimitPrice,
                upperPrice : upperPrice,
                upperLimitPrice : upperLimitPrice);

            if (response.Error != null)
            {
                return(BadRequest(response));
            }

            return(Ok(response.Result));
        }