@@ -22,12 +22,19 @@ export interface Parameters {
2222 iskInterestRate : number ;
2323 iskTax : number ;
2424 cashFlows : TimeBoundCashFlow [ ] ;
25+ countyTaxRate : number ;
26+ churchTax : boolean ;
27+ churchTaxRate : number ;
28+ stateTaxRate : number ;
29+ stateTaxThreshold : number ;
30+ taxFreeThreshold : number ;
2531}
2632
2733export interface TimeBoundCashFlow {
2834 startYear : number ; // Inclusive
29- endYear : number ; // Exclusive
30- yearlyNetCashFlow : number ;
35+ endYear ?: number ; // Exclusive
36+ yearlyCashFlow : number ;
37+ kind : 'GrossTaxableEarnedIncome' | 'NetExpense' ;
3138 //publicPensionContributing: boolean;
3239 //servicePensionContribution: number;
3340}
@@ -45,32 +52,26 @@ export function defaultScenario(): Scenario {
4552 inflationRate : 0.025 ,
4653 iskInterestRate : 0.08 ,
4754 iskTax : 0.01086 ,
55+ countyTaxRate : 0.325 , // Strängnäs:0.325, GBG: 0.326
56+ churchTax : false ,
57+ churchTaxRate : 0.01045 ,
58+ stateTaxRate : 0.2 ,
59+ stateTaxThreshold : 52000 * 12 ,
60+ taxFreeThreshold : 24238 ,
4861 cashFlows : [
4962 {
5063 startYear : currentYear ,
51- endYear : currentYear + 8 ,
52- yearlyNetCashFlow : 38500 * 12
64+ endYear : currentYear + 9 ,
65+ yearlyCashFlow : 52000 * 12 ,
66+ kind : 'GrossTaxableEarnedIncome'
5367 // publicPensionContributing: true,
5468 // servicePensionContribution: 4.5
5569 } ,
5670 {
5771 startYear : currentYear ,
58- endYear : currentYear + 8 ,
59- yearlyNetCashFlow : 2755 * 12
60- // publicPensionContributing: false,
61- // servicePensionContribution: 100
62- } ,
63- {
64- startYear : currentYear ,
65- endYear : currentYear + 8 ,
66- yearlyNetCashFlow : - 2755 * 12
67- // publicPensionContributing: false,
68- // servicePensionContribution: 0
69- } ,
70- {
71- startYear : currentYear ,
72- endYear : currentYear + 50 ,
73- yearlyNetCashFlow : - 15000 * 12
72+ endYear : undefined ,
73+ yearlyCashFlow : 15000 * 12 ,
74+ kind : 'NetExpense'
7475 // pensionContributing: false,
7576 // publicPensionContributing: false,
7677 // servicePensionContribution: 0
@@ -83,7 +84,7 @@ export function defaultScenario(): Scenario {
8384 compoundedInflation : 1 ,
8485 cashFlow : 0
8586 } ,
86- endYear : 2100
87+ endYear : 2080
8788 } ;
8889}
8990
@@ -94,28 +95,64 @@ function simulateYear(state: YearState, params: Parameters): YearState {
9495 const compoundedInflationYearlyAverage =
9596 state . compoundedInflation * ( 1 + params . inflationRate / 2 ) ;
9697
97- const yearlyCashFlows = params . cashFlows . filter (
98- ( cf ) => cf . startYear <= newYear && cf . endYear > newYear
99- ) ;
100- const yearlyCashFlow = yearlyCashFlows . reduce ( ( acc , cf ) => acc + cf . yearlyNetCashFlow , 0 ) ;
101- const yearlyCashFlowPostInflation = yearlyCashFlow * compoundedInflationYearlyAverage ;
98+ const thisYearsStateTaxThreshold = params . stateTaxThreshold * compoundedInflationYearlyAverage ;
99+ const thisYearsTaxFreeThreshold = params . taxFreeThreshold * compoundedInflationYearlyAverage ;
100+
101+ const yearlyCashFlows = params . cashFlows . filter ( ( { startYear, endYear } ) => {
102+ if ( startYear > newYear ) return false ;
103+ if ( endYear === undefined ) return true ;
104+ return endYear > newYear ;
105+ } ) ;
106+
107+ const yearlyGrossTaxableEarnedIncomePostInflation =
108+ yearlyCashFlows
109+ . filter ( ( { kind } ) => kind === 'GrossTaxableEarnedIncome' )
110+ . reduce ( ( acc , cf ) => acc + cf . yearlyCashFlow , 0 ) * compoundedInflationYearlyAverage ;
111+
112+ const thisYearCountyTaxBracketRate =
113+ params . countyTaxRate + ( params . churchTax ? params . churchTaxRate : 0 ) ;
114+ const thisYearCountyTaxBracket =
115+ Math . max (
116+ Math . min ( yearlyGrossTaxableEarnedIncomePostInflation , thisYearsStateTaxThreshold ) -
117+ thisYearsTaxFreeThreshold ,
118+ 0
119+ ) * thisYearCountyTaxBracketRate ;
120+
121+ const thisYearStateTaxBracketRate = thisYearCountyTaxBracketRate + params . stateTaxRate ;
122+ const thisYearStateTaxBracket =
123+ ( Math . max ( yearlyGrossTaxableEarnedIncomePostInflation , thisYearsStateTaxThreshold ) -
124+ thisYearsStateTaxThreshold ) *
125+ thisYearStateTaxBracketRate ;
126+
127+ const yearlyNetIncomePostInflation =
128+ yearlyGrossTaxableEarnedIncomePostInflation -
129+ thisYearCountyTaxBracket -
130+ thisYearStateTaxBracket ;
131+
132+ const yearlyNetExpensePostInflation =
133+ yearlyCashFlows
134+ . filter ( ( { kind } ) => kind === 'NetExpense' )
135+ . reduce ( ( acc , cf ) => acc + cf . yearlyCashFlow , 0 ) * compoundedInflationYearlyAverage ;
136+
137+ const yearlyNetCashFlowPostInflation =
138+ yearlyNetIncomePostInflation - yearlyNetExpensePostInflation ;
102139
103140 // const publicPensionContributingCashFlows = yearlyCashFlows.filter(cf => cf.publicPensionContributing);
104141 // const publicPensionContributingCashFlow = publicPensionContributingCashFlows.reduce((acc, cf) => acc + cf.yearlyNetCashFlow, 0);
105142
106143 // const yearlyIncomePensionRights = publicPensionContributingCashFlow * 0.16; // TODO: This should be calculated
107144 // const yearlyPremiumPensionRights = publicPensionContributingCashFlow * 0.025;
108145
109- const iskSavingsYearlyAverage = state . iskSavings + yearlyCashFlowPostInflation / 2 ;
146+ const iskSavingsYearlyAverage = state . iskSavings + yearlyNetCashFlowPostInflation / 2 ;
110147 const iskInterest = iskSavingsYearlyAverage * params . iskInterestRate ;
111148 const iskTax = iskSavingsYearlyAverage * params . iskTax ;
112- const newSavings = state . iskSavings + yearlyCashFlowPostInflation + iskInterest - iskTax ;
149+ const newSavings = state . iskSavings + yearlyNetCashFlowPostInflation + iskInterest - iskTax ;
113150
114151 return {
115152 year : state . year + 1 ,
116153 iskSavings : Math . floor ( newSavings ) ,
117154 compoundedInflation : compoundedInflation ,
118- cashFlow : yearlyCashFlow
155+ cashFlow : yearlyNetCashFlowPostInflation
119156 // premiumPensionRights: state.premiumPensionRights,
120157 // servicePensionSavings: state.servicePensionSavings,
121158 } ;
0 commit comments