예제 #1
0
        public override async Task <CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
        {
            MeResponseModel response = await _matchingEngineClient.CancelLimitOrderAsync(request.OrderId);

            if (response == null)
            {
                return(new CancelOrderResponse
                {
                    Error = new ErrorResponseBody {
                        Code = ErrorCode.Runtime, Message = ErrorMessages.MeNotAvailable
                    }
                });
            }

            if (response.Status == MeStatusCodes.Ok || response.Status == MeStatusCodes.NotFound)
            {
                return new CancelOrderResponse {
                           Body = new CancelOrderResponse.Types.Body {
                               Payload = true
                           }
                }
            }
            ;

            return(new CancelOrderResponse
            {
                Error = new ErrorResponseBody {
                    Code = ErrorCode.Unknown, Message = $"ME status: {response.Status}, message: {response.Message}"
                }
            });
        }
예제 #2
0
        public async Task <IActionResult> CancelAllOrders([FromQuery] string assetPairId = null, [FromQuery] OrderAction?side = null)
        {
            var assetPairResult = await _validationService.ValidateAssetPairAsync(assetPairId);

            if (assetPairResult != null)
            {
                throw HftApiException.Create(assetPairResult.Code, assetPairResult.Message).AddField(assetPairResult.FieldName);
            }

            bool?isBuy;

            switch (side)
            {
            case OrderAction.Buy:
                isBuy = true;
                break;

            case OrderAction.Sell:
                isBuy = false;
                break;

            default:
                isBuy = null;
                break;
            }

            var model = new LimitOrderMassCancelModel
            {
                Id          = Guid.NewGuid().ToString(),
                AssetPairId = assetPairId,
                ClientId    = User.GetWalletId(),
                IsBuy       = isBuy
            };

            MeResponseModel response = await _matchingEngineClient.MassCancelLimitOrdersAsync(model);

            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 <string> .Ok(null)));
            }

            throw HftApiException.Create(code, message);
        }
예제 #3
0
        public async Task <IActionResult> CancelOrder(string orderId)
        {
            MeResponseModel response = await _matchingEngineClient.CancelLimitOrderAsync(orderId);

            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 <string> .Ok(null)));
            }

            throw HftApiException.Create(code, message);
        }
예제 #4
0
        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);
        }
예제 #5
0
        public override async Task <CancelOrderResponse> CancelOrder(CancelOrderRequest request, ServerCallContext context)
        {
            MeResponseModel response = await _matchingEngineClient.CancelLimitOrderAsync(request.OrderId);

            if (response == null)
            {
                return(new CancelOrderResponse
                {
                    Error = new Error
                    {
                        Code = (int)HftApiErrorCode.MeRuntime,
                        Message = "ME not available"
                    }
                });
            }

            (HftApiErrorCode code, string message) = response.Status.ToHftApiError();

            if (code == HftApiErrorCode.Success)
            {
                return new CancelOrderResponse
                       {
                           Payload = true
                       }
            }
            ;

            return(new CancelOrderResponse
            {
                Error = new Error
                {
                    Code = (int)code,
                    Message = message
                }
            });
        }
