import React, { useState, useEffect, useMemo, useCallback } from 'react'; import { ArrowUp, ArrowDown, Activity, Clock, Zap, TrendingUp, TrendingDown, RefreshCw, Wifi, WifiOff, Layers, Box, AlertTriangle, BookOpen, Info, Flame, Globe, BarChart2, Battery, BatteryCharging, Gauge, HelpCircle, Target, Skull } from 'lucide-react'; // --- AYARLAR --- const SYMBOL = 'BTCUSDT'; const API_BASE = 'https://api.binance.com/api/v3'; // --- YARDIMCI FONKSİYONLAR --- const formatCurrency = (value) => { if (!value) return '---'; return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 2 }).format(value); }; const calculateDistance = (current, target) => { if (!current || !target) return 0; const diff = Math.abs(current - target); return (diff / current) * 100; }; // EMA Hesaplama const calculateEMA = (closes, period) => { if (closes.length < period) return null; const k = 2 / (period + 1); let ema = closes.slice(0, period).reduce((a, b) => a + b, 0) / period; for (let i = period; i < closes.length; i++) { ema = (closes[i] * k) + (ema * (1 - k)); } return ema; }; // ATR (Average True Range) const calculateATR = (candles, period = 14) => { if (candles.length <= period) return 0; let trs = []; for(let i = 1; i < candles.length; i++) { const high = parseFloat(candles[i][2]); const low = parseFloat(candles[i][3]); const prevClose = parseFloat(candles[i-1][4]); const tr = Math.max(high - low, Math.abs(high - prevClose), Math.abs(low - prevClose)); trs.push(tr); } const last14TR = trs.slice(-period); return last14TR.reduce((a, b) => a + b, 0) / period; }; const getActiveSession = () => { const hour = new Date().getUTCHours(); if (hour >= 0 && hour < 8) return { name: 'ASIA SESSION', color: 'text-yellow-500', desc: 'Genelde range (yatay) oluşur. Likidite avı (Sweep) yaygındır.' }; if (hour >= 8 && hour < 13) return { name: 'LONDON OPEN', color: 'text-blue-400', desc: 'Hacim artışı ile gerçek trendin başlama olasılığı artar.' }; if (hour >= 13 && hour < 16) return { name: 'NY & LONDON OVERLAP', color: 'text-purple-400', desc: 'Volatilite zirve yapar. Gün içi ana hareketler genellikle burada gerçekleşir.' }; if (hour >= 16 && hour < 21) return { name: 'NY SESSION (PM)', color: 'text-emerald-400', desc: 'Trend devamı veya gün sonu pozisyon kapama hareketleri.' }; return { name: 'MARKET CLOSE/THIN', color: 'text-neutral-500', desc: 'Düşük likidite nedeniyle spread açılabilir, dikkat.' }; }; // --- STİL MANTIĞI --- const getStatusStyles = (distance, type, isConfluence) => { let styles = { rowBorder: 'border-l-2 border-transparent hover:bg-neutral-900/30', badge: 'text-neutral-600 font-normal', text: 'text-neutral-500', label: 'IDLE', barColor: 'bg-neutral-800' }; if (isConfluence) { styles.text = 'text-amber-200 font-bold'; styles.confluenceBadge = 'bg-purple-900/50 text-purple-200 border border-purple-500/30 px-1.5 rounded text-[9px] ml-2 animate-pulse'; } else if (type.includes('resistance')) { styles.text = 'text-red-400'; } else if (type.includes('support')) { styles.text = 'text-emerald-400'; } else if (type.includes('trap')) { styles.text = 'text-orange-400'; // Trap zone rengi farklı olsun } else { styles.text = 'text-indigo-400'; // Trend target rengi } if (distance < 0.35) { return { ...styles, rowBorder: 'border-l-2 border-amber-500 bg-amber-500/10', badge: 'bg-amber-500 text-black animate-pulse shadow-[0_0_10px_rgba(245,158,11,0.5)]', label: '⚡ BÖLGEDE', barColor: 'bg-amber-500' }; } else if (distance < 1.5) { return { ...styles, rowBorder: 'border-l-2 border-neutral-700 bg-neutral-900/50', badge: 'bg-neutral-800 text-amber-200 border border-amber-500/30', label: '👁️ İZLEMEDE', barColor: 'bg-amber-500/50' }; } return styles; }; export default function BarbarDashboard() { const [price, setPrice] = useState(null); const [levels, setLevels] = useState([]); const [yearlyOpen, setYearlyOpen] = useState(null); const [lastTouch, setLastTouch] = useState({}); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [tooltips, setTooltips] = useState({ yearly: false, trend: false, vitals: false }); const [session, setSession] = useState(getActiveSession()); const [trend, setTrend] = useState({ ema200: null, bias: 'NEUTRAL' }); const [vitals, setVitals] = useState({ atr: 0, dailyRange: 0, rangePercent: 0, rvol: 0 }); const toggleTooltip = (key, state) => setTooltips(prev => ({ ...prev, [key]: state })); // --- API VERİ ÇEKME --- const fetchMarketData = useCallback(async () => { try { setLoading(true); setError(null); const [weeklyRes, monthlyRes, yearlyRes, dailyRes, fourHourRes] = await Promise.all([ fetch(`${API_BASE}/klines?symbol=${SYMBOL}&interval=1w&limit=2`), fetch(`${API_BASE}/klines?symbol=${SYMBOL}&interval=1M&limit=2`), fetch(`${API_BASE}/klines?symbol=${SYMBOL}&interval=1M&limit=12`), fetch(`${API_BASE}/klines?symbol=${SYMBOL}&interval=1d&limit=30`), fetch(`${API_BASE}/klines?symbol=${SYMBOL}&interval=4h&limit=250`) ]); const weeklyData = await weeklyRes.json(); const monthlyData = await monthlyRes.json(); const yearlyData = await yearlyRes.json(); const dailyData = await dailyRes.json(); const fourHourData = await fourHourRes.json(); if (!Array.isArray(weeklyData)) throw new Error("API Error"); // 1. High/Low const prevWeek = weeklyData[weeklyData.length - 2]; const prevMonth = monthlyData[monthlyData.length - 2]; // 2. Yearly Open const currentYear = new Date().getFullYear(); const januaryCandle = yearlyData.find(k => new Date(k[0]).getFullYear() === currentYear && new Date(k[0]).getMonth() === 0); const yOpen = januaryCandle ? parseFloat(januaryCandle[1]) : parseFloat(yearlyData[0][1]); setYearlyOpen(yOpen); // 3. Monday Range let mondayHigh = null; let mondayLow = null; for (let i = dailyData.length - 1; i >= 0; i--) { const d = new Date(dailyData[i][0]); if (d.getDay() === 1) { mondayHigh = parseFloat(dailyData[i][2]); mondayLow = parseFloat(dailyData[i][3]); break; } } // 4. Trend (4H EMA 200) const closes4h = fourHourData.map(c => parseFloat(c[4])); const ema200 = calculateEMA(closes4h, 200); const lastPrice = parseFloat(fourHourData[fourHourData.length - 1][4]); let trendBias = 'NÖTR'; if (ema200) trendBias = lastPrice > ema200 ? 'YÜKSELİŞ (BULL)' : 'DÜŞÜŞ (BEAR)'; setTrend({ ema200, bias: trendBias }); // 5. Vitals (ATR) const atrValue = calculateATR(dailyData, 14); const currentDailyCandle = dailyData[dailyData.length - 1]; const currentHigh = parseFloat(currentDailyCandle[2]); const currentLow = parseFloat(currentDailyCandle[3]); const currentRange = currentHigh - currentLow; const rangeUsagePercent = (currentRange / atrValue) * 100; // 6. RVOL const currentVol = parseFloat(currentDailyCandle[5]); const avgVol = dailyData.slice(dailyData.length - 11, dailyData.length - 1) .reduce((acc, c) => acc + parseFloat(c[5]), 0) / 10; const rvol = currentVol / avgVol; setVitals({ atr: atrValue, dailyRange: currentRange, rangePercent: rangeUsagePercent, rvol: rvol }); // --- SEVİYE HESAPLAMALARI --- const pwh = parseFloat(prevWeek[2]); const pwl = parseFloat(prevWeek[3]); const wRange = pwh - pwl; const pmh = parseFloat(prevMonth[2]); const pml = parseFloat(prevMonth[3]); const mRange = pmh - pml; // --- SECRET SAUCE COEFFICIENTS --- // Gizli Katsayılar: 0.13 (Trap/Sweep) ve 0.618 (Trend/Target) const COEFF_TRAP = 0.13; const COEFF_TREND = 0.618; let rawLevels = [ // Weekly Levels { id: 'w_ext_trend_res', label: 'EXT. II (TREND)', price: pwh + (wRange * COEFF_TREND), type: 'extension_trend_res', group: 'Weekly' }, { id: 'w_ext_trap_res', label: 'EXT. I (TRAP)', price: pwh + (wRange * COEFF_TRAP), type: 'extension_trap_res', group: 'Weekly' }, { id: 'pwh', label: 'PWH (HIGH)', price: pwh, type: 'resistance', group: 'Weekly' }, { id: 'pwl', label: 'PWL (LOW)', price: pwl, type: 'support', group: 'Weekly' }, { id: 'w_ext_trap_sup', label: 'EXT. I (TRAP)', price: pwl - (wRange * COEFF_TRAP), type: 'extension_trap_sup', group: 'Weekly' }, { id: 'w_ext_trend_sup', label: 'EXT. II (TREND)', price: pwl - (wRange * COEFF_TREND), type: 'extension_trend_sup', group: 'Weekly' }, // Monthly Levels { id: 'm_ext_trend_res', label: 'EXT. II (TREND)', price: pmh + (mRange * COEFF_TREND), type: 'extension_trend_res', group: 'Monthly' }, { id: 'm_ext_trap_res', label: 'EXT. I (TRAP)', price: pmh + (mRange * COEFF_TRAP), type: 'extension_trap_res', group: 'Monthly' }, { id: 'pmh', label: 'PMH (HIGH)', price: pmh, type: 'resistance', group: 'Monthly' }, { id: 'pml', label: 'PML (LOW)', price: pml, type: 'support', group: 'Monthly' }, { id: 'm_ext_trap_sup', label: 'EXT. I (TRAP)', price: pml - (mRange * COEFF_TRAP), type: 'extension_trap_sup', group: 'Monthly' }, { id: 'm_ext_trend_sup', label: 'EXT. II (TREND)', price: pml - (mRange * COEFF_TREND), type: 'extension_trend_sup', group: 'Monthly' }, ]; if (mondayHigh) { rawLevels.push( { id: 'mon_high', label: 'MONDAY HIGH', price: mondayHigh, type: 'resistance', group: 'Weekly' }, { id: 'mon_low', label: 'MONDAY LOW', price: mondayLow, type: 'support', group: 'Weekly' } ); } const levelsWithConfluence = rawLevels.map(lvl => { const isConfluence = rawLevels.some(other => other.id !== lvl.id && Math.abs((lvl.price - other.price) / lvl.price) < 0.003 ); return { ...lvl, isConfluence }; }); setLevels(levelsWithConfluence.sort((a, b) => b.price - a.price)); setLoading(false); } catch (err) { console.error(err); setError("Veri Akışı Kesildi. API Bağlantısı Yok."); setLoading(false); } }, []); // --- POLLING --- useEffect(() => { fetchMarketData(); const interval = setInterval(async () => { setSession(getActiveSession()); try { const res = await fetch(`${API_BASE}/ticker/price?symbol=${SYMBOL}`); const data = await res.json(); if (data?.price) setPrice(parseFloat(data.price)); } catch (e) {} }, 3000); return () => clearInterval(interval); }, [fetchMarketData]); // Last Touch Logic useEffect(() => { if (!price || levels.length === 0) return; const now = new Date(); levels.forEach(lvl => { if (calculateDistance(price, lvl.price) < 0.05) { setLastTouch(prev => ({ ...prev, [lvl.id]: now })); } }); }, [price, levels]); const yearlyStatus = useMemo(() => { if (!price || !yearlyOpen) return {}; const isBullish = price > yearlyOpen; return { isBullish, color: isBullish ? 'text-emerald-500' : 'text-red-500', text: isBullish ? 'BULLISH BIAS' : 'BEARISH BIAS', bg: isBullish ? 'bg-emerald-500/10 border-emerald-500/20' : 'bg-red-500/10 border-red-500/20', }; }, [price, yearlyOpen]); // --- RENDER --- const renderTableSection = (title, groupLevels, icon) => (
| Level | Price | Dist. | Status |
|---|---|---|---|
|
{lvl.label}
{lvl.type.includes('trap') &&
{isMainLevel && (
{lvl.id.includes('mon') ? 'WEEKLY PIVOT' : 'LIQUIDITY POOL'}
)}
|
{formatCurrency(lvl.price)} |
|
{status.label}
{lastTouch[lvl.id] && |
Seviye testi sırasında kör emir atma. CVD Uyumsuzluklarını (Absorption) ve
Open Interest (OI) değişimini mutlaka kontrol et.
ÖNEMLİ: 🔥 İşaretli seviyeler (Confluence) çakışma bölgesidir. Yüksek volatilite bekle.
{error}
Kurumsal pivot seviyesi. Üstü alıcı (Boğa), altı satıcı (Ayı) kontrolü demektir.