Пример #1
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)})
Пример #2
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)
Пример #3
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)
Пример #4
0
 def test_get_dividends(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec1: Security = Security("sec1", "SEC1", "sec1_name", 10.0)
     sec2: Security = Security("sec2", "SEC2", "sec2_name", 10.0)
     ac.add_security(sec1)
     ac.add_security(sec2)
     ac.buy(sec1, 3, False)
     ac.buy(sec2, 3, False)
     hol1: Holding = ac.get_holding("sec1")
     hol2: Holding = ac.get_holding("sec2")
     hol1.set_dividends(1.0)
     hol2.set_dividends(2.0)
     self.assertEqual(ac.get_dividends(), 3.0)
Пример #5
0
 def test_add_holding_hs_hh(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", price=10.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     hol: Holding = Holding(sec, 3, 10.0)
     self.assertRaises(Exception, ac.add_holding, hol)
Пример #6
0
 def test_get_return_negative(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", "sec_name", 10.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     sec.set_price(9.0)
     self.assertEqual(ac.get_return(), -0.1)
Пример #7
0
 def test_buy_new(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", price=5.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     self.assertEqual(ac.get_holding("sec"), Holding(sec, 3, 5.0))
     self.assertEqual(ac.get_value(), 15.0)
Пример #8
0
 def test_equality(self):
     ac1: AssetClass = AssetClass("ac", target_percentage=1.0)
     ac2: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC")
     ac1.add_security(sec)
     ac2.add_security(sec)
     self.assertEqual(ac1, ac2)
Пример #9
0
 def test_get_num_shares(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", "sec_name", 15.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     self.assertEqual(ac.get_num_shares(), 3)
     ac.buy(sec, 7, False)
     self.assertEqual(ac.get_num_shares(), 10)
Пример #10
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"))
Пример #11
0
 def test_update_security(self):
     ac: AssetClass = AssetClass("ac", target_percentage=0.5)
     sec: Security = Security("sec", "SEC")
     ac.add_security(sec)
     ac.update_security("sec", "SEC", "Security A", 100.0)
     new_sec: Security = ac.get_security("sec")
     self.assertEqual(new_sec.get_name(), "Security A")
     self.assertEqual(new_sec.get_price(), 100.0)
Пример #12
0
 def test_add_holding_hs_not_hh(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", price=10.0)
     ac.add_security(sec)
     ac.add_holding(Holding(sec, 3, 10.0))
     holding: Holding = ac.get_holding("sec")
     self.assertEqual(holding.get_value(), 30.0)
     self.assertEqual(holding.get_num_shares(), 3)
     self.assertEqual(holding.get_average_buy_price(), 10.0)
Пример #13
0
 def test_get_return_with_dividends(self):
     sec: Security = Security("sec", "SEC", price=11.0)
     # Value: $33
     # Dividends: $7
     # Cost: $30
     # Return = (Value + Dividends - Cost) / Cost
     #        = (33 + 7 - 30) / 30
     #        = 10 / 30 = 0.33
     hol: Holding = Holding(sec, 3, 10.0, 7.0)
     self.assertEqual(hol.get_return(), 1.0 / 3.0)
Пример #14
0
 def add_security(self, security: Security) -> None:
     """
     Adds the given security to this asset class.
     """
     sec_id: str = security.get_id()
     if not self.contains_security(sec_id):
         self.__securities[sec_id] = security
     else:
         raise Exception("add_security(): {} was already added to the '{}'"
                         "asset class.".format(sec_id, self.get_name()))
Пример #15
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)
Пример #16
0
    def buy(self, security: Security, num_shares: int, online: bool) -> str:
        """
        Adds num_shares of the given security to the holdings of this asset
        class. Returns the state of the buy transaction.
        """
        price: Optional[float] = security.get_price()
        if price is None:
            raise Exception("Can't buy security with undefined price")
        security_id: str = security.get_id()
        if self.contains_holding(security_id):
            hol: Holding = self.get_holding(security_id)
            old_num_shares: int = hol.get_num_shares()
            old_abp: float = hol.get_average_buy_price()
            old_div: float = hol.get_dividends()
            new_num_shares: int = old_num_shares + num_shares
            new_abp: float = (old_abp * old_num_shares + price *
                              num_shares) / (old_num_shares + num_shares)
            self.update_holding(security_id, new_num_shares, new_abp, old_div)
        else:
            self.update_holding(security_id, num_shares, price, 0.0)

        log.info("Buy {n} {s} of {c} at {p} for a total of {t}? (Y/n) ".format(
            n=num_shares,
            s="shares" if num_shares > 1 else "share",
            c=security.get_symbol(),
            p=dollar_str(price),
            t=dollar_str(price * num_shares),
        ))
        order_state: str = "confirmed"
        if online:
            # Actually buy the ETFs
            user_choice: str = input("").lower()
            if user_choice in ["", "y"]:
                resp: Dict[str,
                           Any] = r.order_buy_limit(security.get_symbol(),
                                                    num_shares,
                                                    security.get_price())
                if resp is None:
                    order_state = "failed"
                else:
                    order_state = resp["state"]
        return order_state
Пример #17
0
    def load_configuration(
        self, portfolio_config: List[Dict[str, Any]]
    ) -> None:
        """
        Loads the target investment portfolio (weights for asset classes and
        the securities underlying those asset classes) from the given config
        file.
        """
        total_target_pct: float = 0.0
        for a in portfolio_config:
            # Sanity check for portfolio config format
            assert "name" in a
            assert "target_percentage" in a
            assert "securities" in a
            assert "buy_restrictions" in a

            ac_name: str = a["name"]
            ac_target_pct: float = float(a["target_percentage"])
            ac_securities: List[str] = a["securities"]
            ac_buy_restrictions: List[str] = a["buy_restrictions"]

            for sec_id in ac_buy_restrictions:
                assert sec_id in ac_securities

            ac: AssetClass = (
                self.get_asset_class(ac_name)
                if self.contains_asset_class(ac_name)
                else AssetClass(ac_name, ac_target_pct)
            )
            ac.set_target_percentage(ac_target_pct)

            total_target_pct += ac_target_pct
            for s_id in ac_securities:
                buy_restricted: int = int(s_id in ac_buy_restrictions)
                s: Security = Security(s_id, buy_restricted=buy_restricted)
                if not ac.contains_security(s_id):
                    ac.add_security(s)
                else:
                    sec: Security = ac.get_security(s_id)
                    # Potentially update buy restriction status
                    if buy_restricted:
                        sec.restrict_buy()
                    else:
                        sec.enable_buy()
            if not self.contains_asset_class(ac_name):
                self.add_asset_class(ac)

        self.add_asset_class(AssetClass("Other", 0.0))

        if abs(total_target_pct - 1.0) >= 1e-9:
            raise Exception(
                "load_configuration(): asset class target percentages do not "
                "add up to 1."
            )
Пример #18
0
 def test_to_dict_with_nones(self):
     sec: Security = Security("sec", "SEC")
     test = {
         "id": "sec",
         "symbol": "SEC",
         "name": None,
         "price": None,
         "purchase_buffer": 0.0,
         "buy_restricted": 1,
     }
     self.assertEqual(sec.to_dict(), test)
Пример #19
0
 def __init__(self, security: Security, num_shares: int) -> None:
     sec_price = security.get_price()
     if sec_price is None:
         raise Exception(
             "Purchase must be instantiated with a Security "
             "that has a non-None price"
         )
     if num_shares <= 0:
         raise Exception(
             "Purchase must be instantiated with num_shares >= 0"
         )
     self.__security: Security = security
     self.__num_shares: int = num_shares
     self.__cost: float = sec_price * self.__num_shares
Пример #20
0
 def test_update_holding(self):
     ac: AssetClass = AssetClass("ac", target_percentage=0.5)
     sec: Security = Security("sec",
                              "SEC",
                              name="sec_name",
                              price=40.0,
                              buy_restricted=0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     ac.update_holding("sec", 3, 45.0, 15.0)
     new_hol: Holding = ac.get_holding("sec")
     self.assertEqual(new_hol.get_num_shares(), 3)
     self.assertEqual(new_hol.get_average_buy_price(), 45.0)
     self.assertEqual(new_hol.get_dividends(), 15.0)
Пример #21
0
    def update(
        self,
        account_profile: AccountProfile,
        securities: Dict[str, SecurityInfo],
        holdings: Dict[str, HoldingInfo],
        dividends: Dict[str, DividendInfo],
    ) -> None:
        """
        Updates this portfolio (and its underlying asset classes and
        securities).
        """
        cash: float = account_profile.get_buying_power()
        self.set_cash(cash)
        # Group securities that aren't defined in portfolio configuration in
        # "Other" asset class
        for sec_id in holdings.keys():
            # Extract refreshed data for this security
            hol_info: HoldingInfo = holdings[sec_id]
            sec_info: SecurityInfo = securities[sec_id]
            div_info: DividendInfo = dividends[sec_id]
            updated_shares: int = hol_info.get_quantity()
            updated_average_buy_price: float = (
                hol_info.get_average_buy_price()
            )
            updated_name: str = sec_info.get_name()
            updated_symbol: str = sec_info.get_symbol()
            updated_price: float = sec_info.get_price()
            updated_dividends: float = div_info.get_amount()

            # Update the state for this security
            ac: AssetClass = self.get_asset_class_for_security(sec_id)
            if not ac.contains_security(sec_id):
                ac.add_security(Security(sec_id))
            ac.update_security(
                sec_id, updated_symbol, updated_name, updated_price
            )
            ac.update_holding(
                sec_id,
                updated_shares,
                updated_average_buy_price,
                updated_dividends,
            )
Пример #22
0
 def test_add_security_not_exists(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     ac.add_security(Security("sec", "SEC"))
     self.assertEqual(ac.get_security("sec"), Security("sec", "SEC"))
Пример #23
0
 def test_contains_holding_true(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec = Security("sec", "SEC", price=30.0)
     ac.add_security(sec)
     ac.buy(sec, 1, False)
     self.assertTrue(ac.contains_holding("sec"))
Пример #24
0
 def test_inequality(self) -> None:
     ac1: AssetClass = AssetClass("ac", target_percentage=1.0)
     ac2: AssetClass = AssetClass("ac", target_percentage=1.0)
     ac2.add_security(Security("sec", "SEC"))
     self.assertNotEqual(ac1, ac2)
Пример #25
0
 def test_get_return_zero(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", "sec_name", 15.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     self.assertEqual(ac.get_return(), 0.0)
Пример #26
0
 def test_get_holding_not_exists(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", "sec_name", 15.0)
     ac.add_security(sec)
     self.assertRaises(Exception, ac.get_holding, "sec")
Пример #27
0
 def test_get_holding_exists(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC", "sec_name", 15.0)
     ac.add_security(sec)
     ac.buy(sec, 3, False)
     self.assertEqual(ac.get_holding("sec"), Holding(sec, 3, 15.0))
Пример #28
0
 def test_get_security_exists(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec", "SEC")
     ac.add_security(sec)
     self.assertEqual(ac.get_security("sec"), sec)
Пример #29
0
 def test_get_purchase_buffer_update(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec1", "SEC1", "sec1_name", 50.0, 0)
     ac.add_security(sec)
     sec.set_price(100.0)
     self.assertTrue(abs(ac.get_purchase_buffer() - 15.0) < 10e-10)
Пример #30
0
 def test_get_purchase_buffer_new(self):
     ac: AssetClass = AssetClass("ac", target_percentage=1.0)
     sec: Security = Security("sec1", "SEC1", price=50.0)
     ac.add_security(sec)
     self.assertTrue(abs(ac.get_purchase_buffer() - 7.5) < 10e-10)