예제 #6
0
        public async Task <CommandHandlingResult> Handle(EnrollEthCashinToMatchingEngineCommand command, IEventPublisher eventPublisher)
        {
            try
            {
                var cashinId = command.CashinOperationId.ToString("N");
                var clientId = command.ClientId;
                var hash     = command.TransactionHash;
                var amount   = command.Amount;
                var asset    = await _assetsServiceWithCache.TryGetAssetAsync(command.AssetId);

                var createPendingActions = command.CreatePendingActions;
                var paymentTransaction   = PaymentTransaction.Create(hash,
                                                                     CashInPaymentSystem.Ethereum, clientId.ToString(), (double)amount,
                                                                     asset.DisplayId ?? asset.Id, status: PaymentStatus.Processing);

                var exists = await _paymentTransactionsRepository.CheckExistsAsync(paymentTransaction);

                if (exists)
                {
                    _log.Warning(command.TransactionHash ?? "Empty", $"Transaction already handled {hash}",
                                 context: command);

                    return(CommandHandlingResult.Ok());
                }

                if (createPendingActions && asset.IsTrusted)
                {
                    await _ethererumPendingActionsRepository.CreateAsync(clientId.ToString(), Guid.NewGuid().ToString());
                }

                ChaosKitty.Meow();

                MeResponseModel result = null;

                await ExecuteWithTimeoutHelper.ExecuteWithTimeoutAsync(async() =>
                {
                    result = await _matchingEngineClient.CashInOutAsync(cashinId, clientId.ToString(), asset.Id, (double)amount);
                }, 5 * 60 * 1000);     // 5 min in ms

                if (result == null ||
                    (result.Status != MeStatusCodes.Ok &&
                     result.Status != MeStatusCodes.Duplicate))
                {
                    _log.Warning(command.TransactionHash ?? "Empty", "ME error", context: result);

                    return(CommandHandlingResult.Fail(TimeSpan.FromMinutes(1)));
                }

                eventPublisher.PublishEvent(new EthCashinEnrolledToMatchingEngineEvent()
                {
                    TransactionHash = hash,
                });

                ChaosKitty.Meow();

                await _paymentTransactionsRepository.TryCreateAsync(paymentTransaction);

                return(CommandHandlingResult.Ok());
            }
            catch (Exception e)
            {
                _log.Error(nameof(EnrollEthCashinToMatchingEngineCommand), e, context: command);
                throw;
            }
        }
        private static async Task <MeResponseModel> SanitizeExpandedAccount(
            IAccount account,
            IReadOnlyDictionary <string, bool> expansionOptions,
            CancellationToken cancellationToken)
        {
            var sanitizedModel = new MeResponseModel
            {
                Href                   = account.Href,
                Email                  = account.Email,
                Username               = account.Username,
                GivenName              = account.GivenName,
                MiddleName             = account.MiddleName,
                Surname                = account.Surname,
                FullName               = account.FullName,
                CreatedAt              = account.CreatedAt,
                ModifiedAt             = account.ModifiedAt,
                Status                 = account.Status.ToString(),
                PasswordModifiedAt     = account.PasswordModifiedAt,
                EmailVerificationToken = account.EmailVerificationToken?.GetValue()
            };

            if (!expansionOptions.Any(e => e.Value))
            {
                return(sanitizedModel);
            }

            // TODO might be able to simply return the interface objects directly after explicit interfaces are removed

            if (expansionOptions.Any(e => e.Key.Equals("applications", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                // TODO replace with ToArrayAsync
                var applications = await account.GetApplications().ToListAsync(cancellationToken);

                sanitizedModel.Applications = new
                {
                    size  = applications.Count,
                    items = applications.Select(a => new
                    {
                        href        = a.Href,
                        name        = a.Name,
                        description = a.Description,
                        status      = a.Status.ToString(),
                        createdAt   = a.CreatedAt,
                        modifiedAt  = a.ModifiedAt,
                    })
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("apiKeys", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                // TODO replace with ToArrayAsync
                var apiKeys = await account.GetApiKeys().ToListAsync(cancellationToken);

                sanitizedModel.ApiKeys = new
                {
                    size  = apiKeys.Count,
                    items = apiKeys.Select(k => new
                    {
                        href        = k.Href,
                        name        = k.Name,
                        description = k.Description,
                        id          = k.Id,
                        status      = k.Status.ToString(),
                    })
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("customData", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                sanitizedModel.CustomData = (await account.GetCustomDataAsync(cancellationToken))
                                            .ToDictionary(cd => cd.Key, cd => cd.Value);
            }

            if (expansionOptions.Any(e => e.Key.Equals("directory", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                var directory = await account.GetDirectoryAsync(cancellationToken);

                sanitizedModel.Directory = new
                {
                    href        = directory.Href,
                    name        = directory.Name,
                    description = directory.Description,
                    status      = directory.Status.ToString(),
                    createdAt   = directory.CreatedAt,
                    modifiedAt  = directory.ModifiedAt,
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("groupMemberships", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                // TODO replace with ToArrayAsync
                var groupMemberships = await account.GetGroupMemberships().ToListAsync(cancellationToken);

                sanitizedModel.GroupMemberships = new
                {
                    size  = groupMemberships.Count,
                    items = groupMemberships.Select(gm => new
                    {
                        href = gm.Href
                    })
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("groups", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                // TODO replace with ToArrayAsync
                var groups = await account.GetGroups().ToListAsync(cancellationToken);

                sanitizedModel.Groups = new
                {
                    // TODO add href if available on IAsyncQueryable
                    size  = groups.Count,
                    items = groups.Select(g => new
                    {
                        href        = g.Href,
                        name        = g.Name,
                        description = g.Description,
                        status      = g.Status.ToString(),
                        createdAt   = g.CreatedAt,
                        modifiedAt  = g.ModifiedAt,
                    })
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("providerData", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                var providerData = await account.GetProviderDataAsync(cancellationToken);

                sanitizedModel.ProviderData = new
                {
                    href       = providerData.Href,
                    createdAt  = providerData.CreatedAt,
                    modifiedAt = providerData.ModifiedAt,
                    providerId = providerData.ProviderId
                };
            }

            if (expansionOptions.Any(e => e.Key.Equals("tenant", StringComparison.OrdinalIgnoreCase) && e.Value))
            {
                var tenant = await account.GetTenantAsync(cancellationToken);

                sanitizedModel.Tenant = new
                {
                    href       = tenant.Href,
                    name       = tenant.Name,
                    key        = tenant.Key,
                    createdAt  = tenant.CreatedAt,
                    modifiedAt = tenant.ModifiedAt
                };
            }

            return(sanitizedModel);
        }
예제 #8
0
        public async Task LimitOrderBuy() // and CancelLimitOrder
        {
            AccountEntity testAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount);
            BalanceDTO accountBalance = testAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.NotNull(accountBalance);

            string limitOrderID    = Guid.NewGuid().ToString();
            string badLimitOrderID = Guid.NewGuid().ToString();

            double amount = 0.01;
            double price  = Helpers.Random.NextDouble() / 100;

            //Attempt bad buy
            MeResponseModel badOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                badLimitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Buy, accountBalance.Balance + 10, 2);

            Assert.False(badOrderResponse.Status == MeStatusCodes.Ok);

            LimitOrdersResponse badMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds"));

            Assert.NotNull(badMessage);

            LimitOrders badSubMessage = badMessage.orders.Where(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds").FirstOrDefault();

            Assert.NotNull(badSubMessage);
            Assert.True(badSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(badSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(badSubMessage.order.volume == accountBalance.Balance + 10);
            //Assert.True(badSubMessage.order.price == price);


            //Attempt buy stored in order book
            MeResponseModel LimitOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                limitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Buy, amount, price);

            Assert.True(LimitOrderResponse.Status == MeStatusCodes.Ok);

            AccountEntity checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance.Reserved, this.AssetPrecission) == Math.Round(accountBalance.Reserved + amount, this.AssetPrecission));

            LimitOrdersResponse message = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook"));

            Assert.NotNull(message);

            LimitOrders subMessage = message.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook").FirstOrDefault();

            Assert.NotNull(subMessage);
            Assert.True(subMessage.order.clientId == this.TestAccountId1);
            Assert.True(subMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(subMessage.order.volume == amount);
            Assert.True(subMessage.order.price == price);


            //Cancel proper buy
            MeResponseModel LimitOrderCancelResponse = await this.Consumer.Client.CancelLimitOrderAsync(limitOrderID);

            Assert.True(LimitOrderCancelResponse.Status == MeStatusCodes.Ok);

            checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.True(checkAccountBalance.Reserved == accountBalance.Reserved);

            LimitOrdersResponse cancelMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled"));

            Assert.NotNull(cancelMessage);

            LimitOrders cancelSubMessage = cancelMessage.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled").FirstOrDefault();

            Assert.NotNull(cancelSubMessage);
            Assert.True(cancelSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(cancelSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(cancelSubMessage.order.volume == amount);
            Assert.True(cancelSubMessage.order.price == price);
        }
예제 #9
0
        public async Task LimitOrderSell() // and CancelLimitOrder
        {
            AccountEntity testAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount);
            BalanceDTO accountBalance = testAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance);

            string limitOrderID    = Guid.NewGuid().ToString();
            string badLimitOrderID = Guid.NewGuid().ToString();

            double amount       = 0.2;
            double price        = Helpers.Random.Next(100, 999);
            double matchedPrice = Helpers.Random.NextDouble();

            //Attempt bad sell
            MeResponseModel badOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                badLimitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Sell, accountBalance.Balance + 10, price);

            Assert.False(badOrderResponse.Status == MeStatusCodes.Ok);

            LimitOrdersResponse badMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds"));

            Assert.NotNull(badMessage);

            LimitOrders badSubMessage = badMessage.orders.Where(m => m.order.externalId == badLimitOrderID && m.order.status == "NotEnoughFunds").FirstOrDefault();

            Assert.NotNull(badSubMessage);
            Assert.True(badSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(badSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(badSubMessage.order.volume == (accountBalance.Balance + 10) * -1);
            Assert.True(badSubMessage.order.price == price);

            //Attempt sell stored in order book
            MeResponseModel LimitOrderResponse = await this.Consumer.Client.PlaceLimitOrderAsync(
                limitOrderID, this.TestAccountId1, this.TestAssetPair.Id, OrderAction.Sell, amount, price);

            Assert.True(LimitOrderResponse.Status == MeStatusCodes.Ok);

            AccountEntity checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance.Reserved, this.AssetPrecission) == Math.Round(accountBalance.Reserved + amount, this.AssetPrecission));


            LimitOrdersResponse message = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook"));

            Assert.NotNull(message);

            LimitOrders subMessage = message.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "InOrderBook").FirstOrDefault();

            Assert.NotNull(subMessage);
            Assert.True(subMessage.order.clientId == this.TestAccountId1);
            Assert.True(subMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(subMessage.order.volume == amount * -1);
            Assert.True(subMessage.order.price == price);


            //LimitOrderEntity limitOrderFromDB = (LimitOrderEntity)await fixture.LimitOrdersRepository.TryGetAsync("Active_" + fixture.TestAccountId1, subMessage.order.id);
            //Assert.NotNull(limitOrderFromDB);
            //Assert.True(limitOrderFromDB.AssetPairId == fixture.TestAssetPair.Id);
            //Assert.True(limitOrderFromDB.Price == subMessage.order.price);
            //Assert.True(limitOrderFromDB.Status == subMessage.order.status);
            //Assert.True(limitOrderFromDB.Volume == amount);
            //Assert.True(limitOrderFromDB.RemainingVolume == subMessage.order.remainingVolume);
            //Assert.True(limitOrderFromDB.Straight == );
            //Assert.True(limitOrderFromDB.MatchingId == subMessage.order.);

            //Cancel the proper sell
            MeResponseModel LimitOrderCancelResponse = await this.Consumer.Client.CancelLimitOrderAsync(limitOrderID);

            Assert.True(LimitOrderCancelResponse.Status == MeStatusCodes.Ok);

            checkTestAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance = checkTestAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(checkAccountBalance.Reserved == accountBalance.Reserved);

            LimitOrdersResponse cancelMessage = (LimitOrdersResponse)await this.WaitForRabbitMQ <LimitOrdersResponse>(
                o => o.orders.Any(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled"));

            Assert.NotNull(cancelMessage);

            LimitOrders cancelSubMessage = cancelMessage.orders.Where(m => m.order.externalId == limitOrderID && m.order.status == "Cancelled").FirstOrDefault();

            Assert.NotNull(cancelSubMessage);
            Assert.True(cancelSubMessage.order.clientId == this.TestAccountId1);
            Assert.True(cancelSubMessage.order.assetPairId == this.TestAssetPair.Id);
            Assert.True(cancelSubMessage.order.volume == amount * -1);
            Assert.True(cancelSubMessage.order.price == price);
        }
예제 #10
0
        public async Task CashInOut()
        {
            AccountEntity testAccount = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount);
            BalanceDTO accountBalance = testAccount.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance);

            double realBallance = accountBalance.Balance - accountBalance.Reserved;



            // Low Balance cashout test
            double badCashOutAmmount = (realBallance + 0.1) * -1;

            MeResponseModel meBadCashOutResponse = await this.Consumer.Client.CashInOutAsync(
                Guid.NewGuid().ToString(), testAccount.Id, accountBalance.Asset, badCashOutAmmount);


            Assert.True(meBadCashOutResponse.Status == MeStatusCodes.LowBalance);



            // Good cashout test
            string goodCashOutID = Guid.NewGuid().ToString();

            double goodCashOutAmmount = Math.Round((realBallance / 10) * -1, this.AssetPrecission);

            MeResponseModel meGoodCashOutResponse = await this.Consumer.Client.CashInOutAsync(
                goodCashOutID, testAccount.Id, accountBalance.Asset, goodCashOutAmmount);

            Assert.True(meGoodCashOutResponse.Status == MeStatusCodes.Ok);

            CashOperation message = (CashOperation)await this.WaitForRabbitMQ <CashOperation>(o => o.id == goodCashOutID);

            Assert.NotNull(message);

            Assert.True(message.clientId == testAccount.Id);
            Assert.True(message.asset == accountBalance.Asset);

            if (Double.TryParse(message.volume, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedVolume))
            {
                Assert.True(parsedVolume == goodCashOutAmmount);
            }

            AccountEntity testAccountCheck = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO balanceCheck = testAccountCheck.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(Math.Round(balanceCheck.Balance, this.AssetPrecission) == Math.Round(accountBalance.Balance + goodCashOutAmmount, this.AssetPrecission)); // TODO get asset accuracy

            //Cash In test
            string          cashInID         = Guid.NewGuid().ToString();
            double          cashInAmmount    = goodCashOutAmmount * -1; //cash in the same ammount we cashed out
            MeResponseModel meCashInResponse = await this.Consumer.Client.CashInOutAsync(
                cashInID, testAccount.Id, this.TestAsset1, cashInAmmount);

            Assert.True(meCashInResponse.Status == MeStatusCodes.Ok);

            message = (CashOperation)await this.WaitForRabbitMQ <CashOperation>(o => o.id == cashInID);

            Assert.NotNull(message);

            Assert.True(message.clientId == testAccount.Id);
            Assert.True(message.asset == accountBalance.Asset);

            if (Double.TryParse(message.volume, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedVolume))
            {
                Assert.True(parsedVolume == cashInAmmount);
            }


            //balances after cashout -> cashin with the same ammount should not differ

            AccountEntity testAccountAfter = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccountAfter);

            BalanceDTO accountBalanceAfter = testAccountAfter.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalanceAfter);

            Assert.True(accountBalance.Balance == accountBalanceAfter.Balance);
        }
예제 #11
0
        public async Task CashSwap()
        {
            AccountEntity testAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount1);
            BalanceDTO accountBalance1Asset1 = testAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance1Asset1);
            BalanceDTO accountBalance1Asset2 = testAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.NotNull(accountBalance1Asset2);

            AccountEntity testAccount2 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            Assert.NotNull(testAccount2);
            BalanceDTO accountBalance2Asset1 = testAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance2Asset1);
            BalanceDTO accountBalance2Asset2 = testAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.NotNull(accountBalance2Asset2);


            //Attempt invalid swap
            double badSwapAmount1 = accountBalance1Asset1.Balance + 0.7;
            double badSwapAmount2 = accountBalance2Asset2.Balance - 0.2; // this one isn't bad, but the transaction should still fail
            string badSwapId      = Guid.NewGuid().ToString();

            MeResponseModel badSwapResponse = await this.Consumer.Client.SwapAsync(badSwapId,
                                                                                   testAccount1.Id, this.TestAsset1, badSwapAmount1,
                                                                                   testAccount2.Id, this.TestAsset2, badSwapAmount2);

            Assert.True(badSwapResponse.Status == MeStatusCodes.LowBalance);


            //Attempt a valid swap
            double swapAmount1 = Math.Round(accountBalance1Asset1.Balance / 10, this.AssetPrecission);
            double swapAmount2 = Math.Round(accountBalance2Asset2.Balance / 10, this.AssetPrecission);
            string swapId      = Guid.NewGuid().ToString();

            MeResponseModel swapReseponse = await this.Consumer.Client.SwapAsync(swapId,
                                                                                 testAccount1.Id, this.TestAsset1, swapAmount1,
                                                                                 testAccount2.Id, this.TestAsset2, swapAmount2);

            Assert.True(swapReseponse.Status == MeStatusCodes.Ok);

            CashSwapOperation message = (CashSwapOperation)await this.WaitForRabbitMQ <CashSwapOperation>(o => o.id == swapId);

            Assert.True(message.asset1 == this.TestAsset1);
            Assert.True(message.asset2 == this.TestAsset2);
            Assert.True(message.clientId1 == testAccount1.Id);
            Assert.True(message.clientId2 == testAccount2.Id);
            if (Double.TryParse(message.volume1, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedVolume))
            {
                Assert.True(parsedVolume == swapAmount1);
            }
            if (Double.TryParse(message.volume2, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedVolume))
            {
                Assert.True(parsedVolume == swapAmount2);
            }

            CashSwapEntity checkCashSwapOperation = (CashSwapEntity)await this.CashSwapRepository.TryGetAsync(c => c.ExternalId == swapId);

            Assert.True(checkCashSwapOperation.AssetId1 == this.TestAsset1);
            Assert.True(checkCashSwapOperation.AssetId2 == this.TestAsset2);
            Assert.True(checkCashSwapOperation.ClientId1 == testAccount1.Id);
            Assert.True(checkCashSwapOperation.ClientId2 == testAccount2.Id);
            Assert.True(checkCashSwapOperation.Amount1 == swapAmount1);
            Assert.True(checkCashSwapOperation.Amount2 == swapAmount2);

            AccountEntity checkTestAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO checkAccountBalance1Asset1 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            BalanceDTO checkAccountBalance1Asset2 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            AccountEntity checkTestAccount2 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            BalanceDTO checkAccountBalance2Asset1 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            BalanceDTO checkAccountBalance2Asset2 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance1Asset1.Balance, this.AssetPrecission) == Math.Round(accountBalance1Asset1.Balance - swapAmount1, this.AssetPrecission));
            Assert.True(Math.Round(checkAccountBalance2Asset1.Balance, this.AssetPrecission) == Math.Round(accountBalance2Asset1.Balance + swapAmount1, this.AssetPrecission));
            Assert.True(Math.Round(checkAccountBalance1Asset2.Balance, this.AssetPrecission) == Math.Round(accountBalance1Asset2.Balance + swapAmount2, this.AssetPrecission));
            Assert.True(Math.Round(checkAccountBalance2Asset2.Balance, this.AssetPrecission) == Math.Round(accountBalance2Asset2.Balance - swapAmount2, this.AssetPrecission));



            // Attempt swap back
            string swapBackId = Guid.NewGuid().ToString();

            MeResponseModel swapBackReseponse = await this.Consumer.Client.SwapAsync(swapBackId,
                                                                                     testAccount2.Id, this.TestAsset1, swapAmount1,
                                                                                     testAccount1.Id, this.TestAsset2, swapAmount2);

            Assert.True(swapBackReseponse.Status == MeStatusCodes.Ok);

            message = (CashSwapOperation)await this.WaitForRabbitMQ <CashSwapOperation>(o => o.id == swapBackId);

            Assert.True(message.asset1 == this.TestAsset1);
            Assert.True(message.asset2 == this.TestAsset2);
            Assert.True(message.clientId1 == testAccount2.Id);
            Assert.True(message.clientId2 == testAccount1.Id);
            if (Double.TryParse(message.volume1, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedVolume))
            {
                Assert.True(parsedVolume == swapAmount1);
            }
            if (Double.TryParse(message.volume2, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedVolume))
            {
                Assert.True(parsedVolume == swapAmount2);
            }

            checkCashSwapOperation = (CashSwapEntity)await this.CashSwapRepository.TryGetAsync(c => c.ExternalId == swapBackId);

            Assert.True(checkCashSwapOperation.AssetId1 == this.TestAsset1);
            Assert.True(checkCashSwapOperation.AssetId2 == this.TestAsset2);
            Assert.True(checkCashSwapOperation.ClientId1 == testAccount2.Id);
            Assert.True(checkCashSwapOperation.ClientId2 == testAccount1.Id);
            Assert.True(checkCashSwapOperation.Amount1 == swapAmount1);
            Assert.True(checkCashSwapOperation.Amount2 == swapAmount2);

            checkTestAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance1Asset1 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            checkAccountBalance1Asset2 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            checkTestAccount2 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            checkAccountBalance2Asset1 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            checkAccountBalance2Asset2 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset2).FirstOrDefault();

            // balances should be back to their initial state
            Assert.True(accountBalance1Asset1.Balance == checkAccountBalance1Asset1.Balance);
            Assert.True(accountBalance1Asset2.Balance == checkAccountBalance1Asset2.Balance);
            Assert.True(accountBalance2Asset1.Balance == checkAccountBalance2Asset1.Balance);
            Assert.True(accountBalance2Asset2.Balance == checkAccountBalance2Asset2.Balance);
        }
예제 #12
0
        public async Task CashTransfer()
        {
            AccountEntity testAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            Assert.NotNull(testAccount1);
            BalanceDTO accountBalance1 = testAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance1);

            AccountEntity testAccount2 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            Assert.NotNull(testAccount2);
            BalanceDTO accountBalance2 = testAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.NotNull(accountBalance2);

            //Attempt invalid transfer
            double          badTransferAmount   = accountBalance1.Balance + 0.7;
            string          badTransferId       = Guid.NewGuid().ToString();
            MeResponseModel badTransferResponse = await this.Consumer.Client.TransferAsync(badTransferId, testAccount1.Id, testAccount2.Id, this.TestAsset1, badTransferAmount);

            Assert.NotNull(badTransferResponse);
            Assert.True(badTransferResponse.Status == MeStatusCodes.LowBalance);



            //Transfer from Test acc 1 to Test acc 2
            double          transferAmount   = Math.Round(accountBalance1.Balance / 10, this.AssetPrecission);
            string          transferId       = Guid.NewGuid().ToString();
            MeResponseModel transferResponse = await this.Consumer.Client.TransferAsync(transferId, testAccount1.Id, testAccount2.Id, this.TestAsset1, transferAmount);

            Assert.NotNull(transferResponse);
            Assert.True(transferResponse.Status == MeStatusCodes.Ok);

            CashTransferOperation message = (CashTransferOperation)await this.WaitForRabbitMQ <CashTransferOperation>(o => o.id == transferId);

            Assert.NotNull(message);
            Assert.True(message.asset == this.TestAsset1);
            Assert.True(message.fromClientId == testAccount1.Id);
            Assert.True(message.toClientId == testAccount2.Id);
            if (Double.TryParse(message.volume, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedMsgAmount))
            {
                Assert.True(parsedMsgAmount == transferAmount);
            }

            CashSwapEntity checkCashSwapOperation = (CashSwapEntity)await this.CashSwapRepository.TryGetAsync(c => c.ExternalId == transferId);

            Assert.True(checkCashSwapOperation.Amount == transferAmount);
            Assert.True(checkCashSwapOperation.AssetId == this.TestAsset1);
            Assert.True(checkCashSwapOperation.FromClientId == testAccount1.Id);
            Assert.True(checkCashSwapOperation.ToClientId == testAccount2.Id);

            AccountEntity checkTestAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            BalanceDTO    checkAccountBalance1 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            AccountEntity checkTestAccount2    = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            BalanceDTO checkAccountBalance2 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            Assert.True(Math.Round(checkAccountBalance1.Balance, this.AssetPrecission) == Math.Round(accountBalance1.Balance - transferAmount, this.AssetPrecission)); // TODO get asset accuracy
            Assert.True(Math.Round(checkAccountBalance2.Balance, this.AssetPrecission) == Math.Round(accountBalance2.Balance + transferAmount, this.AssetPrecission)); // TODO get asset accuracy



            //Transfer same amount from Test acc 2 to Test acc 1
            string          transferBackId       = Guid.NewGuid().ToString();
            MeResponseModel transferBackResponse = await this.Consumer.Client.TransferAsync(transferBackId, testAccount2.Id, testAccount1.Id, this.TestAsset1, transferAmount);

            Assert.NotNull(transferBackResponse);
            Assert.True(transferBackResponse.Status == MeStatusCodes.Ok);

            message = (CashTransferOperation)await this.WaitForRabbitMQ <CashTransferOperation>(o => o.id == transferBackId);

            Assert.NotNull(message);
            Assert.True(message.asset == this.TestAsset1);
            Assert.True(message.fromClientId == testAccount2.Id);
            Assert.True(message.toClientId == testAccount1.Id);
            if (Double.TryParse(message.volume, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedMsgAmount))
            {
                Assert.True(parsedMsgAmount == transferAmount);
            }

            CashSwapEntity checkCashSwapBackOperation = (CashSwapEntity)await this.CashSwapRepository.TryGetAsync(c => c.ExternalId == transferBackId);

            Assert.True(checkCashSwapBackOperation.Amount == transferAmount);
            Assert.True(checkCashSwapBackOperation.AssetId == this.TestAsset1);
            Assert.True(checkCashSwapBackOperation.FromClientId == testAccount2.Id);
            Assert.True(checkCashSwapBackOperation.ToClientId == testAccount1.Id);

            checkTestAccount1 = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId1);

            checkAccountBalance1 = checkTestAccount1.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();
            checkTestAccount2    = (AccountEntity)await this.AccountRepository.TryGetAsync(this.TestAccountId2);

            checkAccountBalance2 = checkTestAccount2.BalancesParsed.Where(b => b.Asset == this.TestAsset1).FirstOrDefault();

            //balances should be back to their initial state after 2 transfers back and forward
            Assert.True(accountBalance1.Balance == checkAccountBalance1.Balance);
            Assert.True(accountBalance2.Balance == checkAccountBalance2.Balance);
        }
 private static void ValidateResponse(MeResponseModel response, MeStatusCodes expected)
 {
     Assert.NotNull(response);
     Assert.Equal(response.Status, expected);
 }
예제 #14
0
        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
                }
            });
        }
