public void CalculateCgtNotEnoughParcels()
        {
            var parcels = new List <Parcel>();

            var parcel1 = new Parcel(Guid.NewGuid(), new Date(2000, 01, 01), new Date(2000, 01, 01), new ParcelProperties(100, 100.00m, 100.00m), null);

            parcels.Add(parcel1);

            var parcel2 = new Parcel(Guid.NewGuid(), new Date(2002, 01, 01), new Date(2002, 01, 01), new ParcelProperties(100, 100.00m, 100.00m), null);

            parcels.Add(parcel2);

            var parcel3 = new Parcel(Guid.NewGuid(), new Date(2001, 01, 01), new Date(2001, 01, 01), new ParcelProperties(100, 100.00m, 100.00m), null);

            parcel3.Change(new Date(2005, 01, 01), -100, -100.00m, -100.00m, null);
            parcels.Add(parcel3);

            var parcel4 = new Parcel(Guid.NewGuid(), new Date(2003, 01, 01), new Date(2003, 01, 01), new ParcelProperties(100, 100.00m, 100.00m), null);

            parcels.Add(parcel4);

            var calculator = new CgtCalculator();

            var parcelsSold = calculator.Calculate(parcels, new Date(2010, 01, 01), 500, 1000.00m, new FirstInFirstOutCgtComparer());

            Action a = () => parcelsSold.ToList();

            a.Should().Throw <ArgumentException>();
        }
        public void CalculateCgtPartialSale()
        {
            var parcels = new List <Parcel>();

            var parcel1 = new Parcel(Guid.NewGuid(), new Date(2000, 01, 01), new Date(2000, 01, 01), new ParcelProperties(100, 100.00m, 110.00m), null);

            parcels.Add(parcel1);

            var parcel2 = new Parcel(Guid.NewGuid(), new Date(2009, 06, 30), new Date(2009, 01, 01), new ParcelProperties(100, 120.00m, 130.00m), null);

            parcels.Add(parcel2);

            var parcel3 = new Parcel(Guid.NewGuid(), new Date(2001, 01, 01), new Date(2001, 01, 01), new ParcelProperties(100, 130.00m, 140.00m), null);

            parcel3.Change(new Date(2005, 01, 01), -100, -100.00m, -100.00m, null);
            parcels.Add(parcel3);

            var parcel4 = new Parcel(Guid.NewGuid(), new Date(2003, 01, 01), new Date(2003, 01, 01), new ParcelProperties(100, 140.00m, 150.00m), null);

            parcels.Add(parcel4);

            var calculator = new CgtCalculator();

            var parcelsSold = calculator.Calculate(parcels, new Date(2010, 01, 01), 250, 1000.00m, new FirstInFirstOutCgtComparer()).ToArray();

            var expectedResult = new ParcelSold[]
            {
                new ParcelSold(parcel1, 100, 110.00m, 400.00m, 290.00m, CgtMethod.Discount, 145.00m),
                new ParcelSold(parcel4, 100, 150.00m, 400.00m, 250.00m, CgtMethod.Discount, 125.00m),
                new ParcelSold(parcel2, 50, 65.00m, 200.00m, 135.00m, CgtMethod.Other, 135.00m),
            };

            parcelsSold.Should().Equal(expectedResult);
        }
        public void CalculateCgtNoParcels()
        {
            var parcels = new List <Parcel>();

            var calculator = new CgtCalculator();

            var parcelsSold = calculator.Calculate(parcels, new Date(2010, 01, 01), 250, 1000.00m, new FirstInFirstOutCgtComparer());

            Action a = () => parcelsSold.ToList();

            a.Should().Throw <ArgumentException>();
        }
        public void CalculateParcelCgt(Date disposalDate, int unitsSold, decimal saleAmount, decimal expectedCostBase, decimal expectedCapitalGain, decimal expectedDiscountedGain, CgtMethod expectedCgtMethod, string because)
        {
            var aquisitionDate = new Date(2017, 01, 01);
            var properties     = new ParcelProperties(1000, 1000.00m, 2000.00m);
            var parcel         = new Parcel(Guid.NewGuid(), aquisitionDate, aquisitionDate, properties, null);

            parcel.Change(new Date(2017, 08, 01), 1000, 2000.00m, 2000.00m, null);

            var calculator = new CgtCalculator();

            var parcelSold = calculator.CalculateParcelCgt(parcel, disposalDate, unitsSold, saleAmount);

            parcelSold.Should().BeEquivalentTo(new
            {
                AmountReceived = saleAmount,
                CostBase       = expectedCostBase,
                CapitalGain    = expectedCapitalGain,
                DiscountedGain = expectedDiscountedGain,
                CgtMethod      = expectedCgtMethod
            }, because);
        }
        public void CheckAllCgtMethodsHaveAComparere(CgtCalculationMethod method)
        {
            var comparer = CgtCalculator.GetCgtComparer(Date.MinValue, method);

            comparer.Should().BeAssignableTo <IComparer <Parcel> >();
        }
