Пример #1
0
        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;
        }
Пример #2
0
        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;
        }