📖 Trading System – Wiki

← Startseite
🔍
Stand: …

01 Überblick & Architektur

Wall-Street-Bulle als Sinnbild für das Marktregime dieses Systems

Das System besteht aus zehn eigenständigen Apps plus einer verbindenden Startseite (siehe Kurzüberblick-Tabelle in Abschnitt 3): den vier Kern-Web-Apps Hauptapp, Minervini Coach 2, Minervini Markets 360 und Daily Signal Hub (jeweils eine einzige HTML-Datei), fünf ergänzenden Screening-/Analyse-Tools Price-Action-Hub, Rotation-Dashboard, Markets360 Screener (Streamlit), dem Lokalen Trend-Screener und dem app-übergreifenden Backtest-Vergleich (seit 2026-08-17), sowie einer kuratierten externen Link-Sammlung TraderFox KI-Agenten. Alle projekteigenen Dateien liegen im iCloud-Ordner Trading-System/Maick Trading System und sind damit auf allen Macs synchron; die beiden Streamlit-/Screener-Tools haben ihren Quellcode bewusst in eigenen, externen Projektordnern (siehe deren Abschnitte). Der Mac mini ist der Dauerläufer: Er liefert alle Apps per HTTP aus und stellt die Daten-Endpunkte bereit — dadurch funktioniert alles auch auf iPhone und iPad. Zwingend nötig ist er trotzdem nicht: Startseite, Hauptapp, Coach, Signal-Hub, Price-Action-Hub, Rotation-Dashboard, Backtest-Vergleich und TraderFox KI-Agenten laufen komplett ohne ihn über die Cloudflare-Pages-Version (Abschnitt 2); nur die beiden reinen Scan-Werkzeuge (Markets360 Screener, Trend-Screener) sind als rechenintensive lokale Tools ohne eigenen Cloud-Fallback ausgelegt — ihre Cloud-Nachtläufe (GitHub Actions) speisen ihre Ergebnisse aber ohnehin automatisch in den Signal-Hub ein.

