'use client'; import React, { useState, useMemo } from 'react'; import { useSandboxStore, ScannerAlert, WatchlistItem } from '@/lib/store'; import { calculateGJRGARCH } from '@/lib/math/statistics'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts'; import 'katex/dist/katex.min.css'; import { BlockMath, InlineMath } from 'react-katex'; import { ShieldAlert, Sparkles, RefreshCw, Flame, Search, Plus, Trash2, ChevronDown, ChevronUp, AlertTriangle, CheckCircle2, XCircle, Info, Clock, Play } from 'lucide-react'; // Predefined mock database for deep-check searches interface SearchResult { ticker: string; name: string; priceChange: number; sentiment: 'GREEN' | 'YELLOW' | 'RED'; whyDropped: string; gjrGarchVol: number; reboundScore: number; returns: number[]; } const mockSearchDatabase: Record = { 'RACE': { ticker: 'RACE', name: 'Ferrari N.V.', priceChange: -0.065, sentiment: 'GREEN', whyDropped: 'Emotionaler Abverkauf nach viralem Video von Cristiano Ronaldo, der sich über Autoprobleme beschwert. Keine fundamentalen Schäden.', gjrGarchVol: 0.048, reboundScore: 88, returns: [0.01, -0.005, 0.012, -0.008, 0.003, -0.065] }, 'KO': { ticker: 'KO', name: 'The Coca-Cola Co.', priceChange: -0.052, sentiment: 'GREEN', whyDropped: 'Berühmter Influencer entfernt Coca-Cola Flasche während Pressekonferenz. Reine Social-Media-Hype Reaktion.', gjrGarchVol: 0.021, reboundScore: 82, returns: [0.002, 0.005, -0.003, 0.001, -0.002, -0.052] }, 'TSLA': { ticker: 'TSLA', name: 'Tesla Inc.', priceChange: -0.084, sentiment: 'YELLOW', whyDropped: 'Auslieferungszahlen leicht unter Analystenschätzungen. Margenentwicklung bleibt jedoch stabil.', gjrGarchVol: 0.062, reboundScore: 65, returns: [-0.012, 0.008, -0.025, 0.015, -0.005, -0.084] }, 'SMCI': { ticker: 'SMCI', name: 'Super Micro Computer', priceChange: -0.124, sentiment: 'RED', whyDropped: 'Hindenburg Research Short-Seller-Report bezüglich mutmaßlicher Bilanzmanipulationen veröffentlicht.', gjrGarchVol: 0.085, reboundScore: 24, returns: [0.035, -0.018, 0.042, -0.051, 0.012, -0.124] }, 'BA': { ticker: 'BA', name: 'Boeing Co.', priceChange: -0.071, sentiment: 'RED', whyDropped: 'FAA verhängt vorübergehendes Flugverbot nach erneutem technischen Zwischenfall mit Rumpftür.', gjrGarchVol: 0.058, reboundScore: 18, returns: [-0.005, -0.012, 0.005, -0.021, -0.008, -0.071] }, 'NFLX': { ticker: 'NFLX', name: 'Netflix Inc.', priceChange: -0.058, sentiment: 'GREEN', whyDropped: 'Gerüchte über angebliche Preissenkungen in Schwellenländern belasten Kurs kurzfristig.', gjrGarchVol: 0.038, reboundScore: 78, returns: [0.015, -0.002, 0.008, 0.005, -0.011, -0.058] } }; export default function ScannerDemo() { const { watchlist, addToWatchlist, removeFromWatchlist, simulateWatchlistTick } = useSandboxStore(); // Component local states const [scanning, setScanning] = useState(false); const [scanProgress, setScanProgress] = useState(''); const [activeAlerts, setActiveAlerts] = useState([ { id: 'sa1', ticker: 'TSLA', priceChange: -0.084, gjrGarchVol: 0.062, overreactionScore: 65, status: 'UNDEREVALUATED' }, { id: 'sa2', ticker: 'SMCI', priceChange: -0.124, gjrGarchVol: 0.085, overreactionScore: 24, status: 'FAIR' }, ]); const [searchQuery, setSearchQuery] = useState(''); const [searchResult, setSearchResult] = useState(null); const [searchError, setSearchError] = useState(false); const [showMathAccordion, setShowMathAccordion] = useState(false); // Run market scan simulator const handleMarketScan = () => { setScanning(true); setScanProgress('Verbinde mit Börsenfeeds...'); setTimeout(() => { setScanProgress('Berechne historische Volatilitätsmatrizen...'); setTimeout(() => { setScanProgress('Filtere abnormale Abweichungen (Asset > -5%, Index stabil)...'); setTimeout(() => { // Scan isolated anomalies setActiveAlerts([ { id: 'sa3', ticker: 'RACE', priceChange: -0.065, gjrGarchVol: 0.048, overreactionScore: 88, status: 'UNDEREVALUATED' }, { id: 'sa4', ticker: 'KO', priceChange: -0.052, gjrGarchVol: 0.021, overreactionScore: 82, status: 'UNDEREVALUATED' }, { id: 'sa5', ticker: 'TSLA', priceChange: -0.084, gjrGarchVol: 0.062, overreactionScore: 65, status: 'UNDEREVALUATED' }, { id: 'sa6', ticker: 'SMCI', priceChange: -0.124, gjrGarchVol: 0.085, overreactionScore: 24, status: 'FAIR' }, { id: 'sa7', ticker: 'BA', priceChange: -0.071, gjrGarchVol: 0.058, overreactionScore: 18, status: 'OVERVALUATED' }, ]); setScanning(false); setScanProgress(''); }, 600); }, 500); }, 400); }; // Perform a manual deep check const handleDeepCheck = (e: React.FormEvent) => { e.preventDefault(); setSearchError(false); setSearchResult(null); const query = searchQuery.trim().toUpperCase(); if (!query) return; if (mockSearchDatabase[query]) { setSearchResult(mockSearchDatabase[query]); } else { // Simulate dynamic result for unknown assets const simulatedVol = 0.03 + Math.random() * 0.04; const simulatedScore = Math.floor(40 + Math.random() * 50); const isNegative = Math.random() > 0.4; const simulatedChange = -0.05 - Math.random() * 0.06; const res: SearchResult = { ticker: query, name: `${query} Corp.`, priceChange: simulatedChange, sentiment: isNegative ? (simulatedScore > 75 ? 'GREEN' : 'YELLOW') : 'RED', whyDropped: 'Simulierte Marktabweichung basierend auf automatischem Sentiment-Scanning der Finanzberichte.', gjrGarchVol: simulatedVol, reboundScore: simulatedScore, returns: [0.005, -0.008, 0.012, -0.015, 0.004, simulatedChange] }; setSearchResult(res); } }; const handleAddToWatchlist = (ticker: string, priceChange: number, sentiment: 'GREEN' | 'YELLOW' | 'RED', whyDropped: string) => { // Determine a mock initial price based on ticker let initialPrice = 150; if (ticker === 'RACE') initialPrice = 380; if (ticker === 'KO') initialPrice = 60; if (ticker === 'TSLA') initialPrice = 175; if (ticker === 'NFLX') initialPrice = 610; addToWatchlist({ ticker, priceChange, sentiment, whyDropped, initialPrice, currentPrice: initialPrice * (1 + priceChange), // current price after drop }); }; // Compute GJR-GARCH forecasting series for the math accordion/visual validation const gjrGarchMathResult = useMemo(() => { const mockReturns = [0.015, -0.022, 0.008, -0.031, 0.014, -0.055, 0.012, -0.008, 0.024, -0.065]; return calculateGJRGARCH(mockReturns); }, []); const mathChartData = useMemo(() => { return gjrGarchMathResult.series.map((vol, idx) => ({ day: `T-${gjrGarchMathResult.series.length - idx - 1}`, 'GJR-GARCH Vol (%)': parseFloat(vol.toFixed(2)), })); }, [gjrGarchMathResult]); return (
{/* SECTION 1: Overreaction Scan Action */}
Market Scanner Engine

