コード例 #1
0
 def test_rebalance_reinvest(self):
     portfolio = Portfolio({CCC: Decimal(2000), DDD: Decimal(8000)})
     orders = portfolio.rebalance(self.model_portfolio)
     self.assertEqual(orders, [(SELL, CCC, Decimal(2000)),
                               (SELL, DDD, Decimal(8000)),
                               (BUY, AAA, Decimal(4000)),
                               (BUY, BBB, Decimal(5000))])
コード例 #2
0
 def test_get_returns_cash_only(self):
     portfolio = Portfolio({CASH: Decimal(1000)})
     act_dates, act_returns = portfolio.get_returns()
     self.assertEqual(len(act_dates), 365)
     self.assertEqual(len(act_returns), len(act_dates))
     self.assertEqual(act_returns[0][0], 1000)
     self.assertEqual(act_returns[-1][0], 1000)
コード例 #3
0
    def test_rebalancing2(self):
        """
        Test rebalancing algorithm. Part 2.

        Cash is not in the same currency as the assets.
        """
        p = Portfolio()

        p.add_cash(200., "USD")
        p.add_cash(250., "GBP")

        tickers = ["VCN.TO", "XAW.TO", "ZAG.TO"]
        quantities = [5, 12, 20]
        p.easy_add_assets(tickers=tickers, quantities=quantities)

        target_asset_alloc = {
            "VCN.TO": 40.0,
            "ZAG.TO": 40.0,
            "XAW.TO": 20.0,
        }

        initial_value = p.value("CAD")
        p.selling_allowed = False
        (_, prices, _, _) = p.rebalance(target_asset_alloc, verbose=True)
        final_value = p.value("CAD")
        self.assertAlmostEqual(initial_value, final_value, -1)

        # The prices should be in the tickers' currency
        for ticker in tickers:
            self.assertEqual(prices[ticker][1], "CAD")

        # Since there was no CAD to start off with,
        # there should be none after rebalacing either
        # (i.e. amount converted to CAD should be the amount used to purchase CAD assets)
        self.assertAlmostEqual(p.cash["CAD"].amount, 0., 1)
コード例 #4
0
class PortfolioPlottingTest(unittest.TestCase):
    def setUp(self):
        self.portfolio = Portfolio({CASH: Decimal(129), AAA: Decimal(4034)})

    def test_plot(self):
        # mock matplotlib.pyplot pie chart
        fig, ax, plt = [MagicMock() for _ in range(3)]
        plt.subplots.return_value = (fig, ax)
        self.portfolio.plot(plt)

        # check arguments to ax.pie(...)
        args = ax.pie.call_args
        values = args[0][0]
        labels = args[1]['labels']

        pos, allocs = self.portfolio.positions, self.portfolio.allocations
        self.assertEqual(values, [pos[CASH], pos[AAA]])
        self.assertEqual(labels, [CASH, AAA])

        # call autopct function for the pie wedge texts
        autopct = args[1]['autopct']
        text1 = autopct(allocs[CASH])
        text2 = autopct(allocs[AAA])
        self.assertEqual(text1, '$129.00 (3.10%)')
        self.assertEqual(text2, '$4,034.00 (96.90%)')
コード例 #5
0
    def test_asset_allocation(self):
        """
        Test asset allocation method.
        """
        p = Portfolio()

        tickers = ["VCN.TO", "ZAG.TO", "XAW.TO", "TSLA"]
        quantities = [2, 20, 10, 4]
        p.easy_add_assets(tickers=tickers, quantities=quantities)

        asset_alloc = p.asset_allocation()
        self.assertAlmostEqual(sum(asset_alloc.values()), 100., 7)

        rates = CurrencyRates()

        prices = [
            yf.Ticker(ticker).info["ask"] *
            rates.get_rate(yf.Ticker(ticker).info["currency"], "CAD")
            for ticker in tickers
        ]
        total = np.sum(np.asarray(quantities) * np.asarray(prices))
        n = len(tickers)
        for i in range(n):
            self.assertAlmostEqual(asset_alloc[tickers[i]],
                                   quantities[i] * prices[i] / total * 100., 1)
コード例 #6
0
 def test_get_returns(self):
     portfolio = Portfolio({CASH: Decimal(1000), VFV: Decimal(1000)})
     act_dates, act_returns = portfolio.get_returns()
     self.assertEqual(len(act_dates), 365)
     self.assertEqual(len(act_returns), len(act_dates))
     shares = Decimal(1000) / Decimal('28.89')
     self.assertEqual(act_returns[0][0], 2000)  # starting CASH + VFV
     self.assertEqual(act_returns[-1][0], shares * Decimal('30.69') + 1000)
コード例 #7
0
 def test_rebalance_balanced(self):
     portfolio = Portfolio({
         CASH: Decimal(500),
         AAA: Decimal(2000),
         BBB: Decimal(2500)
     })
     orders = portfolio.rebalance(self.model_portfolio)
     self.assertEqual(orders, [])
