Beispiel #1
0
    def setUp(self):
        """ Builds stock variables to test with. """
        self.initial_year = 2000
        # Simple tax treatment: 50% tax rate across the board.
        tax = Tax(tax_brackets={
            self.initial_year: {0: 0.5}})
        # Accounts need an owner:
        timing = Timing(frequency='BW')
        self.person = Person(
            initial_year=self.initial_year,
            name="Test",
            birth_date="1 January 1980",
            retirement_date="31 December 1999",  # last year
            gross_income=5200,
            tax_treatment=tax,
            payment_timing=timing)
        # We want at least two accounts which are withdrawn from
        # in different orders depending on the strategy.
        self.account = Account(
            owner=self.person,
            balance=60000)  # $60,000 <- BIGGER!
        self.rrsp = canada.accounts.RRSP(
            owner=self.person,
            contribution_room=1000,
            balance=6000)  # $6,000

        # Assume there are $2000 in inflows and $22,000 in outflows,
        # for a net need of $20,000:
        self.available = {
            0.25: 1000,
            0.5: -11000,
            0.75: 1000,
            1: -11000
        }

        # Now we can set up the big-ticket items:
        self.strategy = TransactionStrategy(
            strategy=TransactionStrategy.strategy_ordered,
            weights={"RRSP": 1, "Account": 2})
        self.forecast = WithdrawalForecast(
            initial_year=self.initial_year,
            people={self.person},
            accounts={self.account, self.rrsp},
            transaction_strategy=self.strategy)

        # Set up another forecast for testing withholding behaviour:
        self.withholding_account = WithholdingAccount(
            owner=self.person,
            balance=100000)
        self.withholding_strategy = TransactionStrategy(
            strategy=TransactionStrategy.strategy_ordered,
            weights={"WithholdingAccount": 1})
        self.withholding_forecast = WithdrawalForecast(
            initial_year=self.initial_year,
            people={self.person},
            accounts={self.withholding_account},
            transaction_strategy=self.withholding_strategy)
Beispiel #2
0
    def setUp(self):
        """ Sets up variables for testing. """
        # Different groups of tests use different groups of variables.
        # We could split this class up into multiple classes (perhaps
        # one for ordered strategies and one for weighted strategies?),
        # but for now this project's practice is one test case for each
        # custom class.
        # pylint: disable=too-many-instance-attributes

        initial_year = 2000
        person = Person(
            initial_year, 'Testy McTesterson', 1980, retirement_date=2045)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(
            person,
            balance=Money(200), rate=0, contribution_room=Money(200))
        self.tfsa = TFSA(
            person,
            balance=Money(100), rate=0, contribution_room=Money(100))
        self.taxable_account = TaxableAccount(
            person, balance=Money(1000), rate=0)
        self.accounts = {self.rrsp, self.tfsa, self.taxable_account}

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): 1}

        # Build strategy for testing (in non-init tests):
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_ordered, {
                'RRSP': 1,
                'TFSA': 2,
                'TaxableAccount': 3
            })