Anomalien-Scanner & Marktverzerrungen

Isoliert Kursstürze > 5% bei relativem Gesamtmarkt-Stopp (S&P 500 driftet seitwärts oder steigt). Misst die Asymmetrie mittels GJR-GARCH, um Panik von strukturellen Risiken zu separieren.

{scanning && ( {scanProgress} )}
{/* Collapsible Math Accordion */}
{showMathAccordion && (

Das GJR-GARCH(1,1)-Modell erfasst die Asymmetrie im Volatilitätsprozess von Renditen. Es besitzt einen zusätzlichen Term (), der aktiviert wird, wenn der gestrige Schock negativ war.

Die Indikatorvariable nimmt den Wert 1 bei einem Kurssturz an:

Sind die Volatilitätsschocks asymmetrisch (), führt ein Kurssturz (Bad News) zu einer signifikant höheren Volatilität als ein gleich großer Kursgewinn (Good News).

Simulierter GJR-GARCH Volatilitätsprozess nach Schocks
Spike am Tag T-4 repräsentiert die asymmetrische Reaktion auf einen Schock von -6.5%.
)}
{/* SECTION 2: Scanned Anomalies & Sentiment Traffic Light */}
{/* Left 2 Columns: Scanned anomalies details */}

Gefundene Anomalien (Sentiment-Ampel)