コード例 #8
0
 def test_get_returns_mismatched_dates(self):
     aaa_dates = np.array([[date(2016, 1, 1)], [date(2016, 1, 2)],
                           [date(2016, 1, 3)]])
     aaa_prices = np.array([[42], [43], [44]])
     bbb_dates = np.array([[date(2016, 1, 2)], [date(2016, 1, 3)]])
     bbb_prices = np.array([[57], [58]])
     AAA = FixedPricesInstrument('AAA', aaa_dates, aaa_prices)
     BBB = FixedPricesInstrument('BBB', bbb_dates, bbb_prices)
     portfolio = Portfolio({AAA: Decimal(1000), BBB: Decimal(1000)})
     act_dates, act_returns = portfolio.get_returns()
コード例 #9
0
    def test_portfolio_value(self):
        """
        Test total market value, total cash value, and total value methods.
        """

        p = Portfolio()

        tickers = ["VCN.TO", "ZAG.TO", "XAW.TO", "TSLA"]
        quantities = [2, 20, 10, 4]
        p.easy_add_assets(tickers=tickers, quantities=quantities)

        mv = p.market_value("CAD")

        total_mv = np.sum(
            [asset.market_value_in("CAD") for asset in p.assets.values()])

        self.assertAlmostEqual(mv, total_mv, 1)

        amounts = [500.15, 200.00]
        currencies = ["CAD", "USD"]
        p.easy_add_cash(amounts, currencies)

        cv = p.cash_value("CAD")

        usd_to_cad = CurrencyRates().get_rate("USD", "CAD")
        total_cv = np.sum(amounts[0] + amounts[1] * usd_to_cad)
        self.assertAlmostEqual(cv, total_cv, 1)

        self.assertAlmostEqual(p.value("CAD"), total_mv + total_cv, 1)
コード例 #10
0
    def test_cash_interface2(self):
        """
        Test portfolio's interface related to Cash class.

        Collectively adding cash to the portfolio.
        """
        p = Portfolio()
        amounts = [500.15, 200.00]
        currencies = ["CAD", "USD"]
        p.easy_add_cash(amounts, currencies)

        self.assertEqual(p.cash[currencies[0]].amount, amounts[0])
        self.assertEqual(p.cash[currencies[1]].amount, amounts[1])
コード例 #11
0
    def test_asset_interface2(self):
        """
        Test portfolio's interface related to Asset class.

        Collectively adding assets to the portfolio.
        """

        p = Portfolio()

        tickers = ["VCN.TO", "ZAG.TO"]
        quantities = [2, 20]
        p.easy_add_assets(tickers=tickers, quantities=quantities)

        n = len(tickers)
        for i in range(n):
            self.assertEqual(tickers[i], p.assets[tickers[i]].ticker)
            self.assertEqual(quantities[i], p.assets[tickers[i]].quantity)
            self.assertEqual(
                yf.Ticker(tickers[i]).info["ask"], p.assets[tickers[i]].price)
コード例 #12
0
    def test_asset_interface(self):
        """
        Test portfolio's interface related to Asset class.

        Adding assets individually to the portfolio.
        """
        p = Portfolio()

        ticker = "VCN.TO"
        quantity = 2
        ticker_info = yf.Ticker(ticker).info
        price = ticker_info["ask"]
        asset = Asset(ticker=ticker, quantity=quantity)

        p.add_asset(asset)
        self.assertEqual(asset.ticker, p.assets[ticker].ticker)
        self.assertEqual(asset.quantity, p.assets[ticker].quantity)
        self.assertEqual(asset.price, p.assets[ticker].price)

        ticker = "ZAG.TO"
        quantity = 20
        asset2 = Asset(ticker=ticker, quantity=quantity)
        p.add_asset(asset2)

        self.assertEqual(asset2.ticker, p.assets[ticker].ticker)
        self.assertEqual(asset2.quantity, p.assets[ticker].quantity)
        self.assertEqual(asset2.price, p.assets[ticker].price)
コード例 #13
0
    def test_cash_interface(self):
        """
        Test portfolio's interface related to Cash class.

        Adding cash of different currency individually to the portfolio.
        """
        p = Portfolio()
        amount1 = 500.15
        p.add_cash(amount1, "cad")
        amount2 = 200.00
        p.add_cash(amount2, "usd")

        self.assertEqual(p.cash["CAD"].amount, amount1)
        self.assertEqual(p.cash["USD"].amount, amount2)
コード例 #14
0
 def test_rebalance_unbalanced(self):
     portfolio = Portfolio({AAA: Decimal(2000), BBB: Decimal(8000)})
     orders = portfolio.rebalance(self.model_portfolio)
     self.assertEqual(orders, [(SELL, BBB, Decimal(3000)),
                               (BUY, AAA, Decimal(2000))])
コード例 #15
0
 def test_rebalance_cash(self):
     portfolio = Portfolio({CASH: Decimal(5000)})
     orders = portfolio.rebalance(self.model_portfolio)
     self.assertEqual(orders, [(BUY, AAA, Decimal(2000)),
                               (BUY, BBB, Decimal(2500))])
