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> >(); }
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)); } } }