{activeAlerts.map((alert) => { // Fetch associated info from mockDB if available, else generic mock const dbInfo = mockSearchDatabase[alert.ticker] || { name: `${alert.ticker} Corp.`, sentiment: alert.overreactionScore > 75 ? 'GREEN' : (alert.overreactionScore > 40 ? 'YELLOW' : 'RED'), whyDropped: 'Kurzfristige Eindeckungen und Gewinnmitnahmen an den Terminmärkten belasten das Sentiment.' }; const isGreen = dbInfo.sentiment === 'GREEN'; const isYellow = dbInfo.sentiment === 'YELLOW'; const isRed = dbInfo.sentiment === 'RED'; return (
{alert.ticker} ({dbInfo.name})
Kurssturz: {(alert.priceChange * 100).toFixed(1)}% | GJR-GARCH Vol: {(alert.gjrGarchVol * 100).toFixed(1)}%
{/* Traffic Light Sentiment Badge */}
{isGreen && ( EMOTIONALER OVERREACTION (KAUF) )} {isYellow && ( UNSICHERHEIT (HALTEN) )} {isRed && ( FUNDAMENTALER SCHADEN (MEIDEN) )}
{/* Analysis Block */}
KI-Ursachenanalyse:

„{dbInfo.whyDropped}“

{/* Actions & Score */}
Rebound Score {alert.overreactionScore}%
{(isGreen || isYellow) && ( )}
); })}
{/* Right Column: Deep-Check & Search Mask */}

Deep-Check Suchmaske

Suchen Sie gezielt nach Werten, um Anomalien-Analysen abzurufen. (z.B. RACE, KO, TSLA, SMCI, NFLX)

setSearchQuery(e.target.value)} />
{searchResult && (

{searchResult.ticker}

{searchResult.name}
{searchResult.sentiment === 'GREEN' && GREEN} {searchResult.sentiment === 'YELLOW' && YELLOW} {searchResult.sentiment === 'RED' && RED}
Aktueller Sturz: {(searchResult.priceChange * 100).toFixed(1)}%
GJR-GARCH Volatilität: {(searchResult.gjrGarchVol * 100).toFixed(1)}%
Rebound Score: {searchResult.reboundScore}/100
KI-Kommentar:

{searchResult.whyDropped}

{(searchResult.sentiment === 'GREEN' || searchResult.sentiment === 'YELLOW') && ( )}
)}
{/* SECTION 3: Hot Watchlist & Rebound-Tracker (48 Hours) */}

Hot Rebound Watchlist & Tracker (48h)

{watchlist.length > 0 && ( )}
{watchlist.length === 0 ? (
Bislang keine Assets auf der Rebound-Watchlist. Nutzen Sie die Markt-Scanergebnisse oben, um Werte hinzuzufügen.
) : (
{watchlist.map((item) => { const perf = item.reboundPerformance; const isPositive = perf >= 0; const progressPct = (item.hoursTracked / 48) * 100; return (
{item.ticker} {item.sentiment}
Gezogen bei: {(item.priceChange * 100).toFixed(1)}%
Rebound Performance
{isPositive ? '+' : ''}{perf.toFixed(2)}%
{/* Progress timeline */}
Tracking-Dauer: {item.hoursTracked}/48 Std. {Math.round(progressPct)}% abgeschlossen

Hintergrund: {item.whyDropped}

); })}
)}
); }