Tax Simulation DIY

Hi
I intent to simulate my taxes, e.g. calculate what taxes I own when the next bill comes.
I could just use some online calculator like from comparis. However my “dream solution” would be a complete re-engineering of the tax calculation (in my case canton/city of Zurich), so I can implement it as (python) script on my bookkeeping.

Has anyone build something like this that i could use/ get inspired from?

My ideas & challanges are

  • obtain taxation rates (solved: for ZH available as pdf here). bonus: find a machine readable source that updates in case the numbers change
  • find out about all the individual calculation steps by reverse engineering my last tax declaration and some common sense
    • gross income & deductions
    • DA-1 calculation. I felt some shenanegans going on here last time. I honestly did not understand the calculation they put down to estimate my tax credit (which end much less than what I paid in the end)
    • wealth tax calculation (should be easy)
    • what is this personalsteuer of CHF 24???
  • for a given tax declaration, calculate the derivative of the taxes owed w.r.t. certain parameters

bonus question: has anyone had good experience with a Steuerberater in Zurich? I might be interested to get some consultation. mostly for education purpose.

I have made a Python script to systematically calculate financial advantages or disadvantages if I move to another town and/or canton.

Taxation rates can be downloaded as CSV files from the federal tax office, see the link below. The script imports them. Then I’ve made an XML file with all my personal parameters, which is read and processed. The script then produces a CSV with, among other things, the expected taxes for all towns in the new canton. It also calculates how more or less expensive the rent should be to keep costs flat.

I can give it to you, if you want.

If you use it I would appreciate if you shared with me what you make of it. Also, I am not a professional developer, so I don’t know how properly pythonic my code is. And of course, there might be bugs in there, although I checked some numbers against official tax office calculators and they seemed right.

https://swisstaxcalculator.estv.admin.ch/#/taxdata/tax-rates

1 Like

I simply take the tax software for the current year and update the number.

Do not forget that you have to take into account many parameters other than tax rates. Depending on your situation (travel deductions, social deductions, health deductions, etc.) this could vary a lot.

1 Like

Why not using the online tax calculator that all cantons have now online?

They will provide you with accurate figures.

I personally use the tax software of the previous year to calculate my pre payments/taxes for next year.

Unless there are big changes at the canton level, it will give you precise figures. Easy to play with numbers to run simulations.

1 Like

because this does not integrate with my (python based) bookkeeping.

My goal is not to get a rough estimate of my due taxes. This i indeed get from any online calculator.
I want an automated update of my due taxes as I enter more transactions to my bookkeeping :slight_smile:

…and some extended analytics that require me to have full control on the calculation. like analysis & visualisation

Because it is not The Way of the Nerd.

It’s simply fun. I didn’t have to write a script for that, but I was learning Python and that was a welcome use case.

6 Likes

Do you have sub-categories allowing to choose between “tax deductible” vs “non tax deductible” in your bookkeeping system ?

For example, let’s say you buy books. Professional books in relation with your job might be deductible while comics are not.

How will you manage tax deductions when they are lower that what you effectively paid ?

Zurich allows an annual deduction of CHF 2600 for single, CHF 1700 at federal level for health insurance premiums. What if you pay CHF 350/month ?

1 Like

that would be utmost simple logic to include, however i am not that far yet :slight_smile:
i could imagine writing a beancount plugin that lets you whitelist accounts that are tax-deductable, and also maximum amounts etc…

So, how is this project proceeding? :slight_smile:

I do have some Python code for getting the Tax Rate for Zurich. Copy-pasting, it’s not the nicest code, so sorry in advance. You might want to change some parameters in the JSON.

import httplib
import json

def get_rates_base(url, data):
    # host = "www.steueramt.zh.ch"
    host = "webcalc.services.zh.ch"
    headers = {
        'Content-Type' :'application/json'
    }
    conn = httplib.HTTPSConnection(host)
    conn.request("POST", url, json.dumps(data), headers)
    response = conn.getresponse()
    if response.status != 200:
        raise Exception("Bad response")
    data = json.loads(response.read())
    return data

