public void When_Updating_Account_Then_Update_Is_Atomic()
        {
            var portfolio = TestDataGenerator.GenerateDefaultPortfolio();
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            Security yvr = new Security { Symbol = "yvr" };
            Security goog = new Security { Symbol = "goog" };

            var transactions = new List<Transaction>(2)
            {
                new Transaction
                {
                    Account = mandingo,
                    Date = DateTime.UtcNow,
                    Price = 10M,
                    Security = yvr,
                    Shares = 100M,
                    Type = TransactionType.Buy
                },
                new Transaction
                {
                    Account = mandingo,
                    Date = DateTime.UtcNow,
                    Price = 10M,
                    Security = goog,
                    Shares = 10M,
                    Type = TransactionType.Sell
                },
                new Transaction
                {
                    Account = mandingo,
                    Date = DateTime.UtcNow,
                    Price = 10M,
                    Security = new Security { Symbol = "not_owned" },
                    Shares = 100M,
                    Type = TransactionType.Sell
                }
            };

            var portfolioService = new PortfolioService(portfolio);
            Assert.Throws<Exception>(() => portfolioService.UpdateWith(transactions));

            Assert.That(mandingo.Positions.Count, Is.EqualTo(2));
            var googPosition = mandingo.Positions.Single(p => p.Security.Symbol.Equals(goog.Symbol, StringComparison.InvariantCultureIgnoreCase));
            Assert.That(googPosition.Shares, Is.EqualTo(100M));
            var aaplPosition = mandingo.Positions.Single(p => p.Security.Symbol.Equals("aapl", StringComparison.InvariantCultureIgnoreCase));
            Assert.That(aaplPosition.Shares, Is.EqualTo(200M));

            var took = portfolio.Accounts.Single(a => a.Name.Equals("took", StringComparison.InvariantCultureIgnoreCase));
            var msftPosition = took.Positions.Single(p => p.Security.Symbol.Equals("msft", StringComparison.InvariantCultureIgnoreCase));
            Assert.That(msftPosition.Shares, Is.EqualTo(100M));
        }
        public void When_Updating_Account_With_Buy_Transaction_And_No_Position_Then_Account_Gains_Position()
        {
            // setup
            Security goog = new Security { Symbol = "goog" };
            var portfolio = TestDataGenerator.GenerateEmptyPortfolio();
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            var portfolioService = new PortfolioService(portfolio);
            var transaction = new Transaction
            {
                Account = mandingo,
                Date = DateTime.UtcNow,
                Price = 0M,
                Security = goog,
                Shares = 10M,
                Type = TransactionType.Buy
            };

            // execute
            portfolioService.UpdateWith(new List<Transaction> { transaction });

            // verify
            Assert.That(mandingo.Positions.Single().Shares, Is.EqualTo(10M));
        }
        public void When_Updating_Portfolio_With_Invalid_Transaction_Then_Exception_Is_Thrown()
        {
            // setup
            var portfolio = TestDataGenerator.GenerateEmptyPortfolio();
            var portfolioService = new PortfolioService(portfolio);
            Security goog = new Security { Symbol = "goog" };
            var transaction = new Transaction
            {
                Account = null,
                Date = DateTime.UtcNow,
                Price = 0M,
                Security = goog,
                Shares = 10M,
                Type = TransactionType.Buy
            };

            // verify
            try
            {
                portfolioService.UpdateWith(new List<Transaction> { transaction });
            }
            catch (Exception ex)
            {
                Assert.That(ex.Message, Is.EqualTo("One or more transactions are invalid."));
            }
        }
        public void When_Updating_Empty_Portfolio_With_Transactions_Then_Portfolio_Is_Updated_To_Correct_State()
        {
            // setup
            var portfolio = TestDataGenerator.GenerateEmptyPortfolio();
            var portfolioService = new PortfolioService(portfolio);
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            var took = portfolio.Accounts.Single(a => a.Name.Equals("took", StringComparison.InvariantCultureIgnoreCase));
            Security goog = new Security { Symbol = "goog" };
            Security msft = new Security { Symbol = "msft" };
            var transactionDate = DateTime.UtcNow;

            var transactions = new List<Transaction>();
            transactions.Add(new Transaction
            {
                Account = mandingo,
                Date = transactionDate,
                Price = 15.25M,
                Security = goog,
                Shares = 100M,
                Type = TransactionType.Buy
            });
            transactions.Add(new Transaction()
            {
                Account = took,
                Date = transactionDate.AddMinutes(14),
                Price = 21.54M,
                Security = msft,
                Shares = 50M,
                Type = TransactionType.Sell
            });
            transactions.Add(new Transaction()
            {
                Account = took,
                Date = transactionDate,
                Price = 21.34M,
                Security = msft,
                Shares = 200M,
                Type = TransactionType.Buy
            });

            // execute
            portfolioService.UpdateWith(transactions);

            // verify
            Assert.That(mandingo.Transactions.Count, Is.EqualTo(1));
            Assert.That(mandingo.Positions.Count, Is.EqualTo(1));
            var position = mandingo.Positions.Single();
            Assert.That(position.Security.Symbol, Is.EqualTo(goog.Symbol));
            Assert.That(position.Account, Is.EqualTo(mandingo));
            Assert.That(position.Shares, Is.EqualTo(100M));

            Assert.That(took.Transactions.Count, Is.EqualTo(2));
            Assert.That(took.Positions.Count, Is.EqualTo(1));
            position = took.Positions.Single();
            Assert.That(position.Security.Symbol, Is.EqualTo(msft.Symbol));
            Assert.That(position.Account, Is.EqualTo(took));
            Assert.That(position.Shares, Is.EqualTo(150M));
        }
        public void When_Updating_Account_With_Transaction_That_Already_Happened_Then_New_Transaction_Is_Ignored()
        {
            var portfolio = TestDataGenerator.GenerateDefaultPortfolio();
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            Security yvr = new Security { Symbol = "yvr" };

            var transactions = new List<Transaction>();
            transactions.AddRange(mandingo.Transactions);
            transactions.Add(new Transaction
            {
                Account = mandingo,
                Date = DateTime.UtcNow,
                Price = 10M,
                Security = yvr,
                Shares = 50M,
                Type = TransactionType.Buy
            });

            var portfolioService = new PortfolioService(portfolio);
            portfolioService.UpdateWith(transactions);

            Assert.That(mandingo.Transactions.Count, Is.EqualTo(3));
            var googPosition = mandingo.Positions.Single(p => p.Security.Symbol.Equals("goog", StringComparison.InvariantCultureIgnoreCase));
            Assert.That(googPosition.Shares, Is.EqualTo(100M));
            var aaplPosition = mandingo.Positions.Single(p => p.Security.Symbol.Equals("aapl", StringComparison.InvariantCultureIgnoreCase));
            Assert.That(aaplPosition.Shares, Is.EqualTo(200M));
            var yvrPosition = mandingo.Positions.Single(p => p.Security.Symbol.Equals("yvr", StringComparison.InvariantCultureIgnoreCase));
            Assert.That(yvrPosition.Shares, Is.EqualTo(50M));
        }
        public void When_Updating_Account_With_Sell_Transaction_With_More_Shares_Than_Position_Then_Exception_Is_Thrown()
        {
            // setup
            Security goog = new Security { Symbol = "goog" };
            var portfolio = TestDataGenerator.GenerateEmptyPortfolio();
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            mandingo.Positions.Add(new Position
            {
                Account = mandingo,
                Shares = 1M,
                Security = goog
            });
            var portfolioService = new PortfolioService(portfolio);
            var transaction = new Transaction
            {
                Account = mandingo,
                Date = DateTime.UtcNow,
                Price = 0M,
                Security = goog,
                Shares = 10M,
                Type = TransactionType.Sell
            };

            // verify
            try
            {
                portfolioService.UpdateWith(new List<Transaction> { transaction });
            }
            catch (Exception ex)
            {
                Assert.That(ex.Message, Is.EqualTo("Tried to sell more shares than the account has."));
            }
        }
        public void When_Updating_Account_With_Sell_Transaction_Equal_To_Position_Then_Account_Has_Position_Removed()
        {
            // setup
            Security goog = new Security { Symbol = "goog" };
            var portfolio = TestDataGenerator.GenerateEmptyPortfolio();
            var mandingo = portfolio.Accounts.Single(a => a.Name.Equals("mandingo", StringComparison.InvariantCultureIgnoreCase));
            mandingo.Positions.Add(new Position
            {
                Account = mandingo,
                Shares = 100M,
                Security = goog
            });
            var portfolioService = new PortfolioService(portfolio);
            var transaction = new Transaction
            {
                Account = mandingo,
                Date = DateTime.UtcNow,
                Price = 0M,
                Security = goog,
                Shares = 100M,
                Type = TransactionType.Sell
            };

            // verify
            portfolioService.UpdateWith(new List<Transaction> { transaction });

            Assert.That(mandingo.Positions.Count, Is.EqualTo(0));
        }
        private static ErrorCode QuickFundbotWeightReportOperation(string portfolioName)
        {
            var dataDir = Path.GetFullPath(Environment.ExpandEnvironmentVariables(Configuration.DataDirectoryPath));

            if (!Directory.Exists(dataDir))
            {
                Console.Error.WriteLine("Data directory at {0} does not exist.", dataDir);
                return ErrorCode.DirectoryMissing;
            }

            var fundbotBuysFile = Path.Combine(dataDir, "buys.csv");
            if (!File.Exists(fundbotBuysFile))
            {
                Console.Error.WriteLine("Fundbot file at {0} does not exist.", fundbotBuysFile);
                return ErrorCode.FileMissing;
            }

            var fundbotCategoriesFile = Path.Combine(dataDir, "categories.csv");
            if (!File.Exists(fundbotCategoriesFile))
            {
                Console.Error.WriteLine("Fundbot file at {0} does not exist.", fundbotCategoriesFile);
                return ErrorCode.FileMissing;
            }

            var factory = new DataImporterFactory();
            var transactionReader = factory.GetFundbotTransactions(fundbotBuysFile);
            var transactions = transactionReader.GetTransactions();

            var account = new Account
            {
                Name = portfolioName
            };
            var portfolio = new Portfolio
            {
                Name = portfolioName,
                Accounts = new List<Account> { account }
            };
            account.Portfolio = portfolio;

            foreach (var transaction in transactions)
            {
                transaction.Account = account;
            }

            var portfolioService = new PortfolioService(portfolio);
            portfolioService.UpdateWith(transactions);

            var categoryReader = factory.GetFundbotCategories(fundbotCategoriesFile);
            IEnumerable<Category> categories;
            IEnumerable<CategoryWeight> weights;
            categoryReader.GetCategoriesAndWeights(out categories, out weights);

            var quoter = new YahooStockService(new YahooServiceFactory());
            StringWeightReporter reporter = new StringWeightReporter(quoter);
            var report = reporter.GetReport(portfolio, categories, weights);

            Console.Write(report);

            return ErrorCode.NoError;
        }
        private static ErrorCode ImportFundbotOperation(string portfolioName)
        {
            var dataDir = Path.GetFullPath(Environment.ExpandEnvironmentVariables(Configuration.DataDirectoryPath));

            if (!Directory.Exists(dataDir))
            {
                Console.Error.WriteLine("Data directory at {0} does not exist.", dataDir);
                return ErrorCode.DirectoryMissing;
            }

            var fundbotBuysFile = Path.Combine(dataDir, "buys.csv");
            if (!File.Exists(fundbotBuysFile))
            {
                Console.Error.WriteLine("Fundbot file at {0} does not exist.", fundbotBuysFile);
                return ErrorCode.FileMissing;
            }

            var factory = new DataImporterFactory();
            var fundBotImporter = factory.GetFundbotTransactions(fundbotBuysFile);
            var transactions = fundBotImporter.GetTransactions();

            // which portfolio? account?
            var account = new Account
            {
                Name = portfolioName
            };
            var portfolio = new Portfolio
            {
                Name = portfolioName,
                Accounts = new List<Account> { account }
            };
            account.Portfolio = portfolio;

            foreach (var transaction in transactions)
            {
                transaction.Account = account;
            }

            var portfolioService = new PortfolioService(portfolio);
            portfolioService.UpdateWith(transactions);

            var quoter = new YahooStockService(new YahooServiceFactory());
            var reporter = new StringValueReporter(quoter);
            var report = reporter.GetReport(portfolio);

            Console.Write(report);

            //foreach (var transaction in transactions)
            //{
            //	// need to see if security already exists
            //	// need to see if transaction already exists
            //	// key = symbol & date & shares
            //}

            return ErrorCode.NoError;
        }