diff --git a/backend/config/instruments.json b/backend/config/instruments.json index 8d6d124..234ffd5 100644 --- a/backend/config/instruments.json +++ b/backend/config/instruments.json @@ -11,11 +11,11 @@ "description": "US large-cap equity benchmark — 500 plus grandes capitalisations américaines", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "fed_policy", "label": "Fed Policy", "weight": 0.9, "keywords": ["FOMC","Fed","Federal Reserve","Powell","taux directeur","pivot","dot plot","QT","QE","taux Fed"]}, - {"key": "earnings_growth", "label": "Earnings Growth", "weight": 0.85, "keywords": ["Earnings","EPS","bénéfices","résultats","Earnings Season","reporting","profits"]}, - {"key": "real_rates", "label": "Real Rates", "weight": 0.75, "keywords": ["taux réels","TIPS","real yields","breakeven","inflation","CPI","PCE"]}, - {"key": "liquidity", "label": "Global Liquidity", "weight": 0.7, "keywords": ["liquidité","liquidity","QE","QT","bilan Fed","repo","M2","conditions financières"]}, - {"key": "vix", "label": "VIX / Fear", "weight": 0.6, "keywords": ["VIX","volatilité","vol spike","hedging","protection","skew","put","peur","fear"]} + {"key": "fed_policy", "label": "Fed Policy", "type": "event_calendar", "weight": 0.9, "keywords": ["FOMC","Fed","Federal Reserve","Powell","taux directeur","pivot","dot plot","QT","QE","taux Fed"]}, + {"key": "earnings_growth", "label": "Earnings Growth", "type": "report", "weight": 0.85, "keywords": ["Earnings","EPS","bénéfices","résultats","Earnings Season","reporting","profits"]}, + {"key": "real_rates", "label": "Real Rates", "type": "fundamental", "weight": 0.75, "keywords": ["taux réels","TIPS","real yields","breakeven","inflation","CPI","PCE"]}, + {"key": "liquidity", "label": "Global Liquidity", "type": "fundamental", "weight": 0.7, "keywords": ["liquidité","liquidity","QE","QT","bilan Fed","repo","M2","conditions financières"]}, + {"key": "vix", "label": "VIX / Fear", "type": "sentiment", "weight": 0.6, "keywords": ["VIX","volatilité","vol spike","hedging","protection","skew","put","peur","fear"]} ], "regime_labels": ["Risk-On Bull", "Risk-Off Bear", "Stagflation", "Rate Shock", "Recovery"], "event_keywords": ["FOMC","CPI","NFP","GDP","Earnings Season","Fed Chair","VIX"], @@ -34,11 +34,11 @@ "description": "US large-cap tech and growth benchmark — 100 plus grandes valeurs Nasdaq", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "real_rates", "label": "Real Rates", "weight": 0.9, "keywords": ["taux réels","TIPS","real yields","FOMC","Fed","CPI","breakeven"]}, - {"key": "ai_capex", "label": "AI Capex", "weight": 0.85, "keywords": ["IA","AI","Nvidia","Microsoft","capex tech","data center","GPU","intelligence artificielle","ChatGPT"]}, - {"key": "megacaps", "label": "Mégacaps GAFAM", "weight": 0.8, "keywords": ["GAFAM","Apple","Meta","Alphabet","Amazon","Microsoft","earnings tech","Big Tech","résultats tech"]}, - {"key": "growth", "label": "Croissance US", "weight": 0.75, "keywords": ["croissance","GDP","récession","NFP","emploi","PMI","croissance économique"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.5, "keywords": ["Dollar","DXY","dollar index","EUR/USD","devise"]} + {"key": "real_rates", "label": "Real Rates", "type": "fundamental", "weight": 0.9, "keywords": ["taux réels","TIPS","real yields","FOMC","Fed","CPI","breakeven"]}, + {"key": "ai_capex", "label": "AI Capex", "type": "fundamental", "weight": 0.85, "keywords": ["IA","AI","Nvidia","Microsoft","capex tech","data center","GPU","intelligence artificielle","ChatGPT"]}, + {"key": "megacaps", "label": "Mégacaps GAFAM", "type": "report", "weight": 0.8, "keywords": ["GAFAM","Apple","Meta","Alphabet","Amazon","Microsoft","earnings tech","Big Tech","résultats tech"]}, + {"key": "growth", "label": "Croissance US", "type": "event_calendar", "weight": 0.75, "keywords": ["croissance","GDP","récession","NFP","emploi","PMI","croissance économique"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.5, "keywords": ["Dollar","DXY","dollar index","EUR/USD","devise"]} ], "regime_labels": ["Tech Bull (AI-Driven)", "Tech Bear", "Rate Compression", "Earnings Crash", "Recovery"], "event_keywords": ["FOMC","Big Tech Earnings","CPI","AI","Rate","NVDA","AAPL"], @@ -57,10 +57,10 @@ "description": "US small-cap equity benchmark — 2000 petites capitalisations américaines", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "gdp_growth", "label": "Croissance US", "weight": 0.85, "keywords": ["GDP","PIB","croissance US","NFP","emploi","récession","PMI","domestic growth"]}, - {"key": "credit", "label": "Crédit & Spreads", "weight": 0.8, "keywords": ["crédit","credit","HY","high yield","spreads","LBO","conditions de crédit","credit crunch"]}, - {"key": "regional_banks", "label": "Banques Régionales","weight": 0.75, "keywords": ["banques régionales","SVB","FDIC","banque","banking","bank failure","crédit bancaire"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.6, "keywords": ["Dollar","DXY","dollar fort","USD strength"]} + {"key": "gdp_growth", "label": "Croissance US", "type": "event_calendar", "weight": 0.85, "keywords": ["GDP","PIB","croissance US","NFP","emploi","récession","PMI","domestic growth"]}, + {"key": "credit", "label": "Crédit & Spreads", "type": "fundamental", "weight": 0.8, "keywords": ["crédit","credit","HY","high yield","spreads","LBO","conditions de crédit","credit crunch"]}, + {"key": "regional_banks", "label": "Banques Régionales","type": "fundamental", "weight": 0.75, "keywords": ["banques régionales","SVB","FDIC","banque","banking","bank failure","crédit bancaire"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.6, "keywords": ["Dollar","DXY","dollar fort","USD strength"]} ], "regime_labels": ["Small Cap Expansion", "Credit Crunch Squeeze", "Risk-Off", "Recovery", "Neutral"], "event_keywords": ["FOMC","Credit","GDP","NFP","Rates","Regional Banks"], @@ -79,10 +79,10 @@ "description": "MSCI Emerging Markets — grandes capitalisations des marchés émergents", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "dollar_index", "label": "Dollar Index", "weight": 0.9, "keywords": ["Dollar","DXY","USD","dollar index","dollar fort","faible dollar"]}, - {"key": "china_growth", "label": "Chine / PBoC", "weight": 0.85, "keywords": ["China","Chine","PBOC","PBoC","PIB chinois","Xi","immobilier chinois","stimulus Chine","relance Chine"]}, - {"key": "em_flows", "label": "Flux EM", "weight": 0.75, "keywords": ["EM","émergents","emerging","flows","flux","capitaux émergents"]}, - {"key": "commodities", "label": "Matières Premières","weight": 0.7, "keywords": ["matières premières","commodities","minerai","pétrole","métaux","commodité"]} + {"key": "dollar_index", "label": "Dollar Index", "type": "technical", "weight": 0.9, "keywords": ["Dollar","DXY","USD","dollar index","dollar fort","faible dollar"]}, + {"key": "china_growth", "label": "Chine / PBoC", "type": "event_calendar", "weight": 0.85, "keywords": ["China","Chine","PBOC","PBoC","PIB chinois","Xi","immobilier chinois","stimulus Chine","relance Chine"]}, + {"key": "em_flows", "label": "Flux EM", "type": "sentiment", "weight": 0.75, "keywords": ["EM","émergents","emerging","flows","flux","capitaux émergents"]}, + {"key": "commodities", "label": "Matières Premières","type": "fundamental", "weight": 0.7, "keywords": ["matières premières","commodities","minerai","pétrole","métaux","commodité"]} ], "regime_labels": ["EM Growth Rally", "Dollar Squeeze", "China Risk-Off", "Commodity Lift", "Neutral"], "event_keywords": ["China GDP","Dollar","EM","PBOC","Commodities","stimulus Chine"], @@ -101,10 +101,10 @@ "description": "MSCI EAFE — Europe, Australasie, Extrême-Orient (hors US/Canada)", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "ecb_policy", "label": "BCE / ECB", "weight": 0.85, "keywords": ["BCE","ECB","Lagarde","taux BCE","zone euro","politique BCE","ECB rate"]}, - {"key": "energy", "label": "Énergie Europe", "weight": 0.8, "keywords": ["énergie","gaz européen","pétrole","LNG","crisis énergétique","energy","energy price"]}, - {"key": "eurusd", "label": "EUR/USD", "weight": 0.75, "keywords": ["EUR/USD","euro dollar","eurusd","parité euro","euro fort","euro faible"]}, - {"key": "european_growth", "label": "Croissance Européenne", "weight": 0.7, "keywords": ["Europe","zone euro","Allemagne","PIB européen","PMI Europe","récession Europe","croissance européenne"]} + {"key": "ecb_policy", "label": "BCE / ECB", "type": "event_calendar", "weight": 0.85, "keywords": ["BCE","ECB","Lagarde","taux BCE","zone euro","politique BCE","ECB rate"]}, + {"key": "energy", "label": "Énergie Europe", "type": "fundamental", "weight": 0.8, "keywords": ["énergie","gaz européen","pétrole","LNG","crisis énergétique","energy","energy price"]}, + {"key": "eurusd", "label": "EUR/USD", "type": "technical", "weight": 0.75, "keywords": ["EUR/USD","euro dollar","eurusd","parité euro","euro fort","euro faible"]}, + {"key": "european_growth", "label": "Croissance Européenne", "type": "event_calendar", "weight": 0.7, "keywords": ["Europe","zone euro","Allemagne","PIB européen","PMI Europe","récession Europe","croissance européenne"]} ], "regime_labels": ["Global Risk-On", "USD Strength Drag", "Europe Recession", "Recovery", "Neutral"], "event_keywords": ["ECB","EU GDP","Europe","Germany","BOJ","Japan","EUR"], @@ -123,11 +123,11 @@ "description": "SPDR Gold Shares — proxy physique de l'or", "chart": { "ma_periods": [50, 100, 200], "bollinger_period": 50, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "real_rates_us", "label": "Taux Réels US", "weight": 0.95, "keywords": ["taux réels","TIPS","real yields","Fed","FOMC","CPI","breakeven","inflation réelle"]}, - {"key": "dollar_index", "label": "Dollar Index", "weight": 0.85, "keywords": ["Dollar","DXY","dollar index","USD","faible dollar","dollar fort"]}, - {"key": "inflation_expectations", "label": "Anticipations Inflation", "weight": 0.75, "keywords": ["inflation","CPI","PCE","breakeven","attentes d'inflation","stagflation"]}, - {"key": "geopolitical_risk", "label": "Risque Géopolitique", "weight": 0.7, "keywords": ["géopolitique","guerre","Moyen-Orient","Iran","Russie","conflit","Chine","tension","crise","war"]}, - {"key": "cb_buying", "label": "Achats Banques Centrales","weight": 0.5, "keywords": ["banque centrale","central bank","réserves","gold reserves","achats d'or","PBOC gold","dédollarisation"]} + {"key": "real_rates_us", "label": "Taux Réels US", "type": "fundamental", "weight": 0.95, "keywords": ["taux réels","TIPS","real yields","Fed","FOMC","CPI","breakeven","inflation réelle"]}, + {"key": "dollar_index", "label": "Dollar Index", "type": "technical", "weight": 0.85, "keywords": ["Dollar","DXY","dollar index","USD","faible dollar","dollar fort"]}, + {"key": "inflation_expectations", "label": "Anticipations Inflation", "type": "fundamental", "weight": 0.75, "keywords": ["inflation","CPI","PCE","breakeven","attentes d'inflation","stagflation"]}, + {"key": "geopolitical_risk", "label": "Risque Géopolitique", "type": "geopolitical", "weight": 0.7, "keywords": ["géopolitique","guerre","Moyen-Orient","Iran","Russie","conflit","Chine","tension","crise","war"]}, + {"key": "cb_buying", "label": "Achats Banques Centrales","type": "fundamental", "weight": 0.5, "keywords": ["banque centrale","central bank","réserves","gold reserves","achats d'or","PBOC gold","dédollarisation"]} ], "regime_labels": ["Real Rates Falling", "Safe Haven Rally", "Inflation Hedge", "Dollar Weakness", "Range"], "event_keywords": ["CPI","Fed","FOMC","Dollar","Geopolitical","Iran","Gold","guerre","inflation"], @@ -146,11 +146,11 @@ "description": "iShares Silver Trust — proxy physique de l'argent métal", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "industrial_demand", "label": "Demande Industrielle", "weight": 0.8, "keywords": ["industrie","manufacturing","PMI","production industrielle","fabrique","industry"]}, - {"key": "real_rates", "label": "Taux Réels", "weight": 0.75, "keywords": ["taux réels","TIPS","Fed","FOMC","real yields"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.7, "keywords": ["Dollar","DXY","USD"]}, - {"key": "solar_ev_demand", "label": "Solaire / Véhicule EV","weight": 0.65, "keywords": ["solaire","solar","EV","véhicule électrique","énergie verte","green energy","photovoltaïque","battery"]}, - {"key": "gold_ratio", "label": "Ratio Or/Argent", "weight": 0.6, "keywords": ["Gold","or","ratio Or/Argent","gold silver","argent","silver"]} + {"key": "industrial_demand", "label": "Demande Industrielle", "type": "fundamental", "weight": 0.8, "keywords": ["industrie","manufacturing","PMI","production industrielle","fabrique","industry"]}, + {"key": "real_rates", "label": "Taux Réels", "type": "fundamental", "weight": 0.75, "keywords": ["taux réels","TIPS","Fed","FOMC","real yields"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.7, "keywords": ["Dollar","DXY","USD"]}, + {"key": "solar_ev_demand", "label": "Solaire / Véhicule EV","type": "fundamental", "weight": 0.65, "keywords": ["solaire","solar","EV","véhicule électrique","énergie verte","green energy","photovoltaïque","battery"]}, + {"key": "gold_ratio", "label": "Ratio Or/Argent", "type": "technical", "weight": 0.6, "keywords": ["Gold","or","ratio Or/Argent","gold silver","argent","silver"]} ], "regime_labels": ["Industrial Demand", "Safe Haven Flow", "Dollar Weakness", "Risk-Off", "Range"], "event_keywords": ["Manufacturing","PMI","CPI","Dollar","Silver","EV","Solar","taux réels"], @@ -169,11 +169,11 @@ "description": "United States Oil Fund — proxy WTI (pétrole brut américain)", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "opec_policy", "label": "OPEP+ / Production", "weight": 0.9, "keywords": ["OPEC","OPEP","production pétrolière","quotas","Arabie Saoudite","Saudi","réduction","coupes","OPEC meeting"]}, - {"key": "inventories", "label": "Stocks EIA", "weight": 0.8, "keywords": ["EIA","stocks pétroliers","inventaires","inventories","crude stocks","rapport EIA","crude supply"]}, - {"key": "geopolitical_risk","label": "Risque Géopolitique","weight": 0.75, "keywords": ["géopolitique","Moyen-Orient","Iran","Russie","conflit","guerre","war","Golfe Persique","tension"]}, - {"key": "global_demand", "label": "Demande Mondiale", "weight": 0.85, "keywords": ["demande mondiale","China demand","IEA","croissance mondiale","global demand","reprise économique"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.7, "keywords": ["Dollar","DXY","USD"]} + {"key": "opec_policy", "label": "OPEP+ / Production", "type": "event_calendar", "weight": 0.9, "keywords": ["OPEC","OPEP","production pétrolière","quotas","Arabie Saoudite","Saudi","réduction","coupes","OPEC meeting"]}, + {"key": "inventories", "label": "Stocks EIA", "type": "report", "weight": 0.8, "keywords": ["EIA","stocks pétroliers","inventaires","inventories","crude stocks","rapport EIA","crude supply"]}, + {"key": "geopolitical_risk","label": "Risque Géopolitique","type": "geopolitical", "weight": 0.75, "keywords": ["géopolitique","Moyen-Orient","Iran","Russie","conflit","guerre","war","Golfe Persique","tension"]}, + {"key": "global_demand", "label": "Demande Mondiale", "type": "fundamental", "weight": 0.85, "keywords": ["demande mondiale","China demand","IEA","croissance mondiale","global demand","reprise économique"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.7, "keywords": ["Dollar","DXY","USD"]} ], "regime_labels": ["Supply Shock", "Demand Recovery", "Inventory Draw", "Geopolitical Premium", "Neutral"], "event_keywords": ["OPEC","EIA","Inventories","Brent","WTI","Oil","Middle East","Saudi"], @@ -192,10 +192,10 @@ "description": "United States Natural Gas Fund — proxy Henry Hub (gaz naturel)", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "weather_seasonality", "label": "Météo / Saisonnalité","weight": 0.9, "keywords": ["météo","weather","hiver","été","froid","chaleur","El Niño","La Niña","saison","vague de froid","heat wave"]}, - {"key": "storage", "label": "Stockage EIA Gaz", "weight": 0.85, "keywords": ["EIA Gas Storage","stockage gaz","gas storage","inventaires gaz","rapport stockage gaz"]}, - {"key": "lng_exports", "label": "Exports LNG", "weight": 0.75, "keywords": ["LNG","GNL","exportations gaz","terminal LNG","gazoduc","liquefied natural gas"]}, - {"key": "production", "label": "Production US", "weight": 0.7, "keywords": ["production gaz","shale gas","fracking","puits gaz","Marcellus","Appalachian","US gas output"]} + {"key": "weather_seasonality", "label": "Météo / Saisonnalité","type": "fundamental", "weight": 0.9, "keywords": ["météo","weather","hiver","été","froid","chaleur","El Niño","La Niña","saison","vague de froid","heat wave"]}, + {"key": "storage", "label": "Stockage EIA Gaz", "type": "report", "weight": 0.85, "keywords": ["EIA Gas Storage","stockage gaz","gas storage","inventaires gaz","rapport stockage gaz"]}, + {"key": "lng_exports", "label": "Exports LNG", "type": "fundamental", "weight": 0.75, "keywords": ["LNG","GNL","exportations gaz","terminal LNG","gazoduc","liquefied natural gas"]}, + {"key": "production", "label": "Production US", "type": "fundamental", "weight": 0.7, "keywords": ["production gaz","shale gas","fracking","puits gaz","Marcellus","Appalachian","US gas output"]} ], "regime_labels": ["Winter Storage Fill", "Supply Glut", "Demand Surge", "Export LNG Lift", "Neutral"], "event_keywords": ["EIA Gas Storage","LNG","Gas","Natural Gas","Weather","stockage gaz"], @@ -214,11 +214,11 @@ "description": "iShares 20+ Year Treasury — proxy du rendement US 10Y/30Y", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "fed_path", "label": "Trajectoire Fed", "weight": 0.9, "keywords": ["FOMC","Fed","taux directeur","Fed hike","Fed cut","pivot","dot plot","Federal Reserve"]}, - {"key": "inflation_expectations", "label": "Inflation / CPI", "weight": 0.85, "keywords": ["CPI","PCE","inflation","déflation","attentes","breakeven","inflation US"]}, - {"key": "growth", "label": "Croissance / NFP", "weight": 0.75, "keywords": ["GDP","NFP","récession","croissance","emploi","PMI","chômage","payrolls"]}, - {"key": "deficit_supply", "label": "Déficit / Offre Treasury","weight": 0.7, "keywords": ["déficit","dette publique","Treasury auction","enchères","budget","fiscal","dette fédérale"]}, - {"key": "risk_aversion", "label": "Fuite Vers Qualité", "weight": 0.65, "keywords": ["risk-off","crise","fuite vers la qualité","safe haven","vol spike","contagion","crise bancaire"]} + {"key": "fed_path", "label": "Trajectoire Fed", "type": "event_calendar", "weight": 0.9, "keywords": ["FOMC","Fed","taux directeur","Fed hike","Fed cut","pivot","dot plot","Federal Reserve"]}, + {"key": "inflation_expectations", "label": "Inflation / CPI", "type": "fundamental", "weight": 0.85, "keywords": ["CPI","PCE","inflation","déflation","attentes","breakeven","inflation US"]}, + {"key": "growth", "label": "Croissance / NFP", "type": "event_calendar", "weight": 0.75, "keywords": ["GDP","NFP","récession","croissance","emploi","PMI","chômage","payrolls"]}, + {"key": "deficit_supply", "label": "Déficit / Offre Treasury","type": "fundamental", "weight": 0.7, "keywords": ["déficit","dette publique","Treasury auction","enchères","budget","fiscal","dette fédérale"]}, + {"key": "risk_aversion", "label": "Fuite Vers Qualité", "type": "sentiment", "weight": 0.65, "keywords": ["risk-off","crise","fuite vers la qualité","safe haven","vol spike","contagion","crise bancaire"]} ], "regime_labels": ["Safe Haven Bid", "Rate Shock Selloff", "QE Expectations", "Inflation Selloff", "Range"], "event_keywords": ["FOMC","CPI","Fed","Treasury","Yield","Deficit","NFP"], @@ -237,10 +237,10 @@ "description": "iShares iBoxx USD High Yield Corporate Bond — baromètre du crédit HY", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "default_rate", "label": "Taux de Défaut", "weight": 0.85, "keywords": ["défauts","default","faillite","bankruptcy","spreads HY","taux de défaut","HY spreads"]}, - {"key": "growth", "label": "Croissance Économique", "weight": 0.8, "keywords": ["GDP","récession","croissance","PMI","emploi","payrolls","activité"]}, - {"key": "liquidity", "label": "Conditions de Liquidité","weight": 0.8, "keywords": ["liquidité","crédit","QT","QE","conditions financières","FCO","financial conditions"]}, - {"key": "risk_appetite", "label": "Appétit pour le Risque", "weight": 0.75, "keywords": ["risk-on","risk-off","appétit pour le risque","flux crédit","sentiment marché"]} + {"key": "default_rate", "label": "Taux de Défaut", "type": "fundamental", "weight": 0.85, "keywords": ["défauts","default","faillite","bankruptcy","spreads HY","taux de défaut","HY spreads"]}, + {"key": "growth", "label": "Croissance Économique", "type": "event_calendar", "weight": 0.8, "keywords": ["GDP","récession","croissance","PMI","emploi","payrolls","activité"]}, + {"key": "liquidity", "label": "Conditions de Liquidité","type": "fundamental", "weight": 0.8, "keywords": ["liquidité","crédit","QT","QE","conditions financières","FCO","financial conditions"]}, + {"key": "risk_appetite", "label": "Appétit pour le Risque", "type": "sentiment", "weight": 0.75, "keywords": ["risk-on","risk-off","appétit pour le risque","flux crédit","sentiment marché"]} ], "regime_labels": ["Credit Expansion", "Credit Crunch", "Spread Compression", "Recession Fear", "Neutral"], "event_keywords": ["Credit","Default","GDP","FOMC","Recession","HY","spreads"], @@ -259,10 +259,10 @@ "description": "Taux spot Euro / Dollar américain", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": false }, "drivers": [ - {"key": "fed_ecb_differential", "label": "Différentiel Fed/BCE", "weight": 0.95, "keywords": ["BCE","ECB","Fed","FOMC","différentiel","taux directeurs","politique monétaire","rate differential"]}, - {"key": "rate_differential_2y", "label": "Taux 2 ans US-EUR", "weight": 0.85, "keywords": ["taux 2 ans","Bund 2Y","Treasury 2Y","swap","différentiel de taux","2Y spread"]}, - {"key": "inflation_differential", "label": "Inflation US vs EUR", "weight": 0.75, "keywords": ["CPI","inflation","PCE","HICP","zone euro","inflation différentiel"]}, - {"key": "dxy", "label": "Dollar Index DXY", "weight": 0.7, "keywords": ["Dollar","DXY","dollar index","USD","dollar fort","faible dollar"]} + {"key": "fed_ecb_differential", "label": "Différentiel Fed/BCE", "type": "event_calendar", "weight": 0.95, "keywords": ["BCE","ECB","Fed","FOMC","différentiel","taux directeurs","politique monétaire","rate differential"]}, + {"key": "rate_differential_2y", "label": "Taux 2 ans US-EUR", "type": "technical", "weight": 0.85, "keywords": ["taux 2 ans","Bund 2Y","Treasury 2Y","swap","différentiel de taux","2Y spread"]}, + {"key": "inflation_differential", "label": "Inflation US vs EUR", "type": "fundamental", "weight": 0.75, "keywords": ["CPI","inflation","PCE","HICP","zone euro","inflation différentiel"]}, + {"key": "dxy", "label": "Dollar Index DXY", "type": "technical", "weight": 0.7, "keywords": ["Dollar","DXY","dollar index","USD","dollar fort","faible dollar"]} ], "regime_labels": ["EUR Strength (ECB Hawkish)", "USD Strength (Fed Hawkish)", "Risk-On EUR Rally", "Risk-Off USD Safe", "Range"], "event_keywords": ["ECB","FOMC","CPI","EUR","Dollar","Fed","Eurozone","BCE"], @@ -281,10 +281,10 @@ "description": "Taux spot Dollar américain / Yen japonais", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": false }, "drivers": [ - {"key": "boj_policy", "label": "BOJ Policy", "weight": 0.95, "keywords": ["BOJ","Banque du Japon","Ueda","YCC","yield curve control","politique monétaire japonaise","BOJ rate","JGB"]}, - {"key": "rate_diff_us_jp","label": "Différentiel US-JP","weight": 0.9, "keywords": ["différentiel US-Japon","JGB","UST","rendements US-JP","US Japan spread","10Y spread"]}, - {"key": "fed_policy", "label": "Fed Policy", "weight": 0.85, "keywords": ["Fed","FOMC","taux directeur US","hawkish Fed","Fed hike","Federal Reserve"]}, - {"key": "risk_appetite", "label": "Risk Appetite / Carry","weight": 0.7, "keywords": ["risk-off","carry trade","yen safe haven","crise","carry unwind","yen refuge"]} + {"key": "boj_policy", "label": "BOJ Policy", "type": "event_calendar", "weight": 0.95, "keywords": ["BOJ","Banque du Japon","Ueda","YCC","yield curve control","politique monétaire japonaise","BOJ rate","JGB"]}, + {"key": "rate_diff_us_jp","label": "Différentiel US-JP","type": "technical", "weight": 0.9, "keywords": ["différentiel US-Japon","JGB","UST","rendements US-JP","US Japan spread","10Y spread"]}, + {"key": "fed_policy", "label": "Fed Policy", "type": "event_calendar", "weight": 0.85, "keywords": ["Fed","FOMC","taux directeur US","hawkish Fed","Fed hike","Federal Reserve"]}, + {"key": "risk_appetite", "label": "Risk Appetite / Carry","type": "sentiment", "weight": 0.7, "keywords": ["risk-off","carry trade","yen safe haven","crise","carry unwind","yen refuge"]} ], "regime_labels": ["Carry Trade On", "BOJ Tightening Surprise", "Risk-Off JPY Safe Haven", "Dollar Bull", "YCC Adjustment"], "event_keywords": ["BOJ","Fed","Japan","YCC","Carry","JPY","Yen","taux Japon"], @@ -303,10 +303,10 @@ "description": "Taux spot Livre Sterling / Dollar américain", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": false }, "drivers": [ - {"key": "boe_policy", "label": "BOE Policy", "weight": 0.9, "keywords": ["BOE","Bank of England","Bailey","taux UK","Royaume-Uni","Angleterre","UK rate","BOE meeting"]}, - {"key": "uk_inflation", "label": "Inflation UK", "weight": 0.8, "keywords": ["inflation UK","CPI UK","CPIH","RPI","inflation Angleterre"]}, - {"key": "uk_growth", "label": "Croissance UK", "weight": 0.75, "keywords": ["GDP UK","PMI UK","croissance UK","récession UK","UK economy","UK GDP"]}, - {"key": "political_risk","label": "Risque Politique UK","weight": 0.65, "keywords": ["politique UK","budget UK","Labour","Tories","fiscal UK","gilt","UK budget","Reeves"]} + {"key": "boe_policy", "label": "BOE Policy", "type": "event_calendar", "weight": 0.9, "keywords": ["BOE","Bank of England","Bailey","taux UK","Royaume-Uni","Angleterre","UK rate","BOE meeting"]}, + {"key": "uk_inflation", "label": "Inflation UK", "type": "event_calendar", "weight": 0.8, "keywords": ["inflation UK","CPI UK","CPIH","RPI","inflation Angleterre"]}, + {"key": "uk_growth", "label": "Croissance UK", "type": "event_calendar", "weight": 0.75, "keywords": ["GDP UK","PMI UK","croissance UK","récession UK","UK economy","UK GDP"]}, + {"key": "political_risk","label": "Risque Politique UK","type": "geopolitical", "weight": 0.65, "keywords": ["politique UK","budget UK","Labour","Tories","fiscal UK","gilt","UK budget","Reeves"]} ], "regime_labels": ["GBP Strength (BOE Hawkish)", "USD Dominance", "Political Risk GBP", "UK Recession Pressure", "Range"], "event_keywords": ["BOE","Fed","UK","Britain","GBP","Pound","UK CPI"], @@ -325,10 +325,10 @@ "description": "iPath VIX Short-Term Futures ETN — proxy de la peur et de la volatilité implicite", "chart": { "ma_periods": [10, 20, 50], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "market_stress", "label": "Stress de Marché", "weight": 0.9, "keywords": ["krach","crash","crise","choc","panic","volatilité","vol spike","selloff","capitulation","contagion"]}, - {"key": "risk_appetite", "label": "Peur / Risk-Off", "weight": 0.85, "keywords": ["risk-off","risk-on","sentiment","fear","peur","greed","appétit risque","VIX spike"]}, - {"key": "options_demand", "label": "Demande Options (Puts)", "weight": 0.75, "keywords": ["options","puts","hedging","protection","skew","IV","couverture","implied vol","volatilité implicite"]}, - {"key": "macro_uncertainty", "label": "Incertitude Macro", "weight": 0.7, "keywords": ["FOMC","surprise","incertitude","géopolitique","macro","inflation choc","data surprise"]} + {"key": "market_stress", "label": "Stress de Marché", "type": "geopolitical", "weight": 0.9, "keywords": ["krach","crash","crise","choc","panic","volatilité","vol spike","selloff","capitulation","contagion"]}, + {"key": "risk_appetite", "label": "Peur / Risk-Off", "type": "sentiment", "weight": 0.85, "keywords": ["risk-off","risk-on","sentiment","fear","peur","greed","appétit risque","VIX spike"]}, + {"key": "options_demand", "label": "Demande Options (Puts)", "type": "technical", "weight": 0.75, "keywords": ["options","puts","hedging","protection","skew","IV","couverture","implied vol","volatilité implicite"]}, + {"key": "macro_uncertainty", "label": "Incertitude Macro", "type": "event_calendar", "weight": 0.7, "keywords": ["FOMC","surprise","incertitude","géopolitique","macro","inflation choc","data surprise"]} ], "regime_labels": ["Low Vol Complacency", "Vol Spike Crisis", "Vol Expansion", "Vol Compression", "Neutral"], "event_keywords": ["VIX","Volatility","Crisis","FOMC","Market Stress","peur","vol spike"], @@ -347,11 +347,11 @@ "description": "Apple Inc. — ecosystème consommateur tech et services", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "iphone_cycle", "label": "Cycle iPhone", "weight": 0.85, "keywords": ["iPhone","Apple","AAPL earnings","supercycle","launch","iPhone 16","hardware"]}, - {"key": "china_sales", "label": "Ventes Chine", "weight": 0.8, "keywords": ["Chine","China","Huawei","ban Apple","restrictions Apple","China sales","marché chinois"]}, - {"key": "ai_integration","label": "Apple Intelligence / IA","weight": 0.75, "keywords": ["Apple Intelligence","AI","IA","Siri","machine learning","IA Apple","generative AI"]}, - {"key": "margins", "label": "Services & Marges", "weight": 0.7, "keywords": ["services","App Store","iCloud","marge Apple","services revenue","abonnements"]}, - {"key": "fed_policy", "label": "Valorisation / Taux", "weight": 0.65, "keywords": ["Fed","taux","valorisation","taux d'intérêt","discount rate"]} + {"key": "iphone_cycle", "label": "Cycle iPhone", "type": "report", "weight": 0.85, "keywords": ["iPhone","Apple","AAPL earnings","supercycle","launch","iPhone 16","hardware"]}, + {"key": "china_sales", "label": "Ventes Chine", "type": "geopolitical", "weight": 0.8, "keywords": ["Chine","China","Huawei","ban Apple","restrictions Apple","China sales","marché chinois"]}, + {"key": "ai_integration","label": "Apple Intelligence / IA","type": "fundamental", "weight": 0.75, "keywords": ["Apple Intelligence","AI","IA","Siri","machine learning","IA Apple","generative AI"]}, + {"key": "margins", "label": "Services & Marges", "type": "report", "weight": 0.7, "keywords": ["services","App Store","iCloud","marge Apple","services revenue","abonnements"]}, + {"key": "fed_policy", "label": "Valorisation / Taux", "type": "event_calendar", "weight": 0.65, "keywords": ["Fed","taux","valorisation","taux d'intérêt","discount rate"]} ], "regime_labels": ["Growth Bull", "Rate Squeeze", "Earnings Beat", "Tech Selloff", "Neutral"], "event_keywords": ["Apple Earnings","iPhone","Services","China","Fed","AI","AAPL"], @@ -370,11 +370,11 @@ "description": "NVIDIA Corporation — leader mondial des GPU pour IA et data centers", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "ai_capex_cycle", "label": "Capex IA / Hyperscalers","weight": 0.95, "keywords": ["IA","AI","data center","capex","Nvidia","GPU","H100","Blackwell","NVLink","hyperscalers","infrastructure IA"]}, - {"key": "earnings_growth", "label": "Croissance Bénéfices", "weight": 0.9, "keywords": ["NVDA earnings","résultats Nvidia","revenues","data center revenue","beat","guidance"]}, - {"key": "data_center_demand","label": "Demande Data Center", "weight": 0.85, "keywords": ["Amazon AWS","Microsoft Azure","Google Cloud","data center","cloud","computing","GPU demand"]}, - {"key": "export_restrictions","label": "Restrictions Export", "weight": 0.7, "keywords": ["export control","restrictions export","Chine","China ban","BIS","CISA","H20","chip ban"]}, - {"key": "rates", "label": "Taux / Valorisation", "weight": 0.6, "keywords": ["taux","valorisation","growth stock","multiples","discount rate","Fed"]} + {"key": "ai_capex_cycle", "label": "Capex IA / Hyperscalers","type": "fundamental", "weight": 0.95, "keywords": ["IA","AI","data center","capex","Nvidia","GPU","H100","Blackwell","NVLink","hyperscalers","infrastructure IA"]}, + {"key": "earnings_growth", "label": "Croissance Bénéfices", "type": "report", "weight": 0.9, "keywords": ["NVDA earnings","résultats Nvidia","revenues","data center revenue","beat","guidance"]}, + {"key": "data_center_demand","label": "Demande Data Center", "type": "fundamental", "weight": 0.85, "keywords": ["Amazon AWS","Microsoft Azure","Google Cloud","data center","cloud","computing","GPU demand"]}, + {"key": "export_restrictions","label": "Restrictions Export", "type": "geopolitical", "weight": 0.7, "keywords": ["export control","restrictions export","Chine","China ban","BIS","CISA","H20","chip ban"]}, + {"key": "rates", "label": "Taux / Valorisation", "type": "event_calendar", "weight": 0.6, "keywords": ["taux","valorisation","growth stock","multiples","discount rate","Fed"]} ], "regime_labels": ["AI Bull Run", "AI Hype Correction", "Earnings Catalyst", "Rate Compression", "Consolidation"], "event_keywords": ["NVIDIA Earnings","AI","Data Center","Export","GPU","NVDA","Blackwell"], @@ -393,10 +393,10 @@ "description": "The Goldman Sachs Group — banque d'investissement globale", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "yield_curve", "label": "Courbe des Taux", "weight": 0.85, "keywords": ["courbe des taux","2Y-10Y","steepening","inversion","yield curve","10Y-2Y","pente"]}, - {"key": "ma_activity", "label": "M&A / Activité Deals", "weight": 0.8, "keywords": ["M&A","fusion-acquisition","LBO","IPO","deal","advisory","boutique","transaction"]}, - {"key": "rates", "label": "Taux d'Intérêt", "weight": 0.8, "keywords": ["taux","Fed","intérêts","NIM","net interest margin","Fed rate","interest rates"]}, - {"key": "credit_conditions","label": "Conditions de Crédit", "weight": 0.75, "keywords": ["crédit","spreads","conditions financières","leverage loans","credit tightening"]} + {"key": "yield_curve", "label": "Courbe des Taux", "type": "technical", "weight": 0.85, "keywords": ["courbe des taux","2Y-10Y","steepening","inversion","yield curve","10Y-2Y","pente"]}, + {"key": "ma_activity", "label": "M&A / Activité Deals", "type": "fundamental", "weight": 0.8, "keywords": ["M&A","fusion-acquisition","LBO","IPO","deal","advisory","boutique","transaction"]}, + {"key": "rates", "label": "Taux d'Intérêt", "type": "event_calendar", "weight": 0.8, "keywords": ["taux","Fed","intérêts","NIM","net interest margin","Fed rate","interest rates"]}, + {"key": "credit_conditions","label": "Conditions de Crédit", "type": "fundamental", "weight": 0.75, "keywords": ["crédit","spreads","conditions financières","leverage loans","credit tightening"]} ], "regime_labels": ["Finance Bull", "Recession Fear", "Yield Curve Steepen", "M&A Boom", "Range"], "event_keywords": ["Goldman","Financials","Yield Curve","M&A","Banking","Fed","Credit"], @@ -415,11 +415,11 @@ "description": "Exxon Mobil Corporation — major pétrolier intégré mondial", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "oil_price", "label": "Prix du Pétrole", "weight": 0.9, "keywords": ["WTI","Brent","pétrole","crude","oil price","prix pétrole","cours pétrole"]}, - {"key": "global_demand", "label": "Demande Mondiale", "weight": 0.8, "keywords": ["demande mondiale","China demand","IEA","croissance","global demand","reprise"]}, - {"key": "opec_policy", "label": "OPEP+ Production", "weight": 0.75, "keywords": ["OPEC","OPEP","quotas","production","Saudi","Arabie Saoudite","réduction"]}, - {"key": "capex", "label": "Capex / Investissement","weight": 0.6, "keywords": ["capex","investissement","forage","upstream","exploration","rig count"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.6, "keywords": ["Dollar","DXY","USD"]} + {"key": "oil_price", "label": "Prix du Pétrole", "type": "fundamental", "weight": 0.9, "keywords": ["WTI","Brent","pétrole","crude","oil price","prix pétrole","cours pétrole"]}, + {"key": "global_demand", "label": "Demande Mondiale", "type": "fundamental", "weight": 0.8, "keywords": ["demande mondiale","China demand","IEA","croissance","global demand","reprise"]}, + {"key": "opec_policy", "label": "OPEP+ Production", "type": "event_calendar", "weight": 0.75, "keywords": ["OPEC","OPEP","quotas","production","Saudi","Arabie Saoudite","réduction"]}, + {"key": "capex", "label": "Capex / Investissement","type": "fundamental", "weight": 0.6, "keywords": ["capex","investissement","forage","upstream","exploration","rig count"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.6, "keywords": ["Dollar","DXY","USD"]} ], "regime_labels": ["Energy Bull", "Demand Slowdown", "OPEC Benefit", "Green Transition Drag", "Range"], "event_keywords": ["Oil","OPEC","Energy","XOM","EIA","Crude","Exxon","WTI"], @@ -438,11 +438,11 @@ "description": "Bitcoin — premier actif décentralisé, indicateur de liquidité et Risk-On", "chart": { "ma_periods": [20, 50, 200], "bollinger_period": 20, "bollinger_std": 2, "show_volume": true }, "drivers": [ - {"key": "global_liquidity","label": "Liquidité Mondiale", "weight": 0.85, "keywords": ["liquidité mondiale","M2","Fed","QE","QT","conditions financières","liquidity","money supply"]}, - {"key": "etf_flows", "label": "Flux ETF Bitcoin", "weight": 0.85, "keywords": ["ETF Bitcoin","spot BTC ETF","BlackRock","Fidelity","flux ETF","ETF approval","IBIT","FBTC"]}, - {"key": "risk_appetite", "label": "Sentiment Risk-On", "weight": 0.8, "keywords": ["risk-on","risk-off","crypto","sentiment","appétit pour le risque","halving","cycle crypto"]}, - {"key": "regulatory", "label": "Réglementation Crypto", "weight": 0.7, "keywords": ["réglementation crypto","SEC","CFTC","crypto ban","ETF approval","régulation","MiCA"]}, - {"key": "dollar", "label": "Dollar Index", "weight": 0.65, "keywords": ["Dollar","DXY","USD","dédollarisation"]} + {"key": "global_liquidity","label": "Liquidité Mondiale", "type": "fundamental", "weight": 0.85, "keywords": ["liquidité mondiale","M2","Fed","QE","QT","conditions financières","liquidity","money supply"]}, + {"key": "etf_flows", "label": "Flux ETF Bitcoin", "type": "report", "weight": 0.85, "keywords": ["ETF Bitcoin","spot BTC ETF","BlackRock","Fidelity","flux ETF","ETF approval","IBIT","FBTC"]}, + {"key": "risk_appetite", "label": "Sentiment Risk-On", "type": "sentiment", "weight": 0.8, "keywords": ["risk-on","risk-off","crypto","sentiment","appétit pour le risque","halving","cycle crypto"]}, + {"key": "regulatory", "label": "Réglementation Crypto", "type": "geopolitical", "weight": 0.7, "keywords": ["réglementation crypto","SEC","CFTC","crypto ban","ETF approval","régulation","MiCA"]}, + {"key": "dollar", "label": "Dollar Index", "type": "technical", "weight": 0.65, "keywords": ["Dollar","DXY","USD","dédollarisation"]} ], "regime_labels": ["Crypto Bull (ETF Inflows)", "Risk-Off Crypto Selloff", "Liquidity Expansion", "Regulatory Fear", "Consolidation"], "event_keywords": ["Bitcoin","BTC","Crypto","ETF","Fed","Liquidity","Regulation","halving"], diff --git a/backend/routers/timeline.py b/backend/routers/timeline.py index 5ed158b..3e62231 100644 --- a/backend/routers/timeline.py +++ b/backend/routers/timeline.py @@ -226,6 +226,22 @@ def bootstrap_events() -> Dict[str, Any]: return {"seeded": count, "status": "ok" if count > 0 else "already_seeded"} +@router.post("/bootstrap-eco") +def bootstrap_eco(force: bool = False) -> Dict[str, Any]: + """ + Seed the market_events table with economic calendar events (2020-2026). + Includes FOMC, NFP, CPI, GDP, ISM, BOJ, ECB, BOE with expected/actual/surprise fields. + Pass ?force=true to delete existing eco events and re-insert. + """ + try: + from services.eco_calendar_bootstrap import bootstrap_eco_events + result = bootstrap_eco_events(force=force) + return result + except Exception as e: + logger.error(f"[Timeline] bootstrap_eco failed: {e}") + raise HTTPException(500, str(e)) + + @router.post("/bootstrap-ma") async def bootstrap_ma() -> Dict[str, Any]: """Detect MA ruptures on 5 key underlyings and generate historical market events via GPT.""" diff --git a/backend/services/database.py b/backend/services/database.py index 6969318..6b10c4f 100644 --- a/backend/services/database.py +++ b/backend/services/database.py @@ -753,8 +753,13 @@ def init_db(): )""") # Add columns to existing DBs (idempotent via catch) for _col, _def in [ - ("absorption_pct", "REAL DEFAULT NULL"), - ("relevant_indicators", "TEXT DEFAULT '[]'"), + ("absorption_pct", "REAL DEFAULT NULL"), + ("relevant_indicators", "TEXT DEFAULT '[]'"), + ("expected_value", "TEXT DEFAULT NULL"), + ("actual_value", "TEXT DEFAULT NULL"), + ("surprise_pct", "REAL DEFAULT NULL"), + ("unit", "TEXT DEFAULT NULL"), + ("sub_type", "TEXT DEFAULT NULL"), ]: try: c.execute(f"ALTER TABLE market_events ADD COLUMN {_col} {_def}") @@ -4480,12 +4485,16 @@ def save_market_event(ev: Dict[str, Any]) -> int: try: cur = conn.execute("""INSERT INTO market_events (name, start_date, end_date, level, category, description, market_impact, - affected_assets, impact_score, parent_event_id) - VALUES (?,?,?,?,?,?,?,?,?,?)""", + affected_assets, impact_score, parent_event_id, + expected_value, actual_value, surprise_pct, unit, sub_type, absorption_pct) + VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""", (ev["name"], ev["start_date"], ev.get("end_date"), ev["level"], ev.get("category", "macro"), ev.get("description", ""), ev.get("market_impact", ""), json.dumps(ev.get("affected_assets", [])), - ev.get("impact_score", 0.5), ev.get("parent_event_id"))) + ev.get("impact_score", 0.5), ev.get("parent_event_id"), + ev.get("expected_value"), ev.get("actual_value"), + ev.get("surprise_pct"), ev.get("unit"), ev.get("sub_type"), + ev.get("absorption_pct"))) conn.commit() return cur.lastrowid finally: diff --git a/backend/services/eco_calendar_bootstrap.py b/backend/services/eco_calendar_bootstrap.py new file mode 100644 index 0000000..1c2dfb7 --- /dev/null +++ b/backend/services/eco_calendar_bootstrap.py @@ -0,0 +1,586 @@ +""" +Bootstrap historical economic calendar events into market_events DB. +Covers 2020-2026 with actual vs expected values and surprise metrics. +Categories: FOMC, NFP, CPI, GDP, ISM/PMI, BOJ, ECB, BOE. +Convention: surprise_pct positive = bullish surprise, negative = bearish. +""" +import logging +from typing import List, Dict, Any + +logger = logging.getLogger(__name__) + +# Shared asset groups +_EQ = ["SPY", "QQQ", "IWM"] +_RATES = ["TLT", "HYG"] +_FX = ["EURUSD=X", "USDJPY=X", "GBPUSD=X"] +_SAFE = ["GLD", "VXX"] +_ALL = _EQ + _RATES + ["EURUSD=X", "GLD", "BTC-USD"] + +ECO_EVENTS: List[Dict[str, Any]] = [ + + # ══════════════════════════════════════════════════════════ + # FOMC — DECISIONS DE TAUX (2020-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "FOMC — Urgence COVID : coupe -50pb (entre-séances)", + "start_date": "2020-03-03", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "-25pb", "actual_value": "-50pb", "surprise_pct": -12, + "unit": "pb", "impact_score": 0.95, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "Fed coupe -50pb en urgence hors-séance (premier depuis 2008). COVID commence à impacter les marchés. S&P500 avait perdu -10% en une semaine. Marché attendait -25pb."}, + + {"name": "FOMC — Urgence COVID : taux à 0% + QE illimité", + "start_date": "2020-03-16", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "-50pb", "actual_value": "-100pb + QE∞", "surprise_pct": -20, + "unit": "pb", "impact_score": 0.98, "absorption_pct": 100, + "affected_assets": _ALL + ["USO", "EEM"], + "description": "FOMC coupe -100pb en urgence, amène taux à 0-0.25%. Lance QE illimité (Treasuries + MBS). Bazooka monétaire COVID. Circuit breakers activés ce matin. Le tout en un seul dimanche soir."}, + + {"name": "FOMC — Taper talk (dot plot hawkish inattendu)", + "start_date": "2021-06-16", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "stable", "actual_value": "2 hausses en 2023 signalées", "surprise_pct": -18, + "unit": "signal", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Dot plot de juin 2021 révèle que 13 des 18 membres FOMC prévoient 2+ hausses d'ici 2023. Surprise hawkish. Gold -5% en 2 jours. DXY +1%. Prémices du pivot narratif 2022."}, + + {"name": "FOMC — Début réduction QE (tapering annoncé)", + "start_date": "2021-11-03", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "taper annoncé", "actual_value": "$15Md/mois taper", "surprise_pct": 0, + "unit": "signal", "impact_score": 0.78, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Fed annonce début du tapering à -$15Md/mois (Nov-Déc 2021). Largement attendu. Marché absorbe sans choc majeur. SPY au plus haut. Signale la fin de l'ère QE COVID."}, + + {"name": "FOMC — Accélération taper + 3 hausses 2022 signalées", + "start_date": "2021-12-15", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "taper accéléré", "actual_value": "-$30Md/mois + 3 hausses 2022", "surprise_pct": -15, + "unit": "signal", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "Fed double la vitesse du tapering (-$30Md/mois) et signale 3 hausses en 2022 vs 1 attendue. Inflation à 6.8% force Powell à pivoter hawkish. Dollar se renforce. Gold résiste."}, + + {"name": "FOMC — Premier hike cycle : +25pb (premier depuis 2018)", + "start_date": "2022-03-16", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+25pb", "actual_value": "+25pb (cibles 0.25-0.50%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "Premier hike depuis déc 2018. Taux cible 0.25-0.50%. Ukraine envahie 3 semaines avant. Dot plot : 7 hausses totales en 2022. Powell dit 'l'économie est forte'. Début du cycle de resserrement le plus agressif depuis 40 ans."}, + + {"name": "FOMC — +50pb (premier double hike depuis 2000)", + "start_date": "2022-05-04", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+50pb", "actual_value": "+50pb + QT annoncé", "surprise_pct": -5, + "unit": "pb", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "+50pb, plus forte hausse depuis 2000. Taux 0.75-1.00%. Annonce début QT en juin (-$95Md/mois). CPI à 8.3%. Conférence de presse : Powell exclut +75pb pour la prochaine réunion (retournement de veste en juin)."}, + + {"name": "FOMC — Choc +75pb : surprise hawkish (attendu +50pb)", + "start_date": "2022-06-15", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+50pb", "actual_value": "+75pb", "surprise_pct": -25, + "unit": "pb", "impact_score": 0.96, "absorption_pct": 100, + "affected_assets": _ALL + ["EEM", "USO"], + "description": "Fed remonte +75pb, plus fort depuis 1994. FOMC dit +50pb en mai, mais CPI jun 9.1% force la main. Dot plot : taux terminal à 3.4% fin 2022. SPY -3.5%, TLT -2%. Début du bear market officiel."}, + + {"name": "FOMC — +75pb (2e consécutif)", + "start_date": "2022-07-27", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+75pb", "actual_value": "+75pb (taux 2.25-2.50%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "2e +75pb consécutif. Taux 2.25-2.50%. Powell dit 'probablement approprié de ralentir'. Marché interprète comme dovish → rally court terme. GDP Q2 -0.9% annoncé le même jour (récession technique)."}, + + {"name": "FOMC — +75pb + dot plot terminal 4.6% (hawkish peak)", + "start_date": "2022-09-21", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+75pb", "actual_value": "+75pb + terminal 4.6%", "surprise_pct": -20, + "unit": "pb", "impact_score": 0.93, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "3e +75pb. Dot plot choque le marché: taux terminal révisé à 4.6% pour 2023. 'Higher for longer' officiel. Dollar index au plus haut 20 ans. SPY perd -5% semaine. Tous les actifs se vendent."}, + + {"name": "FOMC — +75pb (4e consécutif)", + "start_date": "2022-11-02", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+75pb", "actual_value": "+75pb (taux 3.75-4.00%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "4e +75pb consécutif. Mais communication laisse entrevoir un ralentissement à venir. 'Timing et ampleur des hausses futures' → signal de pivot. Marché commence à pricer pivot 2023."}, + + {"name": "FOMC — Décélération +50pb (fin des gros moves)", + "start_date": "2022-12-14", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+50pb", "actual_value": "+50pb + terminal 5.1%", "surprise_pct": -8, + "unit": "pb", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Décélération à +50pb mais dot plot hawkish : terminal révisé à 5.1% (vs 4.6% en sept). SPY -2.5% sur la semaine. Marché était trop optimiste sur le pivot. Gold résistant."}, + + {"name": "FOMC — +25pb (déceleration confirmée)", + "start_date": "2023-02-01", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+25pb", "actual_value": "+25pb (taux 4.50-4.75%)", "surprise_pct": +5, + "unit": "pb", "impact_score": 0.75, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Premier +25pb depuis mars 2022. Powell signale 'quelques hausses supplémentaires'. Ton moins hawkish qu'attendu. SPY +1.5%. BTC rally. Début du discours désinflation 2023."}, + + {"name": "FOMC — +25pb (avant crise SVB)", + "start_date": "2023-03-22", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+25pb", "actual_value": "+25pb + doutes sur la suite", "surprise_pct": +5, + "unit": "pb", "impact_score": 0.78, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X", "HYG"], + "description": "Réunion post-SVB (faillite 10 mars). Powell dit la crise bancaire remplace 'une ou deux hausses' de taux. Signal de pause proche. Taux 4.75-5.00%. GLD fort sur les craintes bancaires."}, + + {"name": "FOMC — Dernière hausse du cycle : +25pb", + "start_date": "2023-05-03", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+25pb", "actual_value": "+25pb (taux 5.00-5.25%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "Dernière hausse du cycle de resserrement. Taux au plus haut depuis 2007 : 5.00-5.25%. Powell retire la phrase 'additional firming may be appropriate'. Signal de pause officieux. Marché voit le pic."}, + + {"name": "FOMC — Première pause du cycle (skip)", + "start_date": "2023-06-14", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "+25pb ou pause", "actual_value": "pause (hold)", "surprise_pct": +8, + "unit": "signal", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "Première pause depuis mars 2022. Taux stable à 5.00-5.25%. Mais dot plot révise à 5.6% le terminal : une hausse de plus attendue en 2023. SPY tient les gains. 'Higher for longer' s'installe."}, + + {"name": "FOMC — Pivot historique : première baisse -50pb (surprise)", + "start_date": "2024-09-18", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "-25pb", "actual_value": "-50pb", "surprise_pct": +20, + "unit": "pb", "impact_score": 0.94, "absorption_pct": 100, + "affected_assets": _ALL + ["EEM", "USO"], + "description": "Premier cut depuis mars 2020. La Fed surprend avec -50pb alors que le consensus était -25pb. Taux 4.75-5.00%. Powell: 'Cette décision témoigne de notre confiance croissante'. SPY +1%, GLD +1.2%, BTC +3%. Début du cycle d'assouplissement 2024."}, + + {"name": "FOMC — Deuxième baisse -25pb du cycle", + "start_date": "2024-11-07", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "-25pb", "actual_value": "-25pb (taux 4.50-4.75%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.72, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "2e coupe du cycle. Lendemain des élections Trump → incertitude tarifaire. Fed ignore les résultats d'élection. Taux 4.50-4.75%. Marché commence à se questionner sur 2025."}, + + {"name": "FOMC — Dot plot hawkish : 2 cuts 2025 seulement", + "start_date": "2024-12-18", "level": "long", "category": "calendar", "sub_type": "FOMC", + "expected_value": "-25pb + 4 cuts 2025", "actual_value": "-25pb + 2 cuts 2025", "surprise_pct": -18, + "unit": "pb", "impact_score": 0.87, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "3e coupe mais dot plot choc : révision de 4 à 2 baisses prévues en 2025. 'Higher for longer' resurgit. SPY -3% sur la séance. TLT -1.5%. Dollar index au plus haut annuel. Correction de fin d'année violente."}, + + {"name": "FOMC — Hold (incertitude tarifs Trump)", + "start_date": "2025-01-29", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "hold", "actual_value": "hold (taux 4.25-4.50%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.70, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Première réunion de l'ère Trump 2. Fed en pause. Incertitude tarifaire force la prudence. CPI encore au-dessus de 2%. Marché commence à réviser les anticipations de baisses 2025 à la baisse."}, + + {"name": "FOMC — Hold (choc tarifaire Liberation Day)", + "start_date": "2025-05-07", "level": "medium", "category": "calendar", "sub_type": "FOMC", + "expected_value": "hold", "actual_value": "hold — 'wait and see' tarifaire", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.72, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "Fed en mode attentiste post Liberation Day (tarifs réciproques Trump). Stagflation imminente : inflation tarifaire vs ralentissement croissance. Marché incertain sur timing prochain move."}, + + # ══════════════════════════════════════════════════════════ + # NFP — NON-FARM PAYROLLS (2020-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "NFP Mars 2020 — Premier choc COVID (-701K)", + "start_date": "2020-04-03", "level": "medium", "category": "calendar", "sub_type": "NFP", + "expected_value": "-100K", "actual_value": "-701K", "surprise_pct": -85, + "unit": "K emplois", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _EQ + ["GLD", "TLT", "VXX"], + "description": "NFP mars 2020 : -701K (premier mois plein COVID). Attendu -100K. Début de la destruction d'emplois. Le pire viendra en avril. Chômage : 4.4% vs 3.5% en février."}, + + {"name": "NFP Avril 2020 — Record absolu destruction emplois (-20.5M)", + "start_date": "2020-05-08", "level": "long", "category": "calendar", "sub_type": "NFP", + "expected_value": "-22000K", "actual_value": "-20537K", "surprise_pct": +8, + "unit": "K emplois", "impact_score": 0.98, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "NFP avril 2020 : -20.537M emplois détruits en un seul mois. Record absolu dans l'histoire moderne. Chômage 14.7%. Légèrement mieux qu'attendu (-22M) = paradoxal rallye. Début du V-shape recovery."}, + + {"name": "NFP Mai 2020 — Surprise massive de reprise (+2.5M)", + "start_date": "2020-06-05", "level": "long", "category": "calendar", "sub_type": "NFP", + "expected_value": "-8000K", "actual_value": "+2509K", "surprise_pct": +100, + "unit": "K emplois", "impact_score": 0.92, "absorption_pct": 100, + "affected_assets": _EQ + ["GLD", "EURUSD=X", "VXX"], + "description": "NFP mai 2020 : +2.509M ! Attendu -8M. Surprise positive historique. Début de la reprise. SPY +2.6% sur la séance. Fed et marchés reprennent confiance. Mais le taux de chômage mal calculé (mislabeling)."}, + + {"name": "NFP Avril 2021 — Miss catastrophique (+266K vs +1000K attendu)", + "start_date": "2021-05-07", "level": "medium", "category": "calendar", "sub_type": "NFP", + "expected_value": "+1000K", "actual_value": "+266K", "surprise_pct": -75, + "unit": "K emplois", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "GLD", "EURUSD=X"], + "description": "NFP avril 2021 : +266K vs +1000K attendu. Miss le plus large de l'histoire récente. Fed et marchés ont du mal à lire le post-COVID. Dollar chute. Or monte. Fed repousse toute discussion de taper."}, + + {"name": "NFP Octobre 2021 — Forte reprise (+531K)", + "start_date": "2021-11-05", "level": "short", "category": "calendar", "sub_type": "NFP", + "expected_value": "+450K", "actual_value": "+531K", "surprise_pct": +18, + "unit": "K emplois", "impact_score": 0.72, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "EURUSD=X"], + "description": "NFP oct 2021 : +531K, révisions haussières. Marché du travail se resserre. Pression salariale commence. Confirme le taper annoncé en novembre. SPY vers ATH."}, + + {"name": "NFP Janvier 2022 — Beat surprise (+467K vs +150K)", + "start_date": "2022-02-04", "level": "medium", "category": "calendar", "sub_type": "NFP", + "expected_value": "+150K", "actual_value": "+467K", "surprise_pct": +58, + "unit": "K emplois", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "EURUSD=X", "GLD"], + "description": "NFP janvier 2022 : +467K avec révisions massives à la hausse (+708K révisé pour déc). Marché du travail ultra-chaud. Renforce les arguments hawkish pour mars. TLT -1.5%."}, + + {"name": "NFP Juin 2022 — Solide malgré craintes récession (+372K)", + "start_date": "2022-07-08", "level": "short", "category": "calendar", "sub_type": "NFP", + "expected_value": "+268K", "actual_value": "+372K", "surprise_pct": +39, + "unit": "K emplois", "impact_score": 0.72, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "EURUSD=X"], + "description": "NFP juin 2022 : +372K malgré les craintes de récession (GDP Q1 -1.6%, Q2 estimé négatif). Donne à la Fed les munitions pour continuer les hausses agressives."}, + + {"name": "NFP Janvier 2023 — Méga-beat choc (+517K vs +185K)", + "start_date": "2023-02-03", "level": "long", "category": "calendar", "sub_type": "NFP", + "expected_value": "+185K", "actual_value": "+517K", "surprise_pct": +79, + "unit": "K emplois", "impact_score": 0.90, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "NFP janvier 2023 : +517K ! 2.8x le consensus. Chômage 3.4% (plus bas depuis 1969). Donne à la Fed l'argument pour des hausses supplémentaires. TLT -1.5%. Or -1%. Dollar +0.8%. Remet en question le 'pivot'."}, + + {"name": "NFP Juillet 2024 — Choc à la baisse (+114K vs +175K) — Récession panic", + "start_date": "2024-08-02", "level": "long", "category": "calendar", "sub_type": "NFP", + "expected_value": "+175K", "actual_value": "+114K", "surprise_pct": -38, + "unit": "K emplois", "impact_score": 0.92, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "NFP juillet 2024 : +114K, massive miss. Chômage 4.3% (Sahm Rule activée → récession signal). Catalyseur du crash août 2024 (SPY -6%, Nikkei -12%). VIX explose à 65. BOJ avait haussé les taux 2 jours avant → double choc."}, + + {"name": "NFP Décembre 2024 — Beat fort (+256K vs +155K attendu)", + "start_date": "2025-01-10", "level": "medium", "category": "calendar", "sub_type": "NFP", + "expected_value": "+155K", "actual_value": "+256K", "surprise_pct": +65, + "unit": "K emplois", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "EURUSD=X", "GLD"], + "description": "NFP décembre 2024 : +256K, fort beat. Chômage 4.1%. Donne à la Fed un argument supplémentaire pour un 'patient approach'. TLT -1.2%. Repousse les attentes de baisses de taux 2025."}, + + # ══════════════════════════════════════════════════════════ + # CPI — INFLATION US (2021-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "CPI Mai 2021 — Premier saut inflationniste majeur (5.0%)", + "start_date": "2021-06-10", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "4.7%", "actual_value": "5.0%", "surprise_pct": -12, + "unit": "% a/a", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI mai 2021 : 5.0% a/a, plus haut depuis 2008. Attendu 4.7%. Début de l'ère inflationniste post-COVID. Fed dit 'transitoire'. Gold réagit peu car taux réels encore très négatifs."}, + + {"name": "CPI Octobre 2021 — 6.2% (plus haut depuis 31 ans)", + "start_date": "2021-11-10", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "5.8%", "actual_value": "6.2%", "surprise_pct": -18, + "unit": "% a/a", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI oct 2021 : 6.2%, plus haut depuis novembre 1990. Attendu 5.8%. 'Transitoire' commence à être abandonné. Powell devra accélérer le taper. TLT -1.5%. Or +0.5% (protection inflation)."}, + + {"name": "CPI Décembre 2021 — 7.0% (pic 40 ans)", + "start_date": "2022-01-12", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "7.0%", "actual_value": "7.0%", "surprise_pct": 0, + "unit": "% a/a", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI déc 2021 : 7.0% a/a, plus haut depuis 1982. Comme attendu mais confirme la crise inflationniste. Enterre officiellement le mot 'transitoire'. Force la Fed vers un cycle de hausse agressif en 2022."}, + + {"name": "CPI Janvier 2022 — 7.5% (40 ans de record + miss hawkish)", + "start_date": "2022-02-10", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "7.3%", "actual_value": "7.5%", "surprise_pct": -20, + "unit": "% a/a", "impact_score": 0.90, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI jan 2022 : 7.5%, au-dessus des 7.3% attendus. 40Y high. James Bullard (St. Louis Fed) appelle à 100pb de hausse d'ici juillet. TLT -1.5%. SPY -1.8%. Le marché prend conscience de l'ampleur du resserrement nécessaire."}, + + {"name": "CPI Mai 2022 — 8.6% (record 43 ans, miss hawkish)", + "start_date": "2022-06-10", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "8.3%", "actual_value": "8.6%", "surprise_pct": -22, + "unit": "% a/a", "impact_score": 0.94, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI mai 2022 : 8.6%, plus haut depuis 1981. Attendu 8.3%. Force la Fed à +75pb la semaine suivante (annoncé dimanche soir). SPY -2.9%. Or, parfois hedge inflation, chute aussi car taux réels remontent. Début du bear market 2022."}, + + {"name": "CPI Juin 2022 — Pic 9.1% (sommet 43 ans, pire surprise hawkish 2022)", + "start_date": "2022-07-13", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "8.8%", "actual_value": "9.1%", "surprise_pct": -25, + "unit": "% a/a", "impact_score": 0.97, "absorption_pct": 100, + "affected_assets": _ALL + ["EEM", "USO"], + "description": "CPI juin 2022 : 9.1% a/a, plus haut depuis novembre 1981. Pire surprise de l'année. Oblige la Fed à considérer +100pb en juillet (finalement +75pb). Dollar index au plus haut, GLD sous pression malgré l'inflation (taux réels montent)."}, + + {"name": "CPI Octobre 2022 — 7.7% (inflexion baissière, grosse surprise positive)", + "start_date": "2022-11-10", "level": "long", "category": "calendar", "sub_type": "CPI", + "expected_value": "7.9%", "actual_value": "7.7%", "surprise_pct": +20, + "unit": "% a/a", "impact_score": 0.93, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI oct 2022 : 7.7%, première inflexion claire sous les attentes. Attendu 7.9%. Rally historique : SPY +5.5%, NAS +7.4%, GLD +2%, BTC +10%, Dollar -2%. Début du pivot narratif et de la désinflation. Point d'inflexion majeur."}, + + {"name": "CPI Décembre 2022 — 6.5% (désinflation confirmée)", + "start_date": "2023-01-12", "level": "medium", "category": "calendar", "sub_type": "CPI", + "expected_value": "6.5%", "actual_value": "6.5%", "surprise_pct": 0, + "unit": "% a/a", "impact_score": 0.78, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "CPI déc 2022 : 6.5% a/a. Confirme la tendance désinflationniste. 6e mois consécutif de baisse depuis le pic de 9.1%. Marché confirme que le pire est derrière. Bon pour les actifs risqués et obligations."}, + + {"name": "CPI Mars 2024 — 3.5% (surprise hawkish, désinflation bloquée)", + "start_date": "2024-04-10", "level": "medium", "category": "calendar", "sub_type": "CPI", + "expected_value": "3.4%", "actual_value": "3.5%", "surprise_pct": -15, + "unit": "% a/a", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "CPI mars 2024 : 3.5%, au-dessus des 3.4% attendus. 3e mois consécutif au-dessus des attentes. Le 'last mile' est difficile. TLT -1.5%, taux 10Y → 4.5%. Report des baisses Fed de juin à septembre. SPY -1%."}, + + {"name": "CPI Mars 2025 — 2.4% (impact tariffs Trump commence à apparaître)", + "start_date": "2025-04-10", "level": "medium", "category": "calendar", "sub_type": "CPI", + "expected_value": "2.5%", "actual_value": "2.4%", "surprise_pct": +10, + "unit": "% a/a", "impact_score": 0.75, "absorption_pct": 100, + "affected_assets": _EQ + _RATES + ["GLD", "EURUSD=X"], + "description": "CPI mars 2025 : 2.4%, légèrement sous les 2.5% attendus. Dernier mois avant l'impact plein des tarifs Trump (annoncés 2 avril). Le marché sait que l'inflation va remonter. Fed en mode wait-and-see."}, + + # ══════════════════════════════════════════════════════════ + # GDP — CROISSANCE US (2020-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "GDP T1 2020 — Premier choc COVID (-4.8% annualisé)", + "start_date": "2020-04-29", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "-4.0%", "actual_value": "-4.8%", "surprise_pct": -15, + "unit": "% ann.", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "GDP Q1 2020 (estimé) : -4.8% annualisé. 1er choc COVID sur la croissance. Attendu -4.0%. Pire depuis 2008. Mais le marché sait déjà que Q2 sera catastrophique."}, + + {"name": "GDP T2 2020 — Pire contraction de l'histoire US (-32.9%)", + "start_date": "2020-07-30", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "-34.7%", "actual_value": "-32.9%", "surprise_pct": +12, + "unit": "% ann.", "impact_score": 0.92, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "GDP Q2 2020 : -32.9% annualisé. Contraction la plus sévère de l'histoire américaine. Légèrement meilleur qu'attendu (-34.7%) → marché monte légèrement. Marché déjà 'pricé' pour le pire → rallye paradoxal."}, + + {"name": "GDP T3 2020 — Rebond en V historique (+33.1%)", + "start_date": "2020-10-29", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "+31.0%", "actual_value": "+33.1%", "surprise_pct": +10, + "unit": "% ann.", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _EQ + ["EURUSD=X", "GLD"], + "description": "GDP Q3 2020 : +33.1% annualisé. Rebond en V post-COVID historique. Légère beat. Economies restent sous leur potentiel pre-COVID mais la reprise est en marche. Soutient l'élan des marchés."}, + + {"name": "GDP T4 2021 — Croissance forte (+6.9%, beat) malgré Omicron", + "start_date": "2022-01-27", "level": "medium", "category": "calendar", "sub_type": "GDP", + "expected_value": "+5.5%", "actual_value": "+6.9%", "surprise_pct": +20, + "unit": "% ann.", "impact_score": 0.78, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "GLD", "EURUSD=X"], + "description": "GDP Q4 2021 : +6.9%, forte beat. Malgré Omicron et les goulots d'étranglement. Ajoute au scénario 'économie forte = Fed peut hiker'. Taux 10Y remontent. TLT perd -2% sur la semaine."}, + + {"name": "GDP T1 2022 — Récession surprise (-1.4%, attendu +1.1%)", + "start_date": "2022-04-28", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "+1.1%", "actual_value": "-1.4%", "surprise_pct": -55, + "unit": "% ann.", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "GDP Q1 2022 : -1.4%, première contraction depuis COVID. Attendu +1.1%. Choc : stagflation. Inflation à 8.5% et croissance négative. La Fed va-t-elle hiker malgré la récession? Oui → stagflation trade."}, + + {"name": "GDP T2 2022 — Récession technique confirmée (-0.9%)", + "start_date": "2022-07-28", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "+0.4%", "actual_value": "-0.9%", "surprise_pct": -40, + "unit": "% ann.", "impact_score": 0.90, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "GDP Q2 2022 : -0.9%. 2e trimestre négatif consécutif → définition technique de récession. Mais le NBER ne le confirme pas (marché du travail fort). Fed tient le cap hawkish malgré la récession. Jour du +75pb FOMC."}, + + {"name": "GDP T1 2024 — Miss (1.6% vs 2.4% attendu, stagflation fear)", + "start_date": "2024-04-25", "level": "medium", "category": "calendar", "sub_type": "GDP", + "expected_value": "+2.4%", "actual_value": "+1.6%", "surprise_pct": -35, + "unit": "% ann.", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "GDP Q1 2024 : +1.6%, grosse déception vs +2.4% attendu. PCE prix à +3.7% (inflation toujours haute). 'Stagflation light' : croissance ralentit mais inflation reste. SPY -1.5%. Retarde les baisses Fed."}, + + {"name": "GDP T1 2025 — Contraction (-0.3%) sous choc tarifaire Trump", + "start_date": "2025-04-30", "level": "long", "category": "calendar", "sub_type": "GDP", + "expected_value": "+0.4%", "actual_value": "-0.3%", "surprise_pct": -40, + "unit": "% ann.", "impact_score": 0.90, "absorption_pct": 90, + "affected_assets": _ALL, + "description": "GDP Q1 2025 : -0.3%, 1ère contraction depuis COVID. Imports explosent avant les tarifs Trump (entreprises stockent). Consommation ralentit. SPY -2%. Débat : récession ou stockage temporaire? Incertitude maximale."}, + + # ══════════════════════════════════════════════════════════ + # ISM / PMI — ACTIVITÉ MANUFACTURIÈRE + # ══════════════════════════════════════════════════════════ + + {"name": "ISM Manufacturing Mars 2020 — Effondrement COVID (49.1)", + "start_date": "2020-04-01", "level": "medium", "category": "calendar", "sub_type": "ISM", + "expected_value": "44.0", "actual_value": "49.1", "surprise_pct": +13, + "unit": "index", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _EQ + ["GLD", "USO"], + "description": "ISM Manufacturing mars 2020 : 49.1 (contraction). Meilleur qu'attendu (44.0 consensus). La déstructuration COVID arrive mais plus progressivement que craint. Les services vont bien pire."}, + + {"name": "ISM Manufacturing Décembre 2022 — Contraction prolongée (48.4)", + "start_date": "2023-01-04", "level": "medium", "category": "calendar", "sub_type": "ISM", + "expected_value": "48.5", "actual_value": "48.4", "surprise_pct": -2, + "unit": "index", "impact_score": 0.72, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "EURUSD=X"], + "description": "ISM Manufacturing déc 2022 : 48.4, en contraction 2e mois consécutif. Marché commence à pricer un atterrissage plus dur. Mais les services restent solides. Tension entre signaux."}, + + {"name": "ISM Manufacturing Juin 2023 — Contraction accélérée (46.0)", + "start_date": "2023-07-03", "level": "medium", "category": "calendar", "sub_type": "ISM", + "expected_value": "47.2", "actual_value": "46.0", "surprise_pct": -18, + "unit": "index", "impact_score": 0.75, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "GLD", "EURUSD=X"], + "description": "ISM Manufacturing juin 2023 : 46.0, plus bas depuis mai 2020. Contraction accélère. Attendu 47.2. Ajoute aux craintes de récession malgré le marché du travail fort. TLT + (récession trade)."}, + + {"name": "ISM Manufacturing Juillet 2024 — 46.8 (contraction + NFP miss → récession panic)", + "start_date": "2024-08-01", "level": "long", "category": "calendar", "sub_type": "ISM", + "expected_value": "48.8", "actual_value": "46.8", "surprise_pct": -25, + "unit": "index", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": _ALL, + "description": "ISM Manufacturing juil 2024 : 46.8 (miss vs 48.8). Combiné au NFP miss +114K le lendemain, déclenche la panique 'hard landing'. VIX spike, Nikkei -12%, SPY -6%. Catalyseur du grand drawdown d'août 2024."}, + + # ══════════════════════════════════════════════════════════ + # BOJ — BANQUE DU JAPON (2020-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "BOJ — Extension COVID QE + achat ETF actions (stimulus japonais)", + "start_date": "2020-04-27", "level": "medium", "category": "calendar", "sub_type": "BOJ", + "expected_value": "YCC ±20pb + CP", "actual_value": "YCC ±25pb + achats ETF x2", "surprise_pct": +10, + "unit": "signal", "impact_score": 0.78, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "EFA", "GLD"], + "description": "BOJ double ses achats d'ETF actions (de 6 à 12T¥/an) et élargit le YCC à ±25pb. Soutien sans précédent des actifs risqués japonais. Yen se déprécie modestement. Nikkei bien soutenu."}, + + {"name": "BOJ — Maintien YCC malgré spéculation (forte pression vendeuse JGB)", + "start_date": "2022-06-17", "level": "medium", "category": "calendar", "sub_type": "BOJ", + "expected_value": "ajustement YCC", "actual_value": "YCC maintenu (±25pb)", "surprise_pct": -15, + "unit": "signal", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "EFA", "TLT", "GLD"], + "description": "BOJ maintient le YCC malgré les attaques spéculatives de hedge funds. Kuroda : 'pas de changement de politique'. USD/JPY monte à 135, plus haut depuis 2002. Yen à 24Y low. Pression inflationniste importée au Japon."}, + + {"name": "BOJ — Surprise : élargissement YCC de ±25pb à ±50pb", + "start_date": "2022-12-20", "level": "long", "category": "calendar", "sub_type": "BOJ", + "expected_value": "YCC ±25pb (stable)", "actual_value": "YCC ±50pb", "surprise_pct": -25, + "unit": "pb", "impact_score": 0.90, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "TLT", "GLD", "EFA", "SPY"], + "description": "BOJ surprend le monde : élargit la bande YCC de ±25pb à ±50pb. Premier mouvement vers normalisation depuis 2016. USD/JPY chute de 137 à 131 en heures. Marché obligataire mondial se vend. Début de la fin du YCC."}, + + {"name": "BOJ — Fin des taux négatifs (NIRP) : premier hike depuis 2007", + "start_date": "2024-03-19", "level": "long", "category": "calendar", "sub_type": "BOJ", + "expected_value": "hold ou +10pb", "actual_value": "+10pb (fin NIRP)", "surprise_pct": +5, + "unit": "pb", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "EFA", "TLT", "GLD", "EURUSD=X"], + "description": "BOJ met fin aux taux négatifs (NIRP), première hausse depuis 2007. Taux 0-0.1%. Fin du YCC. Annonce plus douce qu'attendue sur le 'chemin futur'. USD/JPY chute -1.5%, puis se reprend. Début de la normalisation."}, + + {"name": "BOJ — Surprise +15pb → Débâcle carry trade (crash août 2024)", + "start_date": "2024-07-31", "level": "long", "category": "calendar", "sub_type": "BOJ", + "expected_value": "hold ou +5pb", "actual_value": "+15pb (taux 0.25%)", "surprise_pct": -30, + "unit": "pb", "impact_score": 0.96, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "SPY", "QQQ", "VXX", "GLD", "EFA"], + "description": "BOJ hausse +15pb de façon surprise. Yen +7% en 48h. USD/JPY 161 → 141. Débâcle massive du carry trade yen : VIX spike à 65 (3e plus haut jamais), Nikkei -12% en 2 jours, SPY -6%. Crise de liquidité mondiale brève mais intense."}, + + {"name": "BOJ — Hausse +25pb (Ueda confirme normalisation graduelle)", + "start_date": "2025-01-24", "level": "medium", "category": "calendar", "sub_type": "BOJ", + "expected_value": "+15pb ou +25pb", "actual_value": "+25pb (taux 0.50%)", "surprise_pct": +5, + "unit": "pb", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": ["USDJPY=X", "EFA", "TLT", "GLD"], + "description": "BOJ hausse à 0.50%, plus haut depuis 2008. Ueda signale une approche graduelle future. USD/JPY chute -1%. Confirme le cycle de normalisation mais sans panique. Yen en tendance de fond haussière vs USD."}, + + # ══════════════════════════════════════════════════════════ + # ECB — BANQUE CENTRALE EUROPÉENNE (2022-2025) + # ══════════════════════════════════════════════════════════ + + {"name": "ECB — Première hausse en 11 ans : +50pb (surprise vs +25pb attendu)", + "start_date": "2022-07-21", "level": "long", "category": "calendar", "sub_type": "ECB", + "expected_value": "+25pb", "actual_value": "+50pb + TPI anti-fragmentation", "surprise_pct": +15, + "unit": "pb", "impact_score": 0.90, "absorption_pct": 100, + "affected_assets": ["EURUSD=X", "EFA", "TLT", "GLD", "GBPUSD=X"], + "description": "BCE monte +50pb (vs +25 attendu) en première hausse depuis 2011. Lance le TPI (Transmission Protection Instrument) anti-fragmentation. EUR/USD rebond +1.5%. BTP Italie spreads se compriment. Hawkish surprise."}, + + {"name": "ECB — Record +75pb (plus grande hausse depuis création Euro)", + "start_date": "2022-09-08", "level": "long", "category": "calendar", "sub_type": "ECB", + "expected_value": "+75pb", "actual_value": "+75pb (taux 1.25%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.88, "absorption_pct": 100, + "affected_assets": ["EURUSD=X", "EFA", "TLT", "GLD", "GBPUSD=X"], + "description": "BCE monte +75pb, le plus fort depuis la création de l'euro en 1999. Inflation eurozone à 9.1%. Lagarde ferme la porte à une récession → marché hausse EUR. Signal que la zone euro va souffrir mais la BCE doit agir."}, + + {"name": "ECB — Dernière hausse du cycle : +25pb (pic 4.00%)", + "start_date": "2023-09-14", "level": "long", "category": "calendar", "sub_type": "ECB", + "expected_value": "+25pb ou hold", "actual_value": "+25pb (fin du cycle)", "surprise_pct": -5, + "unit": "pb", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": ["EURUSD=X", "EFA", "TLT", "GLD"], + "description": "BCE monte +25pb à 4.00%, signale que c'est probablement la fin. Taux maintenus à 4% pendant 9 mois. EUR/USD perd -0.5% sur la semaine. Marché commence à pricer les baisses 2024."}, + + {"name": "ECB — Première baisse de taux depuis 2019 : -25pb", + "start_date": "2024-06-06", "level": "long", "category": "calendar", "sub_type": "ECB", + "expected_value": "-25pb", "actual_value": "-25pb (taux 3.75%)", "surprise_pct": 0, + "unit": "pb", "impact_score": 0.82, "absorption_pct": 100, + "affected_assets": ["EURUSD=X", "EFA", "TLT", "GLD", "GBPUSD=X"], + "description": "BCE baisse -25pb pour la première fois depuis 2019. Mais projections inflation révisées à la hausse. EUR/USD recule -0.3%. Signal de 'gradualisme' — pas de séries de baisses rapides comme Fed."}, + + # ══════════════════════════════════════════════════════════ + # BOE — BANQUE D'ANGLETERRE (2022-2024) + # ══════════════════════════════════════════════════════════ + + {"name": "BOE — +50pb (plus forte hausse depuis 1995) + Truss Budget Crisis", + "start_date": "2022-08-04", "level": "long", "category": "calendar", "sub_type": "BOE", + "expected_value": "+50pb", "actual_value": "+50pb + avertissement récession", "surprise_pct": -10, + "unit": "pb", "impact_score": 0.85, "absorption_pct": 100, + "affected_assets": ["GBPUSD=X", "TLT", "GLD"], + "description": "BOE monte +50pb, plus fort depuis 1995. Prévoit une récession 'prolongée'. CPI UK à 10.1%. Mini-budget Truss fin septembre va accentuer la crise (gilts crash). GBP perd -10% sur les semaines suivantes."}, + + {"name": "BOE — Intervention urgence (Gilts crash, fonds de pension)", + "start_date": "2022-09-28", "level": "long", "category": "calendar", "sub_type": "BOE", + "expected_value": "QT", "actual_value": "QE urgence temporaire (gilts)", "surprise_pct": +20, + "unit": "signal", "impact_score": 0.92, "absorption_pct": 100, + "affected_assets": ["GBPUSD=X", "TLT", "GLD", "VXX", "EFA"], + "description": "BOE lance un QE d'urgence pour acheter des gilts (obligations UK) après l'effondrement post mini-budget Truss. Gilts à 30Y perdent -30% en une semaine. Fonds de pension LDI en crise de liquidité. GBP à 1.035 (ATL). Crise systémique évitée de justesse."}, + + {"name": "BOE — Première baisse de taux depuis COVID : -25pb", + "start_date": "2024-08-01", "level": "long", "category": "calendar", "sub_type": "BOE", + "expected_value": "hold ou -25pb (50/50)", "actual_value": "-25pb (taux 5.00%)", "surprise_pct": +8, + "unit": "pb", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": ["GBPUSD=X", "EFA", "TLT", "GLD"], + "description": "BOE baisse -25pb (vote 5-4, très serré). Première baisse depuis mars 2020. Bailey : 'risques inflationnistes se dissipent'. GBP perd -0.5%. Signale le début du cycle d'assouplissement UK, avec prudence."}, + + # ══════════════════════════════════════════════════════════ + # PCE / CORE DATA (reference Fed) + # ══════════════════════════════════════════════════════════ + + {"name": "PCE Janvier 2024 — Core PCE 2.8% (inflation sticky, cut repoussé)", + "start_date": "2024-02-29", "level": "medium", "category": "calendar", "sub_type": "PCE", + "expected_value": "2.4%", "actual_value": "2.8%", "surprise_pct": -25, + "unit": "% a/a", "impact_score": 0.80, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "GLD", "EURUSD=X"], + "description": "Core PCE jan 2024 : 2.8% a/a, au-dessus de 2.4% attendu et des 2.6% de décembre. L'indicateur préféré de la Fed refuse de descendre. Repousse les anticipations de baisse mars → juin. TLT -1.2%."}, + + {"name": "PCE Septembre 2024 — Core PCE 2.6% (vers 2% mais résistant)", + "start_date": "2024-10-31", "level": "short", "category": "calendar", "sub_type": "PCE", + "expected_value": "2.6%", "actual_value": "2.6%", "surprise_pct": 0, + "unit": "% a/a", "impact_score": 0.68, "absorption_pct": 100, + "affected_assets": _EQ + ["TLT", "GLD"], + "description": "Core PCE sept 2024 : 2.6%, comme attendu. Toujours au-dessus de l'objectif 2%. Confirme que la désinflation 'last mile' est lente. Marché accepte le 'higher for longer' même en phase de baisses."}, +] + + +def bootstrap_eco_events(force: bool = False) -> Dict[str, Any]: + """ + Insert curated economic calendar events into market_events DB. + Idempotent: skips events whose name already exists. + Returns: {inserted, skipped, errors, total} + """ + from services.database import get_all_market_events, save_market_event + + existing = {ev.get("name", "") for ev in get_all_market_events()} + + if force: + from services.database import delete_market_event, get_all_market_events as _gae + eco_names = {e["name"] for e in ECO_EVENTS} + for ev in _gae(): + if ev.get("name") in eco_names: + delete_market_event(ev["id"]) + existing = set() + logger.info("[eco_bootstrap] Force: existing eco events deleted") + + import json + inserted = skipped = errors = 0 + for ev in ECO_EVENTS: + if ev["name"] in existing: + skipped += 1 + continue + try: + save_market_event({ + "name": ev["name"], + "start_date": ev["start_date"], + "end_date": ev.get("end_date"), + "level": ev["level"], + "category": ev["category"], + "sub_type": ev.get("sub_type"), + "description": ev.get("description", ""), + "market_impact": ev.get("description", "")[:80], + "affected_assets": ev.get("affected_assets", []), + "impact_score": ev.get("impact_score", 0.75), + "expected_value": ev.get("expected_value"), + "actual_value": ev.get("actual_value"), + "surprise_pct": ev.get("surprise_pct"), + "unit": ev.get("unit"), + "absorption_pct": ev.get("absorption_pct", 100), + }) + inserted += 1 + except Exception as e: + logger.warning(f"[eco_bootstrap] Error inserting '{ev['name'][:40]}': {e}") + errors += 1 + + from services.database import count_market_events + total = count_market_events() + logger.info(f"[eco_bootstrap] inserted={inserted} skipped={skipped} errors={errors} total={total}") + return {"inserted": inserted, "skipped": skipped, "errors": errors, "total": total} diff --git a/backend/services/instrument_service.py b/backend/services/instrument_service.py index 267959f..3637309 100644 --- a/backend/services/instrument_service.py +++ b/backend/services/instrument_service.py @@ -575,8 +575,14 @@ def _get_relevant_events( "title": ev.get("name") or ev.get("event_name") or "", "level": ev.get("level", "medium"), "category": ev.get("category", ""), + "sub_type": ev.get("sub_type") or None, "description": (ev.get("description") or "")[:120], "impact_score": float(ev.get("impact_score") or 0.5), + "expected_value": ev.get("expected_value") or None, + "actual_value": ev.get("actual_value") or None, + "surprise_pct": ev.get("surprise_pct"), + "unit": ev.get("unit") or None, + "absorption_pct": ev.get("absorption_pct"), }) # Sort by start_date asc for timeline display, cap at 30 diff --git a/frontend/src/pages/InstrumentDashboard.tsx b/frontend/src/pages/InstrumentDashboard.tsx index f67425f..b70f094 100644 --- a/frontend/src/pages/InstrumentDashboard.tsx +++ b/frontend/src/pages/InstrumentDashboard.tsx @@ -13,7 +13,7 @@ const api = axios.create({ baseURL: '/api' }) // ── Types ───────────────────────────────────────────────────────────────────── interface Driver { - key: string; label: string; weight: number; keywords: string[] + key: string; label: string; weight: number; keywords: string[]; type?: string } interface InstrumentConfig { @@ -29,7 +29,9 @@ interface LinePoint { time: string; value: number } interface SnapshotEvent { date: string; end_date: string | null; title: string; level: string - category: string; description: string; impact_score: number + category: string; sub_type?: string; description: string; impact_score: number + expected_value?: string | null; actual_value?: string | null + surprise_pct?: number | null; unit?: string | null; absorption_pct?: number | null } interface RegimeSignals { @@ -114,6 +116,32 @@ function pctN(a: number | undefined, b: number | undefined): number { return ((a - b) / b) * 100 } +// ── Driver type config ──────────────────────────────────────────────────────── + +const DRIVER_TYPES = ['event_calendar', 'report', 'geopolitical', 'fundamental', 'sentiment', 'technical'] as const +type DriverType = typeof DRIVER_TYPES[number] + +const DRIVER_TYPE_CFG: Record = { + event_calendar: { short: 'Cal.', tw: 'text-amber-400 bg-amber-900/30 border-amber-700/30' }, + report: { short: 'Rep.', tw: 'text-blue-400 bg-blue-900/30 border-blue-700/30' }, + geopolitical: { short: 'Geo.', tw: 'text-red-400 bg-red-900/30 border-red-700/30' }, + fundamental: { short: 'Fund.', tw: 'text-emerald-400 bg-emerald-900/30 border-emerald-700/30' }, + sentiment: { short: 'Sent.', tw: 'text-violet-400 bg-violet-900/30 border-violet-700/30' }, + technical: { short: 'Tech.', tw: 'text-cyan-400 bg-cyan-900/30 border-cyan-700/30' }, +} + +function DriverTypeBadge({ type }: { type?: string }) { + if (!type) return null + const cfg = DRIVER_TYPE_CFG[type] + if (!cfg) return null + return ( + + {cfg.short} + + ) +} + // ── Macro regime colour mapping ─────────────────────────────────────────────── const MACRO_COLOR_MAP: Record = { @@ -132,7 +160,7 @@ function macroRegimeColor(dominant: string): string { return MACRO_COLOR_MAP[dominant] ?? 'slate' } -// ── RegimeCard (métriques de signaux) ───────────────────────────────────────── +// ── RegimeCard ──────────────────────────────────────────────────────────────── function RegimeCard({ regime, macroRegime, signalsAt, dateLabel, @@ -155,7 +183,6 @@ function RegimeCard({ amber: 'border-amber-700/40 bg-amber-950/30', } - // 6 signal metrics displayed as a compact grid const ma50Color = signals.ma50_above_ma200 ? 'text-emerald-400' : 'text-red-400' const volColor = (signals.vol_ratio_pct ?? 0) > 130 ? 'text-orange-400' : (signals.vol_ratio_pct ?? 0) < 70 ? 'text-cyan-400' : 'text-slate-300' @@ -166,21 +193,9 @@ function RegimeCard({ sub: signals.ma50_above_ma200 === true ? '↑ Golden cross' : signals.ma50_above_ma200 === false ? '↓ Death cross' : '', color: ma50Color, }, - { - label: 'Slope MA50 (10j)', - value: fmt(signals.ma50_slope_pct) + '%', - color: pctColor(signals.ma50_slope_pct), - }, - { - label: 'Slope MA200 (10j)', - value: fmt(signals.ma200_slope_pct) + '%', - color: pctColor(signals.ma200_slope_pct), - }, - { - label: 'Momentum 20j', - value: fmt(signals.momentum_20d_pct) + '%', - color: pctColor(signals.momentum_20d_pct), - }, + { label: 'Slope MA50 (10j)', value: fmt(signals.ma50_slope_pct) + '%', color: pctColor(signals.ma50_slope_pct) }, + { label: 'Slope MA200 (10j)', value: fmt(signals.ma200_slope_pct) + '%', color: pctColor(signals.ma200_slope_pct) }, + { label: 'Momentum 20j', value: fmt(signals.momentum_20d_pct) + '%', color: pctColor(signals.momentum_20d_pct) }, { label: 'Distance MA200', value: fmt(signals.dist_ma200_pct) + '%', @@ -195,13 +210,11 @@ function RegimeCard({ }, ] - // Macro regime display const macroCol = macroRegime ? macroRegimeColor(macroRegime.dominant) : 'slate' const top3Macro = macroRegime?.ranked?.slice(0, 3) ?? [] return (
- {/* Header */}
@@ -210,7 +223,6 @@ function RegimeCard({ {dateLabel}
- {/* Macro regime section (global cycle) */} {macroRegime && macroRegime.dominant !== 'incertain' && (
@@ -240,7 +252,6 @@ function RegimeCard({
)} - {/* Technical regime label + confidence */}
Régime technique
{regime.current}
@@ -253,7 +264,6 @@ function RegimeCard({
- {/* 6 signal metrics — 2 column grid */}
{metrics.map(m => (
@@ -364,13 +374,32 @@ function TrendCard({ trend, dateLabel }: { trend: TrendMetrics; dateLabel: strin // ── EventsCard ──────────────────────────────────────────────────────────────── -function EventsCard({ events }: { events: SnapshotEvent[] }) { +function EventsCard({ events, selectedDate }: { events: SnapshotEvent[]; selectedDate: string | null }) { const navigate = useNavigate() const LEVEL_C: Record = { long: 'text-violet-400 bg-violet-900/30 border-violet-700/30', medium: 'text-blue-400 bg-blue-900/30 border-blue-700/30', short: 'text-emerald-400 bg-emerald-900/30 border-emerald-700/30', } + + function isActiveAt(ev: SnapshotEvent): boolean { + if (!selectedDate) return false + const evStart = ev.date + const evEnd = ev.end_date + if (evStart > selectedDate) return false + if (evEnd) return evEnd >= selectedDate + // point event: active if within 30 days after + const diffDays = (new Date(selectedDate).getTime() - new Date(evStart).getTime()) / 86400000 + return diffDays <= 30 + } + + function surpriseColor(v: number | null | undefined): string { + if (v === null || v === undefined) return 'text-slate-400' + if (v > 5) return 'text-emerald-400' + if (v < -5) return 'text-red-400' + return 'text-slate-400' + } + return (
@@ -381,25 +410,75 @@ function EventsCard({ events }: { events: SnapshotEvent[] }) {
Aucun événement lié trouvé
) : (
- {events.map((ev, i) => ( -
navigate(`/timeline?date=${ev.date}`)} - > -
- {ev.title} - - {ev.level === 'long' ? 'LT' : ev.level === 'medium' ? 'MT' : 'CT'} - + {events.map((ev, i) => { + const active = isActiveAt(ev) + return ( +
navigate(`/timeline?date=${ev.date}`)} + > +
+
+ {active && } + {ev.title} +
+
+ {ev.sub_type && ( + + {ev.sub_type} + + )} + + {ev.level === 'long' ? 'LT' : ev.level === 'medium' ? 'MT' : 'CT'} + +
+
+ + {/* Eco calendar fields */} + {(ev.expected_value || ev.actual_value) && ( +
+ {ev.expected_value && ( + Att. {ev.expected_value} + )} + {ev.actual_value && ( + Réel {ev.actual_value} + )} + {ev.surprise_pct !== null && ev.surprise_pct !== undefined && ( + + {ev.surprise_pct > 0 ? '+' : ''}{ev.surprise_pct.toFixed(0)}% + {ev.surprise_pct > 5 ? ' ↑' : ev.surprise_pct < -5 ? ' ↓' : ''} + + )} + {ev.unit && {ev.unit}} +
+ )} + + {ev.absorption_pct !== null && ev.absorption_pct !== undefined && ( +
+
+ Absorption marché{ev.absorption_pct}% +
+
+
+
+
+ )} + +
+ + {fmtDateFR(ev.date)}{ev.end_date ? ` → ${fmtDateFR(ev.end_date)}` : ''} + {ev.impact_score > 0.7 && } +
+ {ev.description &&

{ev.description}

}
-
- - {ev.date}{ev.end_date ? ` → ${ev.end_date}` : ''} - {ev.impact_score > 0.7 && } -
- {ev.description &&

{ev.description}

} -
- ))} + ) + })}
)}
@@ -455,9 +534,9 @@ function eventMatchesDriver(ev: SnapshotEvent, keywords: string[]): boolean { } function EventTimelineStrip({ - events, priceData, drivers, + events, priceData, drivers, selectedDate, }: { - events: SnapshotEvent[]; priceData: PriceCandle[]; drivers: Driver[] + events: SnapshotEvent[]; priceData: PriceCandle[]; drivers: Driver[]; selectedDate: string | null }) { if (priceData.length < 2) return null @@ -468,21 +547,21 @@ function EventTimelineStrip({ function leftPct(d: string) { return Math.max(0, Math.min(99, ((dateToMs(d) - chartStart) / totalMs) * 100)) } function widthPct(start: string, end: string | null): number { - // Default width = 3% of period if no end date const endMs = end ? dateToMs(end) : dateToMs(start) + totalMs * 0.03 return Math.min(100, Math.max(0.4, ((endMs - dateToMs(start)) / totalMs) * 100)) } - // Top 4 drivers by weight const topDrivers = [...drivers].sort((a, b) => b.weight - a.weight).slice(0, 4) - // Events matched by ANY driver (for fallback row) const allKeywords = topDrivers.flatMap(d => d.keywords ?? []) const matchedAnyIdxs = new Set( events.map((ev, i) => eventMatchesDriver(ev, allKeywords) ? i : -1).filter(i => i >= 0) ) const unmatchedEvs = events.filter((_ev, i) => !matchedAnyIdxs.has(i)) + // Cursor position for the selected date + const cursorLeft = selectedDate ? leftPct(selectedDate) : null + return (
Événements par driver
@@ -492,13 +571,13 @@ function EventTimelineStrip({ const matchedEvs = events.filter(ev => eventMatchesDriver(ev, driver.keywords ?? [])) return (
- - {driver.label} - - {/* paddingRight aligns with chart right price scale (~60px) */} +
+ + {driver.label} + + +
{matchedEvs.map((ev, i) => { const left = leftPct(ev.date) @@ -523,6 +602,13 @@ function EventTimelineStrip({
)} + {/* Vertical cursor for selected date */} + {cursorLeft !== null && ( +
+ )}
) @@ -552,6 +638,12 @@ function EventTimelineStrip({
) })} + {cursorLeft !== null && ( +
+ )}
)} @@ -582,7 +674,10 @@ function DriversPanel({ instrumentId, drivers, onSave, onClose }: { } function addDriver() { - setLocal(prev => [...prev, { key: `driver_${Date.now()}`, label: 'Nouveau driver', weight: 0.5, keywords: [] }]) + setLocal(prev => [...prev, { + key: `driver_${Date.now()}`, label: 'Nouveau driver', + weight: 0.5, keywords: [], type: 'fundamental', + }]) } function removeDriver(i: number) { @@ -634,6 +729,16 @@ function DriversPanel({ instrumentId, drivers, onSave, onClose }: { value={d.label} onChange={e => updateDriver(i, 'label', e.target.value)} /> + {/* Type selector */} +
Poids (null) const [editDrivers, setEditDrivers] = useState(false) - // Local drivers (updated optimistically after save) const [localDrivers, setLocalDrivers] = useState(null) const instrumentId = id.toUpperCase() @@ -720,7 +824,6 @@ export default function InstrumentDashboard() { if (date) setSelectedDate(date) }, []) - // ── Lookup maps ─────────────────────────────────────────────────────────── const { priceMap, indMap, sortedDates, dateIndex } = useMemo(() => { if (!snapshot) return { priceMap: {} as Record, indMap: {} as Record>, sortedDates: [] as string[], dateIndex: {} as Record } const priceMap: Record = {} @@ -786,7 +889,6 @@ export default function InstrumentDashboard() { } }, [effectiveDate, priceMap, indMap, sortedDates, dateIndex, snapshot]) - // ── UI ──────────────────────────────────────────────────────────────────── const grouped = CATEGORY_ORDER.map(cat => ({ cat, label: CATEGORY_LABELS[cat] ?? cat, items: instruments.filter(i => i.category === cat), @@ -797,7 +899,6 @@ export default function InstrumentDashboard() { const dateLabel = effectiveDate ? fmtDateFR(effectiveDate) : '—' const displayPrice = dateTrend?.current_price ?? snapshot?.current_price - // Drivers to use (local override after edit, else from snapshot) const activeDrivers = localDrivers ?? snapshot?.instrument?.drivers ?? [] return ( @@ -860,7 +961,6 @@ export default function InstrumentDashboard() { )}
- {/* Drivers edit button */} {snapshot && ( )} - {/* Period selector */}
{PERIODS.map(p => (
- {/* Drivers edit panel */} {editDrivers && ( )} - {/* AI Narrative */}