예제 #1
0
 def test_get_asset_class_expenditures(self):
     d: Deposit = Deposit()
     sec1: Security = Security(
         "sec1", "SEC1", price=10.0, buy_restricted=False
     )
     sec2: Security = Security(
         "sec2", "SEC2", price=5.0, buy_restricted=False
     )
     d.add_purchase("ac", Purchase(sec1, 5))
     d.add_purchase("ac", Purchase(sec2, 10))
     self.assertEqual(d.get_asset_class_expenditures("ac"), 100.0)
예제 #2
0
 def add_purchase(self, asset_class_name: str, purchase: Purchase) -> None:
     """
     Adds the given purchase to the list of purchases to be made for the
     given asset class.
     """
     if self.involves_asset_class(asset_class_name):
         self.__purchases[asset_class_name] += [purchase]
     else:
         self.__purchases[asset_class_name] = [purchase]
     self.__total += purchase.get_cost()
     self.__num_shares += purchase.get_num_shares()
예제 #3
0
 def test_plan_purchases_knapsack_test_2(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec1: Security = Security("sec1", "SEC1", price=33.0, buy_restricted=0)
     sec2: Security = Security("sec2", "SEC2", price=49.0, buy_restricted=0)
     ac.add_security(sec1)
     ac.add_security(sec2)
     purchases: List[Purchase] = ac.plan_purchases(98.5)
     self.assertEqual(purchases, {"sec2": Purchase(sec2, 2)})
예제 #4
0
 def test_add_purchase(self):
     d: Deposit = Deposit()
     sec: Security = Security("sec", "SEC", price=10.0)
     pur: Purchase = Purchase(sec, 5)
     d.add_purchase("ac", pur)
     self.assertEqual(d.get_total(), 50.0)
     self.assertEqual(d.get_num_shares(), 5)
     self.assertTrue(pur in d.get_purchases_for_asset_class("ac"))
예제 #5
0
    def plan_purchases(self, budget: float) -> Dict[str, Purchase]:
        """
        Uses a Dynamic Program to determine how to optimally spend the budget
        on the asset class's securities. This is the well known Unbounded
        Knapsack problem.
        """
        budget_cents: int = int(budget * 100)
        if budget_cents < 0:
            return {}

        sec_ids: List[str] = []
        prices_in_cents: List[int] = []
        for s in self.get_securities():
            if not s.get_buy_restricted():
                s_id = s.get_id()
                price = s.with_cents().get_price()
                if price is not None:
                    sec_ids.append(s_id)
                    prices_in_cents.append(int(price))
                else:
                    log.warn("Omitting {} from purchases because it has an "
                             "undefined price".format(s_id))

        # Purchase at T[i] maximizes expenditure with budget i
        T: List[int] = [0 for x in range(budget_cents + 1)]
        for b_cents in range(budget_cents + 1):
            for (j_id, j_price_cents) in zip(sec_ids, prices_in_cents):
                # Check if budget of b allows for a purchase of j
                if j_price_cents <= b_cents:
                    # Check if buying it increases expenditures
                    cur_exp: int = T[b_cents]
                    new_exp: int = T[b_cents - j_price_cents] + j_price_cents
                    if new_exp > cur_exp:
                        # Optimal purchases at budget i now includes buying j
                        T[b_cents] = new_exp

        # Backtrack thru T to construct set of optimal purchases
        purchases: Dict[str, Purchase] = {}
        i: int = len(T) - 1
        while T[i]:
            exp_i: int = T[i]  # Optimal amount spent at budget i
            # Find last security purchased
            for (j_id, j_price_cents) in zip(sec_ids, prices_in_cents):
                # If buying security j brought us to optimal expenditures at
                # budget i
                if (exp_i - j_price_cents >= 0
                        and T[exp_i - j_price_cents] + j_price_cents == exp_i):
                    if j_id in purchases:
                        purchases[j_id].add_shares(1)
                    else:
                        purchases[j_id] = Purchase(self.get_security(j_id), 1)
                    break
            i = exp_i - j_price_cents + 1
        # Prune purchases of no shares from return value
        return dict([(s, p) for (s, p) in purchases.items()
                     if p.get_num_shares() != 0])
예제 #6
0
 def test_plan_purchases_buy_restricted_test_1(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec1: Security = Security("sec1", "SEC1", price=33.0, buy_restricted=0)
     sec2: Security = Security("sec2", "SEC2", price=49.0, buy_restricted=1)
     ac.add_security(sec1)
     ac.add_security(sec2)
     purchases: List[Purchase] = ac.plan_purchases(98.5)
     p1: Purchase = Purchase(sec1, 2)
     self.assertEqual(len(purchases), 1)
     self.assertEqual(purchases["sec1"], p1)
예제 #7
0
 def test_equality(self):
     sec: Security = Security(
         "sec", "SEC", price=10.0, buy_restricted=False
     )
     pur: Purchase = Purchase(sec, 5)
     d1: Deposit = Deposit()
     d1.add_purchase("ac", pur)
     d2: Deposit = Deposit()
     d2.add_purchase("ac", pur)
     self.assertEqual(d1, d2)
예제 #8
0
 def test_equality(self):
     p1: Purchase = Purchase(Security("sec", "SEC", price=10.0), 5)
     p2: Purchase = Purchase(Security("sec", "SEC", price=10.0), 5)
     self.assertEqual(p1, p2)
예제 #9
0
 def test_get_purchases_for_asset_class(self):
     sec: Security = Security("sec", "SEC", "sec_name", 10.0, False)
     pur: Purchase = Purchase(sec, 5)
     d: Deposit = Deposit()
     d.add_purchase("ac", pur)
     self.assertEqual(d.get_purchases_for_asset_class("ac"), [pur])
예제 #10
0
 def test_involves_asset_class_true(self):
     d: Deposit = Deposit()
     sec: Security = Security("sec", "SEC", "sec_name", 10.0)
     pur: Purchase = Purchase(sec, 5)
     d.add_purchase("ac", pur)
     self.assertTrue(d.involves_asset_class("ac"))
예제 #11
0
 def test_inequality(self):
     d1: Deposit = Deposit()
     sec: Security = Security("sec", "SEC", price=10.0)
     d1.add_purchase("ac", Purchase(sec, 5))
     d2: Deposit = Deposit()
     self.assertNotEqual(d1, d2)