Beispiel #1
0
        public void CostBasisAcrossTransfers()
        {
            UiDispatcher.CurrentDispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
            MyMoney  m = new MyMoney();
            Security s = m.Securities.NewSecurity();

            s.Name = "MSFT";
            Account a  = m.Accounts.AddAccount("Ameritrade");
            Account a2 = m.Accounts.AddAccount("Fidelity");

            AddInvestment(m, s, a, DateTime.Parse("1/1/2000"), 10, 1, InvestmentType.Buy);
            m.StockSplits.AddStockSplit(new StockSplit()
            {
                Date        = DateTime.Parse("6/1/2000"),
                Numerator   = 2,
                Denominator = 1,
                Security    = s
            });
            AddInvestment(m, s, a, DateTime.Parse("1/1/2001"), 20, 2, InvestmentType.Buy);

            Transaction transfer = AddInvestment(m, s, a, DateTime.Parse("1/1/2002"), 30, 2, InvestmentType.Remove);

            m.Transfer(transfer, a2);

            // now should be able to sell 10 left in this account (after split)
            AddInvestment(m, s, a, DateTime.Parse("1/1/2003"), 10, 3, InvestmentType.Sell);

            // and we should have 30 in the other account
            AddInvestment(m, s, a2, DateTime.Parse("1/1/2004"), 30, 5, InvestmentType.Sell);

            // Ok, now let's if the cost basis is correct!
            CostBasisCalculator     calc     = new CostBasisCalculator(m, DateTime.Now);
            List <SecurityPurchase> holdings = new List <SecurityPurchase>(calc.GetHolding(a).GetHoldings());

            Assert.AreEqual <int>(0, holdings.Count); // should have nothing left.

            // should have 3 separate cost basis records to cover what we sold.
            List <SecuritySale> sales = new List <SecuritySale>(calc.GetSales());

            Assert.AreEqual <int>(3, sales.Count);

            SecuritySale s1 = sales[0];
            SecuritySale s2 = sales[1];
            SecuritySale s3 = sales[2];

            // since the sale from Ameritrade account happened first it should be returned first
            Assert.AreEqual <decimal>(2, s1.CostBasisPerUnit); // $2, no splits
            Assert.AreEqual(a, s1.Account);                    // Ameritrade
            Assert.AreEqual <decimal>(Math.Round(10M, 5), Math.Round(s1.UnitsSold, 5));

            // Notice here that the Fidelity account inherited the cost basis records correctly
            // from the Ameritrade account as a result of the "Transfer" that happened above.
            Assert.AreEqual <decimal>(Math.Round(1M / 2M, 5), Math.Round(s2.CostBasisPerUnit, 5)); // $1 after 2:1 split
            Assert.AreEqual(a2, s2.Account);                                                       // Fidelity
            Assert.AreEqual <decimal>(Math.Round(20M, 5), Math.Round(s2.UnitsSold, 5));

            Assert.AreEqual <decimal>(2, s3.CostBasisPerUnit); // $2, no splits
            Assert.AreEqual(a2, s2.Account);                   // Fidelity
            Assert.AreEqual <decimal>(Math.Round(10M, 5), Math.Round(s3.UnitsSold, 5));
        }
