# ========== МОДЕЛЬ ДЛЯ ГРАФИКА ========== class ChartRequest(BaseModel): exchange: str = "binance" symbol: str = "BTC/USDT" timeframe: str = "1h" date_from: str date_to: str # ========== ЭНДПОИНТ ДЛЯ ГРАФИКА ========== @app.post("/api/chart/data") async def get_chart_data(request: ChartRequest): """Получение данных для графика с уровнями и индикаторами""" try: print(f"\n📈 Запрос данных графика: {request.symbol} - {request.exchange}") exchange = get_exchange(request.exchange) if not exchange: return JSONResponse({"success": False, "error": f"Биржа {request.exchange} не поддерживается"}) # Парсим даты from datetime import datetime as dt date_from = dt.strptime(request.date_from, "%Y-%m-%d %H:%M") date_to = dt.strptime(request.date_to, "%Y-%m-%d %H:%M") since = int(date_from.timestamp() * 1000) # Получаем исторические данные ohlcv = exchange.fetch_ohlcv(request.symbol, request.timeframe, since=since, limit=500) if not ohlcv or len(ohlcv) == 0: return JSONResponse({"success": False, "error": "Нет данных"}) # Форматируем для графика chart_data = [] closes = [] for candle in ohlcv: ts = datetime.fromtimestamp(candle[0]/1000) # Пропускаем данные после date_to if ts > date_to: continue chart_data.append({ 'time': ts.strftime('%Y-%m-%d %H:%M'), 'open': candle[1], 'high': candle[2], 'low': candle[3], 'close': candle[4], 'volume': candle[5] }) closes.append(candle[4]) if not chart_data: return JSONResponse({"success": False, "error": "Нет данных в выбранном диапазоне"}) # Находим уровни поддержки и сопротивления highs = [c['high'] for c in chart_data] lows = [c['low'] for c in chart_data] # Простые уровни - локальные максимумы и минимумы resistance_level = max(highs[-50:]) if len(highs) >= 50 else max(highs) support_level = min(lows[-50:]) if len(lows) >= 50 else min(lows) # Расчет HMA def calc_hma(prices, period=55): if len(prices) < period * 2: return prices def calc_wma(data, period): if len(data) < period: return data[-1] if data else 0 weights = list(range(1, period + 1)) wma = sum(w * data[-period + i] for i, w in enumerate(weights)) / sum(weights) return wma half_period = period // 2 sqrt_period = int(period ** 0.5) hma_values = [] for i in range(period, len(prices) + 1): window = prices[i-period:i] wma_half = calc_wma(window[-half_period:], half_period) wma_full = calc_wma(window, period) interim = 2 * wma_half - wma_full hma = calc_wma([interim] * sqrt_period, sqrt_period) hma_values.append(hma) # Дополняем начало while len(hma_values) < len(prices): hma_values.insert(0, prices[0]) return hma_values hma_values = calc_hma(closes, 55) return JSONResponse({ "success": True, "data": { "candles": chart_data, "levels": { "resistance": resistance_level, "support": support_level, "hma": hma_values }, "current_price": chart_data[-1]['close'] } }) except Exception as e: print(f"❌ Ошибка получения данных графика: {e}") import traceback traceback.print_exc() return JSONResponse({"success": False, "error": str(e)})