Beispiel #3
0
    def setUp(self):
        """ Sets up variables for testing. """
        # Vars for building accounts:
        initial_year = 2000
        person = Person(
            initial_year, 'Testy McTesterson', 1980, retirement_date=2045)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(
            person,
            balance=Money(200), rate=0, contribution_room=Money(200))
        self.rrsp2 = RRSP(person, balance=Money(100), rate=0)
        self.tfsa = TFSA(
            person,
            balance=Money(100), rate=0, contribution_room=Money(100))
        self.taxable_account = TaxableAccount(
            person, balance=Money(1000), rate=0)
        self.accounts = {
            self.rrsp, self.rrsp2, self.tfsa, self.taxable_account
        }

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): 1}

        # Build strategy for testing (in non-init tests):
        self.weights = {
            'RRSP': Decimal('0.4'),
            'TFSA': Decimal('0.3'),
            'TaxableAccount': Decimal('0.3')
        }
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_weighted, self.weights)
Beispiel #4
0
    def setUp(self):
        """ Sets up variables for testing. """

        # Vars for building accounts:
        initial_year = 2000
        person = Person(initial_year,
                        'Testy McTesterson',
                        1980,
                        retirement_date=2045)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(person, balance=200, rate=0, contribution_room=200)
        self.tfsa = TFSA(person, balance=100, rate=0, contribution_room=100)
        self.taxable_account = TaxableAccount(person, balance=1000, rate=0)
        self.accounts = {self.rrsp, self.tfsa, self.taxable_account}

        # Define a simple timing for transactions:
        self.timing = {0.5: 1}

        self.max_outflow = sum(
            sum(account.max_outflows(timing=self.timing).values())
            for account in self.accounts)
        self.max_inflows = sum(
            sum(account.max_inflows(timing=self.timing).values())
            for account in self.accounts)

        # Build strategy for testing (in non-init tests):
        self.weights = {'RRSP': 0.4, 'TFSA': 0.3, 'TaxableAccount': 0.3}
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_weighted, self.weights)
Beispiel #5
0
    def setUp_decimal(self):
        """ Sets up variables for testing. """
        # pylint: disable=invalid-name
        # Pylint doesn't like `setUp_decimal`, but it's not our naming
        # convention, so don't complain to us!
        # pylint: enable=invalid-name
        initial_year = 2000
        person = Person(initial_year,
                        'Testy McTesterson',
                        1980,
                        retirement_date=2045,
                        high_precision=Decimal)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(person,
                         balance=Decimal(200),
                         rate=Decimal(0),
                         contribution_room=Decimal(200),
                         high_precision=Decimal)
        self.rrsp2 = RRSP(person,
                          balance=Decimal(100),
                          rate=Decimal(0),
                          high_precision=Decimal)
        self.tfsa = TFSA(person,
                         balance=Decimal(100),
                         rate=Decimal(0),
                         contribution_room=Decimal(100),
                         high_precision=Decimal)
        self.taxable_account = TaxableAccount(person,
                                              balance=Decimal(1000),
                                              rate=Decimal(0),
                                              high_precision=Decimal)
        self.accounts = {
            self.rrsp, self.rrsp2, self.tfsa, self.taxable_account
        }

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): Decimal(1)}

        self.max_outflow = sum(
            sum(account.max_outflows(timing=self.timing).values())
            for account in self.accounts)
        self.max_inflows = sum(
            sum(account.max_inflows(timing=self.timing).values())
            for account in self.accounts)

        # Build strategies for testing (in non-init tests):
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_ordered, {
                'RRSP': Decimal(1),
                'TFSA': Decimal(2),
                'TaxableAccount': Decimal(3)
            },
            high_precision=Decimal)
Beispiel #6
0
 def test_account_trans_weighted(self):
     """ Test account transactions under weighted strategy. """
     # Set up forecast:
     self.forecast.transaction_strategy = TransactionStrategy(
         strategy=TransactionStrategy.strategy_weighted,
         weights={"RRSP": 3000, "Account": 17000})
     self.forecast(self.available)
     # We are withdrawing $20,000. We'll withdraw $3000 from
     # `rrsp`, with the rest from `account`:
     self.assertTransactions(
         self.forecast.account_transactions[self.rrsp], -3000)
     self.assertTransactions(
         self.forecast.account_transactions[self.account], -17000)
Beispiel #7
0
 def test_account_trans_ordered(self):
     """ Test account transactions under ordered strategy. """
     # Set up forecast:
     self.forecast.transaction_strategy = TransactionStrategy(
         strategy=TransactionStrategy.strategy_ordered,
         weights={"RRSP": 1, "Account": 2})
     self.forecast(self.available)
     # We are withdrawing $20,000. We'll withdraw the whole balance
     # of `rrsp` ($6000), with the rest from `account`:
     self.assertTransactions(
         self.forecast.account_transactions[self.rrsp], -6000)
     self.assertTransactions(
         self.forecast.account_transactions[self.account], -14000)
Beispiel #8
0
    def setUp_decimal(self):
        """ Sets up variables based on Decimal inputs. """
        # pylint: disable=invalid-name
        # Pylint doesn't like `setUp_decimal`, but it's not our naming
        # convention, so don't complain to us!
        # pylint: enable=invalid-name

        # Vars for building accounts:
        initial_year = 2000
        person = Person(initial_year,
                        'Testy McTesterson',
                        1980,
                        retirement_date=2045,
                        high_precision=Decimal)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(person,
                         balance=Decimal(200),
                         rate=Decimal(0),
                         contribution_room=Decimal(200),
                         high_precision=Decimal)
        self.rrsp2 = RRSP(person,
                          balance=Decimal(100),
                          rate=Decimal(0),
                          high_precision=Decimal)
        self.tfsa = TFSA(person,
                         balance=Decimal(100),
                         rate=Decimal(0),
                         contribution_room=Decimal(100),
                         high_precision=Decimal)
        self.taxable_account = TaxableAccount(person,
                                              balance=Decimal(1000),
                                              rate=Decimal(0),
                                              high_precision=Decimal)
        self.accounts = {
            self.rrsp, self.rrsp2, self.tfsa, self.taxable_account
        }

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): Decimal(1)}

        # Build strategy for testing (in non-init tests):
        self.weights = {
            'RRSP': Decimal(0.4),
            'TFSA': Decimal(0.3),
            'TaxableAccount': Decimal(0.3)
        }
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_weighted,
            self.weights,
            high_precision=Decimal)
