/// <summary> /// Adds an entry to this bucket /// </summary> /// <param name="entry">The entry for a transaction</param> public void AddEntry(ITransactionBookEntry entry) { if (!(entry is ISplitTransactionBookEntry)) { _entries.Add(entry.StockId, entry.Copy()); } AdjustAvailableUnits(entry.Copy()); }
/// <summary> /// Adjusts the amount of available units for every transaction /// </summary> /// <param name="newEntry">New entry</param> private void AdjustAvailableUnits(ITransactionBookEntry newEntry) { var id = newEntry.StockId; if (newEntry is ISellingTransactionBookEntry && newEntry.Shares > GetOrAddOpenPosition(id).Shares) { throw new InvalidOperationException("Cannot sell more units than available."); } _changedEntries.Clear(id); if (newEntry is IBuyingTransactionBookEntry) { UpdateOpenPosition(id); return; } if (newEntry is ISplitTransactionBookEntry split) { var buys = _entries.GetOrAdd(id).Where(e => e is IBuyingTransactionBookEntry).ToList(); buys.ForEach(t => _entries.Delete(id, t)); _entries.Add(id, split.CreatePositionAfterSplit(buys)); UpdateOpenPosition(id); return; } var newUnitsToSell = newEntry.Shares; var deletes = new List <ITransactionBookEntry>(); foreach (var entry in _entries.GetOrAdd(id).OrderBy(e => e.OrderDate)) { if (entry is IBuyingTransactionBookEntry) { var changed = entry.Copy(); //Complete buying transaction filled if (entry.Shares <= newUnitsToSell) { newUnitsToSell -= entry.Shares; if (!(newEntry is IDividendTransactionBookEntry)) { entry.Shares = 0; } } //Partly filled else { changed.Shares = newUnitsToSell; changed.OrderCosts = (entry.OrderCosts / entry.Shares) * newUnitsToSell; if (!(newEntry is IDividendTransactionBookEntry)) { entry.OrderCosts = (entry.OrderCosts / entry.Shares) * (entry.Shares - newUnitsToSell); entry.Shares -= newUnitsToSell; } newUnitsToSell = 0; } _changedEntries.Add(id, changed); if (entry.Shares == 0 && !(newEntry is IDividendTransactionBookEntry)) { deletes.Add(entry); } if (newUnitsToSell == 0) { break; } } } _changedEntries.Add(id, newEntry); _entries.Delete(id, newEntry); if (!(newEntry is IDividendTransactionBookEntry)) { deletes.ForEach(t => _entries.Delete(id, t)); } UpdateOpenPosition(id); }