public SellResults Calculate(IList <Share> shares, int sharesSold, double sellPricePerShare, DateTime sellDate) { var result = new SellResults(); var sharesBeforeDate = 0; var sharesBeforeDatePriceMax = 0.0; var i = 0; while (i < shares.Count && shares[i].PurchaseDate <= sellDate) { sharesBeforeDate += shares[i].Shares; sharesBeforeDatePriceMax = Math.Max(sharesBeforeDatePriceMax, shares[i].Price); i++; } if (sharesBeforeDate < sharesSold) { throw new InvalidOperationException("Not enough shares to sell by the specified date"); } var sharesAfterDate = 0; var sharesAfterDatePriceMax = 0.0; while (i < shares.Count) { sharesAfterDate += shares[i].Shares; sharesAfterDatePriceMax = Math.Max(sharesAfterDatePriceMax, shares[i].Price); i++; } var sellingSharesTotal = sharesBeforeDatePriceMax * sharesSold; var remainingShares = 0; var remainingSharesTotal = 0.0; var remainingSharesPrice = Math.Max(sharesBeforeDatePriceMax, sharesAfterDatePriceMax); remainingShares = sharesBeforeDate - sharesSold + sharesAfterDate; remainingSharesTotal = remainingShares * remainingSharesPrice; result.CostPriceSoldShares = sharesBeforeDatePriceMax; result.GainLossOnSale = sellPricePerShare * sharesSold - result.CostPriceSoldShares * sharesSold; result.RemainingShares = remainingShares; result.CostPriceRemaining = remainingSharesPrice * (result.RemainingShares > 0 ? 1 : 0); return(result); }
public SellResults Calculate(IList <Share> shares, int sharesSold, double sellPricePerShare, DateTime sellDate) { var result = new SellResults(); var sharesBeforeDate = 0; var sharesBeforeDateTotal = 0.0; var sharesSelling = sharesSold; var sharesRemainingInSplit = 0; var sharesRemainingInSplitTotal = 0.0; var i = 0; while (i < shares.Count && shares[i].PurchaseDate <= sellDate && sharesSelling > shares[i].Shares) { sharesBeforeDate += shares[i].Shares; sharesBeforeDateTotal += shares[i].Total; sharesSelling -= shares[i].Shares; i++; } if (sharesSelling <= shares[i].Shares && shares[i].PurchaseDate <= sellDate) { sharesBeforeDate += sharesSelling; sharesBeforeDateTotal += sharesSelling * shares[i].Price; sharesRemainingInSplit = shares[i].Shares - sharesSelling; sharesRemainingInSplitTotal = sharesRemainingInSplit * shares[i].Price; i++; } if (sharesBeforeDate < sharesSold) { throw new InvalidOperationException("Not enough shares to sell by the specified date"); } var sharesAfterDate = 0; var shareAfterDateTotal = 0.0; while (i < shares.Count) { sharesAfterDate += shares[i].Shares; shareAfterDateTotal += shares[i].Total; i++; } var remainingShares = 0; var remainingSharesTotal = 0.0; remainingShares = sharesRemainingInSplit + sharesAfterDate; remainingSharesTotal = sharesRemainingInSplitTotal + shareAfterDateTotal; var remainingSharesPrice = remainingSharesTotal / remainingShares; result.CostPriceSoldShares = sharesBeforeDateTotal / sharesBeforeDate; result.GainLossOnSale = sellPricePerShare * sharesSold - result.CostPriceSoldShares * sharesSold; result.RemainingShares = remainingShares; result.CostPriceRemaining = remainingSharesPrice * (result.RemainingShares > 0 ? 1 : 0); return(result); }
public SellResults Calculate(IList <Share> shares, int sharesSold, double sellPricePerShare, DateTime sellDate) { var result = new SellResults(); var sharesRemaining = 0; var sharesToSell = sharesSold; var sellingShares = 0; var sellingSharesTotal = 0.0; var splitPosition = 0; var remainingSharesAfter = 0; //shares after date var remainingSharesAfterTotal = 0.0; var remainingSharesBefore = 0; //shares before split position var remainingSharesBeforeTotal = 0.0; var remainingSharesInSplit = 0; //shares remaining in the split position var remaininSharesInSplitTotal = 0.0; for (int i = shares.Count - 1; i >= 0; i--) { if (shares[i].PurchaseDate > sellDate) { remainingSharesAfter += shares[i].Shares; remainingSharesAfterTotal += shares[i].Total; } else { sharesRemaining = sharesToSell - shares[i].Shares; if (sharesRemaining > 0) { sellingShares += shares[i].Shares; sellingSharesTotal += shares[i].Total; sharesToSell = sharesRemaining; continue; } else { var finalFillingShares = shares[i].Shares + sharesRemaining; sellingShares += finalFillingShares; sellingSharesTotal += finalFillingShares * shares[i].Price; remainingSharesInSplit = shares[i].Shares - finalFillingShares; remaininSharesInSplitTotal = remainingSharesInSplit * shares[i].Price; splitPosition = i; break; } } } if (sellingShares != sharesSold) { throw new InvalidOperationException("Not enough shares to sell by the specified date"); } //Calculate remaining positions before split for (int i = splitPosition - 1; i >= 0; i--) { remainingSharesBefore += shares[i].Shares; remainingSharesBeforeTotal += shares[i].Total; } //Combine var totalRemainingShares = remainingSharesBefore + remainingSharesInSplit + remainingSharesAfter; var totalRemainingSharesTotal = remainingSharesBeforeTotal + remaininSharesInSplitTotal + remainingSharesAfterTotal; result.CostPriceSoldShares = sellingSharesTotal / sellingShares; result.GainLossOnSale = sellPricePerShare * sharesSold - result.CostPriceSoldShares * sharesSold; result.RemainingShares = totalRemainingShares; result.CostPriceRemaining = (totalRemainingSharesTotal / totalRemainingShares) * (result.RemainingShares > 0 ? 1 : 0); return(result); }