Skip to content

Commit 5468e9d

Browse files
committed
feat: pension rights earning
1 parent 4139d12 commit 5468e9d

2 files changed

Lines changed: 66 additions & 17 deletions

File tree

src/lib/ForecastGraph.svelte

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
66
export let simulation: Array<YearState>;
77
8-
$: data = simulation.map(({ iskSavings, year, cashFlow }) => ({
9-
year: new Date(year, 1),
10-
savings: iskSavings,
11-
cashFlow
12-
}));
8+
$: data = simulation.map(
9+
({ iskSavings, year, cashFlow, premiumPensionRights, incomePensionRights }) => ({
10+
year: new Date(year, 1),
11+
savings: iskSavings,
12+
cashFlow,
13+
pensionRights: premiumPensionRights + incomePensionRights
14+
})
15+
);
1316
1417
export let width = 800;
1518
export let height = 600;
@@ -22,8 +25,8 @@
2225
$: xScale = d3.scaleUtc([minYear ?? 0, maxYear ?? 0], [margin.left, width - margin.right]);
2326
$: yScale = d3.scaleLinear(
2427
[
25-
d3.min(data, (d) => Math.min(d.cashFlow, d.savings)) ?? 0,
26-
d3.max(data, (d) => Math.max(d.cashFlow, d.savings)) ?? 1
28+
d3.min(data, (d) => Math.min(d.cashFlow, d.savings, d.pensionRights)) ?? 0,
29+
d3.max(data, (d) => Math.max(d.cashFlow, d.savings, d.pensionRights)) ?? 1
2730
],
2831
[height - margin.bottom, margin.top]
2932
);
@@ -33,6 +36,11 @@
3336
.x((d) => xScale(d.year))
3437
.y((d) => yScale(d.savings));
3538
39+
$: pensionRightsLine = d3
40+
.line<{ year: Date; pensionRights: number }>()
41+
.x((d) => xScale(d.year))
42+
.y((d) => yScale(d.pensionRights));
43+
3644
$: cashFlowLine = d3
3745
.line<{ year: Date; cashFlow: number }>()
3846
.x((d) => xScale(d.year))
@@ -67,6 +75,7 @@
6775
<!-- Add the path for the line -->
6876
<path d={savingsLine(data)} fill="none" stroke="steelblue" stroke-width="1.5" />
6977
<path d={cashFlowLine(data)} fill="none" stroke="green" stroke-width="1.5" />
78+
<path d={pensionRightsLine(data)} fill="none" stroke="red" stroke-width="1.5" />
7079
</svg>
7180

7281
<style>

src/lib/simulation.ts

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export interface YearState {
1212
iskSavings: number;
1313
compoundedInflation: number;
1414
cashFlow: number;
15-
//incomePensionRights: number;
16-
//premiumPensionRights: number;
15+
incomePensionRights: number;
16+
premiumPensionRights: number;
1717
//servicePensionSavings: number;
1818
}
1919

@@ -28,14 +28,19 @@ export interface Parameters {
2828
stateTaxRate: number;
2929
stateTaxThreshold: number;
3030
taxFreeThreshold: number;
31+
publicPensionContributionThreshold: number;
32+
incomePensionContributionRate: number;
33+
incomePensionRate: number;
34+
premiumPensionContributionRate: number;
35+
premiumPensionRate: number;
3136
}
3237

3338
export interface TimeBoundCashFlow {
3439
startYear: number; // Inclusive
3540
endYear?: number; // Exclusive
3641
yearlyCashFlow: number;
3742
kind: 'GrossTaxableEarnedIncome' | 'NetExpense';
38-
//publicPensionContributing: boolean;
43+
publicPensionContributing: boolean; // Only used for GrossTaxableEarnedIncome
3944
//servicePensionContribution: number;
4045
}
4146