Beispiel #9
0
    def setUp_decimal(self):
        """ Sets up variables based on Decimal inputs. """
        # pylint: disable=invalid-name
        # Pylint doesn't like `setUp_decimal`, but it's not our naming
        # convention, so don't complain to us!
        # pylint: enable=invalid-name

        # Different groups of tests use different groups of variables.
        # We could split this class up into multiple classes (perhaps
        # one for ordered strategies and one for weighted strategies?),
        # but for now this project's practice is one test case for each
        # custom class.
        # pylint: disable=too-many-instance-attributes

        initial_year = 2000
        person = Person(initial_year,
                        'Testy McTesterson',
                        1980,
                        retirement_date=2045,
                        high_precision=Decimal)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(person,
                         balance=Decimal(200),
                         rate=Decimal(0),
                         contribution_room=Decimal(200),
                         high_precision=Decimal)
        self.tfsa = TFSA(person,
                         balance=Decimal(100),
                         rate=Decimal(0),
                         contribution_room=Decimal(100),
                         high_precision=Decimal)
        self.taxable_account = TaxableAccount(person,
                                              balance=Decimal(1000),
                                              rate=Decimal(0),
                                              high_precision=Decimal)
        self.accounts = {self.rrsp, self.tfsa, self.taxable_account}

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): Decimal(1)}

        # Build strategy for testing (in non-init tests):
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_ordered, {
                'RRSP': 1,
                'TFSA': 2,
                'TaxableAccount': 3
            },
            high_precision=Decimal)
Beispiel #10
0
    def setUp(self):
        """ Sets up variables for testing. """
        initial_year = 2000
        person = Person(
            initial_year, 'Testy McTesterson', 1980, retirement_date=2045)

        # Set up some accounts for the tests.
        self.rrsp = RRSP(
            person,
            balance=Money(200), rate=0, contribution_room=Money(200))
        self.rrsp2 = RRSP(person, balance=Money(100), rate=0)
        self.tfsa = TFSA(
            person,
            balance=Money(100), rate=0, contribution_room=Money(100))
        self.taxable_account = TaxableAccount(
            person, balance=Money(1000), rate=0)
        self.accounts = {
            self.rrsp, self.rrsp2, self.tfsa, self.taxable_account
        }

        # Define a simple timing for transactions:
        self.timing = {Decimal(0.5): 1}

        self.max_outflow = sum(
            sum(account.max_outflows(timing=self.timing).values())
            for account in self.accounts)
        self.max_inflows = sum(
            sum(account.max_inflows(timing=self.timing).values())
            for account in self.accounts)

        # Build strategies for testing (in non-init tests):
        self.strategy = TransactionStrategy(
            TransactionStrategy.strategy_ordered, {
                'RRSP': 1,
                'TFSA': 2,
                'TaxableAccount': 3
            })