예제 #15
0
        public override async Task <CancelOrderResponse> CancelAllOrders(CancelOrdersRequest request, ServerCallContext context)
        {
            var result = await _validationService.ValidateAssetPairAsync(request.AssetPairId);

            if (result != null)
            {
                return(new CancelOrderResponse
                {
                    Error = new Error
                    {
                        Code = (int)result.Code,
                        Message = result.Message
                    }
                });
            }

            bool?isBuy;

            switch (request.Side)
            {
            case Side.Buy:
                isBuy = true;
                break;

            case Side.Sell:
                isBuy = false;
                break;

            default:
                isBuy = null;
                break;
            }

            var model = new LimitOrderMassCancelModel
            {
                Id          = Guid.NewGuid().ToString(),
                AssetPairId = request.AssetPairId,
                ClientId    = context.GetHttpContext().User.GetWalletId(),
                IsBuy       = isBuy
            };

            MeResponseModel response = await _matchingEngineClient.MassCancelLimitOrdersAsync(model);

            if (response == null)
            {
                return(new CancelOrderResponse
                {
                    Error = new Error
                    {
                        Code = (int)HftApiErrorCode.MeRuntime,
                        Message = "ME not available"
                    }
                });
            }

            (HftApiErrorCode code, string message) = response.Status.ToHftApiError();

            if (code == HftApiErrorCode.Success)
            {
                return new CancelOrderResponse
                       {
                           Payload = true
                       }
            }
            ;

            return(new CancelOrderResponse
            {
                Error = new Error
                {
                    Code = (int)code,
                    Message = message
                }
            });
        }
