feat: Phase 1 — delta temporel + decay news + cycle_meta dans prompts IA
- database.py: get_last_completed_cycle_ts() pour mesurer le delta entre cycles - auto_cycle.py: calcul delta_minutes + cycle_meta dict transmis aux fonctions IA - ai_analyzer.py: apply_news_decay() (halflife par catégorie), partition_news_by_age() (3 buckets: inter_cycle / recent_24h / older), _build_temporal_news_block() pour le prompt suggestion; cycle_meta injecté aussi dans score_patterns_with_context() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -174,6 +174,7 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
save_pattern_scores, log_macro_regime, log_geo_alert, log_trade_entries,
|
||||
add_cycle_run, update_cycle_run, save_reasoning_trace,
|
||||
get_latest_portfolio_lessons, log_system_event,
|
||||
get_last_completed_cycle_ts,
|
||||
)
|
||||
from services.data_fetcher import fetch_geo_news, get_all_quotes, get_macro_gauges, score_macro_scenarios
|
||||
from services.geo_analyzer import compute_geo_risk_score
|
||||
@@ -206,6 +207,37 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
_current_status["running"] = True
|
||||
_current_status["last_run_id"] = run_id
|
||||
|
||||
# ── Cycle meta — timing context ───────────────────────────────────────
|
||||
_now = datetime.utcnow()
|
||||
_last_cycle_ts_str = get_last_completed_cycle_ts()
|
||||
_delta_minutes: float = 180.0 # default 3h if no prior cycle
|
||||
if _last_cycle_ts_str:
|
||||
try:
|
||||
_last_dt = datetime.fromisoformat(_last_cycle_ts_str.replace("Z", ""))
|
||||
_delta_minutes = max(1.0, (_now - _last_dt).total_seconds() / 60)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
_interval_hours = float(get_config("auto_cycle_interval_hours") or "3")
|
||||
if _delta_minutes < 90:
|
||||
_calib_label = "Court terme (<2h) — signaux très récents"
|
||||
elif _delta_minutes < 720:
|
||||
_calib_label = f"Moyen terme ({_delta_minutes/60:.0f}h) — signaux potentiellement pas encore pricés"
|
||||
else:
|
||||
_calib_label = f"Long terme ({_delta_minutes/60:.0f}h) — marchés ont eu le temps d'intégrer"
|
||||
|
||||
cycle_meta = {
|
||||
"current_cycle_ts": _now.isoformat(),
|
||||
"last_cycle_ts": _last_cycle_ts_str,
|
||||
"delta_minutes": round(_delta_minutes, 1),
|
||||
"interval_hours": _interval_hours,
|
||||
"calibration_label": _calib_label,
|
||||
}
|
||||
logger.info(
|
||||
f"[Cycle {run_id[:16]}] Cycle meta: delta={_delta_minutes:.0f}min depuis dernier cycle"
|
||||
f" ({_last_cycle_ts_str[:16] if _last_cycle_ts_str else 'premier cycle'})"
|
||||
)
|
||||
|
||||
# ── Step 0: Load portfolio lessons + Super Contexte ──────────────────
|
||||
portfolio_lessons = get_latest_portfolio_lessons()
|
||||
|
||||
@@ -341,11 +373,15 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
try:
|
||||
from services.data_fetcher import get_economic_calendar
|
||||
calendar = get_economic_calendar()
|
||||
# Apply decay to news before suggestion (adds decayed_score + age_hours)
|
||||
from services.ai_analyzer import apply_news_decay as _apply_decay
|
||||
news = _apply_decay(news)
|
||||
suggestions = suggest_patterns_from_market_context(
|
||||
news, quotes, calendar, macro_regime=macro_regime, geo_score=geo_score_obj,
|
||||
portfolio_lessons=portfolio_lessons,
|
||||
reliability_map=_reliability_map or None,
|
||||
iv_context=iv_context,
|
||||
cycle_meta=cycle_meta,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"[Cycle] Suggestion step failed: {e}")
|
||||
@@ -468,6 +504,7 @@ def run_cycle_once(trigger: str = "auto") -> Dict[str, Any]:
|
||||
portfolio_lessons=portfolio_lessons,
|
||||
iv_context=iv_context,
|
||||
risk_context=risk_cluster_context,
|
||||
cycle_meta=cycle_meta,
|
||||
)
|
||||
scored_with_id = [s for s in scored if s.get("pattern_id")]
|
||||
scored_without_id = [s for s in scored if not s.get("pattern_id")]
|
||||
|
||||
Reference in New Issue
Block a user