feat: causal lab

This commit is contained in:
OpenSquared
2026-07-02 14:42:50 +02:00
parent 82739e8140
commit 5126360ce9

View File

@@ -67,6 +67,7 @@ BUILT_IN_TEMPLATES = [
"slug": "MACRO_DATA_SURPRISE",
"category": "monetary_shock",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 4, "absorption_days": 12, "decay_type": "exp"},
"instruments": ["EURUSD", "SP500", "XAUUSD", "QQQ", "TLT", "USDJPY", "EEM", "GDX", "SLV"],
"description": "Scheduled economic release vs consensus -> OIS repricing -> full asset repricing",
"ai_rationale": "Hawkish surprise: OIS up -> 2Y up -> USD up -> EURUSD/USDJPY/EEM react; 10Y up -> TLT down, GDX/XAUUSD down. Growth channel -> SP500/QQQ up. Dovish miss: all reversed.",
@@ -162,6 +163,7 @@ BUILT_IN_TEMPLATES = [
"slug": "CENTRAL_BANK_DECISION",
"category": "central_bank",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 5, "absorption_days": 14, "decay_type": "exp"},
"instruments": ["EURUSD", "SP500", "XAUUSD", "QQQ", "TLT", "USDJPY", "GBPUSD", "XLF", "EEM"],
"description": "CB rate decision + forward guidance -> full curve repricing -> carry FX, bonds, equities",
"ai_rationale": "Rate hike -> 2Y/10Y up -> carry differential -> EURUSD/USDJPY/GBPUSD down; TLT down; QQQ hardest hit (duration); XLF benefits from steeper curve. Dovish: all reversed. EEM suffers from USD rate rises (capital outflows).",
@@ -254,6 +256,7 @@ BUILT_IN_TEMPLATES = [
"slug": "GROWTH_CORPORATE_SIGNAL",
"category": "growth_shock",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 4, "absorption_days": 10, "decay_type": "exp"},
"instruments": ["SP500", "QQQ", "IWM", "EURUSD", "XAUUSD", "HYG"],
"description": "Corporate/macro growth signal -> earnings revision + risk appetite -> equities, credit, FX, Gold",
"ai_rationale": "Earnings beats revise EPS upward and compress credit spreads (HYG up). QQQ > SP500 > IWM in tech-driven beats; IWM > SP500 in domestic growth signals. EURUSD follows risk appetite. Gold falls as safe haven demand recedes.",
@@ -325,6 +328,7 @@ BUILT_IN_TEMPLATES = [
"slug": "GEOPOLITICAL_RISK_OFF",
"category": "geopolitical",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 7, "absorption_days": 21, "decay_type": "linear"},
"instruments": ["EURUSD", "XAUUSD", "SP500", "BRENT", "USDJPY", "VXX", "TLT", "HYG", "UNG", "SLV"],
"description": "Geopolitical shock -> risk premium + safe haven demand -> multi-asset risk-off repricing",
"ai_rationale": "Gold/TLT/JPY safe havens rise; EUR/SP500/HYG fall. VXX spikes. USDJPY falls (JPY strengthens as safe haven). BRENT and UNG spike if energy-producing region. EU equities most exposed to European conflicts.",
@@ -408,6 +412,7 @@ BUILT_IN_TEMPLATES = [
"slug": "COMMODITY_SUPPLY_SHOCK",
"category": "commodity",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 1, "half_life_days": 5, "absorption_days": 14, "decay_type": "exp"},
"instruments": ["BRENT", "XAUUSD", "EURUSD", "SP500", "UNG", "XLE", "SLV"],
"description": "Supply disruption/glut -> Brent + energy inflation -> EU trade deficit -> multi-asset",
"ai_rationale": "OPEC cuts hit BRENT and XLE (energy sector stocks) first. Energy inflation pressures EU trade balance (EURUSD down) and inflates Gold/SLV. UNG follows as cross-commodity supply chain linkage. S&P suffers from margin pressure.",
@@ -472,6 +477,7 @@ BUILT_IN_TEMPLATES = [
"slug": "TRADE_POLICY_SHOCK",
"category": "trade_policy",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 1, "half_life_days": 10, "absorption_days": 21, "decay_type": "linear"},
"instruments": ["EURUSD", "SP500", "XAUUSD", "EEM", "QQQ", "GBPUSD", "IWM"],
"description": "Tariff announcement -> stagflationary shock -> EUR/GBP down SP500/QQQ down EEM down Gold up",
"ai_rationale": "Tariffs create stagflation: import cost rise (inflation) + trade volume drop (growth). EEM is hit hardest via global trade contraction and USD strength. QQQ suffers from tech supply chain disruption (AAPL/NVDA exposed). GBPUSD exposed as UK trade-dependent. IWM domestic plays can benefit initially but input cost inflation hurts margins.",
@@ -551,6 +557,7 @@ BUILT_IN_TEMPLATES = [
"slug": "CREDIT_SYSTEMIC_EVENT",
"category": "credit_stress",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 7, "absorption_days": 21, "decay_type": "exp"},
"instruments": ["EURUSD", "SP500", "XAUUSD", "HYG", "TLT", "VXX", "XLF", "USDJPY", "BTC"],
"description": "Credit event -> spread widening + deleveraging -> systemic risk-off + USD liquidity flight",
"ai_rationale": "HYG is the primary instrument (spreads widen = HYG down). TLT initially up (flight to quality) then volatile (sold for cash). VXX spikes hard. XLF (financials) crushed. USDJPY falls (JPY safe haven). BTC complex: initially up as alternative store of value, then down on margin calls.",
@@ -638,6 +645,7 @@ BUILT_IN_TEMPLATES = [
"slug": "TECHNICAL_MOMENTUM_BREAKOUT",
"category": "technical",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 3, "absorption_days": 7, "decay_type": "exp"},
"instruments": ["EURUSD", "SP500", "QQQ"],
"description": "Technical breakout/breakdown -> stop cascade + momentum -> instrument price action",
"ai_rationale": "Technical events operate via microstructure: breakout triggers stops, amplifying the move. No fundamental anchor. The correlated asset move is weaker. Applies to any instrument — the primary and correlated move fields should be overridden per event.",
@@ -687,6 +695,7 @@ BUILT_IN_TEMPLATES = [
"slug": "SENTIMENT_POSITIONING_EXTREME",
"category": "sentiment",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 1, "half_life_days": 5, "absorption_days": 10, "decay_type": "linear"},
"instruments": ["SP500", "QQQ", "EURUSD", "XAUUSD", "VXX", "HYG", "BTC"],
"description": "Extreme fear / greed -> crowded trade unwind -> contrarian mean reversion",
"ai_rationale": "+sigma = extreme fear/oversold (contrarian buy signal). VXX collapses as fear recedes. HYG recovers as credit spreads compress. BTC follows the risk appetite extreme. Mean reversion typically takes 3-10 days to materialize once the flow exhausts.",
@@ -755,6 +764,7 @@ BUILT_IN_TEMPLATES = [
"slug": "COMMODITY_INVENTORY_REPORT",
"category": "commodity",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 2, "absorption_days": 5, "decay_type": "exp"},
"instruments": ["BRENT", "EURUSD", "XAUUSD", "UNG", "XLE"],
"description": "Weekly inventory surprise -> supply/demand balance -> Brent + XLE + UNG",
"ai_rationale": "EIA crude draw vs consensus -> Brent spot up + backwardation. XLE (energy sector ETF) follows Brent with some lag. EIA gas storage report separately drives UNG. Secondary inflation channel hits EURUSD and gold.",
@@ -813,6 +823,7 @@ BUILT_IN_TEMPLATES = [
"slug": "INSTITUTIONAL_FLOW",
"category": "positioning",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 1, "half_life_days": 7, "absorption_days": 14, "decay_type": "linear"},
"instruments": ["EURUSD", "SP500", "XAUUSD"],
"description": "Large institutional flow -> order flow imbalance -> momentum + mean reversion risk",
"ai_rationale": "COT repositioning or FX intervention moves prices via order flow mechanics (not fundamentals). Move is self-limiting — creates a mean reversion setup once the flow exhausts. Low confidence, short-lived signal.",
@@ -859,6 +870,7 @@ BUILT_IN_TEMPLATES = [
"slug": "UNCLASSIFIED_IMPACT",
"category": "unclassified",
"heuristic_ver": 2,
"calibration_json": {"lag_days": 0, "half_life_days": 5, "absorption_days": 12, "decay_type": "exp"},
"instruments": ["EURUSD", "SP500", "XAUUSD"],
"description": "Fallback — event doesn't fit established regimes. Low confidence, no causal chain.",
"ai_rationale": "Direct trigger to output with no intermediate nodes. Precision scores from this template are marked low-confidence and excluded from calibration stats.",
@@ -964,16 +976,41 @@ def seed_templates(conn):
conn.execute("""
INSERT INTO causal_graph_templates
(name, category, sub_type, instruments, description, graph_json,
ai_rationale, heuristic_ver, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'system')
calibration_json, ai_rationale, heuristic_ver, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'system')
""", (
t["name"], t["category"], t.get("sub_type", ""),
json.dumps(t.get("instruments", [])),
t.get("description", ""),
json.dumps(t["graph_json"]),
json.dumps(t.get("calibration_json", {})),
t.get("ai_rationale", ""),
ver,
))
# Migration: fill missing temporal params in calibration_json for all built-in templates.
# Only sets keys that are absent — never overwrites existing calibration stats.
for t in BUILT_IN_TEMPLATES:
defaults = t.get("calibration_json", {})
if not defaults:
continue
row = conn.execute(
"SELECT id, calibration_json FROM causal_graph_templates WHERE name=?", (t["name"],)
).fetchone()
if not row:
continue
calib = json.loads(row["calibration_json"] or "{}")
dirty = False
for key in ("lag_days", "half_life_days", "absorption_days", "decay_type"):
if calib.get(key) is None and key in defaults:
calib[key] = defaults[key]
dirty = True
if dirty:
conn.execute(
"UPDATE causal_graph_templates SET calibration_json=?, updated_at=datetime('now') WHERE id=?",
(json.dumps(calib), row["id"])
)
conn.commit()