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)
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()
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)})
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"))
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])
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)
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)
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)
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])
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"))
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)