ifieryarrows commited on
Commit
31a340a
·
verified ·
1 Parent(s): aa191f1

Sync from GitHub (tests passed)

Browse files
Files changed (3) hide show
  1. app/data_manager.py +34 -10
  2. app/settings.py +3 -3
  3. worker/tasks.py +1 -3
app/data_manager.py CHANGED
@@ -464,6 +464,10 @@ def ingest_prices(session: Session) -> dict:
464
  """
465
  Ingest price data for all configured symbols.
466
 
 
 
 
 
467
  Returns:
468
  Dict with stats per symbol
469
  """
@@ -479,24 +483,44 @@ def ingest_prices(session: Session) -> dict:
479
 
480
  stats = {}
481
 
482
- # Calculate date range
483
  end_date = datetime.now(timezone.utc)
484
- start_date = end_date - timedelta(days=settings.lookback_days)
 
 
 
485
 
486
  for i, symbol in enumerate(symbols):
487
- logger.info(f"Fetching prices for {symbol}...")
488
-
489
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  # Fetch with retry mechanism
491
  df = fetch_symbol_with_retry(symbol, start_date, end_date)
492
 
493
  if df is None or df.empty:
494
  logger.warning(f"No data returned for {symbol}")
495
- stats[symbol] = {"imported": 0, "duplicates": 0, "error": "no_data"}
496
  continue
497
 
498
  imported = 0
499
- duplicates = 0
500
 
501
  for date_idx, row in df.iterrows():
502
  try:
@@ -537,7 +561,7 @@ def ingest_prices(session: Session) -> dict:
537
  if result.rowcount > 0:
538
  imported += 1
539
  else:
540
- duplicates += 1
541
 
542
  except Exception as e:
543
  logger.debug(f"Error processing price bar: {e}")
@@ -545,8 +569,8 @@ def ingest_prices(session: Session) -> dict:
545
 
546
  session.commit()
547
 
548
- stats[symbol] = {"imported": imported, "duplicates": duplicates}
549
- logger.info(f"{symbol}: {imported} bars imported, {duplicates} updated")
550
 
551
  # Add delay between symbols to avoid rate limiting
552
  if i < len(symbols) - 1:
@@ -554,7 +578,7 @@ def ingest_prices(session: Session) -> dict:
554
 
555
  except Exception as e:
556
  logger.error(f"Failed to fetch {symbol}: {e}")
557
- stats[symbol] = {"imported": 0, "duplicates": 0, "error": str(e)}
558
 
559
  return stats
560
 
 
464
  """
465
  Ingest price data for all configured symbols.
466
 
467
+ Uses INCREMENTAL fetching: checks latest bar date per symbol in DB
468
+ and only fetches from that point forward (plus 3-day overlap for corrections).
469
+ Falls back to full lookback if no existing data found for a symbol.
470
+
471
  Returns:
472
  Dict with stats per symbol
473
  """
 
483
 
484
  stats = {}
485
 
486
+ # Full lookback range (used only for first-time fetches)
487
  end_date = datetime.now(timezone.utc)
488
+ full_start_date = end_date - timedelta(days=settings.lookback_days)
489
+
490
+ # Overlap buffer: re-fetch last 3 days to catch any corrections/adjustments
491
+ OVERLAP_DAYS = 3
492
 
493
  for i, symbol in enumerate(symbols):
 
 
494
  try:
495
+ # Check latest bar in DB for incremental fetch
496
+ latest_bar = session.query(PriceBar.date).filter(
497
+ PriceBar.symbol == symbol
498
+ ).order_by(PriceBar.date.desc()).first()
499
+
500
+ if latest_bar and latest_bar.date:
501
+ # Incremental: fetch from (latest - overlap) to now
502
+ latest_date = latest_bar.date
503
+ if latest_date.tzinfo is None:
504
+ latest_date = latest_date.replace(tzinfo=timezone.utc)
505
+ start_date = latest_date - timedelta(days=OVERLAP_DAYS)
506
+ mode = "incremental"
507
+ else:
508
+ # First time: full lookback
509
+ start_date = full_start_date
510
+ mode = "full"
511
+
512
+ logger.info(f"Fetching prices for {symbol} ({mode})...")
513
+
514
  # Fetch with retry mechanism
