Esempio n. 1
0
 def testRRSPForcedWithdrawActive(self):
   fund = funds.RRSP()
   fund.amount = 10000
   year_rec = utils.YearRecord()
   year_rec.age = 70
   fund.Update(year_rec)
   self.assertEqual(fund.forced_withdraw, 528)
Esempio n. 2
0
 def testRRSPRoomLimit(self):
   fund = funds.RRSP()
   year_rec = utils.YearRecord()
   year_rec.incomes.append(incomes.IncomeReceipt(140000, incomes.INCOME_TYPE_EARNINGS))
   self.assertEqual(fund.room, world.RRSP_INITIAL_LIMIT)
   fund.Update(year_rec)
   self.assertEqual(fund.room, world.RRSP_INITIAL_LIMIT+world.RRSP_LIMIT)
Esempio n. 3
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)
Esempio n. 4
0
 def testChainedTransactionDifferentProportion(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 = 100
   nonreg = funds.NonRegistered()
   fund_chain = (rrsp, tfsa, nonreg)
   withdrawal_proportions = (0.5, 0.5, 1)
   deposit_proportions = (0.5, 0.8, 1)
   withdrawn, gains, year_rec = funds.ChainedTransaction(
       60, fund_chain, withdrawal_proportions, deposit_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(16, funds.FUND_TYPE_TFSA),
                           funds.DepositReceipt(4, funds.FUND_TYPE_NONREG)])
   self.assertEqual(rrsp.amount, 20)
   self.assertEqual(tfsa.amount, 66)
   self.assertEqual(nonreg.amount, 4)
