glidepath 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- glidepath/__init__.py +3 -0
- glidepath/app/__init__.py +364 -0
- glidepath/app/backtest.py +281 -0
- glidepath/app/charts.py +759 -0
- glidepath/app/copy.py +174 -0
- glidepath/app/display.py +148 -0
- glidepath/app/drawdown.py +436 -0
- glidepath/app/example.py +66 -0
- glidepath/app/exports.py +487 -0
- glidepath/app/files.py +249 -0
- glidepath/app/firstrun.py +114 -0
- glidepath/app/forms.py +1750 -0
- glidepath/app/inspector.py +506 -0
- glidepath/app/labels.py +66 -0
- glidepath/app/montecarlo.py +399 -0
- glidepath/app/plan.py +354 -0
- glidepath/app/retirement.py +446 -0
- glidepath/app/scenarios.py +831 -0
- glidepath/app/shell.py +185 -0
- glidepath/app/tables.py +138 -0
- glidepath/core/__init__.py +390 -0
- glidepath/core/annuities.py +240 -0
- glidepath/core/backtest.py +514 -0
- glidepath/core/comparison.py +278 -0
- glidepath/core/config.py +82 -0
- glidepath/core/contributions.py +337 -0
- glidepath/core/engine.py +2811 -0
- glidepath/core/entities.py +264 -0
- glidepath/core/glide.py +289 -0
- glidepath/core/investments.py +175 -0
- glidepath/core/money.py +107 -0
- glidepath/core/montecarlo.py +609 -0
- glidepath/core/pensions.py +298 -0
- glidepath/core/periods.py +367 -0
- glidepath/core/provenance.py +271 -0
- glidepath/core/randomness.py +128 -0
- glidepath/core/region.py +46 -0
- glidepath/core/reporting.py +231 -0
- glidepath/core/results.py +504 -0
- glidepath/core/retirement.py +291 -0
- glidepath/core/returns.py +312 -0
- glidepath/core/scenarios.py +579 -0
- glidepath/core/state_pension.py +264 -0
- glidepath/core/tax.py +139 -0
- glidepath/core/withdrawals.py +461 -0
- glidepath/core/wrappers.py +278 -0
- glidepath/gui/__init__.py +6 -0
- glidepath/gui/assets/icon_128.png +0 -0
- glidepath/gui/assets/icon_16.png +0 -0
- glidepath/gui/assets/icon_24.png +0 -0
- glidepath/gui/assets/icon_256.png +0 -0
- glidepath/gui/assets/icon_32.png +0 -0
- glidepath/gui/assets/icon_48.png +0 -0
- glidepath/gui/assets/icon_64.png +0 -0
- glidepath/gui/assets/wordmark.png +0 -0
- glidepath/gui/charts.py +829 -0
- glidepath/gui/forms.py +359 -0
- glidepath/gui/inspector.py +186 -0
- glidepath/gui/main.py +51 -0
- glidepath/gui/scenarios.py +402 -0
- glidepath/gui/style.py +376 -0
- glidepath/gui/tableview.py +67 -0
- glidepath/gui/widgets.py +989 -0
- glidepath/persistence/__init__.py +48 -0
- glidepath/persistence/assumptions.py +112 -0
- glidepath/persistence/decode.py +747 -0
- glidepath/persistence/document.py +101 -0
- glidepath/persistence/encode.py +433 -0
- glidepath/persistence/migrations.py +158 -0
- glidepath/persistence/values.py +298 -0
- glidepath/py.typed +0 -0
- glidepath/regions/__init__.py +7 -0
- glidepath/regions/uk/__init__.py +189 -0
- glidepath/regions/uk/ages.py +156 -0
- glidepath/regions/uk/contributions.py +717 -0
- glidepath/regions/uk/data/age_rules.toml +78 -0
- glidepath/regions/uk/data/assumptions_default.toml +170 -0
- glidepath/regions/uk/data/returns_history.toml +150 -0
- glidepath/regions/uk/data/tax_year_2026_27.toml +98 -0
- glidepath/regions/uk/extension.py +479 -0
- glidepath/regions/uk/loader.py +704 -0
- glidepath/regions/uk/region.py +160 -0
- glidepath/regions/uk/schema.py +563 -0
- glidepath/regions/uk/state_pension.py +129 -0
- glidepath/regions/uk/tax.py +466 -0
- glidepath/regions/uk/wrappers.py +283 -0
- glidepath/regions/uk/years.py +92 -0
- glidepath-0.2.0.dist-info/METADATA +189 -0
- glidepath-0.2.0.dist-info/RECORD +93 -0
- glidepath-0.2.0.dist-info/WHEEL +4 -0
- glidepath-0.2.0.dist-info/entry_points.txt +3 -0
- glidepath-0.2.0.dist-info/licenses/LICENSE +21 -0
- glidepath-0.2.0.dist-info/licenses/LICENSE-DATA +28 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""The UK region bundle and shipped assumption set (roadmap 4.1; planning §4.2).
|
|
2
|
+
|
|
3
|
+
Builds the :class:`~glidepath.core.Region` the engine runs against:
|
|
4
|
+
the UK fiscal calendar (tax years, 6 April to 5 April), the age, tax,
|
|
5
|
+
wrapper, and contribution rulesets over the shipped data files, and a
|
|
6
|
+
content-version string naming each file with its ``verified_on`` date —
|
|
7
|
+
the region part of the run manifest (planning §4.6).
|
|
8
|
+
|
|
9
|
+
Also converts the shipped ``assumptions_default.toml`` into the core
|
|
10
|
+
:class:`~glidepath.core.AssumptionSet` (every entry
|
|
11
|
+
``DEFAULT_ASSUMPTION``-provenanced, carrying its basis), and derives
|
|
12
|
+
the future-years extension from the ``policy.tax.future_years`` and
|
|
13
|
+
``inflation.cpi`` assumptions. Both reads happen at region-build time —
|
|
14
|
+
before the run's read recorder exists — so the extension's effect on a
|
|
15
|
+
result is identified through the region data version, not the
|
|
16
|
+
assumption read list.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from datetime import UTC, datetime, time
|
|
20
|
+
|
|
21
|
+
from glidepath.core import (
|
|
22
|
+
AnnualCalendar,
|
|
23
|
+
Assumption,
|
|
24
|
+
AssumptionKey,
|
|
25
|
+
AssumptionSet,
|
|
26
|
+
Provenance,
|
|
27
|
+
Rate,
|
|
28
|
+
Region,
|
|
29
|
+
decimal_assumption_value,
|
|
30
|
+
)
|
|
31
|
+
from glidepath.regions.uk.ages import UkAgeRules
|
|
32
|
+
from glidepath.regions.uk.contributions import UkContributionRuleset
|
|
33
|
+
from glidepath.regions.uk.extension import FutureYearsExtension, FutureYearsPolicy
|
|
34
|
+
from glidepath.regions.uk.loader import (
|
|
35
|
+
AGE_RULES_FILENAME,
|
|
36
|
+
ASSUMPTIONS_FILENAME,
|
|
37
|
+
available_tax_years,
|
|
38
|
+
data_file_digest,
|
|
39
|
+
load_age_rules,
|
|
40
|
+
load_default_assumptions,
|
|
41
|
+
load_tax_year,
|
|
42
|
+
tax_year_filename,
|
|
43
|
+
)
|
|
44
|
+
from glidepath.regions.uk.schema import SCHEMA_VERSION
|
|
45
|
+
from glidepath.regions.uk.state_pension import UkStatePensionScheme
|
|
46
|
+
from glidepath.regions.uk.tax import UkTaxSystem
|
|
47
|
+
from glidepath.regions.uk.wrappers import UkWrapperRuleset
|
|
48
|
+
|
|
49
|
+
_TAX_YEAR_ANCHOR_MONTH = 4
|
|
50
|
+
_TAX_YEAR_ANCHOR_DAY = 6
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def default_assumption_set() -> AssumptionSet:
|
|
54
|
+
"""The shipped UK defaults as a core assumption set (planning §7).
|
|
55
|
+
|
|
56
|
+
Every entry carries ``DEFAULT_ASSUMPTION`` provenance with its
|
|
57
|
+
default value equal to its effective value; overriding one is the
|
|
58
|
+
caller's concern (a new :class:`~glidepath.core.Assumption` with
|
|
59
|
+
``USER_OVERRIDE`` or ``SCENARIO_OVERRIDE`` provenance in a new
|
|
60
|
+
set). ``recorded_on`` is the data file's ``verified_on`` at
|
|
61
|
+
midnight UTC.
|
|
62
|
+
"""
|
|
63
|
+
file = load_default_assumptions()
|
|
64
|
+
recorded_on = datetime.combine(file.meta.verified_on, time.min, tzinfo=UTC)
|
|
65
|
+
return AssumptionSet(
|
|
66
|
+
Assumption(
|
|
67
|
+
key=entry.key,
|
|
68
|
+
value=entry.value,
|
|
69
|
+
default_value=entry.value,
|
|
70
|
+
provenance=Provenance.DEFAULT_ASSUMPTION,
|
|
71
|
+
source=entry.basis,
|
|
72
|
+
recorded_on=recorded_on,
|
|
73
|
+
description=f"Shipped UK default for '{entry.key.value}'",
|
|
74
|
+
)
|
|
75
|
+
for entry in file.defaults
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def future_years_extension(assumptions: AssumptionSet) -> FutureYearsExtension:
|
|
80
|
+
"""The tax-data extension the ``policy.tax.future_years`` value asks for.
|
|
81
|
+
|
|
82
|
+
Reads the policy table and the CPI assumption directly from the
|
|
83
|
+
set (module docstring: region construction happens before the
|
|
84
|
+
run's read recorder exists).
|
|
85
|
+
"""
|
|
86
|
+
policy = FutureYearsPolicy.from_assumption_value(
|
|
87
|
+
assumptions.get(AssumptionKey.POLICY_TAX_FUTURE_YEARS).value
|
|
88
|
+
)
|
|
89
|
+
cpi = Rate(decimal_assumption_value(assumptions.get(AssumptionKey.INFLATION_CPI)))
|
|
90
|
+
return FutureYearsExtension(policy=policy, cpi=cpi)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def uk_region(future_years: FutureYearsExtension | None = None) -> Region:
|
|
94
|
+
"""The UK region bundle over every shipped data file (planning §4.2).
|
|
95
|
+
|
|
96
|
+
Without ``future_years`` the bundle answers only for the shipped
|
|
97
|
+
tax years and fails loudly past them; pass
|
|
98
|
+
:func:`future_years_extension` to project beyond the last shipped
|
|
99
|
+
file (planning §5.3).
|
|
100
|
+
"""
|
|
101
|
+
return Region(
|
|
102
|
+
calendar=AnnualCalendar(
|
|
103
|
+
anchor_month=_TAX_YEAR_ANCHOR_MONTH, anchor_day=_TAX_YEAR_ANCHOR_DAY
|
|
104
|
+
),
|
|
105
|
+
ages=UkAgeRules.from_shipped_data(),
|
|
106
|
+
tax=UkTaxSystem.from_shipped_data(future_years),
|
|
107
|
+
wrappers=UkWrapperRuleset.from_shipped_data(future_years),
|
|
108
|
+
contributions=UkContributionRuleset.from_shipped_data(future_years),
|
|
109
|
+
state_pension=UkStatePensionScheme.from_shipped_data(),
|
|
110
|
+
data_version=_data_version(future_years),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _data_version(future_years: FutureYearsExtension | None) -> str:
|
|
115
|
+
"""A deterministic content-version string over the shipped files.
|
|
116
|
+
|
|
117
|
+
Names every file with its ``verified_on`` date and a short content
|
|
118
|
+
digest — the date alone cannot tell two same-day revisions apart
|
|
119
|
+
(planning §4.6) — plus the full future-years policy (mode, freeze
|
|
120
|
+
ends incl. the Scottish band groups, CPI): a region-build input
|
|
121
|
+
whose effect must be identifiable from the version string, not the
|
|
122
|
+
assumption read list.
|
|
123
|
+
|
|
124
|
+
``returns_history.toml`` is deliberately absent: it prices no
|
|
125
|
+
assumption and no base projection, and this string doubles as the
|
|
126
|
+
saved-plan ``assumptions_resolved_against`` fingerprint
|
|
127
|
+
(:mod:`glidepath.app.files`) — including it would warn "shipped
|
|
128
|
+
defaults have changed" on every saved plan after a history-only
|
|
129
|
+
refresh. A backtest names its series by carrying it on the result
|
|
130
|
+
(:class:`glidepath.core.BacktestResult`).
|
|
131
|
+
"""
|
|
132
|
+
parts = [f"uk schema={SCHEMA_VERSION}"]
|
|
133
|
+
for start_year in available_tax_years():
|
|
134
|
+
year = load_tax_year(start_year)
|
|
135
|
+
digest = data_file_digest(tax_year_filename(start_year))
|
|
136
|
+
parts.append(
|
|
137
|
+
f"tax_year {year.meta.tax_year} verified {year.meta.verified_on}"
|
|
138
|
+
f" sha256={digest}"
|
|
139
|
+
)
|
|
140
|
+
ages = load_age_rules()
|
|
141
|
+
ages_digest = data_file_digest(AGE_RULES_FILENAME)
|
|
142
|
+
parts.append(f"age_rules verified {ages.meta.verified_on} sha256={ages_digest}")
|
|
143
|
+
assumptions = load_default_assumptions()
|
|
144
|
+
assumptions_digest = data_file_digest(ASSUMPTIONS_FILENAME)
|
|
145
|
+
parts.append(
|
|
146
|
+
f"assumptions verified {assumptions.meta.verified_on}"
|
|
147
|
+
f" sha256={assumptions_digest}"
|
|
148
|
+
)
|
|
149
|
+
if future_years is not None:
|
|
150
|
+
policy = future_years.policy
|
|
151
|
+
detail = policy.mode.value
|
|
152
|
+
if policy.frozen_until_start_year is not None:
|
|
153
|
+
detail += f" until={policy.frozen_until_start_year}"
|
|
154
|
+
if policy.scotland is not None:
|
|
155
|
+
detail += (
|
|
156
|
+
f" scot_lower_until={policy.scotland.lower_frozen_until_start_year}"
|
|
157
|
+
f" scot_upper_until={policy.scotland.upper_frozen_until_start_year}"
|
|
158
|
+
)
|
|
159
|
+
parts.append(f"future_years {detail} cpi={future_years.cpi.value}")
|
|
160
|
+
return "; ".join(parts)
|