feat: instrument model
This commit is contained in:
@@ -193,6 +193,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"name": "EUR/USD",
|
||||
"description": "Taux de change Euro/Dollar — modèle causal 3 couches avec 4 domaines d'influence",
|
||||
"output_node": "eurusd",
|
||||
"price_intercept": 1.10,
|
||||
"pip_to_price": 0.0001,
|
||||
"yf_ticker": "EURUSD=X",
|
||||
"nodes": [
|
||||
# ── Layer 0a : event inputs ───────────────────────────────────────────────
|
||||
{"id":"in_cb", "label":"Banques Centrales", "node_type":"input_event", "category":"central_bank", "unit":"pips","display_col":0,"description":"Décisions Fed/BCE, minutes, forward guidance. Décroissance exp ~14j.","event_category":"central_bank"},
|
||||
@@ -246,6 +249,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"USDJPY": {
|
||||
"name": "USD/JPY", "output_node": "usdjpy",
|
||||
"description": "Carry & safe haven — yield diff 10Y + BoJ + risk appetite",
|
||||
"price_intercept": 145.0,
|
||||
"pip_to_price": 0.01,
|
||||
"yf_ticker": "USDJPY=X",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales", "node_type":"input_event","category":"central_bank", "unit":"pips","display_col":0,"event_category":"central_bank","description":"Fed/BoJ décisions."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"NFP, CPI US, Tankan, CPI Japon."},
|
||||
@@ -283,6 +289,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"XAUUSD": {
|
||||
"name": "XAU/USD (Or)", "output_node": "xauusd",
|
||||
"description": "Or/Dollar — taux réels, dollar, géopolitique, banques centrales",
|
||||
"price_intercept": 2800.0,
|
||||
"pip_to_price": 1.0,
|
||||
"yf_ticker": "GC=F",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales", "node_type":"input_event","category":"central_bank", "unit":"pips","display_col":0,"event_category":"central_bank","description":"Fed (taux réels) → or."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"CPI, PCE → anticipations taux réels → or."},
|
||||
@@ -324,6 +333,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"SP500": {
|
||||
"name": "S&P 500", "output_node": "sp500",
|
||||
"description": "Indice actions US — taux, bénéfices, risque, liquidités",
|
||||
"price_intercept": 5000.0,
|
||||
"pip_to_price": 1.0,
|
||||
"yf_ticker": "^GSPC",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales", "node_type":"input_event","category":"central_bank","unit":"pips","display_col":0,"event_category":"central_bank","description":"Fed pivot/hike → SP500 directement."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"NFP, CPI, PIB US."},
|
||||
@@ -366,6 +378,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"TLT": {
|
||||
"name": "TLT (US Long Bonds)", "output_node": "tlt",
|
||||
"description": "ETF obligations US 20Y+ — duration, inflation, récession, supply",
|
||||
"price_intercept": 85.0,
|
||||
"pip_to_price": 0.01,
|
||||
"yf_ticker": "TLT",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales","node_type":"input_event","category":"central_bank","unit":"pips","display_col":0,"event_category":"central_bank","description":"FOMC décisions/minutes → impact direct TLT."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"CPI, PCE, NFP → réévaluation taux."},
|
||||
@@ -406,6 +421,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"GBPUSD": {
|
||||
"name": "GBP/USD", "output_node": "gbpusd",
|
||||
"description": "Livre sterling/Dollar — BoE, données UK, risque politique",
|
||||
"price_intercept": 1.26,
|
||||
"pip_to_price": 0.0001,
|
||||
"yf_ticker": "GBPUSD=X",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales","node_type":"input_event","category":"central_bank","unit":"pips","display_col":0,"event_category":"central_bank","description":"BoE, Fed."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"CPI UK/US, NFP, GDP UK."},
|
||||
@@ -441,6 +459,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"EEM": {
|
||||
"name": "EEM (Marchés Émergents)", "output_node": "eem",
|
||||
"description": "ETF EM — dollar, Chine, commodités, risk appetite",
|
||||
"price_intercept": 42.0,
|
||||
"pip_to_price": 0.01,
|
||||
"yf_ticker": "EEM",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales","node_type":"input_event","category":"central_bank","unit":"pips","display_col":0,"event_category":"central_bank","description":"Fed pivot → EM bénéficient du dollar faible."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"Données Chine, US macro."},
|
||||
@@ -478,6 +499,9 @@ INSTRUMENT_MODELS: dict[str, dict] = {
|
||||
"QQQ": {
|
||||
"name": "QQQ (NASDAQ-100 Tech)", "output_node": "qqq",
|
||||
"description": "Tech US — taux réels, bénéfices big tech, IA, réglementation",
|
||||
"price_intercept": 480.0,
|
||||
"pip_to_price": 0.10,
|
||||
"yf_ticker": "QQQ",
|
||||
"nodes": [
|
||||
{"id":"in_cb", "label":"Banques Centrales","node_type":"input_event","category":"central_bank","unit":"pips","display_col":0,"event_category":"central_bank","description":"Fed pivot → QQQ amplificateur (duration longue)."},
|
||||
{"id":"in_macro", "label":"Surprises Macro", "node_type":"input_event","category":"monetary_shock","unit":"pips","display_col":0,"event_category":"monetary_shock","description":"CPI, NFP → réévaluation Fed → QQQ."},
|
||||
@@ -804,6 +828,20 @@ def get_model_state(conn, instrument: str, at_date: Optional[str] = None) -> Opt
|
||||
output_id = graph_def["output_node"]
|
||||
net_pips = round(float(all_vals.get(output_id, 0.0)), 1)
|
||||
|
||||
# Compute structural pips (manual inputs only, no events, BALANCED regime)
|
||||
inputs_struct = _build_inputs(graph_def, overrides, {}, saturation=True)
|
||||
gj_struct = _graph_json_for_eval(graph_def, {})
|
||||
vals_struct = evaluate_graph(gj_struct, inputs_struct)
|
||||
structural_pips = round(float(vals_struct.get(output_id, 0.0)), 1)
|
||||
event_pips = round(net_pips - structural_pips, 1)
|
||||
|
||||
meta = INSTRUMENT_MODELS.get(inst_upper, {})
|
||||
price_intercept = meta.get("price_intercept", 0.0)
|
||||
pip_to_price = meta.get("pip_to_price", 0.0001)
|
||||
yf_ticker = meta.get("yf_ticker", "")
|
||||
fundamental_level = round(price_intercept + structural_pips * pip_to_price, 6)
|
||||
synthetic_price = round(price_intercept + net_pips * pip_to_price, 6)
|
||||
|
||||
nodes_out = []
|
||||
for node in graph_def["nodes"]:
|
||||
nid = node["id"]
|
||||
@@ -852,20 +890,28 @@ def get_model_state(conn, instrument: str, at_date: Optional[str] = None) -> Opt
|
||||
direction = "bullish" if net_pips > 5 else "bearish" if net_pips < -5 else "neutral"
|
||||
|
||||
return {
|
||||
"instrument": inst_upper,
|
||||
"name": graph_def["name"],
|
||||
"description": graph_def.get("description", ""),
|
||||
"at_date": str(ref_date),
|
||||
"net_pips": net_pips,
|
||||
"direction": direction,
|
||||
"nodes": nodes_out,
|
||||
"output_node": output_id,
|
||||
"regime": regime_info,
|
||||
"instrument": inst_upper,
|
||||
"name": graph_def["name"],
|
||||
"description": graph_def.get("description", ""),
|
||||
"at_date": str(ref_date),
|
||||
"net_pips": net_pips,
|
||||
"structural_pips": structural_pips,
|
||||
"event_pips": event_pips,
|
||||
"price_intercept": price_intercept,
|
||||
"pip_to_price": pip_to_price,
|
||||
"yf_ticker": yf_ticker,
|
||||
"fundamental_level": fundamental_level,
|
||||
"synthetic_price": synthetic_price,
|
||||
"direction": direction,
|
||||
"nodes": nodes_out,
|
||||
"output_node": output_id,
|
||||
"regime": regime_info,
|
||||
}
|
||||
|
||||
|
||||
def simulate_timeline(
|
||||
conn, instrument: str, period: str = "1y"
|
||||
conn, instrument: str, period: str = "1y",
|
||||
virtual_events: Optional[list] = None,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Simulate all node values day by day over the period.
|
||||
@@ -945,8 +991,31 @@ def simulate_timeline(
|
||||
events.append({
|
||||
"ev_date": ev_date, "category": r["category"], "pips": pips,
|
||||
"rise": rise, "plateau": plateau, "absorption": absorption, "dtype": dtype,
|
||||
"virtual": False,
|
||||
})
|
||||
|
||||
# Inject virtual events
|
||||
for ve in (virtual_events or []):
|
||||
try:
|
||||
ev_date = date_type.fromisoformat(str(ve["date"])[:10])
|
||||
events.append({
|
||||
"ev_date": ev_date,
|
||||
"category": ve.get("category", "unclassified"),
|
||||
"pips": float(ve.get("pips", 0.0)),
|
||||
"rise": int(ve.get("rise_days", 1)),
|
||||
"plateau": int(ve.get("plateau_days", 0)),
|
||||
"absorption": int(ve.get("absorption_days", 14)),
|
||||
"dtype": ve.get("decay_type", "exp"),
|
||||
"virtual": True,
|
||||
"label": ve.get("label", "Event virtuel"),
|
||||
})
|
||||
except (KeyError, ValueError):
|
||||
continue
|
||||
|
||||
meta = INSTRUMENT_MODELS.get(inst_upper, {})
|
||||
price_intercept = meta.get("price_intercept", 0.0)
|
||||
pip_to_price = meta.get("pip_to_price", 0.0001)
|
||||
|
||||
from services.causal_graphs import evaluate_graph
|
||||
|
||||
timeline = []
|
||||
@@ -970,11 +1039,21 @@ def simulate_timeline(
|
||||
vals = evaluate_graph(gj, inputs)
|
||||
net = round(float(vals.get(output_id, 0.0)), 1)
|
||||
|
||||
# Structural pips (manual only, no events)
|
||||
inputs_struct = _build_inputs(graph_def, overrides, {}, saturation=True)
|
||||
gj_struct = _graph_json_for_eval(graph_def, {})
|
||||
vals_struct = evaluate_graph(gj_struct, inputs_struct)
|
||||
structural_pips = round(float(vals_struct.get(output_id, 0.0)), 1)
|
||||
|
||||
timeline.append({
|
||||
"date": str(cur),
|
||||
"net_pips": net,
|
||||
"regime": ri["regime"],
|
||||
"nodes": {k: round(float(v), 1) for k, v in vals.items()},
|
||||
"date": str(cur),
|
||||
"net_pips": net,
|
||||
"structural_pips": structural_pips,
|
||||
"event_pips": round(net - structural_pips, 1),
|
||||
"fundamental_level": round(price_intercept + structural_pips * pip_to_price, 6),
|
||||
"synthetic_price": round(price_intercept + net * pip_to_price, 6),
|
||||
"regime": ri["regime"],
|
||||
"nodes": {k: round(float(v), 1) for k, v in vals.items()},
|
||||
})
|
||||
cur += timedelta(days=1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user