feat: macro series

This commit is contained in:
OpenSquared
2026-07-01 16:16:51 +02:00
parent 776c19e1ae
commit 8b59eff744
3 changed files with 45 additions and 8 deletions

View File

@@ -663,6 +663,10 @@ def series_history(
ff_params: list = [series_id]
if from_date:
ff_where.append("event_date >= ?"); ff_params.append(from_date)
# Filter to the series' native currency to avoid mixing countries
ff_currency = meta.get("ff_currency")
if ff_currency:
ff_where.append("currency = ?"); ff_params.append(ff_currency)
ff_rows = conn.execute(
f"SELECT event_date, event_time, event_name, actual_value, "

View File

@@ -1228,6 +1228,16 @@ def init_db():
except Exception:
pass
# ── Migrations ────────────────────────────────────────────────────────────
# Re-assign ADP events that were incorrectly mapped to PAYEMS
try:
c.execute(
"UPDATE ff_calendar SET series_id = 'ADP_NFP' "
"WHERE series_id = 'PAYEMS' AND event_name LIKE 'ADP%'"
)
except Exception:
pass
conn.commit()
conn.close()

View File

@@ -29,39 +29,56 @@ FRED_SERIES: Dict[str, Dict[str, Any]] = {
"unit": "K",
"freq": "monthly",
"category": "employment",
"ff_currency": "USD",
"higher_is_bullish": True,
"assets": ["SPY", "QQQ", "EURUSD=X", "TLT"],
"zscore_window": 12,
"transform": None,
"delta_absolute": False,
},
"ADP_NFP": {
"name": "ADP Non-Farm Employment",
"unit": "K",
"freq": "monthly",
"category": "employment",
"ff_currency": "USD",
"higher_is_bullish": True,
"assets": ["SPY", "QQQ"],
"zscore_window": 12,
"transform": None,
"delta_absolute": False,
"ff_only": True,
},
"UNRATE": {
"name": "Unemployment Rate",
"unit": "%",
"freq": "monthly",
"category": "employment",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["SPY", "QQQ", "EURUSD=X"],
"zscore_window": 12,
"transform": None,
"delta_absolute": True, # pp change (e.g. 4.1 → 4.0 = -0.1 pp)
"delta_absolute": True,
},
"CPIAUCSL": {
"name": "CPI All Items (YoY %)",
"unit": "%",
"freq": "monthly",
"category": "inflation",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["TLT", "GLD", "EURUSD=X", "SPY"],
"zscore_window": 12,
"transform": "yoy_pct", # FRED gives index level → compute YoY
"delta_absolute": True, # pp change between consecutive YoY readings
"transform": "yoy_pct",
"delta_absolute": True,
},
"CPILFESL": {
"name": "Core CPI (YoY %)",
"unit": "%",
"freq": "monthly",
"category": "inflation",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["TLT", "GLD", "EURUSD=X"],
"zscore_window": 12,
@@ -73,6 +90,7 @@ FRED_SERIES: Dict[str, Dict[str, Any]] = {
"unit": "%",
"freq": "monthly",
"category": "inflation",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["TLT", "GLD", "SPY"],
"zscore_window": 12,
@@ -84,34 +102,36 @@ FRED_SERIES: Dict[str, Dict[str, Any]] = {
"unit": "%",
"freq": "monthly",
"category": "monetary",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["TLT", "SPY", "EURUSD=X", "GLD"],
"zscore_window": 12,
"transform": None,
"delta_absolute": True, # bp/pp move
"delta_absolute": True,
},
"ICSA": {
"name": "Initial Jobless Claims",
"unit": "K",
"freq": "weekly",
"category": "employment",
"ff_currency": "USD",
"higher_is_bullish": False,
"assets": ["SPY", "QQQ"],
"zscore_window": 52,
"transform": "div1000", # FRED gives raw count → display in K
"transform": "div1000",
"delta_absolute": False,
},
"GDPC1": {
# Real GDP level in billions (chained 2017$) → compute QoQ annualized growth
"name": "GDP Growth (QoQ Ann. %)",
"unit": "%",
"freq": "quarterly",
"category": "growth",
"ff_currency": "USD",
"higher_is_bullish": True,
"assets": ["SPY", "QQQ", "EURUSD=X", "TLT"],
"zscore_window": 8,
"transform": "qoq_annualized",
"delta_absolute": True, # pp change between quarterly readings
"delta_absolute": True,
},
"BAMLH0A0HYM2": {
"name": "HY Credit Spread (OAS)",
@@ -122,7 +142,7 @@ FRED_SERIES: Dict[str, Dict[str, Any]] = {
"assets": ["HYG", "LQD", "SPY"],
"zscore_window": 52,
"transform": None,
"delta_absolute": True, # pp change in spread
"delta_absolute": True,
},
"T10Y2Y": {
"name": "Yield Spread 10Y-2Y",
@@ -294,6 +314,9 @@ def bootstrap_fred(
if not meta:
logger.warning(f"[FRED bootstrap] Unknown series: {sid}")
continue
if meta.get("ff_only"):
results[sid] = {"skipped": "ff_calendar only — no FRED fetch"}
continue
# Warm-up period: extra years before from_date for transform + z-score
transform = meta.get("transform")