Пример #1
0
 def testChainedWithdrawForcedWithdrawPreferZero(self):
   year_rec = utils.YearRecord()
   year_rec.age = 94
   year_rec.growth_rate=0
   rrsp = funds.RRSP()
   rrsp.amount = 50
   rrsp.Update(year_rec)
   tfsa = funds.TFSA()
   tfsa.amount = 50
   nonreg = funds.NonRegistered()
   nonreg.amount = 30
   nonreg.unrealized_gains = 15
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (0, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(60, fund_chain,
                                                      proportions,
                                                      utils.YearRecord())
   self.assertEqual(withdrawn, 60)
   self.assertEqual(gains, 12.5)
   self.assertSequenceEqual(
       year_rec.withdrawals, 
       [funds.WithdrawReceipt(10, 0, funds.FUND_TYPE_RRSP),
        funds.WithdrawReceipt(25, 0, funds.FUND_TYPE_TFSA),
        funds.WithdrawReceipt(25, 12.5, funds.FUND_TYPE_NONREG)])
   self.assertEqual(rrsp.amount, 40)
   self.assertEqual(tfsa.amount, 25)
   self.assertEqual(nonreg.amount, 5)
Пример #2
0
 def testChainedWithdrawForcedWithdrawProportionalDeposit(self):
   year_rec = utils.YearRecord()
   rrsp = funds.RRSP()
   rrsp.amount = 100
   rrsp.forced_withdraw = 80
   tfsa = funds.TFSA()
   tfsa.amount = 50
   year_rec.tfsa_room = 50
   nonreg = funds.NonRegistered()
   nonreg.amount = 50
   nonreg.unrealized_gains = 25
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (0.1, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(60, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertEqual(withdrawn, 60)
   self.assertEqual(gains, 0)
   self.assertSequenceEqual(
       year_rec.withdrawals, 
       [funds.WithdrawReceipt(80, 0, funds.FUND_TYPE_RRSP)])
   self.assertSequenceEqual(
       year_rec.deposits,
       [funds.DepositReceipt(10, funds.FUND_TYPE_TFSA),
        funds.DepositReceipt(10, funds.FUND_TYPE_NONREG)])
   self.assertEqual(rrsp.amount, 20)
   self.assertEqual(tfsa.amount, 60)
   self.assertEqual(nonreg.amount, 60)
Пример #3
0
 def testChainedWithdrawRealScenario(self):
   year_rec, tfsa, rrsp, _, nonreg = _SetUpChain(
       rrsp_amount=248968, tfsa_amount=304691, nonreg_amount=39)
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (0.35, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(16603, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertAlmostEqual(withdrawn, 16603)
Пример #4
0
    def OnRetirement(self, year_rec):
        """This deals with events happening at the point of retirement."""

        # Update all incomes
        for income in self.incomes:
            income.OnRetirement(self)

        # Create RRSP bridging fund if needed
        if self.age < world.CPP_EXPECTED_RETIREMENT_AGE:
            requested = (
                world.CPP_EXPECTED_RETIREMENT_AGE - self.age
            ) * world.OAS_BENEFIT * self.strategy.oas_bridging_fraction
            self.funds["wp_rrsp"], self.funds["bridging"] = funds.SplitFund(
                self.funds["wp_rrsp"], funds.RRSPBridging(), requested)
            if self.funds["bridging"].amount < requested:
                top_up_amount = min(self.rrsp_room,
                                    requested - self.funds["bridging"].amount)
                fund_chain = [self.funds["wp_nonreg"], self.funds["wp_tfsa"]]
                withdrawn, _, year_rec = funds.ChainedWithdraw(
                    top_up_amount, fund_chain, (1, 1), year_rec)
                self.funds["bridging"].amount += withdrawn
                year_rec.deposits.append(
                    funds.DepositReceipt(withdrawn, funds.FUND_TYPE_RRSP))
                self.rrsp_room -= withdrawn

            self.bridging_annual_withdrawal = self.funds["bridging"].amount / (
                world.CPP_EXPECTED_RETIREMENT_AGE - self.age)

        # Split each fund into a CED and a CD fund
        self.funds["cd_rrsp"], self.funds["ced_rrsp"] = funds.SplitFund(
            self.funds["wp_rrsp"], funds.RRSP(),
            self.strategy.drawdown_ced_fraction * self.funds["wp_rrsp"].amount)
        del self.funds["wp_rrsp"]

        self.funds["cd_tfsa"], self.funds["ced_tfsa"] = funds.SplitFund(
            self.funds["wp_tfsa"], funds.TFSA(),
            self.strategy.drawdown_ced_fraction * self.funds["wp_tfsa"].amount)
        del self.funds["wp_tfsa"]

        self.funds["cd_nonreg"], self.funds["ced_nonreg"] = funds.SplitFund(
            self.funds["wp_nonreg"], funds.NonRegistered(),
            self.strategy.drawdown_ced_fraction *
            self.funds["wp_nonreg"].amount)
        del self.funds["wp_nonreg"]

        self.cd_drawdown_amount = sum(fund.amount for fund in (
            self.funds["cd_rrsp"], self.funds["cd_tfsa"],
            self.funds["cd_nonreg"])) * self.strategy.initial_cd_fraction

        self.assets_at_retirement = sum(
            fund.amount for fund in self.funds.values()) / year_rec.cpi

        if not self.basic_only:
            self.accumulators.fraction_persons_involuntarily_retired.UpdateOneValue(
                1 if self.age < self.strategy.planned_retirement_age else 0)
Пример #5
0
 def testChainedWithdrawTwoZeroFunds(self):
   year_rec, tfsa, rrsp, _, nonreg = _SetUpChain(
       rrsp_amount=0, tfsa_amount=0, nonreg_amount=80)
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (1/3, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(60, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertAlmostEqual(withdrawn, 60)
   self.assertAlmostEqual(rrsp.amount, 0)
   self.assertAlmostEqual(tfsa.amount, 0)
   self.assertAlmostEqual(nonreg.amount, 20)
Пример #6
0
 def testChainedWithdrawPartialInsufficientFundsOneAdjustment(self):
   year_rec, tfsa, rrsp, _, nonreg = _SetUpChain(
       rrsp_amount=30, tfsa_amount=16, nonreg_amount=40)
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (1/3, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(60, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertAlmostEqual(withdrawn, 60)
   self.assertAlmostEqual(rrsp.amount, 8)
   self.assertAlmostEqual(tfsa.amount, 0)
   self.assertAlmostEqual(nonreg.amount, 18)
Пример #7
0
 def testChainedWithdrawInsufficientFunds(self):
   year_rec, tfsa, rrsp, _, nonreg = _SetUpChain(
       rrsp_amount=20, tfsa_amount=50, nonreg_amount=20)
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (0.1, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(160, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertAlmostEqual(withdrawn, 90)
   self.assertAlmostEqual(rrsp.amount, 0)
   self.assertAlmostEqual(tfsa.amount, 0)
   self.assertAlmostEqual(nonreg.amount, 0)
Пример #8
0
 def testChainedWithdrawSufficientFunds(self):
   year_rec, tfsa, rrsp, _, nonreg = _SetUpChain(
       rrsp_amount=20, tfsa_amount=50, nonreg_amount=30, nonreg_gains=15)
   fund_chain = (rrsp, tfsa, nonreg)
   proportions = (0.1, 0.5, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(60, fund_chain,
                                                      proportions,
                                                      year_rec)
   self.assertAlmostEqual(withdrawn, 60)
   self.assertAlmostEqual(gains, 13.5)
   self.assertAlmostEqual(rrsp.amount, 14)
   self.assertAlmostEqual(tfsa.amount, 23)
   self.assertAlmostEqual(nonreg.amount, 3)
   self.assertAlmostEqual(nonreg.unrealized_gains, 1.5)
Пример #9
0
 def testChainedWithdrawForcedWithdrawWantZero(self):
   rrsp = funds.RRSP()
   rrsp.amount = 100
   rrsp.forced_withdraw = 20
   nonreg = funds.NonRegistered()
   fund_chain = (rrsp, nonreg)
   proportions = (0, 1)
   withdrawn, gains, year_rec = funds.ChainedWithdraw(0, fund_chain,
                                                      proportions,
                                                      utils.YearRecord())
   self.assertEqual(withdrawn, 0)
   self.assertEqual(gains, 0)
   self.assertSequenceEqual(
       year_rec.withdrawals,
       [funds.WithdrawReceipt(20, 0, funds.FUND_TYPE_RRSP)])
   self.assertSequenceEqual(
       year_rec.deposits, [funds.DepositReceipt(20, funds.FUND_TYPE_NONREG)])
   self.assertEqual(rrsp.amount, 80)
   self.assertEqual(nonreg.amount, 20)
Пример #10
0
 def testChainedWithdrawForcedWithdrawOverflow(self):
     rrsp = funds.RRSP()
     rrsp.amount = 100
     rrsp.forced_withdraw = 80
     tfsa = funds.TFSA()
     tfsa.amount = 50
     tfsa.room = 0
     fund_chain = (rrsp, tfsa)
     proportions = (0.5, 1)
     withdrawn, gains, year_rec = funds.ChainedWithdraw(
         60, fund_chain, proportions, utils.YearRecord())
     self.assertEqual(withdrawn, 80)
     self.assertEqual(gains, 0)
     self.assertSequenceEqual(
         year_rec.withdrawals,
         [funds.WithdrawReceipt(80, 0, funds.FUND_TYPE_RRSP)])
     self.assertSequenceEqual(
         year_rec.deposits, [funds.DepositReceipt(0, funds.FUND_TYPE_TFSA)])
     self.assertEqual(rrsp.amount, 20)
     self.assertEqual(tfsa.amount, 50)
Пример #11
0
 def testChainedWithdrawPartialInsufficientFunds(self):
     rrsp = funds.RRSP()
     rrsp.amount = 20
     tfsa = funds.TFSA()
     tfsa.amount = 20
     nonreg = funds.NonRegistered()
     nonreg.amount = 40
     nonreg.unrealized_gains = 20
     fund_chain = (rrsp, tfsa, nonreg)
     proportions = (0.1, 0.5, 1)
     withdrawn, gains, year_rec = funds.ChainedWithdraw(
         60, fund_chain, proportions, utils.YearRecord())
     self.assertEqual(withdrawn, 60)
     self.assertEqual(gains, 17)
     self.assertSequenceEqual(year_rec.withdrawals, [
         funds.WithdrawReceipt(6, 0, funds.FUND_TYPE_RRSP),
         funds.WithdrawReceipt(20, 0, funds.FUND_TYPE_TFSA),
         funds.WithdrawReceipt(34, 17, funds.FUND_TYPE_NONREG)
     ])
     self.assertEqual(rrsp.amount, 14)
     self.assertEqual(tfsa.amount, 0)
     self.assertEqual(nonreg.amount, 6)
Пример #12
0
 def testChainedWithdrawInsufficientFunds(self):
     # TODO check if this is correct behaviour, or if we need more complicated
     # logic for insufficient funds at the end of the chain
     rrsp = funds.RRSP()
     rrsp.amount = 20
     tfsa = funds.TFSA()
     tfsa.amount = 50
     nonreg = funds.NonRegistered()
     nonreg.amount = 20
     nonreg.unrealized_gains = 10
     fund_chain = (rrsp, tfsa, nonreg)
     proportions = (0.1, 0.5, 1)
     withdrawn, gains, year_rec = funds.ChainedWithdraw(
         60, fund_chain, proportions, utils.YearRecord())
     self.assertEqual(withdrawn, 53)
     self.assertEqual(gains, 10)
     self.assertSequenceEqual(year_rec.withdrawals, [
         funds.WithdrawReceipt(6, 0, funds.FUND_TYPE_RRSP),
         funds.WithdrawReceipt(27, 0, funds.FUND_TYPE_TFSA),
         funds.WithdrawReceipt(20, 10, funds.FUND_TYPE_NONREG)
     ])
     self.assertEqual(rrsp.amount, 14)
     self.assertEqual(tfsa.amount, 23)
     self.assertEqual(nonreg.amount, 0)
Пример #13
0
    def MeddleWithCash(self, year_rec):
        """This performs all operations on subject's cash pile"""
        cash = 0

        # Get money from incomes. GIS is excluded and done after withdrawals
        for income in self.incomes[:-1]:
            amount, taxable, year_rec = income.GiveMeMoney(year_rec)
            cash += amount

        # Update RRSP room
        earnings = sum(receipt.amount for receipt in year_rec.incomes
                       if receipt.income_type == incomes.INCOME_TYPE_EARNINGS)
        self.rrsp_room += min(
            earnings * world.RRSP_ACCRUAL_FRACTION,
            utils.Indexed(world.RRSP_LIMIT, year_rec.year, 1 + world.PARGE) *
            year_rec.cpi)
        year_rec.rrsp_room = self.rrsp_room

        # Do withdrawals
        if self.retired:
            # Bridging
            if "bridging" in self.funds and self.age < world.CPP_EXPECTED_RETIREMENT_AGE:
                bridging_withdrawal_amount = self.bridging_withdrawal_table[
                    self.age] * self.funds["bridging"].amount
                withdrawn, gains, year_rec = self.funds["bridging"].Withdraw(
                    bridging_withdrawal_amount, year_rec)
                cash += withdrawn
                self.total_retirement_withdrawals += withdrawn / year_rec.cpi

            # CD drawdown strategy
            proportions = (self.strategy.drawdown_preferred_rrsp_fraction,
                           self.strategy.drawdown_preferred_tfsa_fraction, 1)
            fund_chain = [
                self.funds["cd_rrsp"], self.funds["cd_tfsa"],
                self.funds["cd_nonreg"]
            ]
            year_rec.cd_drawdown_request = self.cd_drawdown_amount * year_rec.cpi
            withdrawn, gains, year_rec = funds.ChainedWithdraw(
                year_rec.cd_drawdown_request, fund_chain, proportions,
                year_rec)
            cash += withdrawn
            year_rec.cd_drawdown_amount = withdrawn
            self.total_retirement_withdrawals += withdrawn / year_rec.cpi

            # CED drawdown_strategy
            fund_chain = [
                self.funds["ced_rrsp"], self.funds["ced_tfsa"],
                self.funds["ced_nonreg"]
            ]
            year_rec.ced_drawdown_request = sum(
                f.amount for f in fund_chain) * world.CED_PROPORTION[self.age]
            withdrawn, gains, year_rec = funds.ChainedWithdraw(
                year_rec.ced_drawdown_request, fund_chain, proportions,
                year_rec)
            cash += withdrawn
            year_rec.ced_drawdown_amount = withdrawn
            self.total_retirement_withdrawals += withdrawn / year_rec.cpi
        else:
            target_cash = utils.Indexed(
                world.YMPE, year_rec.year, 1 + world.PARGE
            ) * year_rec.cpi * self.strategy.savings_threshold * world.EARNINGS_YMPE_FRACTION
            if cash < target_cash:
                # Attempt to withdraw difference from savings
                amount_to_withdraw = target_cash - cash
                proportions = (
                    self.strategy.working_period_drawdown_tfsa_fraction,
                    self.strategy.working_period_drawdown_nonreg_fraction, 1)
                fund_chain = [
                    self.funds["wp_tfsa"], self.funds["wp_nonreg"],
                    self.funds["wp_rrsp"]
                ]
                withdrawn, gains, year_rec = funds.ChainedWithdraw(
                    amount_to_withdraw, fund_chain, proportions, year_rec)
                cash += withdrawn
            else:
                # Save
                earnings_to_save = max(earnings - target_cash,
                                       0) * self.strategy.savings_rate
                proportions = (self.strategy.savings_rrsp_fraction,
                               self.strategy.savings_tfsa_fraction, 1)
                fund_chain = [
                    self.funds["wp_rrsp"], self.funds["wp_tfsa"],
                    self.funds["wp_nonreg"]
                ]
                deposited, year_rec = funds.ChainedDeposit(
                    earnings_to_save, fund_chain, proportions, year_rec)
                cash -= deposited
                if deposited > 0:
                    self.positive_savings_years += 1

        # Update funds
        for fund in self.funds.values():
            fund.Update(year_rec)

        # update the Person's view of RRSP and TFSA room
        self.tfsa_room = year_rec.tfsa_room
        self.rrsp_room = year_rec.rrsp_room

        # Calculate EI premium and CPP contributions
        year_rec = self.CalcPayrollDeductions(year_rec)

        # Now we try to get money from GIS because year_rec is populated with the needed values.
        income = self.incomes[-1]  # GIS is last in this list
        amount, taxable, year_rec = income.GiveMeMoney(year_rec)
        cash += amount

        # Pay income taxes
        year_rec.taxes_payable = self.CalcIncomeTax(year_rec)
        cash -= year_rec.taxes_payable

        # Update incomes
        for income in self.incomes:
            income.AnnualUpdate(year_rec)

        # Pay sales tax
        non_hst_consumption = min(cash, world.SALES_TAX_EXEMPTION)
        hst_consumption = cash - non_hst_consumption
        year_rec.consumption = hst_consumption / (
            1 + world.HST_RATE) + non_hst_consumption
        year_rec.sales_taxes = hst_consumption * world.HST_RATE

        return year_rec