Closes #023 - Isolated PEAD fundamental momentum screener integration

This commit is contained in:
Antigravity Agent
2026-06-14 16:00:36 +02:00
parent e7f0199967
commit 8ffe8de06a
3 changed files with 309 additions and 26 deletions

View File

@@ -11,7 +11,7 @@ import ScannerBlueprintModal from './ScannerBlueprintModal';
import {
ShieldAlert, Sparkles, RefreshCw, Flame, Search, Plus, Trash2,
ChevronDown, ChevronUp, AlertTriangle, CheckCircle2, XCircle, Info, Clock, Play,
BookOpen
BookOpen, TrendingUp
} from 'lucide-react';
// Predefined mock database for deep-check searches (Removed mock database)
@@ -30,6 +30,18 @@ interface SearchResult {
sloanRegime?: 'SAFE' | 'ANOMALY';
}
interface PEADData {
ticker: string;
name: string;
peadSector: string;
announcementDate: string;
daysElapsed: number;
epsActual: number;
epsConsensus: number;
surprisePercent: number;
driftStatus: 'Active Drift' | 'Consolidating';
}
export default function ScannerDemo() {
const { watchlist, addToWatchlist, removeFromWatchlist, simulateWatchlistTick, updateScannerAlerts } = useSandboxStore();
@@ -51,6 +63,14 @@ export default function ScannerDemo() {
const [isMathModalOpen, setIsMathModalOpen] = useState(false);
const [isBlueprintModalOpen, setIsBlueprintModalOpen] = useState(false);
const [isShieldActive, setIsShieldActive] = useState(false);
const [leftPanelTab, setLeftPanelTab] = useState<'screener' | 'pead'>('screener');
const [peadData, setPeadData] = useState<PEADData[]>([
{ ticker: 'NVDA', name: 'NVIDIA Corporation', peadSector: 'Technology', announcementDate: '2026-05-20', daysElapsed: 25, epsActual: 6.12, epsConsensus: 5.58, surprisePercent: 9.68, driftStatus: 'Active Drift' },
{ ticker: 'AAPL', name: 'Apple Inc.', peadSector: 'Technology', announcementDate: '2026-05-02', daysElapsed: 43, epsActual: 1.53, epsConsensus: 1.50, surprisePercent: 2.00, driftStatus: 'Consolidating' },
{ ticker: 'MSFT', name: 'Microsoft Corporation', peadSector: 'Technology', announcementDate: '2026-04-25', daysElapsed: 50, epsActual: 2.94, epsConsensus: 2.82, surprisePercent: 4.26, driftStatus: 'Consolidating' },
{ ticker: 'TSLA', name: 'Tesla Inc.', peadSector: 'Consumer Goods', announcementDate: '2026-04-23', daysElapsed: 52, epsActual: 0.45, epsConsensus: 0.51, surprisePercent: -11.76, driftStatus: 'Consolidating' },
{ ticker: 'JPM', name: 'JPMorgan Chase & Co.', peadSector: 'Financial Services', announcementDate: '2026-04-12', daysElapsed: 63, epsActual: 4.44, epsConsensus: 4.15, surprisePercent: 6.99, driftStatus: 'Consolidating' }
]);
// Cache for metadata and prices retrieved dynamically
const [alertsMetadata, setAlertsMetadata] = useState<Record<string, { name: string; whyDropped: string; sentiment: 'GREEN' | 'YELLOW' | 'RED' }>>({});
@@ -161,6 +181,24 @@ export default function ScannerDemo() {
setAlertsPrices(prev => ({ ...prev, ...newPrices }));
setActiveAlerts(newAlerts);
const peadList: PEADData[] = [];
results.forEach((r: any) => {
if (r.error || r.peadSector === 'Cryptocurrency') return;
peadList.push({
ticker: r.ticker,
name: r.name,
peadSector: r.peadSector || 'Conglomerate',
announcementDate: r.announcementDate || 'N/A',
daysElapsed: r.daysElapsed || 0,
epsActual: r.epsActual || 0,
epsConsensus: r.epsConsensus || 0,
surprisePercent: r.surprisePercent || 0,
driftStatus: r.driftStatus || 'Consolidating'
});
});
peadList.sort((a, b) => Math.abs(b.surprisePercent) - Math.abs(a.surprisePercent));
setPeadData(peadList);
// Update global store alerts for Sandbox module use
updateScannerAlerts(newAlerts);
@@ -717,38 +755,114 @@ export default function ScannerDemo() {
{/* SECTION 2: Scanned Anomalies & Sentiment Traffic Light */}
<div className="grid grid-cols-1 xl:grid-cols-3 gap-8">
{/* Left 2 Columns: 3-Tier Capacity Grid (Top 5 per tier) */}
{/* Left 2 Columns: 3-Tier Capacity Grid (Top 5 per tier) or PEAD Drift Radar */}
<div className="xl:col-span-2 space-y-6">
<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 justify-between items-center border-b border-slate-850 pb-3">
<h3 className="text-lg font-bold text-white flex items-center gap-2">
<Sparkles className="text-amber-400 w-5 h-5 animate-pulse" /> 3-Tier Screener Kapazitäts-Grid (Top 5)
</h3>
<div className="flex items-center gap-4">
<button
onClick={() => setLeftPanelTab('screener')}
className={`text-sm font-bold flex items-center gap-2 pb-1 transition-all cursor-pointer ${leftPanelTab === 'screener' ? 'text-white border-b-2 border-amber-500' : 'text-slate-400 hover:text-slate-200'}`}
>
<Sparkles className="text-amber-400 w-4 h-4 animate-pulse" /> 3-Tier Screener Capacity Grid
</button>
<button
onClick={() => setLeftPanelTab('pead')}
className={`text-sm font-bold flex items-center gap-2 pb-1 transition-all cursor-pointer ${leftPanelTab === 'pead' ? 'text-white border-b-2 border-amber-500' : 'text-slate-400 hover:text-slate-200'}`}
>
<TrendingUp className="text-amber-400 w-4 h-4" /> 🚀 PEAD Drift Radar
</button>
</div>
<span className="text-[10px] text-slate-400 font-mono">Modus: {scanMode.toUpperCase()} | Region: {marketRegion.toUpperCase()}</span>
</div>
<div className="space-y-6">
{/* Category A: Mega Caps */}
{renderCategoryTable(
"Kategorie A: Mega Caps (> 100B USD)",
"Großkonzerne mit hoher institutioneller Liquidität und marktbeherrschender Stellung",
categorizedResults.mega
)}
{leftPanelTab === 'screener' ? (
<div className="space-y-6">
{/* Category A: Mega Caps */}
{renderCategoryTable(
"Kategorie A: Mega Caps (> 100B USD)",
"Großkonzerne mit hoher institutioneller Liquidität und marktbeherrschender Stellung",
categorizedResults.mega
)}
{/* Category B: Mid Caps */}
{renderCategoryTable(
"Kategorie B: Mid Caps (10B - 100B USD)",
"Wachstumsstarke Standardwerte und etablierte Branchenführer",
categorizedResults.mid
)}
{/* Category B: Mid Caps */}
{renderCategoryTable(
"Kategorie B: Mid Caps (10B - 100B USD)",
"Wachstumsstarke Standardwerte und etablierte Branchenführer",
categorizedResults.mid
)}
{/* Category C: Small Caps */}
{renderCategoryTable(
"Kategorie C: Small Caps (< 10B USD)",
"Hochvolatile Nebenwerte, spekulative Nischenplayer und Krypto-Assets",
categorizedResults.small
)}
</div>
{/* Category C: Small Caps */}
{renderCategoryTable(
"Kategorie C: Small Caps (< 10B USD)",
"Hochvolatile Nebenwerte, spekulative Nischenplayer und Krypto-Assets",
categorizedResults.small
)}
</div>
) : (
<div className="space-y-4">
<div className="text-xs text-slate-400 leading-relaxed font-sans">
Monitors Post-Earnings Announcement Drift (PEAD) anomaly using standardized unanticipated earnings momentum.
</div>
<div className="overflow-x-auto rounded-xl border border-slate-850 bg-slate-950/40">
<table className="w-full text-left text-xs border-collapse min-w-[700px] font-mono">
<thead>
<tr className="border-b border-slate-900 text-slate-500 font-mono text-[10px] uppercase tracking-wider bg-slate-900/40">
<th className="py-2.5 px-3">Asset</th>
<th className="py-2.5 px-3">Sector</th>
<th className="py-2.5 px-3">Announcement Date</th>
<th className="py-2.5 px-3 text-right">Reported vs Consensus</th>
<th className="py-2.5 px-3 text-right">Surprise %</th>
<th className="py-2.5 px-3 text-center">Drift Status</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-900/60">
{peadData.length === 0 ? (
<tr>
<td colSpan={6} className="py-6 text-center text-slate-500 italic text-xs">
No equity assets available in scan history.
</td>
</tr>
) : (
peadData.map((pead) => {
const isPositive = pead.surprisePercent >= 0;
const isActiveDrift = pead.driftStatus === 'Active Drift';
return (
<tr key={pead.ticker} className="hover:bg-slate-850/10 transition-colors">
<td className="py-2.5 px-3 font-bold text-slate-200">
<span className="text-amber-400 block font-bold">{pead.ticker}</span>
<span className="text-[10px] text-slate-500 block font-normal">{pead.name}</span>
</td>
<td className="py-2.5 px-3 text-slate-400 font-sans text-xs">
{pead.peadSector}
</td>
<td className="py-2.5 px-3 text-slate-300 font-mono">
<span>{pead.announcementDate}</span>
<span className="text-[10px] text-slate-500 block">({pead.daysElapsed} days elapsed)</span>
</td>
<td className="py-2.5 px-3 text-right text-slate-300">
<span>{pead.epsActual.toFixed(2)}</span>
<span className="text-[10px] text-slate-500 block font-normal">vs {pead.epsConsensus.toFixed(2)}</span>
</td>
<td className={`py-2.5 px-3 text-right font-bold ${isPositive ? 'text-emerald-400' : 'text-rose-400'}`}>
{isPositive ? '+' : ''}{pead.surprisePercent.toFixed(2)}%
</td>
<td className="py-2.5 px-3 text-center">
<span className={`inline-flex items-center gap-1 px-2.5 py-0.5 rounded-full text-[9px] font-bold border ${isActiveDrift ? 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20 shadow-[0_0_8px_rgba(16,185,129,0.1)]' : 'bg-slate-900 text-slate-400 border-slate-800'}`}>
{pead.driftStatus}
</span>
</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
</div>
)}
</div>
</div>