iPhone / iPad / MacBook ──HTTP──► Mac mini (Dauerläufer) │ Port 8090 MTS-Server ────────┤ Startseite, Hauptapp, Coach, Wiki, │ Price-Action-Hub, Rotation-Dashboard, │ Preis-Proxy, /data Port 8080 Markets-360-Server ┤ /markt /fred /sector-perf /status Port 8091 Signal-Hub-Server ─┤ Dashboard, Screening-Lauf, Push Port 8501 Markets360 Screener┤ Streamlit: VCP/RS-Rating-Vollscan Port 8765 Trend-Screener ────┤ Dashboard + /api/* (RS/VCP/Fundamentals) Port 8502 Streamlit-Cockpit ─┘ (optional, erweiterte Analyse) │ iCloud-Ordner = eine Datenquelle für alle Geräte

Live-Status der Server (wird beim Öffnen dieser Seite geprüft):

MTS-Server (8090) … Markets 360 (8080) … Signal-Hub (8091) …
Grundprinzip: Eine App = eine Datei = eine Aufgabe. Die Apps bleiben bewusst getrennt (Entflechtung) und verlinken sich gegenseitig — gemergt wird nichts. Inhalte existieren nur an einem Ort, andere Apps verlinken dorthin.
Minervini Trading Learning: Disziplin schlägt Intuition – täglich.
Leitgedanke: „Disziplin schlägt Intuition – täglich." Genau dafür sind Marktampel, Coach und Regelwerk in diesem System da.

02 Zugriff von allen Geräten

SituationAdresse
Offline-App / unterwegs (empfohlen)https://mts-hub.pages.dev/ — Cloudflare Pages, immer online (HTTPS). Auf dem iPhone in Safari öffnen → „Zum Home-Bildschirm". Läuft offline und ohne WLAN (Service-Worker-Cache); Live-Kurse/FRED über den Cloudflare Worker. Siehe cloudflare-pages/.
Zuhause im WLAN (Mac mini an)http://mac-mini-von-maick.local:8090/
Unterwegs zum Mac (Tailscale)https://mac-mini-von-maick.tail02bccd.ts.net/ohne :8090 (Port), mit https://, ohne „-2" im Namen; tailscale serve leitet HTTPS/443 auf den lokalen 8090-Server um (siehe Abschnitt „HTTPS für die Offline-App" unten). Nur wenn der Mac mini online ist. Korrektur 2026-07-18: zwei Fehler nacheinander behoben — die alte Zeile zeigte http://…:8090/ (falsches Schema/Port), die erste Korrektur hatte zusätzlich einen falschen Hostnamen mit „-2" (existiert im Tailnet nicht, tailscale cert nennt den echten Namen); die tailscale serve-Konfiguration war zudem auf den falschen „-2"-Namen eingerichtet und wurde auf den echten Hostnamen umgestellt.

Die Pages-Version ist der robuste Offline-/Mobil-Zugang (unabhängig vom Mac). Der Mac mini wird noch für KI-Committee und geräteübergreifende Daten-Sync gebraucht; ist er per Tailscale erreichbar, nutzen die Apps ihn automatisch, sonst läuft alles aus Cache + Worker. Die Signal-Hub-Neuberechnung läuft seit 2026-07 zusätzlich vollautomatisch in der Cloud (GitHub Actions, siehe Signal Hub) — braucht den Mini dafür nicht mehr; dessen Zeitplan läuft vorerst nur noch zur Kontrolle parallel. Nach Änderungen an den Apps neu deployen: cloudflare-pages/deploy.command (die Cloud-Pipeline deployt Signal-Hub-Ergebnisse zusätzlich automatisch nach jedem Lauf).

Cloud-Fallback-Hinweis auf der Startseite (seit 2026-07-17). Ist der Mac mini über keinen der Host-Kandidaten (location.hostname / Mac-mini-von-Maick.local / localhost) erreichbar, zeigt index.html jetzt zusätzlich zum „Offline"-Badge einen direkten Link auf https://mts-hub.pages.dev/ — kein automatischer Redirect (ein stiller Host-Wechsel im Hintergrund wäre verwirrend), nur ein sichtbarer Ausweg, damit andere Geräte nicht in einer reinen Fehleranzeige hängen bleiben. Erscheint nicht, wenn die Seite selbst schon auf *.pages.dev läuft.
Zurück zur Startseite. Jede App hat oben links einen 🏠 Start-Button (Link auf /index.html) — funktioniert über Mini, Tailscale und Pages. Die Startseite selbst und das Wiki haben ihn nicht (Wiki hat den „← Startseite"-Link).
Fix 2026-08-15: Nur-Lese-Modus der Hauptapp auf der Cloud-Version entfernt — voll bearbeitbar von jedem Gerät, mit oder ohne laufenden Mac mini. Bisher blockte eine pauschale Origin-Sperre (*.pages.dev) in Maick's Trading System.html jedes Speichern auf der Cloud-Version komplett, obwohl der dafür nötige Cross-Device-Mechanismus — derselbe private GitHub-Gist-Sync wie beim Coach (Token gh_gist_token, Funktionen mtsGistSave/mtsGistLoad) — im Code bereits fertig eingebaut war. Widersprach dem Grundprinzip „Mac mini ist optionaler Bonus, kein Muss" (siehe oben). Die Sperre ist jetzt entfernt: jeder Origin (Mac mini, Tailscale, Pages) speichert gleich — localStorage auf dem jeweiligen Gerät + Gist-Push (falls Token eingerichtet) + optionaler POST /data an den Mini (existiert der Endpunkt nicht, z. B. auf Pages, läuft der Versuch harmlos ins Leere). Damit dabei kein älterer Cloud-Stand frischere lokale Edits verschluckt, vergleicht mtsGistLoad() jetzt Zeitstempel (_meta.lastSaved) vor jedem Überschreiben — genau wie der bereits bestehende /data-Abgleich mit dem Mac mini. Ohne eingerichteten Gist-Token bleiben Änderungen weiterhin nur im localStorage dieses einen Geräts (kein Cross-Device-Sync möglich) — dafür zeigt die App dann oben statt des alten 🔒-Banners einen ☁-Hinweis, den Token im ☁-Panel einzurichten (gleicher Token wie im Coach, einmal auf dem Gerät hinterlegt → in beiden Apps aktiv).
Fix 2026-08-09: Tailscale-Zugriff von einem neuen Gerät zeigte leere Daten statt des echten Mac-mini-Stands. Ursache war kein Netzwerkproblem, sondern ein Timing-Bug beim Start der Hauptapp: Ein Fix, der bei leerer Trade-Liste den Kontostand zurücksetzt, rief dafür sofort MTS.save() auf und stempelte damit _meta.lastSaved auf „jetzt" — auch bei einem komplett frischen Browser, dessen localStorage für diese Origin noch nie beschrieben wurde (z. B. erster Aufruf der Tailscale-Adresse von einem neuen Gerät). Der spätere Server-Sync (holt /data vom Mini und übernimmt es nur, wenn dessen Zeitstempel neuer ist als der lokale) hielt den gerade erst gestempelten leeren lokalen Stand danach für immer für „neuer" als die echten Mac-mini-Daten und übernahm sie nie. Fix: Der Reset-und-Save-Schritt läuft jetzt nur noch, wenn auf diesem Gerät/Origin bereits einmal gespeichert wurde (_meta.lastSaved vorhanden). War ein Gerät vor dem Fix schon betroffen (leerer localStorage-Eintrag bereits „vergiftet"), hilft einmalig in der Browser-Konsole auf der Seite: localStorage.removeItem('mts_v2'); location.reload(); — danach lädt der Server-Sync den echten Stand.
Echte Live-Status-Badges auf der Cloud-Version (seit 2026-07-18). Die Status-Prüfungen auf der Startseite (index.html) versuchen jetzt zusätzlich zu den LAN-Kandidaten (location.hostname, Mac-mini-von-Maick.local, localhost) den Tailscale-Hostnamen mac-mini-von-maick.tail02bccd.ts.net (Konstante TAILSCALE_HOST, Helfer mtsUrl(host) baut je nach Host https://… ohne Port oder http://…:8090). Läuft die Seite auf *.pages.dev und ist der Mac mini per Tailscale erreichbar, zeigen 8090-/Markets-360-/Signal-Hub-/Trend-Screener-Badges jetzt „✓ Live-Daten" statt pauschal „Offline"/„iCloud-Version" — funktioniert, weil server_mts.py für die gelesenen Endpunkte (/status, /markt/*, /Signal-Hub/api/*, /Trend-Screener/*) bereits Access-Control-Allow-Origin: * setzt. Reihenfolge: erst same-origin/LAN (schnell), Tailscale nur als letzter Fallback (etwas höheres Timeout, 3–3,5 s statt 1,5–2 s). Ist der Mac mini auch per Tailscale nicht erreichbar, bleibt es beim bisherigen Offline-Zustand inkl. Cloud-Fallback-Link (siehe oben). Ausnahme seit 2026-07-28: die „Signale"-Kachel zeigt in diesem Fall trotzdem eine echte Zahl statt „–" — ladeSignaleStatisch() liest per Range-Request (nur die ersten ~400 Bytes, nicht die vollen >10 MB) direkt Signal-Hub/data/signals.json, die derselbe Cloud-Deploy ohnehin schon mitbringt, und zeigt die Anzahl mit Badge „☁️ Cloud-Daten" (Tooltip: Stand des letzten Cloud-Laufs) statt „iCloud-Version" ohne Zahl. (Die „Server"/„Preis-Proxy"-Kacheln, die hier ursprünglich standen, gibt es seit 2026-08-12 nicht mehr — siehe Fix unten.)
Umbau 2026-08-12: „Server"/„Preis-Proxy"-Kacheln durch „Cloud-Daten" ersetzt. Die beiden ursprünglichen KPI-Kacheln auf der Startseite prüften ausschließlich Mac-mini-Eigenschaften (Erreichbarkeit, ob yfinance lokal installiert ist) und zeigten dadurch auf *.pages.dev bzw. ohne erreichbaren Mac mini dauerhaft „Offline"/„–" — ein rotes Warnsignal für einen Zustand, der laut Systemdesign (Mac mini ist optionaler Bonus, keine Voraussetzung) gar kein Problem ist. Das sorgte wiederholt für Verunsicherung („warum Server offline, sonst funktioniert doch alles"). Ersetzt durch eine einzige Kachel „Cloud-Daten", die die tatsächlich relevante Information zeigt — ist die Datenlage frisch? — statt eine Geräte-Eigenschaft: „Live" (grün), wenn gerade ein Server (Mac mini/Tailscale) live antwortet, sonst die Uhrzeit des letzten Cloud-Pipeline-Laufs mit Ampel-Farbe nach Alter (<6 h grün, 6–24 h gelb, >24 h rot, exakt dieselben Schwellen wie der Top-Setups-„Stand"-Banner). Funktioniert identisch von jedem Gerät, unabhängig vom Mac-mini-Status — index.html, Funktion setzeCloudFrische(). Das KPI-Grid hat dadurch nur noch 3 statt 4 Kacheln (Cloud-Daten, Signale, S&P heute). Die detaillierten Mac-mini-Infos (LAN-Adresse, Preis-Proxy-Status) stehen weiterhin im Bereich „Netzwerk & Zugriff" weiter unten auf der Startseite — dort als reine technische Zusatzinfo, nicht mehr als Alarm-Kachel oben.
Apps öffnen im neuen Tab — außer in der installierten PWA. Im normalen Browser-Tab öffnet jede App in einem eigenen Tab/Sheet (target="_blank"), damit die Startseite als Absprung erhalten bleibt. Läuft der Hub als installierte Standalone-App (Home-Bildschirm-Icon), navigiert er stattdessen im selben Fenster (siehe Fix 2026-07-05 unten).
Fix 2026-07-05: Service Worker registrierte sich auf Pages nie. Die SW-Registrierung (Manifest/Icon/Theme-Color-Injektion) passierte bisher nur serverseitig im 8090-Server (server_mts.py) — die auf *.pages.dev deployten Dateien enthielten den Registrierungscode gar nicht, wodurch dort nie gecacht wurde und echtes Offline-Verhalten (ohne jede Internetverbindung) unzuverlässig war. cloudflare-pages/deploy.command injiziert das jetzt beim Bauen des Publish-Verzeichnisses selbst in alle HTML-Dateien — ab dem nächsten Deploy cacht der Service Worker auf Pages zuverlässig.
Fix 2026-07-05b: Apps starteten offline nicht, Hub sprang immer zurück zum Start. Der Offline-Cache selbst funktionierte bereits — das eigentliche Problem war target="_blank" auf den App-Karten (index.html): Die installierte Standalone-PWA hat nur ein Fenster, kann also kein „neues Fenster" öffnen. iOS brach die Navigation deshalb ab und blieb auf dem Hub stehen. Fix: target="_blank" wird nur noch im normalen Browser-Tab gesetzt (Prüfung per display-mode: standalone / navigator.standalone); die installierte App navigiert jetzt im selben Fenster.
Fix 2026-08-08: 🔍-Detaillink landete auf Cloudflare Pages im Hub statt in der Setup-Analyse. Signal-Hub/setup-detail.html fehlte in der Kopier-Whitelist von cloudflare-pages/deploy.command — die Datei existierte auf mts-hub.pages.dev schlicht nicht. Ohne eigene _redirects/404.html-Konfiguration liefert Cloudflare Pages für unbekannte Pfade automatisch den Inhalt der Startseite mit Status 200 statt eines echten 404 zurück; der Browser blieb dabei aber auf dem angeforderten /Signal-Hub/…-Pfad stehen, wodurch zusätzlich alle relativen Pfade der zurückgelieferten Startseite doppelt/kaputt wurden. Mit dem Mac mini hatte das nichts zu tun — setup-detail.html liest ausschließlich aus den ohnehin deployten signals.json/pivot.json/priceaction.json und ist wie der Rest bewusst ohne Mac-mini-Abhängigkeit gebaut. Fix: deploy.command kopiert die Datei jetzt mit (neben signal-hub.html/backtest-report.html).
Fix 2026-08-06: Top-Setups-Detaillink (🔍) sprang in der Standalone-PWA ins Leere. Derselbe target="_blank"-Fehler wie beim Fix 2026-07-05b, nur an einer zweiten, übersehenen Stelle: Der 🔍-Link auf die Minervini-Treiber-Analyse (Signal-Hub/setup-detail.html?ticker=…) in den Top-Setups auf der Startseite wird erst nach Seitenaufbau dynamisch erzeugt (renderTopSetups()) und war deshalb von der ursprünglichen Standalone-Prüfung nicht erfasst — er hatte weiterhin fest target="_blank". In der installierten Standalone-PWA (iPhone) brach iOS die Navigation deshalb ab, die App fiel auf den zuletzt gecacheten Stand zurück, statt zur Analyse des angetippten Werts zu springen. Fix: index.html ermittelt IST_STANDALONE_PWA jetzt zentral am Skriptanfang und nutzt dieselbe Prüfung auch beim dynamisch erzeugten Detaillink — target="_blank" nur noch außerhalb der Standalone-PWA.
Fix 2026-07-05c: „Response served by service worker has redirections". Cloudflare Pages leitet jede *.html-URL per 308 auf die endungslose Clean-URL um (/index.html/, /wiki.html/wiki usw.) — solange kein Service Worker eingreift, folgt der Browser dem Redirect normal. Sobald der SW aber (seit Fix 2026-07-05) sauber registriert ist, fängt er die Navigation ab; die per fetch() gefolgte Redirect-Response hat redirected=true, und genau das darf laut Fetch-Spec nicht per respondWith() an eine Navigation zurückgegeben werden — Safari brach mit obiger Fehlermeldung ab. Fix in sw.js: stripRedirectFlag() baut vor Cache-Ablage und vor respondWith() eine frische, redirect-freie Response (new Response(res.body, res)); betrifft Precache und Live-Navigation gleichermaßen (Cache Storage übernimmt das Redirect-Flag sonst mit).
Fix 2026-08-03: Service-Worker-Cache-Version jetzt automatisch. Vorher musste nach jeder Änderung an einer Precache-Datei (index.html u. a.) die Zahl in sw.js (const CACHE = 'mts-pwa-vNN') von Hand hochgezählt werden — sonst blieb die installierte App/PWA für immer auf dem alten Dateistand hängen (dreimal vergessen, zuletzt mit sichtbarem Effekt: veraltete Startseite, Links landeten wieder auf dem alten Cache-Fallback statt der Zielseite). Neues sw_version.py berechnet die Version stattdessen aus einem Hash über den tatsächlichen Inhalt aller Precache-Dateien — ändert sich irgendeine davon, ändert sich automatisch sw.js selbst, der Browser erkennt das über seinen eingebauten Byte-Vergleich und installiert die neue Version ganz ohne manuelles Zutun. Zwei Serving-Wege nutzen dieselbe Logik: server_mts.py (neue Route /sw.js, rendert live pro Anfrage) und cloudflare-pages/deploy.command (neuer Schritt nach dem Kopieren/Injizieren, rendert gegen den finalen Publish-Ordner). Der Wert im Quelltext von sw.js selbst ist nur noch ein Platzhalter.
Fix 2026-08-12: Top-Setups auf der Startseite blieben tagelang auf altem Stand hängen, obwohl die Cloud-Pipeline lief. Server-seitig war nichts kaputt — jeder Cloud-Lauf produzierte pünktlich frische Daten. Ursache war sw.js: Live-Daten unter Signal-Hub/data/… (und den drei Schwester-Ordnern) werden „network-first" behandelt (immer erst frisch vom Netz versuchen), aber die Prüfung griff nur bei Dateiendung .json. Die kleine Zusammenfassungsdatei, die den „Stand"-Banner der Top-Setups speist (top_setups.js), fiel dadurch stattdessen unter die „stale-while-revalidate"-Regel für gewöhnliche Assets: Die zeigt immer zuerst die vorletzte gecachte Version an und aktualisiert den Cache nur im Hintergrund für den nächsten Aufruf. Bei einer installierten Standalone-PWA, die aus dem Hintergrund resumt statt komplett neu zu laden, feuerte dieser Hintergrund-Fetch praktisch nie — der Banner blieb dadurch tage- statt stundenaktuell hängen, auf Mac und iPhone gleichermaßen. Fix: top_setups.js ist jetzt explizit von der network-first-Regel erfasst, genau wie die .json-Dateien.
Fix 2026-08-13: deploy.command fror den Datenstand tagelang ein. Ein Fix vom Vortag ließ deploy.command Signal-Hub/Price-Action-Hub/Rotation-Dashboard-Datendateien immer zuerst vom aktuell live deployten Stand holen (Grund: eine lokale Datei auf einem Mac war tagealt und hatte bei einem manuellen Deploy den frischen Cloud-Stand überschrieben). Das griff aber auch beim automatischen Cloud-Deploy — der ruft dasselbe Skript per GitHub Actions auf, nachdem er die frischen Dateien per rclone aus R2 gezogen hat (siehe deploy.yml). Dort war die „lokale" Kopie die frische, und „Live bevorzugen" hat sie bei jedem automatischen Deploy durch die bereits veraltete Live-Version ersetzt — ein sich selbst verewigender Stillstand, der die Startseite ab dem ursprünglichen Fix für Stunden auf demselben Zeitstempel einfror, obwohl die Pipeline daneben weiterlief und immer wieder „erfolgreich" deployte. Fix: deploy.command unterscheidet jetzt per $GITHUB_ACTIONS-Umgebungsvariable (von Actions automatisch gesetzt) den Kontext — in der Cloud immer die lokale (frische) Kopie nehmen, nur bei einem manuellen Deploy auf einem Mac weiterhin die Live-Version bevorzugen.
Fix 2026-08-21: Trend-Screener-Dashboard zeigte nach einem frischen Cloud-Lauf beim ersten Laden noch den alten Stand. Derselbe Fehler wie beim Fix 2026-08-12, nur an einer zweiten, damals übersehenen Stelle: Trend-Screener/signals.js speist den „Stand"-Zeitstempel im Trend-Screener-Dashboard direkt (analog zu top_setups.js auf der Startseite), liegt aber im App-Root und nicht unter einem …/data/-Pfad — die isProxiedData-Prüfung in sw.js griff dadurch nicht, die Datei fiel unter die „stale-while-revalidate"-Regel und zeigte beim ersten Laden nach einem Deploy die vorletzte gecachte Version. Fix: signals.js ist jetzt wie top_setups.js explizit von der network-first-Regel erfasst.
GitHub-Token nur einmal. Hauptapp und Coach teilen sich denselben GitHub-Token über den gemeinsamen localStorage-Schlüssel gh_gist_token (gleiche Origin). Einmal in einer der beiden Apps eingeben → in der anderen automatisch aktiv; fehlt er, fragt das ☁-Banner danach. Der Token bleibt ein Secret und liegt nur im Browser des Geräts — nie im Code, nie auf Pages (sonst wäre er auf der öffentlichen Seite auslesbar).
Falle 2026-08-17: Gist-Token pro Origin, nicht pro Gerät — und Safari räumt ihn auf pages.dev von selbst wieder weg. Zwei getrennte Effekte, die zusammen wie Datenverlust aussahen, es aber nicht waren: (1) localStorage ist pro Origin isoliert — ein auf mac-mini-von-maick.local:8090/der Tailscale-Adresse eingerichteter Token liegt in einem anderen Speicherbereich als auf mts-hub.pages.dev und muss dort separat eingetragen werden, sonst zeigt genau dieser Origin dauerhaft den ☁-Hinweis „Kein Cloud-Sync eingerichtet" und einen leeren/veralteten Stand (leere trades[] lösen zusätzlich _resetBalancesIfEmpty() aus, Kontostände zeigen dann 0, obwohl mts_data.json auf dem Mac mini unberührt und korrekt ist — MTS.save() pusht zwar bei jedem Origin automatisch debounced an den Gist, aber eben nur, wenn dort überhaupt ein Token hinterlegt ist). War der Token bislang nur auf pages.dev eingerichtet, nie auf dem tatsächlich bearbeiteten Mac-mini-/Tailscale-Origin, blieb der Gist entsprechend auf einem alten Stand stehen. (2) Safaris „Intelligent Tracking Prevention" räumt localStorage selten besuchter Origins nach rund einer Woche automatisch leer — trifft pages.dev besonders hart, weil das laut Konzept genau der Fallback-Pfad ist, der nur bei ausgeschaltetem Mac mini überhaupt aufgerufen wird, also unregelmäßig. Fix/Vorgehen: Token auf jedem tatsächlich genutzten Origin einmal eintragen (auch auf dem Mac-mini-/Tailscale-Origin selbst, nicht nur auf Pages!) — beim Einrichten sucht mtsGistSetup() aktiv nach einem bereits existierenden Gist mit der richtigen Datei (gists.find(...)) statt blind einen neuen anzulegen, das Verbinden ist also gefahrlos wiederholbar. Gegen das ITP-Wegräumen speziell auf pages.dev in Safari hilft „Zum Dock hinzufügen" (macOS Sonoma+) bzw. „Zum Home-Bildschirm" (iOS) für genau diese Adresse — eine installierte Web-App bekommt einen eigenen, von der 7-Tage-Bereinigung ausgenommenen Speicherbereich (apple-mobile-web-app-capable ist in Maick's Trading System.html bereits gesetzt, kein Code nötig). Nur auf Geräten/Browsern nötig, die pages.dev unregelmäßig als Fallback nutzen — der Mac mini selbst braucht das nicht (der ist ja an, wenn er benutzt wird), Chrome/Firefox kennen dieses ITP-Verhalten ohnehin nicht.
☁️ Cloud-Scan manuell anstoßen — von jedem Gerät (seit 2026-07-17, Repo-Struktur seit 2026-07-28 geändert). Signal Hub und Price-Action-Hub (je 🔄 Aktualisieren/☁️ Cloud-Scan starten), Markets 360 (☁️ Cloud-Scan starten, im Kontrollbereich oben) und der Trend-Screener (☁️ Cloud (überall), in der Update-Leiste) haben je einen Button, der den passenden GitHub-Actions-Workflow direkt per REST-API anstößt (POST .../actions/workflows/nightly.yml/dispatches bzw. pipeline.yml) — läuft ohne Mac mini, funktioniert also auch vom iPhone/iPad/MacBook unterwegs. Signal Hub UND Price-Action-Hub lösen beide denselben Workflow aus (Miksch52/signal-hub, pipeline.yml), da Price-Action-Hub dort als Schritt direkt nach Signal-Hub mitläuft. Signal Hub versucht bei erreichbarem Mac mini weiterhin zuerst den lokalen, sofortigen Lauf; erst wenn das fehlschlägt oder die Seite über *.pages.dev läuft, kommt der Cloud-Trigger.

Einmalige Einrichtung pro Gerät: eigener, separater Token nötig (nicht der gh_gist_token — der hat nur Gist-Rechte). Unter github.com/settings/personal-access-tokens/new ein fine-grained Personal Access Token erstellen: Resource owner Miksch52, „Only select repositories" → signal-hub, minervini-markets-360, lokaler-trend-screener auswählen (nicht mehr maick-trading-system — dessen Deploy läuft seit dem Repo-Split server-seitig, kein Browser-Klick nötig), unter Permissions → Repository permissions → „Actions": Read and write setzen (sonst nichts). Beim ersten Klick auf einen der Buttons fragt die App danach und merkt sich ihn in localStorage (Schlüssel gh_actions_token) — pro Gerät einmal einfügen, genau wie beim Gist-Token. Bei 401/403 (Token abgelaufen/falscher Scope) sowie 404 (Fix 2026-08-14 — GitHub meldet fehlende Repo-Berechtigung eines Fine-grained-PATs bei workflow_dispatch bewusst als 404 statt 403, siehe Abschnitt 7) wird der Token automatisch gelöscht und beim nächsten Klick neu abgefragt.

iPhone/iPad als Offline-App (PWA) einrichten

Damit eine App auch bei ausgeschaltetem Mini startet, braucht es einen Service Worker — und der läuft nur über HTTPS. Deshalb dafür die https://…ts.net/-Adresse verwenden. Die http://…-Adressen funktionieren weiter, aber nur solange der Server erreichbar ist.

  1. Die https://…ts.net/-Adresse in Safari öffnen (Mini an, Tailscale aktiv)
  2. Teilen-Symbol → „Zum Home-Bildschirm"
  3. Beim ersten Start cacht der Service Worker die App-Dateien auf dem Gerät
  4. Danach startet die App auch unterwegs ohne Mini: Kurse kommen direkt von Yahoo (CORS-Proxy), das Portfolio aus dem localStorage
Tailscale auf dem iPhone aktiv lassen. Die *.ts.net-Adresse löst nur auf, wenn der Tailscale-Client läuft — sonst startet die installierte App unterwegs nicht. Tailscale ist für genau diesen Dauerbetrieb gemacht.
Wichtig: Auf iPhone/iPad nie die HTML-Datei aus der Dateien-App öffnen — dort läuft kein JavaScript, nichts funktioniert. Immer eine http(s)://…-Adresse verwenden.

03 Die Apps

Kurzüberblick — alle zehn Apps in der Reihenfolge, in der sie auf der Startseite erscheinen. Details siehe jeweilige Karte unten.

AppKurzbeschreibungPort / Zugriff
🎯 HauptappPortfolio, Risiko, Trade-Planer, FIRE-Kalkulator8090 (statisch)
🧠 Minervini Coach 2Lernfortschritt, Quiz, Academy, Mental8090 (statisch)
📊 Minervini Markets 360Marktampel, Technik, Breite, Sentiment, Makro8080
🛰️ Daily Signal HubTägliche Score-Ideenliste aus 5 Quellen + Push8091 (via 8090-Proxy)
📐 Price-Action-HubCandlestick-Muster auf denselben Signal-Hub-Tickern8090 (statisch)
🔄 Rotation-DashboardSektor-/Themen-Rotation mit IBD-Relative-Strength8090 (statisch)
📊 Backtest-VergleichFilterbarer Forward-Test-Vergleich über alle fünf Backtest-Engines8090 (statisch)
🔍 Markets360 ScreenerVCP/RS-Rating/Fab-5-Vollscan (Streamlit)8501
📈 Lokaler Trend-ScreenerRS-Ranking/VCP/Code-33-Fundamentalfilter8765 (via 8090-Proxy)
🤖 TraderFox KI-AgentenKuratierte Links zu 7 externen TraderFox-Research-Agenten8090 (statisch)

🏠 Startseite / Hub (index.html)

Verteiler zu allen Apps mit Live-Status-Badges. Jede Karte prüft beim Laden, ob der zugehörige Server läuft („✓ Live-Daten") und schaltet dann automatisch auf die Live-Version um; ohne Server bleibt die statische iCloud-Version verlinkt (Badge „iCloud-Version").

🚦 Einheitliche Marktampel (seit 2026-07-25, seit 08/2026 auch die Hauptapp): Startseite, Signal-Hub, Markets 360 und die Hauptapp (Markt-Chip, Trade-Gate, Exposure-Deckel) zeigen jetzt exakt dieselbe volle Minervini-Marktampel — eine geteilte Datei assets/marktampel.js (1:1-Portierung von minervini360.scoring.market: Index-Trend 3/4-Kriterien, Distribution Days, VIX, Small Caps, 52-W-Abstand, seit 08/2026 zusätzlich Follow-Through-Day und 10-Jahres-Rendite, Sentiment-Dämpfung), die alle vier Apps laden und live über den Cloudflare-Worker rechnen (^GSPC/^IXIC/^VIX/^RUT/^TNX) — funktioniert ohne Mac mini. Vorher nutzten Startseite und Signal-Hub einen simplen MA50/MA200-Check und die Hauptapp einen eigenen, strengeren S&P/VIX-Check ohne Cloud-Fallback (nur bei erreichbarem 8080-Server); Markets 360 rechnete die volle Ampel → je nach App unterschiedliche Farben bei denselben Daten. Jetzt ist die Farbe überall gleich; die konservative MA50-Vorsicht steckt nur noch in der Exposure-Bandbreite (grün, aber Kurs unter MA50 → „~75 %" statt „100 %"). Der Signal-Hub-Chip zeigt die volle Ampel für US, EU bleibt der einfache Index-Check (keine volle EU-Ampel). Bei Änderungen an der Python-Engine muss assets/marktampel.js nachgezogen werden (wie schon die Dashboard-JS-Portierung). Wird der Signal-Hub per zumLiveServer() auf den 8091-Server umgeleitet, liefert dieser /assets/ aus dem Repo-Root mit (neue Route in Signal-Hub/src/server.py). Markets 360 bindet assets/marktampel.js jetzt ebenfalls ein (Fix 08/2026): Bis dahin hatte Minervini Dashboard.html eine eigene, komplett duplizierte Kopie der Fallback-Berechnung fest einprogrammiert (griff, wenn /marktampel vom 8080-Server nicht erreichbar ist, z. B. auf Cloudflare Pages) — diese Kopie war seit der Follow-Through-Day/10-Jahres-Rendite-Erweiterung nicht nachgezogen worden und zeigte auf Pages deshalb still weniger Faktoren als das Server-Backend, außerdem fehlte ihr die „Tendenz Richtung X"-Erkennung komplett. Minervini/server.py liefert dafür jetzt ebenfalls /assets/ aus dem Projekt-Root aus (analog zur Signal-Hub-Route), und der Fallback ruft nur noch MTSAmpel.berechne() statt der eigenen Kopie. Der zuvor separate Button „Ampel neu laden" wurde entfernt (redundant zu „Live Daten abrufen", das die Ampel ohnehin mit aktualisiert, und ohne sichtbares Feedback bei Klick — der 5-Minuten-Cache im 8080-Server ließ ihn oft wirkungslos wirken). Zweit-Anzeige „Schnell-Check" in Markets 360 (unter der Haupt-Ampel, renderSchnellCheck()): zeigt zusätzlich die strengere Positionsgrößen-Ampel (grün nur bei Kurs > MA50, dieselbe Logik wie die Startseiten-Exposure) mit den konkreten S&P-Werten (Kurs/MA50/MA200) und einem klaren Hinweis, wo sie von der vollen Ampel abweicht und warum (Trend grün, aber Kurs unter MA50 → Positionsgrößen reduzieren). So ist der Unterschied im Dashboard selbst transparent, statt als scheinbarer Widerspruch.

⚠️ Tendenz Richtung Gelb/Grün/Rot (MTSAmpel.tendenz() in assets/marktampel.js, seit 08/2026 auf allen vier Grenzen): Frühwarnung auf der Startseite (Hero-Box unter der Ampel + „Heute wichtig"-Text) und seit 08/2026 auch in Markets 360 (Box unter der Score-Leiste, #ampelTendenz) — erscheint nur, wenn die Ampel wirklich auf der Kippe steht, nicht bei jedem einzelnen Warnfaktor (sonst wäre der Hinweis dauerhaft aktiv und würde seinen Frühwarnwert verlieren). Deckt alle vier Übergänge ab, jeder über die Größe, die den jeweiligen Kipppunkt tatsächlich bestimmt:

  • Grün → Gelb: Ampel steht auf Grün, aber es fehlt nur noch ein einziger roter Sentiment-Faktor bis zur Dämpfungsschwelle (aktuell 3) — „Tendenz Richtung Gelb – N/3 Warnfaktoren aktiv" mit den konkreten Faktornamen.
  • Gelb → Grün: Ampel ist nur wegen der Sentiment-Dämpfung gelb (der Leitindex-Trend selbst wäre grün) und genau ein roter Faktor müsste sich erholen, um die Dämpfungsschwelle zu unterschreiten.
  • Gelb → Rot: einer der beiden Leitindizes (S&P 500/Nasdaq) ist bereits im Abwärtstrend (Index-Kriterien-Status „Rot"), der andere nur neutral statt bullisch — der exakte Kipppunkt der Trend-Kombinationslogik.
  • Rot → Gelb: beide Leitindizes im Abwärtstrend, aber mindestens einer erfüllt trotzdem schon wieder 2 von 4 Einzelkriterien — näher an der Erholung als ein Markt, in dem beide Indizes vollständig gebrochen sind.

Dieselbe Funktion ist über window.MTSAmpel für alle Apps nutzbar, aktuell verdrahtet auf Startseite und Markets 360.

Exposure-Empfehlung (Hero): Die Ampel oben zeigt zusätzlich zur Stufe (🟢 Aggressiv / 🟡 Neutral / 🔴 Defensiv) die empfohlene Aktienquote als konkreten Handlungswert: bis 100 % (Aggressiv, Kurs > MA50 > MA200 & MA50 steigt), bis ~75 % (Aggressiv, aber MA50 flach/fällt — Aufwärtstrend noch fragil), max. ~50 % (Neutral, Kurs über MA200 aber unter MA50), 0–25 % (Defensiv, Kurs unter MA200). Das ist die schnelle Cockpit-Sicht (ein Blick genügt); die harte Kappung der Positionsgröße macht weiterhin der „📊 Exposure-Deckel nach Marktampel" in der Hauptapp (siehe dort) — die Prozentbänder sind bewusst konsistent gehalten.

🏆 Top-Setups heute (Panel unter „Heute wichtig", seit 2026-07-24): zeigt die Schnittmenge, die man sonst über drei Dashboards manuell kreuzen müsste — Score ≥ 70 (Signal-Hub) ∧ ARMED/BREAKOUT (Pivot-Detektor) ∧ Price-Action bullisch (PA-Score > 0). Datenquelle ist eine winzige Zusammenfassung (Signal-Hub/data/top_setups.js, ~5 KB), die der Aggregator Price-Action-Hub/src/top_setups.py als letzter Pipeline-Schritt aus signals.json + pivot.json + priceaction.json per reinem JSON-Join baut (kein Cross-App-Python-Import — Entflechtung; die Startseite lädt so nicht die 11,8 MB signals.js + 5,7 MB priceaction.js). Das Markt-Regime wird pro Eintrag mitgeliefert und weich angewandt: Setups in grünem Regime (und ohne Earnings-Sperre) sind aktiv und verlinken direkt in den Trade-Planner (Entry = Pivot, Stop = Basis-Tief, siehe Trade-Funnel); in gelbem/rotem Regime oder mit Earnings-Sperre erscheinen sie gedämpft mit Minervini-Hinweis und verlinken zur SEPA-Analyse (prüfen statt handeln) — so ist das Panel auch an nicht-grünen Tagen informativ statt leer. Fehlt die Datei (vor dem ersten Lauf), bleibt das Panel ausgeblendet. Auf Pages mitdeployt (deploy.command-Whitelist). Anzeige-Limit (seit 2026-08-17, vorher 5): renderTopSetups()::LIMIT zeigt jetzt 20 Treffer direkt, der Rest bleibt weiterhin hinter „N weitere anzeigen" (<details>) aufklappbar — der Backend-Deckel top_setups.py::MAX_SETUPS wurde dafür von 24 auf 40 angehoben, damit die Aufklappliste an Treffer-reichen Tagen noch etwas zu zeigen hat. ⭐🎯🔥 Konfluenz & Kern-Setups (seit 2026-08-17): drei zusätzliche, rein additive Signale (kein zusätzlicher Filter — jedes bisherige Top-Setup bleibt in der Liste), die Minervinis/O'Neils Grundprinzip „mehrere unabhängige Bestätigungen schlagen ein Einzelsignal" auf das Panel anwenden: ⭐ Kern-Setup — der Aggregator liest zusätzlich pivot_backtest.json (liegt im selben Job wie signals.json/pivot.json vor, kein Cross-Job-Umweg nötig) und markiert Setups, deren Pivot-Status (ARMED/BREAKOUT) im unverzerrten Forward-Test bei mindestens 8 gereiften Picks eine Win-Rate ≥ 60 % zeigt (top_setups.py::KERN_REIFE_N/KERN_WIN_SCHWELLE) — Goldrahmen + Sortierung nach ganz oben, historisch am besten bestätigte Kohorte sticht damit sofort ins Auge. 🎯 Konfluenz-Score (Zählweise korrigiert 2026-08-20) — durchgezählter 0–2-Score, zählt nur die beiden Kriterien, die zwischen den Zeilen tatsächlich unterscheiden: quellen_unabhaengig ≥ 2 (unabhängige externe Engines, aus signals.jsons quellen.unabhängig, dieselbe Grundlage wie der „🔗 N× bestätigt"-Badge im Signal-Hub-Dashboard) und Rotation-Leader (nächster Punkt). Signal-Score, Pivot-Status und Price-Action-Richtung sind für jedes Top-Setup per Definition erfüllt (die drei Gates der Schnittmenge selbst) und bleiben deshalb nur noch als Kontext im Tooltip stehen, zählen aber nicht mehr in den Badge-Wert hinein — vorher landete dadurch fast jedes Setup bei „3/5" und täuschte eine Differenzierung vor, die es kaum gab. Tooltip listet weiterhin alle fünf Punkte mit ✓/– auf; Farbe hebt 2/2 (Gold) und 1/2 (Türkis) hervor. Komplett clientseitig in index.html::row() berechnet, keine neuen Backend-Felder nötig. 🔥 Leader — erstmals fließt das Rotation-Dashboard in Top-Setups ein: Ticker, die dort in der Leader-Liste eines aktuell führenden Sektor-/Themen-Rotationsthemas stehen (O'Neil: „buy leaders in leading groups"), bekommen ein Leader-Badge mit Thema + RS-Rating im Tooltip (fließt auch als fünftes Kriterium in den Konfluenz-Score ein). Bewusst rein clientseitig in index.html gejoint (ladeRotationLeaderMap() lädt zusätzlich das winzige Rotation-Dashboard/data/rotation.js), nicht im Python-Aggregator: Price-Action-Hub und Rotation-Dashboard laufen in der Cloud-Pipeline als parallele Jobs (siehe „Cloud-Workflows" oben, Diamant-Muster) — zum Zeitpunkt von top_setups.py existiert rotation.json auf demselben Runner noch gar nicht, ein serverseitiger Join hätte eine Jobreihenfolge-Abhängigkeit erzwungen, die es bewusst nicht gibt. 📬 Push (seit 2026-08-09): derselbe Aggregator-Lauf schickt neue Ticker in dieser Schnittmenge zusätzlich als eigenen ntfy-Push „🏆 X neue Top-Setups" — bei jedem Pipeline-Lauf (auch manuellem „☁️ Cloud-Scan starten"), nicht an die vier festen Signal-Hub-Slots gekoppelt; Details siehe „Push-Quellen im Überblick" im Signal-Hub-Abschnitt. 🔍 Setup-Analyse (seit 2026-08-02, Signal-Hub/setup-detail.html?ticker=…): jede Zeile hat neben dem Haupt-Link (Trade-Planner/SEPA) ein eigenes 🔍-Icon, das die neue Detailseite in einem separaten Tab öffnet — ein sofortiger Minervini-Überblick über alle Treiber für genau diesen Ticker: die 11 Score-Faktoren aus signals.json (Trend-Template, relative Stärke, Volumen, Branchenstärke, Fundamental/CANSLIM…) mit Ampel + Klartext-Begründung, der volle Pivot-Kennzahlenblock (Basis-Range, Dry-up, Supply-Score, Stop) aus pivot.json — seit 2026-08-02 zusätzlich ein Risiko-Warnhinweis (pivot.py::_stop_info: Stop-Distanz > 8 % gilt für ein enges VCP-Setup als untypisch weit und wird mit ⚠️ markiert, reiner Hinweis ohne Score-/Status-Auswirkung) sowie ein rein informatives Kursziel + Chance/Risiko-Verhältnis (klassische Measured-Move-Projektion: Basis-Höhe ab Pivot nochmal aufgesetzt). Bewusst kein Kauf-/Verkaufssignal — Minervinis Methode tradet ohne festes Kursziel, sondern trailt den Stop und verkauft in Stärke; das Ziel dient nur der groben Einordnung, wie viel Luft ein Setup bei intaktem Trend hätte — sowie die Price-Action-Muster (Trendbar, Bar-Counting, Breakout, Gap, Marktstadium) aus Price-Action-Hub/data/priceaction.json, dazu ein echtes TradingView-Chart-Widget (seit 2026-08-02, ersetzt den anfänglichen lokalen SVG-Chart) mit SMA50/150/200-Studies und Links „Vollbild auf TradingView"/„Finviz-Chart öffnen". Yahoo-Börsensuffixe (.DE/.PA/.L/.SW/.AS/.MI/.ST/.OL/.CO) werden auf die passenden TradingView-Exchange-Codes (XETR/EURONEXT/LSE/SIX/MIL/OMXSTO/OSL/OMXCOP) gemappt, einzeln verifiziert statt geraten. Bekannte Grenze: TradingViews kostenloser Embed verweigert manchen Nicht-US-Börsen die Live-Daten („Symbol nur bei TradingView verfügbar") — dann zeigt ein Hinweistext unter dem Chart auf den Vollbild-Link. Technisch sonst derselbe Aufbau wie der Top-Setups-Aggregator selbst — ein reiner Frontend-JSON-Join der drei fertigen Ausgabedateien, kein neuer Server-Endpunkt, keine Cross-App-Importe. Funktioniert für jeden Ticker, der in signals.json auftaucht, nicht nur für die Top-Setups (direkter Aufruf per URL-Parameter). 📰 Fundamentalanalyse & Story (seit 2026-08-02): zusätzlicher Abschnitt, der beim Öffnen der Seite live nachlädt — anders als der Rest der Seite (feste Pipeline-Momentaufnahme) ruft dieser Block bei jedem Aufruf frisch den /story-Endpunkt des mts-cors-Cloudflare-Workers auf (siehe cloudflare-worker/README.md), der serverseitig Yahoo-Fundamentaldaten + aktuelle News holt und daraus über Cloudflare Workers AI (@cf/meta/llama-3.1-8b-instruct-fp8, kostenloses Kontingent im selben Cloudflare-Konto — kein bezahlter externer API-Key, kein Secret nötig) eine kurze deutsche Zusammenfassung schreibt: 2–3 Sätze „was macht das Unternehmen", 2–4 Sätze „warum gerade interessant/welche Story" — bewusst rein informativ, keine Kauf-/Verkaufsempfehlung, kein Kursziel (siehe Disclaimer im Antworttext). Dazu Kennzahlen (Marktkap., KGV, Umsatz-/Gewinnwachstum, Analysten-Konsens) und bis zu 6 aktuelle Schlagzeilen mit Link. 20-Minuten-Edge-Cache je Ticker verhindert doppelte Yahoo-/KI-Aufrufe bei mehrfachem Öffnen kurz hintereinander. Yahoo verlangt für die Fundamentaldaten einen Cookie+Crumb-Handshake (yahooCrumb() im Worker), da anonyme quoteSummary-Anfragen sonst abgelehnt werden. Ist der Worker nicht erreichbar, zeigt der Block einen Fehlertext plus Direktlink zu Yahoo Finance statt die Seite zu blockieren — der Rest der Setup-Analyse (Score, Pivot, Price-Action) bleibt davon unberührt.

🗒️ Watchlist (kleiner Button neben dem Panel-Titel, seit 16.08.2026): exportiert die aktuell angezeigten Top-Setups (der Zweig, der auch in der Liste zu sehen ist — aktive Setups, oder falls keine im grünen Regime die wartenden Kandidaten) nach Watchlisten/Hauptapp/ im MTS-Hauptordner, gleiches Dateiformat wie bei Signal-Hub/Price-Action-Hub/Trend-Screener (TradingView-.txt, lesbare Zusammenfassung, reine Tickerliste). Nutzt denselben neuen Endpunkt POST /api/watchlist in server_mts.py, den auch der Price-Action-Hub verwendet (kein eigener Port für die Startseite) — funktioniert nur mit erreichbarem lokalem Server, nicht auf der reinen Pages-Version.

🥇 Code 33 + zusammengeführte Fundamentaldaten (seit 2026-08-09): die vorher getrennten Abschnitte „Fundamentale Treiber" (die synchronen Score-Faktoren aus signals.json) und „Fundamentalanalyse & Story" (der live nachladende Yahoo/KI-Block) stehen jetzt unter einer gemeinsamen Überschrift „💵 Fundamentaldaten & Story" direkt hintereinander, statt an zwei verschiedenen Stellen der Seite zu erscheinen — alle Fundamentaldaten zu einem Ticker sind so an einem Ort. Neu darin: eine Ampelkarte „Code 33" nach Mark Minervini (Quelle: aktienmagazin.de „Die Strategie zur ersten Million", Grundidee: EPS, Umsatz und Nettogewinnmarge steigen drei Quartale in Folge). Die konkreten Schwellenwerte stammen aus Tabelle 4 desselben Artikels („Screening Parameter" → „Umsetzung in TraderFox", vom Nutzer als Bild bereitgestellt, im Fließtext des Artikels nicht auslesbar): EPS-Wachstum Quartal ggü. Vorjahr > 40 %, Umsatzwachstum Quartal ggü. Vorjahr > 7 %, Nettogewinnmarge um mehr als 2 Prozentpunkte verbessert (2–3 Quartale zurückgerechnet, erfüllt wenn einer der beiden Vergleichszeiträume die Schwelle reißt) — grün bei allen drei erfüllten Kriterien, gelb bei 1–2, rot bei keinem. Bewusst nicht mitgerechnet: die in derselben Tabelle als „optional" markierte „Stabilität Nettogewinnmarge (0,7–1,0; 3 Jahre)" — eine proprietäre TraderFox-Kennzahl ohne öffentlich dokumentierte Formel, die zudem 3 Jahre Quartalshistorie bräuchte. Berechnet wird das serverseitig im mts-cors-Worker (fetchCode33() in cloudflare-worker/mts-cors-proxy.js) über Yahoos fundamentals-timeseries-Endpunkt statt des einfachen quoteSummary-Moduls „earnings" — Letzteres liefert nur 4 Quartale ohne Vorjahresbasis für einen echten YoY-Vergleich, während fundamentals-timeseries trotz angefragtem 3-Jahres-Fenster in der Praxis nur ca. 5 Quartale zurückgibt (gegen mehrere Ticker verifiziert), aber genau das für einen einzelnen Vorjahresvergleich reicht. Die drei Kennzahlen-Reihen (Umsatz/EPS/Nettogewinn) sind dabei nicht zwingend gleich datiert — deshalb überall über das Quartalsdatum statt über die Arrayposition verknüpft. Kommt als Feld fundamentals.code33 mit der ohnehin schon vorhandenen /story-Antwort (parallel zum quoteSummary-Aufruf per Promise.allSettled, kein zusätzlicher Request-Roundtrip). Kein passendes Vorjahresquartal bei Yahoo gefunden (z. B. junge Börsengänge oder manche Nicht-US-Werte) zeigt einen entsprechenden Hinweis statt einer falschen Ampel.

🎨 Neues Design „Tagesordnung" (seit 2026-08-09, setup-detail.html): die Setup-Analyse hatte bis dahin eine dunkle Glas-Optik (Navy-Hintergrund, transluzente Karten). Umgestellt auf eine helle Papier-Basis (#F6F3EC) mit weichen, schattierten Karten (weiß, dezenter Schlagschatten statt Rahmen-Glas) und Teal (#1F6E66) als einzigem Marken-Akzent statt der vorherigen Türkis/Gold-Mischung. Serif-Schrift (Iowan Old Style/Palatino) ist bewusst auf eine einzige Stelle beschränkt — das KI-Story-Zitat in Fundamentaldaten & Story erscheint jetzt kursiv mit Teal-Randlinie als eigene .story-quote, der Rest der Seite bleibt konsequent Sans/Mono, damit dieser Akzent nicht verwässert. Neue Eyebrow-Zeile („SETUP-ANALYSE · Börse") über dem Ticker im Hero. Das TradingView-Chart-Widget läuft jetzt mit theme:'light' statt 'dark', passend zum Rest der Seite. Ampel-/Badge-Farben (Tier, Pivot-Status, Regime, Price-Action, Marktstadium) wurden komplett auf helle, semantisch gleichbleibende Varianten umgestellt (kräftige Volltöne auf Dunkel → dezente Farbtöne auf Hell, gleiche Zuordnung Grün/Gelb/Rot/Teal). War eines von vier vorgeschlagenen Design-Konzepten (Kontrollraum, Analystennotiz, Nachtsitzung, Tagesordnung) — der Nutzer wählte „Tagesordnung" aus.

🔀 Ticker wechseln, ohne die Seite zu verlassen (seit 2026-08-16): neues Eingabefeld im Header („Ticker wechseln …") lädt bei Enter denselben Datensatz (signals.json/pivot.json/priceaction.json) für einen anderen Ticker neu ein und baut die komplette Ansicht (inkl. Story/Code 33/Chart) neu auf, statt die Seite zu verlassen. Die drei bis zu 10 MB großen Dateien werden dafür nur einmal geladen und für jeden weiteren Wechsel im Speicher neu gejoint. Die URL wird per history.pushState mitgeführt (Zurück-Button/Teilen-Link bleiben korrekt), ein unbekannter Ticker zeigt denselben „Kein Treffer"-Hinweis wie beim direkten Aufruf. Grund: der Lokale Trend-Screener verlinkt seit demselben Tag ebenfalls hierher (siehe dortiger Abschnitt) — bei einem breiteren, teils abweichenden Ticker-Universum ist ein schneller Wechsel zwischen mehreren Kandidaten in derselben Ansicht deutlich praktischer als Tab für Tab neu zu öffnen.

🟢 Erfüllt/nicht-erfüllt + aufklappbare Themenblöcke + Fundamentalanalyse (seit 2026-08-16): drei zusammenhängende Überarbeitungen auf Nutzerwunsch. (1) Visuelle Hervorhebung: jede Kriterien-Karte (.fcard) und jede Quickscan-Kachel bekommt jetzt zusätzlich zum kleinen Ampel-Punkt eine eigene Rand-/Hintergrundfarbe je Ampelstand — grün erfüllte Kriterien stechen mit Teal-Tint und grüner Beschriftung hervor, rote/nicht verfügbare Kriterien sind bewusst blasser (reduzierte Deckkraft, kein Schatten), ohne unlesbar zu werden. (2) Sortierung + Zusammenfassung: die Karten in „📈 Technische Analyse" und „💵 Fundamentalanalyse" werden jetzt serverseitig im Frontend nach Ampelstand sortiert (grün → gelb → rot/n. v.) statt in fester Faktoren-Reihenfolge, im „🔎 Sofort-Überblick" steht zusätzlich eine Kopfzeile „X von Y Kriterien grün erfüllt" (Y variiert je Ticker zwischen 11 und 14, siehe Fix 2026-08-17 unten), jeder Akkordeon-Kopf zeigt einen eigenen „X/Y grün"-Zähler. (3) Aufklappbare Themenblöcke: die vorher als feste <h2>-Abschnitte aneinandergereihte Seite ist jetzt in drei <details class="acc">-Blöcke gegliedert — „🕯️ Charttechnik" (Chart + Pivot + Price-Action), „📈 Technische Analyse" (Trend-Template-Karten + Gegenprüfung) und „💵 Fundamentalanalyse" (CANSLIM/Code 33 + die beiden neuen Unterabschnitte unten + Story/News) — alle standardmäßig offen, einzeln einklappbar. Bewusst ein eigenes, schlankes Akkordeon-CSS-Muster statt Wiederverwendung des wiki.html-Accordions (siehe CLAUDE.md-Regel zu den drei getrennten Anleitungsseiten-Design-Systemen — passt nicht zur hellen „Tagesordnung"-Optik dieser Seite). Neu: Fundamentalanalyse nach Dividendenkontinuität + Buffett/Munger/Graham — zwei zusätzliche Kartenreihen innerhalb der Fundamentalanalyse, beide rein informativ, kein Score-Bestandteil (dieses System ist sonst konsequent Wachstums-/Momentum-orientiert nach Minervini/CANSLIM, hier bewusst eine wertorientierte Zweitmeinung dazu): „💰 Dividendenkontinuität" berechnet aus der Yahoo-Dividendenhistorie der letzten 10 Jahre (eigener Abruf über den bereits bestehenden generischen ?url=-Proxy im mts-cors-Worker, query1.finance.yahoo.com/v8/finance/chart mit events=div — kein neuer Worker-Endpunkt nötig) die Zahl aufeinanderfolgender Jahre mit Zahlung sowie den Trend der letzten abgeschlossenen Jahre (steigend/gleichbleibend/gekürzt — das laufende Jahr fließt bewusst nicht in den Trendvergleich ein, sonst würde eine noch unvollständige Jahressumme fälschlich wie eine Kürzung aussehen). „🏛️ Buffett/Munger/Graham-Kennzahlen" zeigt Eigenkapitalrendite, Nettomarge, Verschuldungsgrad, Liquidität (Current Ratio), Kurs-Buchwert-Verhältnis, Dividendenrendite und Ausschüttungsquote — alle aus denselben quoteSummary-Modulen (summaryDetail/defaultKeyStatistics/financialData), die der /story-Endpunkt für die Fundamentaldaten-Karte ohnehin schon abruft; die Felder wurden bisher nur nicht ausgewertet, kein zusätzlicher Yahoo-Aufruf. Feste, dokumentierte Heuristik-Schwellen je Kennzahl (z. B. ROE ≥ 15 % grün, Verschuldungsgrad < 50 % grün) — bewusst grobe Einordnung statt einer weiteren Scorekomponente.

Fix 2026-08-17: „Sofort-Überblick"-Zähler stimmte nicht mit den sichtbaren Kacheln überein. Die Kopfzeile nutzte für Zähler und Nenner bisher ausschließlich alleKeys (die 10 TECH_KEYS + 1 FUND_KEYS, macht 11) — die Kachel-Liste selbst hängt aber, falls vorhanden, bis zu drei weitere Kriterien dynamisch an (Pivot-Status, Price-Action, Marktstadium), die dabei nie mitgezählt wurden. Sichtbares Symptom (User-Report anhand HUM): „6 von 11" in der Überschrift, obwohl 14 Kacheln sichtbar waren und spürbar mehr als 6 davon grün leuchteten. Fix: qsAmpeln sammelt jetzt parallel zu qsItems die Ampel jedes tatsächlich gerenderten Kachel-Eintrags (inklusive der drei dynamischen); Zähler und Nenner werden erst danach daraus berechnet, statt vorab nur aus alleKeys. Betraf nur die Kopfzeile — die einzelnen Kachel-Farben selbst waren immer korrekt.

🎯 Innerer Wert — Graham Number, Owner-Earnings-DCF, Dividend Discount Model (seit 2026-08-16, Nutzerwunsch „gibt es Möglichkeiten, eine klassische Buffett-Unterbewertung festzustellen"): dritte neue Kartenreihe in der Fundamentalanalyse, direkt nach den Buffett/Munger/Graham-Kennzahlen — drei unabhängige, bewusst einfache Bewertungsheuristiken statt eines einzelnen „richtigen" Werts (Graham selbst empfahl, mehrere Ansätze gegenzurechnen statt einem Modell blind zu vertrauen), ebenfalls rein informativ, kein Score-Bestandteil. Ampel je Karte nach Sicherheitsmarge (Schätzwert minus Kurs, relativ zum Schätzwert): grün ab 20 % Sicherheitsmarge, gelb 0–20 %, rot wenn der Kurs über dem Schätzwert liegt. 📐 Graham Number (Benjamin Grahams klassische Defensiv-Formel, √(22,5 × EPS trailing × Buchwert je Aktie)) und 🧮 Owner-Earnings-DCF (vereinfachtes 2-Phasen-Discounted-Cashflow-Modell nach Buffetts „Owner Earnings": freier Cashflow je Aktie 5 Jahre mit einer aus Gewinn-/Umsatzwachstum abgeleiteten, auf 0–15 % gedeckelten Rate fortgeschrieben, mit festen 9 % abgezinst, danach ein Terminalwert mit 2,5 % ewigem Wachstum) brauchen dafür nur drei zusätzliche Felder aus denselben quoteSummary-Modulen, die /story ohnehin schon abruft (trailingEps, sharesOutstanding, freeCashflow — Letzteres ist Yahoos bereits fertige Operating-Cashflow-minus-Capex-Größe, kein eigenes cashflowStatementHistory-Modul nötig). 💵 Dividend Discount Model (Gordon-Wachstumsmodell) nutzt die ohnehin schon geladene Dividendenhistorie von oben — letzte volle Jahresdividende mit der historischen Wachstumsrate fortgeschrieben, ebenfalls mit 9 % abgezinst; erscheint als „nicht anwendbar" statt eines falschen Werts, wenn das Dividendenwachstum den Diskontsatz übersteigt (Gordon-Modell divergiert sonst) oder die Historie zu dünn ist. Bugfix noch am selben Tag: die erste CAGR-Implementierung nutzte das älteste Jahr im 10-Jahres-Fenster als Startwert — range=10y schneidet aber fast nie exakt am 1. Januar, das älteste Kalenderjahr im Ergebnis ist deshalb fast immer unvollständig (z. B. nur 2 von 4 Quartalsdividenden erfasst) und verzerrte die Wachstumsrate kräftig nach oben — live an JNJ verifiziert: 13,8 % mit dem verkürzten Startjahr, 5,6 % ohne (die 5,6 % passen zur bekannten langjährigen JNJ-Dividendenwachstumsrate, davor hätte das DDM fälschlich „nicht anwendbar" gezeigt). Fix: das älteste Jahr im Fenster wird für die CAGR-Berechnung jetzt verworfen.

🔬 Erweiterter Bericht (seit 2026-08-08, Button unter der Fundamentalanalyse): ruft manuell (nicht automatisch — spürbar langsamer) den neuen /deep-story-Endpunkt desselben Workers auf. Ziel war ursprünglich echte Social-Media-Recherche über Perplexity — verworfen, da Perplexity Pro seit Februar 2026 keine API-Credits mehr mitbringt und die API echtes Geld pro Anfrage kostet. Kostenlose Alternativen wurden live gegen den Worker getestet, nicht nur angenommen — und sind alle gescheitert: Reddits unauthentifizierte .json-Endpunkte sperren seit Mai 2026 Server-/Cloud-IPs (403), StockTwits blockt Server-Anfragen per Cloudflare-Bot-Challenge (403), und selbst Google News RSS — vom eigenen Mac aus einwandfrei erreichbar — antwortet dem Cloudflare Worker mit 503 (mehrfach reproduziert, auch mit vollen Browser-Headern). Der Bericht nutzt deshalb mehr Yahoo-Schlagzeilen (12 statt 6) als Grundlage, plus optional Reddit über den offiziellen OAuth-Weg (Client-Credentials, weiterhin finanziell kostenlos, kein Scraping) — aktiviert sich automatisch, sobald REDDIT_CLIENT_ID/REDDIT_CLIENT_SECRET als Worker-Secrets hinterlegt sind (Einrichtung in cloudflare-worker/README.md), läuft ohne sie sauber nur mit Yahoo-Daten weiter (Antwortfeld reddit_aktiv zeigt den Status). Plus SEC EDGAR (seit 2026-08-09, Nutzerwunsch „Investor-Relations-Seiten einbinden"): die IR-Website des Unternehmens direkt zu scrapen wurde geprüft und verworfen — gleiche Fehlerklasse wie oben, da die meisten IR-Seiten über Q4 Inc. laufen und damit selbst hinter Cloudflare sitzen (Cloudflare-Worker gegen Cloudflare-geschützte Seite = derselbe Bot-Challenge-Fall), dazu JS-Rendering ohne DOM im Worker und PDF-Berichte ohne Text-Extraktion. Stattdessen data.sec.gov/www.sec.gov (offizielle US-Börsenaufsicht, kostenlos, kein API-Key, nur Pflicht-User-Agent) für 10-K (Jahresbericht), 10-Q (Quartalsbericht) und 8-K (Ad-hoc-Pflichtmeldung = „offizielle News") — Ticker→CIK-Zuordnung 24h gecacht. Deckt nur US-börsennotierte Ticker ab (Antwortfeld edgar_aktiv); für europäische Ticker (LSE/SIX/Euronext/OMX) gibt es keine vergleichbare freie einheitliche Quelle, der Bericht läuft dann sauber ohne EDGAR-Abschnitt weiter. Fünf Textblöcke statt vier: Unternehmen, Story & Katalysatoren, Unternehmensberichte (SEC), Marktstimmung/Diskussion (bei fehlender Reddit-Anbindung ehrlich als solche gekennzeichnet statt spekuliert), Risiken — weiterhin rein informativ, keine Kauf-/Verkaufsempfehlung. 30-Minuten-Edge-Cache je Ticker.

🔍 Unabhängige Gegenprüfung (seit 2026-08-09, Button unter den technischen Treibern): rechnet die 8 Minervini-Stage-2-Trend-Template-Kriterien unabhängig neu aus einem frischen Yahoo-Kursabruf im mts-cors-Worker (neuer Endpunkt /verify) und vergleicht das Ergebnis mit dem in signals.json gespeicherten Pipeline-Stand — Prinzip „wer etwas berechnet hat, prüft es nicht selbst nach" (dieselbe Pipeline, die einen Fehler gemacht hat, findet ihn beim Nachrechnen selten). Bewusst ohne KI-Aufruf, anders als Story/Erweiterter Bericht: die 8 Kriterien sind harte Zahlenvergleiche (Kurs vs. SMA50/150/200, 52-Wochen-Hoch/-Tief), ein LLM würde nur Latenz/Kosten hinzufügen, ohne die Prüfung zuverlässiger zu machen. Formel 1:1 aus Signal-Hub/src/scorer.py::f_stage2 portiert, nur die Datenquelle ist unabhängig. Zeigt „✓ bestätigt den Pipeline-Stand" bei Übereinstimmung, eine Abweichungswarnung bei Diskrepanz, oder einen Hinweis auf zu kurze Kurshistorie — je Kriterium einzeln farbcodiert. 20-Minuten-Edge-Cache je Ticker.

🎯 Visuelle Priorisierung + Alters-Ampel (seit 2026-08-08): Das Panel hob sich bisher kaum vom App-Grid darunter ab — acht gleich gewichtete Kacheln lenkten stärker vom eigentlichen Signal ab als der Text-Block selbst. Jetzt: Akzent-Rahmen mit Glow, größere/fettere Titel- und Ticker-Schrift. Der „Stand"-Zeitstempel ist zusätzlich farbcodiert (🟢 <6 Std., 🟡 6–24 Std., 🔴 >24 Std. — an der ~6-stündigen Kadenz der Cloud-Pipeline ausgerichtet); ab 24 Std. erscheint zusätzlich ein rotes Warnbanner mit „☁️ Jetzt aktualisieren"-Button, der denselben triggerCloudWorkflow() auslöst wie in Signal-Hub/Price-Action-Hub/Rotation-Dashboard (jetzt auch in index.html dupliziert, eigener gh_actions_token-Check). Zweck: verhindert, dass während der Arbeit am System (Mac mini kurz aus, Pipeline pausiert) veraltete Setups unbemerkt für frisch gehalten werden.

🎯 Maick's Trading System (Hauptapp)

Portfolio-, Risiko- und Trade-Verwaltung. Tabs: Dashboard (Cockpit Terminal mit 6 KPIs, Risiko-Gauge, Klumpenrisiko, problematische Positionen), Portfolio, CRV-Coach, Trade-Planner (bis 2026-08-06 „Risk Management", inkl. Risiko-Cockpit & Trade-Planner), FIRE Kalkulator; unter „Mehr": Psychology, Committee, Steuer, Lernen & Tools. Der frühere Tab „Trading Cockpit" ist aufgelöst (Tab-Konsolidierung 2026-07): CSV-Import läuft über das 📥-Import-Modal (Dashboard/Portfolio, mit Vorschau & Duplikat-Erkennung), die offenen Positionen leben in Portfolio, die KPIs im Dashboard; die optionale Streamlit-Analyse (Port 8502) ist als Link unter „Lernen & Tools" erreichbar.

📖 Betriebsanleitung (seit 2026-08-09): Header-Button „📖 Anleitung" verlinkt eine dedizierte Anleitung als Claude-Artifact — anders als bei Price-Action-Hub/Rotation-Dashboard (Symbol-/Filter-Referenz) geht es hier um den praktischen Trading-Ablauf: Ersteinrichtung, täglicher Ablauf, Wochen-/Monats-Check (dieselbe Checkliste wie im Psychology-Tab, hier mit Fundstellen im System verknüpft), Trade-Nachbereitung, Einordnung der drei Backtesting-Ebenen sowie ein Kennzahlen-Spickzettel. Enthält zusätzlich eigene Verbesserungsvorschläge (u.a. Tools-Tab-Reste, die im Dashboard bereits am 2026-08-03 als redundant entfernt wurden) — Hauptapp-Anleitung. Design-System und URL siehe CLAUDE.md.

📌 Dashboard-Akkordeons + Trade-Planner-Umbenennung (2026-08-06): Die Detailbereiche im Dashboard (Kurs-Chart, Portfolio-Heatmap, Sektor-Heatmap, Drawdown-Monitor, Monatliche P&L, Datenspeicherung & Sync) sind jetzt echte <details>-Akkordeons (Klasse mts-acc) — auf Nutzerwunsch standardmäßig aufgeklappt, aber jederzeit einzeln zuklappbar; interaktive Steuerelemente (Ticker-Auswahl, Zeitraum-Buttons, Depot-Filter) sitzen bewusst im Akkordeon-Body statt im <summary>, damit ein Klick darauf nicht versehentlich die ganze Sektion zuklappt. mts-acc teilt sich die CSS-Hülle mit dem bereits bestehenden tp-acc aus dem Trade-Planner (ein Akkordeon-Baustein für die ganze App) und behält nur die eigene, kompaktere Label-Typografie. Die Mini-Equity-Curve im Dashboard hat jetzt eigene Zeitraum-Buttons (1J/5J/10J/Max, setEqRange()) und einen Hover-Tooltip (Datum + Stand beim Überfahren mit dem Cursor, samt Crosshair-Linie) — beides vorher nur an der inzwischen entfernten großen Equity-Curve im (aufgelösten) Control Center vorhanden, jetzt am einzigen verbliebenen Ort nachgerüstet. Der frühere Risk-Management-Tab heißt jetzt „Trade-Planner" (Nav-Button & Überschrift „📌 Trade-Planner mit automatischer Risikoberechnung") — Struktur und Sub-Tabs („🎯 Risiko-Cockpit & Trade-Planner" / „🔍 SEPA-Analyse") bleiben unverändert, der Trade-Planner war dem Nutzer wichtig genug, um der Tab-Identität den Namen zu geben. Zusätzlich vereinheitlicht: die vormals kräftige 2px-Akzentumrandung von .trade-setup (Kandidaten-Scanner, Kelly-Kriterium, R-Multiple-Verteilung, Mid-Trade-Checkliste) ist jetzt die gleiche dezente 1px-Umrandung wie überall sonst (.card/.tp-acc) — vorher stach dort alles gleich stark hervor, wodurch nichts mehr wirklich hervorstach; die „📚 Theorie & Referenz"-Karte (Stop-Loss/CRV/Money-Management/Limits/Drawdown, weiterhin standardmäßig eingeklappt) nutzt jetzt ebenfalls die mts-acc-Hülle statt eigener Inline-Styles. Der separate „⚠ Gesamt-Risiko"-Banner unterhalb des Drawdown-Monitors ist entfernt — er duplizierte Prozent/€/Balken 1:1 aus der Cockpit-Terminal-Kachel „Gesamtrisiko"; der einzige darin enthaltene, nicht anderswo verfügbare Wert (konfiguriertes Max-Risiko pro Trade in €) steht jetzt als kurzer Zusatz in der Kachel „Risiko-Budget frei" (z. B. „≈ 24 neue Trades · Max €500/Trade").

🎯 Control Center komplett aufgelöst (2026-08-06, zweistufig): Der Tab zeigte fast alle Kennzahlen des Dashboards ein zweites (Portfolio-Risk-Überblick) und teils drittes Mal (Equity Curve, drei „Detaillierte Dashboards"-Karten) — reine Dopplung derselben Zahlen aus refreshDashboard(). In einem ersten Schritt wurden diese Dopplungen entfernt (Portfolio-Risk-Überblick, die drei Detail-Karten, die zweite Equity Curve samt der dadurch toten refreshControlCenter()/setEqRange()/renderEquityCurve()-Funktionen inkl. Hover-Tooltip, sowie die im CRV-Rechner enthaltene „Gesamt-Risiko"-Tabelle, identisch mit der Dashboard-Depot-Übersicht db-depot-overview). Bei der Prüfung des verbleibenden Rests (Quick Actions, Apple-Ecosystem-Karten, Schnelle Links, Datenspeicherung & Sync) zeigte sich: alles war entweder redundant oder falsch platziert — die Apple-Notes-/Numbers-Deep-Links (notes:///numbers://) funktionieren im Browser nicht zuverlässig, die „Schnelle Links"-Karten ebenso, „Neuer Trade"/„Trades importieren"/„Jahresbericht" existierten in Portfolio bzw. Dashboard bereits als echte Buttons, „Portfolio ansehen"/„FIRE berechnen" waren nur Shortcuts auf ohnehin sichtbare Nav-Tabs, und die „Position Sizing"-Karten verwiesen nur auf den Trade-Planner, der direkt erreichbar ist. Der Tab ist daher komplett entfernt (Nav-Button, HTML, CSS, JS-Tab-Switch-Case); zwei Inhalte mit echtem Eigenwert sind umgezogen: der Daten-Status-Banner (cc-import-status, „Letzter Import: …") steht jetzt oben im Portfolio-Tab, die Karte „Datenspeicherung & Sync" (Offline-First-Hinweis + GitHub-Gist-Sync-Banner mts-gist-banner) steht jetzt ganz unten im Dashboard. Das KPI-Lexikon ist als Nachschlagewerk hierher ins Wiki gewandert (siehe unten).

Dashboard

Gesamt-Portfolio-Hero (Fix 2026-08-03): Die große Zahl zeigt weiterhin die Summe aus Kontostand (reines Cash) und Depotwert (Live-Marktwert der offenen Positionen) über alle Depots. Darunter steht jetzt zusätzlich eine kleine Zeile „Kontostand X · Depotwert Y", die beide Anteile einzeln ausweist — vorher war nur die vermischte Summe sichtbar, obwohl die Portfolioübersicht (Portfolio-Tab) beide Werte pro Depot schon immer getrennt zeigt. Reine Anzeige-Ergänzung, keine Änderung an der zugrundeliegenden Summe (die weiterhin in Risiko-/FIRE-Berechnungen einfließt).

Nachtrag selber Tag — echte Fehletiketten korrigiert: Eine zweite Prüfung ergab, dass mehrere weitere Kacheln nicht nur unvollständig, sondern schlicht falsch beschriftet waren — sie hießen „Kontostand" oder „Depot-Wert", zeigten aber tatsächlich _mtsDepotBalance() = Kontostand + Depotwert kombiniert. Behoben: Portfolio-Tab-KPI-Zeile („Depot-Wert" → „Gesamtkapital", neue Unterzeile mit Aufschlüsselung), 💼 Portfoliostand-Karte (die „Kontostand"-Kachel zeigte die Summe — jetzt eigene „Kontostand"- und „Depotwert"-Kachel), Portfolioübersicht „📊 Alle Depots"-Karte (Kachel „Kontostand" zeigte die Summe — jetzt drei eigene Kacheln Kontostand/Depotwert/Investiert), Dashboard-Mini-Depotkarten (zeigten „Depotwert: X" nur wenn zusätzlich ein Kontostand > 0 vorlag, sonst gar keine Aufschlüsselung — jetzt immer „Kontostand X · Depotwert Y", sobald einer der beiden Werte > 0 ist), Control-Center-Risikotabelle (Spalte „Kontostand" → „Gesamtkapital", da sie als Risiko-%-Basis bewusst die Summe nutzt), Jahresbericht-Export (KPI „Depot-Wert" → „Gesamtkapital" + zwei neue KPIs Kontostand/Depotwert, Depot-Tabelle bekommt eine eigene Depotwert-Spalte statt die Summe in der Kontostand-Spalte zu verstecken) und die FIRE-Eingabe („Aktueller Depot-Wert" → „Aktuelles Gesamtkapital", da das Feld bewusst die Summe für die Vermögens-Hochrechnung nutzt). Durchgängiges Prinzip seither: eine Kachel/Spalte, die „Kontostand" oder „Depotwert" heißt, zeigt ausschließlich den jeweils reinen Anteil; wo bewusst mit der Summe gerechnet wird (Heat, Risiko-%, FIRE, Freies Kapital), heißt die Kachel „Gesamtkapital".

„Liquidität"-Feld komplett entfernt (selber Tag): Beim Nachfragen zur Portfoliostand-Karte fiel auf, dass „Liquidität" (separates manuelles Eingabefeld pro Depot, plus ein Legacy-Duplikat auf Portfolio-Ebene) in keiner echten Berechnung mitzählte — weder Portfolio-Heat noch Freies Kapital noch die Positionsgrößen-Empfehlung lasen es, obwohl die alte Control-Center-Erklärung „Heat = 100% − Liquidität%" versprach. Die einzige Stelle, die es überhaupt nutzte (FIRE-Sync, _syncFireWithDepot), addierte es sogar anstelle von Kontostand — ein zweiter, unabhängiger Fehler. Da es nie befüllt wurde, stand es dauerhaft bei „€0" und sah wie eine tote Dopplung von Kontostand aus. Auf Nutzerentscheidung hin komplett entfernt: Eingabefelder (Depot-Formular, Dashboard-Einstellungen), Anzeige-Kacheln (Portfoliostand, „Alle Depots"-Karte, Control Center, Jahresbericht-Tabelle) und der Datenschlüssel liquiditaet aus defaults()/CSV-Import — bestehende Werte in mts_data.json bleiben unangetastet, fließen nur nirgends mehr ein. Portfolio-Heat im Control Center nutzt jetzt _mtsExposureState().exposurePct (dieselbe Formel wie der Exposure-Deckel), der FIRE-Sync nutzt jetzt durchgängig Kontostand + Depotwert. Mentales Modell seither einfach: Kontostand (manuell) + Depotwert (automatisch) = Gesamtkapital — kein drittes, unabhängiges Feld mehr.

Legacy-Zeile am Dashboard-Ende entfernt (2026-08-03): Die unterste Zeile des Dashboard-Tabs („🎯 Portfolio-Einstellungen" mit den Feldern Kontogröße/Sparrate + drei „Apple Ecosystem"-Kacheln Trading-Journal/Apple-Notizen, Trading-Suite/Numbers, Alle-Dateien/ZIP) ist komplett entfernt — auf Nutzerwunsch, unbenutzt und redundant zu den Depot-basierten Eingaben (Portfolio-Tab) bzw. dem FIRE-Tab (fire-kontostand/fire-sparrate lesen/schreiben dieselben portfolio.kontostand/portfolio.sparrate-Felder bereits vollwertig). Mitentfernt als jetzt toter Code: savePortfolioFromDashboard, syncDashboardInputs sowie die drei Text-Download-Funktionen downloadJournal/downloadNumbers/downloadBoth (inkl. Helfer downloadFile) — alle vier waren ausschließlich von dieser Zeile aus erreichbar.

Markttiming & Gate

Markt-Chip im Cockpit-Terminal-Header: zeigt seit 08/2026 dieselbe volle Minervini-Marktampel wie Startseite/Signal-Hub/Markets 360 (assets/marktampel.js, ladeMarktAmpel()) — Trend-Template + Distribution Days/VIX/Small Caps/52-W-Abstand/Follow-Through-Day/10J-Rendite, live über den Cloudflare-Worker, funktioniert ohne Mac mini. Klick öffnet Markets 360 für die Detailansicht. Vorher war der Chip bewusst eine simple, eigenständige MA/VIX-Regel (🟢 S&P über MA50 und MA200 bei VIX < 20 · 🔴 unter MA200 oder VIX > 25 · 🟡 dazwischen) und lief zudem nur bei erreichbarem 8080-Server (kein Worker-Fallback) — beides seit 08/2026 durch die geteilte Grundlage abgelöst.

🚦 Trade-Gate: Beim Anlegen eines neuen Trades zeigt das Formular die aktuelle Marktphase (grün/gelb/rot mit Begründung, seit 08/2026 aus der vollen Ampel inkl. Faktor-Details und ggf. dem „Tendenz Richtung Gelb"-Hinweis, siehe Startseite). Wird im roten Umfeld eine neue Position eröffnet, fragt die App noch einmal nach — Minervinis Kernregel: in einem schwachen Markt keine neuen Käufe. Geschlossene/historische Trades werden nie geblockt.

📊 Exposure-Deckel nach Marktampel: Die erlaubte Gesamt-Investitionsquote hängt vom Marktumfeld ab — Bearish max. 25 %, Neutral max. 50 %, Bullish bis 100 % investiert (Basis: Einstandswert aller offenen Positionen ÷ Depotwert, dieselbe Kennzahl wie die „invested/heat"-Anzeige in Portfolio und Cockpit). Marktumfeld = window._marktStatus.status, seit 08/2026 aus der vollen Ampel (vorher aus dem eigenen MA/VIX-Check) — dieselbe Grundlage wie überall sonst, daher tendenziell öfter „grün"/höhere erlaubte Exposure als vorher. Der Positionsgrößen-Rechner kappt die empfohlene Stückzahl automatisch auf die verbleibende erlaubte Exposure; würde ein Trade das Limit reißen, fragt die App beim Speichern noch einmal nach. Die aktuelle Exposure samt Limit steht direkt im Marktphasen-Hinweis des Trade-Formulars.

Risiko-Management & Regeln

🎯 Minervini Risiko-Cockpit (Trade-Planner): eine zentrale Sizing-Logik (_mtsSuggestedSize) statt der früher drei parallelen Rechner (Risk-Tab, Trade-Formular, Control-Center). Formel: Max-Risiko€ = Kontostand des gewählten Depots × Risiko-% (Risiko-Registry: risikoProTrade, maxPositions, maxSectorExposure, Tages-/Wochen-/Monats-Risikolimit) ÷ |Entry − Stop| — Sizing rechnet pro einzelnem Depot (nicht mehr gegen die Summe aller Depots), Kill-Switch und Exposure-Deckel bleiben bewusst portfolioweit. Das Cockpit zeigt zusätzlich die Auswirkung aufs Gesamtdepot (Depot-Anteil, Portfolio-Anteil, verbleibende Exposure-Headroom), eine Kill-Switch-/Exposure-Ampel und eine Liste aller offenen Pyramiding-Positionen mit Stufen-Status. Der Trade-Planner hat dafür ein eigenes Depot-Feld (tf-depot) — vorher bekamen manuell angelegte Trades gar kein Depot zugewiesen, wodurch der Formular-Rechner zwangsläufig gegen den gepoolten Gesamtwert rechnete. Das Control-Center verlinkt pro Depot direkt in den Trade-Planner (vorausgewählt), statt eine eigene Formel zu pflegen.

🔍 SEPA-Analyse (Trade-Planner, zweiter Sub-Tab neben Risiko-Cockpit & Trade-Planner — seit 2026-07-23 aus minervini-coach-2.html hierher zusammengeführt, bewusste Teil-Rücknahme der früheren Entflechtung nur für dieses Sub-Feature; Pyramidisieren, Academy, Mental und Quiz bleiben im Coach): TradingView-Chart, 23-Punkte-Checkliste mit Ampel (Trend-Template 8 Kriterien aus SMA50/150/200 + 52-Wochen-Hoch/Tief, Fundamentals & Volumen, Chart Pattern & Setup — Stage-2-Base/VCP-Verengung/Konsolidierungsdauer/Breakout-Volumen automatisch erkannt, Logik aus Signal-Hub/src/pivot.py portiert —, Markt-Stage via S&P 500/SPY vs. SMA200), Batch-Screener (44-Ticker-Universum oder eigene Watchlist) und Watchlist (data.watchlist, Teil von mts_v2 — automatisch per Server-/Gist-Sync gesichert). Preis-Historie: lokaler MTS-Server zuerst (/history, wie ATR-Stop-Rechner/Verkaufs-Check), sonst Yahoo über die bestehende CORS-Proxy-Kette (_yahooJson/MTS_PROXY) — funktioniert dadurch auch ohne laufenden Mac mini. „📌 In Trade-Planner übernehmen" füllt Ticker/Entry/Stop (Entry −8 %) direkt ins Risiko-Cockpit und wechselt dorthin — die Positionsgrößen-Berechnung läuft über die ohnehin vorhandene _mtsSuggestedSize (Kill-Switch, Exposure-Deckel, Max-Position-%), nicht über einen separaten Rechner. Alte Coach-Links (minervini-coach-2.html?ticker=…/?page=sepa) leiten dauerhaft hierher um.

📉 Drawdown-Kill-Switch (Dashboard, „Drawdown-Monitor"): wertet realisierte Trades nach Tages-/Wochen-/Monats-Fenstern aus. Tages-Drawdown ≤ −3 % → 🔴 Handelsstopp (Positionsgrößen-Rechner blockiert, Trade-Formular fragt beim Speichern noch einmal nach), Wochen-Drawdown ≤ −6 % → 🟡 Positionsgröße automatisch auf 50 % reduziert, Monats-Drawdown ≤ −10 % → 🔴 kompletter Reset (ebenfalls Rückfrage vor neuen Trades). Zusätzlich zeigt das Widget die klassische Drawdown-Kurve (aktuelle/maximale Distanz zum Equity-Hoch) als Underwater-Chart. Bugfix 2026-08-03: Das Dashboard-Widget (assets/mts-extensions.js::renderDrawdownMonitor — überschreibt per <script defer> eine ältere, inzwischen entfernte Kopie gleichen Namens in der Hauptdatei, die dadurch nie ausgeführt wurde) rechnete die Prozent-Basis fälschlich nur aus dem reinen Kontostand statt aus Gesamtkapital (Kontostand + Depotwert). Bei jedem Konto mit nennenswertem kumuliertem Gewinn wurde dadurch die Basis rechnerisch auf 0 geklemmt — die Kurve lief flach, die Ampel sprang fälschlich auf 🔴 „Stopp" und die Positionsgrößen-Empfehlung auf 0–25 %, obwohl real ein harmloser einstelliger Drawdown vorlag. Betraf nur die Dashboard-Anzeige — der echte Kill-Switch fürs Trade-Formular (_mtsDrawdownState, siehe oben) nutzte bereits korrekt das Gesamtkapital und war nie betroffen. Pro Depot oder gesamt (seit 2026-08-03): Ein Dropdown neben der Überschrift („Alle Depots (konsolidiert)" + jedes einzelne Depot, identisches Muster wie der Depot-Filter im Portfolio-Tab) schaltet Kurve, Ampel, Kennzahlen und Gesamtkapital-Basis auf ein einzelnes Depot um — dessen eigene Trades und dessen eigenes Gesamtkapital (_mtsDepotBalance), nicht die Summe aller. Ohne Angabe liest renderDrawdownMonitor() die aktuelle Dropdown-Auswahl selbst aus, damit automatische Re-Renders (Kurs-Refresh, Tab-Wechsel) die Auswahl nicht zurücksetzen.

🔺 Progressive Exposure (Pyramiding): Beim Anlegen eines Trades kann „Progressive Exposure nutzen" aktiviert werden — Zielgröße eingeben, die App setzt automatisch die initiale Position auf 25 %. In der Positionsbearbeitung erscheint dann, sobald die Position im Plus ist, ein „Nachkaufen"-Baustein: +25 % ab +2 % Gewinn (Stufe 2/3), +50 % final ab +5 % Gewinn (Stufe 3/3) — jeweils nur aktiv, wenn die Schwelle erreicht ist. Entry, Positionsgröße und Risiko werden nach jedem Nachkauf automatisch als gewichteter Durchschnitt neu berechnet.

🎯 Gestaffelter Ausstieg (Teilverkäufe erfassen) (seit 2026-07-30, Gegenstück zum Pyramid-Nachkauf): in der Positionsbearbeitung erscheint bei offenen Positionen der Block „🎯 Gestaffelter Ausstieg" mit Vorschlag für die nächste Verkaufsstufe (Minervini 50/25/25: Stufe 1 bei T1/+8 %, Stufe 2 bei +20 %, Stufe 3 = Restposition bei +40 %) inkl. Kurs- und Stückzahl-Vorschlag sowie Historie bereits erfasster Teilverkäufe. „✅ Teilverkauf erfassen" (addPartialExit) reduziert die offene Position um die verkaufte Stückzahl — technisch spaltet jeder Teilverkauf, der die Position nicht vollständig schließt, einen eigenen, ganz normalen geschlossenen Trade-Datensatz ab (Feld partialExitOf verweist auf die Ursprungsposition, exitStage zählt mit). Grund: Kelly-Kriterium, R-Multiple-Verteilung, Steuerjahr-Zuordnung und alle „Performance nach …"-Auswertungen gehen von „ein Trade = ein Exit" aus — ein Teilverkauf als eigener geschlossener Trade zählt dort automatisch korrekt mit, ohne dass diese Auswertungen etwas von Teilverkäufen wissen müssen. Der letzte Teilverkauf (Restposition = 0) schließt stattdessen die Ursprungsposition direkt, exakt wie ein normaler Vollverkauf.

🚫 SEPA-Verbotsliste: Vor jeder neuen offenen Position muss eine Pflicht-Checkliste bestätigt werden (Kurs über 50-SMA, positive relative Stärke, Trade mit dem Trend, Kauf am Pivot statt auf Verdacht) — ohne alle vier Häkchen speichert die App nicht. Zusätzlich erkennt sie automatisch Averaging-Down (Nachkauf in eine bereits offene Position zu einem Kurs unterhalb des bisherigen Einstiegs) und fragt vor dem Speichern ausdrücklich nach — Minervinis absolute Regel: niemals Verlustpositionen aufstocken. Pyramiding (siehe oben) ist davon nicht betroffen, da es zwingend Gewinn voraussetzt.

⛔ Minervini 50/80-Regel (seit 2026-07-22, _mtsLoadGap80Cache/_mtsGap80Info): die Hauptapp lädt beim Start zusätzlich Signal-Hub/data/signals.json nach (rein lesend, relativer Pfad — funktioniert nur, wenn beide Apps vom selben Server ausgeliefert werden, z.B. 8090; scheitert sonst bewusst still, das Feature ist rein zusätzlich). Drei Stellen nutzen das: ① „+ Neuer Trade"/Risiko-Cockpit/Trade-Planner zeigen bei einem 50/80-belasteten Ticker automatisch eine Warnung in der Live-Vorschau und als Bestätigungs-Dialog beim Speichern — dieselbe Quelle wie Stop-Abstand/CRV (_mtsPreTradeWarnings), kein separater Dialog. ② Die Positionsgrößen-Empfehlung (_mtsSuggestedSize) halbiert sich automatisch für 50/80-belastete Ticker — analog zur bestehenden Drawdown-Reduktion, keine neue Sizing-Formel. ③ In der Positionsliste (Portfolio, einzeln & aggregiert) markiert ein Badge „⛔50/80" bestehende offene Positionen, die selbst so einen Gap-down hatten — Warnung vor dem Nachkaufen zum Senken des Durchschnittskurses, bevor überhaupt ein neuer Trade angelegt wird. Bewusst kein Kelly-Eingriff: Kelly „Was-wäre-wenn" (siehe unten) rechnet mit den realen R-Multiples der eigenen Trade-Historie, nicht pro Ticker — dafür gibt es keinen sinnvollen Anknüpfungspunkt für eine Ticker-spezifische Regel, die Positionsgrößen-Halbierung deckt denselben Zweck (konservativer bei erhöhtem Risiko) ab.

🛡️ Minervini-Plausibilitätsprüfung (Stop-Abstand · CRV · Positions-Deckel · Limits): Vier weitere Prüfungen, gespeist aus einer gemeinsamen Quelle (_mtsPreTradeWarnings bzw. Risiko-Registry), erscheinen live als Warnbox im „+ Neuer Trade"-Formular und beim Speichern als Bestätigungs-Dialog (analog Markt-Gate): ① Stop-Abstand > 10 % unter Entry (Minervini: max. 10 %, Ideal 7–8 %), ② CRV < 2:1 (sofern Target gesetzt; die CRV-Vorschau färbt sich grün/orange), ③ Positions-Deckel: der Positionsgrößen-Rechner kappt die Empfehlung zusätzlich auf max. maxPositionPct (Standard 25 %) des Depotwerts — verhindert, dass sehr enge Stops rechnerisch das ganze Depot in eine Position schicken, ④ Positionslimit & Sektor-Klumpenrisiko: die bislang ungenutzten Registry-Werte maxPositions (Standard 5 verschiedene Ticker; Aufstocken bestehender Ticker bleibt frei) und maxSectorExposure (Standard 30 % des Gesamtdepots je Sektor, Basis Einstandswert) werden jetzt beim Speichern geprüft. Das Risiko-Cockpit zeigt dazu eine dritte Ampel-Kachel „Positionslimit" und dieselben Stop-Warnungen.

Verkaufsdisziplin

🔍 Verkaufs-Check (Sell-Coach): Knopf über den offenen Positionen. Prüft je Position die Minervini-Ausstiegsregeln aus Tageskursen (vom /history-Endpunkt) und zeigt eine Ampel in der Spalte „🔍 Verkauf": 🔴 Verkauf prüfen bei hartem Signal (Bruch der 50-Tage-Linie auf erhöhtem Volumen oder Kurs unter der 200-Tage-Linie = Stage-2-Ende), 🟡 Beobachten bei weichem Signal (Schluss unter 50-Tage-Linie, größter Tagesverlust seit Einstieg, Bruch des jüngsten Swing-Tiefs oder > 15 % unter dem jüngsten Hoch), sonst 🟢 Halten. Die Begründungen stehen im Tooltip der Ampel. Das ist das Gegenstück zur SEPA-Kaufprüfung im Coach — die Verkaufsdisziplin, wo bei Minervini die Rendite entschieden wird. Der Check schlägt zusätzlich einen nachgezogenen Stop-Loss vor (⤴ Stop → …): ab +8 % Break-Even, ab +20 % unter die 50-Tage-Linie bzw. das jüngste Swing-Tief — nur anhebend, nie senkend. Ein Klick übernimmt den neuen Stop (mit Rückfrage).

🔵 Stärke-Signal „Teilgewinn in Stärke" (seit 2026-07-24): Der Verkaufs-Check war bisher rein defensiv (reagiert auf Schwäche). Minervini verkauft aber genauso in die Stärke. Der Check zeigt daher zusätzlich ein blaues Signal, wenn eine Position im Gewinn überdehnt läuft — Auslöser (einzeln oder kombiniert): > 12 % über der 20-Tage-Linie, +25 % Lauf in 10 Handelstagen, oder Klimax-Volumen (> 2× Ø-Volumen an einem starken Aufwärtstag). Das Signal ist additiv zur defensiven Ampel und erscheint nie bei hartem Verkaufssignal (🔴, dann will man ganz raus). Die Abschlussmeldung des Checks zählt die Stärke-Kandidaten mit.

R akt. (Live-R-Vielfaches je offener Position) (seit 2026-07-24): Neue Spalte in der Positionsliste (zwischen P&L% und SL-Abst.) — offener Gewinn/Verlust ÷ anfängliches Risiko (€), also die risiko-normalisierte Sicht auf jede laufende Position. Nutzt den bereits gespeicherten currentPrice (kein zusätzlicher Kursabruf nötig, anders als der Verkaufs-Check). Farbcodiert: ab +2R 💪 grün (Gewinnrealisieren-Zone, deckt sich mit dem 🔵 Stärke-Signal), 0…+2R blau, im Minus orange, ab −1R rot. Gegenstück zur R-Multiple-Verteilung, die dasselbe für geschlossene Trades zeigt.

📏 ATR-Stop-Rechner: Button „ATR-Stop berechnen" neben dem Stop-Loss-Feld holt Tageskerzen vom 8090-Server (/history, dieselbe Quelle wie der Verkaufs-Check) und errechnet die Average True Range über 14 Tage. Vorschlag: Stop = Entry − 2 × ATR — ein objektiver, volatilitätsbasierter Stop-Abstand als Alternative zur festen Prozent-Regel, mit „Übernehmen"-Knopf.

🎯 SEPA-Score-Snapshot: Das Trade-Formular hat ein Eingabefeld „SEPA-Score bei Kauf" (0–23) plus einen Knopf „🔍 SEPA-Analyse", der seit der Zusammenführung (siehe oben) direkt in den SEPA-Analyse-Subtab des Trade-Planners wechselt und die Analyse für den eingetragenen Ticker startet — kein externer Tab mehr. Von dort füllt „📌 In Trade-Planner übernehmen" den Score automatisch in tf-sepa-score zurück, sobald derselbe Ticker im Formular steht. Der Wert wird als Snapshot am Trade gespeichert und erscheint schreibgeschützt in der Positionsbearbeitung.

📐 Setup-Typ-Tag (seit 2026-07-22, nach einem Minervini-Private-Access-Q&A: „konsequent verschlagworten und auswerten"): Zweites Freitext-Analog-Feld neben „Quelle" — festes Dropdown „Setup-Typ" (Swing / Cheat-Pivot / Pyramid-Add / Test / Sonstige) im Trade-Formular. Wie der SEPA-Score ein reiner Entry-Snapshot (trade.setupTyp), schreibgeschützt in der Positionsbearbeitung sichtbar, nie nachträglich änderbar. Psychology-Tab wertet mit „📐 Performance nach Setup-Typ" aus (Trades/Win-Rate/Ø-CRV/P&L je Setup-Typ, gleiches Schema wie „Performance nach Quelle") — zeigt, welcher Entry-Stil beim eigenen Trading tatsächlich funktioniert.

📍 Entry-Timing-Snapshot (Pivot-Abstand): Videokern „right price, not lowest price" — beim Ausfüllen des Trade-Formulars zeigt eine Live-Hinweisbox, wie weit der eingetragene Kurs vom zuletzt bekannten Signal-Hub-Pivot (Signal-Hub/data/pivot.json, bisher ungenutzt) entfernt liegt, inkl. Pivot-Status (ARMED/BREAKOUT). Wird beim Speichern als Snapshot am Trade abgelegt (pivotEntry, pivotDistPctEntry) — nur wenn zum Zeitpunkt Pivot-Daten für den Ticker vorlagen, sonst bleibt das Feld leer (kein Pflichtfeld, scheitert still wie die 50/80-Cross-App-Anbindung). Schreibgeschützt in der Positionsbearbeitung sichtbar. Psychology-Tab wertet mit „📍 Win-Rate nach Pivot-Nähe" aus: Buckets ≤2 % / 2–7 % / >7 % über Pivot, je mit Trades/Win-Rate/P&L — beantwortet, ob nah am Pivot gekaufte Trades tatsächlich besser laufen als extended gekaufte.

🏷️ Positionsgrößen-Kategorie-Badge (Portfolio-Tab, offene Positionen): rein visuelle Einordnung Voll/Halb/Viertel/Test unter dem bestehenden „Offen"-Badge, abgeleitet aus dem bereits berechneten Depotanteil (depPct) relativ zu maxPositionPct (Standard 25 %, Minervini: 20–25 % = „Full Position"). Keine neue Berechnung, nur Sichtbarmachung der bestehenden Risiko-Registry-Kennzahl direkt in der Tabelle.

Planung & Auswertung

📌 Trade-Planner — ein Bildschirm für Durchrechnen UND Kaufen (zusammengelegt 2026-07-30 aus dem vorherigen Risiko-Cockpit + separatem „+ Neuer Trade"-Modal). Ein Ticker rein — aus dem Kandidaten-Scanner übernommen, per Screener-Deeplink oder manuell — und alles wird automatisch befüllt und berechnet: Firmenname, Entry/Stop, Targets T1/T2/T3 (Minervini 50/25/25: +8 %/+20 %/+40 %), SEPA-Trend-Ampel und SEPA-Verbotsliste (siehe unten), Pyramidisierung, gestaffelter Ausstiegsplan, Depot- & Portfolio-Auswirkung und das Sicherheitsnetz. Gliederung: Gesamtverdikt-Ampel → Risiko-Budget → Stammdaten → Preisplan & Targets → Größe & Risiko → Pyramidisierung → Gestaffelter Ausstieg → Depot-/Portfolio-Auswirkung → Sicherheitsnetz → SEPA-Verbotsliste. Unten zwei gleichwertige Buttons: „📌 Als Plan speichern" (unverbindlich, eigener Datenbereich planned) und „💾 Trade jetzt anlegen" (saveTrade(), alle Gates greifen normal). Gespeicherte Pläne erscheinen darunter mit einem „▶ Übernehmen"-Knopf; nach erfolgreichem „Trade jetzt anlegen" wird der zugehörige Plan automatisch entfernt. „Größe"-Feld ist eine echte Eingabe (Fix 2026-08-01): Positionswert, Risiko-€/%, die Target-Tabelle, Depot-/Portfolio-Auswirkung und der Ausstiegsplan rechneten bislang immer mit der automatischen Risiko-Empfehlung (r.suggested), egal was im „Größe"-Feld selbst stand — eine manuell eingetragene Stückzahl hatte keinerlei Effekt. Alle diese Blöcke nutzen jetzt r.actualSize (manueller Wert, falls >0 gesetzt, sonst weiterhin die Empfehlung); die „empfohlen: N"-Anzeige daneben bleibt unverändert die echte Empfehlung, damit sichtbar bleibt, wovon eine manuelle Größe abweicht. Die Pyramidisierungs-Vorschau folgt zusätzlich einer eigenen, manuell in „Zielgröße" eingetragenen Stückzahl, falls vorhanden.

🔎 Ticker-Autofill (_tfAutofillFromTicker): Ticker-Feld verlassen (oder Enter) → fehlende Felder werden nachgeladen, ohne je einen bereits gesetzten Wert zu überschreiben (Deeplink- oder Handeingaben haben immer Vorrang). Preis bevorzugt den Signal-Hub-Pivot/Basis-Tief (_mtsPivotInfo), sonst Fallback letzter Kurs (Kurs / −8 % / +8 %). Der Firmenname kommt aus derselben Yahoo-Chart-Antwort, die ohnehin für den Kurs abgerufen wird (meta.longName/shortName). Technisch teilen sich alle Bausteine dieselben Render-Funktionen (_renderImpactBlock, _renderAmpelBlock, _renderRRScenarios, _renderPyramidPreview, _renderExitPlanPreview) statt eigener Kopien. „🔄 Aktualisieren"-Knopf neben dem Ticker-Feld (seit 2026-08-01): das bewusste „nie überschreiben" ist beim erstmaligen Ticker-Eintippen richtig, wird aber zum Problem, wenn im selben, schon befüllten Trade-Planner ein anderer Ticker eingetragen wird — Entry/Stop/Target/Name blieben dann vom vorherigen Ticker stehen. Der Knopf ruft _tfAutofillFromTicker(true) auf und überschreibt bewusst alles (inkl. SEPA-Trend/Verbotsliste, dafür wird deren Cache für diesen Ticker geleert). Dabei aufgefallen und mitbehoben: _sepaFetchHistory() liefert bei einem Treffer über den lokalen Mac-mini-Proxy (source:'MTS-Server') keinen Firmennamen mit (/history kennt kein Namensfeld) — nur der Yahoo-Fallback (source:'Yahoo') bringt meta.longName mit. Der Autofill holt den Namen in diesem Fall jetzt gezielt per zusätzlichem, leichtem _yahooFetchHistory()-Aufruf nach, statt ihn leer zu lassen.

🎯 Gesamt-R:R statt reiner T1-CRV (_computeBlendedRR, seit 2026-07-30): die CRV-Kennzahl bezog sich zuvor nur auf Target 1 — bei Minervini bewusst nah am Entry („Risiko finanzieren"), wodurch die reine T1-CRV fast immer nahe 1:1 liegt und als alleinige Kennzahl systematisch falsch gewarnt hätte. Jetzt zählt überall (Kopf-Kachel, Warnschwelle <2:1, Gesamtverdikt) das gewichtete Gesamt-R:R über T1–T3 (50/25/25-Gewichtung, dieselbe Formel wie im Ziel-Szenario-Block). Direkt darüber steht die Gesamtverdikt-Ampel (_computeOverallVerdict): 🟢/🟡/🔴 aus dem schlechtesten Wert von Gesamt-R:R, Kill-Switch, Exposure-Deckel und Positionslimit — eine Zahl/Farbe statt vier Einzel-Ampeln getrennt lesen zu müssen.

⚖️ Duales Risiko-Limit (_mtsSuggestedSize, neue Settings risikoProTradePortfolio): zwei unabhängig einstellbare Prozent-Felder im Trade-Planner-Kopf — „Risiko-Limit dieses Depot" und „Risiko-Limit Gesamtportfolio" (beide leer = Standard aus den Risiko-Einstellungen, Session-Override, nichts wird dauerhaft gespeichert). Die empfohlene Positionsgröße nutzt automatisch die strengere der beiden Grenzen; ein Hinweistext zeigt, welche gerade bindet ("bindend: Depot/Gesamtportfolio, max. X €"). Beide Settings sind standardmäßig identisch, wodurch sich am bisherigen Verhalten nichts ändert, solange niemand den neuen Portfolio-Regler enger stellt.

🚦 Automatische SEPA-Trend-Ampel & Verbotsliste (_computeSepaTrendScore, _computeRelativeStrengthVsSpy, _autofillVerbotsliste): die 8 objektiven Trend-Template-Kriterien (Kurs/SMA50/150/200, 52-Wochen-Range — dieselbe Formel wie die manuelle SEPA-Analyse) werden beim Ticker-Autofill automatisch aus den ohnehin geladenen Kursdaten berechnet und als Kachel „SEPA-Trend N/8" angezeigt (grün ≥7, gelb 5–6, rot <5) mit Link zur vollen 23-Punkte-Analyse. Dieselben Daten füllen die SEPA-Verbotsliste vor: Punkt 1 (>50-SMA) und Punkt 3 (Trendausrichtung) aus den Trend-Kriterien, Punkt 4 (Pivot-Breakout) aus dem Signal-Hub-Pivot-Status, Punkt 2 (relative Stärke) aus einem echten 3-Monats-Kursvergleich gegen SPY (nicht approximiert). Die Checkboxen bleiben real anklickbar — die bewusste Bestätigung vor dem Kauf bleibt Pflicht, nur die Recherche entfällt.

🔍 Kandidaten-Scanner (oberhalb des Trade-Planners, window._scannerTickers): mehrere Ticker parallel grob durchrechnen, bevor man sich für einen entscheidet — Ticker eintippen, Zeile erscheint mit Entry/Stop, Gesamt-R:R, SEPA-Trend-Score, empfohlener Größe, Hinweisen (Pivot-Distanz, Minervini-50/80) und einer Ampel-Punkt-Gesamtbewertung. Bewusst nicht in mts_data.json persistiert (eigenständig von data.watchlist, den dauerhaft gemerkten SEPA-Analyse-Ergebnissen) — für spontane Testläufe/Session-Watchlists gedacht, nicht als zweite dauerhafte Watchlist. Zeile anklicken übernimmt den Ticker in den vollen Trade-Plan darunter (derselbe Autofill-Pfad — seit 2026-08-02 erzwungen wie beim „🔄 Aktualisieren"-Knopf, wenn es ein anderer Ticker als der zuletzt geladene ist: sonst blieben Entry/Stop/Name/Target vom vorherigen Kandidaten stehen, und eine dort manuell gesetzte Größe hätte sich fälschlich auf den neuen Kurs bezogen — deshalb wird beim Tickerwechsel zusätzlich „Größe"/„Zielgröße" geleert. Klickt man denselben, schon geladenen Kandidaten erneut an, bleibt eine laufende manuelle Größe unangetastet). Teure Abrufe (Kurs/Name/Trend) werden pro Ticker gecacht, Größe/CRV/Ampel werden bei jedem Rendern live neu berechnet (abhängig vom gewählten Depot und den Risiko-Limits). Seit 2026-08-01: auch der ?neuerTrade-Deeplink aus dem Signal-Hub trägt den Ticker automatisch in diese Liste ein (_addTickerToScanner, gemeinsamer Kern mit der manuellen Eingabe) — beim Durchklicken mehrerer Signal-Hub-Treffer baut sich so von selbst eine Watchlist zum Vergleichen auf. Da jeder Signal-Hub-Klick eine echte Seiten-Navigation ist (eigenes HTML-Dokument), reicht ein reines In-Memory-Array dafür nicht — die Liste liegt deshalb zusätzlich in sessionStorage (mts_scanner_tickers): überlebt beliebig viele Signal-Hub-Klicks/Reloads im selben Tab, verschwindet aber beim Schließen des Tabs — bewusst kein Dauerzustand wie data.watchlist.

☁️ Kursdaten auch rein über die Cloud-Seite (via Tailscale) (_checkProxy/_apiBase, Fix 2026-08-01): Kandidaten-Scanner, Ticker-Autofill und SEPA-Trend-Ampel brauchten bislang eine echte Verbindung zum Mac mini (LAN/Tailscale) oder scheiterten auf der reinen *.pages.dev-Version mit „keine Kursdaten verfügbar" — obwohl _sepaFetchHistory eigentlich einen Yahoo-Fallback hat. Ursache: Cloudflare Pages beantwortet jeden unbekannten Pfad (auch /ticker_map, /history) mit Status 200 und liefert dabei als SPA-Fallback die index.html aus; die alte Prüfung _checkProxy() verließ sich nur auf r.ok und hielt das fälschlich für einen erreichbaren 8090-Proxy — das blockierte wiederum den echten Yahoo-CORS-Fallback in _yahooJson() (der bei „Proxy vermeintlich verfügbar" bewusst übersprungen wird). Zwei Korrekturen: (1) _checkProxy() validiert jetzt zusätzlich den Content-Type-Header (muss …/json enthalten — server_mts.py setzt das immer, Cloudflare Pages' HTML-Fallback nie); (2) neue dritte Stufe Tailscale-Hostname (TAILSCALE_HOST, dieselbe Konstante wie in index.htmls mtsUrl()) — schlagen gleiche Origin und lokale Ports fehl, wird https://mac-mini-von-maick.tail02bccd.ts.net/ticker_map versucht. Ist das Gerät per Tailscale verbunden, liefert die Cloud-Seite dadurch jetzt echte Mac-mini-Kursdaten (schnell, ISIN-fähig) statt auf die langsameren öffentlichen CORS-Proxys angewiesen zu sein; ist auch das nicht erreichbar, greift jetzt korrekt der Yahoo-Fallback statt stumm leer zu bleiben. Betrifft alle _apiBase()-Verbraucher (Trade-Planner-Preisabruf, ATR-Stop, Verkaufs-Check, Sektor-Rotation, KI-Committee).

🧙 Risiko-Erfassungs-Wizard (Knopf „Risiko-Erfassung" über den offenen Positionen): geht alle offenen Positionen ohne definierten Stop-Loss einzeln durch — Minervini: kein Stop-Loss = kein Trade. Pro Position werden Stop (Pflicht) und optional der SEPA-Score nachgetragen; Risiko wird automatisch neu berechnet. Gedacht für den einmaligen Nachtrag bei Bestandspositionen, die vor Einführung der Risiko-Registry angelegt wurden.

🎲 FIRE Monte-Carlo (FIRE-Tab): zusätzlich zur glatten Compound-Hochrechnung simuliert die App 2000 Verläufe mit schwankenden Jahresrenditen (einstellbare Volatilität) und zeigt eine ehrliche Bandbreite — optimistisch (P10), Median (P50), pessimistisch (P90) — plus die Wahrscheinlichkeit, das Ziel binnen 40 Jahren zu erreichen.

🔬 Kelly „Was-wäre-wenn" (Trade-Planner): wendet ein konsequentes fixes Risiko (1,0 / 1,25 / 2,0 %) auf die realen R-Multiples deiner geschlossenen Trades an und zeigt den kumulierten Depot-Multiplikator. Macht greifbar, wie stark stures Risikomanagement die Equity-Kurve verändert.

📊 R-Multiple-Verteilung (Trade-Planner, unter Kelly): R-Multiple = realisierter Gewinn/Verlust ÷ geplantes Risiko (trade.risiko). Statt nur eines Durchschnitts zeigt ein Histogramm die volle Verteilung (< −2R bis ≥ +5R) — im Minervini-System der entscheidende Indikator, da das System auf wenigen großen Gewinnern bei vielen kleinen kontrollierten Verlusten basiert.

📊 Sektor-Rotation (Portfolio-Tab): zeigt die 11 US-Sektoren nach 1-Monats-Performance gerankt (stark → schwach). „🔄 Laden & einordnen" ordnet zusätzlich die offenen Positionen ihrem Sektor zu (Sektor kommt vom 8090-Server: FMP, sonst yfinance-Fallback) und markiert Positionen in den drei schwächsten Sektoren. Minervini-Logik: Leader in starken Sektoren halten, relative Schwäche im Auge behalten.

🏛️ Committee-Verdikt inline: Hat eine offene Position eine Investment-Committee-Analyse (Minervini/Weinstein/O'Neil), erscheint in der Ticker-Spalte ein farbiges Score-Badge (🏛️ Score). Tooltip zeigt Entscheidung + Entry/Stop/Ziel; Klick öffnet den Committee-Tab. So sieht man das KI-Urteil direkt am Bestand statt nur im separaten Tab.

Überwachung & Speicherung

📲 Proaktive Alarme: Der 8090-Server überwacht die offenen Positionen automatisch (alle 20 Min, außerhalb der Ruhezeit 22–08 Uhr und am Wochenende pausiert) und schickt einen Push an deinen ntfy-Kanal (derselbe wie der Signal-Hub, nichts Neues abonnieren) bei: Stop-Loss-Bruch (Priorität „urgent"), SL-Nähe (Kurs < 3 % über dem Stop), Teilverkaufszonen +8 % / +20 % / +40 % (Minervini 50/25/25) und erreichtem Kursziel. Anti-Spam: Beim ersten Sichten einer Position wird nur der Ist-Zustand gemerkt — gepusht wird erst bei einem echten Übergang. Logik: mts_alarms.py. Test: python3 mts_alarms.py --test.

🩺 Status-Leiste: Oben zeigt die App den Live-Zustand: „Mac mini: online/offline" (alle 30 s neu geprüft — ein Ausfall des Dauerläufers wird sofort sichtbar, nicht erst an leeren Charts) und das Kurs-Datenalter („HH:MM · vor X Min", grün < 15 Min, orange < 60 Min, rot darüber). So ist immer klar, ob die angezeigten Zahlen frisch sind.

Daten werden bei jeder Änderung an den Server gespeichert (mts_data.json, siehe Daten & Sicherung).

KPI-Leitfaden & Lesehilfe

Der frühere Erklärkasten aus dem Control Center (seit 2026-08-06 hierher verschoben, siehe oben) — Formeln und Faustregeln zu den wichtigsten Kennzahlen im Dashboard und Trade-Planner:

📈 Win Rate: Prozentsatz profitabler Trades von allen abgeschlossenen Trades — Gewinner ÷ (Gewinner + Verlierer) × 100. Minervini-Standard: ≥ 50 % ist solide, aber wichtiger als die Win Rate allein ist das CRV. Eine 40-%-Win-Rate mit 3:1-CRV ist besser als 70 % mit 1:1-CRV.

⚖️ CRV — Chance-Risiko-Verhältnis: Verhältnis von durchschnittlichem Gewinn zu durchschnittlichem Verlust — Ø Gewinner ÷ Ø Verlierer. Minervini-Mindestwert 2:1, Ziel 3:1+. CRV > 2 bei Win Rate > 40 % ergibt ein profitables System.

🎯 Erwartungswert (EV): der wichtigste KPI, der durchschnittliche Gewinn/Verlust pro Trade — (Win Rate × Ø Gewinner) − (Verlust-Rate × Ø Verlierer). EV > 0 bedeutet, das System macht langfristig Gewinn; EV = 150 € heißt im Schnitt +150 € pro Trade.

🎲 Kelly-Kriterium: mathematisch optimale Positionsgröße zur Kapitalmaximierung — Kelly % = W − (1 − W) ÷ R (W = Win Rate, R = CRV). Full Kelly ist rechnerisch optimal, aber zu aggressiv für die Praxis; empfohlen ist Half Kelly (halbiertes Risiko bei 75 % der Rendite). Minervini selbst rechnet unabhängig davon mit fixen 1–2 % pro Trade — Kelly nie über Half-Kelly hinaus anwenden, sonst wird das Drawdown-Risiko zu hoch.

🔥 FIRE-Zahl & 4-%-Regel: das Depot-Ziel für finanzielle Unabhängigkeit — Jahresausgaben × 25 (basiert auf der Trinity Study). Beispiel: 3.000 €/Monat Ausgaben = 36.000 €/Jahr → Ziel 900.000 € Depot. Die FIRE-Jahre ergeben sich aus aktueller Sparrate und Rendite bis zum Ziel — je höher die Trading-Performance, desto kürzer der Weg.

📊 Portfolio Heat: Anteil des Gesamtkapitals, der im Einstandswert offener Positionen steckt (80 % Heat = 80 % investiert, 20 % frei). Minervini-Empfehlung: maximal 70–80 % investiert, immer einen Cash-Puffer behalten. Das Gesamtrisiko (Summe aller Stop-Loss-Abstände) sollte 5 % des Depots nicht übersteigen.

📈 Benchmark Alpha: die Mehrrendite gegenüber einem Index wie dem S&P 500 — eigene YTD-Rendite − Benchmark-Rendite. Beispiel: Depot +25 %, S&P 500 +18 % → Alpha = +7 %. Positives Alpha bedeutet echten Mehrwert gegenüber reinem Passiv-Investieren.

⚖️ Abgeltungssteuer (Deutschland): 25 % Abgeltungssteuer + 5,5 % Soli = 26,375 % effektiv, gilt für alle Gewinne (die Spekulationsfrist wurde 2009 abgeschafft). Der Freistellungsauftrag (1.000 €/Jahr steuerfrei, seit 2023) sollte zuerst genutzt werden; Verluste aus Aktienverkäufen sind nur mit Gewinnen aus Aktienverkäufen verrechenbar — steuerliche Planung heißt: Verluste vor Jahresende realisieren, wenn Gewinne überwiegen.

📐 Das Minervini-Gleichgewicht: Profitables System = Win Rate × Ø Gewinner > (1 − Win Rate) × Ø Verlierer — Risiko 1–2 % pro Trade, Stop-Loss 7–10 % unter Entry, Mindest-CRV 2:1, maximale Portfolio Heat 80 %.

🧠 Minervini Coach 2 (minervini-coach-2.html)

Lern- und Analyse-App mit den Seiten Coach, Quiz, Academy (Stage-2-Basen, VCP, Entry, Pyramidisieren), Mental und Guide. Lernfortschritt synchronisiert über GitHub-Gist. Die frühere Seite SEPA-Analyse (Trend-Template-Check, Chart-Pattern-Erkennung, Batch-Screener, Watchlist, Position Size Rechner) lebt seit 2026-07-23 nicht mehr hier, sondern in „Maick's Trading System" (Trade-Planner) — bewusste Zusammenführung mit dem dortigen Trade-Planner, siehe Hauptapp-Abschnitt. Alte Links (?ticker=…, ?page=sepa) leiten automatisch dorthin um.

📊 Minervini Markets 360 (Minervini/Minervini Dashboard.html)

Die 360°-Marktsicht. Tabs: 🚦 Marktampel (Berechnung siehe eigener Absatz unten), Technik, Marktbreite, Sentiment, Makro, Rohstoffe, Sektoren, COT, Grundlagen, Links.

Woraus die Marktampel berechnet wird (seit 2026-07 identisch in Markets 360 und im Markets360 Screener — Streamlit-App, Port 8501, siehe Server-Tabelle unten: beide rufen dieselbe Python-Engine minervini360.scoring.market direkt auf, damit nie wieder unterschiedliche Prozentzahlen erscheinen wie vor der Vereinheitlichung):

  • Trend-Template je Leitindex (S&P 500, Nasdaq): Kurs über SMA50/SMA200, SMA50 über SMA200, SMA200 seit ~1 Monat steigend — 4 Kriterien je Index. Die %-Zahl ist der Anteil erfüllter Kriterien über alle Indizes; grün gibt es nur, wenn ALLE Indizes grün sind (sonst gelb/rot).
  • Sentiment-/Bestätigungsfaktoren (dämpfen eine grüne Ampel auf Gelb, sobald seit 08/2026 mind. 3 davon auf Rot stehen — vorher 2, angehoben beim Hinzufügen der letzten beiden Faktoren, weil Follow-Through-Day und Abstand-zum-Hoch am selben Rücksetzer hängen und sich sonst gegenseitig verstärken würden; nie umgekehrt gelb→rot): Distribution Days, Marktbreite (Russell 2000), Abstand zum 52-Wochen-Hoch, VIX, Follow-Through-Day (O'Neil/IBD-Kriterium, seit 08/2026: läuft ein Rücksetzer von ≥3 % ohne dass ab Rally-Tag 4 ein Tagesgewinn ≥1,25 % bei höherem Volumen als am Vortag folgt, gilt er als unbestätigt — Bestätigungsfenster 25 Handelstage, danach gilt ein nie bestätigter Rücksetzer als veraltet statt als Dauer-Warnsignal) und 10-Jahres-Rendite (^TNX, seit 08/2026: ab 4,5 % erhöhte Wachsamkeit, ab 5,0 % Gegenwind — Minervinis eigene genannte Reizschwelle).
  • Live-Quellen: ausschließlich Yahoo Finance (Indizes/VIX/Russell/^TNX) — bewusst keine Scrapes fremder Seiten ohne API-Vertrag (CBOE Put/Call, AAII-Umfrage, CNN Fear&Greed), die ohne Vorwarnung wegbrechen können.
  • Die früheren 8 manuellen Bullish/Neutral/Bearish-Dropdowns (inkl. Handeingabe für Fear&Greed/Put-Call/AAII) sind komplett entfallen. Leitaktien-Performance und USD-Stärke (DXY) bleiben als reine Zusatzinfo in den Karten sichtbar, zählen aber nicht mehr zur Ampel (keine Minervini-Kriterien).

Markt-Heatmaps (im Marktampel-Tab): „US Sektoren · live" ist selbst gebaut aus eigenen Daten (Yahoo, ±15 Min — Standardansicht). „US Aktien · Vortag" ist das TradingView-Widget, das für US-Aktien prinzipbedingt nur den Vortagesschluss liefert (E-Badge) — daher die Beschriftung.

📊 Wochenanalyse-Link (seit 2026-08-08): Karte unter den Ampel-Faktoren im Marktampel-Tab mit Link auf eine extern erstellte Wochenanalyse (z. B. ein Grok-Chat-Share-Link) plus Datum. Der Link wird manuell gepflegt — keine Engine ruft Grok automatisch auf, dafür gibt es keine öffentliche API/Zeitplan-Anbindung — aber geräteunabhängig über einen kleinen GitHub Gist gehalten: Lesen läuft für alle Geräte ohne Token (fester, „secret" Gist, per ID ohne Auth abrufbar, genau wie ein geteilter Link), Schreiben (Button „✎ Aktualisieren") nutzt den geteilten Token gh_gist_token (localStorage, gleiche Origin wie Coach/Hauptapp — beim ersten Klick auf einem Gerät einmalig per Prompt abgefragt, danach automatisch mitverwendet). Ablauf: neuen Grok-Analyse-Link erzeugen (Prompt in Grok ausführen → „Share"-Link kopieren), dann in Markets 360 auf „✎ Aktualisieren" klicken und Link + Titel einfügen — von jedem Gerät aus, auch ohne Mac mini.

☁️ Cloud-Nachtscan (GitHub Actions, seit 2026-07-17): Der nächtliche Vollscan (minervini360.cli screen --top 100) läuft zusätzlich ohne Mac mini als Workflow im eigenen Repo Miksch52/minervini-markets-360 (.github/workflows/nightly.yml, täglich 05:45 Europe/Berlin) und lädt markets360_latest.csv per rclone nach r2:signalhub-magazine/markets360/ — von dort liest der Daily Signal Hub sie als zusätzliche Quelle (siehe dort). Der Mac-mini-LaunchAgent com.maick.markets360.nightly läuft vorerst parallel weiter.

Datenquelle: Läuft der 8080-Server, kommen Marktampel/FRED/Sektoren über ihn (lokaler Cache; die Marktampel unter /marktampel, siehe oben). Ist der Mac mini aus, holt die App die Kurse selbst — direkt von Yahoo bzw. über CORS-Proxies (VIX, FRED und US-Sektoren-Heatmap). Auch die Marktampel läuft seit 2026-07-25 ohne Mac mini (loadMarktampelViaWorker, JS-Fallback im Dashboard): Ist der 8080-Server nicht erreichbar (Mac mini aus, Pages-Version), holt das Dashboard ^GSPC/^IXIC/^VIX/^RUT/^TNX selbst über den Cloudflare-Worker und rechnet dieselbe Ampel client-seitig — eine 1:1-Portierung von minervini360.scoring.market (Index-Trend, Distribution Days, VIX, Small-Caps, 52-W-Abstand, Follow-Through-Day, 10-Jahres-Rendite, Sentiment-Dämpfung). Bei Änderungen an der Python-Engine muss die JS-Portierung im Dashboard nachgezogen werden, sonst laufen Server- und Fallback-Ampel auseinander. Als robusten, eigenen Proxy gibt es einen Cloudflare Worker (kostenlos, immer erreichbar) — Code + Anleitung in cloudflare-worker/. Nach dem Deploy die Worker-URL in die Konstante MTS_PROXY der drei Apps eintragen; dann wird er bevorzugt genutzt und die unzuverlässigen öffentlichen Gratis-Proxys (corsproxy.io ist kostenpflichtig geworden) nur noch als Notnagel. Über die HTTPS-PWA (https://…ts.net/) reicht zudem der 8090-Server die Datenendpunkte (/markt, /sector-perf, /fred) an den 8080-Server durch — so kommen echte Server-Daten ohne Mixed-Content, ohne Umweg über öffentliche Proxies. Minervinis Kernregel: Nur kaufen, wenn der Markt grün ist.

🛰️ Daily Signal Hub (Signal-Hub/signal-hub.html)

Tägliche, gerankte Ideen-Liste aus fünf Quellen: PDF (Traderfox-Magazine aus dem iCloud-Ordner), Mail (Traderfox-Signale via IMAP/freenet, Passwort im macOS-Schlüsselbund signal-hub-imap), Finviz (8 Screener: Momentum, VCP, SEPA, Zanger, Darvas, Livermore, High-Tight-Flag, Pullback), Markets 360 und der Trend-Screener (beide seit 2026-07-17 als eigene Rohsignal-Quellen eingebunden, siehe Datenquellen-Absatz unten).

Score & Faktoren

Unified Score (0–100) aus Stage-2-Trend, relativer Stärke, 52W-Hoch-Nähe, Basis, Volumen, Quellen-Konsens, der Minervini 50/80-Regel (Gap-down-Malus, siehe unten) und der Branchenstärke (seit 2026-07-24 aktiv mit Gewicht 8, ETF-basiert — siehe unten); Smart-Money (Up/Down-Volumen-Verhältnis) und CMF behalten Startgewicht 0 (sichtbar/filterbar, zählen erst nach bewusster Aktivierung im ⚙︎-Menü). Relative Stärke seit 2026-07-24 verfeinert (scorer.py::rs_gewichtet + f_rs_pool_rang): statt eines einzelnen 6-Monats-Fensters eine gewichtete Multi-Fenster-RS über 3/6/9/12 Monate (40/20/20/20 — das jüngste Quartal zählt doppelt, wie beim IBD-RS-Rating; junge Aktien mit kurzer Historie werden auf den verfügbaren Fenstern renormalisiert), und der Faktorwert ist eine 50/50-Mischung aus dem absoluten Wert gegen den Markt-Index und dem Perzentil-Rang der gewichteten RS im aktuellen Kandidatenpool (Minervini/IBD: RS ist ein Rang — das erkennt Werte, die JETZT Führung übernehmen, statt solcher, die vor Monaten liefen; der absolute Anteil bleibt drin, damit ein schwacher Pool keine Stärke vortäuscht). Das Feld rs_gewichtet steht je Treffer in signals.json. Schwellen: ≥ 70 Kauf-Kandidat, ≥ 50 beobachten. Earnings-Warnung und Depot-Abgleich („hältst du bereits") sind integriert (Depot-Abgleich nur beim lokalen Mini-Lauf, siehe Cloud-Pipeline unten).

🏭 Branchenstärke (scorer.py::f_sektor_staerke, seit 2026-07-24 ETF-basiert und mit Gewicht 8 aktiv — ersetzt die pool-interne Version vom 18.07.): Minervini-Heuristik „erst führende Branchengruppe, dann Marktführer darin". Maßstab ist jetzt der Rang des zugehörigen SPDR-Sektor-ETFs unter allen 11 S&P-500-Sektoren (XLK, XLF, XLV, XLY, XLP, XLE, XLI, XLB, XLU, XLRE, XLC — Symbole am 24.07.2026 gegen sectorspdrs.com/Yahoo verifiziert), gemessen mit derselben gewichteten 3–12-Monats-RS wie bei den Aktien (rs_gewichtet). Nur 11 zusätzliche, tages-gecachte Yahoo-Abrufe je Lauf. Warum der Umbau: Der Kandidatenpool ist bereits momentum-selektiert — ein pool-interner Branchen-Rang (alte Version) sagte deshalb wenig aus; der ETF-Rang misst, ob die Gruppe den Gesamtmarkt führt. Den „Marktführer darin"-Teil übernimmt seit demselben Umbau der Pool-Perzentil-Anteil der relativen Stärke (f_rs_pool_rang). Sektor-Namen aus Nasdaq-Profil („Finance", „Telecommunications") und Yahoo („Financial Services", „Communication Services") werden per Substring-Zuordnung auf die ETFs gemappt; EU-Werte nutzen dieselben US-Sektor-ETFs als Näherung (Sektortrends korrelieren global). Sektor unbekannt/nicht zuordenbar → neutral (0,5). Gewicht im ⚙︎-Menü weiter frei justierbar; ob die 8 gerechtfertigt sind, prüft künftig die Trefferquoten-Auswertung (siehe unten).

🛑 Stop-Distanz (pivot.py::_stop_info, seit 2026-07-18): Jeder ARMED/BREAKOUT-Treffer zeigt jetzt einen Stop-Preis + Stop-% (Badge „🛑 Stop X (-Y %)"). ARMED: Tief der letzten engen Verengung (ENG_FENSTER); BREAKOUT: Tief der Basis vor dem frischen Ausbruch. Bewusst kein Kursziel/R:R dazu — Minervini/Livermore traden ohne festes Ziel (trailen bzw. in Stärke verkaufen), ein erfundenes Ziel wäre reine Spekulation.

🧱 Basis-Zählung (scorer.py::basis_anzahl, seit 2026-07-18): grobe Näherung der Minervini-Basiszahl (1./2./3./4. Basis) über die volle Kurshistorie (nicht das auf 126 Tage gekürzte Dashboard-Chart-Fenster) — zählt abgeschlossene Zyklen „Hoch → Rücksetzer ≥10 % → neues Hoch" seit dem letzten 52-Wochen-Tief. Rein informativ, kein Score-Faktor; Dashboard zeigt ab der 3. Basis ein Vorsicht-Badge, ab der 5. ein Klimax-Warn-Badge („🧱 N. Basis ⚠️"). Test gegen den kompletten lokalen Cache (~14.800 Ticker, alle Marktphasen): Verteilung nimmt erwartungsgemäß mit steigender Basiszahl ab (0er/1er/2er am häufigsten, >8 selten) — plausibel, aber wie bei Branchenstärke eine Heuristik ohne eigenen Backtest.

📈 Extended-Filter (scorer.py::extended_pct, seit 2026-07-18): der Minervini-Standardtest für „zu weit gelaufen" — Prozent-Abstand des Kurses zur SMA50. Ab 25 % Abstand ein Vorsicht-Badge, ab 50 % ein Klimax-Warn-Badge („📈 Extended +N% ⚠️"), rein informativ, kein Score-Faktor. Anders als Branchenstärke/Basis-Zählung gibt es dafür einen echten Filter: Checkbox „📈 Extended ausblenden" (Standard: an) blendet alle Treffer ≥25 % über SMA50 komplett aus der Liste aus — beantwortet die Frage „welcher Filter zeigt mir nicht-überdehnte Setups". Test gegen den kompletten lokalen Cache (~13.100 Ticker mit genug Historie): 85 % normal, ~12 % im 25–50 %-Vorsichtsbereich, ~3 % ≥50 % stark extended — plausible Verteilung, aber ebenfalls eine Heuristik ohne eigenen Backtest. Was weiterhin fehlt: eine explizite Stage-1/2/3/4-Klassifizierung — der Faktor „① Stage-2-Trend" zeigt nur, wie viele von 8 Kriterien erfüllt sind, unterscheidet aber nicht, ob ein schwacher Wert an einer Stage-1-Basis oder einem Stage-3/4-Abwärtstrend liegt.

⛔ Minervini 50/80-Regel (scorer.py::f_gap80, seit 2026-07-22): nach einem scharfen Gap-down auf hohem Volumen (typischerweise eine Erdenttäuschung) hat eine Aktie laut Minervini eine hohe Wahrscheinlichkeit, innerhalb der folgenden ~8 Monate noch einmal unter das Gap-Tief zu fallen — kein „billig" Nachkaufen. Sucht je Ticker den jüngsten Tag im Fenster (Standard 168 Handelstage ≈ 8 Monate) mit Gap (Vortages-Close → Open) ≤ −10 % und Volumen ≥ 1,5× Ø50-Tage-Volumen; ein einzelnes Symbol kann so einbrechen, ein ganzer Index praktisch nie (nur Ereignisse wie 1987/2008/2020) — die Schwelle wirkt dadurch selbst schon als Einzeltitel- vs. Markt-Crash-Filter, ganz ohne Abgleich mit historischen Earnings-Terminen (die liegen nicht vor, earnings_info kennt nur den nächsten Termin). Anders als Basis-Zählung/Extended-Filter ist das ein echter Score-Faktor (Startgewicht 10 von 100 in config.json → score_gewichte.minervini_5080): der Malus ist direkt nach dem Gap am stärksten und klingt bis zum Fensterende linear ab. Dashboard-Badge „⛔ 50/80: −N% vor MW" (rot/fett solange ≤8 Wochen alt, sonst zunehmend transparent) zeigt Gap-Größe, Volumen-Vielfaches und verbleibende Vorsichtsdauer als Tooltip. Einstellbar im ⚙︎-Menü unter „Filter & Quellen" (an/aus, Schwelle, Volumen-Faktor, Fenster). Eigener Filter „⛔ 50/80 ausblenden" (Standard: an) blendet betroffene Treffer wie beim Extended-Filter komplett aus der Liste. Zwei Zusatz-Badges kombinieren das mit bestehenden Signalen: „🔥 Klimax-Risiko" (scorer.py::klimax_warnung) erscheint, wenn zusätzlich schon die 3./4. Basis erreicht ist (spätes Topmuster); „🩳 Short-Setup" (scorer.py::ist_short_setup, Kurs unter SMA50/150/200) ist ein rein optionaler Zusatz-Layer, standardmäßig ausgeblendet, über die Checkbox „🩳 Short-Kandidaten anzeigen" einschaltbar — der Signal-Hub bleibt sonst ein reines Long-Tool.

❄️ Frische-Gewichtung des Quellen-Konsens (config.json → frische_gewichtung, scorer.py::_decay, aktiviert seit 2026-07-19): beantwortet die Frage, wie das System zwischen frischen und veralteten PDF-/Mail-Erwähnungen unterscheidet. Zwei Schutzebenen: harte Altersgrenze bereits vor der Aufnahme als Rohsignal (PDF max_alter_tage 21 Tage, Mail 14 Tage, geprüft über Datei-mtime und ein im Dateinamen kodiertes Datum), plus jetzt zusätzlich ein exponentieller Verfall innerhalb dieses Fensters — jede Erwähnung zählt nach Halbwertszeit (Standard 10 Tage) weniger in den Konsens-Faktor. Empirisch geprüft (Vorher/Nachher-Vergleich, 1371 Ticker, 19.7.2026): kein einziger der 180 bestehenden Kauf-Kandidaten fiel unter die 70-Punkte-Schwelle (größter Rückgang ENVA 72,4→70,1), 76 % aller Ticker blieben komplett unverändert, größter Ausschlag −3,4 Punkte. Grund: Quellen-Konsens macht nur 10 von 100 Punkten aus — die dominanten Faktoren (Stage-2, RS, Volumen, Basis, Nähe-Hoch) werden ohnehin bei jedem Lauf komplett neu aus aktuellen Kursdaten berechnet, unabhängig vom Erwähnungsdatum. Eine echte, dauerhaft laufende Trendaktie kann durch den Verfall also nicht aus dem Kauf-Kandidat-Bereich fallen.

Bewusst zurückgestellt: Smart-Money/CMF dauerhaft ins Score-Gewicht zu übernehmen (bisher nur Ad-hoc-Checkbox im Dashboard) — dafür fehlt bislang ein Beleg aus echter Nutzung/Performance, genau wie bei Branchenstärke. Erst hochgewichten, wenn sich das im Alltag bewährt hat, nicht auf Verdacht.

🔎 Sofort-Überblick auf jeder Kachel (seit 2026-08-03): dieselbe kompakte Punkte-Optik wie in setup-detail.html (grün/gelb/rot-Punkt je Faktor + Klartext-Tooltip) ist jetzt direkt sichtbar auf jeder Karte, nicht mehr hinter „📈 Chart & Faktoren" versteckt — die vorherige Balken-Darstellung dort war dadurch redundant und wurde entfernt (Chart bleibt aufklappbar). Kein neuer Faktor, nur eine sofort sichtbare Zusammenfassung der bestehenden 11 Score-Faktoren.

Pivot-Detektor & Validierung

🎯 Pivot-Armed-Detektor (Signal-Hub/src/pivot.py + pivot_screener.py): Der Unified Score ist nachlaufend — er bestätigt Trends, die schon ausgebrochen sind. Der Pivot-Detektor sucht die Entstehung des Ausbruchs und läuft nach dem Scorer über signals.json (kein neuer Netz-Abruf). Vier Zustände: BREAKOUT (frische Kreuzung eines engen Basis-Pivots der letzten 3 Tage auf ≥ 1,4× Volumen; seit 2026-07-24 nur noch bis max. 4 % über dem Pivot statt 8 % — Backtest-begründet, siehe Backtest-Absatz — und die Pivot-Nähe fließt mit 20 % in die Ausbruchsqualität ein), ARMED (enge VCP-Endkontraktion + Volumen-Dry-up dicht unter dem Pivot — der eigentliche Pre-Breakout-Punkt; seit 2026-07-24 mit Supply-Gate: liegt der Supply-Score unter 0,7 — zu viel jüngstes Handelsvolumen über dem Pivot, also Overhead-Angebot —, wird der Wert zu WATCH degradiert statt scharf gemeldet, und der Supply-Score zählt mit 20 % im armed_score), CHEAT (seit 2026-07-22, siehe unten) und WATCH (Basis bildet sich noch). Ausgabe Signal-Hub/data/pivot.json; Ranking nach Qualität (enge Basis + Schub bzw. Verengung + Austrocknung). Schalter in config.json → pivot (aktiv, armed_schwelle). Push bei neuen ARMED/BREAKOUT via pivot_screener.py --notify über denselben ntfy-Kanal (Anti-Spam nur bei Zustands-Übergang; CHEAT bewusst ohne Push, siehe unten). Bugfix 2026-08-09: run.py reichte --notify bisher nie an pivot_screener.py durch — die Push-Funktion war seit ihrer Einführung faktisch totes Gleis, unabhängig vom config.json-Schalter. Jetzt bekommt pivot_screener.py --notify genau dann, wenn der Lauf ohnehin schon den normalen Signal-Push auslöst (fälliger Slot bzw. manuelles --notify/--push). Zusätzlich wandert der Anti-Spam-Zustand (pivot_state.json, bisher rein lokal unter ~/Library/Application Support/SignalHub/) jetzt genau wie state.json mit in die R2-Sicherung des Cloud-Workflows (pipeline.yml) — ohne das wäre er bei jedem Cloud-Lauf leer (frische VM) und jeder aktuell scharfe Ticker würde bei jedem der vier täglichen Läufe erneut als „neu" gemeldet statt nur beim echten Übergang. Im Dashboard (bewusst kein zweites Sheet, sondern in der bestehenden Liste): jede Kachel zeigt ein Badge 🎯 ARMED / 🚀 BREAKOUT, der Filter „🎯 nur Pivot-Setups" blendet auf die scharfen Werte ein, und die Sortierung „Pivot-Qualität" reiht sie nach oben. signal-hub.html lädt dafür data/pivot.js (file://-Fallback); fehlt die Pivot-Linse, bleiben Badges/Filter einfach leer.

📊 Pivot-Backtest / Evaluations-Loop (Signal-Hub/src/pivot_backtest.py): misst, OB die Zustände tatsächlich Forward-Return bringen. Zwei Wege: (1) Retrospektiv (Walk-Forward über die 126-Tage-Charts in signals.json, sofort) — liefert pro Status Win-Rate, Ø-Return und Ø-R (Return relativ zum Anfangsrisiko mit Stop-Logik) bei +4/+8/+12 Wochen, immer GEGEN eine Baseline (zufälliger Uptrend-Tag derselben Aktien). Wichtig: Das Universum ist die heutige Momentum-Auswahl → absolute Raten sind nach oben verzerrt; aussagekräftig ist nur der Delta gegen die Baseline. In der ersten Messung schlug weder ARMED noch BREAKOUT die Baseline — der Retro-Test kann den Detektor wegen hindsight-perfekter Titelauswahl und einseitigem Markt­regime grundsätzlich nicht fair validieren. Tuning-Splits (seit 2026-07-24): Der Retro-Test misst zusätzlich BREAKOUT nah/weit (≤/>4 % über Pivot), ARMED mit gutem/schlechtem Supply-Score (≥/<0,7) und ARMED mit/ohne Megaphone; der Forward-Test splittet ARMED nach Qualität (≥/<70). Ergebnisse der ersten Messung: BREAKOUT weit klar schlechter als nah (4W Win 57 % vs. 63 %, ΔR −0,89 vs. −0,55) → BREAKOUT_DEHN auf 4 % gesenkt + Pivot-Nähe in die Ausbruchsqualität aufgenommen; Supply-Score trennt die ARMED-Spreu drastisch (Win 67 % vs. 48 %) → Supply-Gate + Score-Bestandteil (siehe Pivot-Absatz); Megaphone trennt nicht → bleibt bewusst rein informativ; der Forward-Qualitäts-Split ist mit n≈15–18 noch zu klein und aktuell invertiert → armed_schwelle unverändert, Entscheidung wartet auf mehr gereifte Kohorten (läuft sonntags automatisch mit). (2) Forward-Logbuch (das einzig unverzerrte Maß): Der Tageslauf hängt via pivot_backtest.py --log jede ARMED/BREAKOUT-Idee mit Datum + Kurs ins Logbuch; der wöchentliche Job com.maick.pivot-backtest.plist (So 08:15) ruft --evaluate auf und bewertet die gereiften Picks gegen aktuelle Kurse. Geräteunabhängig seit 2026-08-16: Das Logbuch (pivot_logbuch.json) lag bis dahin nur unter ~/Library/Application Support/SignalHub/ — auf einem frischen Cloud-Runner leer, jeder Cloud-Lauf verwarf seine Einträge also wieder, die Stichprobe wuchs faktisch nur, wenn der Mac mini lief. Jetzt zieht/sichert sowohl der Cloud-Workflow (pipeline.yml, per rclone) als auch jeder lokale Lauf (run.py::sync_logbuch_lokal(), per scripts/sync_logbuch_pull.sh/sync_logbuch_push.sh mit wrangler) denselben Stand aus R2 (_state/pivot_logbuch.json, _state/pivot_eval_state.json) — die unverzerrte Stichprobe wächst jetzt unabhängig davon, welche Maschine gerade läuft. Diese Stichprobe wächst über Wochen/Regime und ist die Grundlage, um Schwellen/Gewichte datenbasiert zu justieren — bis sie reif ist, ist der Detektor eine plausible, aber unbewiesene Heuristik. CHEAT-Picks fließen bewusst nicht ins Forward-Logbuch ein (siehe unten). Update 2026-08-02: Mit gewachsener Stichprobe (n=83 ARMED, n=90 BREAKOUT, 4W) kehrt sich das Bild gegenüber der ersten Retro-Messung um — im unverzerrten Forward-Test liegt ARMED bei 71 % Win-Rate, BREAKOUT nur bei 34 % (Ø −4,4 %). Die Retro-Zahlen (63,9 % Win) hatten BREAKOUT durch den Universums-Bias zu gut aussehen lassen — ein Lehrbeispiel dafür, warum nur das Forward-Logbuch zählt. Konsequenz: signal-hub.htmls „Pivot-Qualität"-Sortierung und der Top-Setups-Aggregator (Price-Action-Hub/src/top_setups.py) reihen seither ARMED vor BREAKOUT (vorher umgekehrt). Bei wachsender Stichprobe erneut prüfen. Earnings-Fenster-Validierung (seit 2026-08-21): prüft mit derselben Forward-Methodik, ob Minervinis Regel „nicht kurz vor Earnings kaufen" tatsächlich einen messbaren Unterschied macht. log_heute() hängt seither earnings_tage (aus signals.json, gleiche Extraktion wie top_setups.py) an jeden neuen Logbuch-Eintrag; evaluate() splittet ARMED/BREAKOUT je zusätzlich in „earnings-nah" (0…config.jsons earnings.warn_tage, Default 10 Tage, bis zum nächsten Termin) und „earnings-fern" — im Backtest-Report je Panel als eigene Zeile/Balken sichtbar. Kein rückwirkendes Backfill möglich: bereits vor dem 21.08. geloggte Picks tragen kein Earnings-Datum und zählen bis zu ihrer Reife als „fern"; die „nah"-Kohorte wächst nur aus ab jetzt neu geloggten Fällen und braucht wie jede neue Kohorte mehrere Wochen, bevor SCHWELLE_PUSH (8 gereifte Picks) erreicht und die Aussage belastbar wird.

🎯 Trefferquoten-Auswertung für den Momentum-Score (seit 2026-07-24, Signal-Hub/src/score_backtest.py): das Gegenstück zum Pivot-Forward-Test, aber für den Score selbst — beantwortet, ob Tier A (Kauf-Kandidat) nach 4/8/12 Wochen tatsächlich besser läuft als Tier B (Beobachten), und ob beide überhaupt ihren Markt-Index schlagen. Grundlage ist das Score-Logbuch, das der Scorer ohnehin täglich schreibt (alle Treffer ab „Beobachten"-Schwelle mit Kurs, seit 24.07. auch mit Tier; lokal unter ~/Library/Application Support/SignalHub/logbuch.json). Methodik: Episoden-Dedupe (ein Ticker steht täglich im Logbuch, solange er Kandidat bleibt — gewertet wird nur die erste Nennung je Episode; erst nach 30 Tagen Pause zählt ein Wiederauftauchen neu), Forward-Return vom Erstnennungs-Kurs zum aktuellen Yahoo-Kurs (Kohorten nach Alter ≥21/50/78 Kalendertage), plus edge_idx = Differenz zum Markt-Index (^GSPC/^STOXX) im selben Zeitraum — ohne diesen Abzug sähe in einem Bullenmarkt jeder Score gut aus. Läuft täglich in run.py direkt nach dem Scorer (teilt dessen Tages-Yahoo-Cache → fast keine neuen Abrufe), Ausgabe Signal-Hub/data/score_backtest.json; das Dashboard zeigt sie im eingeklappten Panel „🎯 Trefferquoten Score (Forward-Test)" mit vorangestelltem Win-Rate-Balkendiagramm je Tier/Horizont (seit 2026-08-17, btChartHtml() — ein Hue je Horizont, hell→dunkel 4W→12W, nach dataviz-Skill-Vorgaben mit validate_palette.js --ordinal geprüft; identisches Prinzip in allen fünf Backtest-Panels, je App eine eigene, aus der bestehenden Akzentfarbe abgeleitete Ramp). Geräteunabhängig seit 2026-08-16 (siehe Persistenz-Absatz beim Pivot-Backtest oben): logbuch.json wird jetzt bei jedem Lauf — Cloud wie lokal — aus R2 gezogen und zurückgesichert, wächst also unabhängig davon, ob der Mac mini läuft. Vorher reifte es nur lokal und das Panel blieb auf der Cloud-Version dauerhaft leer, weil jeder Cloud-Runner mit einem frischen, leeren Logbuch startete. Erster Befund (Kohorte Juni/Juli 2026, nur 4W reif): Tier A lag mit Win-Rate ~36 % und Ø −4,5 % sogar hinter Tier B und ~4,5 % hinter dem Index — Momentum-Nachkauf in einen korrigierenden US-Markt. Genau solche Befunde sind der Zweck der Auswertung: Gewichte erst ändern, wenn mehrere Kohorten über verschiedene Marktphasen dasselbe Bild zeigen.

🚦 Markt-Regime-Backtest (seit 2026-08-21, Signal-Hub/src/regime_backtest.py): Bislang wurde jeder einzelne Signal-Typ (Pivot, Score, Hebel-Ampel, Price-Action-Muster, Rotation-Setups) unverzerrt forward-getestet — die Grün/Gelb/Rot-Marktampel selbst, die über 25/50/100 % Exposure entscheidet und damit der größte Einzelhebel im gesamten System ist, aber nie. Gleiches Grundprinzip wie hebel_backtest.py (--log/--evaluate, bewusst ohne Retro-Modus — eine rückwirkende Rekonstruktion müsste distribution_days()/follow_through_day() über jeden historischen Tag neu laufen lassen, für einen ersten Baustein unverhältnismäßig aufwendig): hängt täglich den Leitindex-Kurs (^GSPC für USA, ^STOXX für Europa — derselbe „leit"-Index wie in scorer.py::markt_regime()) am Tag der jeweiligen Regime-Einstufung ans Forward-Logbuch (regime_logbuch.json, R2-gesichert von Anfang an, nicht erst nachträglich retrofittet), wertet gereifte Einträge (≥21/50/78 Kalendertage) gegen den aktuellen Kurs aus. run.py ruft log_und_evaluate() bei jedem Lauf auf — anders als bei den ticker-basierten Backtests kommen aber nur zwei neue Einträge pro Tag dazu (ein Regime-Wert je Markt), die Stichprobe wächst also spürbar langsamer und braucht entsprechend länger, bis die Aussage belastbar wird. Im Backtest-Report als vierter Tab „Markt-Regime" sichtbar, gepoolt über USA+Europa (eine Trennung nach Markt würde die ohnehin kleine Stichprobe nochmal halbieren).

🎯 Exit-Regel-Backtest (seit 2026-08-21, pivot_backtest.py::_simulate_exit()): Bislang testeten alle Backtests im System nur den Einstieg (welches Setup kaufen) — simuliert jetzt zusätzlich die Minervini-Ausstiegsstaffel aus dem Trade-Planner (Maick's Trading System.html: T1 +8 %/50 %, T2 +20 %/25 %, T3 +40 %/25 %) Tag für Tag gegen den echten historischen Kursverlauf und vergleicht das Ergebnis mit einfachem Halten bis zum selben 12-Wochen-Stichtag (derselbe Schlusskurs für beide Zahlen, damit der Vergleich nicht durch unterschiedliche Zeitpunkte verzerrt wird). Nutzt Tages-Hoch/-Tief statt nur Schlusskurs — ein Stop/Ziel kann intraday ausgelöst werden, ohne dass der Schlusskurs das zeigt. Keine zusätzliche Yahoo-Anfrage nötig: scorer.py::yahoo_chart() holt bei jedem Aufruf ohnehin schon 2 Jahre komplette Tageshistorie (seit diesem Umbau zusätzlich mit einem Datums-Array je Handelstag, vorher nie extrahiert) — bislang wurde davon nur der letzte Schlusskurs genutzt, jetzt zusätzlich Hoch/Tief/Datum für dieselben ohnehin schon abgerufenen Ticker. Ergebnis wird einmalig pro Logbuch-Eintrag berechnet und dauerhaft gecacht (wie realisiert) — kein erneutes Nachrechnen bei späteren --evaluate-Läufen, die Kosten wachsen nur mit der Zahl neu gereifter Picks, nicht kumulativ mit der Zeit. Nur für ab 2026-08-21 neu geloggte Einträge möglich (ältere haben kein stop-Feld) und erst auswertbar, sobald der Chart tatsächlich 78 Kalendertage nach dem Signal erreicht. Im Backtest-Report als „Exit-Staffel"/„Exit-Hold"-Zeilen in den ARMED- und BREAKOUT-Panels sichtbar.

🧮 Pro-Faktor-Erfolgsanalyse (seit 2026-08-02, Signal-Hub/src/score_faktoren_backtest.py): score_backtest.py testet nur Tier A gegen B — dieses Skript testet die 11 einzelnen Score-Faktoren gegeneinander, um zu beantworten, welche Methoden/Filter überhaupt einen Forward-Return-Edge liefern (nicht nur der Gesamt-Score). Nutzt dieselben Logbuch-Episoden wie score_backtest.py, bucketet aber je Faktor nach Ampel (grün vs. gelb/rot) statt nach Tier — ein Faktor mit echtem Vorhersagewert sollte im grün-Eimer klar bessere Win-Rate zeigen (edge_win); nahe 0 oder negativ heißt, der Faktor trägt aktuell nicht zum Score bei und ist Kandidat für eine Gewicht-Reduktion in config.json → score_gewichte. Braucht das faktoren-Feld, das der Scorer seit 2026-08-02 zusätzlich pro Logbuch-Pick mitspeichert (wert+ampel je Faktor, kein Detail-Text) — ältere Episoden ohne dieses Feld werden übersprungen, deshalb liefert das Skript realistisch erst ab Mitte September 2026 (Episoden brauchen ≥21 Tage) eine erste Auswertung. Läuft täglich mit run.py mit (direkt nach score_backtest.py, teilt denselben Yahoo-Cache) und meldet bis dahin nur „noch keine Episode mit Faktoren alt genug" — kein gesondertes Scheduling nötig, reift einfach mit den Logbuch-Daten. Ausgabe Signal-Hub/data/score_faktoren_backtest.json.

⚡ Cheat-Pivot-Status (seit 2026-07-22, pivot.py::_cheat_pivot, nach einem Minervini-Q&A): ein früher Ausbruch vor dem vollen Stage-2-Trend-Template — Minervini nennt das „cheaten": Kurs innerhalb ±10 % der 50-Tage-Linie (statt sauber darüber), frischer Ausbruch über ein kurzes 8-Tage-Basisfenster auf ≥1,3× Volumen. Greift nur, wenn der normale Stage-2-Gate nicht erfüllt ist (sonst hätte ARMED/BREAKOUT/WATCH längst gefeuert) — kein Ersatz, ein separates, kleineres Signal. Minervini: Position klein halten, bis sich eine saubere rechte Seite entwickelt. Badge ⚡ CHEAT, per Checkbox „⚡ Cheat-Pivots einschließen" (Standard aus) zusätzlich in die „nur Pivot-Setups"-Filterung aufnehmbar — CHEAT-Ticker sind dafür bewusst vom Pflicht-Faktor-Check „Stage-2-Trend muss grün sein" ausgenommen (sie erfüllen den per Definition noch nicht). Abschaltbar über config.json → pivot.cheat_aktiv. Wie Branchenstärke/Basis-Zählung eine unvalidierte Heuristik — deshalb bewusst ohne automatischen Push und ohne Forward-Logbuch-Eintrag, bis sich das Signal in der Praxis bewährt hat.

🌀 Megaphone-Filter & 📦 Supply-Score (seit 2026-07-22, pivot.py::_megaphone/_supply_score, rein informational, kein Einfluss auf armed_score): Die bisherige Verengungs-Logik verglich nur das letzte 15-Tage-Fenster mit dem davor — megaphone prüft zusätzlich, ob sich die rechte Seite über drei aufeinanderfolgende Wellen tatsächlich beruhigt (Range nimmt ab) statt V-förmig zu expandieren; Checkbox „🌀 Megaphone ausblenden" (Standard aus) blendet betroffene ARMED-Treffer aus. supply_score (0–1) nähert das Overhead-Angebot: Anteil des Handelsvolumens der letzten 100 Tage, der über dem Pivot stattfand — bewusst ein deutlich längeres Fenster als das 25-Tage-Basisfenster selbst, sonst wäre der Pivot (per Definition das Hoch dieses Fensters) trivial fast nie überschritten. Als Tooltip-Zusatz im bestehenden ARMED/BREAKOUT-Badge sichtbar, kein eigener Filter — wie Branchenstärke eine unvalidierte Heuristik.

🕯️ Kerzencharts in den Kacheln (seit 2026-07-24): Das Minichart je Kachel (~6 Monate) zeigt statt der bisherigen Schlusskurs-Linie echte Candlesticks — dieselbe Darstellung und Farben (grün auf / rot ab) wie im Price-Action-Hub (candlechart()), damit beide Apps dasselbe Chartbild sprechen; SMA50/150/200-Linien und Volumenbalken bleiben unverändert. Dafür persistiert scorer.py::_chartdaten jetzt zusätzlich Open/High/Low je Treffer (Felder o/h/l im chart-Block, signals.json wächst dadurch von ~7 auf ~10 MB). Abwärtskompatibel: fehlen die neuen Felder (ältere signals.js, z. B. auf Pages bis zum nächsten Cloud-Lauf), rendert minichart() automatisch weiter die alte Linien-Variante. Pivot-Detektor/Backtest lesen aus dem Chart-Block weiterhin nur c/v/SMA — keine Verhaltensänderung.

📈 Leadership-Breadth, Score-Sparkline & Drop-Liste (seit 2026-07-22, Signal-Hub/data/pivot_history.json, geschrieben von pivot_screener.py::aktualisiere_history): eine kompakte Tages-Historie NUR für BREAKOUT/ARMED/CHEAT-Ticker (WATCH bewusst ausgeschlossen — zu breit), auf die letzten 15 Kalendertage zusammengeschnitten, ein Eintrag pro Kalendertag (mehrere Läufe am selben Tag überschreiben denselben Schlüssel). Drei Auswertungen im Dashboard, alle aus derselben Datei: Leadership-Breadth — Kopfzeile „🎯 N aktive Setups (vor 7T: M · ↑/↓/→)", ein Frühindikator für Marktbreite unabhängig von einem offiziellen Follow-Through-Day (Minervini: „führende Aktien haben erste und letzte Stimme"). Score-Sparkline — kleine Farbbalken-Reihe je Kachel (🟠 ARMED/🔴 BREAKOUT/🟣 CHEAT der letzten Tage), reines CSS ohne externe Lib. Drop-Liste — eingeklappter Abschnitt „📉 Kürzlich rausgefallen" oberhalb der Trefferliste: Ticker, die gestern noch ARMED/BREAKOUT waren und es heute nicht mehr sind (Comeback-Watch/Frühwarnung), als eigener Abschnitt statt Teil der Haupt-Filterpipeline, da sie per Definition nicht mehr im gefilterten Grid auftauchen würden. Wie pivot.js gibt es einen pivot_history.js-file://-Fallback; fehlt die Datei, bleiben alle drei Anzeigen einfach leer.

Standard-Ansicht & Filter

🔒 Standard-Ansicht (seit 2026-07-18): Das Dashboard startet nicht mehr ungefiltert, sondern mit einer strengen Kombination für „nur die aussichtsreichsten Chart-/Volumen-Setups im Minervini/Livermore-Stil": Sortierung Pivot-Qualität, Filter nur Pivot-Setups (ARMED/BREAKOUT) und Earnings ausblenden aktiv, Smart Money einrechnen an, sowie die Faktor-Chips Stage-2-Trend und Volumen vorausgewählt (alle Quellen-Typ-Chips ebenfalls aktiv, das schränkt zunächst nichts ein, gibt aber den Hebel, einzelne schwache Quellen gezielt abzuwählen). Bewusst nicht im Standard: „Basis/VCP" (Test mit 1377 Tickern am 18.7.2026: schränkt am stärksten ein, 14→8 Treffer bei sonst gleicher Kombi — per Chip zuschaltbar) und „Branchenstärke" (Test: 14→2, viel zu hart für einen Default — anders als Stage-2/Volumen/Pivot ist dieser Faktor noch unvalidiert, kein Backtest wie beim Pivot-Detektor; als Ranking-Info sichtbar, aber bewusst kein Pflicht-Ausschlusskriterium). Ebenfalls nicht mit drin: „nur neue", „ohne Depot", „Multi-Quellen bestätigt" — das sind Frische-/Depot-Filter, keine Chart-/Volumen-Kriterien. Default-Ergebnis mit dem vollen Datensatz: 14 Treffer; „Basis/VCP" dazuwählen → 8, „nur Pivot-Setups" abwählen → 22. Alle Regler bleiben frei kombinierbar, das ist nur der Startzustand beim Laden. Konsolidierung (18.7.2026): Die Filterleiste war als ein einziger undifferenzierter Kontroll-Block unübersichtlich geworden — jetzt in sichtbare Abschnitte gruppiert (Grundfilter · Qualitäts-Filter · Faktoren · Sonstiges), und die 24 Quellen-Typ-Chips stecken standardmäßig eingeklappt in einem eigenen „🌐 Quellen"-Aufklapper mit Live-Zähler (x/24 aktiv), statt permanent drei Zeilen zu belegen.

Finviz-Liquiditäts-Mindestfilter vereinheitlicht (seit 2026-07-18): „Momentum 52W-Hoch" (vorher sh_price_o1) und „High Tight Flag" (vorher sh_price_o5) auf den gemeinsamen Floor sh_avgvol_o500 + sh_price_o10 angehoben, den 5 der 8 Screener ohnehin schon nutzten — strengere Screener (Zanger o1000, Livermore Pivotal o2000/o20) bleiben unverändert, es wurde nur der Floor angehoben, nichts verwässert. Finviz-Filtercodes vorab gegen die offizielle Doku verifiziert (kein eigener Dollar-Volumen-Filter vorhanden, nur avgvol in Stück + Price in $ kombinierbar).

🚦 Markt-Regime-Ampel (seit 2026-07-24, löst den reinen Server-Chip vom 22.07. ab): Der Scorer berechnet jetzt bei jedem Lauf je Markt (USA: seit 2026-08-16 ^GSPC UND ^IXIC kombiniert, Europa weiterhin nur ^STOXX — Details zur USA-Erweiterung im nächsten Absatz; für die relative Stärke der Einzelaktien bleibt ^GSPC alleiniger Referenzindex) eine Regime-Ampel und schreibt sie nach signals.json → marktregime (scorer.py::markt_regime): 4 Kriterien (Kurs>MA50, Kurs>MA200, MA50>MA200, MA200 steigend — 21-Tage-Lookback, konsistent zu f_stage2), grün = Kurs>MA200 UND MA50>MA200 UND mindestens 3 von 4 Kriterien erfüllt; rot = Kurs<MA200 ODER MA50<MA200; gelb = dazwischen — seit 2026-07-27 identisch zur 4-Kriterien-Schwelle der vollen Minervini-Ampel (assets/marktampel.js::ampelEvaluateIndex, siehe unten); zuvor verlangte „grün" hier zusätzlich hart Kurs>MA50 und prüfte MA50>MA200 gar nicht, wodurch die Score-Dämpfung (nächster Absatz) und der volle Header-Ampel-Chip bei Kurs knapp unter MA50 (sonst überall bullisch) unterschiedliche Farben zeigten — genau der Fall, der den Fehler auffallen ließ. Damit funktioniert die Ampel überall — auch auf der Pages-Version ohne erreichbaren Mac mini (vorher: Chip nur bei erreichbarem 8080-Server). Der Header-Chip zeigt beide Märkte („🟡US · 🟢EU"); ist der 8080-Server erreichbar, wird der Live-VIX als Zusatzinfo nachgeladen (ohne marktregime-Daten in einer alten signals.json greift weiter der alte reine Server-Check). Und die Ampel ist jetzt ein echtes Gate: Bei roter Ampel unterdrückt notify.py die Push-Signale aus dem betroffenen Markt (Minervini: keine neuen Positionen im schwachen Markt) — teilweise Unterdrückung wird im Push-Fußtext ausgewiesen, bei komplett rotem Markt kommt statt Stille eine ehrliche „🔴 Markt rot"-Meldung mit der Zahl der zurückgehaltenen Kandidaten. Im Dashboard bleiben alle Treffer sichtbar (die Ampel liefert dort den Kontext). Schalter: config.json → marktregime (aktiv, push_bei_rot_unterdruecken; Cloud-Lauf: SIGNALHUB_CONFIG_JSON-Secret nachziehen — ohne den Block gelten dieselben Defaults, beides an). Und seit 2026-07-24 auch ein Score-Gate, nicht nur ein Push-Filter: scorer.py::f_marktampel_dynamik läuft als letzter Post-Pass nach Fundamental/Sektor/RS-Pool-Rang und dämpft den fertigen Unified Score jedes Tickers multiplikativ nach der Ampel seines Marktes (USA/Europa getrennt bewertet) — grün bleibt unverändert (×1,0), gelb ×0,92, rot ×0,80 (Standardwerte, einstellbar unter config.json → marktregime → score_gelb_faktor/score_rot_faktor, Schalter score_daempfung_aktiv); „unbekannt" (zu wenig Index-Historie) dämpft nicht, damit fehlende Daten nie bestrafen. Dadurch rutscht z. B. ein Score-75-Kauf-Kandidat bei roter Ampel automatisch unter die 70er-Schwelle zu „Beobachten" statt nur einen unbeachteten Kontext-Hinweis zu bekommen — Minervini/Weinstein: „Erst das Umfeld, dann die Aktie", nicht nur eine Anzeige daneben. Im Dashboard zeigt ein eigenes Badge auf der Karte („🔴 Markt ×0,8" bzw. „🟡 Markt ×0,92"), wenn und warum gedämpft wurde; die Dämpfung zieht auch durch den Smart-Money-Recompute (effScore()) durch, damit sie beim Slider-Toggle nicht verschwindet.

🗳️ Politikzyklus-Badge (seit 2026-08-15): kleiner neutraler Chip neben der Marktampel im Header („🗳️ Zyklusjahr 2/4"), berechnet aus dem 4-Jahres-Politikzyklus nach Richard S. Love (Superperformance Stocks, 1977) — US-Präsidentschaftswahlen liegen in allen durch 4 teilbaren Jahren, Zyklusjahr 1 = Jahr nach der Wahl (historisch schwächste Phase), 3 = Vorwahljahr (historisch stärkste Phase), 4 = Wahljahr selbst (scorer.py::politikzyklus_jahr(), schreibt nach signals.json → politikzyklus). Bewusst reiner Kontext-Hinweis — anders als die Markt-Regime-Ampel im Absatz oben beeinflusst er weder den Score (kein neuer Faktor in f_marktampel_dynamik) noch die Push-Unterdrückung in notify.py: die Datenbasis sind nur wenige historische US-Wahlzyklen, ein hartes Signal daraus wäre Overfitting-Risiko. Tooltip nennt Quelle und Charakter der Heuristik explizit. Bewusst nicht nachgebaut bei derselben Anfrage: ein eigener Distribution-/Accumulation-Days-Zähler und ein Follow-Through-Day-Highlight fürs Dashboard (ebenfalls aus Loves Studie abgeleitet) — beides existiert bereits vollständig in der geteilten assets/marktampel.js (siehe „Einheitliche Marktampel" oben, Faktoren „Distribution Days" und „Follow-Through Day"), wäre also Doppelarbeit gewesen. Die eine damals noch offene Lücke — der automatisierte Cron-Push prüfte nur die einfache MA50/MA200-Ampel, nicht die Sentiment-Faktoren — ist im nächsten Absatz geschlossen.

⚠️ Distribution-Days-/Follow-Through-Day-Sentiment-Gate im Push (seit 2026-08-15): Der automatisierte Cron-Push in notify.py läuft ohne Browser/Cloudflare-Worker und sah bis dahin nur die einfache MA50/MA200-Ampel aus markt_regime() — die Distribution-Days-/Follow-Through-Day-Faktoren der vollen Ampel (voriger Absatz) blieben ihm verborgen, weil sie clientseitig in assets/marktampel.js berechnet werden. Jetzt rechnet scorer.py::distribution_days()/follow_through_day() — 1:1-Portierung derselben JS-Funktionen, gleiche Schwellen (25-Tage-Fenster, ≥0,2 % Rückgang bei Volumenanstieg = Distribution Day; ≥3 % Rücksetzer, ab Tag 4 ein Tagesgewinn ≥1,25 % bei Volumenanstieg = Follow-Through Day) — direkt serverseitig auf denselben Index-Kursen/-Volumen (^GSPC/^STOXX), die markt_regime() ohnehin schon lädt: keine neue Datenquelle nötig, anders als VIX/Small-Caps/10-Jahres-Rendite in der vollen Browser-Ampel, die deshalb bewusst nicht mitportiert wurden. Ergebnis steht als distribution_days/distribution_state/follow_through/sentiment_warnung/sentiment_hinweis in signals.json → marktregime.<Markt>. USA seit 2026-08-16 auf zwei Indizes erweitert (^GSPC + ^IXIC): Auslöser war eine Nutzer-Meldung, dass der Morning-Brief-Push andere Werte zeigte als Markets 360/die volle Browser-Ampel (z. B. „4 Distribution Days, FTD bestätigt" im Push gegen „5 Distribution Days, FTD ausstehend" im Dashboard) — Ursache war nicht ein Rechenfehler (identische Schwellen), sondern dass markt_regime() für USA bis dahin ausschließlich ^GSPC auswertete, während sowohl /marktampel (externe minervini360.scoring.market-Engine) als auch die volle Browser-Ampel (assets/marktampel.js) für USA schon immer ^GSPC UND ^IXIC kombinieren. markt_regime() nimmt jetzt eine Liste von Index-Paaren entgegen (config.json → maerkte.USA.index_yahoo ist jetzt ein Array) und kombiniert sie identisch zum Dashboard: Trend-Ampel grün nur, wenn alle Indizes grün sind, Distribution Days als Maximum über beide Indizes, Follow-Through-Day-Status als schwächster Zustand beider Indizes (ein unbestätigter Rücksetzer in einem Index reicht). Europa bleibt bei einem einzelnen Index (^STOXX, keine Dashboard-Gegenstelle). Bei Cloud-Läufen muss dafür das GitHub-Secret SIGNALHUB_CONFIG_JSON im signal-hub-Repo mit demselben Array-Wert nachgezogen werden — ohne den Nachzug rechnet der Cron-Job dort weiter nur mit ^GSPC.

Bedeutung: Institutionelle Fonds verkaufen selten an einem Tag, sondern verteilen Positionen über Tage mit erhöhtem Volumen — 5 oder mehr solcher „Distribution Days" binnen 25 Handelstagen sind laut O'Neil/IBD ein verlässliches Frühwarnsignal, das dem eigentlichen Trendbruch (MA50/MA200 kippen) oft vorausläuft: ein Markt kann also technisch noch grün sein und trotzdem schon unter institutionellem Verkaufsdruck stehen. Der Follow-Through Day ist das Gegenstück beim Wiederaufbau: nach einem echten Rücksetzer (≥3 % vom Zwischenhoch) gilt ein neuer Aufwärtstrend laut Minervini/O'Neil erst als bestätigt, wenn ab Tag 4 ein kräftiger Anstieg (≥1,25 %) mit steigendem Volumen auftritt — ohne diese Bestätigung ist ein Rücksetzer nur „möglicherweise vorbei", keine Kaufgrundlage.

Nutzung: Beide Faktoren wirken als zusätzliches, von der Trend-Ampel unabhängiges Gate — Schalter config.json → marktregime → push_bei_sentiment_warnung_unterdruecken (Default true, Cloud-Lauf: optional im SIGNALHUB_CONFIG_JSON-Secret nachziehen, ohne den Schlüssel gilt derselbe Default). Bei sentiment_warnung = true (5+ Distribution Days oder unbestätigter Rücksetzer) hält notify.py Kandidaten aus dem betroffenen Markt zurück — im Dashboard bleiben sie sichtbar. Der Push nennt den Grund explizit: bei komplett leerem Push „⚠️ Sentiment-Warnung – Push-Signale zurückgehalten" mit Klartext-Begründung; bei teilweiser Unterdrückung ein eigener Fußtext „⚠️ N Wert(e) aus … zurückgehalten (Distribution Days/Follow-Through-Day)", getrennt vom „🔴 … unterdrückt (Markt rot)"-Fußtext, weil es zwei unabhängige Ampeln sind. Die schwächere Vorstufe (3–4 Distribution Days, „beobachten") unterdrückt nichts, taucht aber im Morning Brief als Klartext-Zeile hinter dem Ampel-Hinweis auf (_ampel_zeilen()) — bewusst nur der harte 5+-Fall (bzw. unbestätigter Rücksetzer) filtert, damit das Gate nicht zu häufig greift und seinen Frühwarnwert verliert.

🏆 Top-of-the-Day-Modus, Branchenstärke- & Leadership-Persistenz-Sortierung (seit 2026-07-22): drei neue Sortier-Optionen im Dropdown, alle aus bereits vorhandenen Daten — kein neuer Score-Faktor, keine neue Datenquelle. „Branchenstärke" sortiert nach dem bisher nur als Ranking-Info sichtbaren, ungewichteten sektor_staerke-Faktor. „Leadership-Persistenz" sortiert nach der Anzahl der im 15-Tage-Fenster erfassten Tage, an denen ein Ticker BREAKOUT/ARMED/CHEAT war (pivot_history.json, siehe Pivot-Detektor-Abschnitt) — ein Ticker mit mehrtägiger Serie zeigt echtere Führungsstärke als ein Eintagesfund. „🏆 Top-Kombi" kombiniert Pivot-Qualität (50 %), Branchenstärke (30 %) und Multi-Quellen-Bestätigung (20 %, gedeckelt bei 3 Quellen) zu einem Konzentrations-Score. Checkbox „🏆 Nur Top 5 (Fokus-Modus)" erzwingt diese Sortierung und kappt die Liste hart auf 5 Treffer — Minervini handelt konzentriert in wenige echte Marktführer statt breit gestreut; die Standard-Pivot-Sortierung bleibt bei >250 gleichzeitig scharfen Tickern sonst unhandlich für den Tagesgebrauch.

🔗 Multi-Quellen-Bestätigung im Ranking (seit 2026-07-22): das Feld quellen.unabhaengig (Anzahl unabhängiger bestätigender Engines) floss bisher nur in den Filter „Multi-Quellen bestätigt" ein, nicht in die Sortierung. Jetzt zusätzlicher Tiebreaker in der Pivot- und der Score-Standardsortierung: bei gleicher Pivot-Qualität/gleichem Score gewinnt der zusätzlich bestätigte Ticker.

🥇 Code 33 als filterbares Kriterium (seit 2026-08-09): war bis dahin nur live auf der Setup-Analyse-Detailseite verfügbar (siehe dortiger Abschnitt für die Kriterien-Herleitung) — jetzt zusätzlich als Pipeline-Post-Pass direkt im Dashboard. scorer.py::f_code33() (Aufruf direkt nach f_fundamental()) ist eine Python-Portierung von cloudflare-worker/mts-cors-proxy.js::fetchCode33() — dieselben drei TraderFox-Schwellen (EPS-Wachstum Quartal ggü. Vorjahr >40 %, Umsatzwachstum >7 %, Nettogewinnmarge um >2 Prozentpunkte verbessert über 2–3 Quartale), dieselbe Yahoo-fundamentals-timeseries-Datenquelle, gegen mehrere Ticker mit identischen Ergebniswerten wie die JS-Fassung verifiziert. Läuft wie der Fundamental-Post-Pass nur für Treffer ab Beobachten-Schwelle, 7-Tage-Cache (code33_cache.json), Deckel 300 Abrufe/Lauf — kein Score-Einfluss (das deckt bereits der bestehende „fundamental"-Faktor ab), reines Zusatzkriterium. Neues Badge „🥇 Code 33" auf der Kachel nur bei vollständig erfülltem 3/3 (bewusst keine Teilerfüllungs-Badges — das wäre nur der Fundamental-Faktor mit anderen Worten), Tooltip zeigt die drei Einzelwerte gegen ihre Schwellen. Neuer Filter „🥇 nur Code 33" in der Gruppe „Sonstiges" blendet auf dieselbe Bedingung ein. Nebenbei gefundener und behobener Fehler: scorer.py::yahoo_crumb() holte das Session-Cookie bisher von finance.yahoo.com statt wie das bereits produktive JS-Pendant im Worker von fc.yahoo.com — Ersteres lieferte nur ein wirkungsloses „dflow"-Cookie, mit dem der anschließende Crumb-Abruf zuverlässig mit 401 Unauthorized scheiterte (live gegen beide Varianten getestet, nicht nur vermutet). Das war vermutlich die Hauptursache für die im Fundamental-Post-Pass-Log wiederholt beobachteten „Crumb fehlt → Nasdaq-Fallback"-Meldungen. Fix betrifft yahoo_crumb() zentral und verbessert damit automatisch auch den bestehenden Fundamental-Faktor sowie yahoo_profil_earnings() (EU-Sektor/Branche), nicht nur Code 33.

📊 Fundamental-Faktor (seit 2026-07-24 echter Score-Faktor mit Gewicht 8, scorer.py::f_fundamental — erweitert das Pass/Fail-Badge vom 22.07.): O'Neils C-A-N bzw. Minervinis SEPA verlangen Gewinn- und Umsatzwachstum — der Score war bis dahin rein technisch. Der neue Post-Pass holt für Treffer ab Beobachten-Schwelle EPS- und Umsatzwachstum aus zwei Quellen mit gemeinsamem 7-Tage-Cache (fundamental_cache.json, Fundamentals ändern sich quartalsweise; auch Fehlversuche werden gecacht), max. 300 Abrufe je Lauf: (1) Yahoo quoteSummary/financialData (earningsGrowth/revenueGrowth, jüngstes Quartal vs. Vorjahresquartal, Felder am 24.07.2026 verifiziert) — erste Wahl, braucht aber den Crumb, der zeitweise Yahoo-seitig blockiert ist; (2) als Crumb-freie Zweitquelle für US-Werte das Nasdaq-Jahres-Income-Statement (api.nasdaq.com/api/company/{symbol}/financials?frequency=1, am 24.07.2026 gegen die echte Antwort verifiziert; scorer.py::nasdaq_fundamental) — Total Revenue und Net Income über vier Geschäftsjahre (Nasdaq liefert die Spalten value2value5 in einem einzigen Abruf) → Jahres-YoY, wobei Net-Income-Wachstum als Näherung fürs EPS-Wachstum dient (Aktienzahl meist stabil; O'Neil/Minervini zielen ohnehin aufs Gewinnwachstum). Sie springt ein, wenn Yahoo nichts liefert; ein erfolgloser Yahoo-only-Cache blockiert den Nasdaq-Versuch bewusst nicht (sonst bliebe der Fallback bei blockiertem Crumb 7 Tage ungenutzt), und Fehlversuche gegen Nasdaq selbst werden gecacht (kein Hämmern). Bewertung: EPS 0 % → 0, ≥25 % → 1; Umsatz 0 % → 0, ≥20 % → 1; Mittel der vorhandenen Teile. Beschleunigungs-Bonus (seit 2026-07-24, +0,15 gedeckelt bei 1,0): aus den vier Nasdaq-Jahresspalten lässt sich neben der aktuellen YoY-Rate auch die Vorjahres-YoY-Rate bilden (eps_g_prior) — wächst der Gewinn schneller als in der Vorperiode (bei positivem Wachstum), gibt's den Bonus, denn Minervini gewichtet beschleunigendes Wachstum höher als die reine Höhe der Rate. Nur über den Nasdaq-Zweig verfügbar (US), da Yahoos financialData-Modul nur die aktuelle Rate liefert, keine Historie. Fallback ohne Zahlen aus beiden Quellen (z. B. EU-Wert bei blockiertem Crumb, unprofitable Aktie mit Vorjahresverlust, ADR/nicht gelistet): Fund über den Finviz-SEPA-Screener (harter EPS/Sales>20%-QoQ-Filter) oder „Code 33" im Trend-Screener-Kontext → 0,75; sonst leichter Malus 0,35 (bis 2026-07-24: neutral 0,5) — komplett fehlende Fundamentaldaten sollen nicht wie eine Bestätigung wirken, bleiben aber bewusst „gelb" statt „rot" (ampel()-Schwelle 0,33), da es oft nur an der Datenquelle liegt. Der Detail-Text kennzeichnet die Herkunft (Quartal-Yahoo vs. „Jahr, YoY · Nasdaq", plus „beschleunigt ggü. Vorjahr" wenn der Bonus griff). Das „📊 EPS/Sales +20%"-Badge bleibt daneben bestehen; Faktor ⑪ in Legende/Filterchips. Erste Messung 24.07.2026 (Crumb blockiert): 277 US-Werte über die Nasdaq-Zweitquelle mit echten Zahlen versorgt (z. B. AMD EPS +164 %/Umsatz +34 %, DELL +29 %/+19 %), Rest neutral bzw. jetzt leicht negativ ohne Zahlen.

⚡ Hebel-Ampel (seit 2026-08-16, signal-hub.html::hebelAmpel()): eine Reife-Ampel speziell für Hebelprodukte (Knock-Outs/Optionsscheine, gehandelt z. B. über Finanzen.net Zero) — kombiniert ausschließlich bereits vorhandene Signale zu einem einzigen Ampelwert, keine neue Berechnung. Ein gehebelter Trade verlangt eine engere Stop-Distanz und weniger Fehlertoleranz als ein Cash-Trade, daher strenger als der bestehende „🏆 Top-Setups"-Filter: 🟢 bereit nur, wenn alle Kriterien gleichzeitig erfüllt sind — Markt-Ampel grün, Stage-2-Trend-Template grün, Basis/VCP eng (= geringe Volatilität vor dem Einstieg, nicht während der Haltedauer — das wäre ein Widerspruch zum Zweck des Hebels), ein Pivot-Trigger (ARMED/BREAKOUT, Livermores Pivotpunkt), kein Extended (<25 % über SMA50), keine akute Earnings-Sperre und kein 50/80-/Klimax-Risiko. Fehlen nur Markt-Ampel oder Trend-Template, gilt der Wert als 🔴 ungeeignet (kein Badge, wäre auf fast jeder Karte sichtbar); sind Markt/Trend intakt, aber mindestens ein weiteres Kriterium offen, 🟡 im Fokus (Tooltip nennt die offenen Punkte). Badge steht als erster Hinweis noch vor „📚 N Ausgaben" auf der Kachel; neuer Filter „⚡ nur Hebel-Kandidaten (grün)" in der Gruppe „Qualitäts-Filter" (Standard aus) — wie „🏆 Top-Setups" bewusst von der Faktor-Pflicht („Volumen muss grün sein") ausgenommen, da ARMED-Kandidaten typischerweise Volumen-austrocknung statt -schub zeigen. Identische Kriterien serverseitig in Price-Action-Hub/src/scorer.py::hebel_ampel() — siehe dortigen Wiki-Abschnitt für die Begründung, warum das dort in Python statt clientseitig berechnet wird.

Datenquellen & Cloud-Pipeline

🔗 Datenfusion Markets 360 / Trend-Screener → Signal-Hub (seit 2026-07-17): Beide Engines laufen inzwischen selbst als eigene GitHub-Actions-Cloud-Workflows (kein Mac mini nötig) und laden ihr Ergebnis per rclone in denselben R2-Bucket signalhub-magazine hoch, den auch die Signal-Hub-Pipeline nutzt: signalhub-magazine/markets360/markets360_latest.csv (Repo Miksch52/minervini-markets-360, Workflow nightly.yml, täglich 05:45) und signalhub-magazine/trendscreener/signals.json (Repo Miksch52/lokaler-trend-screener, Workflow nightly.yml, Mo–Fr 23:00). Der bestehende rclone copy r2:signalhub-magazine/ _magazine/-Schritt in pipeline.yml (Repo Miksch52/signal-hub) zieht beide Präfixe automatisch mit; zwei neue Skripte markets360_screener.py und trendscreener_screener.py lesen sie und schreiben Rohsignale im selben Schema wie PDF/Mail/Finviz. Lokaler Lauf auf dem Mac mini: Dort existiert _magazine/ nicht (nur der Cloud-Checkout zieht es per rclone) — beide Skripte probieren deshalb zuerst die Original-Dateien, die Markets 360 und der Trend-Screener als eigene LaunchAgents auf derselben Maschine ohnehin schon direkt schreiben (MinerviniMarkets360/exports/markets360_latest.csv bzw. ~/Library/Application Support/LokalerTrendScreener/output/signals.json, siehe pfade.py::LOKAL_MARKETS360/LOKAL_TRENDSCREENER), und fallen nur zurück auf _magazine/, wenn diese fehlen (Cloud-Lauf; die Traderfox-PDFs selbst liegen dabei direkt im Root von _magazine/, kein eigenes Präfix, pdf_screener.py faellt seit 2026-07-18 nach demselben Muster auf pfade.EXTERN_PDF_ORDNER zurueck). Fix 2026-07-18: vor dieser Änderung lieferten beide Quellen bei einem lokalen "Aktualisieren"-Klick fälschlich 0 Signale (Status-Zeile zeigte "Markets360 ⚠️0 · Trend-Screener ⚠️0"), obwohl der Cloud-Lauf zeitgleich echte Fusionsdaten hatte. Der Scorer behandelt Markets 360 und den Trend-Screener als eigene, unabhängige Anbieter (nicht mit den TraderFox-Signalen verrechnet) — jeder Treffer bekommt ein Feld quellen.unabhaengig mit der Liste bestätigender Engines. Im Dashboard zeigt das ein Badge „🔗 N× bestätigt" auf der Kachel und der neue Filter „🔗 Multi-Quellen bestätigt" blendet auf Ticker ein, die von mindestens zwei unabhängigen Engines gleichzeitig gesehen werden — das ist die angestrebte Gesamtauswertung aller Minervini-Quellen an einer Stelle. Schwellenwerte: Die 30 % (über 52W-Tief) / 25 % (unter 52W-Hoch) im Trend-Template waren bei allen drei Engines schon identisch; der SMA200/150-Steigungs-Lookback in scorer.py::f_stage2 wurde von 22 auf 21 Handelstage angeglichen (wie MinerviniMarkets360s sma200_uptrend_lookback). RS-Schwellen und VCP-Erkennung bleiben bewusst je Engine eigenständig — unterschiedliche Konzepte (stetiger Faktor vs. hartes Kriterium vs. Leader-Label), keine gemeinsame Zahl; eine echte Code-Zusammenführung wäre ein groß angelegter, risikoreicher Umbau ohne Tests in mehreren der beteiligten Repos und ist bewusst zurückgestellt. Qualitätsfilter für Markets 360 (seit 2026-08-20): markets360_latest.csv enthält das gesamte gescannte Universum (~625 Ticker, minervini360.cli screen exportiert immer den vollen DataFrame, --top begrenzt nur die Konsolenausgabe) — ohne Filter zählte praktisch jeder Signal-Hub-Treffer automatisch als „von Markets 360 bestätigt" (72 % Überschneidung gemessen), unabhängig von der tatsächlichen Fab5/TT_Pass-Qualität, und verwässerte damit den Konfluenz-Gedanken. markets360_screener.py filtert jetzt wie der Trend-Screener von Anfang an („nur auffällige Treffer, nicht das ganze Universum"): eine Zeile zählt nur noch als bestätigende Quelle, wenn sie config.json::markets360_filter.min_fab5 erreicht oder (falls tt_pass_zaehlt_auch) TT_Pass=true hat — beide Kriterien einstellbar, ODER-verknüpft. Test gegen echte Daten (Default min_fab5=70): 625 → 142 bestätigte Ticker; von 6 Top-Setups mit Markets-360-Bestätigung blieben 5, nur der mit schwächstem Fab5/TT_Pass fiel korrekt raus. Fehlt der Config-Abschnitt (Cloud-Secret SIGNALHUB_CONFIG_JSON noch nicht nachgezogen), filtert das Skript sauber gar nicht statt zu crashen.

☁️ Cloud-Pipeline (GitHub Actions, seit 2026-07, Repo-Split seit 2026-07-28, Parallel-Jobs seit 2026-08-09): Der komplette Lauf (PDF/Mail/Finviz/Markets 360/Trend-Screener/Scoring/Push, danach parallel Price-Action-Hub + Rotation-Dashboard) läuft zusätzlich ohne Mac mini als GitHub-Actions-Workflow (.github/workflows/pipeline.yml, öffentliches Repo Miksch52/signal-hub). Warum öffentlich: GitHub-Actions-Minuten für private Repos sind kontoweit auf 2.000/Monat gedeckelt (Free-Plan) — bei 4×/Tag Cron + häufigen manuellen Cloud-Trigger-Klicks war dieses Kontingent Ende Juli 2026 aufgebraucht, alle drei damaligen Cloud-Repos scheiterten mit „job was not started because recent account payments have failed…". Öffentliche Repos haben unbegrenzte Minuten; Miksch52/maick-trading-system selbst bleibt aber privat (die Git-Historie enthält alte Depot-/Kontodaten aus der Zeit vor der Datentrennung) — deshalb wurden Signal-Hub UND Price-Action-Hub in zwei frische, öffentliche Repos ausgelagert (signal-hub, price-action-hub, ohne übernommene Historie), während Hauptapp/Wiki/Coach/Markets-360-Dashboard im privaten Hauptrepo bleiben. Vier Jobs statt einer Kette (seit 2026-08-09): Price-Action-Hub und Rotation-Dashboard hängen beide nur von Signal-Hubs Ausgabe ab, nicht voneinander (Rotation-Dashboard braucht nie Price-Action-Hub-Output) — sie laufen deshalb als zwei parallele Jobs (price-action-hub, rotation-dashboard), die vom signal-hub-Job per actions/upload-artifact/download-artifact genau die benötigten Dateien bekommen (data/signals.json, bei Rotation-Dashboard zusätzlich die Markets-360-CSV aus dem Magazin) statt den kompletten Signal-Hub-Checkout mitzuziehen. Ein vierter Job (deploy) wartet auf alle drei und bündelt Upload nach R2 + Deploy-Trigger. Kürzere Gesamtlaufzeit, dieselbe pfade.py-Ordnerstruktur wie lokal in iCloud, keine Code-Änderung in den drei Repos nötig.

Die Traderfox-Magazine liegen gespiegelt in einem Cloudflare-R2-Bucket (signalhub-magazine). Automatischer Sync seit 2026-08-20 (vorher: manueller Upload per Cloudflare-Dashboard/rclone nötig, was regelmäßig vergessen wurde und die PDF-Quelle im Cloud-Lauf strukturell auf 0 hielt — siehe Postmortem unten): scripts/upload_magazine_to_r2.py spiegelt alle PDFs im aktuellen Alters-Fenster (config.json::quellen.pdf.max_alter_tage, dieselbe Filterfunktion wie pdf_screener.py::finde_pdfs, damit lokaler Scan und R2-Spiegel nie auseinanderlaufen) per wrangler r2 object put/delete nach R2 — nur neue/geänderte Dateien werden hochgeladen, aus dem Fenster gefallene wieder entfernt (sonst würde der Bucket unbegrenzt wachsen und jeder Cloud-Lauf müsste immer mehr Altlast im „Magazine aus R2 laden"-Schritt pullen). Ein LaunchAgent (com.maick.signalhub.pdfsync.plist, WatchPaths auf den iCloud-Magazin-Ordner + 6-Std.-Sicherheitsnetz StartInterval + RunAtLoad) stößt das automatisch an, sobald ein neues Magazin im iCloud-Ordner landet — kein manueller Schritt mehr nötig, muss aber auf jedem Mac installiert sein, auf dem PDFs gespeichert werden (Mac mini und MacBook), da WatchPaths nur lokal auf der jeweiligen Maschine feuert. Fix 2026-08-21: Auf dem Mac mini lief der manuelle Terminal-Aufruf sofort fehlerfrei, der LaunchAgent selbst brach aber bei jeder Datei mit env: node: No such file or directory ab — npx wird per absolutem Pfad gefunden, aber dessen Shebang #!/usr/bin/env node scheitert in der minimalen launchctl/osascript-Umgebung, der (anders als der interaktiven Login-Shell mit ihrem .zshrc-PATH) /usr/local/bin fehlt. wrangler() in upload_magazine_to_r2.py ergänzt das PATH jetzt explizit um die üblichen Homebrew-Verzeichnisse (Intel und Apple Silicon), bevor der Subprozess startet.

Postmortem 2026-08-20 (PDF/Mail-Quellen zeigten 0): Zwei getrennte Ursachen, an genau demselben Tag entdeckt. PDF: alle geprüften Cloud-Läufe zeigten === 0 Roh-Signale === direkt nach pdf_screener.py — der R2-Spiegel war leer, weil der manuelle Upload-Schritt schlicht nicht (mehr) passierte; siehe Auto-Sync-Fix oben. Mail: intermittierend — mail_screener.py fand im Cloud-Lauf zuverlässig hunderte passende Mails, brach aber teils mitten im UID FETCH-Loop mit imaplib.IMAP4.abort: socket error: EOF ab (freenet killt die Verbindung vom GitHub-Runner aus gelegentlich bei vielen Einzel-Fetches am Stück). Da screene_mails() alle Signale erst am Ende in einem Rutsch speicherte, ging bei einem Abbruch der komplette Lauf verloren, signals_raw_mail.json wurde nie geschrieben. Fix: _mit_retry()/_neu_verbinden() in mail_screener.py fangen IMAP4.abort/OSError jetzt bei jeder Suche/jedem Fetch ab, bauen die Verbindung neu auf (Login + Ordner neu selektiert) und versuchen es bis zu dreimal — schlägt eine einzelne UID endgültig fehl, wird nur sie übersprungen, nicht der ganze Lauf.

IMAP-Passwort und die restliche Konfiguration liegen als GitHub-Secrets im signal-hub-Repo vor (nie im Repo-Code, inkl. SIGNALHUB_CONFIG_JSON — jede lokale config.json-Änderung, die auch in der Cloud gelten soll, muss manuell per gh secret set SIGNALHUB_CONFIG_JSON --repo Miksch52/signal-hub < Signal-Hub/config.json nachgezogen werden, kein automatischer Sync); mail_screener.py nutzt lokal weiter den macOS-Schlüsselbund und fällt nur auf dem Linux-Runner auf die Umgebungsvariable SIGNALHUB_IMAP_PASSWORD zurück. Der Sende-Zeitplan (state.json) wird zwischen den Läufen ebenfalls in R2 gesichert, damit die acht täglichen Cron-Anstöße (vier Slots × je zwei für Sommer-/Winterzeit, wegen der auf flüchtigen Runnern sonst verlorenen Zustandsdatei) nicht doppelt pushen. Bugfix 2026-08-16: pipeline.yml schrieb config.json bisher per printf '%s' '${{ secrets.SIGNALHUB_CONFIG_JSON }}' > config.json — ein einzelnes Apostroph im Secret-Inhalt (ausgelöst durch den Hinweistext „O'Neil-IBD" im neuen Sentiment-Gate-Absatz oben) schließt dabei das umgebende Shell-Quoting vorzeitig und lässt den Schritt mit einem Syntaxfehler abbrechen — betraf beide Vorkommen in der Datei und legte einen kompletten Cron-Slot lahm, bevor es auffiel. Fix: Secret per env: an eine Variable binden und mit printf '%s' "$SIGNALHUB_CONFIG_JSON" schreiben — unempfindlich gegen jeden Zeicheninhalt, keine direkte ${{ }}-Interpolation mehr in einen Shell-Befehl.

Deploy als eigener, getrennter Schritt: Da der Hauptrepo privat bleibt, aber Wiki/Hauptapp/Coach von dort deployt werden müssen, lädt pipeline.yml am Ende die frischen Ausgabedateien nach r2:signalhub-magazine/_deploy/ hoch und stößt per GitHub-REST-API (Secret DEPLOY_TRIGGER_TOKEN, ein eng auf maick-trading-system begrenztes PAT) automatisch dessen neuen, schlanken deploy.yml-Workflow an (nur workflow_dispatch, kein eigener Cron). Dieser holt sich die aktuellen signal-hub.html/price-action-hub.html per Checkout der beiden öffentlichen Repos (kein Token nötig), zieht die frischen Daten aus _deploy/ und ruft danach unverändert cloudflare-pages/deploy.command auf — dadurch bleibt „Klick auf Aktualisieren → in ~15–30 Min live" trotz Repo-Split erhalten.

Depot-Abgleich (seit 2026-07-17 auch im Cloud-Lauf): mts_data.json selbst darf laut Projektregel nie in die Cloud — stattdessen liegen NUR die Namen offener Positionen (kein Betrag, keine Stückzahl) als eigenes GitHub-Secret SIGNALHUB_DEPOT_NAMEN (im signal-hub-Repo) vor. scorer.py::lade_depot_namen liest diese Umgebungsvariable, wenn gesetzt (unabhängig vom depotabgleich.aktiv-Flag in SIGNALHUB_CONFIG_JSON, die dafür unangetastet bleibt) — sonst wie gehabt die lokale Datei. Nach jeder Trade-Änderung muss das Secret manuell nachgezogen werden: die aktuelle Namensliste aus mts_data.json extrahieren und per gh secret set SIGNALHUB_DEPOT_NAMEN --repo Miksch52/signal-hub neu setzen (kein automatischer Sync, da mts_data.json nicht in Git liegt). Die Mac-mini-Zeitpläne com.maick.markets360.nightly und com.maick.trendscreener laufen vorerst parallel weiter zur Kontrolle — com.maick.signalhub dagegen nicht mehr (2026-08-10 als Ursache doppelter/dreifacher Pushes identifiziert und auf allen Macs entfernt, siehe Push-Absatz unten und Wartungstabelle). Manueller Testlauf je Repo: gh workflow run nightly.yml --repo Miksch52/minervini-markets-360, gh workflow run nightly.yml --repo Miksch52/lokaler-trend-screener, gh workflow run pipeline.yml --repo Miksch52/signal-hub.

📈 OHLC-Tagessnapshot (seit 2026-08-20, Top-Setups-Roadmap Punkt 4): Bis dahin gab es im gesamten System keine tatsächlich dauerhafte Kurshistorie — alle fünf Screening-Engines cachen Yahoo-Kurse nur mit Tages-TTL, und auf dem Cloud-Runner (GitHub Actions, pro Lauf frisch) wird dieser Cache nie nach R2 gesichert, sondern fängt bei jedem der vier täglichen Läufe leer an und wird am Lauf-Ende verworfen. src/ohlc_history.py läuft jetzt direkt nach scorer.py und zieht ohne zusätzlichen Yahoo-Abruf aus dem ohnehin schon in signals.json eingebetteten 126-Tage-Chartfenster (treffer[].chart.c/.v) nur den jeweils letzten Handelstag je Ticker heraus und schreibt eine kompakte, datumsgestempelte CSV (Signal-Hub/data/ohlc-history/JJJJ-MM-TT.csv, ~20 KB für alle ~860 Ticker). Beide Datenpfade sichern die Datei zusätzlich dauerhaft nach r2:signalhub-magazine/ohlc-history/ — der Cloud-Lauf per rclone direkt in pipeline.yml, der lokale Mac-mini-Lauf per neuem scripts/upload_ohlc_to_r2.sh (wrangler r2 object put, gleiches Muster wie upload_to_r2.sh). Anders als der bestehende _state/-Ordner (Zustandsdateien, die bei jedem Lauf überschrieben werden) wächst ohlc-history/ Tag für Tag — Grundlage für einen künftigen Punkt-in-Zeit-Backtest ohne den im RETRO-Modus von pivot_backtest.py dokumentierten Universums-Bias. Rückwirkendes Backfill (seit 2026-08-20): scripts/backfill_ohlc_history.py (einmaliger, manueller Lauf — bewusst nicht Teil von run.py::pipeline()) hat die Lücke vor dem ersten echten Snapshot geschlossen: für die 891 eindeutigen Ticker aus dem Pivot-Logbuch (_state/pivot_logbuch.json, wächst schon seit 2026-07-02) per range=2y&interval=1d direkt von Yahoo (dieselbe Rohquelle wie scorer.py::yahoo_chart, hier aber mit den Zeitstempeln statt nur den letzten 126 Werten) 35 fehlende Handelstage (02.07.–19.08.) rekonstruiert und ergänzt — rein additiv, überschreibt nie einen bereits vorhandenen Tag. Deckt bewusst nur die im Logbuch tatsächlich aufgetauchten Ticker ab, nicht das komplette Tagesuniversum rückwirkend (welche Ticker an einem vergangenen Tag gescreent wurden, ist nicht mehr rekonstruierbar) — für die Forward-Auswertung historischer Pivot-Signale ist das genau der richtige, vollständige Datensatz.

Rückmeldung & Auswertung

Push: viermal täglich (07:30 / 15:00 / 17:00 / 21:30) via ntfy an alle Geräte — nur neue Kandidaten ≥ 70. Läuft seit 2026-07 vollautomatisch in der Cloud (GitHub Actions, siehe oben), unabhängig davon ob/welcher Mac läuft. Der lokale Mac-mini-Zeitplan (com.maick.signalhub-LaunchAgent) ist damit obsolet — er pushte entgegen der ursprünglichen Doku nicht an einen separaten Test-Kanal, sondern an denselben ntfy-Kanal wie die Cloud (bestätigter Doppel-Push-Fall 2026-08-10, siehe Wartungstabelle unten); die Plist gehört auf keinem Mac mehr nach ~/Library/LaunchAgents. ☀️ Morning Brief (seit 2026-08-02, notify.py::baue_nachricht(morgens=True)): der erste fällige Slot des Tages (zeiten[0], i.d.R. 07:30, wird von run.py --scheduled automatisch erkannt) bekommt vor der Kandidatenliste zusätzlich eine Ampel-Zeile je aktivem Markt (🟢/🟡/🔴 + Klartext-Hinweis aus signals.json → marktregime) vorangestellt und bleibt — anders als die drei übrigen Slots — auch ganz ohne Kauf-Kandidaten nicht stumm, sondern zeigt wenigstens die Marktlage. Die drei späteren Slots pushen unverändert nur die reine Kandidatenliste.

📬 Push-Quellen im Überblick

Alle Push-Systeme im Trading-System schicken an denselben ntfy-Kanal (benachrichtigung.ntfy_thema aus Signal-Hub/config.json) — im Handy-Feed erscheinen sie deshalb gemischt und wirken wie „unterschiedliche Listen". Es sind aber fünf unabhängige Quellen mit eigener Logik, kein Duplikat/Fehler:

QuelleWannInhalt
notify.py (Signal-Hub-Digest)4×/Tag: 07:30 · 15:00 · 17:00 · 21:30Neue Score-Kauf-Kandidaten ≥ 70 (nur Neuzugänge seit letztem Push, Earnings-nahe und rot-Ampel-Markt rausgefiltert). Der 07:30-Slot ist zusätzlich das ☀️ Morning Brief mit Marktampel-Status je Markt vorweg.
pivot_screener.py --notify (Pivot-Screener)läuft im selben 4×/Tag-Zyklus mitNeue ARMED/BREAKOUT-Ticker aus der Pivot-Musteranalyse — eigene Erkennungslogik, nicht der Unified Score. Titel „Pivot: X Ausbruch / Y scharf".
top_setups.py (🏆 Top-Setups, seit 2026-08-09, siehe Startseite)bei jedem Pipeline-Lauf, auch bei manuellem „☁️ Cloud-Scan starten" — bewusst nicht an die 4 Slots gekoppelt, da diese Schnittmenge selten und hochwertig genug istNeue Ticker in der dreifach bestätigten Schnittmenge Score ≥ 70 ∧ ARMED/BREAKOUT ∧ Price-Action bullisch. Eigenständiger Versand (kein Import von notify.py — Entflechtung), Titel „🏆 X neue Top-Setups", je Zeile Markt-Ampel-Icon + 🎯/🚀-Status.
mts_alarms.py (Trading-Alarme, siehe Hauptapp)alle 20 Min, nur 08–22 Uhr, kein Wochenende, läuft nur lokal am laufenden Mac miniBetrifft ausschließlich deine offenen Positionen aus mts_data.json: SL-Bruch/-Nähe, Teilverkaufszonen +8/20/40 %, Kursziel erreicht — kein Markt-Scan.
pivot_backtest.py --evaluate (wöchentlicher Backtest-Push)So 08:15 (com.maick.pivot-backtest.plist)Keine Ticker-Liste, sondern eine Trefferquoten-Meldung „📊 Pivot-Forward-Test reif", sobald genug Forward-Test-Daten für eine Kohorte gereift sind.

📖 Visuelle Referenzseite (seit 2026-08-20): Dieselben fünf Quellen stehen zusätzlich als eigene Karte „🔔 Push-Kriterien" im Karten-Grid der Startseite — anders als die App-Anleitungen (Header-Button einer einzelnen App) ist das eine Cross-App-Referenzseite, die kein Header einer einzelnen App verlinkt, sondern die Startseite selbst. Zeigt dieselben Kriterien wie die Tabelle oben visuell aufbereitet (Karte pro Quelle, Beispielnachricht, Stellschrauben-Tabelle mit den aktuellen config.json-Werten) — Push-Kriterien-Übersicht. Eigenes, viertes Design (IBM Plex Sans/Mono, Türkis-Akzent) — siehe CLAUDE.md für die vollständige Design-System-Übersicht.

Anti-Spam & Zustand des Top-Setups-Push: top_setups.py::_neuzugaenge() vergleicht die aktuelle Schnittmenge gegen die beim letzten Lauf gepushten Ticker (top_setups_state.json) — nur echte Neuzugänge lösen aus, ein Dropout mit späterem Wiedereinstieg zählt erneut als neu (gleiches Prinzip wie beim Pivot-Screener). Da Price-Action-Hub/src/top_setups.py in einem eigenen, oeffentlichen Repo/Cloud-Job läuft (kein Cross-App-Python-Import zu Signal-Hub/src/notify.py — Entflechtung), braucht der price-action-hub-Job in pipeline.yml dafür einen eigenen kleinen R2-Umweg: top_setups_state.json wird vor dem Lauf aus r2:signalhub-magazine/_state/ wiederhergestellt und danach zurückgesichert (sonst wäre der Zustand bei jedem frischen Runner leer), und Signal-Hub/config.json (nur für den ntfy-Kanal gebraucht) wird aus dem SIGNALHUB_CONFIG_JSON-Secret direkt in diesem Job geschrieben — bleibt im ephemeren Runner, landet nie in einem Artifact-Upload (das Repo ist öffentlich).

🔍 Setup-Analyse (seit 2026-08-07): Jede Kachel verlinkt jetzt zusätzlich direkt auf setup-detail.html?ticker=… — denselben Detail-Überblick (Score-Faktoren, Pivot-Kennzahlen, Price-Action-Muster, TradingView-Chart, Fundamentaldaten & Story), den bisher nur das 🔍-Icon der Top-Setups auf der Startseite öffnete. Der bestehende Link zur SEPA-Analyse in der Hauptapp heißt zur Unterscheidung jetzt 🔎 SEPA-Analyse (anderes Lupen-Symbol) — 🔍 steht im ganzen System einheitlich für „Setup-Analyse öffnen".

📈 Trade-Funnel: Jede Kachel hat (im HTTP-Modus) einen „📈 Trade"-Link, der in der Hauptapp das Trade-Formular vorbefüllt öffnet (Ticker + Quelle = „Signal-Hub"). Seit 2026-07-24 gibt der Link zusätzlich Entry = Pivot und Stop = Basis-Tief aus dem Pivot-Detektor mit (&entry=…&stop=…, Helfer tradeParams()/tradeTitle()), sofern für den Ticker ARMED/BREAKOUT-Pivot-Daten vorliegen — die Hauptapp füllt beide Felder und rechnet die Positionsgröße sofort (updateTradePreview()); ohne Pivot-Daten bleibt es beim reinen Ticker+Quelle-Vorbefüllen. Bei einem Earnings-gesperrten Wert (siehe unten) trägt der Link-Tooltip zusätzlich die Warnung. Die Hauptapp speichert die Quelle am Trade (Feld im Formular, frei wählbar/Vorschlagsliste). Im Psychology-Tab wertet „Performance nach Quelle" dann aus, welche Ideen-Quelle tatsächlich Gewinner bringt (Trades, Win-Rate, Ø-CRV, P&L je Quelle) — so lassen sich schwache Quellen datenbasiert aussortieren.

🔒 Earnings-Sperre für Kauf-Kandidaten (seit 2026-07-24, signal-hub.html::earnGesperrt()): Bisher wurden Werte mit baldigen Quartalszahlen nur aus dem Push genommen. Jetzt wird ein Kauf-Kandidat (Tier A) mit Earnings im Warnfenster (Standard 10 Tage) auch im Dashboard sichtbar gesperrt: die Einstufung zeigt „🔒 Earnings-Sperre" statt „Kauf-Kandidat" (rote Pille, rot getönter Kachelrahmen), und der „📈 Trade"-Link warnt im Tooltip. Minervini kauft nicht kurz vor Zahlen. Der bestehende Filter „⚠︎ Earnings ausblenden" (Standard an) nimmt solche Werte weiterhin ganz aus der Liste — die Sperre ist die sichtbare Behandlung, wenn man den Filter abschaltet.

🏆 „nur Top-Setups"-Filter + 📐 PA-Badge (seit 2026-07-24): Dieselbe dreifach bestätigte Schnittmenge wie das Startseiten-Panel — Score ≥ 70 ∧ ARMED/BREAKOUT ∧ Price-Action bullisch (PA-Score > 0) — jetzt auch als Filter im Signal-Hub, plus ein Badge 📐 PA +N auf jeder Kachel der Schnittmenge (verlinkt zum Price-Action-Hub). Damit bekommt der Signal-Hub die bisher fehlende Price-Action-Dimension direkt in die Kartenansicht. Datenquelle ist die winzige top_setups.js (~5 KB, vom Aggregator gebaut, siehe Startseite) — nicht die 5,7 MB priceaction.js, deshalb erscheint das PA-Badge nur auf den Tickern der Schnittmenge (mehr pa_score-Daten liegen dem Hub bewusst nicht vor — Entflechtung). Bewusste Besonderheit: „nur Top-Setups" umgeht die Faktor-Pflicht („müssen grün sein"), denn das Set ist bereits kuratiert und der Default „Volumen grün" widerspräche ARMED direkt (die brauchen Volumen-Austrocknung, keinen -Schub — sonst wäre die Ansicht fast immer leer); die Risiko-Filter (Earnings/Extended/50-80) bleiben dagegen aktiv. Der Zähler zeigt die Gesamtzahl der Setups, die Trefferzahl das, was nach den Risiko-Filtern übrig bleibt.

🧭 Regel-Check (Psychology-Tab): wertet automatisch deine Disziplin aus — Positionsgröße ≤ 2 % Depotrisiko, Stop-Loss eingehalten (Verlust nicht größer als geplant), Verlierer schneller geschnitten als Gewinner gehalten, Ø Gewinn ≥ 2× Ø Verlust. Jede Regel mit ✅/⚠️ und konkreten Zahlen. Verhaltensmuster sind bei Minervini der eigentliche Edge.

⭐ Fokusliste-Verknüpfung mit der SEPA-Analyse (seit 2026-07-22, Ziel seit 2026-07-23 die Hauptapp statt des Coaches — siehe Hauptapp-Abschnitt): bewusst kein eigenes Watchlist-Feature im Signal-Hub (Entflechtung) — die SEPA-Analyse in „Maick's Trading System" hat eine server-/gist-synchronisierte Watchlist (localStorage['mts_v2'].watchlist). Da beide Apps unter derselben Origin laufen (8090-Proxy/Tailscale/Cloudflare Pages), liest der Signal-Hub diese Watchlist nur lesend mit: Badge „⭐ Fokusliste" auf bereits gemerkten Tickern, Filter „⭐ nur Fokusliste". Der „🔎 SEPA-Analyse"-Link jeder Kachel öffnet mit ?ticker=… direkt die Analyse in der Hauptapp (vorher musste der Ticker manuell eingetippt werden) — „Idee prüfen → bei Bestätigung zur Fokusliste hinzufügen" ist damit ein echter Zwei-Klick-Flow, ohne dass eine Idee ungeprüft auf die Liste kommt. Live-Nachziehen per storage-Event: Klickt man im offenen Hauptapp-Tab „⭐ Speichern", feuert das Browser-storage-Event automatisch in jedem anderen gleichzeitig offenen Tab derselben Origin (nur dort, nie im schreibenden Tab selbst) — der Signal-Hub-Tab rendert daraufhin sofort neu, Badge/Filter zeigen den frischen Stand ohne manuelles Neuladen. Gegen echte Zwei-Tab-Situation getestet.

📊 Backtest-Report (Signal-Hub/backtest-report.html, seit 2026-08-07, Link im Header): eigene Seite im Wochennotiz-Stil, die auswertet, welche Pivot-Setups (ARMED/BREAKOUT/WATCH) unverzerrt tatsächlich funktioniert haben — Fließtext-Einordnung je Setup, dahinter eine vollständige, live aus data/pivot_backtest.json geladene Fundstellen-Tabelle mit jedem Einzelfall (Ticker, Signal-Datum, Einstiegskurs, realisierte Rendite) plus Chart-Link zu Yahoo Finance. Links wählt man das Setup, rechts aktualisiert sich die Auswertung. Datengrundlage: pivot_backtest.py --evaluate schreibt seit 2026-08-07 zusätzlich zu den aggregierten Kennzahlen (forward_realisiert) auch die ticker-scharfen Einzelfälle (forward_einzelfaelle) — vorher lagen diese nur im nie synchronisierten, lokalen Forward-Logbuch (~/Library/Application Support/SignalHub/pivot_logbuch.json) und waren dem Dashboard gar nicht zugänglich. Läuft wöchentlich mit (com.maick.pivot-backtest.plist, So 08:15) und ist über data/pivot_backtest.js auch als file://-Fallback sowie auf der Cloudflare-Pages-Version verfügbar. Win-Rate-Balken (seit 2026-08-17): jede der drei Kohorten-Tabellen (ARMED gesamt/Score≥70/Score<70, BREAKOUT Forward/Retro, WATCH Retro) bekam ein kompaktes horizontales Balkendiagramm direkt darüber (miniBars()) — eine Farbe (Gold, aus --gold), Retro-/Baseline-Zeilen bewusst im helleren Farbton als sekundäre Kennzeichnung „weniger belastbar" (deckt sich mit dem Fließtext daneben), zusätzlich seit der Überarbeitung unten ein farbiges Ø-Return-Label rechts im Balken. Nach dataviz-Skill-Vorgaben entworfen und mit validate_palette.js --ordinal geprüft.

Überarbeitung für mehr Übersichtlichkeit (seit 2026-08-17): Fünf gezielte Verbesserungen, redaktioneller Charakter (Serif, Wochennotiz-Rahmen, Gold-Akzent) bewusst erhalten statt auf das dunkle Dashboard-Template der anderen Apps zu wechseln. (1) Dark Mode — vorher die einzige Seite im System ohne Dunkelmodus; jetzt automatisch nach Systemeinstellung (prefers-color-scheme + data-theme-Override wie überall sonst), alle Farbwerte inkl. der zweistufigen Gold-Balkenrampe mit validate_palette.js gegen die dunkle Kartenfläche geprüft (Kontraste 5–14:1). (2) Kennzahlen-Leiste — drei Kacheln (ARMED/BREAKOUT/WATCH) direkt unter dem Titel zeigen alle Win-Raten auf einen Blick, bevor man in ein Detail eintaucht; dieselben Radio-Inputs wie der bestehende Index steuern sowohl die Kacheln als auch die Detailauswahl (ein Klick wirkt wie ein Klick auf den passenden Index-Eintrag). (3) Tabellen-Paginierung — die „Fundstellen"-Tabelle rendert bei großen Kohorten (ARMED z. B. n=1.710) seither jeden einzelnen Fall unpaginiert ins DOM, praktisch nur noch per Strg+F nutzbar; jetzt zeigt renderFundstellen() nur 50 auf einmal mit „Mehr laden"-Knopf, dazu eine Sortierung (Rendite/Datum, je auf-/absteigend) über die komplette Liste. (4) Tab-Optik — ein Chevron (›) und ein deutlicherer Aktiv-Zustand (Randfarbe + Hintergrund) machen die Status-Auswahl links jetzt auch mobil klar als umschaltbar erkennbar (vorher nur eine dünne, kaum sichtbare Randlinie). (5) Chart-Ausbau — die Win-Rate-Balken zeigen jetzt zusätzlich ein farbiges Ø-Return-Label rechts (grün/rot), Richtung und Magnitude beider Kennzahlen auf einen Blick, exakte Werte bleiben in der Tabelle darunter.

🛒 Kauf-Review-Queue

Kauf-Review-Queue (Signal-Hub/kauf-review.html, seit 2026-08-20, Top-Setups-Roadmap Punkt 7 — verlinkt von der Startseite ("🛒 Kauf-Review" neben „🗒️ Watchlist" im Top-Setups-Panel) und vom Signal-Hub-Header): sequenzielles, mobil-optimiertes Durchgehen aller aktiven Top-Setups (grünes Regime, kein Earnings-Fenster) statt der bisherigen Einzelticker-Ansicht von setup-detail.html — für den Anwendungsfall „unterwegs auf dem iPhone die Tagesliste durchgehen und entscheiden". Lädt ausschließlich die ohnehin schon winzige data/top_setups.js (kein neuer Datenpfad, keine 11,8 MB signals.js) plus Rotation-Dashboard/data/rotation.js für den Leader-Abgleich, exakt wie das Top-Setups-Panel selbst. Pro Karte: Kurs, Pivot/Stop/Abstand, dieselben Badges wie im Panel (⭐ Kern-Setup, 📌 im Depot, 🎯 Konfluenz X/2, 🔥 Leader), eine Trend-Template-Checkliste (5 Kernfaktoren mit Ampel — top_setups.py reicht dafür seit demselben Tag preis und trend_template zusätzlich durch, weiterhin nur die Ampel je Faktor, kein Volltext, um die Datei winzig zu halten) sowie ein grober Positionsgrößen-Rechner (Kapital × Risiko-% ÷ Stop-Abstand, Kapital/Risiko-% werden lokal gemerkt und best-effort per /data aus der Summe aller depotwert-Felder vorausgefüllt, wenn ein lokaler Server erreichbar ist). Bewusst keine Neuimplementierung der vollen Positionsgrößen-/Exposure-Logik der Hauptapp (_mtsSuggestedSize, Multi-Depot, Exposure-Deckel) — das wäre Code-Duplikation mit Drift-Risiko (Entflechtung); die Karte zeigt nur eine grobe Schätzung mit explizitem Hinweis, „🛒 Kaufen" verlinkt stattdessen direkt in den Trade-Planner der Hauptapp (?neuerTrade=…&entry=…&stop=…, derselbe Deeplink-Vertrag wie das bestehende Top-Setups-Panel), wo die verbindliche Rechnung inkl. aller Limits läuft. Drei Aktionen pro Karte (👀 Beobachten / ✕ Verwerfen / 🛒 Kaufen, alle ≥52 px Touch-Fläche) — die ersten beiden blättern nur weiter, Fortschritt + Entscheidungen bleiben in sessionStorage erhalten (Browser-Zurück nach einem Kauf-Klick setzt die Queue an derselben Stelle fort). Abschluss-Screen zeigt die Zusammenfassung (gekauft/beobachtet/verworfen) mit Neustart-Option. Gesperrte Setups (nicht-grünes Regime/Earnings-Fenster) werden bewusst nicht in die Queue aufgenommen, aber gezählt und referenziert. Deploy-Bugfix (2026-08-20): Die neue Seite landete beim ersten Cloud-Deploy nicht auf Cloudflare Pages — sowohl cloudflare-pages/deploy.command als auch .github/workflows/deploy.yml (Hauptrepo) kopieren Signal-Hub-Apps über eine feste Datei-Liste statt den ganzen Ordner (dieselbe Whitelist-Logik wie bei signal-hub.html/setup-detail.html) — beide Listen mussten um kauf-review.html ergänzt werden, sonst Redirect zur Startseite statt Anzeige der Seite. Bei künftigen neuen Signal-Hub-Einzeldateien immer beide Stellen zusammen bedenken.

Zugriff

Zugriff (iPhone/PWA): Der Signal Hub wird über denselben 8090-Origin geöffnet (relativer Link) — der 8090-Server reicht /Signal-Hub/api/* an den 8091-Server durch. So funktioniert er in der installierten PWA und über Tailscale-HTTPS, ohne dass das Gerät den separaten Port 8091 erreichen muss (früher zeigte der Link direkt auf http://…:8091 → auf dem iPhone „Seite nicht erreichbar").

🔎 SEPA-Analyse/📈 Trade-Link — Basis-URL-Fix (2026-08-03): Beide Deeplinks in die Hauptapp bauten die Ziel-URL bislang immer als location.hostname + ':8090/…' — korrekt nur bei reinem LAN-http://-Zugriff auf den Mac mini. Bei https-Zugriff (Cloudflare Pages und Tailscale, siehe Abschnitt „Primärzugang") liegen beide Apps aber bereits unter demselben Origin auf Port 443 — das angehängte :8090 zeigte dort ins Leere (bei Tailscale sogar zwingend falsch, da nur 443 nach außen exponiert ist), der Klick auf „📈 Trade" landete dadurch nirgends und der Ticker kam nie im Trade-Planner an. Neue Hilfsfunktion mtsHauptappBasis(): bei https: wird location.origin verwendet (kein Port), nur bei reinem http: weiterhin hostname:8090. Betrifft auch den identischen Mechanismus im Price-Action-Hub (siehe dort).

Token: Lesen ist offen; Schreiben (Aktualisieren/Einstellungen speichern) verlangt das Token aus Signal-Hub/config.json. Einmal mit ?token=… öffnen — danach merkt sich das Gerät den Zugang (Cookie, 1 Jahr).

🗒️ Watchlist erstellen (Header-Toolbar, seit 16.08.2026): schreibt die aktuell gefilterte Ansicht (Markt/Score/Suche/alle Toggle-Filter, CURRENT_LIST aus render()) als TradingView-importierbare .txt + lesbare Zusammenfassung + reine Ticker-Liste nach Watchlisten/Signal-Hub/ im MTS-Hauptordner — identisches Dateiformat wie beim Trend-Screener (dort zuerst gebaut), eigener Unterordner statt eines gemeinsamen Zieldateinamens. Neuer, tokengeschützter Endpunkt POST /api/watchlist in Signal-Hub/src/server.py (dasselbe Token wie /api/run//api/config) — läuft über den eigenen 8091-Server, same-origin über den 8090-Proxy erreichbar wie die übrigen /Signal-Hub/api/*-Endpunkte, kein Sonderfall im Proxy nötig.

📐 Price-Action-Hub (Price-Action-Hub/price-action-hub.html, seit 2026-07-23)

Ergänzt den Signal-Hub um eine reine Preisverlauf-Sicht auf dieselben Aktien: liest Signal-Hub/data/signals.json für Symbol/Name/Markt (bewusste Entflechtung, Signal-Hub bleibt allein zuständig für „welche Ticker sind relevant" — Price-Action-Hub übernimmt daraus nicht den Signal-Hub-Score selbst, seit 2026-08-16 aber ein eng begrenztes Set an fertigen Ampelfeldern für die Hebel-Ampel, siehe unten), holt dafür aber eigenständig echte OHLC-Kursdaten (Open/High/Low/Close/Volumen) über die Yahoo-Chart-API und wertet fünf Price-Action-Muster aus den PDF-Quellen im Ordner price action/ (Al Brooks, Rayner Teo, Tom Hougaard) aus: Trendbar-Stärke (Close-Position + Body-Anteil in der Tagesrange), Inside Bar (Konsolidierung im Vorbar-Rahmen), Bar-Counting (High1/2 bzw. Low1/2 nach einem Swing — nur die ersten zwei Korrekturbars gelten als zuverlässig), Breakout-Stärke/Failed Breakout (neues Hoch/Tief vs. 20-Tage-Referenz, Scheitern binnen 5 Bars) und Gap + Fill-Tracking. Dazu ein Kontext-Filter Marktstadium (Advancing/Accumulation/Distribution/Declining aus MA200-Stand + 21-Tage-Steigung, bewusst derselbe Lookback wie Signal-Hub/src/scorer.py::f_stage2, damit beide Apps nie widersprüchliche Trendaussagen treffen). Der resultierende Price-Action-Score (Price-Action-Hub/src/scorer.py::pa_score) ist eine einfache, transparente Summe der Musterergebnisse, gewichtet nach Richtung des Marktstadiums (Gegentrend-Signale zählen nur halb) — reine Dashboard-Sortierhilfe, kein Ersatz für den Signal-Hub-Score. Das Dashboard zeigt einen echten Kerzenchart (candlechart()) — seit 2026-07-24 zeigt auch das Signal-Hub-Minichart Kerzen in derselben Darstellung (siehe Signal-Hub-Abschnitt), womit beide Apps dasselbe Chartbild sprechen.

Datenfluss & Betrieb: Läuft im selben Cloud-Workflow wie der Signal-Hub (pipeline.yml im Repo Miksch52/signal-hub), seit 2026-08-09 aber als eigener, paralleler Job (price-action-hub) statt als Schritt direkt nach der Signal-Hub-Pipeline — läuft dadurch gleichzeitig mit Rotation-Dashboard, nicht mehr danach, weil beide nur von Signal-Hubs Ausgabe abhängen, nicht voneinander. Seit 2026-07-28 ein eigenes, öffentliches Repo (Miksch52/price-action-hub, ausgelagert damit es unbegrenzte Actions-Minuten hat, siehe Signal-Hub-Abschnitt oben), weiterhin ohne eigenen Pipeline-Workflow — checkt sich selbst per actions/checkout aus (kein Token nötig, da public) und bekommt Signal-Hubs Ausgabedatei separat per actions/download-artifact in einen Geschwister-Ordner Signal-Hub/data/ gelegt (statt wie zuvor den kompletten Signal-Hub-Checkout mitzuziehen), genau die Ordnerstruktur, die pfade.py erwartet. Der Schritt prüft per Datei-Existenz ([ -f ../Signal-Hub/data/signals.json ]), ob der Signal-Hub in genau diesem Lauf frische Daten geschrieben hat — bei einem Cron-Anstoß außerhalb der vier täglichen Push-Slots wird die Price-Action-Pipeline sauber übersprungen, kein Fehler. Bewusst kein eigener Server/Port/LaunchAgent: das Dashboard wird wie Coach/Wiki einfach vom bestehenden 8090-Server statisch mitausgeliefert; Aktualisierung ausschließlich über denselben „☁️ Cloud-Scan starten"-Button (triggerCloudWorkflow(), Ziel-Repo signal-hub, Workflow pipeline.yml). Eigener Yahoo-Cache (~/Library/Application Support/PriceActionHub), getrennt vom Signal-Hub-Cache, um Schreibkonflikte zwischen den beiden unabhängigen Apps zu vermeiden. Eigener Deploy-Trigger (seit 2026-08-09): ein schlanker deploy-trigger.yml (on: push: main) stößt bei einem Edit direkt an dieser App sofort den Pages-Deploy im Hauptrepo an, statt bis zu 6 Stunden auf den nächsten Signal-Hub-Zyklus zu warten — braucht das Secret DEPLOY_TRIGGER_TOKEN (gleicher Token-Wert wie im signal-hub-Repo, separat in diesem Repo hinterlegt).

📈 Trade-Planner-Verknüpfung (seit 2026-07-23): Jede Kachel hat wie im Signal-Hub einen „📈 Trade-Planner"-Link (identischer Deeplink-Mechanismus, ?neuerTrade=TICKER&quelle=Price-Action-Hub), der in der Hauptapp das Trade-Formular samt Risk-Reward-/Pyramidisierungs-Vorschau vorbefüllt öffnet. Basis-URL-Fix 2026-08-03 (dieselbe Ursache/Lösung wie im Signal-Hub, siehe dort): mtsHauptappBasis() nutzt bei https:-Zugriff (Cloudflare Pages/Tailscale) location.origin statt fälschlich :8090 anzuhängen.

Filter & Standardansicht (seit 2026-07-23): Das Dashboard startet nicht ungefiltert, sondern mit „Nur bullisch" + Min. |Score| 2 — zeigt die aktuell stärksten Treffer statt aller ~1300 Ticker; „↺ Zurücksetzen" stellt genau diesen Zustand wieder her. Zusätzlich zu Markt/Richtung/Score-Schwelle/Sortierung/Suche gibt es Muster-Chips (Starke Trendbar, Inside Bar, Bar-Counting zuverlässig, Breakout, Failed Breakout, Gap — Mehrfachauswahl UND-verknüpft) und einen Marktstadium-Filter (Advancing/Accumulation/Distribution/Declining). Die Suche akzeptiert mehrere Komma-/Leerzeichen-getrennte Begriffe (ODER-verknüpft) und durchsucht zusätzlich die Börse.

Fix 2026-08-17: Filterleiste blockierte auf dem iPhone dauerhaft die Ergebnisliste. <details id="filterbox" open> stand fest auf „offen" im HTML — anders als im Signal-Hub, wo dieselbe Leiste auf schmalen Bildschirmen von Anfang an eingeklappt startet und beim Runterscrollen automatisch zuklappt (mehr Platz für die Trefferkarten). Auf dem iPhone nahm die immer offene, sticky Filter-&-Sortierung-Leiste dadurch dauerhaft einen großen Teil des Bildschirms ein. Fix: open-Attribut entfernt (öffnet sich jetzt nur noch automatisch, wenn window.innerWidth>700, also am Desktop) plus 1:1 aus signal-hub.html übernommenes Scroll-Throttle (100 ms), das alle offenen details.filterbox-Panels (Filter & Sortierung, Legende, Hebel-/Muster-Backtest) beim Runterscrollen über 80 px automatisch schließt — bewusst kein Wiederaufklappen beim Hochscrollen, der Nutzer klickt gezielt erneut auf.

Qualitäts-/Konfluenzfilter (seit 2026-08-13): Drei weitere, rein clientseitig aus den ohnehin im Payload enthaltenen chart-Arrays (o/h/l/c/v) bzw. den bestehenden Musterfeldern berechnete Filter — kein neuer Pipeline-Lauf nötig, gedacht um die typischerweise ~100 Treffer der Standardansicht auf eine überschaubare Kernauswahl einzudampfen: Min. Konfluenz (0–5-Slider, zählt wie viele der fünf richtungsgebenden Signale — Trendbar, Bar-Counting, Breakout ohne Failed, offenes Gap, Marktstadium — gleichzeitig in dieselbe Richtung wie der Score zeigen; ein 🔗-N/5-Badge auf jeder Kachel zeigt den Wert direkt an), Ø Volumen (Ø Handelsvolumen in USD/EUR der letzten 20 Tage, Stufen ≥1/5/10/25 Mio. — filtert marktenge, schwer handelbare Titel raus) und Abstand 6M-Hoch (% Abstand des aktuellen Kurses vom höchsten Hoch im ~6-Monats-Chartfenster, Stufen ≤5/10/15/20 % — grenzt auf Titel nah am Hoch ein, echte Momentum-/Trendfortsetzungskandidaten statt tiefer Korrekturen). Zusätzliche Sortier-Option „Konfluenz". Alle drei starten auf „Alle" (kein Effekt auf die Standardansicht), bis der Nutzer sie aktiv setzt.

Tri-State-Qualitätsfilter (seit 2026-08-13): Drei weitere Chips in einer eigenen Gruppe „Qualität", die anders als die bestehenden Muster-Chips (nur „muss vorhanden sein") per Klick zwischen drei Zuständen zyklen: ausaktiv (grün, muss zutreffen) → negativ (rot, darf nicht zutreffen) → wieder aus. 📊 Volumen-bestätigter Breakout (Breakout mit Vol-Ratio ≥ 1.5x — aktiv zeigt nur überzeugend bestätigte Ausbrüche, negativ blendet genau diese aus und lässt schwach-volumige/keine Breakouts stehen), ⛔ Failed Breakout (aktiv = nur gescheiterte Ausbrüche, negativ = gescheiterte Ausbrüche explizit ausschließen — ersetzt den bisherigen einfachen Muster-Chip „Failed Breakout"), 🎯 Trendkonform (prüft, ob alle aktuell aktiven richtungsgebenden Muster — Trendbar, Bar-Counting, Breakout, Gap — mit dem Marktstadium-Kontext übereinstimmen, dieselbe Bull-/Bär-Kontext-Logik wie scorer.py::_gewichtet, das Gegentrend-Signale nur halb gewichtet statt hart auszuschließen; aktiv zeigt nur widerspruchsfreie Chartbilder, negativ isoliert genau die Ticker mit mindestens einem Gegentrend-Signal). Alle drei rein clientseitig aus den bestehenden Musterfeldern berechnet, kein neuer Pipeline-Lauf nötig.

🔎 Sofort-Überblick auf jeder Kachel (seit 2026-08-03, paQuickscan()): kompakter Punkte-Raster analog zum Signal-Hub, aber auf die eigenen Muster gemünzt (Trend-Bar, Inside Bar, Bar-Counting, Breakout, Gap, Marktstadium) statt der Signal-Hub-Score-Faktoren — anders als dort ist Grau hier der Normalfall („Muster nicht vorhanden"), nicht „schwach"; Grün/Rot markieren ein ausgeprägtes bullisches/bärisches Muster, Gelb ein vorhandenes, aber schwächeres (Inside Bar, Failed Breakout, gefülltes Gap, unzuverlässiges Bar-Counting). Ergänzt die bestehenden Badges, ersetzt sie nicht.

🔍 Setup-Analyse-Verknüpfung (seit 2026-08-07): Jede Kachel verlinkt jetzt zusätzlich auf ../Signal-Hub/setup-detail.html?ticker=… — derselbe Detail-Überblick wie bei den Top-Setups und im Signal-Hub (Score-Faktoren, Pivot-Kennzahlen, Price-Action-Muster, TradingView-Chart, Fundamentaldaten & Story). Bekannte Einschränkung: setup-detail.html braucht zwingend einen Eintrag in Signal-Hub/data/signals.json (dort landen nur Ticker mit Score ≥ „Beobachten"), Price-Action-Hub deckt aber ein deutlich breiteres Universum ab (~1300 vs. ~740 überschneidende Ticker, ≈ 57 %) — für den Rest zeigt die Seite den vorhandenen „Kein Treffer"-Hinweis statt eines Fehlers.

⚡ Hebel-Ampel (seit 2026-08-16, scorer.py::hebel_ampel()): dieselbe Reife-Ampel für Hebelprodukte (Knock-Outs/Optionsscheine, z. B. Finanzen.net Zero) wie im Signal-Hub-Abschnitt beschrieben — identische Kriterien (Markt-Ampel, Stage-2-Trend, Basis/VCP, Pivot-Trigger, kein Extended/Earnings/50-80/Klimax-Risiko), hier aber serverseitig in Python berechnet, weil der Price-Action-Hub bewusst kein 8 MB großes signals.js zusätzlich clientseitig laden soll (dieselbe Überlegung wie beim „🏆 Top-Setups"-Panel auf der Startseite). Dafür liest lade_tickerliste() zusätzlich zur Tickerliste ein eng begrenztes Set an bereits fertigen Ampel-/Risikofeldern je Ticker aus signals.json (Stage-2-Trend, Basis/VCP, Extended, Earnings, 50/80, Klimax, Marktregime) sowie den Pivot-Status aus Signal-Hub/data/pivot.json — reines Durchreichen fertiger Werte, keine Neuberechnung und kein Ersatz für pa_score (siehe Entflechtungshinweis oben). Badge „🟢 Hebel bereit"/„🟡 Hebel im Fokus" steht als erster Hinweis noch vor dem Marktstadium-Badge auf der Kachel (🔴 bewusst ohne Badge); eigene Filtergruppe „Hebel-Trade" mit Checkbox „⚡ nur Hebel-Kandidaten (grün)" (Standard aus).

📊 Hebel-Ampel-Backtest (seit 2026-08-16, Price-Action-Hub/src/hebel_backtest.py): misst, OB „🟢 Hebel bereit" tatsächlich einen besseren Forward-Return liefert als „🟡 Hebel im Fokus" — unverzerrtes Forward-Logbuch nach demselben Grundprinzip wie Signal-Hubs pivot_backtest.py (siehe dortiger Abschnitt), hier bewusst ohne Retro-Modus: die Hebel-Ampel kombiniert mehrere fremde Ampeln (Markt-Regime, Pivot-Status, Stage-2-Trend, …), eine rückwirkende Walk-Forward-Rekonstruktion wäre für einen ersten Baustein unverhältnismäßig aufwendig. run.py hängt bei jedem Lauf die heutigen grün/gelb-Ticker mit Datum + Kurs ans lokale Logbuch (~/Library/Application Support/PriceActionHub/hebel_logbuch.json) und wertet zugleich die gereiften Picks (≥21/50/78 Kalendertage) gegen aktuelle Yahoo-Kurse aus (kein eigener wöchentlicher Rhythmus wie beim Pivot-Backtest — die Stichprobe ist klein genug, um jedes Mal mitzulaufen). Ausgabe Price-Action-Hub/data/hebel_backtest.json, im Dashboard als eingeklapptes Panel „⚡ Trefferquoten Hebel-Ampel (Forward-Test)" mit vorangestelltem Win-Rate-Balkendiagramm sichtbar, sobald die ersten Fälle gereift sind (seit 2026-08-17, gleiches btChartHtml()-Prinzip wie in den anderen vier Backtest-Panels, hier mit der amber-Ramp aus --primary/--primary2). Persistenz von Anfang an über R2 (_state/hebel_logbuch.json, Pull/Push in pipeline.ymls price-action-hub-Job): anders als beim ursprünglichen Signal-Hub-Pivot-Logbuch (das erst nachträglich, siehe dortiger Abschnitt, von reinem Mac-mini-Zustand auf R2 umgestellt wurde) gibt es hier von vornherein keinen lokalen Dauerlauf, der als Notlösung einspringen könnte — Price-Action-Hub läuft ausschließlich in der Cloud, jeder Runner ist pro Lauf frisch. Ohne die R2-Sicherung hätte die Stichprobe nie über Kalenderzeit wachsen können.

📊 Price-Action-Muster-Backtest (seit 2026-08-17, Price-Action-Hub/src/muster_backtest.py): gleiches Prinzip wie der Hebel-Ampel-Backtest direkt darüber, hier für sechs Kohorten aus den eigentlichen Chartmustern: breakout_up/breakout_down (frischer Ausbruch gegen die 20-Tage-Referenz — bewusst ohne das failed-Flag aus muster.py als Vorfilter, das reift erst über die nächsten 5 Bars und ist am Signaltag selbst immer None; der 4/8/12-Wochen-Forward-Return hier ist die eigentliche, spätere Antwort auf „hat der Ausbruch gehalten"), trendbar_stark_bull/trendbar_stark_bear (starke Trendbar) und score_bullisch/score_baerisch (pa_score ≥2/≤-2, dieselbe Schwelle wie die Standardansicht im Dashboard). Ein Ticker kann an einem Tag mehrere Kohorten gleichzeitig treffen. Ausgabe Price-Action-Hub/data/muster_backtest.json, Panel „📐 Trefferquoten Price-Action-Muster (Forward-Test)" mit vorangestelltem Win-Rate-Balkendiagramm (seit 2026-08-17, gleiches Prinzip wie beim Hebel-Ampel-Backtest — Zeilenhöhe passt sich dynamisch an, wie viele Horizonte je Kohorte tatsächlich gereift sind, statt leere Balken-Slots stehen zu lassen). Logbuch ~/Library/Application Support/PriceActionHub/muster_logbuch.json, R2-Persistenz von Anfang an (_state/muster_logbuch.json, gleicher Grund wie beim Hebel-Ampel-Backtest — kein lokaler Dauerlauf als Ausweichquelle).

🔮 Vorausschau-Zähler an den Filter-Chips (seit 2026-08-16, updateChipCounts()): jeder Muster-Chip (Starke Trendbar/Inside Bar/Bar-Counting/Breakout/Gap), jeder Qualitäts-Chip (Volumen-bestätigter Breakout/Failed Breakout/Trendkonform) sowie jede Option im Marktstadium-Dropdown zeigt jetzt direkt eine Zahl („🚀 Breakout · 65", „Advancing · 504") — wie viele Ticker im gesamten Datensatz genau dieses eine Kriterium erfüllen, unabhängig von sonst aktiven Filtern (gleiches Prinzip wie die bestehenden Zähler bei „🎯 nur Pivot-Setups"/„🏆 Top-Setups" im Signal-Hub bzw. „⚡ nur Hebel-Kandidaten" hier). Einmalig nach dem Laden berechnet, kein Filterwechsel nötig, um die Selektivität einer Option vorab abzuschätzen.

📖 Betriebsanleitung: Wie beim Signal-Hub verlinkt der Header-Button „📖 Anleitung" auf eine dedizierte Symbol-/Filter-Erklärung (Claude-Artifact) — Price-Action-Hub-Anleitung. Diese Seite (und dieser Wiki-Abschnitt) werden bei jeder funktionalen Änderung am Tool mit aktualisiert.

🗒️ Watchlist erstellen (Header-Toolbar, seit 16.08.2026): identisches Prinzip wie im Signal-Hub/Trend-Screener (siehe dort) — schreibt die aktuell gefilterte Ansicht (Markt/Richtung/Score/Muster/Qualität/Suche, CURRENT_LIST aus render()) nach Watchlisten/Price-Action-Hub/ im MTS-Hauptordner. Price-Action-Hub hat keinen eigenen Server/Port — der neue Endpunkt POST /Price-Action-Hub/api/watchlist läuft deshalb direkt im 8090-Server (server_mts.py::_api_watchlist, ohne Proxy-Umweg und ohne Token — die App hat ohnehin keine anderen geschützten Schreib-Endpunkte); funktioniert nur mit erreichbarem lokalem Server (Mac mini/Tailscale), nicht auf der reinen Pages-Version.

🔄 Rotation-Dashboard (Rotation-Dashboard/rotation-dashboard.html, seit 2026-07-28)

Sektor-/Themen-Rotation à la IBD: welche der ~20 Themen-ETFs (Industrials, Halbleiter, Biotech, Cyber, Energie, Uran, Software, Regionalbanken, Defense/Aero, Solar, Gold-Miner, KI-Robotik u. a.) sind gerade am stärksten, welche Einzelaktien führen darin, und welche Aktien halten sich an roten Marktagen überdurchschnittlich gut. Drei Tabellen: Sektoren (RS-Rang, 1M/3M-Performance, Abstand vom 52-Wochen-Hoch, über 50-Tage-Linie), Leader in den stärksten Themen (Top-Aktien je Top-Sektor) und Rote-Tage-Resilienz (Aktien, die an den jüngsten Markt-Abwärtstagen relativ zur eigenen Norm überdurchschnittlich stark waren).

Echtes IBD-Relative-Strength-Rating für die Themen-ETFs: Anders als eine simple %-Performance berechnet Rotation-Dashboard/src/rs.py für jeden Themen-ETF dieselbe gewichtete Formel, die IBD für sein RS-Rating nutzt und die der Trend-Screener bereits für Einzelaktien verwendet (raw_rs_score: Outperformance ggü. ^GSPC über 3/6/9/12 Monate, gewichtet 40/20/20/20 — jüngstes Quartal zählt am meisten), anschließend Perzentil-Rang 1–99 unter den ~20 Themen-ETFs. Formel bewusst 1:1 aus dem externen Trend-Screener-Projekt übernommen (kein Neuerfinden, keine Import-Abhängigkeit zwischen den Repos — Entflechtung).

Keine doppelten Datenzüge: Sektor-Tag, RS-Rating, Kurs und Trend-Template-Kriterienzahl je Einzelaktie kommen unverändert aus dem Markets-360-Export (Rotation-Dashboard/src/markets360_reader.py liest denselben _magazine/markets360/markets360_latest.csv, den Signal-Hub im selben Workflow-Lauf schon per rclone gezogen hat, mit lokalem Fallback auf die Original-Datei wie bei Signal-Hub) — keine eigene RS-Berechnung für Einzelaktien. Neu geholt wird nur (1) der Kursverlauf der Themen-ETFs selbst (für deren eigenes RS-Rating, das sonst niemand berechnet) und (2) eine kleine Teilmenge von ~50–80 Leader-/Resilienz-Kandidaten-Tickern für 1M/3M-Performance, Volumen-Ratio und die Rote-Tage-Berechnung — nicht das ganze Aktienuniversum.

Bekannte Einschränkung — Sektor→Themen-Zuordnung: Die Markets-360-„Sektor"-Spalte ist eine grobe GICS-/TradingView-Branchenklassifizierung, keine thematische Nische. Themen-ETFs, die quer durch mehrere Branchen gehen (Biotech, Cyber, Uran/Nuklear, Regionalbanken, KI-Robotik, Gold-Miner, Solar, Defense/Aero), bekommen deshalb selten oder nie Leader-Aktien zugeordnet (sektor_mapping.py dokumentiert das bewusst, statt es über eine Ticker-Einzelfallliste zu "reparieren") — deren eigenes ETF-RS in der Sektoren-Tabelle bleibt davon unberührt und korrekt.

🔗 TradingView-Verlinkung & 📖 Anleitung (seit 2026-08-09): Jedes Ticker-Symbol in allen vier Tabellen (Sektoren-ETFs, Leader, Rote-Tage-Resilienz, Vorbörse) öffnet per Klick den TradingView-Chart in neuem Tab — dieselbe Yahoo-Suffix→TradingView-Börsencode-Zuordnung wie in der Signal-Hub-Setup-Analyse (YAHOO_SUFFIX_TV_EXCHANGE, 1:1 dupliziert, Single-File-App-Prinzip). Header-Button „📖 Anleitung" verlinkt eine dedizierte Betriebsanleitung als Claude-Artifact (Marktregime-Panel, Themen-RS-Formel, die vier Tabellen, Datenherkunft) — siehe CLAUDE.md für die URL und das Design-System.

Datenfluss & Betrieb: Läuft wie Price-Action-Hub im selben Cloud-Workflow (pipeline.yml, Repo Miksch52/signal-hub, eigenes öffentliches Repo Miksch52/rotation-dashboard ohne eigenen Pipeline-Workflow), seit 2026-08-09 als eigener, zu Price-Action-Hub paralleler Job (rotation-dashboard) statt als Schritt danach — beide hängen nur von Signal-Hubs Ausgabe ab, nie voneinander, laufen deshalb gleichzeitig. Bekommt Signal-Hubs data/signals.json (Gate) und die Markets-360-CSV aus dessen Magazin-Ordner separat per actions/download-artifact in die von pfade.py erwartete Geschwister-Struktur Signal-Hub/data/ bzw. Signal-Hub/_magazine/markets360/ gelegt (statt wie zuvor den kompletten Signal-Hub-Checkout mitzuziehen), ebenfalls gegated auf [ -f ../Signal-Hub/data/signals.json ]. Kein eigener Server/Port/LaunchAgent — wird wie Coach/Wiki vom bestehenden 8090-Server statisch mitausgeliefert; Aktualisierung über denselben „☁️ Cloud-Scan starten"-Button (triggerCloudWorkflow(), Ziel-Repo signal-hub, Workflow pipeline.yml). Eigener Yahoo-Cache (~/Library/Application Support/RotationDashboard), getrennt von den anderen beiden Apps. Eigener Deploy-Trigger (seit 2026-08-09): derselbe deploy-trigger.yml-Mechanismus wie bei Price-Action-Hub — ein Edit direkt an dieser App löst sofort einen Pages-Deploy aus, ohne auf den nächsten Signal-Hub-Zyklus zu warten (Secret DEPLOY_TRIGGER_TOKEN separat in diesem Repo nötig).

📊 Setup-Backtest (seit 2026-08-17, Rotation-Dashboard/src/rotation_backtest.py): unverzerrter Forward-Test nach demselben Grundprinzip wie die Backtests in Signal-Hub/Price-Action-Hub (kein Retro-Modus — die drei Kategorien kombinieren bereits mehrere fremde Quellen, eine rückwirkende Rekonstruktion lohnt sich für einen ersten Baustein nicht) für drei Kohorten: top_rs_etf (Themen-ETF mit RS-Rating ≥80 — die IBD/Minervini-Konvention für „führend", testet die Momentum-Persistenz des eigenen ETF-RS-Ratings), leader (Leader-Aktie im stärksten Thema) und resilient (Rote-Tage-Resilienz-Kandidat). Bewusst absoluter Forward-Return, kein Index-Vergleich wie bei Signal-Hubs score_backtest.py — kann bei Bedarf später ergänzt werden. run.py hängt bei jedem Lauf die heutigen Treffer je Kategorie mit Datum + Kurs ans Logbuch (~/Library/Application Support/RotationDashboard/rotation_logbuch.json) und wertet zugleich die gereiften Picks (≥21/50/78 Kalendertage) gegen aktuelle Kurse aus. Ausgabe data/rotation_backtest.json, im Dashboard als Tabellenabschnitt „Trefferquoten (Forward-Test)" mit vorangestelltem Win-Rate-Balkendiagramm unterhalb der Rote-Tage-Resilienz-Tabelle sichtbar, sobald die ersten Fälle gereift sind (seit 2026-08-17, gleiches btChartHtml()-Prinzip wie in Signal-Hub/Price-Action-Hub, hier mit der violetten Ramp aus --acc). R2-Persistenz von Anfang an (_state/rotation_logbuch.json): Rotation-Dashboard hat wie Price-Action-Hub keinen eigenen LaunchAgent, läuft ausschließlich in der Cloud — ohne die R2-Sicherung (neu im rotation-dashboard-Job von pipeline.yml, der bis dahin gar kein rclone/R2 brauchte) hätte die Stichprobe nie über Kalenderzeit wachsen können.

📊 Backtest-Vergleich (backtest-vergleich.html, seit 2026-08-17)

Stufe 3 des Backtest-Ausbaus: ein filter- und sortierbares Panel, das alle unverzerrten Forward-Test-Kohorten der fünf Backtest-Engines an einem Ort zusammenführt — Signal-Hubs Pivot-Detektor (ARMED/BREAKOUT) und Momentum-Score (Tier A/B), Price-Action-Hubs Hebel-Ampel (grün/gelb) und Chartmuster (Breakout/Trendbar/Score), Rotation-Dashboards Setup-Kategorien (Top-RS-ETF/Leader/Resilienz). Beantwortet direkt „was ist gerade das beste Setup im ganzen System" statt fünf Apps einzeln durchklicken zu müssen. Bewusst kein Merge, sondern ein Aggregator (Entflechtungsprinzip): liest live die fünf bereits bestehenden Backtest-JSON-Dateien der drei Apps per relativem fetch() (funktioniert lokal über den 8090-Server UND auf Cloudflare Pages, da alle Apps als Geschwister-Ordner unter derselben Domain liegen — identisches Prinzip wie index.htmls bestehender Top-Setups-Fetch auf Signal-Hub/data/top_setups.js), normalisiert sie in eine flache Zeilenliste und verlinkt jede Zeile zur jeweiligen App-Detailseite zurück. Reine Retro-/Baseline-Kohorten ohne eigenen Forward-Test (z. B. WATCH) sind bewusst ausgeschlossen, damit alle gezeigten Zahlen methodisch vergleichbar bleiben.

Filter: Quelle (5 Chips, Mehrfachauswahl), Horizont (4W/8W/12W, Mehrfachauswahl), Min. n (Stichprobengröße, Standard ≥20 gegen Zufallsrauschen bei kleinen Kohorten) und Sortierung (Win-Rate/Ø-Return/n). Hero-Kennzahl oben zeigt immer das aktuell beste Setup über alle Quellen (unabhängig von der Quelle-Filterauswahl, reagiert nur auf die Datenlage selbst) mit Link zur Detailseite. Win-Rate je Zeile zusätzlich als kleiner Inline-Balken (grün/rot ggü. der 50 %-Basislinie) für den schnellen visuellen Vergleich.

Bugfix beim Bauen entdeckt (2026-08-17): cloudflare-pages/deploy.command hat eine explizite Datei-Whitelist (DATENDATEIEN) für das, was auf mts-hub.pages.dev landet — die neuen Stufe-1-Backtest-Ausgaben hebel_backtest.json/muster_backtest.json/rotation_backtest.json fehlten dort komplett, obwohl der Cloud-Job sie längst per Wildcard nach R2 hochlud. Da Price-Action-Hub/Rotation-Dashboard-Daten vom lokalen 8090-Server immer zu mts-hub.pages.dev durchgereicht werden (server_mts.py::_proxy_cloud_data, kein eigener Dauerlauf für diese Apps), waren die drei neuen Panels dadurch nirgends erreichbar gewesen, auch nicht über den Mac mini — jetzt nachgetragen. Gleicher Fehler auch bei den HTML-Dateien selbst behoben (backtest-vergleich.html fehlte in der HTML-Whitelist).

Verlinkt von der Startseite unter „Trading Apps" (kein eigener Server/Port/LaunchAgent, wird wie Coach/Wiki vom bestehenden 8090-Server statisch mitausgeliefert bzw. komplett client-seitig auf Cloudflare Pages).

🔍 Markets360 Screener (Streamlit, Port 8501)

Volles Screening-Werkzeug für VCP/RS-Rating/Fab-5 (Minervini-Kennzahlen) über ein wählbares Universum (S&P 500, Nasdaq-100, DAX, MDAX, EU-Kern) — nicht zu verwechseln mit „Minervini Markets 360" (Port 8080, siehe oben), der reinen Marktsicht/-ampel. Beide teilen sich dieselbe Python-Engine (minervini360-Package) und damit exakt dieselbe Marktampel-Berechnung (siehe „Woraus die Marktampel berechnet wird" im 8080-Abschnitt) — nur der Screener rechnet zusätzlich den vollen Einzeltitel-Scan.

Sidebar-Features (seit 2026-07-16): Markt-/Index-Auswahl mit automatischer Wikipedia-Aktualisierung der Konstituenten-Listen (>7 Tage alt → Refresh), Zusatz-Indikatoren (RSI/MACD/ADX/Stochastik/Bollinger/OBV) mit Erläuterungen, Pivot-Abstands-Filter („nahe am Kaufpunkt"), Marktampel-Verlauf über die Zeit und ein Scan-Vergleich (gegenüber dem letzten Lauf neu hinzugekommene/herausgefallene Ticker).

☁️ Cloud-Nachtscan (GitHub Actions, seit 2026-07-17): läuft zusätzlich ohne Mac mini als eigener Workflow im Repo Miksch52/minervini-markets-360 (nightly.yml, täglich 05:45 Europe/Berlin, minervini360.cli screen --top 100) und lädt das Ergebnis per rclone nach r2:signalhub-magazine/markets360/ hoch — von dort liest der Daily Signal Hub es als eigene, unabhängige Quelle ein (siehe Datenfusion). Startseite/Signal-Hub haben zusätzlich einen „☁️ Cloud-Scan starten"-Button, der genau diesen Workflow von jedem Gerät aus anstößt. Seit 2026-08-20 sichert derselbe Lauf das Ergebnis zusätzlich datiert unter r2:signalhub-magazine/markets360/history/JJJJ-MM-TT.csv — der Pfad oben bleibt der überschriebene „letzter Stand", die Historie wächst separat (Top-Setups-Roadmap Punkt 5, gleiches Muster wie der OHLC-Tagessnapshot im Signal-Hub).

Lokaler Dauerbetrieb: LaunchAgent com.maick.markets360.dashboard (osascript-Wrapper wegen TCC + lsof-Guard gegen Doppelstarts, wie die Signal-Hub-/Trend-Screener-Server). Quellcode/Git liegt bewusst außerhalb dieses Repos in Mein Minervini Trading-Journal-System/MinerviniMarkets360 (iCloud, eigenes venv) — scripts/sync_runtime.sh spiegelt den Code nach ~/Library/Application Support/Maick Minervini System/app, von wo aus auch der 8080-Server dieselbe Engine importiert (daher garantiert identische Ampel-Werte in beiden Apps). Läuft seit 2026-08-03 automatisch: lokale Git-Hooks (.git/hooks/post-commit/post-merge in diesem Repo) rufen das Skript nach jedem Commit/Pull auf, der src/, data/, scripts/, config.yaml oder requirements.txt betrifft. Grund: das manuelle „einmal ausführen" wurde wiederholt vergessen — zuletzt fehlten dadurch tagelang die Faktoren Follow-Through-Day/10-Jahres-Rendite in der Marktampel, obwohl der Code dafür längst committet war. Details zu Server/Ports/LaunchAgents siehe Abschnitt 4/5.

Läuft der Streamlit-Prozess nicht (Startseiten-Badge „Streamlit offline"), reicht ein Neustart: launchctl kickstart gui/$(id -u)/com.maick.markets360.dashboard. Anders als die Kern-Apps hat dieses Tool keinen eigenen Offline-/Cloud-Fallback für den Live-Scan selbst — es ist bewusst ein rechenintensives lokales Analyse-Werkzeug (voller Scan über hunderte Ticker), kein leichtgewichtiges Dashboard; der nächtliche Cloud-Scan (siehe oben) deckt die Geräteunabhängigkeit stattdessen über den Signal-Hub ab.

📈 Lokaler Trend-Screener (Trend-Screener/dashboard.html, Server-Port 8765)

Screening-/Watchlist-Zentrale nach Minervini, Darvas, Dan Zanger und Jesse Livermore — rein preis-/volumenbasiert, ohne bezahltes Datenabo (yfinance primär für Kurse, stooq-Fallback; Finnhub für Fundamentaldaten). Wählbare Universen (US-Auswahl, kompletter US-Markt, Europa, DAX/MDAX u.a.) liefern je Ticker ein RS-Ranking/VCP/Trend-Template-Ergebnis.

⚡ Code 33 (Minervini-Fundamentalfilter): mindestens drei aufeinanderfolgende Quartale mit beschleunigendem Wachstum bei EPS, Umsatz und Nettomarge gleichzeitig — eigenes Badge/Filter/CSV-Spalte (code33). 🏆 Top-Picks = charttechnisches Minervini-Setup und Code 33 gleichzeitig erfüllt — eigener Chip/Filter, die Schnittmenge aus Chart und Fundamentaldaten.

⚡ Hebel-Ampel (Filter „Hebel-Kandidaten (grün)", seit 2026-08-16): Reife-Ampel speziell für Hebelprodukte (Knock-Outs/Optionsscheine, z. B. über Finanzen.net Zero) — identische Kriterien wie im Daily Signal Hub und Price-Action-Hub (Markt-Ampel und Stage-2-Trend-Template grün, sonst sofort 🔴/kein Badge; zusätzlich enge Basis/VCP, Pivot-Trigger ARMED/BREAKOUT, kein Extended ≥25 % über SMA50, kein Earnings-Fenster, kein 50/80-Gap-Risiko, kein Klimax-Warnsignal → 🟢 „bereit", sonst bei grünem Markt/Trend 🟡 „im Fokus"). Der Trend-Screener berechnet dafür nichts neu, sondern lädt die bereits vorhandenen Faktoren per same-origin-Fetch aus Signal-Hub/data/signals.json und pivot.json (dritte, unabhängige Kopie derselben Logik — kein Cross-App-Import, siehe Entflechtungsprinzip) und gleicht sie über das Ticker-Symbol ab. Nur Ticker, die auch im Signal-Hub-Universum auftauchen, bekommen ein Badge/einen Chip-Zähler — bei den übrigen bleibt es leer statt eines falschen Werts.

🔍 Setup-Analyse-Verknüpfung (seit 2026-08-16): die aufgeklappte Detailzeile jedes Tickers verlinkt zusätzlich auf ../Signal-Hub/setup-detail.html?ticker=… — denselben Detail-Überblick wie bei Signal-Hub und Price-Action-Hub (Score-Faktoren, Pivot-Kennzahlen, Price-Action-Muster, TradingView-Chart, Fundamentaldaten & Story), statt einer eigenen, duplizierten Analyse-Ansicht. Bekannte Einschränkung wie beim Price-Action-Hub: setup-detail.html braucht zwingend einen Eintrag in Signal-Hub/data/signals.json — für Ticker außerhalb dieses Universums (Erfahrungswert ~65–80 % Überschneidung, siehe Hebel-Ampel-Absatz oben) zeigt die Zielseite ihren vorhandenen „Kein Treffer"-Hinweis statt eines Fehlers. Die Setup-Analyse selbst hat seit demselben Tag ein Eingabefeld zum Ticker-Wechsel direkt in der geöffneten Seite (siehe Signal-Hub-Abschnitt) — praktisch bei einem breiteren Ticker-Universum wie hier.

Zugriff & Aktualisieren: Läuft über den externen hub_server.py (Port 8765), same-origin über den 8090-Server erreichbar (/Trend-Screener/* wird durchgereicht — Dashboard, signals.js, /api/status, /api/links). Drei Update-Buttons im Dashboard (USA-Auswahl / USA gesamt / Europa) rufen /api/run?markets=… auf (der Proxy erzwingt eine feste Markt-Allowlist); /api/open (öffnet Dateien/Apps auf dem Mac) bleibt mit 403 gesperrt — Ausnahme /api/watchlist (POST, siehe unten), die ist erlaubt. Der Scan läuft via osascript (sonst kein TCC-iCloud-Zugriff im Subprozess) und nutzt einen lokalen Cache außerhalb iCloud (~/Library/Application Support/LokalerTrendScreener) — sonst OSError EDEADLK bei den tausenden Kurs-CSV-Zugriffen. Nur signals.js selbst liegt im iCloud-Ordner (Auslieferung + Pages-Snapshot).

☁️ Cloud-Nachtlauf (GitHub Actions, seit 2026-07-17): eigenes privates Repo Miksch52/lokaler-trend-screener (nightly.yml, Mo–Fr 23:00 Europe/Berlin, run.py --hub --markets us,europe -f, bewusst ohne --notify — Push übernimmt der Signal-Hub gebündelt), Ergebnis geht per rclone nach r2:signalhub-magazine/trendscreener/ — von dort liest der Daily Signal Hub es als eigene, unabhängige Quelle ein (siehe Datenfusion). „☁️ Cloud (überall)"-Button im Dashboard stößt denselben Workflow von jedem Gerät aus an. Fix 2026-08-13: nightly.yml lud danach zwar den Dashboard-Snapshot nach R2 hoch, stieß aber (anders als Price-Action-Hub/Rotation-Dashboard mit ihrem eigenen deploy-trigger.yml) keinen Pages-Deploy an — frische Daten aus einem manuellen „Cloud (überall)"-Klick erschienen auf mts-hub.pages.dev dadurch erst zufällig mit dem nächsten Signal-Hub-Zyklus (bis zu 6 Std. Verzögerung statt sofort). Neuer letzter Schritt in nightly.yml stößt jetzt direkt deploy.yml im Hauptrepo an (identischer curl-Aufruf wie in price-action-hub/.github/workflows/deploy-trigger.yml), braucht dafür das Secret DEPLOY_TRIGGER_TOKEN auch in diesem Repo (gh secret set DEPLOY_TRIGGER_TOKEN --repo Miksch52/lokaler-trend-screener, gleicher Token-Wert wie in den anderen Repos). Seit 2026-08-20 sichert derselbe Lauf das Ergebnis zusätzlich datiert unter r2:signalhub-magazine/trendscreener/history/JJJJ-MM-TT.json — der Pfad oben bleibt der überschriebene „letzter Stand", die Historie wächst separat (Top-Setups-Roadmap Punkt 5, gleiches Muster wie der OHLC-Tagessnapshot im Signal-Hub).

🗒️ Watchlist erstellen (Tools-Leiste, seit 16.08.2026): schreibt die aktuell gefilterte Tabellenansicht (Suche, RS-Min, alle Toggle-Filter inkl. Hebel-Ampel) als zwei Dateien nach Watchlisten/Trend-Screener/ im MTS-Hauptordner (nicht im Trend-Screener-eigenen Output — bewusst zentral mit eigenem Unterordner, damit künftig auch andere Apps dort ablegen können, ohne den gemeinsamen Ordner unübersichtlich zu machen): (1) eine TradingView-importierbare .txt — Symbole laufen durch dieselbe tvSymbol()-Zuordnung wie die TradingView-Links je Zeile (europäische Suffixe → Börsencode, z. B. AIXA.DEXETR:AIXA), Inhalt ist eine einzelne ###LABEL-Kopfzeile plus kommagetrennte Symbole, dasselbe Format, das export.py::write_watchlist im Trend-Screener-eigenen Output schon länger für die Pipeline-Ergebnisse schreibt; (2) eine gleichnamige _lesbar.txt zum schnellen Durchlesen ohne TradingView — eine Zeile pro Ticker mit RS/Kurs/M-Score/Flags/Sektor, dazu eine Kopfzeile mit Zeitstempel und einer Klartext-Zusammenfassung der aktiven Filter. Dateiname enthält Datum, Herkunft und Markt (z. B. 2026-08-16_Trend-Screener_USA-Auswahl.txt); mehrere Exporte am selben Tag/Markt bekommen automatisch einen _2/_3-Suffix statt sich still zu überschreiben. Neuer Endpunkt POST /api/watchlist in hub_server.py (Validierung: Markt aus fester Allowlist, max. 3000 Symbole mit engem Ticker-Muster, Größenlimit für den freien lesbaren Text) — dafür musste der 8090-Proxy erstmals überhaupt POST-Requests an /Trend-Screener/* durchreichen (server_mts.py::do_POST kannte bis dahin nur /data und /Signal-Hub/api/*, jeder POST an den Trend-Screener lief ins Leere).

Fix 16.08.2026 — „📂 Ergebnisse"-Button öffnete den falschen (leeren) Ordner. links.jsons Eintrag {"target":"output"} wurde in /api/open relativ zu config.BASE_DIR aufgelöst (dem iCloud-Projektordner) — der echte Ergebnisordner ist aber config.OUTPUT_DIR, bewusst außerhalb iCloud (siehe Cache-Begründung oben). Der iCloud-seitige output/-Ordner existierte zwar (uralter Rest vom 24.06.), war aber nie der befüllte — der Button öffnete faktisch nichts Aktuelles. /api/open löst "output" jetzt als symbolischen Namen direkt auf config.OUTPUT_DIR auf. Bleibt trotzdem wirkungslos, wenn die Seite über den 8090-Proxy/Tailscale/Cloud geöffnet wird — das ist keine Regression, sondern der bewusste /api/open-403-Schutz (s. o.): der Button funktioniert nur direkt auf dem Mac mini unter localhost:8765, weil er lokal Finder öffnet — auf einem iPhone/iPad oder von einem anderen Gerät aus gäbe es ohnehin nichts sinnvoll zu öffnen.

📖 Betriebsanleitung (seit 2026-08-16): Header-Button „📖 Anleitung" verlinkt wie bei den anderen Apps eine dedizierte Betriebsanleitung als Claude-Artifact (Status-Badges, Strategien-Flags M/D/Z/L/V, M-Score-Formel, Filter-Referenz, Datenherkunft) — Trend-Screener-Anleitung. Eigenes, viertes Design (dunkle Navy-Basis + Masthead/Nav-Rail wie das gemeinsame Template von Price-Action-Hub/Rotation-Dashboard/Hauptapp, aber mit dem echten Blau-Akzent (#4493F8) des Dashboards selbst statt deren jeweiliger Akzentfarbe) — siehe CLAUDE.md für die vollständige Design-System-Übersicht. Diese Seite (und dieser Wiki-Abschnitt) werden bei jeder funktionalen Änderung am Tool mit aktualisiert.

Projektort: Liegt bewusst außerhalb dieses Repos/iCloud-Ordners (GPT/KI-Projekte/Projekt-Versuche/Lokaler-Trend-Screener, eigenes Git-Repo) — der 8090-Server reicht die App nur durch, entwickelt/dokumentiert wird sie separat. Der Trend-Screener/-Ordner in diesem Repo existiert deshalb nicht dauerhaft: cloudflare-pages/deploy.command kopiert bei jedem Deploy lediglich einen Snapshot (dashboard.html + signals.js) aus dem externen Ordner hinein, damit die Pages-Version offline etwas zum Anzeigen hat — Live-Aktualisieren funktioniert dort naturgemäß nicht (kein Mac-mini-Proxy erreichbar), nur der letzte Cloud-Nachtlauf-Stand.

🤖 TraderFox KI-Agenten (traderfox-ki-agenten.html)

Kuratierte Linksammlung zu den 7 wichtigsten externen KI-Research-Agenten von TraderFox/Trader-Zeitung (Signal-Agent, News-Signal-Agent, Screener-Agent) — jeweils mit Kurzbeschreibung, Kategorie-Badge und Kadenz (sofort bei Ereignis / stündlich / Mo–Fr / Di & Do / Mo & Do). Jede Karte verlinkt direkt auf den passenden Newsticker-Filter bei traderzeitung.de.

Bewusst reine Linkseite, kein eigener Datenabruf (Entflechtung): Die Agenten laufen komplett extern bei TraderFox, hier wird nichts gespiegelt oder gecacht. Voller Zugriff auf einzelne Artikel kann ein Trader-Zeitung-/TraderFox-Abo voraussetzen. Quelle: Weekly Briefing vom 06.08.2026 (Simon Betschinger); zusätzlich verlinkt die Seite auf die vollständige Agenten-Übersicht (traderzeitung.de/agents.html).

Statische Single-File-Seite ohne eigenen Server/Port — wird wie Coach/Wiki vom 8090-Server mitausgeliefert und ist auch auf der Cloudflare-Pages-Version direkt erreichbar.

🧭 Ruhestands-Fahrplan (Ruhestands-Fahrplan/ruhestand-fahrplan.html, seit 2026-08-13)

Persönliches Ruhestands-Cockpit, kein Trading-Tool: eigene Zahlen (Ausgaben/Einnahmen, Eigenheim, Mietwohnung, Depot & Liquidität, beliebig viele Lebens-/Rentenversicherungen — auch beitragsfrei gestellte mit Restguthaben) werden live zu Netto-Rentenlücke, Ziel-Liquiditätsreserve, Depot-Entnahmerate und einer Ist-vs-Ziel-Vermögensstruktur verrechnet. Dazu ein automatisch aus den eingetragenen Terminen erzeugter Fahrplan (Zinsbindungsenden, Versicherungsauszahlungen, Renteneintritt) und eine 23-Punkte-Maßnahmenliste mit Terminierung, Haken und Notizen.

Bewusst kein Cloud-/KI-Tool (seit 2026-08-15): Lief zunächst als Claude-Artifact, läuft jetzt komplett lokal wie Coach/Wiki — statisch vom 8090-Server mitausgeliefert, kein eigener Server/Port, keine Abhängigkeit von claude.ai mehr. Alle Daten bleiben ausschließlich im localStorage des jeweiligen Browsers, kein Server-Sync. Kein geräteübergreifender Datenabgleich (anders als der Coach): Mac mini und MacBook haben je einen eigenen Datenstand — Abgleich bei Bedarf manuell über „Export JSON" → „Import JSON". Bewusst nicht im Cloudflare-Pages-Deploy enthalten (rein lokales/LAN-Tool).

Vorschläge aus dem Trading-System (nur lokal): Ruft beim Öffnen per fetch("/data") same-origin mts_data.json ab — funktioniert nur, wenn die Seite tatsächlich vom 8090-Server kommt — und zeigt Depotwert/Liquidität/Jahresausgaben aus dem Trading-System als Vorschlagsbox, aber nur solange das jeweilige Zielfeld noch leer ist. Nie automatisch übernommen: immer per explizitem Klick, mit deutlicher Warnung, dass das Trading-Depot überwiegend aktiv gehandeltes Momentum-Kapital ist (SEPA/VCP-Stil), keine automatische Rentenreserve.

📖 Anleitung: Header-Button verlinkt Ruhestands-Fahrplan/anleitung.html — Workflow, Symbol-/Kennzahlen-Legende, Geräte-Hinweis und Erweiterungsvorschläge, läuft ebenfalls komplett lokal ohne Claude-Artifact.

04 Server & Ports

PortServerAufgabe
8090server_mts.pyLiefert den ganzen Projektordner aus (Startseite, Hauptapp, Coach, Wiki). Preis-Proxy (yfinance + onvista für dt. Derivate), Daten-Persistenz /data, /status; reicht /markt /sector-perf /fred an den 8080-Server durch (Markets 360 über HTTPS)
8080Minervini/server.pyMarkets 360 + Daten-Endpunkte /markt/<symbol>, /fred/<serie> (Key im macOS-Schlüsselbund minervini-fred-api; bewusst nicht in GitHub Secrets verschoben — nur der lokale 8080-Server/Makro-Tab braucht ihn, keine der Cloud-Pipelines ruft FRED auf; relevant erst, falls die Marktampel selbst mal cloud-fähig werden soll), /sector-perf (15-Min-Cache), /marktampel (ruft die minervini360-Engine des Markets360 Screeners direkt an, siehe Marktampel-Absatz oben), /status
8091Signal-Hub/src/server.pySignal-Hub-Dashboard, Screening-Lauf (POST /api/run), Konfiguration, /api/status; liefert auch den Coach aus (Fernzugriff über einen Port)
8501Markets360 Screener (Streamlit, Quellordner Mein Minervini Trading-Journal-System/MinerviniMarkets360 in iCloud, LaunchAgent com.maick.markets360.dashboard, seit 2026-07-22)Screening-Engine (VCP/RS-Rating/Fab-5) + dieselbe Marktampel-Engine (minervini360.scoring.market), die auch der 8080-Server direkt importiert — beide zeigen seit 2026-07 exakt denselben Ampel-Prozentwert. Seit 2026-07-16 zusätzlich: Markt-/Index-Auswahl in der Sidebar (S&P 500, Nasdaq-100, DAX, MDAX, EU-Kern) mit automatischer Wikipedia-Aktualisierung der Listen (>7 Tage), Zusatz-Indikatoren (RSI/MACD/ADX/Stochastik/Bollinger/OBV) mit Erläuterungen, Pivot-Abstands-Filter („nahe am Kaufpunkt"), Marktampel-Verlauf und Scan-Vergleich (Neu/Rausgefallen). Quellcode/Git: Mein Minervini Trading-Journal-System/MinerviniMarkets360 (iCloud); scripts/sync_runtime.sh spiegelt nach ~/Library/Application Support/Maick Minervini System/app, von dort importiert der 8080-Server die Marktampel-Engine — läuft seit 2026-08-03 automatisch per Git-Hook (post-commit/post-merge), siehe 8080-Abschnitt oben.
8765hub_server.py (Lokaler Trend-Screener, externer iCloud-Ordner)Trend-Screener-Dashboard + /api/*. Same-origin über 8090 erreichbar: der 8090-Server reicht /Trend-Screener/* durch (dashboard.html, signals.js, /api/status, /api/links). Aktualisieren läuft über /api/run?markets=us|us_all|europe — drei Buttons im Dashboard (USA-Auswahl / USA gesamt / Europa); der Proxy lässt /api/run nur mit dieser Markt-Allowlist durch. /api/open (öffnet Dateien/Apps auf dem Mac) bleibt mit 403 gesperrt — Ausnahme /api/watchlist (POST, „🗒️ Watchlist erstellen", siehe App-Abschnitt oben), die ist erlaubt. Der Screening-Lauf startet via osascript (nur so hat der Subprozess TCC-iCloud-Zugriff) und nutzt einen lokalen Cache außerhalb iCloud (~/Library/Application Support/LokalerTrendScreener) — sonst OSError EDEADLK bei den tausenden Kurs-CSV-Zugriffen. Nur signals.js bleibt im iCloud-Ordner (Auslieferung + Pages-Deploy).
8502StreamlitTrading Cockpit (optional, manuell gestartet)

05 Dauerbetrieb auf dem Mac mini

Alle Dienste laufen als LaunchAgents: Sie starten beim Login automatisch und arbeiten als Watchdog — alle 5 Minuten wird geprüft, ob der Server noch läuft; wenn nicht, wird er neu gestartet. Ein abgestürzter Server ist also spätestens nach 5 Minuten von selbst wieder da.

LaunchAgentDienst
de.maickschwillo.mts-serverMTS-Server (8090)
de.maickschwillo.minervini-dashboardMarkets-360-Server (8080)
com.maick.signalhub.serverSignal-Hub-Server (8091)
com.maick.trendscreener.serverTrend-Screener-Server (8765, KeepAlive; Plist im externen Trend-Screener-Ordner). Läuft mit /usr/bin/python3 (System 3.9, hat die Screener-Deps — wie der 8090-Server). Der osascript-Start nutzt kein & (osascript bleibt am Server hängen), damit KeepAlive nicht in ein Start-Race läuft. Muss einmalig nach ~/Library/LaunchAgents kopiert und per launchctl bootstrap geladen sein — sonst überlebt er keinen Neustart.
com.maick.trendscreenerTrend-Screener-Nachtlauf: Mo–Fr 23:00 Uhr, run.py --hub --markets us,europe -f --notify (schreibt signals.js, das Dashboard liest nur diese Datei). Plist im externen Trend-Screener-Ordner, seit 2026-07-06 installiert. Bewusst ohne us_all und ohne --force-fund — diese Kombination ließ den Lauf am 2026-07-06 wegen eines yfinance-Sqlite-Locks über 30 Min hängen (siehe Abschnitt 8). Seit 2026-07-17 zusätzlich als Cloud-Workflow ohne Mac mini: der bislang ungetrackte Ordner ist jetzt ein eigenes privates Repo Miksch52/lokaler-trend-screener mit .github/workflows/nightly.yml (gleicher Zeitplan, ohne --notify — Push übernimmt Signal-Hub gebündelt); Ergebnis geht per rclone nach r2:signalhub-magazine/trendscreener/. Dieser LaunchAgent läuft vorerst nur noch zur Kontrolle parallel.
com.maick.signalhub (entfernt seit 2026-08-10)War der lokale Push-Zeitplan (alle 15 Min, löste je einmal pro Slot Lauf + Push aus) — pushte entgegen der ursprünglichen Doku an denselben ntfy-Kanal wie die längst produktive Cloud-Pipeline, nicht an einen separaten Test-Kanal. Führte unbemerkt seit mind. 2026-07-31 zu doppelten/dreifachen Pushes (verschärft dadurch, dass die Plist zusätzlich fälschlich auf dem MacBook statt nur dem Mac mini lag). Die Cloud-Pipeline deckt alle 4 Slots bereits vollständig und unabhängig von jedem Mac ab — dieser LaunchAgent gehört auf keinem Mac mehr nach ~/Library/LaunchAgents (launchctl bootout gui/$(id -u)/com.maick.signalhub && rm ~/Library/LaunchAgents/com.maick.signalhub.plist).
com.maick.pivot-backtestPivot-Evaluations-Loop: So 08:15 — bewertet gereifte Forward-Picks gegen aktuelle Kurse (--evaluate) + neuer Retro-Walk-Forward. Plist: Signal-Hub/com.maick.pivot-backtest.plist (per launchctl bootstrap laden)
com.maick.markets360.nightlyMarkets360-Screener-Nachtlauf (seit 2026-07-16): täglich 05:45 Vollscan des gewählten Universums über die CLI (minervini360.cli screen --top 50, osascript-Wrapper wegen TCC, Log /tmp/markets360-nightly.log). Schreibt zeitgestempelte CSV und den stabilen Stand exports/markets360_latest.csv. Seit 2026-07-17 zusätzlich als Cloud-Workflow ohne Mac mini (siehe Markets-360-Karte oben) — dieser LaunchAgent läuft vorerst nur noch zur Kontrolle parallel. Plist direkt in ~/Library/LaunchAgents.
com.maick.markets360.dashboardMarkets360-Screener-Dashboard (8501, Streamlit, KeepAlive; seit 2026-07-22). osascript-Wrapper wegen TCC + lsof-Guard gegen Doppelstarts (wie Signal-Hub-/Trend-Screener-Server), Kommando PYTHONPATH=src .venv/bin/streamlit run src/minervini360/dashboard.py --server.headless true --server.port 8501 im iCloud-Projektordner Mein Minervini Trading-Journal-System/MinerviniMarkets360. Läuft auf dem jeweils dort ausgecheckten Branch (Stand 2026-07-22: main). Log /tmp/markets360-dashboard.log. Plist direkt in ~/Library/LaunchAgents. Vorher musste die App manuell per Terminal gestartet werden — daher „Streamlit offline" auf der Startseite, wenn sie nach einem Neustart nicht lief.
TCC-Besonderheit: launchd-Python darf iCloud-Dateien nicht direkt öffnen („Operation not permitted"). Alle Plists nutzen deshalb einen osascript-Wrapper, der den Server entkoppelt startet. Folge: launchctl bootout beendet den Server nicht — erst den Prozess am Port beenden.

Nützliche Kommandos (Terminal am Mac mini)

# Status aller Agents
launchctl list | grep -E "maick|signalhub|minervini|mts"

# Server neu starten (Beispiel Signal-Hub, Port anpassen)
kill $(lsof -tnP -iTCP:8091 -sTCP:LISTEN)
launchctl kickstart gui/$(id -u)/com.maick.signalhub.server

# Logs
tail -f /tmp/mts-server.log
tail -f /tmp/minervini-dashboard.log
tail -f /tmp/signalhub-server.log        # Server
tail -f /tmp/signalhub-scheduled.log     # Screening-Läufe/Push

Energie: sleep 0, per Netzwerk weckbar (womp 1), nur das Display geht aus. Den Mini nicht herunterfahren.

Zwei Regeln:Automatik installieren.command / Mac Mini Dauerbetrieb.command nie auf dem MacBook ausführen (sonst doppelte Pushes, und das MacBook verlernt den Ruhezustand). ② Keine gleichzeitigen Screening-Läufe von zwei Macs — Risiko von iCloud-Sync-Konflikten in data/signals.json. Anschauen/Lesen ist immer unkritisch.

HTTPS für die Offline-App (einmalig)

Die PWA (Abschnitt 2) braucht HTTPS. Das liefert tailscale serve mit gültigem Zertifikat — rein im Tailnet, nichts wird öffentlich (kein funnel).

  1. Einmalig in der Admin-Konsole: login.tailscale.com/admin/dnsHTTPS Certificates aktivieren (sonst hängt der nächste Schritt beim Zertifikat).
  2. Auf dem Mini: tailscale serve --bg --https=443 http://127.0.0.1:8090
  3. Prüfen: tailscale serve status → zeigt https://…ts.net/ → http://127.0.0.1:8090

--bg macht die Weiterleitung dauerhaft (übersteht Neustarts). Rückgängig: tailscale serve --https=443 off. Nach Code-Änderungen am 8090-Server diesen wie oben neu starten, damit die PWA-Verdrahtung (Manifest/Service Worker) aktuell ist.

06 Daten & Sicherung

WasWoSicherung
Trades, Portfolio, Einstellungenmts_data.json (geschrieben vom 8090-Server bei jedem Speichern) + privater GitHub-Gist (Cross-Device-Sync, seit Fix 2026-08-15 auf jedem Origin aktiv, siehe Abschnitt 2)① Rotierende Backups: data-backups/, die letzten 30 Stände, automatisch vor jedem Überschreiben · ② iCloud-Versionierung · ③ der Gist selbst (privat, GitHub-seitig). Nicht mehr in Git (private Trading-Daten gehören nicht ins Repo — seit 2026-06 in .gitignore; Quelle der Wahrheit sind die data-backups/). Backup-Wächter: Die Hauptapp prüft über /backup-status die jüngste Sicherung (Alter, Lesbarkeit, Trade-Zahl) und warnt in der Status-Leiste, falls das Backup > 7 Tage alt, leer oder unlesbar ist.
Signal-Hub-ErgebnisseSignal-Hub/data/signals.jsonWird bei jedem Lauf neu erzeugt — kein Backup nötig
Signal-Hub-Konfiguration (inkl. Token)Signal-Hub/config.jsoniCloud; bewusst nicht in Git (Secrets). Für die Cloud-Pipeline liegt eine angepasste Kopie (PDF-Ordner umgebogen, Depot-Abgleich aus) als GitHub-Secret SIGNALHUB_CONFIG_JSON vor.
Traderfox-Magazine (Kopie für Cloud-Pipeline)Cloudflare R2, Bucket signalhub-magazineAutomatischer Sync seit 2026-08-20 (scripts/upload_magazine_to_r2.py + LaunchAgent com.maick.signalhub.pdfsync, WatchPaths auf den iCloud-Ordner); Original bleibt der iCloud-Ordner für den lokalen Mini-Lauf
Coach-LernfortschrittGitHub-GistCloud-seitig
Mail-Passwort (IMAP)macOS-Schlüsselbund signal-hub-imap (pro Mac); für die Cloud-Pipeline zusätzlich als GitHub-Secret SIGNALHUB_IMAP_PASSWORD
Konvention: mts_data.json wird in Git nur als bewusster, separater Snapshot committet („Daten: …"), nie vermischt mit Code-Änderungen. So kann ein Code-Rollback nie Trading-Daten zurückdrehen.

07 Wartung & Fehlerbehebung

SymptomUrsache / Lösung
Startseiten-Badge zeigt „iCloud-Version"Zugehöriger Server läuft nicht → der Watchdog startet ihn binnen 5 Min selbst neu; sofort: launchctl kickstart gui/$(id -u)/<agent> (siehe Abschnitt 5)
Trend-Screener: „Connection refused (8765)"Der Hub-Server (8765) läuft nicht — der 8090-Proxy kann /Trend-Screener/* nicht durchreichen. Prüfen: lsof -iTCP:8765 -sTCP:LISTEN und launchctl list | grep trendscreener. Häufige Ursachen: (1) LaunchAgent nicht in ~/Library/LaunchAgents installiert → nach jedem Neustart weg; (2) Plist zeigt auf ein fehlendes Python (früher /usr/local/bin/python3 — Homebrew fehlt auf dem Mini). Fix: Plist auf /usr/bin/python3 und ohne & am Serverstart (sonst Start-Race → OSError: Resource deadlock avoided beim gleichzeitigen iCloud-Lesen von config.py), dann cp nach ~/Library/LaunchAgents + launchctl bootstrap gui/$(id -u) <plist>.
Trend-Screener zeigt tagelang denselben Stand (behoben 2026-07-06)Ursache war nicht der Server (der lief unauffällig und meldete auch bei veralteten Daten "running": true/false), sondern der Nachtlauf: die dokumentierte Automatisierung (com.maick.trendscreener.plist) war nie nach ~/Library/LaunchAgents installiert — launchctl list | grep trendscreener zeigte nur den Server-Agent, nicht den Scan-Agent. Zusätzlich hätte die alte Plist-Fassung ohnehin nicht funktioniert: sie rief python3 direkt statt über osascript auf (TCC-Problem, siehe Hinweis oben) und ohne --hub (schreibt dann nicht signals.js, das Dashboard bleibt trotzdem alt). Fix: Plist mit osascript-Wrapper + --hub --markets us,europe -f --notify neu gebaut, installiert und geladen (Zeile „com.maick.trendscreener" oben). Bei erneutem Auftreten: launchctl list | grep com.maick.trendscreener prüfen (muss zwei Zeilen zeigen, .server und ohne Suffix) und tail /tmp/trendscreener-scheduled.log.
Startseite: „Server nicht erreichbar", obwohl der Mini läuftMini und Gerät im selben WLAN? Von unterwegs: Tailscale aktiv? Die Seite findet den Server selbst, wenn sie als Datei geöffnet wurde — erreichbar muss er aber sein
Markets 360: Marktampel/Sektoren leerDaten kommen sonst per CORS-Proxy auch ohne Server → bleibt alles leer, ist die Internet-Verbindung weg oder die öffentlichen Yahoo-Proxies (allorigins/corsproxy) gerade gestört; einfach erneut laden
Derivate-/Optionsschein-Kurse fehlen oder zeigen den BasiswertKurse deutscher Derivate (Turbos/OS/Faktor-/Knock-Out-Zertifikate) holt der 8090-Server per ISIN über die onvista-API (Yahoo listet sie nicht; daher nie den Basiswert verwenden). Zeigt eine Position „—", war onvista kurz nicht erreichbar → erneut „🔄 Kurse". Der Abruf nutzt zuerst den lokalen Proxy (8090); ohne ihn bleiben reine Derivate „—".
Signal-Hub: keine Mail-SignaleSchlüsselbund-Eintrag fehlt auf dem Mac, der den Lauf ausführt → security add-generic-password -a "mschwillo@freenet.de" -s "signal-hub-imap" -U -w
Signal-Hub: keine PDF-Signalepypdf fehlt → /usr/bin/python3 -m pip install --user pypdf; Magazin-Ordner-Pfad in config.json prüfen
„Speichern" im Signal-Hub geht nicht (403)Token fehlt auf dem Gerät → Seite einmal mit ?token=… öffnen
Pushes kommen doppelt/dreifachBestätigter Fall, MacBook (2026-08-10): Push-Zeitplan lief auf zwei Macs parallel — Cloud-Pipeline UND lokaler com.maick.signalhub-LaunchAgent (eigentlich nur für den Mac mini gedacht, „Vergleichsphase" vom 2026-07 nie beendet) pushten beide zu denselben 4 Slots an denselben ntfy-Kanal, seit mindestens 2026-07-31 unbemerkt. Die Cloud-Pipeline selbst pusht sauber (geprüft in den GitHub-Actions-Logs: pro Slot genau einmal). Fix: launchctl bootout gui/$(id -u)/com.maick.signalhub UND die Plist dauerhaft entfernen (rm ~/Library/LaunchAgents/com.maick.signalhub.plist, sonst lädt sie beim nächsten Login neu) — auf jedem Mac außer dem, der ihn wirklich betreiben soll (aktuell: auf keinem mehr nötig, die Cloud-Pipeline deckt alle 4 Slots unabhängig von beiden Macs ab). Prüfen: launchctl list | grep com.maick.signalhub darf auf keinem Mac mehr eine Zeile ohne .server-Suffix zeigen.
iPhone: Seite „tot", nichts klickbarHTML-Datei statt HTTP-Adresse geöffnet → http://mac-mini-von-maick.local:8090/ verwenden
Markets 360: FRED/Makro oder Marktdaten veraltetDer Service-Worker (PWA) reicht /markt, /fred, /sector-perf jetzt immer frisch ans Netz (nie aus dem Cache). Falls nach einem Update noch alte Werte erscheinen: Seite neu laden (ggf. zweimal) bzw. die PWA einmal schließen und neu öffnen, damit der neue Service-Worker (Cache-Version wird seit Fix 2026-08-03 automatisch aus einem Hash über die Precache-Dateien berechnet, siehe Abschnitt 2) aktiv wird.
Signal-Hub „Aktualisieren" tut nichts / „Lauf läuft bereits"Ein früherer Lauf hing → das in-memory-Lock blieb gehalten. Behoben: server.py bricht einen Lauf nach RUN_TIMEOUT (10 Min) hart ab und gibt das Lock frei. Sofort-Abhilfe: 8091-Server neu starten (Port-Prozess killen, dann launchctl bootstrap gui/$(id -u) Signal-Hub/com.maick.signalhub.server.plist). Der Server-Job läuft jetzt mit KeepAlive — stirbt der Server, startet launchd ihn binnen ~10 s neu (zusätzlich 5-Min-Watchdog via StartInterval). Voraussetzung: Der Job muss in launchd geladen sein (einmalig per bootstrap bzw. „Automatik installieren.command"). Der Timeout killt jetzt die ganze Prozessgruppe (run.py + scorer.py), sonst hielt ein überlebendes Kind die Pipe offen und das Lock blieb hängen.
Signal-Hub aktualisiert nicht automatisch (kein Morgen-/Abend-Push)Seit 2026-08-10 kein lokaler Job mehr dafür zuständig — der frühere Scheduler com.maick.signalhub ist auf allen Macs entfernt (war Ursache doppelter Pushes, siehe oben), Push kommt ausschließlich aus der Cloud-Pipeline. Prüfen bei Ausbleiben: gh run list --repo Miksch52/signal-hub --workflow=pipeline.yml --limit 5 (lief der Slot? Status failure?) statt lokal nach Plist/Log zu suchen.
Markt-Chip im Cockpit fehlt8080-Server nicht erreichbar — Chip blendet sich dann bewusst aus
Kein Zugriff von unterwegsTailscale auf iPhone und Mini aktiv? Mini wach? (Display darf aus sein)
MTS Hub startet auf dem iPhone nicht, wenn der Mac mini offline istHäufigste Ursache: Das Home-Bildschirm-Icon zeigt auf eine Mac-mini-Adresse (Tailscale-.ts.net, .local oder lokale IP) statt auf https://mts-hub.pages.dev/. Diese Adressen sind reine Weiterleitungen zum Mini ohne eigenen Service-Worker-Cache — ist der Mini offline, gibt es dort nichts zu laden (kein Bug, erwartetes Verhalten). Fix: altes Icon löschen, in Safari https://mts-hub.pages.dev/ öffnen, Teilen → „Zum Home-Bildschirm", einmal online starten (füllt den Precache), siehe Abschnitt 2.
Hub startet offline, aber Apps öffnen sich nicht (springt immer zurück zum Hub)Behoben (Fix 2026-07-05b, Abschnitt 2): target="_blank" auf den App-Karten funktioniert nicht in der installierten Standalone-PWA (nur ein Fenster) — iOS brach die Navigation ab. Falls das Verhalten nach einem Update wieder auftritt: neuen Deploy-Stand prüfen (cloudflare-pages/deploy.command erneut ausführen) und die PWA einmal online neu öffnen, damit index.html aktualisiert wird.
„☁️ Cloud-Scan starten"/„🔄 Aktualisieren" meldet „Fehler beim Starten (404)"Fix 2026-08-14 (signal-hub-Repo): Ursache ist praktisch immer der gh_actions_token auf genau diesem Gerät (localStorage, pro Gerät separat eingerichtet, siehe Abschnitt 2) — fehlt er, ist er abgelaufen, oder fehlt ihm „Actions: Read and write" auf signal-hub. GitHub meldet fehlende Repo-Berechtigung eines Fine-grained-PATs bei workflow_dispatch bewusst als 404 statt 403 (verschleiert damit, ob das Repo existiert) — triggerCloudWorkflow() behandelt seither auch 404 wie 401/403: der kaputte Token wird automatisch aus localStorage gelöscht, beim nächsten Klick fragt die App neu danach. Funktioniert der Scan auf einem anderen Gerät (z. B. MacBook) einwandfrei, bestätigt das die Diagnose. Fix: neuen Token unter github.com/settings/personal-access-tokens/new erstellen, siehe Einrichtungs-Hinweis in Abschnitt 2.

08 Tests

  • tests/test-hub-token.sh — prüft Token/Cookie/CORS-Logik des Signal-Hub-Servers (nur GETs bzw. nebenwirkungsfreie POSTs)
  • tests/test_pivot.py — Selbsttest des Pivot-Armed-Detektors (synthetische Charts → erwartete Klassifikation; kein Netz, keine POSTs)
  • tests/ — Playwright-Setup für Browser-Tests der Apps
Eiserne Regel: Browser-Tests gegen die Live-Server dürfen keine POSTs absetzen — MTS.save() würde die echte mts_data.json überschreiben. In Playwright immer alle POST-Requests blocken.

09 Pflege dieses Wikis

Dieses Wiki ist Teil des Repos und wird bei jeder Systemänderung im selben Commit mitgepflegt (Regel in CLAUDE.md verankert — gilt damit für jede Claude-Code-Session). Das „Stand"-Datum oben rechts kommt automatisch vom Dateidatum, die Server-Status-Chips in Abschnitt 1 sind live. Da die Datei in iCloud liegt und über Port 8090 ausgeliefert wird, ist immer und überall die aktuelle Fassung sichtbar.

Multi-Device-Entwicklung: Mac mini + MacBook gleichwertig

Das Repo ist normales Git und liegt in iCloud — Mac mini und MacBook sind damit gleichwertige Entwicklungsumgebungen für Claude Code, sobald git/gh dort eingerichtet sind. Reines Bearbeiten/Committen braucht nur die normale Git-Anmeldung (war auf beiden Rechnern schon vorher aktiv). Für administrative gh-Aktionen (Secrets setzen, Workflows manuell per CLI auslösen mit gh workflow run) ist zusätzlich einmalig pro Rechner gh auth login nötig — auf dem MacBook seit 2026-07-18 eingerichtet (gh per brew install gh installiert, HTTPS-Protokoll, Scopes gist/read:org/repo/workflow). Das ist kein Bug, sondern normales, pro Gerät getrenntes GitHub-CLI-Verhalten.

Damit das so bleibt: keine Mac-mini-spezifischen absoluten Pfade hardcoden — immer os.path.expanduser("~/…") (Vorbild: Signal-Hub/src/pfade.py::LOKAL_MARKETS360), nie einen festen Benutzernamen-Pfad.