Example #1
0
        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);
        }
Example #3
0
        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);
        }