Esempio n. 5
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)
Esempio n. 6
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"]]
                # Not using ChainedWithdraw because it can't express strict overflow
                withdrawn, _, year_rec = funds.ChainedTransaction(
                    top_up_amount, fund_chain, (1, 1), (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_withdrawal_table = world.GenerateCEDDrawdownTable(
                self.age, world.CPP_EXPECTED_RETIREMENT_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 / year_rec.cpi

        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)
Esempio n. 7
0
    def __init__(self,
                 strategy,
                 gender=FEMALE,
                 basic_only=False,
                 real_values=True):
        self.year = world.BASE_YEAR
        self.age = world.START_AGE
        self.gender = gender
        self.strategy = strategy
        self.cpi = 1  # Ignoring factor of 100 and StatsCan rounding rules here.
        self.cpi_history = []
        self.basic_only = basic_only
        self.real_values = real_values
        self.employed_last_year = True
        self.retired = False
        # CAUTION: GIS must be the last income in the list.
        self.incomes = [
            incomes.Earnings(),
            incomes.EI(),
            incomes.CPP(),
            incomes.OAS(),
            incomes.GIS()
        ]
        self.funds = {
            "wp_tfsa": funds.TFSA(),
            "wp_rrsp": funds.RRSP(),
            "wp_nonreg": funds.NonRegistered()
        }
        self.involuntary_retirement_random = random.random()
        self.tfsa_room = world.TFSA_INITIAL_CONTRIBUTION_LIMIT
        self.rrsp_room = world.RRSP_INITIAL_LIMIT
        self.capital_loss_carry_forward = 0

        self.accumulators = utils.AccumulatorBundle()
        self.has_been_ruined = False
        self.has_received_gis = False
        self.has_experienced_income_under_lico = False

        # The following hold real dollar amounts
        self.assets_at_retirement = 0
        self.total_retirement_withdrawals = 0
        self.total_lifetime_withdrawals = 0
        self.total_working_savings = 0

        self.positive_earnings_years = 0
        self.positive_savings_years = 0
        self.ei_years = 0
        self.gis_years = 0
        self.gross_income_below_lico_years = 0
        self.no_assets_years = 0

        self.period_years = {
            EMPLOYED: 0,
            UNEMPLOYED: 0,
            RETIRED: 0,
            INVOLUNTARILY_RETIRED: 0
        }
Esempio n. 8
0
 def testRRSPDeposit(self):
   fund = funds.RRSP()
   year_rec = utils.YearRecord()
   year_rec.rrsp_room = 20
   deposited, year_rec = fund.Deposit(15, year_rec)
   self.assertEqual(deposited, 15)
   self.assertEqual(fund.amount, 15)
   self.assertIn(funds.DepositReceipt(15, funds.FUND_TYPE_RRSP),
                 year_rec.deposits)
   self.assertEqual(year_rec.rrsp_room, 5)
Esempio n. 9
0
 def testRRSPUpdate(self):
   fund = funds.RRSP()
   fund.amount = 20
   year_rec = utils.YearRecord()
   year_rec.growth_rate = 0.2
   year_rec.inflation = 1
   year_rec.incomes.append(incomes.IncomeReceipt(10000, incomes.INCOME_TYPE_EARNINGS))
   fund.Update(year_rec)
   self.assertEqual(fund.amount, 48)
   self.assertEqual(fund.unrealized_gains, 0)
Esempio n. 10
0
 def testRRSPWithdraw(self):
   fund = funds.RRSP()
   fund.amount = 20
   year_rec = utils.YearRecord()
   year_rec.rrsp_room = 0
   withdrawn, gains, year_rec = fund.Withdraw(15, year_rec)
   self.assertEqual(withdrawn, 15)
   self.assertEqual(fund.amount, 5)
   self.assertIn(funds.WithdrawReceipt(15, 0, funds.FUND_TYPE_RRSP),
                 year_rec.withdrawals)
   self.assertEqual(year_rec.rrsp_room, 0)
Esempio n. 11
0
 def testChainedDepositInsufficientRoom(self):
   year_rec = utils.YearRecord()
   tfsa = funds.TFSA()
   year_rec.tfsa_room = 30
   rrsp = funds.RRSP()
   year_rec.rrsp_room = 50
   fund_chain = (tfsa, rrsp)
   proportions = (1, 1)
   deposited, year_rec = funds.ChainedDeposit(100, fund_chain, proportions,
                                              year_rec)
   self.assertEqual(deposited, 80)
   self.assertSequenceEqual(year_rec.deposits,
                            [funds.DepositReceipt(30, funds.FUND_TYPE_TFSA),
                             funds.DepositReceipt(50, funds.FUND_TYPE_RRSP)])
   self.assertEqual(tfsa.amount, 30)
   self.assertEqual(rrsp.amount, 50)
Esempio n. 12
0
def _SetUpChain(tfsa_amount=0, tfsa_room=0,
                rrsp_amount=0, rrsp_room=0,
                bridging_amount=0,
                nonreg_amount=0, nonreg_gains=0):
  year_rec = utils.YearRecord()
  tfsa = funds.TFSA()
  tfsa.amount = tfsa_amount
  year_rec.tfsa_room = tfsa_room
  rrsp = funds.RRSP()
  rrsp.amount = rrsp_amount
  year_rec.rrsp_room = rrsp_room
  bridging = funds.RRSPBridging()
  bridging.amount = bridging_amount
  nonreg = funds.NonRegistered()
  nonreg.amount = nonreg_amount
  nonreg.unrealized_gains = nonreg_gains

  return year_rec, tfsa, rrsp, bridging, nonreg 
Esempio n. 13
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)
Esempio n. 14
0
 def testChainedDepositProportions(self):
   year_rec = utils.YearRecord()
   tfsa = funds.TFSA()
   year_rec.tfsa_room = 30
   rrsp = funds.RRSP()
   year_rec.rrsp_room = 30
   nonreg = funds.NonRegistered()
   fund_chain = (tfsa, rrsp, nonreg)
   proportions = (0.2, 0.5, 1)
   deposited, year_rec = funds.ChainedDeposit(100, fund_chain, proportions,
                                              year_rec)
   self.assertEqual(deposited, 100)
   self.assertSequenceEqual(year_rec.deposits,
                            [funds.DepositReceipt(20, funds.FUND_TYPE_TFSA),
                             funds.DepositReceipt(30, funds.FUND_TYPE_RRSP),
                             funds.DepositReceipt(50, funds.FUND_TYPE_NONREG)])
   self.assertEqual(tfsa.amount, 20)
   self.assertEqual(rrsp.amount, 30)
   self.assertEqual(nonreg.amount, 50)
Esempio n. 15
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)
Esempio n. 16
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)
Esempio n. 17
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)