Von: Riccardo Ambühl
Datum: 26.06.2025
Da ich die in den Modulen Berechnung der Kündigungsfrist und Rekonstruktion der Mittelflussrechnung behandelten Funktionen und Logiken sicher beherrsche, dokumentiere ich im Folgenden, was ich im Detail gelernt habe und wie ich dieses Wissen im Alltag anwenden kann.
Diese Funktionen unterstützen die Berechnung und Prüfung von Fristen im Mietrecht. Es werden u.a. Wochenenden, Feiertage sowie Fristen für die Kündigungszustellung berücksichtigt.
import datetime
def get_weekday(datum: datetime.date) -> bool:
return datum.weekday()
beispieldatum = datetime.date(2020, 1, 2)
wochentage = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']
wochentag = get_weekday(beispieldatum)
wochentag = wochentage[wochentag]
print(wochentag)
Nimmt ein Datum und gibt den Wochentag als Zahl (0=Montag, ..., 6=Sonntag) zurück.
import holidays
import datetime
def is_holiday(datum: datetime.date) -> bool:
feiertage = holidays.Switzerland(subdiv='ZH')
return datum in feiertage
print(is_holiday(datetime.date(2025, 5, 1)))
print(is_holiday(datetime.date(2025, 5, 2)))
Prüft, ob ein gegebenes Datum im Kanton Zürich ein Feiertag ist. Sie gibt True oder False zurück.
import datetime
def is_weekend(datum: datetime.date) -> bool:
return datum.weekday() > 4
print(is_weekend(datetime.date(2025, 5, 20)))
Überprüft, ob ein Datum am Wochenende liegt.
import datetime
def get_zustelldatum(abgabedatum: datetime.date) -> datetime.date:
zustelldatum = abgabedatum + datetime.timedelta(days=1)
while is_weekend(zustelldatum) or is_holiday(zustelldatum):
zustelldatum += datetime.timedelta(days=1)
return zustelldatum
print(get_zustelldatum(datetime.date(2025, 5, 16)))
Berechnet das Zustelldatum eines Briefs, indem es das Wochenende und Feiertage berücksichtigt. Der nächste gültige Werktag wird zurückgegeben.
import datetime
def get_abgabedatum(zustelldatum: datetime.date) -> datetime.date:
abgabedatum = zustelldatum - datetime.timedelta(days=1)
while is_weekend(abgabedatum) or is_holiday(abgabedatum):
abgabedatum -= datetime.timedelta(days=1)
return abgabedatum
print(get_abgabedatum(datetime.date(2025, 5, 19)))
Ermittelt das späteste mögliche Abgabedatum, damit ein Brief an einem gewünschten Werktag zugestellt wird.
import datetime
def set_kuendigungstermine(referenzdatum: datetime.date) -> list:
year = referenzdatum.year + 1 if referenzdatum.month >= 6 else referenzdatum.year
return [
datetime.date(year, 3, 31),
datetime.date(year, 6, 30),
datetime.date(year, 9, 30)
]
print(set_kuendigungstermine(datetime.date(2025, 7, 20)))
Die Funktion liefert die möglichen Kündigungstermine, basierend auf einem Referenzdatum.
import datetime
def get_kuendigungstermin(aufgabedatum: datetime.date) -> datetime.date:
zustellung = get_zustelldatum(aufgabedatum)
kuendigungstermine = set_kuendigungstermine(aufgabedatum)
monat = zustellung.month + 3
jahr = zustellung.year
if monat > 12:
monat -= 12
jahr += 1
termin = datetime.date(jahr, monat, zustellung.day)
if termin < kuendigungstermine[0]:
return kuendigungstermine[0]
elif termin < kuendigungstermine[1]:
return kuendigungstermine[1]
else:
return kuendigungstermine[2]
print(get_kuendigungstermin(datetime.date(2024, 12, 1)))
Berechnet den nächstmöglichen Kündigungstermin unter Berücksichtigung einer Zustellung + 3 Monate Frist.
import datetime
def get_aufgabedatum(kuendigungstermin: datetime.date) -> datetime.date:
monat = kuendigungstermin.month - 3
jahr = kuendigungstermin.year
if monat <= 0:
monat += 12
jahr -= 1
rueckdatum = get_abgabedatum(
datetime.date(
jahr,
monat,
kuendigungstermin.day
)
)
return rueckdatum
print(get_aufgabedatum(datetime.date(2025, 1, 19)))
Bestimmt das letztmögliche Aufgabedatum für einen Kündigungstermin unter Einhaltung der dreimonatigen Frist.
In diesem Abschnitt wird die indirekte Berechnung des Cash Flows gezeigt – anhand von Bilanz- und Jahresabschlussdaten.
import pandas as pd
bilanz = pd.read_csv('beispieldaten-1.csv', index_col=0)
liquide_mittel = bilanz.loc[1000:1020, 'Betrag'].sum()
print(liquide_mittel)
Liest die Bilanzdaten ein und summiert die Konten von 1000 bis 1020. Das ergibt die gesamten liquiden Mittel.
jahresabschluss = pd.read_csv('beispieldaten-2.csv', index_col=0, dtype={'Eroeffnung': 'Int64'})
veraenderung_liquide_mittel = jahresabschluss.loc[1000:1020, 'Abschluss'].sum() - jahresabschluss.loc[1000:1020, 'Eroeffnung'].sum()
print(veraenderung_liquide_mittel)
Berechnet die Differenz der liquiden Mittel zwischen Eröffnung und Abschluss der Konten 1000–1020.
positionen = {}
positionen["Jahresgewinn"] = jahresabschluss.loc[3000:8900]['Abschluss'].sum()
positionen["Abschreibungen"] = jahresabschluss.loc[6800:6899]['Abschluss'].sum() * -1
positionen["Rückstellungen"] = (
(jahresabschluss.loc[2330:2399]['Abschluss'].sum() + jahresabschluss.loc[2600:2799]['Abschluss'].sum()) -
(jahresabschluss.loc[2330:2399]['Eroeffnung'].sum() + jahresabschluss.loc[2600:2799]['Eroeffnung'].sum())
) * -1
positionen["Liquide WS"] = jahresabschluss.loc[1060:1069]['Eroeffnung'].sum() - jahresabschluss.loc[1060:1069]['Abschluss'].sum()
positionen["Veränderung FLL"] = jahresabschluss.loc[1100:1109]['Eroeffnung'].sum() - jahresabschluss.loc[1100:1109]['Abschluss'].sum()
positionen["Veränderung übrige kf Forderungen"] = jahresabschluss.loc[1140:1199]['Eroeffnung'].sum() - jahresabschluss.loc[1140:1199]['Abschluss'].sum()
positionen["Veränderung Vorräte"] = jahresabschluss.loc[1200:1299]['Eroeffnung'].sum() - jahresabschluss.loc[1200:1299]['Abschluss'].sum()
positionen["Veränderung ARA"] = jahresabschluss.loc[1300:1399]['Eroeffnung'].sum() - jahresabschluss.loc[1300:1399]['Abschluss'].sum()
positionen["Veränderung VLL"] = jahresabschluss.loc[2000:2099]['Abschluss'].sum() - jahresabschluss.loc[2000:2099]['Eroeffnung'].sum()
positionen["Veränderung übrige Verbindlichkeiten"] = (
(jahresabschluss.loc[2200:2210]['Abschluss'].sum() - jahresabschluss.loc[2200:2210]['Eroeffnung'].sum()) +
(jahresabschluss.loc[2270:2279]['Abschluss'].sum() - jahresabschluss.loc[2270:2279]['Eroeffnung'].sum())
)
positionen["Veränderung PRA"] = jahresabschluss.loc[2300:2399]['Abschluss'].sum() - jahresabschluss.loc[2300:2399]['Eroeffnung'].sum()
positionen["Veränderung übriger Fondsfremder Erfolg"] = (
jahresabschluss.loc[8000:8999]['Abschluss'].sum() - jahresabschluss.loc[8000:8999]['Eroeffnung'].sum()
) * -1
Hier werden alle Positionen für die indirekte Geldflussrechnung anhand von Kontoänderungen im Jahresabschluss berechnet.
print(f'Jahresgewinn: {positionen["Jahresgewinn"]}')
print(f'Abschreibungen: {positionen["Abschreibungen"]}')
print(f'Rückstellungen: {positionen["Rückstellungen"]}')
print(f'FLL: {positionen["Veränderung FLL"]}')
print(f'KF-Forderungen: {positionen["Veränderung übrige kf Forderungen"]}')
print(f'Liquide WS: {positionen["Liquide WS"]}')
print(f'Vorräte: {positionen["Veränderung Vorräte"]}')
print(f'ARA: {positionen["Veränderung ARA"]}')
print(f'VLL: {positionen["Veränderung VLL"]}')
print(f'Ãbrige Verbindlichkeiten: {positionen["Veränderung übrige Verbindlichkeiten"]}')
print(f'PRA: {positionen["Veränderung PRA"]}')
print(f'Rest: {positionen["Veränderung übriger Fondsfremder Erfolg"]}')
print(f'Cash Flow: {sum(positionen.values())}')
Die Werte aus den Positionen werden ausgegeben – darunter der finale berechnete Cash Flow.
from tabulate import tabulate
def cash_flow(ledger: pd.DataFrame) -> None:
positionen = {}
positionen["Jahresgewinn"] = ledger.loc[3000:8900]['Abschluss'].sum()
positionen["Abschreibungen"] = ledger.loc[6800:6899]['Abschluss'].sum() * -1
positionen["Rückstellungen"] = (
(ledger.loc[2330:2399]['Abschluss'].sum() + ledger.loc[2600:2799]['Abschluss'].sum()) -
(ledger.loc[2330:2399]['Eroeffnung'].sum() + ledger.loc[2600:2799]['Eroeffnung'].sum())
) * -1
positionen["Liquide WS"] = ledger.loc[1060:1069]['Eroeffnung'].sum() - ledger.loc[1060:1069]['Abschluss'].sum()
positionen["Veränderung FLL"] = ledger.loc[1100:1109]['Eroeffnung'].sum() - ledger.loc[1100:1109]['Abschluss'].sum()
positionen["Veränderung übrige kf Forderungen"] = ledger.loc[1140:1199]['Eroeffnung'].sum() - ledger.loc[1140:1199]['Abschluss'].sum()
positionen["Veränderung Vorräte"] = ledger.loc[1200:1299]['Eroeffnung'].sum() - ledger.loc[1200:1299]['Abschluss'].sum()
positionen["Veränderung ARA"] = ledger.loc[1300:1399]['Eroeffnung'].sum() - ledger.loc[1300:1399]['Abschluss'].sum()
positionen["Veränderung VLL"] = ledger.loc[2000:2099]['Abschluss'].sum() - ledger.loc[2000:2099]['Eroeffnung'].sum()
positionen["Veränderung übrige Verbindlichkeiten"] = (
(ledger.loc[2200:2210]['Abschluss'].sum() - ledger.loc[2200:2210]['Eroeffnung'].sum()) +
(ledger.loc[2270:2279]['Abschluss'].sum() - ledger.loc[2270:2279]['Eroeffnung'].sum())
)
positionen["Veränderung PRA"] = ledger.loc[2300:2399]['Abschluss'].sum() - ledger.loc[2300:2399]['Eroeffnung'].sum()
positionen["Veränderung übriger Fondsfremder Erfolg"] = (
ledger.loc[8000:8999]['Abschluss'].sum() - ledger.loc[8000:8999]['Eroeffnung'].sum()
) * -1
gesamt_cashflow = sum(positionen.values())
table = [[key, f"{value:,.2f} CHF"] for key, value in positionen.items() if value != 0]
table.append(["Gesamt Cash Flow", f"{gesamt_cashflow:,.2f} CHF"])
print("Indirekte Geldflussrechnung\n")
print(tabulate(table, headers=["Position", "Betrag"], tablefmt="github"))
cash_flow(jahresabschluss)
Die Funktion gibt eine formatierte Übersicht über alle Cash Flow Positionen und den Gesamtwert aus. Tabulate hilft bei der Darstellung der Daten.
Diese Funktionen analysieren die Investitionstätigkeit eines Unternehmens – aufgeteilt nach Mobilien und Immobilien.
import pandas as pd
from typing import Iterable
jahresabschluss = pd.read_csv('beispieldaten-2.csv', index_col=0)
Die notwendigen Module werden importiert. Anschliessend wird die CSV-Datei mit dem Jahresabschluss eingelesen. Iterable hilft, Typen präzise anzugeben und macht den Code übersichtlicher.
def _check_konto(ledger: pd.DataFrame, konti: Iterable[int]) -> bool:
return any(konto in ledger.index for konto in konti)
Prüft, ob ein bestimmter Satz an Kontonummern im gegebenen Jahresabschluss enthalten ist.
def _get_total_absch(ledger: pd.DataFrame) -> float:
konti = (ledger.index >= 6800) & (ledger.index < 6900)
total_absch = ledger.loc[konti, 'Abschluss'].sum() * -1
return total_absch
Berechnet die gesamten Abschreibungen aus den Konten 6800–6899 im Abschluss.
def _check_wb_mob(ledger: pd.DataFrame) -> bool:
return _check_konto(ledger, [1509, 1519, 1529, 1539, 1549])
def _check_wb_immo(ledger: pd.DataFrame) -> bool:
return _check_konto(ledger, [1609])
Diese Funktionen prüfen, ob Wertberichtigungskonten für Mobilien bzw. Immobilien im Jahresabschluss enthalten sind.
def _get_delta_wb_mob(ledger: pd.DataFrame) -> float:
konti = ledger.index.intersection([1509, 1519, 1529, 1539, 1549])
if konti.empty:
return 0
return (ledger.loc[konti, 'Abschluss'].sum() - ledger.loc[konti, 'Eroeffnung'].sum()) * -1
def _get_delta_wb_immo(ledger: pd.DataFrame) -> float:
if _check_wb_immo(ledger):
return (ledger.loc[1609, 'Abschluss'] - ledger.loc[1609, 'Eroeffnung']) * -1
return 0
Berechnet die Veränderung der Wertberichtigungen auf Mobilien und Immobilien als Teil der Investitionsrechnung.
def _get_absch_mob(ledger: pd.DataFrame) -> float:
absch = _get_total_absch(ledger)
if _check_wb_mob(ledger):
return _get_delta_wb_mob(ledger)
delta_wb_immo = _get_delta_wb_immo(ledger)
if delta_wb_immo < 0:
return absch
return absch - delta_wb_immo
def _get_absch_immo(ledger: pd.DataFrame) -> float:
if _check_wb_immo(ledger):
return _get_delta_wb_immo(ledger)
return _get_total_absch(ledger) + _get_absch_mob(ledger)
Berechnung der Abschreibungen für Mobilien und Immobilien – abhängig davon, ob direkt oder über Wertberichtigungen gebucht wurde.
def _get_invest_mob(ledger: pd.DataFrame) -> float:
konti = ledger.index.intersection([1500, 1510, 1520, 1530, 1540])
invest_mob = (ledger.loc[konti, 'Abschluss'] - ledger.loc[konti, 'Eroeffnung']).sum()
if not _check_wb_mob(ledger):
invest_mob += _get_absch_mob(ledger)
return invest_mob
def _get_invest_immo(ledger: pd.DataFrame) -> float:
detla_immo = ledger.loc[1600, 'Abschluss'] - ledger.loc[1600, 'Eroeffnung']
absch_immo = _get_absch_immo(ledger)
if detla_immo * -1 == absch_immo:
return 0
return detla_immo + absch_immo
Diese Funktionen berechnen die Nettoinvestitionen in Mobilien und Immobilien aus dem Jahresabschluss.
from tabulate import tabulate
def investitionsbereich(ledger: pd.DataFrame):
positionen = {
'Mobilien': _get_invest_mob(ledger),
'Immobilien': _get_invest_immo(ledger),
}
nettoinvestitionen = positionen['Mobilien'] + positionen['Immobilien']
table = [[key, f"{value:,.2f} CHF"] for key, value in positionen.items() if value != 0]
table.append(["Nettoinvestitionen", f"{nettoinvestitionen:,.2f} CHF"])
print('Mittelfluss aus Investitionen\\n')
print(tabulate(table, headers=['Position', 'Betrag'], tablefmt='github'))
investitionsbereich(jahresabschluss)
Die Gesamtsumme der Investitionen wird hier in einer Tabelle angezeigt – unterteilt in Mobilien und Immobilien. Tabulate hilft auch hier bei der Angabe der Daten.
Allgemein kann ich sagen, dass ich sowohl die technologischen als auch die buchhalterischen Aspekte dieser Arbeit verstanden habe. Ich hätte keine Schwierigkeiten, den Code neu zu programmieren oder in komplexeren Projekten wiederzuverwenden, mithilfe meiner Notizen und der dokumentierten Syntax. In der Praxis lassen sich die erlernten Inhalte gut anwenden, zum Beispiel wenn man später in einem Unternehmen im Bereich Buchhaltung tätig ist und Arbeitsprozesse automatisieren möchte, oder auch, wenn man ein eigenes Unternehmen führt. Dennoch ist die Welt der Finanzen weitaus umfangreicher, und es gibt viele Möglichkeiten, das Projekt weiter auszubauen, beispielsweise durch zusätzliche Funktionen oder den Einsatz neuer Technologien, wie zum Beispiel eine automatisierte Abschreibungenberechnung, die Abschreibungen automatisiert berechnet und den jährlichen Rechenaufwand abnimmt. Ausserdem könnte man die entwickelten Technologien auch kommerziell weiterverwenden, zum Beispiel in Form einer App, in der man Finanzdaten im CSV-Format einliest und daraufhin automatisch eine Bilanz, Erfolgsrechnung sowie Geldflussrechnung generiert.
Während meines Projekts habe ich viele konkrete Dinge gelernt, vor allem im Umgang mit Daten und Datumswerten. Hier sind die wichtigsten Kenntnisse, die ich mir angeeignet habe:
Was mir dabei besonders aufgefallen ist: Viele Funktionen in meinem Projekt basieren nicht nur auf einem dieser Punkte allein, sondern auf der Kombination mehrerer dieser Kenntnisse. Zum Beispiel war es oft nötig, gleichzeitig zu prüfen, ob ein Tag ein Wochenende oder Feiertag ist und dann auch die Beträge herauszufiltern war immer gleich, aber das kombinieren hat das Projekt ausgemacht. Das Zusammenspiel dieser Fähigkeiten war also entscheidend, um das Projekt erfolgreich umzusetzen und gar nicht unbedingt viel Wissen. Ein sehr gutes Vorgehen ist immer zuerst die Logik dahinter zu verstehen und es dann zu programmieren, so kann man sehr viel Zeit und Aufwand sparen.
Das vorliegende Projekt wurde eigenständig auf Grundlage des Unterrichtsskripts sowie eigener Notizen umgesetzt. Zur Unterstützung beim Programmieren kam GitHub Copilot zum Einsatz – ein KI-gestütztes System, das in Visual Studio Code integriert ist und kontextabhängige Vorschläge für Codeergänzungen, Vervollständigungen und Verbesserungen unterbreitet. Die Verwendung von GitHub Copilot erfolgte ausschliesslich zur technischen Unterstützung beim Codieren, insbesondere zur automatischen Vervollständigung bekannter Muster, Strukturen und Syntax. Copilot arbeitet promptfrei, das heisst, es wurden keine aktiven Eingaben oder Chatverläufe zur Generierung von Vorschlägen verwendet. Alle inhaltlichen, konzeptionellen und logischen Entscheidungen wurden eigenständig getroffen. Die KI wurde nicht zur Entwicklung neuer Ideen oder zur Lösung fachlicher Problemstellungen herangezogen. Erstellt mit Hilfe von ChatGPT, OpenAI
Die vollständige Urheberschaft dieses Projekts liegt bei mir (Riccardo Ambühl), soweit nicht anders angegeben. Sämtliche Inhalte, Strukturen und Entscheidungen stammen eigenständig von mir. Drittinhalte (z. B. Icons oder Vorlagen) wurden gemäss ihrer jeweiligen Lizenz eingebunden und entsprechend gekennzeichnet.
Vielen Dank für Ihre Aufmerksamkeit!