import logging from datetime import datetime, timezone, date as dt_date from sqlalchemy.orm import Session from ..models import OHLCCandle from .btc import get_btc_ohlc_eur, aggregate_to_daily logger = logging.getLogger(__name__) def seed_candles(db: Session) -> None: """Fetch 30 days of daily OHLC candles from CoinGecko and store them. Free tier gives 4-hour bars for days<=30, which aggregate cleanly to daily candles. days>30 drops to 4-day granularity (unusable for a daily chart). """ raw = get_btc_ohlc_eur(days=30) if not raw: logger.warning("Candle seed: CoinGecko returned no data — will retry on next startup.") return daily = aggregate_to_daily(raw) rows = [ OHLCCandle(date=date, open=v["open"], high=v["high"], low=v["low"], close=v["close"]) for date, v in sorted(daily.items()) ] for row in rows: db.merge(row) db.commit() logger.info("Candle seed: stored %d daily candles (%s → %s).", len(rows), min(daily.keys()), max(daily.keys())) def refresh_latest_candles(db: Session) -> None: """Add any missing candles up to today. Seeds the DB if empty. Also detects and replaces coarse (>2-day gap) legacy data from a previous days=365 seed. """ # Sparse-data detection: if existing candles have >2-day gaps, wipe and re-seed first_two = db.query(OHLCCandle).order_by(OHLCCandle.date.asc()).limit(2).all() if len(first_two) == 2: d1 = dt_date.fromisoformat(first_two[0].date) d2 = dt_date.fromisoformat(first_two[1].date) if (d2 - d1).days > 2: logger.warning("Candle refresh: detected coarse candle data (gap=%d days). Wiping and re-seeding with daily candles.", (d2 - d1).days) db.query(OHLCCandle).delete() db.commit() seed_candles(db) return latest = db.query(OHLCCandle).order_by(OHLCCandle.date.desc()).first() if latest is None: seed_candles(db) return today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d") if latest.date >= today: return # Already up to date raw = get_btc_ohlc_eur(days=7) if not raw: logger.warning("Candle refresh: CoinGecko returned no data.") return daily = aggregate_to_daily(raw) new_dates = [d for d in daily if d > latest.date] if not new_dates: return for date in new_dates: v = daily[date] db.merge(OHLCCandle(date=date, open=v["open"], high=v["high"], low=v["low"], close=v["close"])) db.commit() logger.info("Candle refresh: upserted %d candle(s) up to %s.", len(new_dates), max(new_dates))