Closes #014 - System-wide handbook sweep, English consolidation & Crypto state persistence

This commit is contained in:
Antigravity Agent
2026-06-13 13:59:29 +02:00
parent f3c549e476
commit dc703e1bb8
18 changed files with 839 additions and 488 deletions

View File

@@ -122,3 +122,21 @@ This document tracks all modifications, npm packages, active compilation states,
### Active Bugs / Compile Status
* **Active Bugs**: None.
* **Type Checker Status**: Verified clean compilation (`npx tsc --noEmit` returns exit code 0).
---
## [2026-06-13] - System-Wide Handbook Sweep, English Consolidation & Crypto State Persistence (#ISSUE-014)
### Added
* **Sandbox Math Handbook**: Created `components/modules/sandbox/SandboxMathModal.tsx` detailing the Kelly Criterion, Half-Kelly safety buffers, percentage weightings (\(w_i\)), and synthetic portfolio returns (\(R_{pt}\)) in double-escaped BlockMath LaTeX.
* **Crypto Online Learning Loop**: Integrated a client-side background evaluation routine inside `components/modules/crypto/CryptoDemo.tsx` that resolves active forecasts against price histories from `/api/finance?region=crypto` and updates the Bayesian online calibration parameters.
### Modified
* **KaTeX Escaping & Close Handler Audit**: Standardized all 8 math handbook modals with Escape key listeners and glassmorphic floating top-right "X" buttons. Repaired all escaping sequences for KaTeX rendering strings across all components.
* **100% Institutional English Translation**: Swapped all remaining German UI texts, buttons (e.g. `📖 Modulerklärung` renamed to `📖 Quantitative Handbook`), table cells, and warnings to professional English across all tabs (`Smart Money`, `Events/Econometrics`, `Macro`, `Tech Silo`, `Sandbox`, `Scanner`).
* **Next.js SSR Hydration Safeguard**: Wrapped `localStorage` operations for `alphaSuccess`, `betaFailure`, and active forecasts inside a React `useEffect` hook in `CryptoDemo.tsx` to prevent hydration mismatches.
* **`QUANT_ROADMAP.md`**: Updated Section 1 and Section 4.VI detailing the Sandbox Portfolio and Kelly sizing formulations.
### Active Bugs / Compile Status
* **Active Bugs**: None.
* **Type Checker Status**: Verified clean compilation (`npx tsc --noEmit` returns exit code 0).

View File

@@ -197,6 +197,29 @@ $$P_{\text{Posterior}} = \frac{\alpha_{\text{prior}} + (P_{\text{ML}} \times w)}
---
### VI. Sandbox Portfolio Cockpit & Kelly Sizing
Integrates fractional betting algorithms and asset weight models inside the active Portfolio Sandbox environment.
#### 1. Active Portfolio Weighting ($w_i$)
Calculates the dynamic percentage value allocation of constituent assets:
$$w_i = \frac{\text{Shares}_i \times P_{\text{current}, i}}{\sum_{j} \text{Shares}_j \times P_{\text{current}, j}}$$
#### 2. Synthetic Portfolio Return ($R_{pt}$)
Simulates active log returns of the combined holdings:
$$R_{pt} = \sum_{i} w_i \times \ln\left(\frac{P_{t, i}}{P_{t-1, i}}\right)$$
#### 3. Theoretical Kelly Sizing ($f^*$)
Calculates the optimal size fraction to maximize the log growth of capital:
$$f^* = \frac{p \cdot b - (1 - p)}{b}$$
Where $p$ is the probability of success, and $b$ is the payout odds ratio (average win/average loss).
#### 4. Half-Kelly Safety Buffer Sizing
Applies a fractional buffer to lower estimation variance and protect against drawdowns:
$$f_{\text{applied}} = \max\left(0, 0.5 \times f^*\right)$$
---
## 5. Multi-Regime Transition Classifier
The core cognitive brain of the sandbox dynamically adjusts allocation weights across our portfolio modules based on estimated macroeconomic and market states.

View File

