private async Task CreateEvent(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades, OrderStatus status) { var order = limitOrderWithTrades.Order; var type = order.Volume > 0 ? OrderType.Buy : OrderType.Sell; var assetPair = await _assetsServiceWithCache.TryGetAssetPairAsync(order.AssetPairId); var date = status == OrderStatus.InOrderBook ? limitOrderWithTrades.Order.CreatedAt : DateTime.UtcNow; var insertRequest = new LimitTradeEventInsertRequest { Volume = order.Volume, Type = type, OrderId = order.Id, Status = status, AssetId = assetPair?.BaseAssetId, ClientId = order.ClientId, Price = order.Price, AssetPair = order.AssetPairId, DateTime = date }; await _limitTradeEventsRepositoryClient.CreateAsync(insertRequest); _log.Info(nameof(OperationHistoryProjection), $"Client {order.ClientId}. Limit trade {order.Id}. State has changed -> {status}", JsonConvert.SerializeObject(insertRequest, Formatting.Indented)); }
private async Task CreateEvent(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades, OrderStatus status) { var order = limitOrderWithTrades.Order; var type = order.Volume > 0 ? OrderType.Buy : OrderType.Sell; var assetPair = await _assetsService.TryGetAssetPairAsync(order.AssetPairId); var date = status == OrderStatus.InOrderBook ? limitOrderWithTrades.Order.CreatedAt : DateTime.UtcNow; await _limitTradeEventsRepository.CreateEvent(order.Id, order.ClientId, type, order.Volume, assetPair?.BaseAssetId, order.AssetPairId, order.Price, status, date); }
private async Task <ClientTrade[]> CreateTrades(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades) { if (limitOrderWithTrades.Trades == null || limitOrderWithTrades.Trades.Count == 0) { return(new ClientTrade[0]); } var assetPair = await _assetsServiceWithCache.TryGetAssetPairAsync(limitOrderWithTrades.Order.AssetPairId); var trades = limitOrderWithTrades.ToDomain(assetPair); return(trades.ToArray()); }
public static IReadOnlyList <ClientTrade> ToDomain(this LimitQueueItem.LimitOrderWithTrades item, AssetPair assetPair) { var trade = item.Trades[0]; var limitVolume = item.Trades.Sum(x => x.Volume); var oppositeLimitVolume = item.Trades.Sum(x => x.OppositeVolume); var price = CalcEffectivePrice(item.Trades, assetPair, item.Order.Volume > 0); var clientId = trade.ClientId ?? item.Order.ClientId; var depositAssetRecord = CreateCommonPartForTradeRecord(trade, item.Order, item.Order.Id, price); var withdrawAssetRecord = CreateCommonPartForTradeRecord(trade, item.Order, item.Order.Id, price); depositAssetRecord.ClientId = withdrawAssetRecord.ClientId = clientId; depositAssetRecord.Amount = oppositeLimitVolume; depositAssetRecord.AssetId = trade.OppositeAsset; withdrawAssetRecord.Amount = limitVolume; if (Math.Sign(limitVolume) == Math.Sign(oppositeLimitVolume)) { withdrawAssetRecord.Amount *= -1; } withdrawAssetRecord.AssetId = trade.Asset; foreach (var t in item.Trades) { var transfer = t.Fees?.FirstOrDefault()?.Transfer; if (transfer != null) { if (depositAssetRecord.AssetId == transfer.Asset) { depositAssetRecord.FeeSize += (double)transfer.Volume; depositAssetRecord.FeeType = Service.OperationsRepository.AutorestClient.Models.FeeType.Absolute; } else { withdrawAssetRecord.FeeSize += (double)transfer.Volume; withdrawAssetRecord.FeeType = Service.OperationsRepository.AutorestClient.Models.FeeType.Absolute; } } } depositAssetRecord.Id = Core.Domain.CashOperations.Utils.GenerateRecordId(depositAssetRecord.DateTime); withdrawAssetRecord.Id = Core.Domain.CashOperations.Utils.GenerateRecordId(withdrawAssetRecord.DateTime); return(new[] { depositAssetRecord, withdrawAssetRecord }); }
private async Task <IClientTrade[]> SaveTrades(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades) { if (limitOrderWithTrades.Trades.Count == 0) { return(new IClientTrade[0]); } var walletCredsClientA = await _walletCredentialsRepository.GetAsync(limitOrderWithTrades.Trades[0].ClientId); var walletCredsClientB = await _walletCredentialsRepository.GetAsync(limitOrderWithTrades.Trades[0].OppositeClientId); var trades = limitOrderWithTrades.ToDomainOffchain(limitOrderWithTrades.Order.Id, walletCredsClientA, walletCredsClientB); await _clientTradesRepository.SaveAsync(trades); return(trades); }
private async Task ReturnRemainingVolume(LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades) { var order = limitOrderWithTrades.Order; var offchainOrder = await _offchainOrdersRepository.GetOrder(order.Id); var type = order.Volume > 0 ? OrderType.Buy : OrderType.Sell; var assetPair = await _assetsService.TryGetAssetPairAsync(order.AssetPairId); var neededAsset = type == OrderType.Buy ? assetPair.QuotingAssetId : assetPair.BaseAssetId; var asset = await _assetsService.TryGetAssetAsync(neededAsset); if (type == OrderType.Buy) { var initial = offchainOrder.ReservedVolume; var trades = await _clientTradesRepository.GetByOrderAsync(order.Id); var executed = trades.Where(x => x.AssetId == neededAsset && x.ClientId == order.ClientId) .Select(x => x.Amount).DefaultIfEmpty(0).Sum(); var returnAmount = Math.Max(0, initial - Math.Abs((decimal)executed)); if (asset.Blockchain == Blockchain.Ethereum) { // if order partially or fully executed then broadcast guarantee transfer if (offchainOrder.Volume > returnAmount) { await ProcessEthGuaranteeTransfer(order.Id, returnAmount); } return; } if (returnAmount > 0) { await _offchainRequestService.CreateOffchainRequestAndUnlock(Guid.NewGuid().ToString(), order.ClientId, neededAsset, returnAmount, order.Id, OffchainTransferType.FromHub); } } else { var remainigVolume = Math.Abs((decimal)order.RemainingVolume); if (asset.Blockchain == Blockchain.Ethereum) { var initialVolume = Math.Abs(offchainOrder.Volume); // if order partially or fully executed then broadcast guarantee transfer // if initialVolume == remainigVolume then user cancelled limit order without partial executing if (initialVolume > remainigVolume) { await ProcessEthGuaranteeTransfer(order.Id, remainigVolume); } return; } if (remainigVolume > 0) { await _offchainRequestService.CreateOffchainRequestAndUnlock(Guid.NewGuid().ToString(), order.ClientId, neededAsset, remainigVolume, order.Id, OffchainTransferType.FromHub); } } }
private async Task <IClientTrade[]> SaveTransactionAndContext(IClientTrade[] trades, List <AggregatedTransfer> operations, LimitQueueItem.LimitOrderWithTrades limitOrderWithTrades) { var contextData = await _bitcoinTransactionService.GetTransactionContext <SwapOffchainContextData>(limitOrderWithTrades.Order.Id) ?? new SwapOffchainContextData(); foreach (var operation in operations.Where(x => x.ClientId == limitOrderWithTrades.Order.ClientId)) { var trade = trades.FirstOrDefault(x => x.ClientId == operation.ClientId && x.AssetId == operation.AssetId && Math.Abs(x.Amount - (double)operation.Amount) < 0.00000001); contextData.Operations.Add(new SwapOffchainContextData.Operation() { TransactionId = operation.TransferId, Amount = operation.Amount, ClientId = operation.ClientId, AssetId = operation.AssetId, ClientTradeId = trade?.Id }); } await _bitcoinTransactionService.CreateOrUpdateAsync(limitOrderWithTrades.Order.Id); await _bitcoinTransactionService.SetTransactionContext(limitOrderWithTrades.Order.Id, contextData); return(trades); }