GEP 3 — Parameters of the taxes and transfers system#
Author |
|
Status |
Provisional |
Type |
Standards Track |
Created |
2022-03-28 |
Updated |
2025-07-23 |
Resolution |
Abstract#
This GEP describes the structure of the parameters of the taxes and transfers system. This includes the format of the yaml files (initial input) and storage of the processed parameters.
Motivation and Scope#
The parameters of the taxes and transfers system are among the core elements of GETTSIM. Along with the functions operating on them and the input data, they determine all quantities of interest. Sensibly structuring and cleanly documenting the meaning and sources of these parameters requires particular care.
Usage and Impact#
GETTSIM developers should closely look at the Section Structure of the YAML files before adding new parameters. Some validation happens via the pre-commit hooks, but that cannot catch all inconsistencies.
Structure of the YAML files#
Each YAML file contains a number of parameters at the outermost level of indentation.
Each of these parameters is a dictionary with at least 6 keys: name
, description
,
unit
, reference_period
, type
and the YYYY-MM-DD
-formatted date on which it first
took effect.
Values usually change over time; each time a value is changed, another YYYY-MM-DD
entry is added. Beyond that, no additional keys are allowed.
The
name
key has two sub-keysde
anden
, which areshort names without re-stating the realm of the parameter (e.g. “Arbeitslosengeld II” or “Kinderzuschlag”);
not sentences;
correctly capitalised.
Example (from
kindergeld
):altersgrenze: name: de: Alter, ab dem Kindergeld nicht mehr gezahlt wird. en: Age at which child benefit is no longer paid.
The
description
key has two sub-keysde
anden
, whichare exhaustive explanations of the parameter;
show the § and Gesetzbuch of that parameter (including its entire history if the location has changed);
mention bigger amendments / Neufassungen and be as helpful as possible to make sense of that parameter.
Example:
altersgrenze: description: de: >- § 32 Art. 2-4 EStG. Für minderjährige Kinder besteht ohne Bedingungen ein Anspruch auf Kindergeld. Auch für erwachsene Kinder kann bis zu einer Altersgrenze unter bestimmten Bedingungen ein Anspruch auf Kindergeld bestehen. en: >- § 32 Art. 2-4 EStG. Underage children are entitled to child benefit without any conditions. Also adult children up to a specified age are entitled to child benefit under certain conditions.
The
unit
key informs on the unit of the values (Euro or DM if monetary, share of some other value, …).In some cases (e.g., factor for the calculation of the marginal employment threshold), there is no unit.
It should be capitalised.
Possible values:
Euros
,DM
,Share
,Percent
,Years
,Months
,Hours
,Square Meters
,Euros / Square Meter
,None.
Example:
altersgrenze: name: de: Alter, ab dem Kindergeld nicht mehr gezahlt wird. unit: Euro
The
type
key signals to GETTSIM how the parameter is to be interpreted. It must be specified as one of:scalar
,dict
,piecewise_constant
,piecewise_linear
,piecewise_quadratic
,piecewise_cubic
,birth_month_based_phase_inout
birth_year_based_phase_inout
,require_converter
,
scalar
is self-explanatory;dict
must be a homogeneous dictionary with string or integer keys and scalar values (int, float, bool).piecewise_constant
,piecewise_linear
,piecewise_quadratic
,piecewise_cubic
will be converted automatically to be used with thepiecewise_polynomial
function.birth_month_based_phase_inout
andbirth_year_based_phase_inout
are used to phase in or out a parameter based on the birth year of the individual. They are automatically converted to be used asConsecutiveIntLookupTableParamValue
objects.require_converter
can be anything. However there must be a converter function in the codebase.The
reference_period
key informs on the reference period of the values, if applicable. Possible values:Year
,Quarter
,Month
,Week
,Day
,Hour
,None
The optional
add_jahresanfang
can be used to make the parameter that is relevant at the start of the year (relative to the date for which the policy environment is set up) available to GETTSIM functions.If specified, two parameters will be available:
("path", "to", "parameter") ("path", "to", "parameter_jahresanfang")
Example from
sozialversicherung
/arbeitslosen
/beitragssatz.yaml
:beitragssatz: name: de: Beitragssatz zur Arbeitslosenversicherung unit: Share reference_period: null type: scalar add_jahresanfang: true
The YYYY-MM-DD key(s)
hold all historical values for a specific parameter or set of parameters in dictionaries
contain a precise reference to the law in the
reference
subkey;may add additional descriptions in the
note
key;is present with a note or reference only if a parameter ceases to exist starting on a particular date;
in case of a
scalar
type, the key of the scalar isvalue
.
The remainder of this section explains this element in much more detail.
The reference
key of [YYYY-MM-DD]#
cites the law (Gesetz “G. v.”), decree (Verordnung “V. v.”) or proclamation (Bekanntmachung “B. v.”) that changes the law
uses German language
follows the style
Artikel [n] [G./V./B.] v. [DD.MM.YYYY] BGBl. I S. [SSSS].
for references published until 2022 (the page should be the first page of the law/decree/proclamation, not the exact page of the parameter)Artikel [n] [G./V./B.] v. [DD.MM.YYYY] BGBl. [YYYY] I Nr. [NNN].
for references from 2023 on
does not add information “geändert durch” (it is always a change) or the date the law comes into force (this would just repeat the date key one level above)
Example:
beitragssatz:
name:
de: Beitragssatz zur Arbeitslosenversicherung
2019-01-01:
value: 0.0125
reference: V. v. 21.12.2018 BGBl. I S. 2663
The note
key of [YYYY-MM-DD]#
This optional key may contain a free-form note holding any information that may be relevant for the interpretation of the parameter, the implementer, user, …
beitragssatz:
name:
de: Beitragssatz zur Arbeitslosenversicherung
2019-01-01:
value: 0.0125
reference: V. v. 21.12.2018 BGBl. I S. 2663
note: >-
Set to 0.013 in Art. 2 Nr. 15 G. v. 18.12.2018 BGBl. I S. 2651. Temporarily
reduced to 0.0125 in BeiSaV 2019.
The updates_previous
key of [YYYY-MM-DD]#
Often laws change only part of a parameter. To avoid error-prone code duplication, we
allow for such cases via updates_previous
key.
This must not be used with a scalar parameter type. Furthermore, it cannot be used in the first period a parameter is defined.
Example from sozialversicherung
/ minijob.yaml
:
minijobgrenze_ost_west_unterschied
name:
de: Minijobgrenze
unit: Euros
reference_period: Month
type: dict
1997-01-01:
west: 312
ost: 266
1998-01-01:
updates_previous: true
west: 317
The values of [YYYY-MM-DD]#
The general idea is to make the replication of the laws very obvious. If the law includes a table, we will have a dictionary with keys 0, 1, 2, …. If the law includes a formula, the formula should be included and its parameters referenced. Etc..
The following walks through several cases.
The simplest case is a single parameter, which should be specified as:
minijobgrenze: name: de: Minijobgrenze en: Thresholds for marginal employment (minijobs) description: de: Minijob § 8 (1) Nr. 1 SGB IV en: Minijob § 8 (1) Nr. 1 SGB IV unit: Euros reference_period: Month type: scalar 1984-01-01: value: 199 1985-01-01: value: 205 1986-01-01: value: 210 1987-01-01: value: 220 1988-01-01: value: 225 1989-01-01: value: 230 1990-01-01: note: >- Minijobgrenze differs between West and East Germany. See ``parameter_minijobgrenze_ost_west_unterschied``. 2000-01-01: value: 322 2002-01-01: value: 325 2003-04-01: value: 400 2013-01-01: value: 450 2022-10-01: note: Minijob thresholds now calculated based on statutory minimum wage reference: Art. 7 G. v. 28.06.2022 BGBl. I S. 969
Note that there are different “active periods” for this parameter. The first one lasts from 1984-01-01 to 1989-12-31, after which there were different values in East and West Germany. from 2000-01-01 until 2022-10-01, the parameter is active again. After that, it is superseded by a formula based on the statutory minimum wage.
There could be a dictionary, which has to be homogenous in the keys (integers or strings) and values (scalar floating point numbers, integers, or Booleans):
minijobgrenze_ost_west_unterschied: name: de: Minijobgrenze, unterschiedlich in Ost und West en: Thresholds for marginal employment (minijobs), different in East and West description: de: Minijob § 8 (1) Nr. 1 SGB IV en: Minijob § 8 (1) Nr. 1 SGB IV unit: Euros reference_period: Month type: dict 1990-01-01: west: 240 ost: 102 1991-01-01: west: 245 ost: 120 1992-01-01: west: 256 ost: 153 1993-01-01: west: 271 ost: 199 1994-01-01: west: 286 ost: 225 1995-01-01: west: 297 ost: 240 1996-01-01: west: 302 ost: 256 1997-01-01: west: 312 ost: 266 1998-01-01: updates_previous: true west: 317 1999-01-01: west: 322 ost: 271 2000-01-01: note: >- Minijob thresholds do not differ between West and East Germany. See `minijobgrenze_m`.
In some cases, a dictionary with numbered keys makes sense. It is important to use these, not lists! The reason is that we always allow for the
note
andreference
keys to be present.satz_gestaffelt: name: de: Kindergeld pro Kind, Betrag je nach Reihenfolge der Kinder. en: Child benefit amount, depending on succession of children. description: de: >- § 66 (1) EStG. Identische Werte in §6 (1) BKGG, diese sind aber nur für beschränkt Steuerpflichtige relevant (d.h. Ausländer mit Erwerbstätigkeit in Deutschland). Für Werte vor 2002, siehe 'BMF - Datensammlung zur Steuerpolitik' en: null unit: Euros reference_period: Month type: dict 2002-01-01: 1: 154 2: 154 3: 154 4: 179 2009-01-01: reference: Art. 1 G. v. 22.12.2008 BGBl. I S. 2955 1: 164 2: 164 3: 170 4: 195
Another example would be referring to the parameters of a piecewise linear function:
parameter_solidaritätszuschlag: name: de: Solidaritätszuschlag en: null description: de: >- Ab 1995, der upper threshold im Intervall 1 ist nach der Formel transition_threshold in soli_st.py berechnet. en: null unit: Euros reference_period: Year type: piecewise_linear 1991-01-01: reference: Artikel 1 G. v. 24.06.1991 BGBl. I S. 1318. 0: lower_threshold: -inf rate_linear: 0 intercept_at_lower_threshold: 0 upper_threshold: 0 1: lower_threshold: 0 rate_linear: 0.0375 upper_threshold: inf
Phase-in or phase-out of age thresholds based on the birth year of the individual (e.g. increasing statutory retirement age thresholds) should be specified as type
birth_year_based_phase_inout
. The parameter specification is converted to a lookup table that maps a birth year to the age threshold. The conversion requires the following stucture after theYYYY-MM-DD
key:first_birthyear_to_consider
: The birth year at which the lookup table starts (just choose some birthyear that is far enough in the past).last_birthyear_to_consider
: The birth year at which the lookup table ends (just choose some birthyear that is far enough in the future).YYYY
entries with the following structure:years
: The age threshold in years.months
: The age threshold in months.
Example from
sozialversicherung
/rente
/altersrente
/regelaltersrente
/altersgrenze.yaml
:altersgrenze_gestaffelt: name: de: Gestaffeltes Eintrittsalter für Regelaltersrente nach Geburtsjahr en: Staggered normal retirement age (NRA) for Regelaltersrente by birth year description: de: >- § 35 Satz 2 SGB VI Regelaltersgrenze ab der Renteneintritt möglich ist. Wenn früher oder später in Rente gegangen wird, wird der Zugangsfaktor und damit der Rentenanspruch höher oder niedriger, sofern keine Sonderregelungen gelten. en: >- § 35 Satz 2 SGB VI Normal retirement age from which pension can be received. If retirement benefits are claimed earlier or later, the Zugangsfaktor and thus the pension entitlement is higher or lower unless special regulations apply. unit: Years reference_period: null type: birth_year_based_phase_inout 2007-04-20: reference: RV-Altersgrenzenanpassungsgesetz 20.04.2007. BGBl. I S. 554 note: >- Increase of the early retirement age from 65 to 67 for birth cohort 1947-1964. Vertrauensschutz (Art. 56) applies for birth cohorts before 1955 who were in Altersteilzeit before January 1st, 2007 or received "Anpassungsgeld für entlassene Arbeitnehmer des Bergbaus". first_birthyear_to_consider: 1900 last_birthyear_to_consider: 2031 1946: years: 65 months: 0 1947: years: 65 months: 1 1948: years: 65 months: 2 1949: years: 65 months: 3 1950: years: 65 months: 4 1951: years: 65 months: 5 1952: years: 65 months: 6 1953: years: 65 months: 7 1954: years: 65 months: 8 1955: years: 65 months: 9 1956: years: 65 months: 10 1957: years: 65 months: 11 1958: years: 66 months: 0 1959: years: 66 months: 2 1960: years: 66 months: 4 1961: years: 66 months: 6 1962: years: 66 months: 8 1963: years: 66 months: 10 1964: years: 67 months: 0
Phase-in or phase-out of age thresholds based on the birth month of the individual should be specified as type
birth_month_based_phase_inout
. The parameter specification is the same as forbirth_year_based_phase_inout
, except that theYYYY
entries are followed byMM
keys. TheMM
keys a have the following structure:first_birthmonth_to_consider
: The birth month at which the lookup table starts (just choose some birthmonth that is far enough in the past).last_birthmonth_to_consider
: The birth month at which the lookup table ends (just choose some birthmonth that is far enough in the future).years
: The age threshold in years.months
: The age threshold in months.
Excerpt from
sozialversicherung
/rente
/altersrente
/langjährig
/altersgrenze.yaml
:... 1989-12-18: reference: Rentenreformgesetz 1992. BGBl. I S. 2261 1989 § 41 note: Increase of full retirement age from 63 to 65 for birth cohort 1938-1943. first_birthyear_to_consider: 1900 last_birthyear_to_consider: 2100 1937: 12: years: 63 months: 0 1938: 1: years: 63 months: 1 ...
Finally, there are parameters that have a more complex structure, which is not as common as
piecewise_linear
etc. These need to be specified asrequire_converter
.Example from
arbeitslosengeld_2
/bedarfe.yaml
:parameter_regelsatz_nach_regelbedarfsstufen: name: de: Regelsatz mit direkter Angabe für Regelbedarfsstufen en: Standard rate with direct specification of "Regelbedarfsstufen" description: de: >- § 20 V SGB II. Neufassung SGB II § 20 (1a) und (2) durch Artikel 6 G. v. 22.12.2016 BGBl. I S. 3159. Regelbedafstufen: 1: Alleinstehender Erwachsener 2: Erwachsene in Partnerschaft 3: Erwachsene unter 25 im Haushalt der Eltern 4: Jugendliche 5: Ältere Kinder 6: Jüngste Kinder en: >- Regelbedarfsstufen: 1: Single Adult 2: Adults in a partner relationship 3: Adults under 25 in the household of their parents 4: Adolescents 5: Older children 6: Youngest children unit: Euros reference_period: Month type: require_converter 2011-01-01: 1: 364 2: 328 3: 291 4: min_alter: 14 max_alter: 17 betrag: 287 5: min_alter: 6 max_alter: 13 betrag: 251 6: min_alter: 0 max_alter: 5 betrag: 215 reference: Artikel 1 G. v. 24.03.2011 BGBl. I S. 453.
In general, a parameter should appear for the first time that it is mentioned in a law, becomes relevant, etc..
Do not set parameters to some value if they are not relevant yet.
If a parameter ceases to be relevant, is superseded by something else, etc., there must be a
YYYY-MM-DD
key with anote
and/orreference
key. There must not be other entries except for these two.Example:
parameter_regelsatz_anteilsbasiert: name: de: Berechnungsgrundlagen für den Regelsatz 2011-01-01: note: Calculation method changed, see regelsatz_nach_regelbedarfsstufen.
Handling of parameters in the codebase#
The contents of the YAML files are processed and are a pytree-like structure, similar to the functions. That is, they can be used directly in their namespace (=path to the yaml file excluding the file name) and accessed by absolute paths otherwise.
In this tree, they are specialised to the relevant policy date. Depending on the type of the parameter (see the previous section), the following types are possible:
scalar
parameters are just floats / ints / Booleans; i.e., simply thevalue
key of the yaml file.dict
parameters are homogenous dictionaries with all contents of theYYYY-MM-DD
entries except for thenote
andreference
keys.piecewise_constant
/piecewise_linear
/piecewise_quadratic
/piecewise_cubic
parameters are converted toPiecewisePolynomialParameter
objects.birth_month_based_phase_inout
andbirth_year_based_phase_inout
are converted toConsecutiveIntLookupTableParamValue
objects.require_converter
must have aparams_function
that converts theYYYY-MM-DD
entries to a clear type.
Discussion#
https://gettsim.zulipchat.com/#narrow/stream/309998-GEPs/topic/GEP.2003
GitHub PR for update (changes because of
GEP-6 <gep-6>
): ttsim-dev/gettsim#855
Copyright#
This document has been placed in the public domain.
Appendix: json-schema for the yaml files#
{
"$comment": "If you change this file, always change it in both locations: 1. ttsim/src/ttsim/params-schema.json 2. gettsim/docs/geps/params-schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9äöüßÄÖÜ_]+$": {
"type": "object",
"properties": {
"name": {
"type": "object",
"properties": {
"de": { "type": "string" },
"en": { "type": ["string", "null"] }
},
"required": ["de"],
"additionalProperties": false
},
"description": {
"type": "object",
"properties": {
"de": { "type": "string" },
"en": { "type": ["string", "null"] }
},
"required": ["de"],
"additionalProperties": false
},
"unit": {
"type": ["string", "null"],
"enum": [
"Euros",
"DM",
"Share",
"Percent",
"Years",
"Months",
"Hours",
"Square Meters",
"Euros / Square Meter",
null
]
},
"type": {
"type": "string",
"enum": [
"scalar",
"dict",
"piecewise_constant",
"piecewise_linear",
"piecewise_quadratic",
"piecewise_cubic",
"consecutive_int_lookup_table",
"sparse_to_consecutive_int_lookup_table",
"month_based_phase_inout_of_age_thresholds",
"year_based_phase_inout_of_age_thresholds",
"require_converter"
]
},
"reference_period": {
"type": ["string", "null"],
"enum": ["Year", "Quarter", "Month", "Week", "Day", "Hour", null]
},
"add_jahresanfang": {"type": "boolean"}
},
"patternProperties": {
"^(19|20)[0-9]{2}-(0[1-9]|1[0-2])-[0-3][0-9]$": {
"type": "object",
"properties": {
"value": {
"oneOf": [
{ "type": ["number"] },
{ "type": "string", "enum": ["inf", "-inf"] }
]
},
"reference": { "type": "string" },
"note": { "type": "string" },
"deviation_from": { "type": "string" }
},
"additionalProperties": true
}
},
"additionalProperties": false,
"allOf": [
{ "required": [
"name",
"description",
"unit",
"reference_period",
"type"
]
},
{
"minProperties": 1,
"patternProperties": {
"^(19|20)[0-9]{2}-(0[1-9]|1[0-2])-[0-3][0-9]$": {}
}
}
]
}
},
"additionalProperties": false
}