fire-planner/fire_planner/tax/cyprus.py
2026-05-07 17:06:19 +00:00

49 lines
2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Cyprus regime — non-dom 17-year exemption on foreign dividends +
interest, plus 2.65% GeSY healthcare levy capped at €180k.
The non-dom regime (Art 8(20)/(20A) Income Tax Law 118(I)/2002) gives
17 years of full exemption from SDC (Special Defence Contribution) on
foreign dividends and interest. Capital gains on shares are exempt
under standard CGT rules (only Cypriot real estate is taxed). Earned
income from employment is taxed under standard PIT bands — irrelevant
for our retirement scenarios.
GeSY (Γε.Σ.Υ. — General Healthcare System) levies 2.65% on worldwide
income with an annual cap of €180,000 of contributing income. We
convert the €180k cap to GBP via the FX rate at scenario time;
default = 0.86 GBP/EUR ≈ £154,800.
"""
from __future__ import annotations
from decimal import Decimal
from fire_planner.tax.base import TaxBreakdown, TaxInputs, TaxRegime
DEFAULT_GESY_RATE = Decimal("0.0265")
DEFAULT_GESY_CAP_EUR = Decimal("180000")
class CyprusTaxRegime(TaxRegime):
name = "cyprus"
def __init__(
self,
gesy_rate: Decimal = DEFAULT_GESY_RATE,
gesy_cap_gbp: Decimal | None = None,
gbp_per_eur: Decimal = Decimal("0.86"),
) -> None:
self.gesy_rate = gesy_rate
self.gesy_cap_gbp = (gesy_cap_gbp if gesy_cap_gbp is not None else DEFAULT_GESY_CAP_EUR *
gbp_per_eur)
def compute_tax(self, inputs: TaxInputs) -> TaxBreakdown:
# Foreign divs/interest exempt under non-dom (assumed within 17y window).
# Foreign capital gains exempt unless the underlying is Cypriot real estate.
chargeable = (inputs.earned_income + inputs.pension_withdrawal + inputs.capital_gains +
inputs.dividends + inputs.interest)
capped = min(chargeable, self.gesy_cap_gbp)
return TaxBreakdown(
healthcare_levy=capped * self.gesy_rate,
notes=("cyprus-non-dom", f"gesy_rate={self.gesy_rate}",
f"gesy_cap_gbp={self.gesy_cap_gbp}"),
)