In einem früheren Artikel habe ich gezeigt, wie ich die 200-Tageslinie mit einem Python-Script und der Stooq-API berechne. Das Script funktionierte – aber es lief lokal, die Daten mussten manuell aktualisiert werden, und die Ergebnisse verschwanden, sobald das Terminal geschlossen wurde. Der nächste logische Schritt war klar: eine vollwertige Web-App.

Entstanden ist ein Django-Dashboard für Aktienanalyse mit OHLC-Charts, automatischer täglicher Datenpflege und Portfolio-Tracking – selbst gehostet, ohne Cloud-Abhängigkeiten.

Architektur im Überblick

  • Datenmodell: Stock (Symbol, Name), StockDailyMetrics (OHLC-Daten pro Tag), Account und Transaction für Portfolio-Tracking
  • Datenpflege: APScheduler läuft täglich früh morgens und aktualisiert alle Aktien automatisch
  • Frontend: Django-Templates mit Chart.js für OHLC-Visualisierung

Datenabruf mit yfinance und curl_cffi

yfinance ist die einfachste Möglichkeit, historische Kursdaten kostenlos zu beziehen. Das Problem: Yahoo Finance blockiert reguläre Requests mit 429-Fehlern. Die Lösung ist Browser-Impersonation über curl_cffi:

import yfinance as yf
from curl_cffi import requests as cffi_requests

session = cffi_requests.Session(impersonate="chrome")
ticker = yf.Ticker(symbol, session=session)
hist = ticker.history(period="2y")

for date, row in hist.iterrows():
    StockDailyMetrics.objects.update_or_create(
        stock=stock,
        date=date.date(),
        defaults={
            "open": row["Open"],
            "high": row["High"],
            "low": row["Low"],
            "close": row["Close"],
            "volume": row["Volume"],
        }
    )

APScheduler: Automatische Updates ohne Celery

Für wiederkehrende Hintergrundaufgaben in Django gibt es zwei verbreitete Ansätze: Celery (mächtig, aber komplex) und APScheduler (einfach, kein Redis nötig). Für diesen Anwendungsfall reicht APScheduler vollständig:

from apscheduler.schedulers.background import BackgroundScheduler
from django.apps import AppConfig
import os

class StockAnalysisConfig(AppConfig):
    def ready(self):
        # Verhindert Doppelstart im Django Dev-Server
        if os.environ.get("RUN_MAIN") != "true":
            return
        scheduler = BackgroundScheduler(timezone="Europe/Berlin")
        scheduler.add_job(
            refresh_all_stocks,
            "cron",
            hour=3, minute=10,
            id="daily_stock_refresh",
            replace_existing=True,
        )
        scheduler.start()

Der RUN_MAIN-Check ist wichtig: Django startet ready() zweimal im Development-Server – ohne diese Prüfung würde der Scheduler doppelt starten.

Die 200-Tageslinie im Dashboard

Die 200-Tageslinie wird dynamisch aus den vorhandenen Schlusskursen berechnet:

def calculate_sma200(stock):
    closes = list(
        StockDailyMetrics.objects
        .filter(stock=stock)
        .order_by("date")
        .values_list("close", flat=True)
    )
    if len(closes) < 200:
        return None
    return sum(closes[-200:]) / 200

Im Chart wird die SMA-200-Linie als horizontale Referenzlinie eingezeichnet. Liegt der aktuelle Kurs darunter, ist die Aktie laut dieser Metrik im Abwärtstrend.

Portfolio-Tracking

Das Account-Modell repräsentiert ein Broker-Konto, Transaction speichert Käufe und Verkäufe. Daraus wird der aktuelle Depotwert gegen den Einstandspreis berechnet und als Performance-Chart dargestellt.

Fazit

Das Dashboard hat mein Python-Script vollständig ersetzt. Die tägliche Automatisierung bedeutet, dass ich morgens aktuelle Daten vorfinde, ohne etwas tun zu müssen. Alle Daten liegen lokal in SQLite – keine API-Kosten, keine Datenschutzbedenken, vollständige Kontrolle.

Das Dashboard ist Teil dieser Website und unter Aktienanalyse einsehbar. Fragen zur Umsetzung gerne über das Kontaktformular.