62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
"""
|
|
Unified calendar sync — FXStreet (primary) with FF live fallback.
|
|
Called by the background loop in main.py and manually via POST /api/eco/calendar-sync.
|
|
"""
|
|
import logging
|
|
from datetime import datetime, timezone
|
|
from typing import Any, Dict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_sync_status: Dict[str, Any] = {
|
|
"running": False,
|
|
"last_run": None,
|
|
"last_result": None,
|
|
"source": None,
|
|
"next_run": None,
|
|
}
|
|
|
|
|
|
def calendar_sync(weeks_ahead: int = 8) -> Dict[str, Any]:
|
|
"""
|
|
Sync upcoming economic events:
|
|
1. Try FXStreet (no API key, ~300-400 events over weeks_ahead weeks)
|
|
2. Fall back to FF live JSON if FXStreet returns 403 or fails
|
|
"""
|
|
global _sync_status
|
|
_sync_status["running"] = True
|
|
_sync_status["last_run"] = datetime.now(timezone.utc).isoformat()
|
|
|
|
result: Dict[str, Any] = {}
|
|
source = "unknown"
|
|
|
|
try:
|
|
from services.fxstreet_calendar import fetch_upcoming as fxs_fetch
|
|
r = fxs_fetch(weeks_ahead=weeks_ahead)
|
|
if r.get("error"):
|
|
logger.warning(f"[calendar_sync] FXStreet error: {r['error']} — falling back to FF live")
|
|
from services.ff_calendar import sync_live
|
|
r_ff = sync_live()
|
|
result = {**r_ff, "_fallback": True, "_fxs_error": r["error"]}
|
|
source = "ff_fallback"
|
|
else:
|
|
result = r
|
|
source = "fxstreet"
|
|
except Exception as e:
|
|
logger.error(f"[calendar_sync] Exception: {e}")
|
|
result = {"error": str(e)}
|
|
source = "error"
|
|
|
|
_sync_status["running"] = False
|
|
_sync_status["last_result"] = result
|
|
_sync_status["source"] = source
|
|
return result
|
|
|
|
|
|
def get_sync_status() -> Dict[str, Any]:
|
|
return dict(_sync_status)
|
|
|
|
|
|
def set_next_run(ts: str):
|
|
_sync_status["next_run"] = ts
|