Beispiel #1
0
    def determine_target_spending_at_node(profile, config, spending_boundary_at_projection_year, 
                                        dynamic_spending_ratio_at_projection_year,starting_wealth_at_sim_run,
                                        annuity_Income, SS_Income):
        # target = profile['target']['fixed']
        # income_tax_assumption = 0.25 #used to determine the after tax dynamic spending target at each node
        minimum_spending_boundary = profile['target']['essential']
        maximum_spending_boundary = profile['target']['discretional']
        minimum_boundary = minimum_spending_boundary * spending_boundary_at_projection_year #lower boundary
        maximum_boundary = maximum_spending_boundary * spending_boundary_at_projection_year #upper boundary

        ## Dynamic amount is the product of the starting account balance and the ratio following from the specified method
        # dynamic_amount = starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year * (1 - income_tax_assumption) + annuity_Income + SS_Income if starting_wealth_at_sim_run > 0 else 0
        '''
        Apply tax model to accounts to calculate dynamical spending amount
        '''
        if profile['account']['type'] == 'Traditional': 
            dynamic_amount_tax = calc_income_tax_liability(starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year, SS_Income, income_tax_config)
        else:
            dynamic_amount_tax = 0
        dynamic_amount = starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year + annuity_Income + SS_Income - dynamic_amount_tax if starting_wealth_at_sim_run > 0 else 0
        
        ## Dynamic target is higher than lower boundary if enough account balance
        dynamic_target = max(minimum_boundary, min(maximum_boundary, dynamic_amount))

        return dynamic_target
Beispiel #2
0
 def objectiveFunction(pre_tax_withdrawal, target, accountType):
     if accountType == 'Traditional':
         income_tax_liability = calc_income_tax_liability(
             pre_tax_withdrawal, SS_Income, income_tax_config)
     else:
         income_tax_liability = 0
     return abs(pre_tax_withdrawal + SS_Income + annuity_Income -
                income_tax_liability - target)
Beispiel #3
0
def decumulate_for_one_year(profile, starting_wealth, model_port, projection_year, SS_Income, annuity_Income, config,
                            spending_boundary_at_projection_year, dynamic_spending_ratio_at_projection_year, num_sim_runs = 100):
    
    ModelPortReturnsBySimAndYear = calc_model_port_ret_across_sim_runs_at_projection_year(model_port, projection_year,config)

    EOY_wealth = np.zeros(num_sim_runs)
    after_tax_retirement_income = np.zeros(num_sim_runs)
    income_tax_config = config['income_tax']

    ## Dynamic Spending function
    def determine_target_spending_at_node(profile, config, spending_boundary_at_projection_year, 
                                        dynamic_spending_ratio_at_projection_year,starting_wealth_at_sim_run,
                                        annuity_Income, SS_Income):
        # target = profile['target']['fixed']
        # income_tax_assumption = 0.25 #used to determine the after tax dynamic spending target at each node
        minimum_spending_boundary = profile['target']['essential']
        maximum_spending_boundary = profile['target']['discretional']
        minimum_boundary = minimum_spending_boundary * spending_boundary_at_projection_year #lower boundary
        maximum_boundary = maximum_spending_boundary * spending_boundary_at_projection_year #upper boundary

        ## Dynamic amount is the product of the starting account balance and the ratio following from the specified method
        # dynamic_amount = starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year * (1 - income_tax_assumption) + annuity_Income + SS_Income if starting_wealth_at_sim_run > 0 else 0
        '''
        Apply tax model to accounts to calculate dynamical spending amount
        '''
        if profile['account']['type'] == 'Traditional': 
            dynamic_amount_tax = calc_income_tax_liability(starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year, SS_Income, income_tax_config)
        else:
            dynamic_amount_tax = 0
        dynamic_amount = starting_wealth_at_sim_run * dynamic_spending_ratio_at_projection_year + annuity_Income + SS_Income - dynamic_amount_tax if starting_wealth_at_sim_run > 0 else 0
        
        ## Dynamic target is higher than lower boundary if enough account balance
        dynamic_target = max(minimum_boundary, min(maximum_boundary, dynamic_amount))

        return dynamic_target

    ## Define the optimization function 
    def objectiveFunction(pre_tax_withdrawal,target,accountType):
        if accountType == 'Traditional':
            income_tax_liability = calc_income_tax_liability(pre_tax_withdrawal, SS_Income, income_tax_config)
        else:
            income_tax_liability = 0
        return abs(pre_tax_withdrawal + SS_Income + annuity_Income - income_tax_liability - target)

    for i in range(num_sim_runs):
        target = determine_target_spending_at_node(profile, config, spending_boundary_at_projection_year, 
                                        dynamic_spending_ratio_at_projection_year, starting_wealth[i],
                                        annuity_Income, SS_Income)
        
        if starting_wealth[i] < 100:
            optimized_pre_tax_withdrawal = starting_wealth[i]
        else: 
            solution = minimize(fun=lambda x: objectiveFunction(x,target,profile['account']['type']), x0 = 0,method='SLSQP',bounds=[(0,starting_wealth[i])])
            optimized_pre_tax_withdrawal = solution.x

        EOY_wealth[i] = max(starting_wealth[i] - optimized_pre_tax_withdrawal,0) * (1 + ModelPortReturnsBySimAndYear[:,i])
        
        if profile['account']['type'] == 'Traditional':
            income_tax_liability = calc_income_tax_liability(optimized_pre_tax_withdrawal, SS_Income, income_tax_config)
        else:
            income_tax_liability = 0
        after_tax_retirement_income[i] = optimized_pre_tax_withdrawal + SS_Income + annuity_Income - income_tax_liability

    return EOY_wealth, after_tax_retirement_income