コード例 #16
0
 def setUp(self):
     self.model_portfolio = Portfolio({
         CASH: Decimal(10),
         AAA: Decimal(40),
         BBB: Decimal(50)
     })
コード例 #17
0
 def setUp(self):
     self.portfolio = Portfolio({CASH: Decimal(1200), AAA: Decimal(300)})
コード例 #18
0
 def setUp(self):
     self.portfolio = Portfolio({CASH: Decimal(129), AAA: Decimal(4034)})
コード例 #19
0
    def test_rebalancing(self):
        """
        Test rebalancing algorithm.

        This might break over time as prices increase.
        If we have enough cash though, the optimizer should ideally
        be able to match the target asset allocation
        pretty closely
        """

        p = Portfolio()

        tickers = ["XBB.TO", "XIC.TO", "ITOT", "IEFA", "IEMG"]
        quantities = [36, 64, 32, 8, 7]
        p.easy_add_assets(tickers=tickers, quantities=quantities)
        p.add_cash(3000, "USD")
        p.add_cash(515.21, "CAD")
        p.add_cash(5.00, "GBP")
        p.selling_allowed = True

        self.assertTrue(p.selling_allowed)

        # different order than tickers.
        # rebalance method should be able to handle such a case
        target_asset_alloc = {
            "XBB.TO": 20,
            "XIC.TO": 20,
            "IEFA": 20,
            "ITOT": 36,
            "IEMG": 4
        }

        initial_value = p.value("CAD")
        (_, _, _, max_diff) = p.rebalance(target_asset_alloc, verbose=True)
        final_value = p.value("CAD")
        self.assertAlmostEqual(initial_value, final_value, 1)
        self.assertLessEqual(max_diff, 2.)

        # Error handling
        with self.assertRaises(Exception):
            target_asset_alloc = {
                "XBB.TO": 20,
                "XIC.TO": 20,
                "IEFA": 20,
            }
            p.rebalance(target_asset_alloc)
コード例 #20
0
    def test_exchange(self):
        """
        Test currency exchange in Portfolio.
        """

        p = Portfolio()

        amounts = [500.15, 200.00]
        currencies = ["CAD", "USD"]
        p.easy_add_cash(amounts, currencies)

        cad_to_usd = CurrencyRates().get_rate("CAD", "USD")

        p.exchange_currency(to_currency="CAD",
                            from_currency="USD",
                            to_amount=100)
        self.assertAlmostEqual(p.cash["CAD"].amount, 500.15 + 100., 1)
        self.assertAlmostEqual(p.cash["USD"].amount, 200. - 100. * cad_to_usd,
                               1)

        p.exchange_currency(from_currency="USD",
                            to_currency="CAD",
                            from_amount=50)
        self.assertAlmostEqual(p.cash["CAD"].amount,
                               500.15 + 100 + 50 / cad_to_usd, 1)
        self.assertAlmostEqual(p.cash["USD"].amount,
                               200. - 100. * cad_to_usd - 50, 1)

        # error handling:
        with self.assertRaises(Exception):
            p.exchange_currency(to_currency="CAD",
                                from_currency="USD",
                                to_amount=100,
                                from_amount=20)

        # error handling
        with self.assertRaises(Exception):
            p.exchange_currency(to_currency="CAD", from_currency="USD")
コード例 #21
0
 def setUp(self):
     self.model_portfolio = Portfolio({AAA: Decimal(10), BBB: Decimal(90)})
コード例 #22
0
from rebalance import Portfolio

# My portfolio
p = Portfolio()

# Cash in portfolio
cash_amounts = [5000]
cash_currency = ["CAD"]
p.easy_add_cash(amounts=cash_amounts, currencies=cash_currency)

# Assets in portfolio
# The price will be retrieved automatically
tickers = ["XIC.TO", "VCN.TO", "TSLA"]
quantities = [20, 20, 10]
p.easy_add_assets(tickers=tickers, quantities=quantities)

# Target asset allocation (in %)
target_asset_alloc = {"XIC.TO": 20, "VCN.TO": 30, "TSLA": 50}

# rebalance
p.selling_allowed = True  # Don't allow selling while rebalancing
p.rebalance(target_asset_alloc, verbose=True)
コード例 #23
0
 def make_portfolio(self, aaa, bbb):
     return Portfolio({AAA: Decimal(aaa), BBB: Decimal(bbb)})
コード例 #24
0
from rebalance import Portfolio

p = Portfolio()

tickers = ["XBB.TO", "XIC.TO", "ITOT", "IEFA", "IEMG"]
quantities = [36, 64, 32, 8, 7]
p.easy_add_assets(tickers=tickers, quantities = quantities)
p.add_cash(5000.00, "GBP")
p.add_cash(1000.00, "EUR")

target_asset_alloc = {
"XBB.TO": 20,
"XIC.TO": 20,
"IEFA":   20,
"ITOT":   36,
"IEMG":    4
}


initial_value = p.value("CAD")
p.selling_allowed = False
(_, _, exchange_rates, _) = p.rebalance(target_asset_alloc, verbose=True)
final_value = p.value("CAD")