Beispiel #2
0
        private void CreateInvestmentSamples(SampleData data, List <Account> brokerageAccounts)
        {
            if (brokerageAccounts.Count == 0)
            {
                return;
            }

            // now balance the accounts.
            foreach (Account a in money.Accounts.GetAccounts())
            {
                money.Rebalance(a);
            }

            // first figure out how much we can spend each year.
            int      year  = DateTime.Now.Year - 10;
            DateTime start = new DateTime(year, 1, 1); // start in January
            DateTime end   = start.AddYears(1);
            Dictionary <int, decimal> cash = new Dictionary <int, decimal>();
            Ownership ownership            = new Ownership();
            decimal   removed = 0;

            foreach (var t in money.Transactions.GetTransactionsFrom(this.checking))
            {
                if (t.Date > end)
                {
                    cash[year] = GetStockMoney(t.Balance);
                    end        = end.AddYears(1);
                    year++;
                }
            }

            money.BeginUpdate(this);

            Dictionary <Account, decimal> cashBalance = new Dictionary <Account, decimal>();

            foreach (var a in brokerageAccounts)
            {
                cashBalance[a] = 0;
            }

            Transactions transactions = money.Transactions;

            for (year = DateTime.Now.Year - 10; year <= DateTime.Now.Year; year++)
            {
                cash.TryGetValue(year, out decimal balance);
                balance -= removed;
                if (balance < 100)
                {
                    continue; // not enough.
                }
                decimal startBalance = balance;

                int numberOfTransactionForThatYear = rand.Next(5, 100); // up to 100 transactions max per year.

                // keep track of how much we own so we never go negative.
                IList <int> selectedDays = GetRandomDaysInTheYearForTransactions(numberOfTransactionForThatYear);

                foreach (var day in selectedDays)
                {
                    // select random security.
                    SampleSecurity ss = data.Securities[rand.Next(0, data.Securities.Count)];
                    // Get or Create the security
                    Security stock = money.Securities.FindSecurity(ss.Name, true);
                    stock.SecurityType = ss.SecurityType;
                    stock.Symbol       = ss.Symbol;

                    // select a random brokerage.
                    Account a = brokerageAccounts[rand.Next(brokerageAccounts.Count)];

                    var canSpend = balance + cashBalance[a];
                    if (canSpend < 100)
                    {
                        break;
                    }

                    // the date the purchase or sale was done
                    var date = new DateTime(year, 1, 1).AddDays(day);

                    // How many unit bought or sold
                    var quote = GetClosingPrice(ss.Symbol, date);

                    Transaction t     = null;
                    decimal     owned = ownership.GetUnits(a, ss.Symbol);
                    if (owned > 4 && rand.Next(3) == 1)
                    {
                        // make this a sell transaction.
                        // Create a new Transaction
                        t      = money.Transactions.NewTransaction(a);
                        t.Date = date;
                        //-----------------------------------------------------
                        // Create the matching Investment transaction
                        Investment i = t.GetOrCreateInvestment();
                        i.Transaction = t;
                        i.Security    = stock;
                        i.UnitPrice   = quote;
                        i.Price       = quote;
                        i.Type        = InvestmentType.Sell;
                        // Create the a SELL transaction
                        i.Units = rand.Next(1, (int)(owned / 2));
                        ownership.AddUnits(a, ss.Symbol, -i.Units);
                        // Calculate the Payment or Deposit amount
                        t.Amount = RoundCents(i.Units * i.UnitPrice);
                    }
                    else
                    {
                        int max = (int)(canSpend / quote);
                        if (max > 0)
                        {
                            // Create a new Transaction
                            t      = money.Transactions.NewTransaction(a);
                            t.Date = date;

                            //-----------------------------------------------------
                            // Create the matching Investment transaction
                            Investment i = t.GetOrCreateInvestment();
                            i.Transaction = t;
                            i.Security    = stock;
                            i.UnitPrice   = quote;
                            i.Price       = quote;
                            i.Type        = InvestmentType.Buy;
                            i.Units       = rand.Next(1, max);
                            ownership.AddUnits(a, ss.Symbol, i.Units);
                            // Calculate the Payment or Deposit amount
                            t.Amount = RoundCents(i.Units * i.UnitPrice * -1);
                        }
                    }

                    if (t != null)
                    {
                        t.Payee         = money.Payees.FindPayee(ss.Name, true);
                        t.Category      = money.Categories.InvestmentStocks;
                        balance        += t.Amount;
                        cashBalance[a] += t.Amount;
                        // Finally add the new transaction
                        money.Transactions.AddTransaction(t);
                    }
                }

                foreach (var acct in brokerageAccounts)
                {
                    var amount = cashBalance[acct];
                    if (amount < 0)
                    {
                        // then we need to transfer money to cover the cost of the stock purchases.
                        Transaction payment = transactions.NewTransaction(checking);
                        payment.Date   = new DateTime(year, 1, 1);
                        payment.Amount = RoundCents(amount);
                        transactions.AddTransaction(payment);
                        money.Transfer(payment, acct);
                        removed           += -amount;
                        cashBalance[acct] += -amount;
                    }
                }
            }
            money.EndUpdate();

            // now balance the accounts again!
            foreach (Account a in money.Accounts.GetAccounts())
            {
                money.Rebalance(a);
            }
        }