import { useState, useEffect } from 'react'; import { patternsAPI } from '../api/client'; import { formatCurrency, detectCurrencyFromTicker } from '../utils/currencyUtils'; import TickerSearch from '../components/TickerSearch'; /* ── SVG Icons (no emojis) ─────────────────────────────────────────────── */ const ScanIcon = () => ; const ChartIcon = () => ; const CatalogIcon = () => ; const AccuracyIcon = () => ; const ArrowUp = () => ; const ArrowDown = () => ; const TABS = [ { id: 'scanner', label: 'Pattern Scanner', icon: }, { id: 'catalog', label: 'Pattern Catalog', icon: }, { id: 'accuracy', label: 'Accuracy Report', icon: }, ]; export default function PatternIntelligence() { const [activeTab, setActiveTab] = useState('scanner'); const [ticker, setTicker] = useState(''); const [period, setPeriod] = useState('2y'); const [horizon, setHorizon] = useState(5); const [loading, setLoading] = useState(false); const [analysis, setAnalysis] = useState(null); const [catalog, setCatalog] = useState(null); const [accuracy, setAccuracy] = useState(null); const [error, setError] = useState(''); const handleAnalyze = async () => { if (!ticker.trim()) return; setLoading(true); setError(''); try { const { data } = await patternsAPI.analyze({ ticker: ticker.toUpperCase(), period, horizon }); setAnalysis(data); } catch (err: any) { setError(err.response?.data?.detail || 'Analysis failed'); } finally { setLoading(false); } }; const loadCatalog = async () => { try { const { data } = await patternsAPI.catalog(); setCatalog(data); } catch (err) { setError('Failed to load catalog'); } }; const handleBacktestAccuracy = async () => { if (!ticker.trim()) return; setLoading(true); setError(''); try { const { data } = await patternsAPI.backtestAccuracy({ ticker: ticker.toUpperCase(), period: '5y', horizon }); setAccuracy(data); } catch (err: any) { setError(err.response?.data?.detail || 'Backtest failed'); } finally { setLoading(false); } }; useEffect(() => { if (activeTab === 'catalog' && !catalog) loadCatalog(); }, [activeTab]); const directionColor = (d: string) => { if (d === 'bullish' || d === 'strong_up') return 'var(--accent-green)'; if (d === 'bearish' || d === 'strong_down') return 'var(--accent-red, #ef4444)'; return 'var(--text-muted)'; }; const confidenceColor = (c: number) => { if (c >= 0.65) return 'var(--accent-green)'; if (c >= 0.45) return 'var(--accent-yellow, #f59e0b)'; return 'var(--accent-red, #ef4444)'; }; return (
{/* Header */}

Pattern Intelligence

AI-powered candlestick pattern recognition with LightGBM ensemble prediction

{/* Tabs */}
{TABS.map(tab => ( ))}
{/* Search Bar */} {(activeTab === 'scanner' || activeTab === 'accuracy') && (
activeTab === 'scanner' ? handleAnalyze() : handleBacktestAccuracy()} placeholder="Search stocks, ETFs, crypto..." style={{ flex: '1 1 200px', minWidth: 180 }} />
)} {error && (
{error}
)} {/* ── Scanner Tab ──────────────────────────────────────────────── */} {activeTab === 'scanner' && analysis && (
{/* Prediction Card */}
Prediction
{analysis.prediction === 'strong_up' && } {analysis.prediction === 'strong_down' && } {analysis.prediction_label}
Confidence
{(analysis.confidence * 100).toFixed(1)}%
{analysis.confidence_level} confidence
{/* Probability Bar */}
BearishBullish
{(analysis.probabilities.strong_down * 100).toFixed(1)}% {(analysis.probabilities.neutral * 100).toFixed(1)}% {(analysis.probabilities.strong_up * 100).toFixed(1)}%
{/* Stats Row */}
Price: {formatCurrency(analysis.current_price, detectCurrencyFromTicker(ticker))}
Expected Return: {analysis.expected_return_pct > 0 ? '+' : ''}{analysis.expected_return_pct}%
Horizon: {analysis.horizon_days}D
Accuracy: {(analysis.model_metrics?.accuracy * 100).toFixed(1)}%
F1: {analysis.model_metrics?.f1?.toFixed(4)}
{/* Hedge Recommendation Card */} {analysis.hedge_recommendation && (
Hedge Recommendation
{analysis.hedge_recommendation.action?.replace(/_/g, ' ').toUpperCase()}
Suggested Hedge
{analysis.hedge_recommendation.suggested_hedge_pct}%
Pattern Consensus
{analysis.hedge_recommendation.pattern_consensus?.charAt(0).toUpperCase() + analysis.hedge_recommendation.pattern_consensus?.slice(1)}
Bearish Signals
{analysis.hedge_recommendation.bearish_pattern_count}
Bullish Signals
{analysis.hedge_recommendation.bullish_pattern_count}
{analysis.hedge_recommendation.rationale}
{analysis.hedge_recommendation.instruments?.length > 0 && (
{analysis.hedge_recommendation.instruments.map((inst: string, i: number) => ( {inst} ))}
)}
)} {/* Detected Patterns */}
Detected Patterns ({analysis.detected_patterns?.length || 0})
{(analysis.detected_patterns || []).map((p: any, i: number) => (
{p.name}
{p.category}
{p.direction === 'bullish' ? 'Bullish' : p.direction === 'bearish' ? 'Bearish' : 'Neutral'}
{(p.reliability * 100).toFixed(0)}% reliability
))} {(!analysis.detected_patterns || analysis.detected_patterns.length === 0) && (
No patterns detected in recent candles
)}
{/* Top Features */}
Top Feature Importances
{(analysis.top_features || []).slice(0, 10).map((f: any, i: number) => { const maxImp = analysis.top_features[0]?.importance || 1; return (
{f.name}
{f.importance.toFixed(1)}
); })}
{/* Advanced Features */}
Advanced Mathematical Features
{analysis.advanced_features && Object.entries(analysis.advanced_features).filter(([_, v]) => typeof v === 'number').map(([key, val]: [string, any]) => (
{key.replace(/_/g, ' ')}
{typeof val === 'number' ? val.toFixed(4) : val}
))}
)} {/* ── Catalog Tab ──────────────────────────────────────────────── */} {activeTab === 'catalog' && catalog && (
{(catalog.patterns || []).map((p: any, i: number) => (
{p.name} {p.category}
{p.description}
{p.direction === 'bullish' ? 'Bullish' : p.direction === 'bearish' ? 'Bearish' : 'Neutral'}
{(p.reliability * 100).toFixed(0)}% reliable
))}
)} {/* ── Accuracy Tab ─────────────────────────────────────────────── */} {activeTab === 'accuracy' && accuracy && (
Bars Analyzed
{accuracy.total_bars_analyzed}
Patterns Found
{accuracy.patterns_found}
Horizon
{accuracy.horizon_days}D
{(accuracy.accuracy_report || []).map((r: any, i: number) => ( ))}
Pattern Direction Occurrences Win Rate Avg Return Actual vs Theoretical
{r.pattern} {r.direction} {r.occurrences} = 0.5 ? 'var(--accent-green)' : '#ef4444' }}> {(r.win_rate * 100).toFixed(1)}% = 0 ? 'var(--accent-green)' : '#ef4444' }}> {r.avg_return_pct >= 0 ? '+' : ''}{r.avg_return_pct.toFixed(2)}% = 0 ? 'var(--accent-green)' : '#ef4444' }}> {r.actual_vs_theoretical >= 0 ? '+' : ''}{(r.actual_vs_theoretical * 100).toFixed(1)}%
)} {/* Empty state */} {activeTab === 'scanner' && !analysis && !loading && (

Enter a ticker symbol and click Analyze to detect candlestick patterns and get AI predictions

Supports all markets: US equities, Indian stocks (.NS), crypto, and more

)}
); }