# Staats- und Gemeindesteuer
def get_rates(year, income, assets):
    url = "/ZH-Web-Calculators/calculators/INCOME_ASSETS/calculate"

    data = {
        "isLiabilityLessThanAYear": False,
        "hasTaxSeparation": False,
        "hasQualifiedInvestments": False,
        "taxYear": str(year),
        "liabilityBegin": None,
        "liabilityEnd": None,
        "name": "",
        "maritalStatus": "single",
        "taxScale": "BASIC",
        "religionP1": "OTHERS",
        "religionP2": "OTHERS",
        "municipality": "261",
        "taxableIncome": str(income),
        "ascertainedTaxableIncome": None,
        "qualifiedInvestmentsIncome": None,
        "taxableAssets": str(assets),
        "ascertainedTaxableAssets": None,
        "withholdingTax": "0"
    }

    data = get_rates_base(url, data)

    income_tax_rate = data['incomeTaxRate']['value'] * 0.01
    assets_tax_rate = data['assetsTaxRate']['value'] * 0.001

    result = (income_tax_rate, assets_tax_rate)
    return result

# Direkte Bundessteuer
def get_rate(year, income):
    url = "/ZH-Web-Calculators/calculators/FEDERAL/calculate"
    data = {
      "isLiabilityLessThanAYearOrHasTaxSeparation": False,
      "taxYear": str(year),
      "name": "",
      "taxScale": "SINGLE",
      "childrenNo": "0",
      "taxableIncome": str(income),
      "ascertainedTaxableIncome": None,
    }
    data = get_rates_base(url, data)
    result = data['federalTaxRate']['value'] * 0.01
    return result
2 Likes

hey @the_p
thanks so much for this code snippet, i only look at it now.

may I ask where you got the infromation that this api exists, and its details? is there a swagger page? i could not find any.

in the data points, there is the " municipality" that you set to 261, which I’d guess stands for the city of zurich. where can I find this information, and the numbers for other municipalities?
also for the other enum values, where can I find info on what allowed values exist?
Thanks!!

I’ve started from this online calculator:

And was trying to automate it. These were the steps:

  • Navigate to the calculator in the Chrome browser.
  • Go to “Menu > More Tools > Developer Tools”, then the tab “Network”.
  • There is a red circle indicating that traffic is being recorded.
  • Fill out the form, to make it calculate the taxes.
  • In the traffic recorded, an item “calculate” appears when the results are displayed.
  • Click on the item “calculate”, then click on the tabs “Headers, Payload, Response”. You see that it’s a POST request, with a JSON request and response.
  • By playing around with the form, figure out the necessary JSON parameters.

For the list of municipalities:

  • In the recording of the network traffic, there is an item INCOME_ASSETS, which contains in the response a JSON with all the municipality codes. (261 is indeed Zurich)
5 Likes

aha so you simply reverse engineered their page - alright, what is the worst answer i could expect :smiley:
so when I have questions then threre won’t be a user manual, but just hacking this online calculator. thanks anyway for pointing out :smiley:

1 Like

…by the way, the other calculators (Kapitalbezugssteuer for pillar 2/3a cash-out; inheritnace) also work via an api that you can access from your python script :smiley:

mentioning here that also ESTV has a calcuator tat works for all cantons:

it also uses an api. just run it and watch the netowrk traffic :slight_smile:

this one allows for basic deductions like 3a, work expenses, etc

I ended up copying & hardcoding the ESTV data into a Jupyter notebook, mostly because I use the code to calculate multiple years and it iterates many times through some parts. Accessing it online every time is too slow, and I’m too lazy / unskilled to make it collect data once only and then use a cached version… Plus, for multiple years ahead, it kind of needs the logic of when different deductions kick in or stop (e.g. children deduction, no professional expenses post fire).

But I have to say, it’s quite some spaghetti code and updates are getting increasingly painful! Getting it through the API is quite neat.