The pipeline
Given a Profile (canton, commune, age, civil status, gross salary, etc.), the engine runs the following steps in order:
- Social deductions: AHV/IV/EO + ALV from the gross (6.4 % of salary in 2026), removed from taxable base.
- Standard deductions: professional (3 % of net, floor CHF 2 000, cap CHF 4 000), insurance (CHF 1 800 single / 3 600 married), child (CHF 6 700 per child federal).
- Taxable income = gross − social − standard deductions. Same base used for both federal and cantonal (a simplification; real assessments allow more cantonal deductions).
- Federal direct tax: walk the federal bracket schedule (2026, ESTV).
- Cantonal simple tax: walk the canton's “einfache Steuer” scale (or apply the formula in BL's case).
- Cantonal tax = simple × cantonal multiplier ÷ 100.
- Communal tax = simple × commune Steuerfuss ÷ 100.
- Total = federal + cantonal + communal (with Geneva-specific additive logic, see special cases).
Bracket walking
A Scale is a list of brackets. Each bracket has {from, to, rate, base}. To compute tax at income I:
- Find the bracket where
from ≤ I < to. - Tax =
base + (I − from) × rate.
Effective rate cap: some cantons (SH, NW, GL, etc.) have a regressive flat top — above a threshold the tax becomes a fixed % of total income, not marginal. We express this via Scale.effectiveRateCap; after computing via brackets we clamp the result to income × cap.
Special-case cantons
Six cantons require non-standard treatment:
- GE (Geneva) — additive multiplier, not replacement.
total = base × (1 + 0.475_canton + commune/100 + 0.01_homecare) × (1 − 0.12_rebate)The +1 represents the impôt de base itself; commune/canton centimes are added on top. The 12 % rabais d'impôt is the standard cantonal rebate. Per LCACant Art. 2. - BL (Basel-Landschaft) — logarithmic formula.
Tax = b·x + c·x·(ln(x) − 1) + dThree piecewise sections (15k–40k, 40k–100k, 100k–1.15M) plus a linear top above CHF 1 150 000. Coefficients from §34 StG BL. Implemented via theScale.formulaescape hatch in the engine; the bracket array remains defined for marginal-rate fallback only. - VS (Valais) — uses a de-indexation procedure (income ÷ 1.10⁷ ÷ 1.03) then piecewise-linear rate × original income. We approximate as a 26-bracket scale, exact at class boundaries. Married couples receive a 35 % rebate bounded CHF 680–4 900; this is applied post-bracket (not yet wired — single scale used for both).
- NE (Neuchâtel) — married uses a 52 % rate-determination coefficient (taux at half income). We approximate by using the single scale for married too.
- Splitting cantons (FR / GR / SO / SZ / SH / NW / GL / AI / TG / ZG / BS): married tax = scale(income ÷ divisor) × divisor. Implemented via
splitScale()which stretches every bracket boundary by the divisor. - Flat-rate cantons (UR, OW): single bracket with rate 7.1 % (UR) or 1.8 % (OW). The married difference comes from cantonal Sozialabzüge applied before the scale.
Levers (paid tier)
Optiqo's paid plan evaluates “levers” — discrete tax optimisations:
- LPP buy-in (single year) — capped at buy-in capacity and annual cashflow
- LPP buy-in (multi-year, DP solver) — distribute a target amount over N years maximising tax saved
- Pillar 3a max — CHF 7 258 employees / CHF 36 288 self-employed (2026)
- Pillar 3a retroactive buy-back (new 2026) — fill gaps from 2025 onward, up to 10 years
- Cantonal move — simulate relocation impact across all 26 cantons
- Combo (LPP + 3a) — joint optimisation with cashflow constraint
Each lever returns a LeverResult with saving, ROI, fit assessment (4 grades), and constraint-violation notes (e.g. Art. 79b three-year lock-in before retirement withdrawal).
Opportunity-cost comparison
For the LPP buy-in lever, the engine compares the after-tax pension outcome against an alternative: invest the same out-of-pocket amount in an SMI ETF. Both paths are computed with CAGR on out-of-pocket spend so the comparison is apples-to-apples.
Inputs to the alternative-path computation:
- Alternative return (default 6 % SMI long-run)
- ETF TER (default 0.25 % p.a.)
- Dividend yield (default 3 % p.a., subject to your marginal rate)
- Wealth tax rate (default 0.3 % p.a. on growing balance)
- Lump-sum withdrawal tax (BVG path — cantonal scale)
Source code
The engine is a pure-TypeScript package (@swiss-tax/engine) with no I/O — it's safe to embed in any runtime. Tests run via Vitest; we maintain 57 unit tests covering golden-reference cases (ZH/GE/VD at multiple incomes) and per-lever sanity checks.