Exemple #6
0
        public void Apply(IPortfolioTransaction transaction, IHolding holding, ICashAccount cashAccount)
        {
            var disposal = transaction as Disposal;

            if (disposal == null)
            {
                throw new ArgumentException("Expected transaction to be a Disposal");
            }

            if (!holding.IsEffectiveAt(disposal.Date))
            {
                throw new NoSharesOwnedException("No holdings");
            }

            if (holding.Properties[disposal.Date].Units < disposal.Units)
            {
                throw new NotEnoughSharesForDisposal("Not enough shares for disposal");
            }

            // Determine which parcels to sell based on CGT method
            decimal amountReceived = (disposal.Units * disposal.AveragePrice) - disposal.TransactionCosts;

            var cgtCalculator = new CgtCalculator();
            var parcelsSold   = cgtCalculator.Calculate(holding.Parcels(disposal.Date), disposal.Date, disposal.Units, amountReceived, CgtCalculator.GetCgtComparer(disposal.Date, disposal.CgtMethod));

            // Dispose of select parcels
            if (disposal.Stock is StapledSecurity)
            {
                /*     foreach (ParcelSold parcelSold in cgtCalculation.ParcelsSold)
                 *   {
                 *       var childStocks = _StockQuery.GetChildStocks(stock.Id, disposal.TransactionDate);
                 *
                 *       // Apportion amount based on NTA of child stocks
                 *       var amountsReceived = PortfolioUtils.ApportionAmountOverChildStocks(childStocks, disposal.TransactionDate, parcelSold.AmountReceived, _StockQuery);
                 *
                 *       int i = 0;
                 *       foreach (var childStock in childStocks)
                 *       {
                 *           var childParcels = _PortfolioQuery.GetParcelsForStock(childStock.Id, disposal.TransactionDate, disposal.TransactionDate);
                 *
                 *           var childParcel = childParcels.First(x => x.PurchaseId == parcelSold.Parcel.PurchaseId);
                 *           DisposeOfParcel(unitOfWork, childParcel, disposal.TransactionDate, parcelSold.UnitsSold, amountsReceived[i].Amount, transaction.Id);
                 *
                 *           i++;
                 *       }
                 *
                 *   };  */
            }
            else
            {
                foreach (var parcelSold in parcelsSold)
                {
                    holding.DisposeOfParcel(parcelSold.Parcel.Id, disposal.Date, parcelSold.UnitsSold, parcelSold.AmountReceived, parcelSold.CapitalGain, parcelSold.CgtMethod, transaction);
                }
            }

            if (disposal.CreateCashTransaction)
            {
                var cost = disposal.Units * disposal.AveragePrice;

                var asxCode = disposal.Stock.Properties[disposal.Date].AsxCode;
                cashAccount.Transfer(disposal.Date, cost, String.Format("Sale of {0}", asxCode));

                if (disposal.TransactionCosts > 0.00m)
                {
                    cashAccount.FeeDeducted(disposal.Date, disposal.TransactionCosts, String.Format("Brokerage for sale of {0}", asxCode));
                }
            }
        }