Closes #012 - Implement Sloan Ratio Accrual Radar
This commit is contained in:
@@ -25,6 +25,8 @@ interface SearchResult {
|
||||
returns: number[];
|
||||
currentPrice?: number;
|
||||
peakPrice?: number;
|
||||
sloanRatio?: number;
|
||||
sloanRegime?: 'SAFE' | 'ANOMALY';
|
||||
}
|
||||
|
||||
export default function ScannerDemo() {
|
||||
@@ -218,7 +220,9 @@ export default function ScannerDemo() {
|
||||
reboundScore: overreactionScore,
|
||||
returns: result.returns,
|
||||
currentPrice: result.currentPrice,
|
||||
peakPrice: result.peakPrice
|
||||
peakPrice: result.peakPrice,
|
||||
sloanRatio: result.sloanRatio,
|
||||
sloanRegime: result.sloanRegime
|
||||
};
|
||||
|
||||
setAlertsMetadata(prev => ({
|
||||
@@ -796,6 +800,26 @@ export default function ScannerDemo() {
|
||||
{searchResult.reboundScore}/100
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{searchResult.sloanRatio !== undefined && (
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-slate-400">Sloan Accrual Ratio:</span>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="font-mono font-bold text-slate-300">
|
||||
{searchResult.sloanRatio.toFixed(2)}%
|
||||
</span>
|
||||
{searchResult.sloanRegime === 'SAFE' ? (
|
||||
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[9px] font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||
SAFE
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[9px] font-bold bg-rose-500/10 text-rose-400 border border-rose-500/20 animate-pulse">
|
||||
ANOMALY
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="pt-2 border-t border-slate-900">
|
||||
<span className="text-[10px] text-slate-400 uppercase font-semibold block mb-1">KI-Kommentar:</span>
|
||||
|
||||
@@ -69,6 +69,19 @@ interface Payload {
|
||||
}[];
|
||||
}>;
|
||||
};
|
||||
sloan: {
|
||||
name: string;
|
||||
tickers: Record<string, {
|
||||
currentSloan: number;
|
||||
currentRegime: 'SAFE' | 'ANOMALY';
|
||||
data: {
|
||||
quarter: string;
|
||||
accruals: number;
|
||||
sloanRatio: number;
|
||||
regime: 'SAFE' | 'ANOMALY';
|
||||
}[];
|
||||
}>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -122,7 +135,7 @@ export default function AiSpecialSilo() {
|
||||
);
|
||||
}
|
||||
|
||||
const { monetizationGap, supplyChain, infrastructure } = payload.metrics;
|
||||
const { monetizationGap, supplyChain, infrastructure, sloan } = payload.metrics;
|
||||
|
||||
// HSL Status Colors based on metric thresholds
|
||||
const getMonetizationStatus = () => {
|
||||
@@ -151,9 +164,15 @@ export default function AiSpecialSilo() {
|
||||
return 'GREEN';
|
||||
};
|
||||
|
||||
const getSloanStatus = () => {
|
||||
const hasAnomaly = Object.values(sloan.tickers).some(t => t.currentRegime === 'ANOMALY');
|
||||
return hasAnomaly ? 'ANOMALY' : 'SAFE';
|
||||
};
|
||||
|
||||
const monetizationStatus = getMonetizationStatus();
|
||||
const supplyStatus = getSupplyChainStatus();
|
||||
const infraStatus = getInfrastructureStatus();
|
||||
const sloanStatus = getSloanStatus();
|
||||
|
||||
// Helper for trend icons
|
||||
const renderTrendIcon = (trend: 'UP' | 'DOWN' | 'FLAT', isDangerUp = false) => {
|
||||
@@ -227,8 +246,8 @@ export default function AiSpecialSilo() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 🚥 3 LARGE GLOWING NEON-AMPEL CARDS */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{/* 🚥 4 LARGE GLOWING NEON-AMPEL CARDS */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
|
||||
{/* CARD 1: ROI-to-CapEx & Monetization Gap */}
|
||||
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-850 rounded-2xl p-5 relative overflow-hidden shadow-lg flex flex-col justify-between min-h-[140px]">
|
||||
@@ -330,10 +349,46 @@ export default function AiSpecialSilo() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CARD 4: Sloan Earnings Quality */}
|
||||
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-850 rounded-2xl p-5 relative overflow-hidden shadow-lg flex flex-col justify-between min-h-[140px]">
|
||||
<div className="absolute top-0 right-0 w-24 h-24 bg-gradient-to-br from-teal-500/10 to-transparent rounded-full blur-2xl pointer-events-none" />
|
||||
<div className="flex justify-between items-start">
|
||||
<div className="space-y-1">
|
||||
<div className="text-[10px] text-teal-400 uppercase font-bold tracking-widest font-mono">4. Earnings Accrual Integrity</div>
|
||||
<div className="text-lg font-black text-white leading-tight">Sloan Earnings Quality</div>
|
||||
<div className="text-[10px] text-slate-400">Richard Sloan Accounting Anomaly Radar</div>
|
||||
</div>
|
||||
|
||||
<span className={`w-3.5 h-3.5 rounded-full ${
|
||||
sloanStatus === 'SAFE' ? 'bg-emerald-500 shadow-[0_0_10px_#10b981]' :
|
||||
'bg-rose-500 shadow-[0_0_10px_#f43f5e] animate-pulse'
|
||||
}`} />
|
||||
</div>
|
||||
|
||||
<div className="mt-4 pt-4 border-t border-slate-850 flex justify-between items-end">
|
||||
<div>
|
||||
<div className="text-[9px] uppercase font-mono text-slate-500">Max Accrual Spread</div>
|
||||
<div className="font-mono text-xl font-bold text-slate-200">
|
||||
{Math.max(...Object.values(sloan.tickers).map(t => Math.abs(t.currentSloan))).toFixed(1)}%
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-[9px] uppercase font-mono text-slate-500">Silo Status</div>
|
||||
<div className="text-xs font-semibold text-slate-300 flex items-center gap-1 justify-end">
|
||||
{sloanStatus === 'SAFE' ? (
|
||||
<span className="text-emerald-400">Safe Regime</span>
|
||||
) : (
|
||||
<span className="text-rose-400 animate-pulse font-bold">Anomaly Warning</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* DETAILED LEDGER GRID */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
|
||||
{/* PANEL A: ROI-TO-CAPEX & MONETIZATION GAPS */}
|
||||
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
||||
@@ -463,6 +518,66 @@ export default function AiSpecialSilo() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* PANEL D: SLOAN EARNINGS QUALITY ACCRUAL RADAR */}
|
||||
<div className="bg-slate-900/60 backdrop-blur-md border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
||||
<div className="space-y-0.5">
|
||||
<h3 className="text-sm font-bold text-white flex items-center gap-2">
|
||||
<Activity className="w-4 h-4 text-emerald-400" /> Sloan Accrual Quality Radar
|
||||
</h3>
|
||||
<p className="text-[10px] text-slate-400">
|
||||
Richard Sloan Accrual Index. Anomalies (>10% or <-10%) indicate aggressive accounting.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{Object.entries(sloan.tickers).map(([ticker, metrics]) => {
|
||||
const currentSloan = metrics.currentSloan;
|
||||
const isAnomaly = metrics.currentRegime === 'ANOMALY';
|
||||
|
||||
const highlightClass = isAnomaly
|
||||
? 'text-rose-400 font-bold animate-pulse'
|
||||
: 'text-emerald-400';
|
||||
|
||||
const strokeColor = isAnomaly
|
||||
? '#f43f5e'
|
||||
: '#10b981';
|
||||
|
||||
return (
|
||||
<div key={ticker} className="bg-slate-955/40 border border-slate-850 rounded-xl p-3 flex justify-between items-center hover:bg-slate-955/60 transition-colors">
|
||||
<div className="space-y-0.5 w-1/4">
|
||||
<div className="text-xs font-bold text-slate-200">{ticker}</div>
|
||||
<div className="text-[9px] text-slate-500 font-mono">
|
||||
Regime: {metrics.currentRegime}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Sparkline for Sloan Ratio */}
|
||||
<div className="w-1/3 h-8">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<LineChart data={metrics.data}>
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="sloanRatio"
|
||||
stroke={strokeColor}
|
||||
strokeWidth={1.5}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
|
||||
<div className="text-right w-1/3">
|
||||
<div className="text-[9px] text-slate-500 uppercase font-mono">Sloan Ratio</div>
|
||||
<div className={`font-mono text-sm font-bold ${highlightClass}`}>
|
||||
{currentSloan.toFixed(2)}%
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* PANEL C: SUPPLY CHAIN FLOW DETAILS */}
|
||||
|
||||
@@ -185,6 +185,46 @@ export default function TechMathModal({ isOpen, onClose }: TechMathModalProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section 5: Sloan Accrual Radar */}
|
||||
<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">
|
||||
<Percent className="w-3.5 h-3.5" /> 5. Sloan Earnings Quality Accrual Radar
|
||||
</h4>
|
||||
<p className="text-xs leading-relaxed text-slate-400">
|
||||
The Sloan Ratio identifies discrepancies between reported net income and actual cash flows. A high proportion of non-cash accruals signals low earnings quality and is a historically proven accounting anomaly predictor:
|
||||
</p>
|
||||
<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">
|
||||
{"Formula for Accruals (\\(\\text{Accruals}\\)):"}
|
||||
</p>
|
||||
<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" />
|
||||
<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."}
|
||||
<br />
|
||||
{"- "}<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."}
|
||||
<br />
|
||||
{"- "}<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">
|
||||
<strong className="text-teal-300">Regime Classifications:</strong>
|
||||
<br />
|
||||
{"- "}<strong className="text-emerald-400">Safe Regime (-10% to +10%):</strong>{" High earnings quality, where profits are strongly supported by actual cash flows."}
|
||||
<br />
|
||||
{"- "}<strong className="text-rose-400 font-bold">Anomaly Regime (> +10% or < -10%):</strong>{" Aggressive accounting or accrual expansion, indicating high earnings manipulation risk."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user