Example #1
0
        public IReadOnlyList <CapitalGain> CalculateCapialGains(IReadOnlyList <Transaction> transactions, AccountingMethodType accountingMethod, Crypto.CryptoType crypto)
        {
            var capitalGains       = new List <CapitalGain>();
            var sortedTransactions = transactions
                                     .Where(x => x.Crypto == crypto)
                                     .OrderBy(x => x.TransactionDate);
            var assetCollection = new AssetCollection(accountingMethod);

            foreach (var transaction in sortedTransactions)
            {
                switch (transaction.TransactionType)
                {
                case TransactionType.Buy:
                    assetCollection.Add(new Asset
                    {
                        TransactionDate = transaction.TransactionDate,
                        Amount          = transaction.Quantity,
                        ExchangeRate    = transaction.PriceInUsd
                    });
                    break;

                case TransactionType.Sell:
                    var cryptoSellAmount = transaction.Quantity;
                    while (cryptoSellAmount > 0)
                    {
                        if (assetCollection.Count == 0)
                        {
                            return(null);
                        }
                        Asset   soldAsset;
                        decimal sellAmount;
                        if (assetCollection.Peek().Amount <= cryptoSellAmount)
                        {
                            soldAsset  = assetCollection.Pop();
                            sellAmount = soldAsset.Amount;
                        }
                        else
                        {
                            soldAsset         = assetCollection.Peek();
                            sellAmount        = cryptoSellAmount;
                            soldAsset.Amount -= sellAmount;
                        }
                        cryptoSellAmount -= sellAmount;
                        capitalGains.Add(new CapitalGain
                        {
                            YearIncurred  = transaction.TransactionDate.Year,
                            AssetLifetime = transaction.TransactionDate - soldAsset.TransactionDate,
                            UsdAmount     = sellAmount * (transaction.PriceInUsd - soldAsset.ExchangeRate)
                        });
                    }
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }
            return(capitalGains);
        }
        private List <Asset> GetHeldAssets(IReadOnlyCollection <Transaction> transactions)
        {
            var assetCollection = new AssetCollection(AccountingMethodType.Lifo);

            var sortedtransactions = transactions
                                     .OrderBy(x => x.TransactionDate);

            foreach (var transaction in sortedtransactions)
            {
                switch (transaction.TransactionType)
                {
                case TransactionType.Buy:
                    assetCollection.Add(new Asset
                    {
                        TransactionDate = transaction.TransactionDate,
                        Amount          = transaction.Quantity,
                        ExchangeRate    = transaction.PriceInUsd
                    });
                    break;

                case TransactionType.Sell:
                    var cryptoSellAmount = transaction.Quantity;
                    while (cryptoSellAmount > 0)
                    {
                        if (assetCollection.Count == 0)
                        {
                            // return an empty list if the assets can't be correctly calculated
                            return(new List <Asset>());
                        }
                        Asset   soldAsset;
                        decimal sellAmount;
                        if (assetCollection.Peek().Amount <= cryptoSellAmount)
                        {
                            soldAsset  = assetCollection.Pop();
                            sellAmount = soldAsset.Amount;
                        }
                        else
                        {
                            soldAsset         = assetCollection.Peek();
                            sellAmount        = cryptoSellAmount;
                            soldAsset.Amount -= sellAmount;
                        }
                        cryptoSellAmount -= sellAmount;
                    }
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            return(assetCollection.ToList());
        }