feat: instrument model
This commit is contained in:
@@ -1085,25 +1085,29 @@ def simulate_timeline(
|
||||
structural_pips = round(float(vals_struct.get(output_id, 0.0)), 1)
|
||||
fundamental_level_base = round(price_intercept + structural_pips * pip_to_price, 6)
|
||||
|
||||
# Auto-anchor : caler le niveau fondamental sur le prix réel au début de la fenêtre.
|
||||
# start_offset = prix_réel_début - niveau_fondamental_machine
|
||||
# → synthetic_price(t) = prix_réel_début + event_pips(t) * pip_to_price
|
||||
start_offset = 0.0
|
||||
# Guidance EMA : la baseline de la synthétique est l'EMA lissée du prix réel.
|
||||
# synthetic_price(t) = EMA(t) + event_pips(t) × pip_to_price
|
||||
# → sans event perturbateur : synthétique colle au lissé historique
|
||||
# → avec events : déviation proportionnelle à leur contribution
|
||||
ema_prices: dict[str, float] = {}
|
||||
last_ema: float = fundamental_level_base # fallback si pas de données prix
|
||||
try:
|
||||
ph_row = conn.execute(
|
||||
"""SELECT close FROM price_history_cache
|
||||
WHERE instrument=? AND date>=? ORDER BY date ASC LIMIT 1""",
|
||||
(inst_upper, str(date_from))
|
||||
).fetchone()
|
||||
if ph_row is None:
|
||||
# Weekends/jours fériés : on remonte jusqu'à 7 jours avant
|
||||
ph_row = conn.execute(
|
||||
"""SELECT close FROM price_history_cache
|
||||
WHERE instrument=? AND date>=? ORDER BY date ASC LIMIT 1""",
|
||||
(inst_upper, str(date_from - timedelta(days=7)))
|
||||
).fetchone()
|
||||
if ph_row:
|
||||
start_offset = round(float(ph_row["close"]) - fundamental_level_base, 6)
|
||||
# 30j de warmup avant date_from pour que l'EMA soit stabilisée dès le début
|
||||
warmup_from = str(date_from - timedelta(days=30))
|
||||
ph_rows = conn.execute(
|
||||
"""SELECT date, close FROM price_history_cache
|
||||
WHERE instrument=? AND date>=? ORDER BY date ASC""",
|
||||
(inst_upper, warmup_from)
|
||||
).fetchall()
|
||||
alpha = 0.15 # lissage EMA (~6j de demi-vie)
|
||||
ema_val: Optional[float] = None
|
||||
for r in ph_rows:
|
||||
c = float(r["close"])
|
||||
ema_val = c if ema_val is None else alpha * c + (1.0 - alpha) * ema_val
|
||||
if r["date"] >= str(date_from):
|
||||
ema_prices[r["date"]] = round(ema_val, 6)
|
||||
if ema_prices:
|
||||
last_ema = list(ema_prices.values())[-1]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -1150,13 +1154,23 @@ def simulate_timeline(
|
||||
net = structural_pips
|
||||
regime_label = "BALANCED"
|
||||
|
||||
# Guide price : EMA du prix réel si disponible, sinon dernier EMA connu (futur)
|
||||
date_str = str(cur)
|
||||
if date_str in ema_prices:
|
||||
guide_price = ema_prices[date_str]
|
||||
last_ema = guide_price
|
||||
else:
|
||||
guide_price = last_ema # dates futures : tient le dernier EMA connu
|
||||
|
||||
event_pips = round(net - structural_pips, 1)
|
||||
|
||||
timeline.append({
|
||||
"date": str(cur),
|
||||
"date": date_str,
|
||||
"net_pips": net,
|
||||
"structural_pips": structural_pips,
|
||||
"event_pips": round(net - structural_pips, 1),
|
||||
"fundamental_level": round(fundamental_level_base + start_offset, 6),
|
||||
"synthetic_price": round(price_intercept + start_offset + net * pip_to_price, 6),
|
||||
"event_pips": event_pips,
|
||||
"fundamental_level": guide_price,
|
||||
"synthetic_price": round(guide_price + event_pips * pip_to_price, 6),
|
||||
"regime": regime_label,
|
||||
"nodes": {k: round(float(v), 1) for k, v in vals.items()},
|
||||
"active_events": active_events_detail,
|
||||
|
||||
Reference in New Issue
Block a user