Closes #014 - System-wide handbook sweep, English consolidation & Crypto state persistence
This commit is contained in:
18
DEV_LOG.md
18
DEV_LOG.md
@@ -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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
16
app/page.tsx
16
app/page.tsx
@@ -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 Ö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 ökonometrische Modelle – von EWMA und GJR-GARCH Volatilitätsprognosen über Bayesianisches On-Chain-Lernen bis hin zu Überlebens- und LMM-Regressionsmodellen.
|
||||
This modular architecture pools advanced econometric models – 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>© 2026 QuantSandbox Inc. Alle Rechte vorbehalten.</p>
|
||||
<p>© 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>
|
||||
|
||||
@@ -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 & Derivate-Indikatoren ({activeCoin.ticker})
|
||||
<BarChart2 className="text-cyan-400 w-5 h-5" /> On-Chain & 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 & Kontrakte (OI)</h4>
|
||||
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Funding Rates & 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 & Liquidationen</h4>
|
||||
<h4 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">Positioning & 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 (α):</div>
|
||||
<div className="text-slate-400">Successes (α):</div>
|
||||
<div className="text-emerald-400 font-bold">{alphaSuccess}</div>
|
||||
<div className="text-slate-400">Fehlalarme (β):</div>
|
||||
<div className="text-slate-400">False Alarms (β):</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 & Random Forest)</span>
|
||||
<span className="font-semibold uppercase tracking-wider">Mathematical Formulation (Beta Update & 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. „Funding-Rate < -0.04%“ und „Open Interest > 10%“) 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 < -0.04%' and 'Open Interest > 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 fü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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }}>
|
||||
|
||||
@@ -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 > 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 > 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 > 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 > 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 & Bayesianische Kopplung)</span>
|
||||
<span className="font-semibold uppercase tracking-wider">Mathematical Formulation (Z-Score & 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 > 2.0 wird als Ausreißer (Anomaly Trigger) eingestuft, was einer Wahrscheinlichkeit von unter 2.27% für einen zufälligen Anstieg entspricht (einseitiger Test bei Normalverteilung).
|
||||
A Z-Score > 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 fü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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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ät wird mittels des <strong>Exponentially Weighted Moving Average (EWMA)</strong>-Modells ermittelt. Jüngere Renditen erhalten hierbei ein hö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ägliche Volatilitä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ür tä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 (λ)</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 (λ)</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 > 0.70 zu bestehenden Positionen. Kelly-Empfehlung wurde um 50% halbiert.
|
||||
<strong>Concentration Risk!</strong> Correlation > 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>
|
||||
);
|
||||
}
|
||||
|
||||
135
components/modules/sandbox/SandboxMathModal.tsx
Normal file
135
components/modules/sandbox/SandboxMathModal.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@@ -573,7 +573,7 @@ export default function ScannerDemo() {
|
||||
)}
|
||||
</h2>
|
||||
<p className="text-slate-400 text-xs max-w-2xl">
|
||||
Isoliert Kursstürze > 5% bei relativem Gesamtmarkt-Stopp (S&P 500 driftet seitwärts oder steigt). Misst die Asymmetrie mittels GJR-GARCH, um Panik von strukturellen Risiken zu separieren.
|
||||
Isolates price crashes > 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' },
|
||||
|
||||
@@ -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>> $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>< $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 < 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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user