@@ -30,16 +30,16 @@ export default function Home() {
</div>
<div>
<h1 className="text-xl font-bold bg-gradient-to-r from-teal-400 via-sky-300 to-indigo-400 bg-clip-text text-transparent">
QuantSandbox &Ouml;konometrie
QuantSandbox Econometrics
</h1>
<p className="text-[10px] text-slate-400 uppercase tracking-widest font-mono">KI-gestützte Investment-Sandbox</p>
<p className="text-[10px] text-slate-400 uppercase tracking-widest font-mono">AI-Powered Investment Sandbox</p>
</div>
</div>
<div className="hidden md:flex items-center gap-6 text-xs text-slate-400">
<div className="flex items-center gap-2 border-r border-slate-800 pr-4">
<span className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
<span>Verbindung aktiv</span>
<span>Connection Active</span>
</div>
<div className="flex items-center gap-1.5 font-mono">
<span className="text-slate-500">Workspace:</span>
@@ -58,10 +58,10 @@ export default function Home() {
Scaffolding Version 1.0.0
</span>
<h2 className="text-3xl font-extrabold text-white tracking-tight sm:text-4xl">
Statistische Investment-Analyse & Sandbox
Statistical Investment Analysis & Sandbox
</h2>
<p className="text-slate-400 text-sm leading-relaxed">
Diese modulare Architektur bündelt fortgeschrittene &ouml;konometrische Modelle &ndash; von EWMA und GJR-GARCH Volatilit&auml;tsprognosen über Bayesianisches On-Chain-Lernen bis hin zu Überlebens- und LMM-Regressionsmodellen.
This modular architecture pools advanced econometric models &ndash; from EWMA and GJR-GARCH volatility forecasts to Bayesian on-chain learning, survival analysis, and LMM panel regressions.
</p>
</div>
@@ -88,13 +88,13 @@ export default function Home() {
onClick={() => setActiveTab('crypto')}
className={`flex-1 lg:flex-none px-4 py-2.5 rounded-xl text-xs font-semibold flex items-center justify-center gap-2 transition-all ${activeTab === 'crypto' ? 'bg-gradient-to-r from-cyan-500 to-sky-500 text-slate-950 font-bold shadow-lg shadow-cyan-500/25' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-900/50'}`}
>
<BarChart3 className="w-4 h-4" /> Krypto Bayes
<BarChart3 className="w-4 h-4" /> Crypto Bayes
</button>
<button
onClick={() => setActiveTab('events')}
className={`flex-1 lg:flex-none px-4 py-2.5 rounded-xl text-xs font-semibold flex items-center justify-center gap-2 transition-all ${activeTab === 'events' ? 'bg-gradient-to-r from-rose-500 to-pink-500 text-slate-950 font-bold shadow-lg shadow-rose-500/25' : 'text-slate-400 hover:text-slate-200 hover:bg-slate-900/50'}`}
>
<Landmark className="w-4 h-4" /> Ökonometrie
<Landmark className="w-4 h-4" /> Econometrics
</button>
<button
onClick={() => setActiveTab('macro')}
@@ -148,7 +148,7 @@ export default function Home() {
{/* Footer */}
<footer className="border-t border-slate-900 bg-slate-950/60 py-6 text-center text-xs text-slate-500 mt-auto">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col sm:flex-row justify-between items-center gap-4">
<p>&copy; 2026 QuantSandbox Inc. Alle Rechte vorbehalten.</p>
<p>&copy; 2026 QuantSandbox Inc. All rights reserved.</p>
<div className="flex items-center gap-4">
<span className="flex items-center gap-1"><RefreshCw className="w-3.5 h-3.5 text-teal-400 animate-spin-slow" /> Zustand State Engine</span>
<span>|</span>

View File

@@ -9,7 +9,7 @@ import CryptoMathModal from './CryptoMathModal';
import {
Cpu, Search, RefreshCw, BarChart2, TrendingUp, AlertCircle, Info,
ChevronDown, ChevronUp, ArrowUpRight, ArrowDownRight, Compass, ShieldAlert, Sparkles,
BookOpen
BookOpen, Check
} from 'lucide-react';
interface CoinData {
@@ -68,8 +68,26 @@ const defaultCoins: Record<string, CoinData> = {
}
};
interface Forecast {
id: string;
ticker: string;
predictedDirection: 'UP' | 'DOWN';
predictedProb: number;
entryPrice: number;
resolved: boolean;
result?: 'SUCCESS' | 'FAILURE';
timestamp: number;
targetTime: number;
}
export default function CryptoDemo() {
const { alphaSuccess, betaFailure, addModelTrial } = useSandboxStore();
const { addModelTrial } = useSandboxStore();
// Local state for alphaSuccess and betaFailure to satisfy SSR hydration safeguarding
const [alphaSuccess, setAlphaSuccess] = useState<number>(394);
const [betaFailure, setBetaFailure] = useState<number>(118);
const [forecasts, setForecasts] = useState<Forecast[]>([]);
const [learningLoopLog, setLearningLoopLog] = useState<string>('');
const [activeTicker, setActiveTicker] = useState<string>('BTC');
const [searchQuery, setSearchQuery] = useState('');
@@ -80,6 +98,166 @@ export default function CryptoDemo() {
const [simulatedTrialLogged, setSimulatedTrialLogged] = useState(false);
const [lastTrialSuccess, setLastTrialSuccess] = useState(false);
// Safely load counters and forecasts from localStorage on client mount
React.useEffect(() => {
const savedAlpha = localStorage.getItem('crypto_bayes_alpha');
const savedBeta = localStorage.getItem('crypto_bayes_beta');
const savedForecasts = localStorage.getItem('crypto_bayes_forecasts');
let loadedAlpha = 394;
let loadedBeta = 118;
if (savedAlpha !== null) {
loadedAlpha = parseInt(savedAlpha, 10);
setAlphaSuccess(loadedAlpha);
} else {
localStorage.setItem('crypto_bayes_alpha', '394');
}
if (savedBeta !== null) {
loadedBeta = parseInt(savedBeta, 10);
setBetaFailure(loadedBeta);
} else {
localStorage.setItem('crypto_bayes_beta', '118');
}
if (savedForecasts !== null) {
setForecasts(JSON.parse(savedForecasts));
} else {
const now = Date.now();
const mockForecasts: Forecast[] = [
{
id: 'mock-1',
ticker: 'BTC',
predictedDirection: 'UP',
predictedProb: 0.68,
entryPrice: 65000,
resolved: true,
result: 'SUCCESS',
timestamp: now - 86400 * 1000 * 3,
targetTime: now - 86400 * 1000 * 2,
},
{
id: 'mock-2',
ticker: 'ETH',
predictedDirection: 'DOWN',
predictedProb: 0.35,
entryPrice: 3950,
resolved: true,
result: 'SUCCESS',
timestamp: now - 86400 * 1000 * 3,
targetTime: now - 86400 * 1000 * 2,
},
{
id: 'mock-3',
ticker: 'SOL',
predictedDirection: 'UP',
predictedProb: 0.72,
entryPrice: 170,
resolved: true,
result: 'SUCCESS',
timestamp: now - 86400 * 1000 * 2,
targetTime: now - 86400 * 1000 * 1,
},
{
id: 'mock-4',
ticker: 'BTC',
predictedDirection: 'UP',
predictedProb: 0.62,
entryPrice: 71000,
resolved: true,
result: 'FAILURE',
timestamp: now - 86400 * 1000 * 2,
targetTime: now - 86400 * 1000 * 1,
},
{
id: 'mock-5',
ticker: 'ETH',
predictedDirection: 'UP',
predictedProb: 0.58,
entryPrice: 3900,
resolved: true,
result: 'FAILURE',
timestamp: now - 86400 * 1000 * 2,
targetTime: now - 86400 * 1000 * 1,
}
];
setForecasts(mockForecasts);
localStorage.setItem('crypto_bayes_forecasts', JSON.stringify(mockForecasts));
}
}, []);
// Client-side background learning loop evaluating forecasts against actual live returns
React.useEffect(() => {
const runLearningLoop = async () => {
try {
const res = await fetch('/api/finance?region=crypto');
if (!res.ok) return;
const data = await res.ok ? await res.json() : { results: [] };
const results = data.results || [];
const pricesMap: Record<string, number> = {};
results.forEach((r: any) => {
pricesMap[r.ticker] = r.currentPrice;
const cleanTicker = r.ticker.replace('-USD', '');
pricesMap[cleanTicker] = r.currentPrice;
});
let updatedAny = false;
let newAlpha = alphaSuccess;
let newBeta = betaFailure;
const updatedForecasts = forecasts.map((f) => {
if (f.resolved) return f;
const currentPrice = pricesMap[f.ticker] || pricesMap[`${f.ticker}-USD`];
if (!currentPrice) return f;
const now = Date.now();
if (now >= f.targetTime) {
const priceWentUp = currentPrice > f.entryPrice;
const success = (f.predictedDirection === 'UP' && priceWentUp) || (f.predictedDirection === 'DOWN' && !priceWentUp);
updatedAny = true;
if (success) {
newAlpha += 1;
} else {
newBeta += 1;
}
addModelTrial(success);
return {
...f,
resolved: true,
result: success ? ('SUCCESS' as const) : ('FAILURE' as const)
};
}
return f;
});
if (updatedAny) {
setAlphaSuccess(newAlpha);
setBetaFailure(newBeta);
setForecasts(updatedForecasts);
localStorage.setItem('crypto_bayes_alpha', String(newAlpha));
localStorage.setItem('crypto_bayes_beta', String(newBeta));
localStorage.setItem('crypto_bayes_forecasts', JSON.stringify(updatedForecasts));
setLearningLoopLog(`Processed active forecasts. New successes: ${newAlpha}, New failures: ${newBeta}`);
setTimeout(() => setLearningLoopLog(''), 6000);
}
} catch (err) {
console.error("Learning loop evaluation error:", err);
}
};
if (forecasts.length > 0) {
runLearningLoop();
}
const interval = setInterval(runLearningLoop, 30000);
return () => clearInterval(interval);
}, [forecasts, alphaSuccess, betaFailure, addModelTrial]);
// Active Coin data retrieval
const activeCoin = useMemo(() => {
return customCoins[activeTicker] || defaultCoins[activeTicker] || defaultCoins['BTC'];
@@ -98,14 +276,12 @@ export default function CryptoDemo() {
// Apply Bayesian online learning error-correction posterior update
const correctedPredictions = useMemo(() => {
// Correct short term probability
const shortTermCorrected = calculateBetaPosterior(
alphaSuccess,
betaFailure,
mlPredictions.shortTermProb,
12 // pseudo weight/confidence scale
12 // confidence scale
);
// Correct medium term probability
const mediumTermCorrected = calculateBetaPosterior(
alphaSuccess,
betaFailure,
@@ -119,7 +295,7 @@ export default function CryptoDemo() {
};
}, [mlPredictions, alphaSuccess, betaFailure]);
// Perform search check for Altcoins
// Search/add new altcoin
const handleAltcoinSearch = (e: React.FormEvent) => {
e.preventDefault();
setSearchError(false);
@@ -138,7 +314,6 @@ export default function CryptoDemo() {
return;
}
// Generate simulated data for Altcoin
const isBull = Math.random() > 0.45;
const simulatedChange = isBull ? 3 + Math.random() * 8 : -2 - Math.random() * 6;
const simulatedPrice = isBull ? 2 + Math.random() * 10 : 0.2 + Math.random() * 3;
@@ -162,8 +337,44 @@ export default function CryptoDemo() {
setSearchQuery('');
};
// Manual logging of active forecast
const handleLogManualForecast = () => {
const entryPrice = parseFloat(activeCoin.price.replace(/[^0-9.]/g, ''));
const predictedDirection = correctedPredictions.shortTerm > 0.5 ? 'UP' : 'DOWN';
const predictedProb = correctedPredictions.shortTerm;
const newForecast: Forecast = {
id: 'fc-' + Date.now(),
ticker: activeCoin.ticker,
predictedDirection,
predictedProb,
entryPrice,
resolved: false,
timestamp: Date.now(),
targetTime: Date.now() + 60 * 1000 // resolves in 60s for direct visual validation
};
const nextForecasts = [newForecast, ...forecasts];
setForecasts(nextForecasts);
localStorage.setItem('crypto_bayes_forecasts', JSON.stringify(nextForecasts));
setLearningLoopLog(`Registered active forecast for ${activeCoin.ticker} at $${entryPrice}. Evaluating returns in 60 seconds.`);
setTimeout(() => setLearningLoopLog(''), 6000);
};
// Simulator for calibration
const handleSimulateTrial = (success: boolean) => {
addModelTrial(success);
setAlphaSuccess(prev => {
const next = success ? prev + 1 : prev;
localStorage.setItem('crypto_bayes_alpha', String(next));
return next;
});
setBetaFailure(prev => {
const next = !success ? prev + 1 : prev;
localStorage.setItem('crypto_bayes_beta', String(next));
return next;
});
setLastTrialSuccess(success);
setSimulatedTrialLogged(true);
setTimeout(() => setSimulatedTrialLogged(false), 2500);
@@ -179,9 +390,9 @@ export default function CryptoDemo() {
{/* Header */}
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4 border-b border-slate-800 pb-4 mb-6">
<div>
<span className="text-cyan-400 text-xs font-semibold uppercase tracking-wider">Element 4</span>
<span className="text-cyan-400 text-xs font-semibold uppercase tracking-wider">Level 4</span>
<h2 className="text-2xl font-bold bg-gradient-to-r from-cyan-400 to-sky-200 bg-clip-text text-transparent">
Predictive Krypto-Modelle & Bayes Self-Correction
Predictive Crypto Models & Bayes Self-Correction
</h2>
</div>
<div className="flex flex-wrap items-center gap-3">
@@ -195,13 +406,13 @@ export default function CryptoDemo() {
className="flex items-center gap-1.5 px-4 py-2 rounded-xl bg-slate-950/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-cyan-400 justify-center h-11"
>
<BookOpen className="w-3.5 h-3.5" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
<div className="bg-slate-900 border border-slate-800 rounded-xl px-4 py-2 flex items-center gap-3 h-11">
<Cpu className="text-cyan-400 w-5 h-5 animate-spin-slow" />
<div>
<p className="text-slate-400 text-xs">A-Priori Genauigkeit</p>
<p className="text-slate-400 text-xs">Prior Accuracy</p>
<p className="font-mono text-sm font-bold text-cyan-400">
{priorAccuracy.toFixed(1)}% (n={totalTrials})
</p>
@@ -245,7 +456,7 @@ export default function CryptoDemo() {
<input
type="text"
required
placeholder="Altcoin Ticker (z.B. LINK)"
placeholder="Altcoin Ticker (e.g. LINK)"
className="bg-slate-900 border border-slate-800 rounded-lg p-2 flex-1 text-slate-100 font-mono text-xs uppercase focus:outline-none focus:border-cyan-500"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
@@ -279,14 +490,14 @@ export default function CryptoDemo() {
{/* Left Column: Metrics Widgets */}
<div className="xl:col-span-2 space-y-6">
<h3 className="text-base font-bold text-white flex items-center gap-2 border-b border-slate-800 pb-3">
<BarChart2 className="text-cyan-400 w-5 h-5" /> On-Chain &amp; Derivate-Indikatoren ({activeCoin.ticker})
<BarChart2 className="text-cyan-400 w-5 h-5" /> On-Chain &amp; Derivative Indicators ({activeCoin.ticker})
</h3>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Funding & Open Interest Widget */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/40 space-y-3">
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Ref-Zinssatz &amp; Kontrakte (OI)</h4>
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Funding Rates &amp; Open Interest</h4>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-mono">
<span className="text-slate-400 text-xs">Daily Funding Rate:</span>
@@ -305,14 +516,14 @@ export default function CryptoDemo() {
{/* Long/Short & Liquidation Widget */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/40 space-y-3">
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Positionierung &amp; Liquidationen</h4>
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Positioning &amp; Liquidations</h4>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-mono">
<span className="text-slate-400 text-xs">Long / Short Ratio:</span>
<span className="text-slate-200 font-bold">{activeCoin.longShortRatio}</span>
</div>
<div className="flex justify-between items-center text-xs font-mono">
<span className="text-slate-400">Liq-Cluster:</span>
<span className="text-slate-400">Liq Cluster:</span>
<span className="text-rose-400">Long: {activeCoin.liqLong} | Short: {activeCoin.liqShort}</span>
</div>
</div>
@@ -320,32 +531,32 @@ export default function CryptoDemo() {
{/* Whale Flows Widget */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/40 space-y-3">
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Whale-Ströme (Nettozufluss)</h4>
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Whale Flows (Net Inflow)</h4>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-mono">
<span className="text-slate-400 text-xs">Netto Inflow (Wallets):</span>
<span className="text-slate-400 text-xs">Net Inflow (Wallets):</span>
<span className={`font-bold ${activeCoin.whaleInflow >= 0 ? 'text-emerald-400' : 'text-rose-400'}`}>
{activeCoin.whaleInflow > 0 ? '+' : ''}{activeCoin.whaleInflow} {activeCoin.ticker}
</span>
</div>
<div className="text-[10px] text-slate-500 leading-relaxed font-sans">
Positive Werte signalisieren, dass Großinvestoren Bestände von Börsen auf private Wallets (Akkumulation) abziehen.
Positive values signal that large investors are withdrawing assets from exchanges to private wallets (accumulation).
</div>
</div>
</div>
{/* Exchange Reserves Widget */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/40 space-y-3">
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Börsenreserven (Spot)</h4>
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Exchange Reserves (Spot)</h4>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm font-mono">
<span className="text-slate-400 text-xs">Reservenänderung (7d):</span>
<span className="text-slate-400 text-xs">Reserve Change (7d):</span>
<span className={`font-bold ${activeCoin.exchangeReserves <= 0 ? 'text-emerald-400' : 'text-rose-400'}`}>
{activeCoin.exchangeReserves > 0 ? '+' : ''}{activeCoin.exchangeReserves}%
</span>
</div>
<div className="text-[10px] text-slate-500 leading-relaxed font-sans">
Sinkende Reserven an den Spot-Börsen reduzieren den verfügbaren Verkaufsdruck und begünstigen Squeezes.
Falling reserves at spot exchanges reduce available selling pressure and favor squeezes.
</div>
</div>
</div>
@@ -356,7 +567,7 @@ export default function CryptoDemo() {
{/* Right Column: Predictive Gauges & Correction Calibration */}
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-6">
<h3 className="text-base font-bold text-white flex items-center gap-2 border-b border-slate-800 pb-3">
<Compass className="text-cyan-400 w-5 h-5" /> Vorhersage-Wahrscheinlichkeiten
<Compass className="text-cyan-400 w-5 h-5" /> Prediction Probabilities
</h3>
{/* Gauges / Progress Bars */}
@@ -369,27 +580,25 @@ export default function CryptoDemo() {
<span className="text-cyan-400 font-mono">{(correctedPredictions.shortTerm * 100).toFixed(0)}%</span>
</div>
<div className="w-full bg-slate-950 rounded-full h-3 overflow-hidden border border-slate-850 flex">
{/* ML Baseline Overlay */}
<div
className="bg-cyan-500 h-full rounded-l transition-all duration-500 opacity-30"
style={{ width: `${mlPredictions.shortTermProb * 100}%` }}
/>
{/* Corrected Posterior Marker */}
<div
className="bg-cyan-400 h-full rounded-r transition-all duration-500 -ml-[20%] shadow-[0_0_10px_rgba(34,211,238,0.5)]"
style={{ width: `${correctedPredictions.shortTerm * 100}%` }}
/>
</div>
<div className="flex justify-between text-[9px] text-slate-500 font-mono">
<span>ML-Signal: {(mlPredictions.shortTermProb * 100).toFixed(0)}%</span>
<span className="text-cyan-400">Bayes-Korrigiert: {(correctedPredictions.shortTerm * 100).toFixed(0)}%</span>
<span>ML Signal: {(mlPredictions.shortTermProb * 100).toFixed(0)}%</span>
<span className="text-cyan-400">Bayes Corrected: {(correctedPredictions.shortTerm * 100).toFixed(0)}%</span>
</div>
</div>
{/* 14d Gauge */}
<div className="space-y-2">
<div className="flex justify-between text-xs font-semibold">
<span className="text-slate-300">14d Struktureller Bullish-Trend (Medium-Term)</span>
<span className="text-slate-300">14d Structural Bullish Trend (Medium-Term)</span>
<span className="text-teal-400 font-mono">{(correctedPredictions.mediumTerm * 100).toFixed(0)}%</span>
</div>
<div className="w-full bg-slate-950 rounded-full h-3 overflow-hidden border border-slate-850 flex">
@@ -403,8 +612,8 @@ export default function CryptoDemo() {
/>
</div>
<div className="flex justify-between text-[9px] text-slate-500 font-mono">
<span>ML-Signal: {(mlPredictions.mediumTermProb * 100).toFixed(0)}%</span>
<span className="text-teal-400">Bayes-Korrigiert: {(correctedPredictions.mediumTerm * 100).toFixed(0)}%</span>
<span>ML Signal: {(mlPredictions.mediumTermProb * 100).toFixed(0)}%</span>
<span className="text-teal-400">Bayes Corrected: {(correctedPredictions.mediumTerm * 100).toFixed(0)}%</span>
</div>
</div>
@@ -413,88 +622,161 @@ export default function CryptoDemo() {
{/* Model Calibration Log & Simulation */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/40 space-y-3">
<div className="flex items-center justify-between">
<h4 className="text-xs font-bold text-slate-300 uppercase">Bayes Modell-Kalibrierung</h4>
<h4 className="text-xs font-bold text-slate-300 uppercase">Bayes Model Calibration</h4>
<span className="text-[10px] text-slate-500 font-mono">n = {totalTrials} Trials</span>
</div>
<div className="grid grid-cols-2 gap-2 text-xs font-mono pb-2 border-b border-slate-900">
<div className="text-slate-400">Erfolge (&alpha;):</div>
<div className="text-slate-400">Successes (&alpha;):</div>
<div className="text-emerald-400 font-bold">{alphaSuccess}</div>
<div className="text-slate-400">Fehlalarme (&beta;):</div>
<div className="text-slate-400">False Alarms (&beta;):</div>
<div className="text-rose-400 font-bold">{betaFailure}</div>
</div>
{/* Trial simulator */}
<div className="space-y-2">
<p className="text-[10px] text-slate-400">Modell-Drift simulieren: Fügen Sie richtige/falsche Outcomes hinzu, um die Beta-Verteilung anzupassen.</p>
<p className="text-[10px] text-slate-400">Simulate model drift: Add correct/false outcomes to calibrate the Beta distribution.</p>
<div className="flex gap-2">
<button
onClick={() => handleSimulateTrial(true)}
className="flex-1 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 border border-emerald-500/20 py-1.5 rounded-lg text-xs font-semibold font-mono"
>
+1 Erfolg
+1 Success
</button>
<button
onClick={() => handleSimulateTrial(false)}
className="flex-1 bg-rose-500/10 hover:bg-rose-500/20 text-rose-400 border border-rose-500/20 py-1.5 rounded-lg text-xs font-semibold font-mono"
>
+1 Fehlalarm
+1 False Alarm
</button>
</div>
{simulatedTrialLogged && (
<div className="text-[10px] text-cyan-400 font-mono text-center animate-pulse">
Trial geloggt! Bayes-Prior wurde auf {lastTrialSuccess ? 'Erfolg' : 'Fehlalarm'} aktualisiert.
Trial logged! Bayes prior updated to {lastTrialSuccess ? 'Success' : 'False Alarm'}.
</div>
)}
</div>
</div>
</div>
</div>
{/* SECTION 3: Mathematical LaTeX Accordion */}
{/* SECTION 3: Active Forecasts (Feedback Loop) */}
<div className="grid grid-cols-1 xl:grid-cols-3 gap-8 mt-6">
<div className="xl:col-span-2 bg-slate-950/30 rounded-xl p-4 border border-slate-850 space-y-4">
<div className="flex justify-between items-center border-b border-slate-800 pb-3">
<h3 className="text-sm font-bold text-white flex items-center gap-2">
<TrendingUp className="text-cyan-400 w-4 h-4" /> Active Learning Feedback Loop
</h3>
<button
onClick={handleLogManualForecast}
className="bg-cyan-500 hover:bg-cyan-600 text-slate-950 font-bold py-1.5 px-3 rounded-lg text-xs transition-all active:scale-[0.96]"
>
Log Forecast to Feedback Loop
</button>
</div>
{learningLoopLog && (
<div className="p-3 bg-cyan-950/20 border border-cyan-900/40 rounded-lg text-xs text-cyan-300 flex items-center gap-2">
<Info className="w-4 h-4 shrink-0" />
<span>{learningLoopLog}</span>
</div>
)}
<div className="overflow-x-auto max-h-56 scrollbar-thin">
<table className="w-full border-collapse text-left text-xs font-mono">
<thead>
<tr className="border-b border-slate-800 text-slate-400 font-semibold bg-slate-900/40">
<th className="p-2">Ticker</th>
<th className="p-2">Direction</th>
<th className="p-2">Probability</th>
<th className="p-2">Entry Price</th>
<th className="p-2">Status</th>
<th className="p-2 text-right">Result</th>
</tr>
</thead>
<tbody>
{forecasts.length === 0 ? (
<tr>
<td colSpan={6} className="p-4 text-center text-slate-500 italic">No forecasts registered yet.</td>
</tr>
) : (
forecasts.map((fc) => (
<tr key={fc.id} className="border-b border-slate-900 hover:bg-slate-850/10">
<td className="p-2 text-slate-200 font-bold">{fc.ticker}</td>
<td className="p-2">
<span className={`px-1.5 py-0.5 rounded text-[10px] font-bold ${fc.predictedDirection === 'UP' ? 'bg-emerald-500/10 text-emerald-400' : 'bg-rose-500/10 text-rose-400'}`}>
{fc.predictedDirection}
</span>
</td>
<td className="p-2 text-slate-350">{(fc.predictedProb * 100).toFixed(0)}%</td>
<td className="p-2 text-slate-300">${fc.entryPrice.toLocaleString()}</td>
<td className="p-2 text-slate-400">{fc.resolved ? 'RESOLVED' : 'PENDING'}</td>
<td className={`p-2 text-right font-bold ${fc.result === 'SUCCESS' ? 'text-emerald-400' : fc.result === 'FAILURE' ? 'text-rose-400' : 'text-slate-500'}`}>
{fc.result || '-'}
</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
{/* Informational overlay */}
<div className="bg-slate-950/40 rounded-xl p-4 border border-slate-850 text-xs text-slate-400 space-y-2">
<h4 className="font-bold text-slate-300 uppercase">Econometric Feedback Loop Spec</h4>
<p className="leading-relaxed">
The learning loop automatically evaluates active forecast parameters in the background against actual price histories returned by <code className="text-cyan-400 font-mono">/api/finance?region=crypto</code>.
</p>
<p className="leading-relaxed">
When a logged forecast passes its evaluation target timestamp, it resolves against live market data, updating the Bayesian online calibration metrics <InlineMath math="\alpha" /> and <InlineMath math="\beta" />.
</p>
</div>
</div>
{/* SECTION 4: Mathematical LaTeX Accordion */}
<div className="border-t border-slate-850 pt-4 mt-6">
<button
onClick={() => setShowMathAccordion(!showMathAccordion)}
className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-cyan-400 transition-colors focus:outline-none"
>
<span>{showMathAccordion ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}</span>
<span className="font-semibold uppercase tracking-wider">Mathematische Formulierung (Beta-Update &amp; Random Forest)</span>
<span className="font-semibold uppercase tracking-wider">Mathematical Formulation (Beta Update &amp; Random Forest)</span>
</button>
{showMathAccordion && (
<div className="mt-4 p-4 rounded-xl border border-slate-850 bg-slate-950/40 text-xs text-slate-300 space-y-4">
<div>
<h4 className="font-bold text-cyan-400 mb-1">1. Bayesianische Beta-Konjugierte Fehlerkorrektur</h4>
<h4 className="font-bold text-cyan-400 mb-1">1. Bayesian Beta-Conjugate Error Correction</h4>
<p className="mb-2">
Wir modellieren das Vertrauensintervall über die Fehlerraten des Modells mittels einer Beta-Verteilung. Der A-Priori Fehlerzustand wird durch die Parameter <InlineMath math="\alpha" /> (Erfolge) und <InlineMath math="\beta" /> (Fehlalarme) dargestellt:
We model the error rate confidence interval of the model using a Beta distribution. The prior error state is represented by the parameters <InlineMath math="\alpha" /> (Successes) and <InlineMath math="\beta" /> (False Alarms):
</p>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="P \sim \text{Beta}(\alpha, \beta) \quad \text{mit Erwartungswert } \mathbb{E}[P] = \frac{\alpha}{\alpha + \beta}" />
<BlockMath math="P \\sim \\text{Beta}(\\alpha, \\beta) \\quad \\text{with expected value } \\mathbb{E}[P] = \\frac{\\alpha}{\\alpha + \\beta}" />
</div>
<p className="mb-2">
Bei einem neuen ML-Signal <InlineMath math="P_{\text{ML}}" /> führen wir ein konjugiertes Bayes-Update mit einem Vertrauensgewicht <InlineMath math="w" /> aus:
With a new ML signal <InlineMath math="P_{\\text{ML}}" />, we perform a conjugate Bayes update with a confidence weight <InlineMath math="w" />:
</p>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="\alpha_{\text{post}} = \alpha + w \cdot P_{\text{ML}}, \quad \beta_{\text{post}} = \beta + w \cdot (1 - P_{\text{ML}})" />
<BlockMath math="\\alpha_{\\text{post}} = \\alpha + w \\cdot P_{\\text{ML}}, \\quad \\beta_{\\text{post}} = \\beta + w \\cdot (1 - P_{\\text{ML}})" />
</div>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="P_{\text{Posterior}} = \frac{\alpha_{\text{post}}}{\alpha_{\text{post}} + \beta_{\text{post}}}" />
<BlockMath math="P_{\\text{Posterior}} = \\frac{\\alpha_{\\text{post}}}{\\alpha_{\\text{post}} + \\beta_{\\text{post}}}" />
</div>
<p className="text-slate-400">
Ist das Modell historisch sehr instabil (hohes <InlineMath math="\beta" />), korrigiert der Bayesianische Term ein übermütiges ML-Signal nach unten, was die Robustheit des Gesamtsystems schützt.
If the model is historically highly unstable (high <InlineMath math="\\beta" />), the Bayesian term corrects an overconfident ML signal downwards, safeguarding the robustness of the system.
</p>
</div>
<div className="border-t border-slate-900 pt-3">
<h4 className="font-bold text-cyan-400 mb-1">2. Random Forest Nicht-Lineares Signalmapping</h4>
<h4 className="font-bold text-cyan-400 mb-1">2. Random Forest Non-Linear Signal Mapping</h4>
<p className="mb-2">
Der Random Forest simuliert ein Ensemble von 10 schwachen Entscheidungsbäumen. Jeder Baum spaltet die Daten nach Schwellenwerten (z.B. &bdquo;Funding-Rate &lt; -0.04%&ldquo; und &bdquo;Open Interest &gt; 10%&ldquo;) auf:
The Random Forest simulates an ensemble of 10 weak decision trees. Each tree splits the data based on threshold criteria (e.g., 'Funding Rate &lt; -0.04%' and 'Open Interest &gt; 10%'):
</p>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="\text{ML}_{\text{prob}} = \frac{1}{M} \sum_{m=1}^{M} T_m(\mathbf{x})" />
<BlockMath math="\\text{ML}_{\\text{prob}} = \\frac{1}{M} \\sum_{m=1}^{M} T_m(\\mathbf{x})" />
</div>
<p className="text-slate-400">
wobei <InlineMath math="T_m(\mathbf{x})" /> der prognostizierte Ausgabewert des <InlineMath math="m" />-ten Entscheidungsbaumes r den Featurevektor <InlineMath math="\mathbf{x}" /> ist.
where <InlineMath math="T_m(\\mathbf{x})" /> is the predicted output value of the <InlineMath math="m" />-th decision tree for the feature vector <InlineMath math="\\mathbf{x}" />.
</p>
</div>
</div>

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { BookOpen } from 'lucide-react';
import { BookOpen, X } from 'lucide-react';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
@@ -26,8 +26,8 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/85 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-300">
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-955/90 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-350">
{/* Modal Header */}
<div className="flex justify-between items-center px-6 py-4 bg-slate-950/40 border-b border-slate-800/60">
@@ -39,9 +39,10 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
</div>
<button
onClick={onClose}
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 px-3 py-1.5 rounded-lg text-xs font-semibold font-mono transition-all cursor-pointer"
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 p-2 rounded-xl transition-all cursor-pointer flex items-center justify-center"
aria-label="Close modal"
>
Schließen (ESC)
<X className="w-4 h-4" />
</button>
</div>
@@ -69,10 +70,10 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
<div className="space-y-3">
<h4 className="text-xs font-bold text-rose-400 uppercase tracking-wider font-mono">B. Endogenous Calibration</h4>
<p className="text-xs leading-relaxed text-slate-400">
Active future matrix cells pre-fill suggested scores by looking up the corresponding historical LMM coefficient <InlineMath math="\beta_{asset\_event\_post}" /> and scaling it to our native score scale:
Active future matrix cells pre-fill suggested scores by looking up the corresponding historical LMM coefficient <InlineMath math="\\beta_{\\text{asset}\\_\\text{event}\\_\\text{post}}" /> and scaling it to our native score scale:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="\text{Score}_{\text{suggested}} = \max\left(-3, \min\left(3, \text{Round}(\beta_{\text{estimate}} \times 100)\right)\right)" />
<BlockMath math="\\text{Score}_{\\text{suggested}} = \\max\\left(-3, \\min\\left(3, \\text{Round}(\\beta_{\\text{estimate}} \\times 100)\\right)\\right)" />
</div>
</div>
@@ -82,13 +83,17 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
The engine estimates direct event drift and impact returns, isolating asset-level intercepts as random deviances and purging macro volatility using VIX indices:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="Y_{it} = X_{it}\beta + Z_{it}b_i + \varepsilon_{it}" />
<BlockMath math="Y_{it} = X_{it}\\beta + Z_{it}b_i + \\varepsilon_{it}" />
<p className="text-[11px] text-slate-400 mt-2 font-mono leading-relaxed">
Where:<br/>
- <InlineMath math="Y_{it}" /> is the log-return <InlineMath math="\ln(P_t/P_0)" /> of asset <InlineMath math="i" /> at relative index <InlineMath math="t \in [-30, 30]" />.<br/>
- <InlineMath math="X_{it}" /> design matrix elements isolate Pre-Event Drift (<InlineMath math="t < 0" />) and Post-Event Impact (<InlineMath math="t \ge 0" />) while controlling for systemic covariates (VIX).<br/>
- <InlineMath math="b_i \sim N(0, \sigma_b^2)" /> random intercept captures unique baseline asset variance.<br/>
- <InlineMath math="\varepsilon_{it} \sim N(0, \sigma^2)" /> residuals noise.
{"Where:"}
<br />
{"- "}<InlineMath math="Y_{it}" />{" is the log-return "}<InlineMath math="\\ln(P_t/P_0)" />{" of asset "}<InlineMath math="i" />{" at relative index "}<InlineMath math="t \\in [-30, 30]" />{"."}
<br />
{"- "}<InlineMath math="X_{it}" />{" design matrix elements isolate Pre-Event Drift ("}<InlineMath math="t < 0" />{") and Post-Event Impact ("}<InlineMath math="t \\ge 0" />{") while controlling for systemic covariates (VIX)."}
<br />
{"- "}<InlineMath math="b_i \\sim N(0, \\sigma_b^2)" />{" random intercept captures unique baseline asset variance."}
<br />
{"- "}<InlineMath math="\\varepsilon_{it} \\sim N(0, \\sigma^2)" />{" residuals noise."}
</p>
</div>
</div>
@@ -101,15 +106,15 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">Logistic Probability Projection:</p>
<BlockMath math="P(\text{Bullish}) = \frac{1}{1 + e^{-\text{Score}}}" />
<BlockMath math="P(\\text{Bullish}) = \\frac{1}{1 + e^{-\\text{Score}}}" />
</div>
<div>
<p className="text-xs text-slate-400 mb-1">Optimal Youden Index (J):</p>
<BlockMath math="J = \text{Sensitivity} + \text{Specificity} - 1 = \text{TPR} + (1 - \text{FPR}) - 1" />
<BlockMath math="J = \\text{Sensitivity} + \\text{Specificity} - 1 = \\text{TPR} + (1 - \\text{FPR}) - 1" />
</div>
<div>
<p className="text-xs text-slate-400 mb-1">Inverting probability optimal threshold <InlineMath math="P^*" /> back to native score <InlineMath math="S^*" /> via Logit:</p>
<BlockMath math="S^* = \ln\left(\frac{P^*}{1 - P^*}\right)" />
<p className="text-xs text-slate-400 mb-1">{"Inverting probability optimal threshold "}<InlineMath math="P^*" />{" back to native score "}<InlineMath math="S^*" />{" via Logit:"}</p>
<BlockMath math="S^* = \\ln\\left(\\frac{P^*}{1 - P^*}\\right)" />
</div>
</div>
</div>
@@ -121,16 +126,18 @@ export default function EconometricsMathModal({ isOpen, onClose }: EconometricsM
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<BlockMath math="\hat{S}(t) = \prod_{t_i \le t} \left(1 - \frac{d_i}{n_i}\right)" />
<p className="text-[11px] text-slate-400 mt-2 font-mono">
Where:<br/>
- <InlineMath math="n_i" /> is the number of active asset-run observations at risk at day <InlineMath math="t" />.<br/>
- <InlineMath math="d_i" /> is the number of trend-reversal events recorded on day <InlineMath math="t" />.
<BlockMath math="\\hat{S}(t) = \\prod_{t_i \\le t} \\left(1 - \\frac{d_i}{n_i}\\right)" />
<p className="text-[11px] text-slate-400 mt-2 font-mono leading-relaxed">
{"Where:"}
<br />
{"- "}<InlineMath math="n_i" />{" is the number of active asset-run observations at risk at day "}<InlineMath math="t" />{"."}
<br />
{"- "}<InlineMath math="d_i" />{" is the number of trend-reversal events recorded on day "}<InlineMath math="t" />{"."}
</p>
</div>
<div>
<p className="text-xs text-slate-400 mb-1">Reversal trigger with 1% Volatility Buffer:</p>
<BlockMath math="\text{Sign}(\text{Score}) \times \text{Return} \le -0.01" />
<BlockMath math="\\text{Sign}(\\text{Score}) \\times \\text{Return} \\le -0.01" />
</div>
</div>
</div>

View File

@@ -43,20 +43,20 @@ import {
// Predefined archetypes for Event Creation
const ARCHETYPES: Record<string, { name: string; defaultScores: Record<string, number> }> = {
'🏦 Fed-Zinsentscheid (FOMC)': {
name: 'Fed-Zinsentscheid (FOMC)',
'🏦 Fed Rate Decision (FOMC)': {
name: 'Fed Rate Decision (FOMC)',
defaultScores: { Apple: 1, NASDAQ: 2, Gold: -1, Bitcoin: 2 }
},
'📈 US-Inflationsdaten (CPI)': {
name: 'US-Inflationsdaten (CPI)',
'📈 US Inflation Data (CPI)': {
name: 'US Inflation Data (CPI)',
defaultScores: { Apple: 1, NASDAQ: 2, Gold: -2, Bitcoin: 1 }
},
'💼 Non-Farm Payrolls (NFP)': {
name: 'Non-Farm Payrolls (NFP)',
defaultScores: { Apple: 0, NASDAQ: 1, Gold: -1, Bitcoin: 0 }
},
'🛒 OPEC-Treffen': {
name: 'OPEC-Treffen',
'🛒 OPEC Meeting': {
name: 'OPEC Meeting',
defaultScores: { Apple: -1, NASDAQ: -1, Gold: 2, Bitcoin: 1 }
}
};
@@ -258,7 +258,6 @@ export default function EventsDemo() {
// Custom Event Form State
const [customName, setCustomName] = useState<string>('');
const [customDate, setCustomDate] = useState<string>('2026-06-15');
const [selectedArchetype, setSelectedArchetype] = useState<string>('Custom');
@@ -522,7 +521,7 @@ export default function EventsDemo() {
scores[asset.name] = typeof arch.defaultScores[asset.name] === 'number' ? arch.defaultScores[asset.name] : 0;
});
} else {
name = name || 'Benutzerdefiniertes Ereignis';
name = name || 'Custom Event';
}
addEventToMatrix(name, customDate, scores);
@@ -608,7 +607,7 @@ export default function EventsDemo() {
className="flex items-center gap-1.5 px-3 py-2 rounded-lg bg-slate-950/80 hover:bg-slate-905 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-rose-400"
>
<BookOpen className="w-3.5 h-3.5" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
</div>
</div>
@@ -630,7 +629,7 @@ export default function EventsDemo() {
<form onSubmit={handleAddAsset} className="flex items-center gap-1 bg-slate-950 p-1 rounded-lg border border-slate-800">
<input
type="text"
placeholder="Ticker (z.B. TSLA)"
placeholder="Ticker (e.g. TSLA)"
value={newTickerInput}
onChange={(e) => setNewTickerInput(e.target.value)}
className="bg-transparent text-[11px] text-slate-200 focus:outline-none px-2 py-0.5 w-24 uppercase font-mono"
@@ -664,7 +663,7 @@ export default function EventsDemo() {
<button
onClick={() => handleRemoveAsset(asset.symbol)}
className="text-slate-500 hover:text-rose-400 p-0.5 rounded opacity-0 group-hover/header:opacity-100 transition-opacity"
title={`${asset.name} Spalte löschen`}
title={`${asset.name} Column delete`}
>
<Trash2 className="w-3 h-3" />
</button>
@@ -687,7 +686,7 @@ export default function EventsDemo() {
<td className="py-3 px-3 text-slate-400 font-mono">
{ev.date}
<span className="block text-[10px] text-slate-500">
{d === 0 ? 'Heute' : d > 0 ? `In ${d} Tagen` : `Vor ${-d} Tagen`}
{d === 0 ? 'Today' : d > 0 ? `In ${d} days` : `${-d} days ago`}
</span>
</td>
@@ -750,7 +749,7 @@ export default function EventsDemo() {
<button
onClick={() => deleteEventFromMatrix(ev.id)}
className="text-slate-500 hover:text-rose-400 p-1 hover:bg-slate-800/50 rounded transition-all"
title="Event aus Matrix löschen"
title="Delete event from matrix"
>
<Trash2 className="w-3.5 h-3.5" />
</button>
@@ -1082,7 +1081,7 @@ export default function EventsDemo() {
{calibrationSuccess && (
<div className="bg-emerald-950/30 border border-emerald-800/80 text-emerald-400 text-[10px] rounded-lg p-2 flex items-center gap-1.5 justify-center font-semibold">
<Check className="w-3.5 h-3.5" /> Kalibrierung erfolgreich abgeschlossen!
<Check className="w-3.5 h-3.5" /> Calibration successfully completed!
</div>
)}
@@ -1101,7 +1100,7 @@ export default function EventsDemo() {
{lastCalibrationTime && (
<div className="text-[9px] text-slate-500 font-mono">
Letzter Durchlauf: {lastCalibrationTime} ({lmmObservations.length} Obs.)
Last run: {lastCalibrationTime} ({lmmObservations.length} Obs.)
</div>
)}
</div>
@@ -1169,7 +1168,7 @@ export default function EventsDemo() {
</p>
<div>
<label className="block text-slate-500 mb-1 text-[10px] uppercase font-semibold">Fokus Asset</label>
<label className="block text-slate-500 mb-1 text-[10px] uppercase font-semibold">Focus Asset</label>
<select
value={selectedSurvivalAsset}
onChange={(e) => setSelectedSurvivalAsset(e.target.value)}
@@ -1184,7 +1183,7 @@ export default function EventsDemo() {
<div className="grid grid-cols-2 gap-3 mt-2">
<div className="bg-slate-950/40 border border-slate-805 p-3 rounded-xl">
<span className="block text-[10px] text-slate-500 uppercase font-semibold">Right Censoring</span>
<span className="text-sm font-bold text-slate-200 font-mono">30 Tage</span>
<span className="text-sm font-bold text-slate-200 font-mono">30 days</span>
</div>
<div className="bg-slate-950/40 border border-slate-805 p-3 rounded-xl">
<span className="block text-[10px] text-slate-500 uppercase font-semibold">Observation Count</span>
@@ -1226,7 +1225,7 @@ export default function EventsDemo() {
{selectedModel === 'ROC' && (
<div className="w-full h-full">
<div className="text-[10px] font-mono text-slate-400 mb-2 text-center flex items-center justify-center gap-1.5">
<span>Modell-Klassifikationstrennung (FPR vs TPR)</span>
<span>Model Classification Separation (FPR vs TPR)</span>
</div>
<ResponsiveContainer width="100%" height="90%">
<AreaChart data={rocData} margin={{ top: 10, right: 10, left: -25, bottom: 5 }}>

View File

@@ -113,7 +113,7 @@ export default function InsiderDemo() {
if (whaleRes.liveDataAvailable === false) unavailable.push('Whales (13F Filings)');
if (unavailable.length > 0) {
setErrorMsg(`Echtzeitdaten-Quelle vorübergehend ausgelastet für: ${unavailable.join(', ')}. Bitte später erneut versuchen.`);
setErrorMsg(`Real-time data source temporarily busy for: ${unavailable.join(', ')}. Please try again later.`);
}
useSandboxStore.setState({
@@ -125,7 +125,7 @@ export default function InsiderDemo() {
} catch (err: any) {
console.error('Failed to load live insider data:', err.message);
if (active) {
setErrorMsg(err.message || 'Echtzeitdaten-Quelle vorübergehend nicht erreichbar.');
setErrorMsg(err.message || 'Real-time data source temporarily unreachable.');
}
} finally {
if (active) setLoading(false);
@@ -237,7 +237,7 @@ export default function InsiderDemo() {
if (!tickerStats || !selectedTicker) return [];
return tickerStats.volumes.map((vol, idx) => ({
month: `M-${tickerStats.volumes.length - idx - 1}`,
'Volumen (Shares)': vol,
'Volume (Shares)': vol,
}));
}, [tickerStats, selectedTicker]);
@@ -254,12 +254,12 @@ export default function InsiderDemo() {
{isShieldActive ? (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-amber-500/10 text-amber-400 border border-amber-500/20 shadow-[0_0_10px_rgba(245,158,11,0.15)] animate-pulse">
<span className="w-1.5 h-1.5 rounded-full bg-amber-500" />
DEV-ARCHIV AKTIV (0 CALLS)
DEV ARCHIVE ACTIVE (0 CALLS)
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 shadow-[0_0_10px_rgba(16,185,129,0.15)]">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-ping" />
LIVE-API ENDPUNKT (FMP CORPO)
LIVE API ENDPOINT (FMP CORPO)
</span>
)}
</h2>
@@ -270,13 +270,13 @@ export default function InsiderDemo() {
className="flex items-center gap-1.5 px-4 py-2 rounded-xl bg-slate-950/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-purple-400 justify-center h-11"
>
<BookOpen className="w-3.5 h-3.5" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
<div className="bg-slate-900 border border-slate-800 rounded-xl px-4 py-2 flex items-center gap-3 h-11">
<Shield className="text-purple-400 w-5 h-5" />
<div>
<p className="text-slate-400 text-xs">Bayesianische Kopplung</p>
<p className="text-slate-400 text-xs">Bayesian Coupling</p>
<p className="font-mono text-sm font-bold text-purple-400">
Prior Rebound: {(priorProbability * 100).toFixed(0)}%
</p>
@@ -290,7 +290,7 @@ export default function InsiderDemo() {
<div className="p-4 rounded-xl border border-slate-800 bg-slate-950/30 flex flex-col justify-between gap-4">
<div className="space-y-1">
<h4 className="text-sm font-semibold text-slate-300">Global Flow Outlier Scan</h4>
<p className="text-xs text-slate-400">Filtert den Markt nach statistisch signifikanten Kaufvolumina (Z-Score &gt; 2.0) und konzertierten Käufen (Insider-Cluster).</p>
<p className="text-xs text-slate-400">Filters the market for statistically significant purchase volumes (Z-Score &gt; 2.0) and concerted buying (insider clusters).</p>
</div>
<button
onClick={handleGlobalFlowScan}
@@ -298,20 +298,20 @@ export default function InsiderDemo() {
className="w-full bg-gradient-to-r from-purple-500 to-indigo-500 hover:from-purple-600 hover:to-indigo-600 disabled:from-purple-900 text-white font-bold py-2.5 px-4 rounded-xl transition-all shadow-lg shadow-purple-500/10 flex items-center justify-center gap-2"
>
<Radio className={`w-4 h-4 ${scanning ? 'animate-pulse' : ''}`} />
<span>{scanning ? 'Scanne Transaktionen...' : 'Global Flow Scan starten'}</span>
<span>{scanning ? 'Scanning Transactions...' : 'Start Global Flow Scan'}</span>
</button>
</div>
<div className="p-4 rounded-xl border border-slate-800 bg-slate-950/30 flex flex-col justify-between gap-4">
<div className="space-y-1">
<h4 className="text-sm font-semibold text-slate-300">Ticker Lookup (Einzelauswertung)</h4>
<p className="text-xs text-slate-400">Gezielte Abfrage von Insider-Z-Scores und Bayesianischen Kopplungs-Updates (z.B. PLTR, RACE, AMZN, AAPL).</p>
<h4 className="text-sm font-semibold text-slate-300">Ticker Lookup (Single Evaluation)</h4>
<p className="text-xs text-slate-400">Targeted query of insider Z-scores and Bayesian coupling updates (e.g., PLTR, RACE, AMZN, AAPL).</p>
</div>
<form onSubmit={handleTickerLookup} className="flex gap-2">
<input
type="text"
required
placeholder="z.B. PLTR"
placeholder="e.g. PLTR"
className="bg-slate-950 border border-slate-800 rounded-lg p-2.5 flex-1 text-slate-100 font-mono text-sm uppercase focus:outline-none focus:border-purple-500"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
@@ -331,31 +331,31 @@ export default function InsiderDemo() {
<div className="p-5 rounded-2xl border border-purple-500/30 bg-purple-500/5 grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6 animate-fade-in">
<div className="space-y-3">
<div className="flex justify-between items-center border-b border-slate-800 pb-2">
<h3 className="font-mono font-bold text-lg text-slate-100">{selectedTicker} Einzelauswertung</h3>
<h3 className="font-mono font-bold text-lg text-slate-100">{selectedTicker} Single Evaluation</h3>
{tickerStats.isAnomaly && <span className="px-2 py-0.5 rounded bg-purple-500/20 text-purple-300 text-[10px] font-bold border border-purple-500/30 animate-pulse">FLOW OUTLIER</span>}
</div>
<div className="space-y-2 text-xs">
<div className="flex justify-between font-mono">
<span className="text-slate-400">Volumetrischer Z-Score:</span>
<span className="text-slate-400">Volumetric Z-Score:</span>
<span className={`font-bold ${tickerStats.isAnomaly ? 'text-purple-400' : 'text-slate-300'}`}>
Z = {tickerStats.zScore.toFixed(2)}
</span>
</div>
<div className="flex justify-between font-mono">
<span className="text-slate-400">Konzertiertes Cluster (14 Tage):</span>
<span className="text-slate-400">Concerted Cluster (14 Days):</span>
<span className={`font-bold ${tickerStats.isCluster ? 'text-emerald-400' : 'text-slate-400'}`}>
{tickerStats.isCluster ? `JA (${tickerStats.clusterCount} Insiders)` : `NEIN (${tickerStats.clusterCount})`}
{tickerStats.isCluster ? `YES (${tickerStats.clusterCount} Insiders)` : `NO (${tickerStats.clusterCount})`}
</span>
</div>
{tickerStats.isCluster && (
<div className="flex justify-between font-mono text-emerald-400">
<span>Cluster Exponent-Multiplikator:</span>
<span>Cluster Exponent Multiplier:</span>
<span>x{tickerStats.multiplier.toFixed(2)}</span>
</div>
)}
<div className="flex justify-between font-mono border-t border-slate-800/80 pt-2 text-sm">
<span className="text-slate-300">Gekoppelte Rebound-Wahrsch.:</span>
<span className="text-slate-300">Coupled Rebound Prob.:</span>
<span className="text-purple-400 font-bold flex items-center gap-1">
<Percent className="w-3.5 h-3.5" />
{(tickerStats.coupledRebound * 100).toFixed(0)}%
@@ -366,14 +366,14 @@ export default function InsiderDemo() {
{/* Volume chart */}
<div className="lg:col-span-2 h-44 w-full">
<div className="text-[10px] text-slate-400 mb-1 text-center font-mono font-semibold">Insider Handelsvolumen (24 Monate Baseline)</div>
<div className="text-[10px] text-slate-400 mb-1 text-center font-mono font-semibold">Insider Trading Volume (24-Month Baseline)</div>
<ResponsiveContainer width="100%" height="90%">
<BarChart data={volumeChartData}>
<CartesianGrid strokeDasharray="3 3" stroke="#1e293b" />
<XAxis dataKey="month" stroke="#64748b" fontSize={9} />
<YAxis stroke="#64748b" fontSize={9} />
<Tooltip contentStyle={{ backgroundColor: '#0f172a', borderColor: '#334155', borderRadius: '8px' }} />
<Bar dataKey="Volumen (Shares)" fill="#8b5cf6" radius={[3, 3, 0, 0]} />
<Bar dataKey="Volume (Shares)" fill="#8b5cf6" radius={[3, 3, 0, 0]} />
</BarChart>
</ResponsiveContainer>
</div>
@@ -383,12 +383,12 @@ export default function InsiderDemo() {
{/* Global Scan Outlier List */}
{scanResults && (
<div className="p-5 rounded-2xl border border-slate-800 bg-slate-950/20 mb-6 space-y-3 animate-fade-in">
<h3 className="text-sm font-bold text-slate-200 uppercase tracking-wider">Ergebnisse des Global Flow Scans</h3>
<h3 className="text-sm font-bold text-slate-200 uppercase tracking-wider">Global Flow Scan Results</h3>
{scanResults.length === 0 ? (
<div className="p-6 text-center border border-dashed border-slate-800 rounded-xl text-slate-400 bg-slate-900/10">
<Radio className="w-8 h-8 text-purple-500/50 mx-auto mb-2 animate-pulse" />
<p className="text-xs font-semibold text-slate-300">Keine signifikanten Volumen-Anomalien gefunden</p>
<p className="text-[10px] text-slate-500 mt-1">Es wurden keine Transaktionen mit einem berechneten volumetric Z-Score &gt; 2.0 in den aktiven Live-Feeds identifiziert.</p>
<p className="text-xs font-semibold text-slate-300">No Significant Volume Anomalies Found</p>
<p className="text-[10px] text-slate-500 mt-1">No transactions with a calculated volumetric Z-Score &gt; 2.0 were identified in the active live feeds.</p>
</div>
) : (
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
@@ -421,13 +421,13 @@ export default function InsiderDemo() {
onClick={() => setActiveSegment('executives')}
className={`flex-1 py-2 rounded-lg text-xs font-semibold font-sans transition-all flex items-center justify-center gap-1.5 ${activeSegment === 'executives' ? 'bg-purple-500 text-white font-bold' : 'text-slate-400 hover:text-slate-200'}`}
>
<User className="w-3.5 h-3.5" /> Vorstände (Form 4)
<User className="w-3.5 h-3.5" /> Executives (Form 4)
</button>
<button
onClick={() => setActiveSegment('congress')}
className={`flex-1 py-2 rounded-lg text-xs font-semibold font-sans transition-all flex items-center justify-center gap-1.5 ${activeSegment === 'congress' ? 'bg-purple-500 text-white font-bold' : 'text-slate-400 hover:text-slate-200'}`}
>
<Landmark className="w-3.5 h-3.5" /> Kongress (Stock Act)
<Landmark className="w-3.5 h-3.5" /> Congress (Stock Act)
</button>
<button
onClick={() => setActiveSegment('whales')}
@@ -441,7 +441,7 @@ export default function InsiderDemo() {
<div className="p-4 rounded-xl border border-red-550/30 bg-red-550/10 text-red-400 text-xs flex items-center gap-3 mb-4 animate-fade-in">
<AlertTriangle className="w-5 h-5 shrink-0 animate-pulse" />
<div>
<span className="font-bold">Datenladefehler:</span> {errorMsg}
<span className="font-bold">Data Load Error:</span> {errorMsg}
</div>
</div>
)}
@@ -455,12 +455,12 @@ export default function InsiderDemo() {
<th className="p-3">Ticker</th>
<th className="p-3">Insider Name</th>
<th className="p-3">Position</th>
<th className="p-3">Transaktion</th>
<th className="p-3 font-mono">Stücke</th>
<th className="p-3 text-right">Wert ($)</th>
<th className="p-3 font-mono text-center">Volumetrischer Z-Score</th>
<th className="p-3">Transaction</th>
<th className="p-3 font-mono">Shares</th>
<th className="p-3 text-right">Value ($)</th>
<th className="p-3 font-mono text-center">Volumetric Z-Score</th>
<th className="p-3 font-mono text-center">P(R|Z)</th>
<th className="p-3">Strategische Einordnung</th>
<th className="p-3">Strategic Assessment</th>
</tr>
</thead>
<tbody>
@@ -469,7 +469,7 @@ export default function InsiderDemo() {
<td colSpan={9} className="p-8 text-center text-slate-400">
<div className="flex items-center justify-center gap-2">
<div className="w-4 h-4 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
<span>Lade live Insider-Transaktionen (Form 4)...</span>
<span>Loading live insider transactions (Form 4)...</span>
</div>
</td>
</tr>
@@ -477,7 +477,7 @@ export default function InsiderDemo() {
{!loading && insiderTrades.length === 0 && (
<tr>
<td colSpan={9} className="p-8 text-center text-slate-500">
Keine Insider-Transaktionen geladen.
No insider transactions loaded.
</td>
</tr>
)}
@@ -496,7 +496,7 @@ export default function InsiderDemo() {
<td className="p-3 text-slate-400">{t.relation}</td>
<td className="p-3">
<span className={`px-1.5 py-0.5 rounded text-[9px] font-bold ${isBuy ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border border-rose-500/20'}`}>
{isBuy ? 'KAUF' : 'VERKAUF'}
{isBuy ? 'BUY' : 'SELL'}
</span>
</td>
<td className="p-3 font-mono text-slate-300">{t.shares.toLocaleString()}</td>
@@ -505,7 +505,7 @@ export default function InsiderDemo() {
</td>
<td className={`p-3 font-mono text-center font-bold ${zScore >= 2.0 ? 'text-purple-400' : 'text-slate-350'}`}>{zScore}</td>
<td className="p-3 font-mono text-center text-purple-400 font-bold">{(coupledRebound * 100).toFixed(0)}%</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{t.insight || 'Opportunistische Diversifikation'}</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{t.insight || 'Opportunistic Diversification'}</td>
</tr>
);
})}
@@ -518,23 +518,23 @@ export default function InsiderDemo() {
<div className="p-3 bg-amber-500/10 border-b border-slate-800 text-xs text-amber-400 flex items-start gap-2.5">
<AlertTriangle className="w-5 h-5 shrink-0" />
<div>
<span className="font-bold">U.S. Congress Stock Act Offenlegungslags:</span> Abgeordnete müssen Käufe innerhalb von 30 bis 45 Tagen offenlegen. Der Alpha-Lag in der Tabelle visualisiert diese Meldeverzögerung. Käufe können verzögert eingepreist sein.
<span className="font-bold">U.S. Congress Stock Act Disclosure Lags:</span> Representatives must disclose transactions within 30 to 45 days. The Alpha Lag in the table visualizes this reporting delay. Transactions may be priced in with a delay.
</div>
</div>
<table className="w-full border-collapse text-left text-xs">
<thead>
<tr className="border-b border-slate-800 text-slate-400 font-semibold bg-slate-900/40">
<th className="p-3">Ticker</th>
<th className="p-3">Abgeordneter</th>
<th className="p-3">Kammer</th>
<th className="p-3">Transaktion</th>
<th className="p-3">Volumen-Spanne</th>
<th className="p-3 font-mono">Handelsdatum</th>
<th className="p-3 font-mono">Meldedatum</th>
<th className="p-3 text-right">Alpha-Lag</th>
<th className="p-3 font-mono text-center">Volumetrischer Z-Score</th>
<th className="p-3">Representative</th>
<th className="p-3">Chamber</th>
<th className="p-3">Transaction</th>
<th className="p-3">Volume Range</th>
<th className="p-3 font-mono">Transaction Date</th>
<th className="p-3 font-mono">Filing Date</th>
<th className="p-3 text-right">Alpha Lag</th>
<th className="p-3 font-mono text-center">Volumetric Z-Score</th>
<th className="p-3 font-mono text-center">P(R|Z)</th>
<th className="p-3">Strategische Einordnung</th>
<th className="p-3">Strategic Assessment</th>
</tr>
</thead>
<tbody>
@@ -543,7 +543,7 @@ export default function InsiderDemo() {
<td colSpan={11} className="p-8 text-center text-slate-400">
<div className="flex items-center justify-center gap-2">
<div className="w-4 h-4 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
<span>Lade US-Kongress-Transaktionen...</span>
<span>Loading US Congress transactions...</span>
</div>
</td>
</tr>
@@ -551,7 +551,7 @@ export default function InsiderDemo() {
{!loading && congressTrades.length === 0 && (
<tr>
<td colSpan={11} className="p-8 text-center text-slate-500">
Keine Kongress-Transaktionen geladen.
No Congress transactions loaded.
</td>
</tr>
)}
@@ -571,16 +571,16 @@ export default function InsiderDemo() {
<td className="p-3 text-slate-400">{c.chamber}</td>
<td className="p-3">
<span className={`px-1.5 py-0.5 rounded text-[9px] font-bold ${isBuy ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border border-rose-500/20'}`}>
{isBuy ? 'KAUF' : 'VERKAUF'}
{isBuy ? 'BUY' : 'SELL'}
</span>
</td>
<td className="p-3 text-slate-300 font-mono">{c.valueRange}</td>
<td className="p-3 font-mono text-slate-400">{c.transactionDate}</td>
<td className="p-3 font-mono text-slate-400">{c.filingDate}</td>
<td className="p-3 font-mono text-right text-amber-400 font-bold">{c.lagDays} Tage</td>
<td className="p-3 font-mono text-right text-amber-400 font-bold">{c.lagDays} Days</td>
<td className={`p-3 font-mono text-center font-bold ${zScore >= 2.0 ? 'text-purple-400' : 'text-slate-350'}`}>{zScore}</td>
<td className="p-3 font-mono text-center text-purple-400 font-bold">{(coupledRebound * 100).toFixed(0)}%</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{c.insight || 'Opportunistische Diversifikation'}</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{c.insight || 'Opportunistic Diversification'}</td>
</tr>
);
})}
@@ -595,14 +595,14 @@ export default function InsiderDemo() {
<tr className="border-b border-slate-800 text-slate-400 font-semibold bg-slate-900/40">
<th className="p-3">Ticker</th>
<th className="p-3">Institution (13F Filers)</th>
<th className="p-3">Art</th>
<th className="p-3 font-mono">Gehandelte Anteile</th>
<th className="p-3 font-mono">Aktueller Bestand</th>
<th className="p-3 font-mono">Meldedatum</th>
<th className="p-3 text-right">Geschätzter Wert ($)</th>
<th className="p-3 font-mono text-center">Volumetrischer Z-Score</th>
<th className="p-3">Type</th>
<th className="p-3 font-mono">Shares Traded</th>
<th className="p-3 font-mono">Shares Held</th>
<th className="p-3 font-mono">Filing Date</th>
<th className="p-3 text-right">Estimated Value ($)</th>
<th className="p-3 font-mono text-center">Volumetric Z-Score</th>
<th className="p-3 font-mono text-center">P(R|Z)</th>
<th className="p-3">Strategische Einordnung</th>
<th className="p-3">Strategic Assessment</th>
</tr>
</thead>
<tbody>
@@ -611,7 +611,7 @@ export default function InsiderDemo() {
<td colSpan={10} className="p-8 text-center text-slate-400">
<div className="flex items-center justify-center gap-2">
<div className="w-4 h-4 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
<span>Lade 13F Whales-Transaktionen...</span>
<span>Loading 13F whale transactions...</span>
</div>
</td>
</tr>
@@ -619,7 +619,7 @@ export default function InsiderDemo() {
{!loading && whaleTrades.length === 0 && (
<tr>
<td colSpan={10} className="p-8 text-center text-slate-500">
Keine Institutionen-Transaktionen geladen.
No institutional transactions loaded.
</td>
</tr>
)}
@@ -648,7 +648,7 @@ export default function InsiderDemo() {
</td>
<td className={`p-3 font-mono text-center font-bold ${zScore >= 2.0 ? 'text-purple-400' : 'text-slate-350'}`}>{zScore}</td>
<td className="p-3 font-mono text-center text-purple-400 font-bold">{(coupledRebound * 100).toFixed(0)}%</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{w.insight || 'Opportunistisches Rebalancing'}</td>
<td className="p-3 text-slate-350 whitespace-normal break-words">{w.insight || 'Opportunistic Rebalancing'}</td>
</tr>
);
})}
@@ -665,34 +665,34 @@ export default function InsiderDemo() {
className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-purple-400 transition-colors focus:outline-none"
>
<span>{showMathAccordion ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}</span>
<span className="font-semibold uppercase tracking-wider">Mathematische Formulierung (Z-Score &amp; Bayesianische Kopplung)</span>
<span className="font-semibold uppercase tracking-wider">Mathematical Formulation (Z-Score &amp; Bayesian Coupling)</span>
</button>
{showMathAccordion && (
<div className="mt-4 p-4 rounded-xl border border-slate-850 bg-slate-950/40 text-xs text-slate-300 space-y-4">
<div>
<h4 className="font-bold text-purple-400 mb-1">1. Volumetrischer Z-Score (Statistische Signifikanz)</h4>
<h4 className="font-bold text-purple-400 mb-1">1. Volumetric Z-Score (Statistical Significance)</h4>
<p className="mb-2">
Der Z-Score gibt an, um wie viele Standardabweichungen das aktuelle Transaktionsvolumen <InlineMath math="X_t" /> vom historischen Durchschnitt <InlineMath math="\mu" /> abweicht:
The Z-Score indicates how many standard deviations the current transaction volume <InlineMath math="X_t" /> deviates from the historical average <InlineMath math="\\mu" />:
</p>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="Z = \frac{X_t - \mu}{\sigma}" />
<BlockMath math="Z = \\frac{X_t - \\mu}{\\sigma}" />
</div>
<p className="text-slate-400">
Ein Z-Score &gt; 2.0 wird als Ausreißer (Anomaly Trigger) eingestuft, was einer Wahrscheinlichkeit von unter 2.27% r einen zufälligen Anstieg entspricht (einseitiger Test bei Normalverteilung).
A Z-Score &gt; 2.0 is classified as an outlier (anomaly trigger), corresponding to a probability of less than 2.27% for a random spike (one-sided test under a normal distribution).
</p>
</div>
<div className="border-t border-slate-900 pt-3">
<h4 className="font-bold text-purple-400 mb-1">2. Bayesianische Kopplung (Rebound-Wahrscheinlichkeit)</h4>
<h4 className="font-bold text-purple-400 mb-1">2. Bayesian Coupling (Rebound Probability)</h4>
<p className="mb-2">
Wir verknüpfen den Preisdrop-Sentiment (Element 2) mit den Insider-Z-Scores (Element 3), um die A-Posteriori-Wahrscheinlichkeit eines echten Rebounds zu ermitteln:
We couple price drop sentiment (Element 2) with insider Z-Scores (Element 3) to determine the posterior probability of a true rebound:
</p>
<div className="py-2 overflow-x-auto text-slate-200">
<BlockMath math="P(R|Z) = \frac{P(Z|R) \cdot P(R)}{P(Z|R) \cdot P(R) + P(Z|\neg R) \cdot (1 - P(R))}" />
<BlockMath math="P(R|Z) = \\frac{P(Z|R) \\cdot P(R)}{P(Z|R) \\cdot P(R) + P(Z|\\neg R) \\cdot (1 - P(R))}" />
</div>
<p className="text-slate-400">
wobei <InlineMath math="P(R)" /> die Prior-Wahrscheinlichkeit ist. Ist der Z-Score hoch (Käufe), steigt die Likelihood <InlineMath math="P(Z|R)" /> stark an und maximiert den Rebound-Erwartungswert.
where <InlineMath math="P(R)" /> is the prior probability. When the Z-Score is high (buying), the likelihood <InlineMath math="P(Z|R)" /> increases significantly, maximizing the rebound expectation.
</p>
</div>
</div>

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { BookOpen } from 'lucide-react';
import { BookOpen, X } from 'lucide-react';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
@@ -26,7 +26,7 @@ export default function InsiderMathModal({ isOpen, onClose }: InsiderMathModalPr
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/85 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-955/90 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-300">
{/* Modal Header */}
@@ -39,9 +39,10 @@ export default function InsiderMathModal({ isOpen, onClose }: InsiderMathModalPr
</div>
<button
onClick={onClose}
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 px-3 py-1.5 rounded-lg text-xs font-semibold font-mono transition-all cursor-pointer"
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 p-2 rounded-xl transition-all cursor-pointer flex items-center justify-center"
aria-label="Close modal"
>
Schließen (ESC)
<X className="w-4 h-4" />
</button>
</div>
@@ -69,8 +70,8 @@ export default function InsiderMathModal({ isOpen, onClose }: InsiderMathModalPr
<p className="text-xs leading-relaxed text-slate-400">
Insiders have unique company information, but clusters yield highest significance. A cluster is registered if:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="\text{Count}_{\text{insiders}} \ge 3 \quad \text{within a rolling 14-day window}" />
<div className="bg-slate-955/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="\\text{Count}_{\\text{insiders}} \\ge 3 \\quad \\text{within a rolling 14-day window}" />
<p className="text-[11px] text-slate-400 font-mono mt-2 text-center">
Insiders must represent distinct entities (e.g. CEO, CFO, and Directors trading concurrently).
</p>
@@ -82,8 +83,8 @@ export default function InsiderMathModal({ isOpen, onClose }: InsiderMathModalPr
<p className="text-xs leading-relaxed text-slate-400">
The Insider Intensity Score scales signals based on size, conviction value, and count of participants:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="I_{score} = \ln\left(\sum_{k=1}^N \text{Volume}_{shares, k}\right) \times \left(\frac{\sum_{k=1}^N \text{Value}_{USD, k}}{\text{Market Cap}}\right) \times \text{Count}_{\text{insiders}}" />
<div className="bg-slate-955/40 p-4 rounded-xl border border-slate-800/60 my-2">
<BlockMath math="I_{\\text{score}} = \\ln\\left(\\sum_{k=1}^N \\text{Volume}_{\\text{shares}, k}\\right) \\times \\left(\\frac{\\sum_{k=1}^N \\text{Value}_{\\text{USD}, k}}{\\text{Market Cap}}\\right) \\times \\text{Count}_{\\text{insiders}}" />
</div>
</div>
@@ -92,9 +93,9 @@ export default function InsiderMathModal({ isOpen, onClose }: InsiderMathModalPr
<p className="text-xs leading-relaxed text-slate-400">
The engine cross-references corporate clusters with the Overreaction Scanner, isolating stocks with the highest rebound probabilities:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<div className="bg-slate-955/40 p-4 rounded-xl border border-slate-800/60 my-2">
<p className="text-xs leading-relaxed font-mono">
If <InlineMath math="\text{Alert} \in \text{Scanner}_{\text{Oversold}}" /> and <InlineMath math="\text{Cluster} \in \text{Insider}_{\text{Active}}" />:
{"If "}<InlineMath math="\\text{Alert} \\in \\text{Scanner}_{\\text{Oversold}}" />{" and "}<InlineMath math="\\text{Cluster} \\in \\text{Insider}_{\\text{Active}}" />{":"}
<br/>
Prioritize tickers showing asymmetric insider buying during panic drops, suggesting fundamental divergence from market sentiment.
</p>

View File

@@ -49,11 +49,11 @@ export default function MacroIndicatorsDemo() {
const data = await response.json();
setPayload(data);
} else {
setError('Fehler beim Abruf der makroökonomischen Indikatoren.');
setError('Error fetching macroeconomic indicators.');
}
} catch (err) {
console.error('Fetch macro indicators error:', err);
setError('Netzwerkfehler beim Laden der Makroökonomischen Daten.');
setError('Network error loading macroeconomic data.');
} finally {
setLoading(false);
}
@@ -95,7 +95,7 @@ export default function MacroIndicatorsDemo() {
return {
name: 'Federal Reserve Net Liquidity Proxy',
unit: 'T$',
category: 'Zentralbanken & Liquidität',
category: 'Central Banks & Liquidity',
current,
previous,
trend,
@@ -107,7 +107,7 @@ export default function MacroIndicatorsDemo() {
return (
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-8 text-slate-100 shadow-xl min-h-[450px] flex flex-col items-center justify-center space-y-4">
<div className="w-10 h-10 rounded-full border-2 border-indigo-500 border-t-transparent animate-spin" />
<div className="text-slate-400 text-sm font-mono animate-pulse">Lade makroökonomisches Datenarchiv...</div>
<div className="text-slate-400 text-sm font-mono animate-pulse">Loading macroeconomic data archive...</div>
</div>
);
}
@@ -116,7 +116,7 @@ export default function MacroIndicatorsDemo() {
return (
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl min-h-[400px] flex items-center justify-center">
<div className="text-rose-400 font-semibold flex items-center gap-2">
<AlertCircle className="w-5 h-5" /> {error || 'Fehler beim Laden.'}
<AlertCircle className="w-5 h-5" /> {error || 'Error loading data.'}
</div>
</div>
);
@@ -218,7 +218,7 @@ export default function MacroIndicatorsDemo() {
<div key={key} className="bg-slate-950/40 border border-slate-850 rounded-xl p-3 flex justify-between items-center hover:bg-slate-950/60 transition-colors">
<div className="space-y-0.5 max-w-[130px]">
<div className="text-xs font-semibold text-slate-200 truncate" title={ind.name}>{ind.name}</div>
<div className="text-[9px] text-slate-500 font-mono">Vorherig: {ind.previous === null || ind.previous === undefined ? '' : ind.previous}{ind.unit}</div>
<div className="text-[9px] text-slate-500 font-mono">Previous: {ind.previous === null || ind.previous === undefined ? '' : ind.previous}{ind.unit}</div>
</div>
{/* Micro Recharts Sparkline */}
@@ -258,7 +258,7 @@ export default function MacroIndicatorsDemo() {
<AlertCircle className="w-5 h-5 text-rose-400 shrink-0" />
<div className="flex-1">
<span className="font-bold font-mono uppercase tracking-wider block mb-0.5">[ API Limit - Historical Archive Active]</span>
Der Echtzeit-Datenabruf (Juni 2026) ist aufgrund von Ratenbeschränkungen (FMP HTTP 429) gedrosselt. Das System operiert im sicheren, gepufferten historischen Archiv-Modus.
Real-time data retrieval (June 2026) is throttled due to rate limits (FMP HTTP 429). The system is operating in a secure, buffered historical archive mode.
</div>
</div>
)}
@@ -271,10 +271,10 @@ export default function MacroIndicatorsDemo() {
<div className="space-y-1">
<span className="text-indigo-400 text-xs font-semibold uppercase tracking-wider">Macroeconomics Silo</span>
<h2 className="text-2xl font-extrabold text-white flex items-center gap-2">
<Landmark className="text-indigo-400 w-6 h-6" /> Makroökonomische Indikatoren & Kredit-Silo
<Landmark className="text-indigo-400 w-6 h-6" /> Macroeconomic Indicators & Credit Silo
</h2>
<p className="text-xs text-slate-400">
Analysiert Zyklen, Liquiditätsflüsse und Zinskurven über die letzten 24 Monate.
Analyzes cycles, liquidity flows, and yield curves over the past 24 months.
</p>
</div>
@@ -284,11 +284,11 @@ export default function MacroIndicatorsDemo() {
className="flex items-center gap-1.5 px-4 py-2.5 rounded-xl bg-slate-955/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-indigo-400 w-full md:w-auto justify-center h-11 cursor-pointer"
>
<BookOpen className="w-4 h-4" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
<div className="bg-slate-955/80 border border-slate-800 rounded-xl px-4 py-2 text-right shrink-0 h-11 flex flex-col justify-center">
<div className="text-[9px] text-slate-555 uppercase font-mono">Letztes Update</div>
<div className="text-[9px] text-slate-555 uppercase font-mono">Last Update</div>
<div className="font-mono text-xs text-slate-300">
{new Date(payload.timestamp).toLocaleTimeString()}
</div>
@@ -309,8 +309,8 @@ export default function MacroIndicatorsDemo() {
<div className="absolute top-0 right-0 w-24 h-24 bg-rose-500/5 rounded-full blur-2xl -z-10" />
<div className="flex justify-between items-start">
<div className="space-y-1">
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Kategorie 1</span>
<h4 className="text-sm font-bold text-slate-200">Inflation & Konsum-Stress</h4>
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Category 1</span>
<h4 className="text-sm font-bold text-slate-200">Inflation & Consumer Stress</h4>
</div>
{/* Glowing Neon-Ampel Light */}
<div className={`w-3 h-3 rounded-full ${
@@ -321,11 +321,11 @@ export default function MacroIndicatorsDemo() {
</div>
<div className="mt-4 space-y-3">
<div className="text-xs text-slate-400">
Risiko-Status:{' '}
Risk Status:{' '}
<span className={`font-bold ${
card1Status === 'RED' ? 'text-rose-400' : card1Status === 'AMBER' ? 'text-amber-400' : 'text-emerald-400'
}`}>
{card1Status === 'RED' ? '🚨 Kritischer Konsumdruck' : card1Status === 'AMBER' ? '⚠️ Erhöhtes Risiko' : '✅ Stabil'}
{card1Status === 'RED' ? '🚨 Critical Consumer Pressure' : card1Status === 'AMBER' ? '⚠️ Elevated Risk' : '✅ Stable'}
</span>
</div>
<div className="grid grid-cols-3 gap-2 pt-2 border-t border-slate-800/60 text-center font-mono">
@@ -336,13 +336,13 @@ export default function MacroIndicatorsDemo() {
</div>
</div>
<div>
<div className="text-[10px] text-slate-500">Sparquote</div>
<div className="text-[10px] text-slate-500">Savings Rate</div>
<div className={`text-xs font-bold ${savingsRate && savingsRate.current < 3.0 ? 'text-rose-400' : 'text-slate-200'}`}>
{savingsRate ? savingsRate.current.toFixed(1) : '0.0'}%
</div>
</div>
<div>
<div className="text-[10px] text-slate-500">Ausfälle</div>
<div className="text-[10px] text-slate-500">Delinquencies</div>
<div className={`text-xs font-bold ${ccDelinquency && ccDelinquency.current > 4.5 ? 'text-rose-400' : 'text-slate-200'}`}>
{ccDelinquency ? ccDelinquency.current.toFixed(1) : '0.0'}%
</div>
@@ -360,8 +360,8 @@ export default function MacroIndicatorsDemo() {
<div className="absolute top-0 right-0 w-24 h-24 bg-indigo-500/5 rounded-full blur-2xl -z-10" />
<div className="flex justify-between items-start">
<div className="space-y-1">
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Kategorie 2</span>
<h4 className="text-sm font-bold text-slate-200">Bewertung & Liquidität</h4>
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Category 2</span>
<h4 className="text-sm font-bold text-slate-200">Valuation & Liquidity</h4>
</div>
{/* Glowing Neon-Ampel Light */}
<div className={`w-3 h-3 rounded-full ${
@@ -372,11 +372,11 @@ export default function MacroIndicatorsDemo() {
</div>
<div className="mt-4 space-y-3">
<div className="text-xs text-slate-400">
Risiko-Status:{' '}
Risk Status:{' '}
<span className={`font-bold ${
card2Status === 'RED' ? 'text-rose-400' : card2Status === 'AMBER' ? 'text-amber-400' : 'text-emerald-400'
}`}>
{card2Status === 'RED' ? '🚨 Extreme Überbewertung' : card2Status === 'AMBER' ? '⚠️ Liquiditäts-Engpass' : '✅ Ausreichend'}
{card2Status === 'RED' ? '🚨 Extreme Overvaluation' : card2Status === 'AMBER' ? '⚠️ Liquidity Squeeze' : '✅ Sufficient'}
</span>
</div>
<div className="grid grid-cols-2 gap-2 pt-2 border-t border-slate-800/60 text-center font-mono">
@@ -405,8 +405,8 @@ export default function MacroIndicatorsDemo() {
<div className="absolute top-0 right-0 w-24 h-24 bg-emerald-500/5 rounded-full blur-2xl -z-10" />
<div className="flex justify-between items-start">
<div className="space-y-1">
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Kategorie 3</span>
<h4 className="text-sm font-bold text-slate-200">Kredit- & Rezessionsrisiko</h4>
<span className="text-slate-400 text-[10px] font-mono uppercase tracking-wider">Category 3</span>
<h4 className="text-sm font-bold text-slate-200">Credit & Recession Risk</h4>
</div>
{/* Glowing Neon-Ampel Light */}
<div className={`w-3 h-3 rounded-full ${
@@ -417,11 +417,11 @@ export default function MacroIndicatorsDemo() {
</div>
<div className="mt-4 space-y-3">
<div className="text-xs text-slate-400">
Risiko-Status:{' '}
Risk Status:{' '}
<span className={`font-bold ${
card3Status === 'RED' ? 'text-rose-400' : card3Status === 'AMBER' ? 'text-amber-400' : 'text-emerald-400'
}`}>
{card3Status === 'RED' ? '🚨 Rezessions-Inversion' : card3Status === 'AMBER' ? '⚠️ Zinskurven-Warnung' : '✅ Stabil'}
{card3Status === 'RED' ? '🚨 Recession Inversion' : card3Status === 'AMBER' ? '⚠️ Yield Curve Warning' : '✅ Stable'}
</span>
</div>
<div className="grid grid-cols-2 gap-2 pt-2 border-t border-slate-800/60 text-center font-mono">
@@ -451,11 +451,11 @@ export default function MacroIndicatorsDemo() {
>
<div className="flex items-center gap-2">
<Activity className="w-5 h-5 text-indigo-400" />
<span>🏛 Detailliertes makroökonomisches Indikatoren-Hauptbuch (21 Indikatoren)</span>
<span>🏛 Detailed Macroeconomic Indicators Ledger (21 Indicators)</span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-slate-500 font-mono">
{isAccordionOpen ? 'Einklappen' : 'Ausklappen'}
{isAccordionOpen ? 'Collapse' : 'Expand'}
</span>
<div className="text-slate-400">
{isAccordionOpen ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
@@ -472,9 +472,9 @@ export default function MacroIndicatorsDemo() {
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-5 text-slate-100 shadow-xl space-y-4">
<div className="border-b border-slate-800 pb-3 flex items-center justify-between">
<h3 className="font-bold text-sm text-white flex items-center gap-2">
<Activity className="w-4 h-4 text-emerald-400" /> Inflation & Wachstum
<Activity className="w-4 h-4 text-emerald-400" /> Inflation & Growth
</h3>
<span className="text-[10px] bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-2 py-0.5 rounded font-mono font-bold">Real-Data</span>
<span className="text-[10px] bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-2 py-0.5 rounded font-mono font-bold">Real Data</span>
</div>
<div className="space-y-4">
@@ -490,7 +490,7 @@ export default function MacroIndicatorsDemo() {
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-5 text-slate-100 shadow-xl space-y-4">
<div className="border-b border-slate-800 pb-3 flex items-center justify-between">
<h3 className="font-bold text-sm text-white flex items-center gap-2">
<Coins className="w-4 h-4 text-indigo-400" /> Zentralbanken & Liquidität
<Coins className="w-4 h-4 text-indigo-400" /> Central Banks & Liquidity
</h3>
<span className="text-[10px] bg-indigo-500/10 text-indigo-400 border border-indigo-500/20 px-2 py-0.5 rounded font-mono font-bold">M2 / RRP / TGA</span>
</div>
@@ -511,7 +511,7 @@ export default function MacroIndicatorsDemo() {
<div className="text-xs font-bold text-indigo-300 truncate" title={netLiquidityIndicator.name}>
Net Fed Liquidity
</div>
<div className="text-[9px] text-indigo-400/70 font-mono">Vorherig: {netLiquidityIndicator.previous}{netLiquidityIndicator.unit}</div>
<div className="text-[9px] text-indigo-400/70 font-mono">Previous: {netLiquidityIndicator.previous}{netLiquidityIndicator.unit}</div>
</div>
{/* Micro Recharts Sparkline */}
@@ -547,9 +547,9 @@ export default function MacroIndicatorsDemo() {
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-5 text-slate-100 shadow-xl space-y-4">
<div className="border-b border-slate-800 pb-3 flex items-center justify-between">
<h3 className="font-bold text-sm text-white flex items-center gap-2">
<ShieldAlert className="w-4 h-4 text-rose-400" /> Kredit- & Anleihemarkt
<ShieldAlert className="w-4 h-4 text-rose-400" /> Credit & Bond Market
</h3>
<span className="text-[10px] bg-rose-500/10 text-rose-400 border border-rose-500/20 px-2 py-0.5 rounded font-mono font-bold">Zinskurven & Spreads</span>
<span className="text-[10px] bg-rose-500/10 text-rose-400 border border-rose-500/20 px-2 py-0.5 rounded font-mono font-bold">Yield Curves & Spreads</span>
</div>
<div className="space-y-4">
@@ -557,10 +557,10 @@ export default function MacroIndicatorsDemo() {
{renderRow('yieldSpread', yieldSpread)}
{renderRow('hySpread', hySpread)}
{/* Sub-section named "Immobilien- & Hypotheken-Kredite" */}
{/* Sub-section named "Real Estate & Mortgage Credit" */}
<div className="border-t border-slate-800/80 pt-4 mt-4">
<h4 className="text-xs font-bold text-indigo-400 uppercase tracking-wider font-mono mb-3 flex items-center gap-1.5">
<Landmark className="w-3.5 h-3.5" /> Immobilien- & Hypotheken-Kredite
<Landmark className="w-3.5 h-3.5" /> Real Estate & Mortgage Credit
</h4>
</div>
@@ -578,10 +578,10 @@ export default function MacroIndicatorsDemo() {
{/* SECTION 3: Dynamic Macro analysis and explanation */}
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-4">
<h3 className="font-bold text-sm text-slate-200">Systemische Macro- & Kreditmarkt-Analyse</h3>
<h3 className="font-bold text-sm text-slate-200">Systemic Macro & Credit Market Analysis</h3>
<p className="text-xs text-slate-400 leading-relaxed">
Zinskurveninversionen (z. B. wenn der <span className="text-indigo-400 font-semibold font-mono">2S10S-Yield-Spread</span> negativ ist) gelten historisch als zuverlässige Vorläufer ökonomischer Kontraktionen. Derzeit beträgt der Spread <span className="text-emerald-400 font-bold font-mono">{yieldSpread !== undefined ? (yieldSpread.current >= 0 ? '+' : '') + yieldSpread.current.toFixed(2) : '0.00'}%</span>. Gleichzeitig signalisiert der Buffett-Indikator mit <span className="text-rose-400 font-bold font-mono">{buffett !== undefined ? buffett.current.toFixed(1) : '0.0'}%</span> eine erhebliche Überbewertung des US-Aktienmarktes relativ zur Wirtschaftsleistung. Im Konsumsektor deutet die Kombination aus einer niedrigen Sparquote (<span className="text-amber-400 font-mono">{savingsRate !== undefined ? savingsRate.current.toFixed(1) : '0.0'}%</span>) und steigenden Kreditkartenausfällen (<span className="text-rose-400 font-mono">{ccDelinquency !== undefined ? ccDelinquency.current.toFixed(1) : '0.0'}%</span>) auf echten Stress hin, während der High-Yield Credit Spread (<span className="text-slate-300 font-bold font-mono">{hySpread !== undefined ? hySpread.current.toFixed(1) : '0.0'}%</span>) noch Stabilität anzeigt.
Monetäre Liquidität (<span className="font-bold text-indigo-300 font-mono">Net Fed Liquidity Proxy: {netLiquidityIndicator ? netLiquidityIndicator.current.toFixed(2) : '0.00'} T$</span>) wirkt als zentraler Impulsgeber: Ein Anstieg des TGA-Volumens oder der RRP-Nutzung zieht freie Liquidität aus dem Bankensystem ab (Bremswirkung für Aktien/Krypto), während ein Abbau dieser Posten zusätzliche Liquidität freisetzt (Rückenwind r Risk Assets).
Yield curve inversions (e.g. when the <span className="text-indigo-400 font-semibold font-mono">2S10S Yield Spread</span> is negative) are historically reliable leading indicators of economic contractions. Currently, the spread is <span className="text-emerald-400 font-bold font-mono">{yieldSpread !== undefined ? (yieldSpread.current >= 0 ? '+' : '') + yieldSpread.current.toFixed(2) : '0.00'}%</span>. At the same time, the Buffett Indicator indicates an overvaluation of the US stock market relative to economic output. In the consumer sector, the combination of a low savings rate (<span className="text-amber-400 font-mono">{savingsRate !== undefined ? savingsRate.current.toFixed(1) : '0.0'}%</span>) and rising credit card delinquencies (<span className="text-rose-400 font-mono">{ccDelinquency !== undefined ? ccDelinquency.current.toFixed(1) : '0.0'}%</span>) suggests genuine distress, while the High-Yield credit spread (<span className="text-slate-300 font-bold font-mono">{hySpread !== undefined ? hySpread.current.toFixed(1) : '0.0'}%</span>) still indicates stability.
Monetary liquidity (<span className="font-bold text-indigo-300 font-mono">Net Fed Liquidity Proxy: {netLiquidityIndicator ? netLiquidityIndicator.current.toFixed(2) : '0.00'} T$</span>) acts as a central impulse: an increase in TGA volume or RRP usage drains liquidity from the banking system (headwind for equities/crypto), while a decrease in these items releases additional liquidity (tailwind for risk assets).
</p>
</div>

View File

@@ -1,115 +0,0 @@
import React from 'react';
import { BookOpen } from 'lucide-react';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
interface PortfolioMathModalProps {
isOpen: boolean;
onClose: () => void;
}
export default function PortfolioMathModal({ isOpen, onClose }: PortfolioMathModalProps) {
React.useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
};
if (isOpen) {
window.addEventListener('keydown', handleKeyDown);
}
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/85 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-300">
{/* Modal Header */}
<div className="flex justify-between items-center px-6 py-4 bg-slate-950/40 border-b border-slate-800/60">
<div>
<h2 className="text-base font-bold bg-gradient-to-r from-teal-400 to-emerald-400 bg-clip-text text-transparent flex items-center gap-2">
<BookOpen className="w-5 h-5 text-teal-400" /> Portfolio Sandbox - Math & Logic Specification
</h2>
<p className="text-[10px] text-slate-500 font-mono">Institutional Specification Manual</p>
</div>
<button
onClick={onClose}
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 px-3 py-1.5 rounded-lg text-xs font-semibold font-mono transition-all cursor-pointer"
>
Schließen (ESC)
</button>
</div>
{/* Modal Body */}
<div className="flex-1 overflow-y-auto p-6 sm:p-8 space-y-6 text-slate-300 scrollbar-thin">
<div className="space-y-6">
<div className="border-b border-slate-800/80 pb-3">
<h3 className="text-base font-bold text-slate-200">5. Portfolio Sandbox & Rebalancing Engine</h3>
<p className="text-xs text-slate-400 mt-1">Estimates aggregate portfolio drawdowns and controls covariance drift boundaries.</p>
</div>
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono">A. Synthetic Portfolio Model & Asset Weightings</h4>
<p className="text-xs leading-relaxed text-slate-400">
Constructs a continuous synthetic asset representing your active weight allocations and its daily return track:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">Active Percentage Weighting (<InlineMath math="w_i" />) Calculation:</p>
<BlockMath math="w_i = \\frac{\\text{Shares}_i \\times P_{\\text{current}, i}}{\\sum_{j} \\text{Shares}_j \\times P_{\\text{current}, j}}" />
</div>
<div className="border-t border-slate-850 pt-3">
<p className="text-xs text-slate-400 mb-1">Synthetic Portfolio Log Return (<InlineMath math="R_{pt}" />):</p>
<BlockMath math="R_{pt} = \\sum_{i} w_i \\times \\ln\\left(\\frac{P_{t, i}}{P_{t-1, i}}\\right)" />
</div>
</div>
</div>
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono">B. Linear Mixed Effects Panel Regression (LMM)</h4>
<p className="text-xs leading-relaxed text-slate-400">
Solves the system-wide macro response model across all historical event instances <InlineMath math="j" /> using a Swamy-Arora GLS estimator:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">Panel Model Specification with VIX Controls:</p>
<BlockMath math="R_{ptj} = \\beta_0 + \\beta_{\\text{drift}} \\text{Pre}_t + \\beta_{\\text{impact}} \\text{Post}_t + \\beta_{\\text{VIX}} VIX_{tj} + u_j + e_{ptj}" />
<p className="text-[10px] text-slate-500 mt-2 font-mono leading-relaxed">
where:
<br />
- <InlineMath math="t \\in [-30, +30]" /> is the relative day offset from event date <InlineMath math="T_j" />.
<br />
- <InlineMath math="\\text{Pre}_t = \\mathbb{I}(t < 0)" /> and <InlineMath math="\\text{Post}_t = \\mathbb{I}(t > 0)" /> are relative phase indicators.
<br />
- <InlineMath math="VIX_{tj}" /> is the background market-wide volatility covariate.
<br />
- <InlineMath math="u_j \\sim N(0, \\sigma_u^2)" /> is the random group intercept (event instance shock).
<br />
- <InlineMath math="e_{ptj} \\sim N(0, \\sigma_e^2)" /> is the residual error.
</p>
</div>
<div className="border-t border-slate-850 pt-3">
<p className="text-xs text-slate-400 mb-1">Optimal Kelly Criterion Position Sizing:</p>
<BlockMath math="f^* = \\frac{p \\times b - (1 - p)}{b}" />
</div>
</div>
</div>
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono">C. Reinvestment & Optimization Generation</h4>
<p className="text-xs leading-relaxed text-slate-400">
Integrates signals across three engines: Scanner (underpriced value), Econometrics (macro event post-event betas), and Insiders (corporate buying).
Ranks candidates and suggests target reallocations.
</p>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -6,7 +6,7 @@ import { calculateEWMA, calculateKellyFraction, calculateAssetCovariance } from
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, ReferenceLine, AreaChart, Area } from 'recharts';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
import PortfolioMathModal from './PortfolioMathModal';
import SandboxMathModal from './SandboxMathModal';
import {
TrendingUp, Wallet, ArrowDownRight, ArrowUpRight, Percent, Plus, FolderSync,
HelpCircle, Settings, Calendar, DollarSign, Tag, Check, AlertCircle, ChevronDown, ChevronUp, Sparkles,
@@ -53,7 +53,7 @@ export default function SandboxDemo() {
const [simulateFees, setSimulateFees] = useState(true);
const [isBackfill, setIsBackfill] = useState(false);
const [backfillDate, setBackfillDate] = useState('2026-05-20');
const [hypothesisTag, setHypothesisTag] = useState('Fokus auf KI-Infrastruktur');
const [hypothesisTag, setHypothesisTag] = useState('Focus on AI Infrastructure');
const [orderError, setOrderError] = useState<string | null>(null);
const [orderSuccess, setOrderSuccess] = useState(false);
@@ -89,11 +89,11 @@ export default function SandboxDemo() {
const data = await response.json();
setStressData(data);
} else {
setStressError("Fehler beim Laden der Stresstest-Daten.");
setStressError("Error loading stress test data.");
}
} catch (err) {
console.error("Stress test fetch error:", err);
setStressError("Netzwerkfehler beim Laden des Stresstests.");
setStressError("Network error loading stress test.");
} finally {
setStressLoading(false);
}
@@ -174,7 +174,7 @@ export default function SandboxDemo() {
const shares = Number(newAssetShares);
const price = Number(newAssetPrice);
if (isNaN(shares) || shares <= 0 || isNaN(price) || price <= 0) {
alert("Bitte geben Sie eine gültige Stückzahl und einen Einstandskurs an.");
alert("Please enter a valid number of shares and entry price.");
return;
}
updatePortfolioAsset(ticker, shares, price);
@@ -307,7 +307,7 @@ export default function SandboxDemo() {
if (!mounted) {
return (
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl min-h-[400px] flex items-center justify-center">
<div className="text-slate-400 text-sm font-mono animate-pulse">Lade Sandbox-Modul...</div>
<div className="text-slate-400 text-sm font-mono animate-pulse">Loading Sandbox Module...</div>
</div>
);
}
@@ -331,7 +331,7 @@ export default function SandboxDemo() {
setOrderSuccess(false);
if (tradeShares <= 0 || tradePrice <= 0) {
setOrderError('Bitte geben Sie eine gültige Stückzahl und einen Kurs an.');
setOrderError('Please enter a valid number of shares and price.');
return;
}
@@ -354,8 +354,8 @@ export default function SandboxDemo() {
} else {
setOrderError(
tradeType === 'BUY'
? 'Unzureichendes Barguthaben (inklusive allfälliger Transaktionsgebühren).'
: 'Unzureichende Anteile im Depot für den Verkauf.'
? 'Insufficient cash balance (including transaction fees).'
: 'Insufficient shares in portfolio for sale.'
);
}
};
@@ -367,7 +367,7 @@ export default function SandboxDemo() {
<div className="bg-rose-950/40 border border-rose-800/80 text-rose-400 text-xs rounded-xl p-4 flex items-center gap-3 shadow-[0_0_15px_rgba(244,63,94,0.15)] animate-pulse">
<AlertCircle className="w-5 h-5 text-rose-400 shrink-0" />
<div className="flex-1">
<span className="font-bold">Kritische Klumpenrisiken (Kovarianz RED):</span> {activePortfolio.riskProfile.message}
<span className="font-bold">Critical Concentration Risks (Covariance RED):</span> {activePortfolio.riskProfile.message}
</div>
</div>
)}
@@ -395,7 +395,7 @@ export default function SandboxDemo() {
<button
onClick={() => setShowNewPortfolioModal(true)}
className="p-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-emerald-400 hover:text-emerald-300 transition-colors border border-slate-700"
title="Neues Sandbox-Portfolio erstellen"
title="Create new Sandbox Portfolio"
>
<Plus className="w-5 h-5" />
</button>
@@ -408,12 +408,12 @@ export default function SandboxDemo() {
className="flex items-center gap-1.5 px-4 py-3 rounded-xl bg-slate-950/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-emerald-400 justify-center h-[58px] shrink-0"
>
<BookOpen className="w-3.5 h-3.5" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
{/* Net Worth Card */}
<div className="flex-1 md:flex-initial bg-slate-950/80 border border-slate-800 rounded-xl p-3 px-5 min-w-[140px]">
<div className="text-[10px] text-slate-400 uppercase font-semibold">Gesamtwert</div>
<div className="text-[10px] text-slate-400 uppercase font-semibold">Total Value</div>
<div className="font-mono text-xl font-bold text-slate-100 mt-1">
${netWorth.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</div>
@@ -421,7 +421,7 @@ export default function SandboxDemo() {
{/* Performance Card */}
<div className="flex-1 md:flex-initial bg-slate-950/80 border border-slate-800 rounded-xl p-3 px-5 min-w-[140px]">
<div className="text-[10px] text-slate-400 uppercase font-semibold">GuV (Gesamt)</div>
<div className="text-[10px] text-slate-400 uppercase font-semibold">PnL (Total)</div>
<div className={`font-mono text-xl font-bold mt-1 flex items-center gap-1 ${isPositiveOverall ? 'text-emerald-400' : 'text-rose-400'}`}>
{isPositiveOverall ? <ArrowUpRight className="w-5 h-5" /> : <ArrowDownRight className="w-5 h-5" />}
<span>{isPositiveOverall ? '+' : ''}{totalGainLossPct.toFixed(2)}%</span>
@@ -431,8 +431,8 @@ export default function SandboxDemo() {
{/* Live EWMA Vol Card */}
<div className="flex-1 md:flex-initial bg-slate-950/80 border border-slate-800 rounded-xl p-3 px-5 min-w-[140px] relative group">
<div className="text-[10px] text-slate-400 uppercase font-semibold flex items-center gap-1">
<span>EWMA Volatilität</span>
<span className="cursor-help flex items-center" title="Annualisierte Schwankungsbreite basierend auf historischen Renditen.">
<span>EWMA Volatility</span>
<span className="cursor-help flex items-center" title="Annualized volatility based on historical returns.">
<HelpCircle className="w-3.5 h-3.5 text-slate-500 group-hover:text-emerald-400 transition-colors" />
</span>
</div>
@@ -444,8 +444,8 @@ export default function SandboxDemo() {
{/* Covariance Risk Traffic Light Card */}
<div className="flex-1 md:flex-initial bg-slate-950/80 border border-slate-800 rounded-xl p-3 px-5 min-w-[150px] relative group">
<div className="text-[10px] text-slate-400 uppercase font-semibold flex items-center gap-1">
<span>Kovarianz-Ampel</span>
<span className="cursor-help flex items-center" title="Systemische Portfolio-Klumpenrisiken basierend auf historischen Asset-Kovarianzen.">
<span>Covariance Traffic Light</span>
<span className="cursor-help flex items-center" title="Systemic portfolio concentration risks based on historical asset covariances.">
<HelpCircle className="w-3.5 h-3.5 text-slate-500 group-hover:text-rose-400 transition-colors" />
</span>
</div>
@@ -471,21 +471,21 @@ export default function SandboxDemo() {
{showNewPortfolioModal && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm p-4">
<div className="bg-slate-900 border border-slate-800 rounded-2xl p-6 max-w-sm w-full space-y-4 shadow-2xl">
<h3 className="text-lg font-bold text-white">Neues Sandbox-Portfolio</h3>
<h3 className="text-lg font-bold text-white">New Sandbox Portfolio</h3>
<form onSubmit={handleCreatePortfolio} className="space-y-4">
<div>
<label className="text-xs text-slate-400 block mb-1">Portfolio Name</label>
<input
type="text"
required
placeholder="z.B. Biotech Risk High Yield"
placeholder="e.g. Biotech Risk High Yield"
className="w-full bg-slate-950 border border-slate-800 rounded-lg p-2.5 text-slate-100 focus:outline-none focus:border-emerald-500"
value={newPortfolioName}
onChange={(e) => setNewPortfolioName(e.target.value)}
/>
</div>
<div>
<label className="text-xs text-slate-400 block mb-1">Startkapital ($)</label>
<label className="text-xs text-slate-400 block mb-1">Starting Capital ($)</label>
<input
type="number"
required
@@ -500,13 +500,13 @@ export default function SandboxDemo() {
onClick={() => setShowNewPortfolioModal(false)}
className="flex-1 bg-slate-850 hover:bg-slate-800 text-slate-300 font-semibold py-2 rounded-lg transition-colors border border-slate-700"
>
Abbrechen
Cancel
</button>
<button
type="submit"
className="flex-1 bg-gradient-to-r from-emerald-500 to-teal-500 hover:from-emerald-600 hover:to-teal-600 text-slate-950 font-bold py-2 rounded-lg transition-all shadow-lg shadow-emerald-500/20"
>
Erstellen
Create
</button>
</div>
</form>
@@ -521,53 +521,53 @@ export default function SandboxDemo() {
className="flex items-center gap-1.5 text-xs text-slate-400 hover:text-emerald-400 transition-colors focus:outline-none"
>
<span>{showMathAccordion ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}</span>
<span className="font-semibold uppercase tracking-wider">Mathematische Spezifikation & EWMA-Volatilitätsmodell</span>
<span className="font-semibold uppercase tracking-wider">Mathematical Specification & EWMA Volatility Model</span>
</button>
{showMathAccordion && (
<div className="mt-4 p-4 rounded-xl border border-slate-850 bg-slate-950/40 text-xs text-slate-300 space-y-4">
<div>
<h4 className="font-semibold text-emerald-400 mb-1.5">1. EWMA Volatilitätsmodell</h4>
<h4 className="font-semibold text-emerald-400 mb-1.5">1. EWMA Volatility Model</h4>
<p className="mb-2">
Die Volatilit&auml;t wird mittels des <strong>Exponentially Weighted Moving Average (EWMA)</strong>-Modells ermittelt. J&uuml;ngere Renditen erhalten hierbei ein h&ouml;heres Gewicht als weiter in der Vergangenheit liegende Renditen, gesteuert durch den Zerfallsparameter <InlineMath math="\lambda" /> (Lambda).
Volatility is calculated using the <strong>Exponentially Weighted Moving Average (EWMA)</strong> model. Recent returns receive a higher weighting than returns further in the past, controlled by the decay parameter <InlineMath math="\lambda" /> (Lambda).
</p>
<div className="py-2 overflow-x-auto">
<BlockMath math="\sigma_t^2 = \lambda \sigma_{t-1}^2 + (1 - \lambda) r_{t-1}^2" />
</div>
<p className="mb-2">
Die t&auml;gliche Volatilit&auml;t <InlineMath math="\sigma_t" /> wird auf ein ganzes Jahr hochgerechnet (Annualisierung) unter der Annahme von 252 Handelstagen:
The daily volatility <InlineMath math="\sigma_t" /> is extrapolated to an entire year (annualization) assuming 252 trading days:
</p>
<div className="py-2 overflow-x-auto">
<BlockMath math="\sigma_{\text{ann}} = \sqrt{\sigma_t^2 \times 252}" />
</div>
<p className="text-slate-400">
RiskMetrics empfiehlt f&uuml;r t&auml;gliche Finanzdaten einen Lambda-Wert von <InlineMath math="\lambda = 0.94" />.
RiskMetrics recommends a Lambda value of <InlineMath math="\lambda = 0.94" /> for daily financial data.
</p>
</div>
<div className="border-t border-slate-800 pt-3">
<h4 className="font-semibold text-emerald-400 mb-1.5">2. Kelly-Kriterium zur Positionsgrößenbestimmung</h4>
<h4 className="font-semibold text-emerald-400 mb-1.5">2. Kelly Criterion for Position Sizing</h4>
<p className="mb-2">
Die Kelly-Formel bestimmt den optimalen Anteil des Kapitals (<InlineMath math="f^*" />), der in ein Geschäft investiert werden soll, um das exponentielle Wachstum des Kapitals zu maximieren:
The Kelly formula determines the optimal fraction of capital (<InlineMath math="f^*" />) to invest in a trade to maximize the exponential growth of wealth:
</p>
<div className="py-2 overflow-x-auto">
<BlockMath math="f^* = \frac{p \cdot b - q}{b} = \frac{p \cdot b - (1 - p)}{b}" />
</div>
<p className="mb-2">
Um Risiken durch ungenaue Schätzungen zu verringern, wenden wir das konservative <strong>Half-Kelly</strong>-Sizing an und begrenzen das Ergebnis auf <InlineMath math="0.5 \times f^*" /> (zusätzlich begrenzt auf <InlineMath math="\ge 0" />).
To mitigate risks from inaccurate estimations, we apply the conservative <strong>Half-Kelly</strong> sizing and limit the result to <InlineMath math="0.5 \times f^*" /> (additionally constrained to <InlineMath math="\ge 0" />).
</p>
</div>
<div className="border-t border-slate-800 pt-3">
<h4 className="font-semibold text-rose-400 mb-1.5">3. Covariance & Cluster Risk (Kovarianz-Ampel)</h4>
<h4 className="font-semibold text-rose-400 mb-1.5">3. Covariance & Cluster Risk (Covariance Traffic Light)</h4>
<p className="mb-2">
Die Kovarianz zwischen Assets wird durch Multiplikation ihrer paarweisen Korrelation mit ihren jeweiligen Standardabweichungen (Volatilitäten) bestimmt:
The covariance between assets is determined by multiplying their pairwise correlation by their respective standard deviations (volatilities):
</p>
<div className="py-2 overflow-x-auto">
<BlockMath math="\text{Cov}(A, B) = \text{Corr}(A, B) \times \sigma_A \times \sigma_B" />
</div>
<p className="text-slate-400">
Ein <strong>Klumpenrisiko (Risk RED)</strong> wird ausgelöst, wenn ein Asset eine Korrelation <InlineMath math="\text{Corr}(A, B) > 0.70" /> zu bestehenden Positionen aufweist und diese Positionen jeweils mehr als 15% des Portfolios ausmachen.
A <strong>concentration risk (Risk RED)</strong> is triggered when an asset exhibits a correlation <InlineMath math="\text{Corr}(A, B) > 0.70" /> to existing positions and these positions each exceed 15% of the portfolio.
</p>
</div>
</div>
@@ -575,14 +575,14 @@ export default function SandboxDemo() {
</div>
</div>
{/* SECTION: Mein Portfolio Ingestion Cockpit */}
{/* SECTION: My Portfolio Ingestion Cockpit */}
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-4">
<div className="flex justify-between items-center border-b border-slate-800 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<Wallet className="text-emerald-400 w-5 h-5" /> Mein Portfolio Cockpit
<Wallet className="text-emerald-400 w-5 h-5" /> My Portfolio Cockpit
</h3>
<span className="text-xs text-slate-400 font-mono">
Gesamt-Inventarwert: <span className="text-emerald-400 font-bold font-mono">${portfolioCalculated.totalValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
Total Inventory Value: <span className="text-emerald-400 font-bold font-mono">${portfolioCalculated.totalValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</span>
</span>
</div>
@@ -591,20 +591,20 @@ export default function SandboxDemo() {
<thead>
<tr className="border-b border-slate-800 text-slate-400 font-semibold bg-slate-900/40">
<th className="p-3">Asset / Ticker</th>
<th className="p-3 text-center">Stücke (Shares)</th>
<th className="p-3 text-center">Einstandspreis</th>
<th className="p-3 text-center">Aktueller Kurs</th>
<th className="p-3 text-right">Positionswert</th>
<th className="p-3 text-center">Shares</th>
<th className="p-3 text-center">Entry Price</th>
<th className="p-3 text-center">Current Price</th>
<th className="p-3 text-right">Position Value</th>
<th className="p-3 text-right">Performance (PnL)</th>
<th className="p-3">Gewichtung (w_i)</th>
<th className="p-3 text-center">Aktionen</th>
<th className="p-3">Weighting (w_i)</th>
<th className="p-3 text-center">Actions</th>
</tr>
</thead>
<tbody>
{portfolioCalculated.items.length === 0 ? (
<tr>
<td colSpan={8} className="p-8 text-center text-slate-500 italic">
Bislang keine Assets im Ingestion-Cockpit. Fügen Sie unten ein Asset hinzu.
No assets in the Ingestion Cockpit yet. Add an asset below.
</td>
</tr>
) : (
@@ -687,7 +687,7 @@ export default function SandboxDemo() {
<button
onClick={() => removePortfolioAsset(item.ticker)}
className="p-1.5 rounded-lg bg-slate-950 hover:bg-rose-950/40 text-slate-500 hover:text-rose-400 transition-colors border border-slate-850 hover:border-rose-900/30 cursor-pointer"
title="Asset löschen"
title="Delete asset"
>
<Trash2 className="w-4 h-4" />
</button>
@@ -703,7 +703,7 @@ export default function SandboxDemo() {
<input
type="text"
required
placeholder="Ticker (z.B. AAPL)"
placeholder="Ticker (e.g. AAPL)"
className="w-full bg-slate-950 border border-slate-800 rounded-lg p-2 text-slate-100 font-mono text-xs uppercase focus:border-emerald-500 focus:outline-none"
value={newAssetTicker}
onChange={(e) => setNewAssetTicker(e.target.value)}
@@ -713,7 +713,7 @@ export default function SandboxDemo() {
<input
type="number"
required
placeholder="Stücke"
placeholder="Shares"
className="w-24 bg-slate-950 border border-slate-800 rounded-lg p-2 text-slate-100 font-mono text-xs text-center focus:border-emerald-500 focus:outline-none"
value={newAssetShares === '' ? '' : newAssetShares}
onChange={(e) => setNewAssetShares(e.target.value === '' ? '' : Number(e.target.value))}
@@ -723,7 +723,7 @@ export default function SandboxDemo() {
<input
type="number"
required
placeholder="Einstand ($)"
placeholder="Entry ($)"
className="w-28 bg-slate-950 border border-slate-800 rounded-lg p-2 text-slate-100 font-mono text-xs text-center focus:border-emerald-500 focus:outline-none"
value={newAssetPrice === '' ? '' : newAssetPrice}
onChange={(e) => setNewAssetPrice(e.target.value === '' ? '' : Number(e.target.value))}
@@ -736,9 +736,9 @@ export default function SandboxDemo() {
<td className="p-3 text-center">
<button
onClick={handleAddNewAsset}
className="bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-1.5 px-3 rounded-lg text-xs shadow-md shadow-emerald-500/10 flex items-center justify-center gap-1 mx-auto transition-all active:scale-[0.96] cursor-pointer animate-pulse hover:animate-none"
className="bg-emerald-500 hover:bg-emerald-600 text-slate-950 font-bold py-1.5 px-3 rounded-lg text-xs shadow-md shadow-emerald-500/10 flex items-center justify-center gap-1 mx-auto transition-all active:scale-[0.96] cursor-pointer"
>
<Plus className="w-3.5 h-3.5" /> Hinzufügen
<Plus className="w-3.5 h-3.5" /> Add
</button>
</td>
</tr>
@@ -747,15 +747,15 @@ export default function SandboxDemo() {
</div>
</div>
{/* SECTION: Systemischer Makro-Stresstest (Portfolio-LMM) */}
{/* SECTION: Systemic Macro Stress Test (Portfolio LMM) */}
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-6">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 border-b border-slate-800 pb-3">
<div className="space-y-1">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<TrendingUp className="text-purple-400 w-5 h-5" /> Systemischer Makro-Stresstest (Portfolio-LMM)
<TrendingUp className="text-purple-400 w-5 h-5" /> Systemic Macro Stress Test (Portfolio LMM)
</h3>
<p className="text-xs text-slate-400">
Analysiert die historische Sensitivität des Portfolios gegenüber Kern-Makro-Ereignissen über die letzten 36 Monate.
Analyzes the historical sensitivity of the portfolio to core macro events over the last 36 months.
</p>
</div>
{/* Event type tabs */}
@@ -779,18 +779,18 @@ export default function SandboxDemo() {
{stressLoading ? (
<div className="h-80 flex flex-col items-center justify-center space-y-3">
<div className="w-8 h-8 rounded-full border-2 border-purple-500 border-t-transparent animate-spin" />
<span className="text-xs text-slate-400 font-mono animate-pulse">Kalkuliere Swamy-Arora GLS-Schätzer...</span>
<span className="text-xs text-slate-400 font-mono animate-pulse">Calculating Swamy-Arora GLS estimators...</span>
</div>
) : stressError || !stressData ? (
<div className="h-80 flex items-center justify-center text-slate-500 italic">
{stressError || 'Keine Daten geladen.'}
{stressError || 'No data loaded.'}
</div>
) : (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* LMM Summary Statistics */}
<div className="bg-slate-950/40 rounded-xl p-4 border border-slate-850 flex flex-col justify-between space-y-4">
<div>
<span className="text-[10px] uppercase tracking-wider text-purple-400 font-bold block mb-2">Regressions-Koeffizienten (GLS)</span>
<span className="text-[10px] uppercase tracking-wider text-purple-400 font-bold block mb-2">Regression Coefficients (GLS)</span>
{/* Fixed Effects list */}
<div className="space-y-3">
@@ -803,13 +803,13 @@ export default function SandboxDemo() {
}`}>
<div>
<div className={`text-xs font-semibold ${isImpact ? 'text-purple-300 font-bold' : 'text-slate-350'}`}>
{fe.name === 'Intercept' ? 'Basisschnittstelle (Intercept)' :
{fe.name === 'Intercept' ? 'Baseline Intercept' :
fe.name === 'Pre-Event Drift' ? 'Pre-Event Trend (Drift)' :
fe.name === 'Post-Event Impact' ? 'Systemisches Portfolio Beta' :
'VIX-Volatilitäts-Sensitivität'}
fe.name === 'Post-Event Impact' ? 'Systemic Portfolio Beta' :
'VIX Volatility Sensitivity'}
</div>
<div className="text-[9px] text-slate-500">
SE: {fe.se.toFixed(4)} | p-Wert: {fe.pVal.toFixed(4)}
SE: {fe.se.toFixed(4)} | p-value: {fe.pVal.toFixed(4)}
</div>
</div>
<div className="text-right">
@@ -830,7 +830,7 @@ export default function SandboxDemo() {
{/* Model Fit metrics */}
<div className="border-t border-slate-850 pt-3 space-y-2">
<div className="flex justify-between text-xs">
<span className="text-slate-400">R-Quadrat (Bestimmtheitsmaß):</span>
<span className="text-slate-400">R-Squared:</span>
<span className="font-mono font-bold text-slate-200">{(stressData.regressionResults?.rSquared * 100).toFixed(1)}%</span>
</div>
<div className="flex justify-between text-[11px] text-slate-500 font-mono">
@@ -844,8 +844,8 @@ export default function SandboxDemo() {
{/* Recharts Area/Line Chart (2/3 width) */}
<div className="lg:col-span-2 bg-slate-950/30 rounded-xl p-4 border border-slate-850 space-y-3">
<div className="flex justify-between items-center text-xs">
<span className="text-slate-400 font-mono">Durchschnittlicher kumulierter Ertrag im Zeitfenster [-30, +30] Tage</span>
<span className="text-[9px] text-slate-500 font-mono">Akkumulierte Log-Renditen</span>
<span className="text-slate-400 font-mono">Average cumulative return in the [-30, +30] days window</span>
<span className="text-[9px] text-slate-500 font-mono">Accumulated log returns</span>
</div>
<div className="h-64 w-full">
@@ -875,7 +875,7 @@ export default function SandboxDemo() {
/>
<Tooltip
contentStyle={{ backgroundColor: '#090d16', borderColor: '#1e293b', borderRadius: '8px', fontSize: '11px' }}
labelFormatter={(label) => `Relativer Tag: T${label >= 0 ? '+' : ''}${label}`}
labelFormatter={(label) => `Relative Day: T${label >= 0 ? '+' : ''}${label}`}
/>
<Legend verticalAlign="top" height={36} iconType="circle" />
@@ -911,7 +911,7 @@ export default function SandboxDemo() {
stroke="#ef4444"
strokeWidth={1.5}
strokeDasharray="3 3"
label={{ value: 'Stichtag (T0)', fill: '#ef4444', fontSize: 9, position: 'top' }}
label={{ value: 'Event Date (T0)', fill: '#ef4444', fontSize: 9, position: 'top' }}
/>
</AreaChart>
</ResponsiveContainer>
@@ -925,7 +925,7 @@ export default function SandboxDemo() {
<div className="bg-purple-950/20 border border-purple-900/40 rounded-xl p-4 flex gap-3 items-start text-xs text-purple-300">
<Sparkles className="w-5 h-5 text-purple-400 shrink-0 mt-0.5" />
<div>
<span className="font-bold uppercase tracking-wider block mb-1">Quantitative Analyse-Auswertung</span>
<span className="font-bold uppercase tracking-wider block mb-1">Quantitative Analysis Evaluation</span>
<p className="leading-relaxed">
{(() => {
const impactBeta = stressData.regressionResults?.fixedEffects.find((f: any) => f.name === 'Post-Event Impact')?.estimate || 0;
@@ -934,17 +934,17 @@ export default function SandboxDemo() {
const pVal = stressData.regressionResults?.fixedEffects.find((f: any) => f.name === 'Post-Event Impact')?.pVal || 0;
const isSignificant = pVal < 0.05;
let eventNameText = activeStressTab === 'FOMC Rates' ? 'FOMC-Zinsentscheiden' :
activeStressTab === 'CPI Inflation' ? 'CPI-Inflationsdaten' : 'Arbeitsmarktdaten';
let eventNameText = activeStressTab === 'FOMC Rates' ? 'FOMC rate decisions' :
activeStressTab === 'CPI Inflation' ? 'CPI inflation releases' : 'labor market updates';
let significanceText = isSignificant
? `Dieser Effekt ist mit einem p-Wert von ${pVal.toFixed(4)} statistisch signifikant.`
: `Dieser Effekt ist mit einem p-Wert von ${pVal.toFixed(4)} statistisch nicht hochgradig signifikant (Rauscheinfluss möglich).`;
? `This effect is statistically significant with a p-value of ${pVal.toFixed(4)}.`
: `This effect is not highly statistically significant (potential noise) with a p-value of ${pVal.toFixed(4)}.`;
if (isNegative) {
return `Historische Reaktivität: Bei ${eventNameText} zeigt dein Depot ein negatives Beta von -${absBeta}. ${significanceText} Eine Absicherung über defensive Sektoren (z.B. Erhöhung der Bargeldquote oder defensive Consumer-Titel) senkt das Volatilitätsrisiko in dieser Post-Event-Phase um ca. ${Math.round(Math.abs(impactBeta) * 35)}%.`;
return `Historical reactivity: During ${eventNameText}, your portfolio exhibits a negative Beta of -${absBeta}. ${significanceText} Hedging via defensive sectors (e.g., increasing cash ratio or defensive consumer stocks) reduces volatility risk in this post-event phase by approx. ${Math.round(Math.abs(impactBeta) * 35)}%.`;
} else {
return `Historische Reaktivität: Bei ${eventNameText} zeigt dein Depot ein positives Beta von +${absBeta}. ${significanceText} Dein Portfolio profitiert tendenziell von der anschließenden Marktdynamik. Sie können erwägen, die Hebelwirkung durch Zukäufe in Momentum-Aktien zu erhöhen.`;
return `Historical reactivity: During ${eventNameText}, your portfolio exhibits a positive Beta of +${absBeta}. ${significanceText} Your portfolio tends to benefit from the subsequent market momentum. You might consider increasing leverage via momentum additions.`;
}
})()}
</p>
@@ -960,7 +960,7 @@ export default function SandboxDemo() {
<div className="xl:col-span-2 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-6">
<div className="flex justify-between items-center border-b border-slate-800 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<TrendingUp className="text-emerald-400 w-5 h-5" /> Portfolio Wertentwicklung & Benchmark
<TrendingUp className="text-emerald-400 w-5 h-5" /> Portfolio Performance & Benchmark
</h3>
<div className="flex items-center gap-3">
<label className="flex items-center gap-2 text-xs text-slate-400 cursor-pointer">
@@ -970,7 +970,7 @@ export default function SandboxDemo() {
onChange={(e) => setShowMsciBenchmark(e.target.checked)}
className="rounded border-slate-800 text-emerald-500 focus:ring-0 accent-emerald-500 w-4 h-4"
/>
<span>MSCI World (Benchmark) anzeigen</span>
<span>Show MSCI World (Benchmark)</span>
</label>
</div>
</div>
@@ -985,7 +985,7 @@ export default function SandboxDemo() {
<Legend verticalAlign="top" height={36} />
<Line type="monotone" dataKey="Portfolio" name={activePortfolio.name} stroke="#10b981" strokeWidth={3} dot={false} activeDot={{ r: 6 }} />
{showMsciBenchmark && (
<Line type="monotone" dataKey="MSCI World (Benchmark)" name="MSCI World Index (Normiert)" stroke="#3b82f6" strokeWidth={2} strokeDasharray="4 4" dot={false} />
<Line type="monotone" dataKey="MSCI World (Benchmark)" name="MSCI World Index (Normalized)" stroke="#3b82f6" strokeWidth={2} strokeDasharray="4 4" dot={false} />
)}
</LineChart>
</ResponsiveContainer>
@@ -994,8 +994,8 @@ export default function SandboxDemo() {
{/* EWMA parameter tuner slider */}
<div className="p-4 rounded-xl border border-slate-850 bg-slate-950/20 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<div className="space-y-1">
<h4 className="text-sm font-semibold text-slate-200">Parameteranpassung EWMA Lambda (&lambda;)</h4>
<p className="text-xs text-slate-400">Zerfallsfaktor steuert die Schock-Sensitivität des Volatilitätsmodells.</p>
<h4 className="text-sm font-semibold text-slate-200">Parameter Tuning EWMA Lambda (&lambda;)</h4>
<p className="text-xs text-slate-400">Decay factor controls the shock sensitivity of the volatility model.</p>
</div>
<div className="flex items-center gap-4 w-full sm:w-auto">
<input
@@ -1017,7 +1017,7 @@ export default function SandboxDemo() {
<div className="space-y-6">
<div className="border-b border-slate-800 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<Settings className="text-emerald-400 w-5 h-5" /> Order-Maske (Simuliert)
<Settings className="text-emerald-400 w-5 h-5" /> Order Mask (Simulated)
</h3>
</div>
@@ -1045,7 +1045,7 @@ export default function SandboxDemo() {
/>
</div>
<div>
<label className="text-xs text-slate-400 block mb-1">Stücke</label>
<label className="text-xs text-slate-400 block mb-1">Shares</label>
<input
type="number"
required
@@ -1055,7 +1055,7 @@ export default function SandboxDemo() {
/>
</div>
<div>
<label className="text-xs text-slate-400 block mb-1">Kurs ($)</label>
<label className="text-xs text-slate-400 block mb-1">Price ($)</label>
<input
type="number"
required
@@ -1073,14 +1073,14 @@ export default function SandboxDemo() {
onClick={() => setTradeType('BUY')}
className={`flex-1 py-1.5 text-xs font-bold rounded-lg transition-all ${tradeType === 'BUY' ? 'bg-emerald-500 text-slate-950 shadow-md shadow-emerald-500/10' : 'text-slate-400 hover:text-slate-200'}`}
>
Kauf (Long)
Buy (Long)
</button>
<button
type="button"
onClick={() => setTradeType('SELL')}
className={`flex-1 py-1.5 text-xs font-bold rounded-lg transition-all ${tradeType === 'SELL' ? 'bg-rose-500 text-white shadow-md shadow-rose-500/10' : 'text-slate-400 hover:text-slate-200'}`}
>
Verkauf (Short)
Sell (Short)
</button>
</div>
@@ -1102,15 +1102,15 @@ export default function SandboxDemo() {
onChange={(e) => setKellySource(e.target.value as any)}
className="w-full bg-slate-900 border border-slate-800 rounded px-1.5 py-1 text-[10px] text-slate-200 focus:outline-none"
>
<option value="custom">Manueller Regler</option>
<option value="scanner">El. 2 Scanner-Score</option>
<option value="crypto">El. 4 Bayes Posterior</option>
<option value="econometric">El. 5 ROC Breakout</option>
<option value="custom">Manual Slider</option>
<option value="scanner">Level 2 Scanner Score</option>
<option value="crypto">Level 4 Bayes Posterior</option>
<option value="econometric">Level 5 ROC Breakout</option>
</select>
</div>
<div>
<label className="text-[9px] text-slate-500 block mb-0.5 font-semibold uppercase">Odds-Verhältnis (b)</label>
<label className="text-[9px] text-slate-500 block mb-0.5 font-semibold uppercase">Odds Ratio (b)</label>
<input
type="number"
step="0.1"
@@ -1125,7 +1125,7 @@ export default function SandboxDemo() {
{kellySource === 'custom' && (
<div className="space-y-1">
<div className="flex justify-between text-[9px] text-slate-500">
<span>Erfolgswahrscheinlichkeit:</span>
<span>Probability of Success:</span>
<span className="font-mono text-emerald-400 font-bold">{(kellyProbability * 100).toFixed(0)}%</span>
</div>
<input
@@ -1142,7 +1142,7 @@ export default function SandboxDemo() {
{kellySource !== 'custom' && (
<div className="text-[9px] text-slate-400 flex justify-between bg-slate-900/40 p-1 px-1.5 rounded border border-slate-900">
<span>System-Wahrscheinlichkeit:</span>
<span>System Probability:</span>
<span className="font-mono text-emerald-400 font-bold">{(kellyProbability * 100).toFixed(1)}%</span>
</div>
)}
@@ -1151,18 +1151,18 @@ export default function SandboxDemo() {
<div className="p-2 bg-rose-500/10 text-rose-400 border border-rose-500/20 text-[9px] rounded flex items-start gap-1">
<AlertCircle className="w-3.5 h-3.5 shrink-0 text-rose-400" />
<div>
<strong>Klumpenrisiko!</strong> Korrelation &gt; 0.70 zu bestehenden Positionen. Kelly-Empfehlung wurde um 50% halbiert.
<strong>Concentration Risk!</strong> Correlation &gt; 0.70 to existing positions. Kelly recommendation halved by 50%.
</div>
</div>
)}
<div className="bg-slate-900/80 p-2 rounded-lg border border-slate-850 flex justify-between items-center text-xs">
<div>
<span className="block text-[9px] text-slate-500 uppercase font-semibold">Kelly-Anteil:</span>
<span className="font-mono font-bold text-slate-200">{(kellyFraction * 100).toFixed(1)}% des Cashs</span>
<span className="block text-[9px] text-slate-500 uppercase font-semibold">Kelly Fraction:</span>
<span className="font-mono font-bold text-slate-200">{(kellyFraction * 100).toFixed(1)}% of Cash</span>
</div>
<div className="text-right">
<span className="block text-[9px] text-slate-500 uppercase font-semibold">Kaufvolumen:</span>
<span className="block text-[9px] text-slate-500 uppercase font-semibold">Buy Volume:</span>
<span className="font-mono font-bold text-emerald-400">${Math.round(recommendedKellyCash).toLocaleString()}</span>
</div>
</div>
@@ -1173,11 +1173,11 @@ export default function SandboxDemo() {
<div>
<label className="text-xs text-slate-400 block mb-1 flex items-center gap-1">
<Tag className="w-3 h-3 text-emerald-400" />
<span>Hypothese / What-if Notiz</span>
<span>Hypothesis / What-if Note</span>
</label>
<input
type="text"
placeholder="z.B. Ferrari E-Auto Skepsis"
placeholder="e.g., Ferrari EV Skepticism"
className="w-full bg-slate-950 border border-slate-800 rounded-lg p-2 text-slate-100 text-xs focus:outline-none focus:border-emerald-500"
value={hypothesisTag}
onChange={(e) => setHypothesisTag(e.target.value)}
@@ -1187,7 +1187,7 @@ export default function SandboxDemo() {
{/* Fees Toggle */}
<div className="flex items-center justify-between border-t border-slate-850 pt-3 text-xs">
<span className="text-slate-400 flex items-center gap-1">
<DollarSign className="w-3.5 h-3.5 text-slate-500" /> Ordergebühren simulieren
<DollarSign className="w-3.5 h-3.5 text-slate-500" /> Simulate transaction fees
</span>
<input
type="checkbox"
@@ -1201,7 +1201,7 @@ export default function SandboxDemo() {
<div className="space-y-2 border-t border-slate-850 pt-3 text-xs">
<div className="flex items-center justify-between">
<span className="text-slate-400 flex items-center gap-1">
<Calendar className="w-3.5 h-3.5 text-slate-500" /> Historischer Backfill
<Calendar className="w-3.5 h-3.5 text-slate-500" /> Historical Backfill
</span>
<input
type="checkbox"
@@ -1231,7 +1231,7 @@ export default function SandboxDemo() {
{orderSuccess && (
<div className="p-3 rounded-lg bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 text-xs flex items-center gap-2">
<Check className="w-4 h-4 shrink-0" />
<span>Transaktion erfolgreich gebucht!</span>
<span>Transaction successfully recorded!</span>
</div>
)}
@@ -1239,7 +1239,7 @@ export default function SandboxDemo() {
type="submit"
className={`w-full font-bold py-2.5 px-4 rounded-lg transition-all active:scale-[0.98] mt-2 shadow-lg ${tradeType === 'BUY' ? 'bg-gradient-to-r from-emerald-500 to-teal-500 hover:from-emerald-600 hover:to-teal-600 text-slate-950 shadow-emerald-500/10' : 'bg-gradient-to-r from-rose-500 to-pink-500 hover:from-rose-600 hover:to-pink-600 text-white shadow-rose-500/10'}`}
>
Order an den Markt senden
Submit Order to Market
</button>
</form>
</div>
@@ -1254,10 +1254,10 @@ export default function SandboxDemo() {
<div className="xl:col-span-2 bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-4">
<div className="flex justify-between items-center border-b border-slate-800 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<TrendingUp className="text-emerald-400 w-5 h-5" /> Depotbestände ({activePortfolio.holdings.length})
<TrendingUp className="text-emerald-400 w-5 h-5" /> Portfolio Holdings ({activePortfolio.holdings.length})
</h3>
<div className="text-xs text-slate-400 flex items-center gap-4">
<span>Barguthaben: <span className="font-mono text-emerald-400 font-bold">${activePortfolio.cash.toLocaleString()}</span></span>
<span>Cash Balance: <span className="font-mono text-emerald-400 font-bold">${activePortfolio.cash.toLocaleString()}</span></span>
</div>
</div>
@@ -1266,18 +1266,18 @@ export default function SandboxDemo() {
<thead>
<tr className="border-b border-slate-800 text-slate-400 font-semibold bg-slate-900/40">
<th className="p-3">Asset</th>
<th className="p-3">Stücke</th>
<th className="p-3">Einstand</th>
<th className="p-3">Kurs</th>
<th className="p-3">Hypothese</th>
<th className="p-3 text-right">GuV</th>
<th className="p-3">Shares</th>
<th className="p-3">Avg Price</th>
<th className="p-3">Price</th>
<th className="p-3">Hypothesis</th>
<th className="p-3 text-right">PnL</th>
</tr>
</thead>
<tbody>
{activePortfolio.holdings.length === 0 ? (
<tr>
<td colSpan={6} className="p-8 text-center text-slate-500">
Keine Bestände in diesem Sandbox-Portfolio. Nutzen Sie die Order-Maske, um Werte hinzuzufügen.
No holdings in this Sandbox portfolio. Use the order mask to add assets.
</td>
</tr>
) : (
@@ -1313,13 +1313,13 @@ export default function SandboxDemo() {
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 text-slate-100 shadow-xl space-y-4">
<div className="border-b border-slate-800 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<Calendar className="text-emerald-400 w-5 h-5" /> Letzte Orderbuch-Einträge
<Calendar className="text-emerald-400 w-5 h-5" /> Recent Order Book Entries
</h3>
</div>
<div className="max-h-60 overflow-y-auto space-y-2 pr-1">
{activePortfolio.transactions.length === 0 ? (
<p className="text-xs text-slate-500 text-center py-8">Bislang keine Transaktionen in diesem Portfolio.</p>
<p className="text-xs text-slate-500 text-center py-8">No transactions in this portfolio yet.</p>
) : (
activePortfolio.transactions.map((tx) => {
const isBuy = tx.type === 'BUY';
@@ -1328,7 +1328,7 @@ export default function SandboxDemo() {
<div className="flex justify-between items-start">
<div className="flex items-center gap-2">
<span className={`px-1.5 py-0.5 rounded text-[9px] font-bold ${isBuy ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20' : 'bg-rose-500/10 text-rose-400 border border-rose-500/20'}`}>
{isBuy ? 'KAUF' : 'VERKAUF'}
{isBuy ? 'BUY' : 'SELL'}
</span>
<span className="font-mono font-bold text-slate-200">{tx.symbol}</span>
</div>
@@ -1336,8 +1336,8 @@ export default function SandboxDemo() {
</div>
<div className="flex justify-between text-xs font-mono text-slate-400">
<span>{tx.shares} Stk @ ${tx.price.toFixed(2)}</span>
<span className="text-[10px] text-slate-500">Gebühr: ${tx.feeApplied.toFixed(2)}</span>
<span>{tx.shares} shares @ ${tx.price.toFixed(2)}</span>
<span className="text-[10px] text-slate-500">Fee: ${tx.feeApplied.toFixed(2)}</span>
</div>
{tx.hypothesisTag && (
@@ -1355,7 +1355,7 @@ export default function SandboxDemo() {
</div>
<PortfolioMathModal isOpen={isMathModalOpen} onClose={() => setIsMathModalOpen(false)} />
<SandboxMathModal isOpen={isMathModalOpen} onClose={() => setIsMathModalOpen(false)} />
</div>
);
}

View File

@@ -0,0 +1,135 @@
import React from 'react';
import { BookOpen, X, TrendingUp, BarChart2, ShieldAlert } from 'lucide-react';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
interface SandboxMathModalProps {
isOpen: boolean;
onClose: () => void;
}
export default function SandboxMathModal({ isOpen, onClose }: SandboxMathModalProps) {
React.useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
};
if (isOpen) {
window.addEventListener('keydown', handleKeyDown);
}
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-955/90 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-350">
{/* Modal Header */}
<div className="flex justify-between items-center px-6 py-4 bg-slate-950/50 border-b border-slate-800/80">
<div>
<h2 className="text-base font-bold bg-gradient-to-r from-teal-400 to-emerald-400 bg-clip-text text-transparent flex items-center gap-2">
<BookOpen className="w-5 h-5 text-teal-400" /> Portfolio Sandbox - Math & Sizing Handbook
</h2>
<p className="text-[10px] text-slate-500 font-mono">Institutional Portfolio Construction & Allocation Spec</p>
</div>
<button
onClick={onClose}
className="text-slate-400 hover:text-slate-200 bg-slate-955/50 border border-slate-800 hover:border-slate-700 p-2 rounded-xl transition-all cursor-pointer flex items-center justify-center"
aria-label="Close modal"
>
<X className="w-4 h-4" />
</button>
</div>
{/* Modal Body */}
<div className="flex-1 overflow-y-auto p-6 sm:p-8 space-y-8 text-slate-300 scrollbar-thin">
{/* Section A: Synthetic Portfolio Model & Asset Weightings */}
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono flex items-center gap-1.5">
<TrendingUp className="w-3.5 h-3.5" /> A. Synthetic Portfolio Model & Asset Weightings
</h4>
<p className="text-xs leading-relaxed text-slate-400">
The sandbox constructs a continuous synthetic asset representing your active weight allocations and its daily return track:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">Active Percentage Weighting (<InlineMath math="w_i" />) Calculation:</p>
<BlockMath math="w_i = \\frac{\\text{Shares}_i \\times P_{\\text{current}, i}}{\\sum_{j} \\text{Shares}_j \\times P_{\\text{current}, j}}" />
</div>
<div className="border-t border-slate-850 pt-3">
<p className="text-xs text-slate-400 mb-1">Synthetic Portfolio Log Return (<InlineMath math="R_{pt}" />):</p>
<BlockMath math="R_{pt} = \\sum_{i} w_i \\times \\ln\\left(\\frac{P_{t, i}}{P_{t-1, i}}\\right)" />
</div>
</div>
</div>
{/* Section B: Linear Mixed Effects Panel Regression (LMM) */}
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono flex items-center gap-1.5">
<BarChart2 className="w-3.5 h-3.5" /> B. Linear Mixed Effects Panel Regression (LMM)
</h4>
<p className="text-xs leading-relaxed text-slate-400">
Solves the system-wide macro response model across all historical event instances <InlineMath math="j" /> using a Swamy-Arora GLS estimator:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2">
<div>
<p className="text-xs text-slate-400 mb-1">Panel Model Specification with VIX Controls:</p>
<BlockMath math="R_{ptj} = \\beta_0 + \\beta_{\\text{drift}} \\text{Pre}_t + \\beta_{\\text{impact}} \\text{Post}_t + \\beta_{\\text{VIX}} VIX_{tj} + u_j + e_{ptj}" />
<p className="text-[10px] text-slate-500 mt-2 font-mono leading-relaxed">
where:
<br />
- <InlineMath math="t \\in [-30, +30]" /> is the relative day offset from event date <InlineMath math="T_j" />.
<br />
- <InlineMath math="\\text{Pre}_t = \\mathbb{I}(t < 0)" /> and <InlineMath math="\\text{Post}_t = \\mathbb{I}(t > 0)" /> are relative phase indicators.
<br />
- <InlineMath math="VIX_{tj}" /> is the background market-wide volatility covariate.
<br />
- <InlineMath math="u_j \\sim N(0, \\sigma_u^2)" /> is the random group intercept (event instance shock).
<br />
- <InlineMath math="e_{ptj} \\sim N(0, \\sigma_e^2)" /> is the residual error.
</p>
</div>
</div>
</div>
{/* Section C: Kelly Criterion & Fractional Betting Sizing */}
<div className="space-y-3">
<h4 className="text-xs font-bold text-teal-400 uppercase tracking-wider font-mono flex items-center gap-1.5">
<ShieldAlert className="w-3.5 h-3.5" /> C. Kelly Criterion & Fractional Betting Sizing
</h4>
<p className="text-xs leading-relaxed text-slate-400">
The Kelly Criterion optimizes allocation sizing to maximize the expected value of the logarithm of wealth, balancing capital preservation with growth:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">Theoretical Kelly Fraction (<InlineMath math="f^*" />) Equation:</p>
<BlockMath math="f^* = \\frac{p \\cdot b - (1 - p)}{b}" />
<p className="text-[10px] text-slate-500 mt-2 font-mono leading-relaxed">
where:
<br />
- <InlineMath math="p" /> is the probability of a positive outcome (rebound or trade success).
<br />
- <InlineMath math="b" /> is the payout odds ratio (average win size divided by average loss size).
</p>
</div>
<div className="border-t border-slate-850 pt-3">
<p className="text-xs text-slate-400 mb-1">Fractional Kelly (Half-Kelly) Safety Buffer:</p>
<BlockMath math="f_{\\text{applied}} = \\max\\left(0, 0.5 \\times f^*\\right)" />
<p className="text-xs text-slate-400 leading-relaxed mt-2">
To mitigate estimation variance and protect against catastrophic drawdown due to model error or fat-tailed market returns, the cockpit clips the suggested sizing to a **Half-Kelly** multiplier ($0.5$).
</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -573,7 +573,7 @@ export default function ScannerDemo() {
)}
</h2>
<p className="text-slate-400 text-xs max-w-2xl">
Isoliert Kursstürze &gt; 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.
Isolates price crashes &gt; 5% under relative market stability (S&P 500 drifting sideways or rising). Measures asymmetry using GJR-GARCH to separate panic from structural risks.
</p>
</div>
@@ -583,7 +583,7 @@ export default function ScannerDemo() {
className="flex items-center gap-1.5 px-4 py-3 rounded-xl bg-slate-950/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-amber-400 justify-center"
>
<BookOpen className="w-3.5 h-3.5" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
<button
@@ -592,7 +592,7 @@ export default function ScannerDemo() {
className="bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600 disabled:from-amber-850 disabled:to-orange-900 disabled:text-slate-400 text-slate-950 font-bold py-3 px-6 rounded-xl transition-all shadow-lg shadow-amber-500/10 flex items-center justify-center gap-2 active:scale-[0.98]"
>
<RefreshCw className={`w-5 h-5 ${scanning ? 'animate-spin' : ''}`} />
<span>{scanning ? 'Scanne Markt...' : 'Markt scannen'}</span>
<span>{scanning ? 'Scanning Market...' : 'Scan Market'}</span>
</button>
{scanning && (
<span className="text-[10px] text-amber-400 font-mono text-center md:text-right animate-pulse">{scanProgress}</span>
@@ -604,11 +604,11 @@ export default function ScannerDemo() {
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 border-t border-slate-850 pt-5 mt-5">
{/* Mode Toggles */}
<div className="space-y-2">
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-semibold block">Screener-Modus</span>
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-semibold block">Screener Mode</span>
<div className="flex flex-wrap gap-1.5 bg-slate-950/60 p-1 rounded-xl border border-slate-800/80 w-fit">
{[
{ id: 'day_crash', label: 'Day-Crashs' },
{ id: 'ma_drop', label: 'MA-Drop (SMA50)' },
{ id: 'day_crash', label: 'Day Crashes' },
{ id: 'ma_drop', label: 'MA Drop (SMA50)' },
{ id: '52w_dist', label: '52W-Distance' },
{ id: 'rsi_oversold', label: 'RSI-Oversold' }
].map((m) => (
@@ -629,7 +629,7 @@ export default function ScannerDemo() {
{/* Region Toggles */}
<div className="space-y-2 md:text-right">
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-semibold block md:pr-1">Markt-Region</span>
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-semibold block md:pr-1">Market Region</span>
<div className="flex flex-wrap gap-1.5 bg-slate-950/60 p-1 rounded-xl border border-slate-800/80 w-fit md:ml-auto">
{[
{ id: 'us', label: 'US Markets' },

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { BookOpen } from 'lucide-react';
import { BookOpen, X } from 'lucide-react';
import 'katex/dist/katex.min.css';
import { BlockMath, InlineMath } from 'react-katex';
@@ -26,8 +26,8 @@ export default function ScannerMathModal({ isOpen, onClose }: ScannerMathModalPr
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-950/85 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-300">
<div className="fixed inset-0 z-50 flex items-center justify-center bg-slate-955/90 backdrop-blur-md p-4 sm:p-6 md:p-8">
<div className="bg-slate-900 border border-slate-800/80 rounded-3xl w-full max-w-4xl h-[80vh] flex flex-col overflow-hidden shadow-2xl relative text-slate-350">
{/* Modal Header */}
<div className="flex justify-between items-center px-6 py-4 bg-slate-950/40 border-b border-slate-800/60">
@@ -39,9 +39,10 @@ export default function ScannerMathModal({ isOpen, onClose }: ScannerMathModalPr
</div>
<button
onClick={onClose}
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 px-3 py-1.5 rounded-lg text-xs font-semibold font-mono transition-all cursor-pointer"
className="text-slate-400 hover:text-slate-200 bg-slate-950/50 border border-slate-800 hover:border-slate-700 p-2 rounded-xl transition-all cursor-pointer flex items-center justify-center"
aria-label="Close modal"
>
Schließen (ESC)
<X className="w-4 h-4" />
</button>
</div>
@@ -59,15 +60,15 @@ export default function ScannerMathModal({ isOpen, onClose }: ScannerMathModalPr
Scans the entire corporate equity universe daily, segmenting equities into three distinct market capitalization classes to identify localized overreactions:
</p>
<div className="grid grid-cols-3 gap-3 text-[11px] text-slate-400 font-mono text-center">
<div className="bg-slate-950/40 p-3 rounded-lg border border-slate-800/50">
<div className="bg-slate-955/40 p-3 rounded-lg border border-slate-800/50">
<span className="block font-bold text-slate-300">Mega Caps</span>
<span>&gt; $100B</span>
</div>
<div className="bg-slate-950/40 p-3 rounded-lg border border-slate-800/50">
<div className="bg-slate-955/40 p-3 rounded-lg border border-slate-800/50">
<span className="block font-bold text-slate-300">Mid Caps</span>
<span>$10B - $100B</span>
</div>
<div className="bg-slate-950/40 p-3 rounded-lg border border-slate-800/50">
<div className="bg-slate-955/40 p-3 rounded-lg border border-slate-800/50">
<span className="block font-bold text-slate-300">Small Caps</span>
<span>&lt; $10B</span>
</div>
@@ -79,20 +80,20 @@ export default function ScannerMathModal({ isOpen, onClose }: ScannerMathModalPr
<p className="text-xs leading-relaxed text-slate-400">
Calculates price distance ratios relative to support levels:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div className="bg-slate-955/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div>
<p className="text-xs text-slate-400 mb-1">1. 52-Week High Deviation:</p>
<BlockMath math="\Delta_{52w} = \frac{P_{\text{current}} - P_{52w\_high}}{P_{52w\_high}}" />
<BlockMath math="\\Delta_{52w} = \\frac{P_{\\text{current}} - P_{52w\\_high}}{P_{52w\\_high}}" />
</div>
<div>
<p className="text-xs text-slate-400 mb-1">2. 50-Day Moving Average Drop:</p>
<BlockMath math="\Delta_{MA} = \frac{P_{\text{current}} - \text{MA}_{50}}{\text{MA}_{50}}" />
<BlockMath math="\\Delta_{MA} = \\frac{P_{\\text{current}} - \\text{MA}_{50}}{\\text{MA}_{50}}" />
</div>
<div>
<p className="text-xs text-slate-400 mb-1">3. Relative Strength Index (RSI-14) with smoothing:</p>
<BlockMath math="\text{RSI} = 100 - \frac{100}{1 + \text{RS}}" />
<BlockMath math="\text{RS} = \frac{\text{Smoothed Gain}_t}{\text{Smoothed Loss}_t}" />
<p className="text-[11px] text-slate-505 mt-2 font-mono">
<BlockMath math="\\text{RSI} = 100 - \\frac{100}{1 + \\text{RS}}" />
<BlockMath math="\\text{RS} = \\frac{\\text{Smoothed Gain}_t}{\\text{Smoothed Loss}_t}" />
<p className="text-[11px] text-slate-500 mt-2 font-mono">
where smoothed elements use Welles Wilder alpha = 1/14. Deep oversold signals trigger at RSI &lt; 30.
</p>
</div>
@@ -104,19 +105,19 @@ export default function ScannerMathModal({ isOpen, onClose }: ScannerMathModalPr
<p className="text-xs leading-relaxed text-slate-400">
To avoid value traps, technical drop factors are coupled with valuation metrics fetched in real-time from FMP:
</p>
<div className="bg-slate-950/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<div className="bg-slate-955/40 p-4 rounded-xl border border-slate-800/60 my-2 space-y-4">
<ul className="list-disc pl-5 text-xs text-slate-400 space-y-2 font-mono">
<li><strong>Trailing P/E (KGV)</strong>: Measures the price relative to trailing 12-month earnings.</li>
<li><strong>Price-to-Book (KBV)</strong>: Measures the asset backing relative to equity capital.</li>
<li><strong>Trailing P/E</strong>: Measures the price relative to trailing 12-month earnings.</li>
<li><strong>Price-to-Book</strong>: Measures the asset backing relative to equity capital.</li>
<li><strong>Dividend Yield (%)</strong>: Tangible dividend payouts to measure cash backflow support.</li>
<li><strong>PEG Ratio</strong>: Relates PE multiple to annual earnings growth:
<BlockMath math="\text{PEG} = \frac{\text{PE Ratio}}{\text{Earnings Growth Rate} \times 100}" />
<BlockMath math="\\text{PEG} = \\frac{\\text{PE Ratio}}{\\text{Earnings Growth Rate} \\times 100}" />
</li>
</ul>
<div className="border-t border-slate-850 pt-3">
<p className="text-xs text-slate-400 mb-1">Implicit Forward P/E calculation from PEG relationship:</p>
<BlockMath math="\text{Forward PE} = \frac{\text{Trailing PE}}{1 + g_{\text{implicit}}}" />
<BlockMath math="g_{\text{implicit}} = \frac{\text{Trailing PE}}{\text{PEG} \times 100}" />
<BlockMath math="\\text{Forward PE} = \\frac{\\text{Trailing PE}}{1 + g_{\\text{implicit}}}" />
<BlockMath math="g_{\\text{implicit}} = \\frac{\\text{Trailing PE}}{\\text{PEG} \\times 100}" />
<p className="text-[11px] text-slate-500 mt-2 font-mono">
If PEG is unavailable, a default growth rate of 10% is assumed as a conservative fallback baseline.
</p>

View File

@@ -213,12 +213,12 @@ export default function AiSpecialSilo() {
{isShieldActive ? (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-amber-500/10 text-amber-400 border border-amber-500/20 shadow-[0_0_10px_rgba(245,158,11,0.15)] ml-2 animate-pulse">
<span className="w-1.5 h-1.5 rounded-full bg-amber-500" />
DEV-ARCHIV AKTIV (0 CALLS)
DEV ARCHIVE ACTIVE (0 CALLS)
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 shadow-[0_0_10px_rgba(16,185,129,0.15)] ml-2">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-ping" />
LIVE-API ENDPUNKT (FMP CORPO)
LIVE API ENDPOINT (FMP CORPO)
</span>
)}
</h2>
@@ -233,7 +233,7 @@ export default function AiSpecialSilo() {
className="flex items-center gap-1.5 px-4 py-2.5 rounded-xl bg-slate-955/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-teal-400 w-full md:w-auto justify-center h-11 cursor-pointer"
>
<BookOpen className="w-4 h-4" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
<div className="bg-slate-955/80 border border-slate-800 rounded-xl px-4 py-2 text-right shrink-0 h-11 flex flex-col justify-center">

View File

@@ -198,21 +198,21 @@ export default function TechMathModal({ isOpen, onClose }: TechMathModalProps) {
<p className="text-xs text-slate-300 mb-2 font-semibold">
{"Formula for Accruals (\\(\\text{Accruals}\\)):"}
</p>
<BlockMath math="\text{Accruals}_{t} = \text{Net Income}_{t} - (\text{CFO}_{t} + \text{CFI}_{t})" />
<BlockMath math="\\text{Accruals}_{t} = \\text{Net Income}_{t} - (\\text{CFO}_{t} + \\text{CFI}_{t})" />
<p className="text-xs text-slate-300 my-2 font-semibold">
{"Formula for Sloan Ratio (\\(\\text{Sloan Ratio}\\)):"}
</p>
<BlockMath math="\text{Sloan Ratio}_{t} = \frac{\text{Accruals}_{t}}{\text{Total Assets}_{t}} \times 100" />
<BlockMath math="\\text{Sloan Ratio}_{t} = \\frac{\\text{Accruals}_{t}}{\\text{Total Assets}_{t}} \\times 100" />
<p className="text-[10px] text-slate-555 mt-3 font-mono leading-relaxed">
{"Where:"}
<br />
{"- "}<InlineMath math="\text{Net Income}_{t}" />{" is the company's net income for the fiscal period."}
{"- "}<InlineMath math="\\text{Net Income}_{t}" />{" is the company's net income for the fiscal period."}
<br />
{"- "}<InlineMath math="\text{CFO}_{t}" />{" is Cash Flow from Operations (operating cash flow)."}
{"- "}<InlineMath math="\\text{CFO}_{t}" />{" is Cash Flow from Operations (operating cash flow)."}
<br />
{"- "}<InlineMath math="\text{CFI}_{t}" />{" is Cash Flow from Investing activities."}
{"- "}<InlineMath math="\\text{CFI}_{t}" />{" is Cash Flow from Investing activities."}
<br />
{"- "}<InlineMath math="\text{Total Assets}_{t}" />{" is the total assets reported on the balance sheet at the end of the period."}
{"- "}<InlineMath math="\\text{Total Assets}_{t}" />{" is the total assets reported on the balance sheet at the end of the period."}
</p>
</div>
<p className="text-xs leading-relaxed text-slate-400">

View File

@@ -90,9 +90,9 @@ export default function WhaleMathModal({ isOpen, onClose }: WhaleMathModalProps)
<div className="bg-slate-955/40 p-5 rounded-2xl border border-slate-850 my-2 space-y-4">
<div>
<p className="text-xs text-slate-300 mb-2 font-semibold">Velocity of Conviction (VoC) Delta:</p>
<BlockMath math="\text{VoC}_{i} = w_{i, t} - w_{i, t-1}" />
<BlockMath math="\\text{VoC}_{i} = w_{i, t} - w_{i, t-1}" />
<p className="text-xs text-slate-300 my-2 font-semibold">Asset Portfolio Weight Calculation:</p>
<BlockMath math="w_{i, t} = \frac{V_{i, t}}{\sum_{j} V_{j, t}} \times 100" />
<BlockMath math="w_{i, t} = \\frac{V_{i, t}}{\\sum_{j} V_{j, t}} \\times 100" />
<p className="text-[10px] text-slate-500 mt-3 font-mono leading-relaxed">
Where:
<br />
@@ -102,7 +102,7 @@ export default function WhaleMathModal({ isOpen, onClose }: WhaleMathModalProps)
<br />
- <InlineMath math="V_{i, t}" /> is the market value of the position in asset \(i\) as reported in the 13F filing for quarter \(t\).
<br />
- <InlineMath math="\sum_{j} V_{j, t}" /> represents the total market value of all reported equity holdings in the filing for quarter \(t\) (AUM proxy).
- <InlineMath math="\\sum_{j} V_{j, t}" /> represents the total market value of all reported equity holdings in the filing for quarter \(t\) (AUM proxy).
</p>
</div>
<p className="text-xs leading-relaxed text-slate-400">

View File

@@ -106,12 +106,12 @@ export default function WhaleScreener() {
{isShieldActive ? (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-amber-500/10 text-amber-400 border border-amber-500/20 shadow-[0_0_10px_rgba(245,158,11,0.15)] ml-2 animate-pulse">
<span className="w-1.5 h-1.5 rounded-full bg-amber-500" />
DEV-ARCHIV AKTIV (0 CALLS)
DEV ARCHIVE ACTIVE (0 CALLS)
</span>
) : (
<span className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 shadow-[0_0_10px_rgba(16,185,129,0.15)] ml-2">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-ping" />
LIVE-API ENDPUNKT (FMP CORPO)
LIVE API ENDPOINT (FMP CORPO)
</span>
)}
</h2>
@@ -123,7 +123,7 @@ export default function WhaleScreener() {
<div className="flex items-center gap-3 w-full md:w-auto justify-end">
<button
onClick={() => setRefreshKey(prev => prev + 1)}
className="flex items-center justify-center p-2.5 rounded-xl bg-slate-950/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all text-slate-400 hover:text-slate-200 h-11 w-11 cursor-pointer"
className="flex items-center justify-center p-2.5 rounded-xl bg-slate-955/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all text-slate-400 hover:text-slate-200 h-11 w-11 cursor-pointer"
title="Refresh holdings"
>
<RefreshCw className="w-4 h-4" />
@@ -133,7 +133,7 @@ export default function WhaleScreener() {
className="flex items-center gap-1.5 px-4 py-2.5 rounded-xl bg-slate-955/80 hover:bg-slate-900 border border-slate-800 hover:border-slate-700 transition-all font-semibold text-xs tracking-wider text-blue-400 w-full md:w-auto justify-center h-11 cursor-pointer"
>
<BookOpen className="w-4 h-4" />
<span>📖 Modulerklärung</span>
<span>📖 Quantitative Handbook</span>
</button>
</div>
</div>