public void ExecuteQuoteSuccessTest() { var getQuoteRequest = new GetQuoteRequest() { FromAsset = "BTC", ToAsset = "USD", FromAssetVolume = 0.1, ToAssetVolume = 0, IsFromFixed = true, BrokerId = "broker", AccountId = "Acc", WalletId = "wallet" }; var response = Service.GetQuoteAsync(getQuoteRequest).Result; Assert.IsTrue(response.IsSuccess, "Unable to calculate quote"); var quote = response.Data; var executeQuoteRequest = new ExecuteQuoteRequest() { FromAsset = quote.FromAsset, ToAsset = quote.ToAsset, FromAssetVolume = quote.FromAssetVolume, ToAssetVolume = quote.ToAssetVolume, IsFromFixed = quote.IsFromFixed, BrokerId = quote.BrokerId, AccountId = quote.AccountId, WalletId = quote.WalletId, OperationId = quote.OperationId, Price = quote.Price }; var executeQuoteResponse = Service.ExecuteQuoteAsync(executeQuoteRequest); Assert.IsTrue(executeQuoteResponse.Result.QuoteExecutionResult == QuoteExecutionResult.Success); }
public static bool IsQuoteEquals(ConvertQuote entity, ExecuteQuoteRequest quote) { return(entity.FromAsset.Equals(quote.FromAsset) && entity.ToAsset.Equals(quote.ToAsset) && entity.FromAssetVolume.Equals(quote.FromAssetVolume) && entity.ToAssetVolume.Equals(quote.ToAssetVolume) && entity.IsFromFixed.Equals(quote.IsFromFixed) && entity.BrokerId.Equals(quote.BrokerId) && entity.AccountId.Equals(quote.AccountId) && entity.WalletId.Equals(quote.WalletId) && entity.OperationId.Equals(quote.OperationId) && entity.Price.Equals(quote.Price)); }
public void ExecuteQuoteReQuoteTest() { this._liquidityConverterSettingsAccessor.Data["broker"].ClientExpirationInSeconds = 0; var getQuoteRequest = new GetQuoteRequest() { FromAsset = "BTC", ToAsset = "USD", FromAssetVolume = 0.1, ToAssetVolume = 0, IsFromFixed = true, BrokerId = "broker", AccountId = "Acc", WalletId = "wallet" }; var response = Service.GetQuoteAsync(getQuoteRequest).Result; Assert.IsTrue(response.IsSuccess, "Unable to calculate quote"); var quote = response.Data; var executeQuoteRequest = new ExecuteQuoteRequest() { FromAsset = quote.FromAsset, ToAsset = quote.ToAsset, FromAssetVolume = quote.FromAssetVolume, ToAssetVolume = quote.ToAssetVolume, IsFromFixed = quote.IsFromFixed, BrokerId = quote.BrokerId, AccountId = quote.AccountId, WalletId = quote.WalletId, OperationId = quote.OperationId, Price = quote.Price }; var executeQuoteResponseResult = Service.ExecuteQuoteAsync(executeQuoteRequest).Result; Assert.IsTrue(executeQuoteResponseResult.QuoteExecutionResult == QuoteExecutionResult.ReQuote); this._liquidityConverterSettingsAccessor.Data["broker"].ClientExpirationInSeconds = 8; }
public void ExecuteQuoteValidationTest() { var storageQuote = new ConvertQuote() { FromAsset = "BTC", ToAsset = "USD", FromAssetVolume = 0.1, ToAssetVolume = 150, IsFromFixed = true, BrokerId = "broker", AccountId = "Acc", WalletId = "wallet", Price = 323, ExpireDate = DateTime.MaxValue, OperationId = "someId", OpenDate = DateTime.UtcNow, ClosedDate = DateTime.MinValue, State = QuoteState.Active }; ConvertQuoteStorageMock.SaveAsync(storageQuote); var executeQuoteRequestCase1 = new ExecuteQuoteRequest() { FromAsset = storageQuote.FromAsset, ToAsset = storageQuote.ToAsset, FromAssetVolume = storageQuote.FromAssetVolume, ToAssetVolume = storageQuote.ToAssetVolume, IsFromFixed = storageQuote.IsFromFixed, BrokerId = storageQuote.BrokerId, AccountId = storageQuote.AccountId, WalletId = "something else", OperationId = storageQuote.OperationId, Price = storageQuote.Price }; var response = Service.ExecuteQuoteAsync(executeQuoteRequestCase1); Assert.IsTrue(response.Result.QuoteExecutionResult == QuoteExecutionResult.Error); var executeQuoteRequestCase2 = new ExecuteQuoteRequest() { FromAsset = storageQuote.FromAsset, ToAsset = storageQuote.ToAsset, FromAssetVolume = storageQuote.FromAssetVolume, ToAssetVolume = 11, IsFromFixed = storageQuote.IsFromFixed, BrokerId = storageQuote.BrokerId, AccountId = storageQuote.AccountId, WalletId = storageQuote.WalletId, OperationId = storageQuote.OperationId, Price = storageQuote.Price }; var response2 = Service.ExecuteQuoteAsync(executeQuoteRequestCase2); Assert.IsTrue(response2.Result.QuoteExecutionResult == QuoteExecutionResult.Error); var executeQuoteRequestCase3 = new ExecuteQuoteRequest() { FromAsset = storageQuote.FromAsset, ToAsset = "new asset", FromAssetVolume = storageQuote.FromAssetVolume, ToAssetVolume = storageQuote.ToAssetVolume, IsFromFixed = storageQuote.IsFromFixed, BrokerId = storageQuote.BrokerId, AccountId = storageQuote.AccountId, WalletId = storageQuote.WalletId, OperationId = storageQuote.OperationId, Price = storageQuote.Price }; var response3 = Service.ExecuteQuoteAsync(executeQuoteRequestCase3); Assert.IsTrue(response3.Result.QuoteExecutionResult == QuoteExecutionResult.Error); }
public async Task <QuoteExecutionResponse> ExecuteQuoteAsync(ExecuteQuoteRequest request) { _logger.LogInformation("Receive ExecuteQuote request: {JsonText}", JsonConvert.SerializeObject(request)); var quote = await _convertQuoteStorage.GetQuoteAsync(request.OperationId); if (quote == null) { return(ErrorQuoteExecutionReport("Quote not found")); } if (quote.State == QuoteState.Executed) { _logger.LogInformation("Quote is Executed. Quote: {JsonOperationId}", JsonConvert.SerializeObject(request)); return(QuoteExecutionResponse.Success(quote)); } if (quote.ExpireDate < DateTime.UtcNow) { _logger.LogInformation("Quote expired and ReQuote will be started. Quote {JsonOperationId}", JsonConvert.SerializeObject(request)); quote.State = QuoteState.Expired; await _convertQuoteStorage.SaveAsync(quote); return(await GenerateReQuote(quote)); } var settings = _liquidityConverterSettingsAccessor.GetLiquidityConverterSettings(request.BrokerId); if (settings == null) { return(ErrorQuoteExecutionReport("Liquidity Converter is not configured for broker")); } if (!QuoteValidator.IsQuoteEquals(quote, request)) { _logger.LogWarning("Request quote not equals to execute quote. Request quote: {RequestQuoteJson}. Execute quote {ExecuteQuoteJson}", JsonConvert.SerializeObject(quote), JsonConvert.SerializeObject(request)); return(ErrorQuoteExecutionReport("Request quote not equals to execute quote")); } quote.State = QuoteState.Executed; await _convertQuoteStorage.SaveAsync(quote); return(QuoteExecutionResponse.Success(quote)); // var instrument = _spotInstrumentDictionaryClient.GetSpotInstrumentById(new SpotInstrumentIdentity() // {BrokerId = quote.BrokerId, Symbol = quote.InstrumentSymbol}); // if (instrument == null) // return ErrorQuoteExecutionReport("Unknown instrument"); // // quote.ClientReserveOperationId = Guid.NewGuid().ToString("N"); // if (!await ctx.UpdateQuoteStatusAndClientReserveId(quote.QuoteEntityId, QuoteStatus.Processing, // QuoteStatus.Created, quote.ClientReserveOperationId)) // return ErrorQuoteExecutionReport("Invalid quote status"); // // //reserve client's funds in ME // var clientFundsReserveResponse = await _cashServiceClient.ReservedCashInOutAsync( // new ReservedCashInOutOperation() // { // BrokerId = quote.BrokerId, // AccountId = quote.AccountId, // WalletId = quote.WalletId, // Id = quote.ClientReserveOperationId, // MessageId = quote.ClientReserveOperationId, // AssetId = (quote.OrderSide == OrderSide.Buy && quote.AssetSymbol == instrument.QuoteAsset) || // (quote.OrderSide == OrderSide.Sell && quote.AssetSymbol == instrument.BaseAsset) // ? instrument.BaseAsset // : instrument.QuoteAsset, // Description = "Reserve funds for swap", // Timestamp = Timestamp.FromDateTime(now), // ReservedForSwapVolume = // quote.OrderSide == OrderSide.Sell // ? quote.Volume.ToString("N") // : quote.OppositeVolume.ToString("N") // }); // if (clientFundsReserveResponse.Status == Status.Duplicate) // { // //stop processing as quote is being processing by another instance // return QuoteExecutionResponse<Quote>.Error("Processing by another instance"); // } // // if (clientFundsReserveResponse.Status != Status.Ok) // { // await ctx.UpdateQuoteStatusAndReason(quote.QuoteEntityId, QuoteStatus.Error, QuoteStatus.Processing, // "Unable to reserve client's funds"); // } // // quote.MarketOrderId = Guid.NewGuid().ToString("N"); // if (!await ctx.UpdateQuoteStatusAndMarketOrderId(quote.QuoteEntityId, QuoteStatus.ClientFundsReserved, // QuoteStatus.Processing, quote.MarketOrderId)) // return ErrorQuoteExecutionReport("Invalid quote status"); // // //execute market order on behalf of broker // var marketOrderResponse = await _tradingServiceClient.MarketOrderAsync(new MarketOrder() // { // Id = quote.MarketOrderId, // MessageId = quote.MarketOrderId, // BrokerId = settings.BrokerId, // AccountId = settings.BrokerAccountId, // WalletId = settings.BrokerWalletId, // Timestamp = Timestamp.FromDateTime(now), // AssetPairId = quote.InstrumentSymbol, // Volume = quote.OrderSide == OrderSide.Buy // ? quote.Volume.ToString("N") // : quote.OppositeVolume.ToString("N"), // Straight = (quote.OrderSide == OrderSide.Buy && quote.AssetSymbol == instrument.BaseAsset) || // (quote.OrderSide == OrderSide.Sell && quote.AssetSymbol == instrument.QuoteAsset), // ReservedLimitVolume = quote.OrderSide == OrderSide.Buy // ? quote.OppositeVolume.ToString("N") // : quote.Volume.ToString("N") // }); // // if (marketOrderResponse.Status == Status.Duplicate) // { // //stop processing as quote is being processing by another instance // return QuoteExecutionResponse<Quote>.Error("Processing by another instance"); // } // // if (marketOrderResponse.Status != Status.Ok) // { // await ctx.UpdateQuoteStatusAndReason(quote.QuoteEntityId, QuoteStatus.Error, // QuoteStatus.ClientFundsReserved, "Unable to execute market order"); // return await GenerateReQuote(ctx, quote); // } // // quote.BrokerReserveOperationId = Guid.NewGuid().ToString("N"); // if (!await ctx.UpdateQuoteStatusAndBrokerReserveId(quote.QuoteEntityId, QuoteStatus.MarketOrderExecuted, // QuoteStatus.ClientFundsReserved, quote.BrokerReserveOperationId)) // return ErrorQuoteExecutionReport("Invalid quote status"); // // //reserve broker's funds in ME // var brokerFundsReserveResponse = await _cashServiceClient.ReservedCashInOutAsync( // new ReservedCashInOutOperation() // { // BrokerId = settings.BrokerId, // AccountId = settings.BrokerAccountId, // WalletId = settings.BrokerWalletId, // Id = quote.BrokerReserveOperationId, // MessageId = quote.BrokerReserveOperationId, // AssetId = (quote.OrderSide == OrderSide.Buy && quote.AssetSymbol == instrument.QuoteAsset) || // (quote.OrderSide == OrderSide.Sell && quote.AssetSymbol == instrument.BaseAsset) // ? instrument.QuoteAsset // : instrument.BaseAsset, // Description = "Reserve funds for swap", // Timestamp = Timestamp.FromDateTime(now), // ReservedForSwapVolume = quote.OrderSide == OrderSide.Sell // ? quote.OppositeVolume.ToString("N") // : quote.Volume.ToString("N") // }); // // if (brokerFundsReserveResponse.Status == Status.Duplicate) // { // //stop processing as quote is being processing by another instance // return QuoteExecutionResponse<Quote>.Error("Processing by another instance"); // } // // if (brokerFundsReserveResponse.Status != Status.Ok) // { // await ctx.UpdateQuoteStatusAndReason(quote.QuoteEntityId, QuoteStatus.Error, // QuoteStatus.MarketOrderExecuted, // "Unable to execute market order"); // } // // quote.SwapOperationId = Guid.NewGuid().ToString("N"); // if (!await ctx.UpdateQuoteStatusAndClientReserveId(quote.QuoteEntityId, QuoteStatus.BrokerFundsReserved, // QuoteStatus.MarketOrderExecuted, quote.SwapOperationId)) // return ErrorQuoteExecutionReport("Invalid quote status"); // // //execute swap in ME // var swapResponse = await _cashServiceClient.CashSwapAsync( // new CashSwapOperation() // { // BrokerId = settings.BrokerId, // Id = quote.SwapOperationId, // MessageId = quote.SwapOperationId, // AccountId1 = quote.AccountId, // WalletId1 = quote.WalletId, // AssetId1 = (quote.OrderSide == OrderSide.Buy && quote.AssetSymbol == instrument.QuoteAsset) || // (quote.OrderSide == OrderSide.Sell && quote.AssetSymbol == instrument.BaseAsset) // ? instrument.BaseAsset // : instrument.QuoteAsset, // Volume1 = quote.OrderSide == OrderSide.Sell // ? quote.Volume.ToString("N") // : quote.OppositeVolume.ToString("N"), // AccountId2 = settings.BrokerAccountId, // WalletId2 = settings.BrokerWalletId, // AssetId2 = (quote.OrderSide == OrderSide.Buy && quote.AssetSymbol == instrument.QuoteAsset) || // (quote.OrderSide == OrderSide.Sell && quote.AssetSymbol == instrument.BaseAsset) // ? instrument.QuoteAsset // : instrument.BaseAsset, // Volume2 = quote.OrderSide == OrderSide.Sell // ? quote.OppositeVolume.ToString("N") // : quote.Volume.ToString("N"), // Timestamp = Timestamp.FromDateTime(now), // }); // // if (swapResponse.Status == Status.Duplicate) // { // //stop processing as quote is being processing by another instance // return QuoteExecutionResponse<Quote>.Error("Processing by another instance"); // } // // if (swapResponse.Status != Status.Ok) // { // await ctx.UpdateQuoteStatusAndReason(quote.QuoteEntityId, QuoteStatus.Error, // QuoteStatus.BrokerFundsReserved, // "Unable to execute market order"); // } // // if (!await ctx.UpdateQuoteStatus(quote.QuoteEntityId, QuoteStatus.Executed, // QuoteStatus.BrokerFundsReserved)) // return ErrorQuoteExecutionReport("Invalid quote status"); // // return QuoteExecutionResponse<Quote>.Success(new Quote() // { // BrokerId = quote.BrokerId, // AccountId = quote.AccountId, // WalletId = quote.WalletId, // InstrumentSymbol = quote.InstrumentSymbol, // AssetSymbol = quote.AssetSymbol, // OrderSide = quote.OrderSide, // Volume = quote.Volume, // OperationId = quote.OperationId, // Price = quote.FinalPrice, // ExpireTime = quote.ClientExpireTime // }); }