예제 #16
0
        public override async Task <CancelOrderResponse> CancelAllOrders(CancelOrdersRequest request, ServerCallContext context)
        {
            MeResponseModel response;

            if (!string.IsNullOrEmpty(request.AssetPairId))
            {
                var result = await _validationService.ValidateAssetPairAsync(request.AssetPairId);

                if (result != null)
                {
                    var res = new CancelOrderResponse
                    {
                        Error = new ErrorResponseBody {
                            Code = ErrorCode.InvalidField, Message = result.Message
                        }
                    };

                    res.Error.Fields.Add(result.FieldName, result.Message);
                }

                bool?isBuy;

                if (request.OptionalSideCase == CancelOrdersRequest.OptionalSideOneofCase.None)
                {
                    isBuy = null;
                }
                else
                {
                    switch (request.Side)
                    {
                    case Side.Buy:
                        isBuy = true;
                        break;

                    case Side.Sell:
                        isBuy = false;
                        break;

                    default:
                        isBuy = null;
                        break;
                    }
                }

                var model = new LimitOrderMassCancelModel
                {
                    Id          = Guid.NewGuid().ToString(),
                    AssetPairId = request.AssetPairId,
                    ClientId    = context.GetClientId(),
                    IsBuy       = isBuy
                };

                response = await _matchingEngineClient.MassCancelLimitOrdersAsync(model);
            }
            else
            {
                var orders = await GetOrders(new LimitOrdersRequest(), context);

                if (orders.Body?.Orders.Any() ?? false)
                {
                    var orderIds = orders.Body.Orders.Select(x => x.Id).ToList();
                    response = await _matchingEngineClient.CancelLimitOrdersAsync(orderIds);
                }
                else
                {
                    response = new MeResponseModel {
                        Status = MeStatusCodes.Ok
                    };
                }
            }

            if (response == null)
            {
                return(new CancelOrderResponse
                {
                    Error = new ErrorResponseBody {
                        Code = ErrorCode.Runtime, Message = ErrorMessages.MeNotAvailable
                    }
                });
            }

            if (response.Status == MeStatusCodes.Ok)
            {
                return new CancelOrderResponse
                       {
                           Body = new CancelOrderResponse.Types.Body
                           {
                               Payload = true
                           }
                       }
            }
            ;

            return(new CancelOrderResponse
            {
                Error = new ErrorResponseBody {
                    Code = ErrorCode.Runtime, Message = response.Message ?? response.Status.ToString()
                }
            });
        }