Beispiel #11
0
    def setUp_decimal(self):
        """ Builds stock variables to test with. """
        # pylint: disable=invalid-name
        # Pylint doesn't like `setUp_decimal`, but it's not our naming
        # convention, so don't complain to us!
        # pylint: enable=invalid-name

        self.initial_year = 2000
        # Simple tax treatment: 50% tax rate across the board.
        tax = Tax(tax_brackets={
            self.initial_year: {Decimal(0): Decimal(0.5)}},
            high_precision=Decimal)
        # Accounts need an owner:
        timing = Timing(frequency='BW',high_precision=Decimal)
        self.person = Person(
            initial_year=self.initial_year,
            name="Test",
            birth_date="1 January 1980",
            retirement_date="31 December 1999",  # last year
            gross_income=Decimal(5200),
            tax_treatment=tax,
            payment_timing=timing,
            high_precision=Decimal)
        # We want at least two accounts which are withdrawn from
        # in different orders depending on the strategy.
        self.account = Account(
            owner=self.person,
            balance=Decimal(60000),  # $60,000 <- BIGGER!
            high_precision=Decimal)
        self.rrsp = canada.accounts.RRSP(
            owner=self.person,
            contribution_room=Decimal(1000),
            balance=Decimal(6000),  # $6,000
            high_precision=Decimal)

        # Assume there are $2000 in inflows and $22,000 in outflows,
        # for a net need of $20,000:
        self.available = {
            Decimal(0.25): Decimal(1000),
            Decimal(0.5): Decimal(-11000),
            Decimal(0.75): Decimal(1000),
            Decimal(1): Decimal(-11000)
        }

        # Now we can set up the big-ticket items:
        self.strategy = TransactionStrategy(
            strategy=TransactionStrategy.strategy_ordered,
            weights={"RRSP": Decimal(1), "Account": Decimal(2)})
        self.forecast = WithdrawalForecast(
            initial_year=self.initial_year,
            people={self.person},
            accounts={self.account, self.rrsp},
            transaction_strategy=self.strategy,
            high_precision=Decimal)

        # Set up another forecast for testing withholding behaviour:
        self.withholding_account = WithholdingAccount(
            owner=self.person,
            balance=Decimal(100000),
            high_precision=Decimal)
        self.withholding_strategy = TransactionStrategy(
            strategy=TransactionStrategy.strategy_ordered,
            weights={"WithholdingAccount": Decimal(1)},
            high_precision=Decimal)
        self.withholding_forecast = WithdrawalForecast(
            initial_year=self.initial_year,
            people={self.person},
            accounts={self.withholding_account},
            transaction_strategy=self.withholding_strategy,
            high_precision=Decimal)
    def setUp_decimal(self):
        """ Builds default strategies/persons/etc. with Decimal inputs. """
        # pylint: disable=invalid-name
        # This name is based on `setUp`, which doesn't follow Pylint's rules
        # pylint: enable=invalid-name

        # Use a default settings object:
        # (This is conditional so that subclasses can assign their own
        # settings object before calling super().setUp())
        if not hasattr(self, 'settings'):
            self.settings = Settings()

        # To simplify tests, modify Settings so that forecasts are
        # just 2 years with easy-to-predict contributions ($1000/yr)
        self.settings.num_years = 2
        self.settings.living_expenses_strategy = (
            LivingExpensesStrategy.strategy_const_contribution)
        self.settings.living_expenses_base_amount = Decimal(1000)

        # Allow subclasses to use subclasses of Forecaster by assigning
        # to forecaster_type
        if not hasattr(self, 'forecaster_type'):
            self.forecaster_type = Forecaster

        # Build default `SubForecast` inputs based on `settings`:
        self.initial_year = self.settings.initial_year
        self.scenario = Scenario(
            inflation=Decimal(self.settings.inflation),
            stock_return=Decimal(self.settings.stock_return),
            bond_return=Decimal(self.settings.bond_return),
            other_return=Decimal(self.settings.other_return),
            management_fees=Decimal(self.settings.management_fees),
            initial_year=self.settings.initial_year,
            num_years=self.settings.num_years)
        self.living_expenses_strategy = LivingExpensesStrategy(
            strategy=self.settings.living_expenses_strategy,
            base_amount=Decimal(self.settings.living_expenses_base_amount),
            rate=Decimal(self.settings.living_expenses_rate),
            inflation_adjust=self.scenario.inflation_adjust)
        self.saving_strategy = TransactionStrategy(
            strategy=self.settings.saving_strategy,
            weights={
                year: Decimal(val)
                for (year, val) in self.settings.saving_weights.items()
            })
        self.withdrawal_strategy = TransactionStrategy(
            strategy=self.settings.withdrawal_strategy,
            weights={
                year: Decimal(val)
                for (year, val) in self.settings.withdrawal_weights.items()
            })
        self.allocation_strategy = AllocationStrategy(
            strategy=self.settings.allocation_strategy,
            min_equity=Decimal(self.settings.allocation_min_equity),
            max_equity=Decimal(self.settings.allocation_max_equity),
            target=Decimal(self.settings.allocation_target),
            standard_retirement_age=(
                self.settings.allocation_std_retirement_age),
            risk_transition_period=self.settings.allocation_risk_trans_period,
            adjust_for_retirement_plan=(
                self.settings.allocation_adjust_retirement))
        self.debt_payment_strategy = DebtPaymentStrategy(
            strategy=self.settings.debt_payment_strategy,
            high_precision=Decimal)
        self.tax_treatment = Tax(
            tax_brackets={
                year: {
                    Decimal(lower): Decimal(upper)
                }
                for (year, vals) in self.settings.tax_brackets.items()
                for (lower, upper) in vals.items()
            },
            personal_deduction={
                year: Decimal(val)
                for (year,
                     val) in self.settings.tax_personal_deduction.items()
            },
            credit_rate={
                year: Decimal(val)
                for (year, val) in self.settings.tax_credit_rate.items()
            },
            inflation_adjust=self.scenario.inflation_adjust,
            high_precision=Decimal)

        # Now build some Ledger objects to test against:
        # A person making $10,000/yr
        self.person = Person(initial_year=self.initial_year,
                             name="Test 1",
                             birth_date="1 January 1980",
                             retirement_date="31 December 2040",
                             gross_income=Decimal(10000),
                             raise_rate=Decimal(0),
                             spouse=None,
                             tax_treatment=self.tax_treatment,
                             high_precision=Decimal)
        # An account with $1000 in it (and no interest)
        self.account = Account(owner=self.person,
                               balance=Decimal(1000),
                               high_precision=Decimal)
        # A debt with a $100 balance (and no interest)
        self.debt = Debt(owner=self.person,
                         balance=Decimal(100),
                         high_precision=Decimal)

        # Init a Forecaster object here for convenience:
        self.forecaster = self.forecaster_type(settings=self.settings,
                                               high_precision=Decimal)
    def setUp(self):
        """ Builds default strategies, persons, etc. """
        # Use a default settings object:
        # (This is conditional so that subclasses can assign their own
        # settings object before calling super().setUp())
        if not hasattr(self, 'settings'):
            self.settings = Settings()

        # To simplify tests, modify Settings so that forecasts are
        # just 2 years with easy-to-predict contributions ($1000/yr)
        self.settings.num_years = 2
        self.settings.living_expenses_strategy = (
            LivingExpensesStrategy.strategy_const_contribution)
        self.settings.living_expenses_base_amount = 1000

        # Allow subclasses to use subclasses of Forecaster by assigning
        # to forecaster_type
        if not hasattr(self, 'forecaster_type'):
            self.forecaster_type = Forecaster

        # Build default `SubForecast` inputs based on `settings`:
        self.initial_year = self.settings.initial_year
        self.scenario = Scenario(inflation=self.settings.inflation,
                                 stock_return=self.settings.stock_return,
                                 bond_return=self.settings.bond_return,
                                 other_return=self.settings.other_return,
                                 management_fees=self.settings.management_fees,
                                 initial_year=self.settings.initial_year,
                                 num_years=self.settings.num_years)
        self.living_expenses_strategy = LivingExpensesStrategy(
            strategy=self.settings.living_expenses_strategy,
            base_amount=self.settings.living_expenses_base_amount,
            rate=self.settings.living_expenses_rate,
            inflation_adjust=self.scenario.inflation_adjust)
        self.saving_strategy = TransactionStrategy(
            strategy=self.settings.saving_strategy,
            weights=self.settings.saving_weights)
        self.withdrawal_strategy = TransactionStrategy(
            strategy=self.settings.withdrawal_strategy,
            weights=self.settings.withdrawal_weights)
        self.allocation_strategy = AllocationStrategy(
            strategy=self.settings.allocation_strategy,
            min_equity=self.settings.allocation_min_equity,
            max_equity=self.settings.allocation_max_equity,
            target=self.settings.allocation_target,
            standard_retirement_age=(
                self.settings.allocation_std_retirement_age),
            risk_transition_period=self.settings.allocation_risk_trans_period,
            adjust_for_retirement_plan=(
                self.settings.allocation_adjust_retirement))
        self.debt_payment_strategy = DebtPaymentStrategy(
            strategy=self.settings.debt_payment_strategy)
        self.tax_treatment = Tax(
            tax_brackets=self.settings.tax_brackets,
            personal_deduction=self.settings.tax_personal_deduction,
            credit_rate=self.settings.tax_credit_rate,
            inflation_adjust=self.scenario.inflation_adjust)

        # Now build some Ledger objects to test against:
        # A person making $10,000/yr
        self.person = Person(initial_year=self.initial_year,
                             name="Test 1",
                             birth_date="1 January 1980",
                             retirement_date="31 December 2040",
                             gross_income=10000,
                             raise_rate=0,
                             spouse=None,
                             tax_treatment=self.tax_treatment)
        # An account with $1000 in it (and no interest)
        self.account = Account(owner=self.person, balance=1000)
        # A debt with a $100 balance (and no interest)
        self.debt = Debt(owner=self.person, balance=100)

        # Init a Forecaster object here for convenience:
        self.forecaster = self.forecaster_type(settings=self.settings)