Optiqo

Tax engine

The core computation: how the engine derives federal + cantonal + commune tax from a profile, with documented special cases per canton.

The pipeline

Given a Profile (canton, commune, age, civil status, gross salary, etc.), the engine runs the following steps in order:

  1. Social deductions: AHV/IV/EO + ALV from the gross (6.4 % of salary in 2026), removed from taxable base.
  2. 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).
  3. Taxable income = gross − social − standard deductions. Same base used for both federal and cantonal (a simplification; real assessments allow more cantonal deductions).
  4. Federal direct tax: walk the federal bracket schedule (2026, ESTV).
  5. Cantonal simple tax: walk the canton's “einfache Steuer” scale (or apply the formula in BL's case).
  6. Cantonal tax = simple × cantonal multiplier ÷ 100.
  7. Communal tax = simple × commune Steuerfuss ÷ 100.
  8. 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:

  1. Find the bracket where from ≤ I < to.
  2. 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 the Scale.formula escape 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 viasplitScale() 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.

Continue to data sources →