515
  df = fetch_symbol_with_retry(symbol, start_date, end_date)
516
 
517
  if df is None or df.empty:
518
  logger.warning(f"No data returned for {symbol}")
519
+ stats[symbol] = {"imported": 0, "updated": 0, "error": "no_data"}
520
  continue
521
 
522
  imported = 0
523
+ updated = 0
524
 
525
  for date_idx, row in df.iterrows():
526
  try:
 
561
  if result.rowcount > 0:
562
  imported += 1
563
  else:
564
+ updated += 1
565
 
566
  except Exception as e:
567
  logger.debug(f"Error processing price bar: {e}")
 
569
 
570
  session.commit()
571
 
572
+ stats[symbol] = {"imported": imported, "updated": updated, "mode": mode}
573
+ logger.info(f"{symbol}: {imported} bars imported, {updated} unchanged ({mode}, {len(df)} fetched)")
574
 
575
  # Add delay between symbols to avoid rate limiting
576
  if i < len(symbols) - 1:
 
578
 
579
  except Exception as e:
580
  logger.error(f"Failed to fetch {symbol}: {e}")
581
+ stats[symbol] = {"imported": 0, "updated": 0, "error": str(e)}
582
 
583
  return stats
584
 
app/settings.py CHANGED
@@ -78,10 +78,10 @@ class Settings(BaseSettings):
78
  openrouter_api_key: Optional[str] = None
79
  # Deprecated - kept for backward compatibility
80
  openrouter_model: str = "arcee-ai/trinity-large-preview:free"
81
- # New primary config
82
- openrouter_model_scoring: str = "arcee-ai/trinity-large-preview:free"
83
  openrouter_model_scoring_fast: Optional[str] = None
84
- openrouter_model_scoring_reliable: Optional[str] = None
85
  openrouter_model_commentary: str = "arcee-ai/trinity-large-preview:free"
86
  openrouter_rpm: int = 18
87
  openrouter_max_retries: int = 3
 
78
  openrouter_api_key: Optional[str] = None
79
  # Deprecated - kept for backward compatibility
80
  openrouter_model: str = "arcee-ai/trinity-large-preview:free"
81
+ # New primary config - Nemotron supports structured output (response_format/json_schema)
82
+ openrouter_model_scoring: str = "nvidia/nemotron-3-nano-30b-a3b:free"
83
  openrouter_model_scoring_fast: Optional[str] = None
84
+ openrouter_model_scoring_reliable: Optional[str] = "google/gemma-3-27b-it:free"
85
  openrouter_model_commentary: str = "arcee-ai/trinity-large-preview:free"
86
  openrouter_rpm: int = 18
87
  openrouter_max_retries: int = 3
worker/tasks.py CHANGED
@@ -421,13 +421,11 @@ async def _execute_pipeline_stages_v2(
421
  # -------------------------------------------------------------------------
422
  logger.info(f"[run_id={run_id}] Stage 3: Sentiment aggregation")
423
  try:
424
- from app.ai_engine import aggregate_daily_sentiment, aggregate_daily_sentiment_v2
425
 
426
  days_aggregated_v2 = aggregate_daily_sentiment_v2(session)
427
- days_aggregated = aggregate_daily_sentiment(session)
428
  session.commit()
429
 
430
- result["days_aggregated"] = days_aggregated
431
  result["days_aggregated_v2"] = days_aggregated_v2
432
 
433
  except Exception as e:
 
421
  # -------------------------------------------------------------------------
422
  logger.info(f"[run_id={run_id}] Stage 3: Sentiment aggregation")
423
  try:
424
+ from app.ai_engine import aggregate_daily_sentiment_v2
425
 
426
  days_aggregated_v2 = aggregate_daily_sentiment_v2(session)
 
427
  session.commit()
428
 
 
429
  result["days_aggregated_v2"] = days_aggregated_v2
430
 
431
  except Exception as e: