feat: instrument model
This commit is contained in:
@@ -1639,6 +1639,22 @@ def simulate_timeline(
|
|||||||
vals_struct = evaluate_graph(gj_struct, inputs_struct)
|
vals_struct = evaluate_graph(gj_struct, inputs_struct)
|
||||||
static_structural = round(float(vals_struct.get(output_id, 0.0)), 1)
|
static_structural = round(float(vals_struct.get(output_id, 0.0)), 1)
|
||||||
|
|
||||||
|
# Unités par nœud input_manual — pour corriger les valeurs brutes de ff_calendar
|
||||||
|
# (NFP: raw=228000 → attendu=228 K; PMI: raw=54.7 → attendu=4.7 pts écart/50)
|
||||||
|
macro_node_units: dict[str, str] = {
|
||||||
|
n["id"]: n.get("unit", "")
|
||||||
|
for n in graph_def.get("nodes", [])
|
||||||
|
if n.get("node_type") == "input_manual"
|
||||||
|
}
|
||||||
|
|
||||||
|
def _unit_correct(v: float, unit: str) -> float:
|
||||||
|
"""Convertit les valeurs brutes ff_calendar en valeur attendue par le nœud."""
|
||||||
|
if unit == "K" and abs(v) >= 1_000:
|
||||||
|
return round(v / 1_000, 1)
|
||||||
|
if unit == "pts" and v > 10:
|
||||||
|
return round(v - 50.0, 1)
|
||||||
|
return v
|
||||||
|
|
||||||
# ── Auto-anchor : offset pour que la synthétique parte du prix réel à date_from ──
|
# ── Auto-anchor : offset pour que la synthétique parte du prix réel à date_from ──
|
||||||
# Calculé une seule fois sur le prix réel à date_from (ou le plus proche disponible).
|
# Calculé une seule fois sur le prix réel à date_from (ou le plus proche disponible).
|
||||||
# Cet offset compense l'écart de calibration sans changer la dynamique du modèle.
|
# Cet offset compense l'écart de calibration sans changer la dynamique du modèle.
|
||||||
@@ -1660,6 +1676,7 @@ def simulate_timeline(
|
|||||||
# Valeur la plus proche avant date_from
|
# Valeur la plus proche avant date_from
|
||||||
v = next((tl[d] for d in sorted(tl) if d <= str(date_from)), next(iter(tl.values()), None))
|
v = next((tl[d] for d in sorted(tl) if d <= str(date_from)), next(iter(tl.values()), None))
|
||||||
if v is not None:
|
if v is not None:
|
||||||
|
v = _unit_correct(v, macro_node_units.get(node_id, ""))
|
||||||
anchor_overrides[node_id] = {"value": v, "note": "anchor", "set_at": ""}
|
anchor_overrides[node_id] = {"value": v, "note": "anchor", "set_at": ""}
|
||||||
gj_a = _graph_json_for_eval(graph_def, {})
|
gj_a = _graph_json_for_eval(graph_def, {})
|
||||||
in_a = _build_inputs(graph_def, anchor_overrides, {}, saturation=True)
|
in_a = _build_inputs(graph_def, anchor_overrides, {}, saturation=True)
|
||||||
@@ -1677,7 +1694,7 @@ def simulate_timeline(
|
|||||||
for node_id, tl in macro_node_timelines.items():
|
for node_id, tl in macro_node_timelines.items():
|
||||||
v0 = tl.get(str(date_from))
|
v0 = tl.get(str(date_from))
|
||||||
if v0 is not None:
|
if v0 is not None:
|
||||||
macro_last[node_id] = v0
|
macro_last[node_id] = _unit_correct(v0, macro_node_units.get(node_id, ""))
|
||||||
|
|
||||||
# Catégories d'events gérées par les nœuds input_event du graphe
|
# Catégories d'events gérées par les nœuds input_event du graphe
|
||||||
# Les catégories sans nœud correspondant sont appliquées comme choc direct sur l'output.
|
# Les catégories sans nœud correspondant sont appliquées comme choc direct sur l'output.
|
||||||
@@ -1733,6 +1750,7 @@ def simulate_timeline(
|
|||||||
for node_id, tl in macro_node_timelines.items():
|
for node_id, tl in macro_node_timelines.items():
|
||||||
v = tl.get(cur_str)
|
v = tl.get(cur_str)
|
||||||
if v is not None:
|
if v is not None:
|
||||||
|
v = _unit_correct(v, macro_node_units.get(node_id, ""))
|
||||||
macro_last[node_id] = v
|
macro_last[node_id] = v
|
||||||
else:
|
else:
|
||||||
v = macro_last.get(node_id) # gap-fill (weekend)
|
v = macro_last.get(node_id) # gap-fill (weekend)
|
||||||
|
|||||||
Reference in New Issue
Block a user