feat: causal lab
This commit is contained in:
@@ -134,12 +134,12 @@ def _fetch_prices(event_date_str: str, instruments: list[str]) -> dict:
|
||||
return out
|
||||
|
||||
|
||||
def _drift_metrics(prices: dict, event_date_str: str, inst: str, lag_min: int = 0) -> dict:
|
||||
def _drift_metrics(prices: dict, event_date_str: str, inst: str, lag_min: int = 0, lag_days: int = 0) -> dict:
|
||||
series = prices.get(inst, [])
|
||||
mode = prices.get("mode", "none")
|
||||
edate = event_date_str[:10]
|
||||
|
||||
empty = {"pre_pips": None, "post_pips": None, "drift_ratio": None, "leak": "unknown", "lag_min": lag_min}
|
||||
empty = {"pre_pips": None, "post_pips": None, "drift_ratio": None, "leak": "unknown", "lag_min": lag_min, "lag_days": lag_days}
|
||||
if not series:
|
||||
return empty
|
||||
|
||||
@@ -154,13 +154,18 @@ def _drift_metrics(prices: dict, event_date_str: str, inst: str, lag_min: int =
|
||||
pre_pips = round((series[mid - 1]["c"] - series[0]["c"]) * mult)
|
||||
post_pips = round((series[-1]["c"] - series[mid]["c"]) * mult)
|
||||
else:
|
||||
pre = [b for b in series if b["t"] < edate]
|
||||
same = [b for b in series if b["t"] == edate]
|
||||
if not pre or not same:
|
||||
# En mode journalier, lag_days décale la date de référence "post"
|
||||
if lag_days > 0:
|
||||
post_date = (datetime.strptime(edate, "%Y-%m-%d") + timedelta(days=lag_days)).strftime("%Y-%m-%d")
|
||||
pre = [b for b in series if b["t"] <= edate]
|
||||
post = [b for b in series if b["t"] >= post_date]
|
||||
else:
|
||||
pre = [b for b in series if b["t"] < edate]
|
||||
post = [b for b in series if b["t"] == edate]
|
||||
if not pre or not post:
|
||||
return empty
|
||||
mult = 10000 if inst in ("EURUSD",) else 10
|
||||
pre_pips = None
|
||||
post_pips = round((same[0]["c"] - pre[-1]["c"]) * mult)
|
||||
post_pips = round((post[0]["c"] - pre[-1]["c"]) * mult)
|
||||
|
||||
ratio: Optional[float] = None
|
||||
if pre_pips is not None and post_pips and post_pips != 0:
|
||||
@@ -866,7 +871,7 @@ def analyze_event(body: AnalyzeRequest):
|
||||
# Évaluation du graphe
|
||||
node_values = evaluate_graph(graph, inputs, body.coef_overrides or {})
|
||||
|
||||
# Lag effectif : max des lag_min sur toutes les arêtes menant à un market_asset
|
||||
# Lag effectif : max des lag_min/lag_days sur toutes les arêtes menant à un market_asset
|
||||
edges = graph.get("edges", [])
|
||||
nodes_map = {n["id"]: n for n in graph.get("nodes", [])}
|
||||
output_ids = {n["id"] for n in graph.get("nodes", []) if n.get("type") in ("market_asset", "output")}
|
||||
@@ -874,6 +879,10 @@ def analyze_event(body: AnalyzeRequest):
|
||||
(e.get("lag_min", 0) or 0 for e in edges if e.get("to") in output_ids),
|
||||
default=0,
|
||||
)
|
||||
effective_lag_days = max(
|
||||
(e.get("lag_days", 0) or 0 for e in edges if e.get("to") in output_ids),
|
||||
default=0,
|
||||
)
|
||||
|
||||
# Instruments : utiliser tous ceux du template si aucun spécifié
|
||||
if body.instrument:
|
||||
@@ -888,7 +897,7 @@ def analyze_event(body: AnalyzeRequest):
|
||||
actual_moves: dict = {}
|
||||
drift_by_inst: dict = {}
|
||||
for inst in instruments:
|
||||
drift = _drift_metrics(prices, event["start_date"], inst, lag_min=effective_lag)
|
||||
drift = _drift_metrics(prices, event["start_date"], inst, lag_min=effective_lag, lag_days=effective_lag_days)
|
||||
drift_by_inst[inst] = drift
|
||||
if drift.get("post_pips") is not None:
|
||||
actual_moves[inst] = drift["post_pips"]
|
||||
@@ -919,6 +928,7 @@ def analyze_event(body: AnalyzeRequest):
|
||||
"drift": drift_by_inst.get(primary_inst, {}),
|
||||
"prices_mode": prices.get("mode", "none"),
|
||||
"effective_lag_min": effective_lag,
|
||||
"effective_lag_days": effective_lag_days,
|
||||
"analyzed_at": analyzed_at,
|
||||
"graph_json": graph, # structure complète pour visualisation frontend
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user