@@ -58,21 +63,26 @@ export function defaultScenario(): Scenario {
5863
stateTaxRate: 0.2,
5964
stateTaxThreshold: 52000 * 12,
6065
taxFreeThreshold: 24238,
66+
publicPensionContributionThreshold: 571500,
67+
incomePensionContributionRate: 0.16,
68+
incomePensionRate: 0.033,
69+
premiumPensionContributionRate: 0.025,
70+
premiumPensionRate: 0.074,
6171
cashFlows: [
6272
{
6373
startYear: currentYear,
6474
endYear: currentYear + 9,
6575
yearlyCashFlow: 52000 * 12,
66-
kind: 'GrossTaxableEarnedIncome'
67-
// publicPensionContributing: true,
76+
kind: 'GrossTaxableEarnedIncome',
77+
publicPensionContributing: true
6878
// servicePensionContribution: 4.5
6979
},
7080
{
7181
startYear: currentYear,
7282
endYear: undefined,
7383
yearlyCashFlow: 15000 * 12,
74-
kind: 'NetExpense'
75-
// pensionContributing: false,
84+
kind: 'NetExpense',
85+
publicPensionContributing: false
7686
// publicPensionContributing: false,
7787
// servicePensionContribution: 0
7888
}
@@ -82,7 +92,9 @@ export function defaultScenario(): Scenario {
8292
year: currentYear,
8393
iskSavings: 1000000,
8494
compoundedInflation: 1,
85-
cashFlow: 0
95+
cashFlow: 0,
96+
premiumPensionRights: 0,
97+
incomePensionRights: 0
8698
},
8799
endYear: 2080
88100
};
@@ -104,6 +116,33 @@ function simulateYear(state: YearState, params: Parameters): YearState {
104116
return endYear > newYear;
105117
});
106118

119+
const yearlyGrossPublicPensionContributingIncomePostInflation =
120+
Math.min(
121+
yearlyCashFlows
122+
.filter(
123+
({ kind, publicPensionContributing }) =>
124+
kind === 'GrossTaxableEarnedIncome' && publicPensionContributing
125+
)
126+
.reduce((acc, cf) => acc + cf.yearlyCashFlow, 0),
127+
params.publicPensionContributionThreshold
128+
) * compoundedInflationYearlyAverage;
129+
130+
const incomePensionContributionPostInflation =
131+
yearlyGrossPublicPensionContributingIncomePostInflation * params.incomePensionContributionRate;
132+
const premiumPensionContributionPostInflation =
133+
yearlyGrossPublicPensionContributingIncomePostInflation * params.premiumPensionContributionRate;
134+
135+
const incomePensionRights =
136+
(state.incomePensionRights + incomePensionContributionPostInflation / 2) *
137+
(1 + params.incomePensionRate) +
138+
incomePensionContributionPostInflation / 2;
139+
const premiumPensionRights =
140+
(state.premiumPensionRights + premiumPensionContributionPostInflation / 2) *
141+
(1 + params.premiumPensionRate) +
142+
premiumPensionContributionPostInflation / 2;
143+
144+
// TODO: arvsvinst: https://www.pensionsmyndigheten.se/statistik/publikationer/orange-rapport-2021/a-berakningsfaktorer.html
145+
107146
const yearlyGrossTaxableEarnedIncomePostInflation =
108147
yearlyCashFlows
109148
.filter(({ kind }) => kind === 'GrossTaxableEarnedIncome')
@@ -152,8 +191,9 @@ function simulateYear(state: YearState, params: Parameters): YearState {
152191
year: state.year + 1,
153192
iskSavings: Math.floor(newSavings),
154193
compoundedInflation: compoundedInflation,
155-
cashFlow: yearlyNetCashFlowPostInflation
156-
// premiumPensionRights: state.premiumPensionRights,
194+
cashFlow: yearlyNetCashFlowPostInflation,
195+
incomePensionRights: incomePensionRights,
196+
premiumPensionRights: premiumPensionRights
157197
// servicePensionSavings: state.servicePensionSavings,
158198
};
159199
}

0 commit comments

Comments
 (0)