private void StateUpdateLoop() { decimal quantity = 0; decimal cost = 0; var txs = new List <CryptoTransaction>(); DateTimeOffset?oldestOpen = null; var positionInstances = new List <PositionInstance>(); DateTimeOffset lastTransaction = DateTimeOffset.UtcNow; bool PurchaseProcessing(ICryptoTransaction st) { lastTransaction = st.When; if (quantity == 0) { oldestOpen = st.When; positionInstances.Add(new PositionInstance(Token)); } quantity += st.Quantity; cost += st.DollarAmount; txs.Add( CryptoTransaction.DebitTx( Id, st.Id, Token, $"Purchased {st.Quantity} for ${st.DollarAmount}", st.DollarAmount, st.When ) ); positionInstances[positionInstances.Count - 1].Buy(st.Quantity, st.DollarAmount, st.When); return(true); } bool SellProcessing(ICryptoTransaction st) { // TODO: this should never happen but in prod I see sell get // triggered before purchase... something is amiss if (positionInstances.Count > 0) { positionInstances[positionInstances.Count - 1].Sell(st.Quantity, st.DollarAmount, st.When); } lastTransaction = st.When; txs.Add( CryptoTransaction.CreditTx( Id, st.Id, Token, $"Sold {st.Quantity} for ${st.DollarAmount}", st.DollarAmount, st.When ) ); quantity -= st.Quantity; cost -= st.DollarAmount; return(true); } foreach (var st in BuyOrSell.OrderBy(e => e.When).ThenBy(i => BuyOrSell.IndexOf(i))) { if (Deletes.Contains(st.Id)) { continue; } if (st is CryptoPurchased sp) { PurchaseProcessing(sp); } else if (st is CryptoSold ss) { SellProcessing(ss); } if (quantity == 0) { cost = 0; oldestOpen = null; } } foreach (var a in Awards) { if (Deletes.Contains(a.Id)) { continue; } if (quantity == 0) { oldestOpen = a.When; } quantity += a.Quantity; } foreach (var y in Yields) { if (Deletes.Contains(y.Id)) { continue; } quantity += y.Quantity; } Quantity = quantity; Cost = cost; Transactions.Clear(); Transactions.AddRange(txs); PositionInstances.Clear(); PositionInstances.AddRange(positionInstances); DaysHeld = oldestOpen.HasValue ? (int)Math.Floor(DateTimeOffset.UtcNow.Subtract(oldestOpen.Value).TotalDays) : 0; DaysSinceLastTransaction = (int)DateTimeOffset.UtcNow.Subtract(lastTransaction).TotalDays; }
private void StateUpdateLoop() { decimal avgCost = 0; decimal owned = 0; decimal cost = 0; var txs = new List <Transaction>(); DateTimeOffset?oldestOpen = null; var positionInstances = new List <PositionInstance>(); DateTimeOffset lastTransaction = DateTimeOffset.UtcNow; bool PurchaseProcessing(IStockTransaction st) { lastTransaction = st.When; if (owned == 0) { oldestOpen = st.When; positionInstances.Add(new PositionInstance(Ticker)); } avgCost = (avgCost * owned + st.Price * st.NumberOfShares) / (owned + st.NumberOfShares); owned += st.NumberOfShares; cost += st.Price * st.NumberOfShares; txs.Add( Transaction.DebitTx( Id, st.Id, Ticker, $"Purchased {st.NumberOfShares} shares @ ${st.Price}/share", st.Price * st.NumberOfShares, st.When, isOption: false ) ); positionInstances[positionInstances.Count - 1].Buy(st.NumberOfShares, st.Price, st.When); return(true); } bool SellProcessing(IStockTransaction st) { // TODO: this should never happen but in prod I see sell get // triggered before purchase... something is amiss if (positionInstances.Count > 0) { positionInstances[positionInstances.Count - 1].Sell(st.NumberOfShares, st.Price, st.When); } lastTransaction = st.When; txs.Add( Transaction.CreditTx( Id, st.Id, Ticker, $"Sold {st.NumberOfShares} shares @ ${st.Price}/share", st.Price * st.NumberOfShares, st.When, isOption: false ) ); txs.Add( Transaction.PLTx( Id, Ticker, $"Sold {st.NumberOfShares} shares @ ${st.Price}/share", avgCost * st.NumberOfShares, st.Price * st.NumberOfShares, st.When, isOption: false ) ); owned -= st.NumberOfShares; cost -= avgCost * st.NumberOfShares; return(true); } foreach (var st in BuyOrSell.OrderBy(e => e.When).ThenBy(i => BuyOrSell.IndexOf(i))) { if (Deletes.Contains(st.Id)) { continue; } if (st is StockPurchased sp) { PurchaseProcessing(sp); } else if (st is StockSold ss) { SellProcessing(ss); } if (owned == 0) { avgCost = 0; cost = 0; oldestOpen = null; } } AverageCost = avgCost; Owned = owned; Cost = cost; Transactions.Clear(); Transactions.AddRange(txs); PositionInstances.Clear(); PositionInstances.AddRange(positionInstances); DaysHeld = oldestOpen.HasValue ? (int)Math.Floor(DateTimeOffset.UtcNow.Subtract(oldestOpen.Value).TotalDays) : 0; DaysSinceLastTransaction = (int)DateTimeOffset.UtcNow.Subtract(lastTransaction).TotalDays; }