fix: sim portfolio asset_class fallback + consolidate risk into Risk Dashboard
- portfolio_risk.py: add _infer_asset_class() with ticker→asset_class map covering energy/metals/agri/indices/forex/rates futures, ETFs, forex pairs, exchange prefixes (NSE:). Fallback applied when JOIN finds no match (orphaned pattern_id after re-seed). Fixes "unknown 100%" shown in screenshot. - RiskDashboard.tsx: add Portefeuille Réel / Simulé toggle at top. New SimRiskPanel component with KPI row + concentration bars + conflict cards + AI recommendations — all visible inline in Risk Dashboard. Red badge on Simulé tab when danger alerts exist. - JournalDeBord.tsx: remove standalone Risque Sim. tab (moved to Risk Dashboard). Replace with a red banner in summary cards when conflicts are detected, pointing user to Risk Dashboard → Simulé. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,55 @@ from services.database import get_conn
|
||||
|
||||
_BEARISH_KEYWORDS = {"bear", "put", "short", "sell", "vente", "baissier"}
|
||||
|
||||
# Ticker → asset_class mapping for common instruments (fallback when pattern not in DB)
|
||||
_TICKER_AC: Dict[str, str] = {
|
||||
# Energy
|
||||
"CL=F": "energy", "BZ=F": "energy", "NG=F": "energy", "RB=F": "energy",
|
||||
"HO=F": "energy", "USO": "energy", "XLE": "energy", "XOP": "energy", "OIL": "energy",
|
||||
# Metals
|
||||
"GC=F": "metals", "SI=F": "metals", "HG=F": "metals", "PL=F": "metals",
|
||||
"PA=F": "metals", "GLD": "metals", "SLV": "metals", "GDX": "metals", "GDXJ": "metals",
|
||||
# Agriculture
|
||||
"ZW=F": "agriculture", "ZC=F": "agriculture", "ZS=F": "agriculture",
|
||||
"CT=F": "agriculture", "KC=F": "agriculture", "SB=F": "agriculture", "CC=F": "agriculture",
|
||||
"WEAT": "agriculture", "CORN": "agriculture", "SOYB": "agriculture",
|
||||
# Equity indices
|
||||
"^GSPC": "indices", "^DJI": "indices", "^NDX": "indices", "^RUT": "indices",
|
||||
"^VIX": "indices", "^FTSE": "indices", "^GDAXI": "indices", "^FCHI": "indices",
|
||||
"^N225": "indices", "^HSI": "indices", "^NSEI": "indices", "^BSESN": "indices",
|
||||
"^STOXX50E": "indices", "^IBEX": "indices",
|
||||
"SPY": "indices", "QQQ": "indices", "IWM": "indices", "DIA": "indices",
|
||||
"VXX": "indices", "UVXY": "indices", "SVXY": "indices",
|
||||
# Forex
|
||||
"EURUSD=X": "forex", "GBPUSD=X": "forex", "USDJPY=X": "forex",
|
||||
"AUDUSD=X": "forex", "USDCAD=X": "forex", "USDCHF=X": "forex",
|
||||
"NZDUSD=X": "forex", "EURGBP=X": "forex", "EURJPY=X": "forex",
|
||||
"GBPJPY=X": "forex", "USDCNH=X": "forex",
|
||||
"FXE": "forex", "UUP": "forex", "FXB": "forex", "FXY": "forex",
|
||||
# Rates
|
||||
"ZB=F": "rates", "ZN=F": "rates", "ZF=F": "rates", "ZT=F": "rates",
|
||||
"TLT": "rates", "IEF": "rates", "SHY": "rates", "HYG": "rates",
|
||||
"LQD": "rates", "EMB": "rates",
|
||||
}
|
||||
|
||||
|
||||
def _infer_asset_class(ticker: str) -> str:
|
||||
"""Derive asset_class from ticker when not stored in DB."""
|
||||
t = (ticker or "").upper().strip()
|
||||
if t in _TICKER_AC:
|
||||
return _TICKER_AC[t]
|
||||
if ":" in t: # NSE:RELIANCE, BSE:TCS, etc.
|
||||
return "equities"
|
||||
if t.endswith("=X") and len(t) >= 7: # forex pairs like EURUSD=X
|
||||
return "forex"
|
||||
if t.endswith("=F"): # generic futures
|
||||
return "energy" # most unknown futures are commodities
|
||||
if t.startswith("^"): # index
|
||||
return "indices"
|
||||
if t.isalpha() and len(t) <= 5: # short alpha = equity
|
||||
return "equities"
|
||||
return "unknown"
|
||||
|
||||
|
||||
def _direction(strategy: str) -> str:
|
||||
s = (strategy or "").lower()
|
||||
@@ -12,7 +61,7 @@ def _direction(strategy: str) -> str:
|
||||
|
||||
|
||||
def get_open_simulation_trades() -> List[Dict[str, Any]]:
|
||||
"""Open trades enriched with asset_class from joined pattern table."""
|
||||
"""Open trades enriched with asset_class — via stored column, JOIN fallback, then ticker inference."""
|
||||
conn = get_conn()
|
||||
rows = conn.execute("""
|
||||
SELECT tep.*,
|
||||
@@ -23,7 +72,13 @@ def get_open_simulation_trades() -> List[Dict[str, Any]]:
|
||||
ORDER BY tep.entry_date DESC
|
||||
""").fetchall()
|
||||
conn.close()
|
||||
return [dict(r) for r in rows]
|
||||
result = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
if not d.get("asset_class"):
|
||||
d["asset_class"] = _infer_asset_class(d.get("underlying", ""))
|
||||
result.append(d)
|
||||
return result
|
||||
|
||||
|
||||
def analyze_simulation_portfolio() -> Dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user