Aurelius / adapters /finance.py
murtaza-2007
Rebuild Aurelius as a multi-source graph intelligence engine
75ce203
Raw
History Blame Contribute Delete
3.58 kB
"""Aurelius adapter β€” Finance (ingested mode): the financial knowledge graph.
Not just companies any more: the ingested graph is heterogeneous β€” companies,
ETFs, sectors, executives, countries and macro indicators, wired together by
typed, weighted relationships (node kind rides in features.kind):
sector_member / has_member company ↔ sector
holds / held_by ETF ↔ constituent company
led_by / leads company ↔ chief executive
based_in / headquarters_of company ↔ country
supplies / supplied_by supplier ↔ customer (curated seed set)
competes_with rivals (curated, symmetric)
owns_stake / stake_held_by investor ↔ holding
co_moves return-correlation kNN (computed)
macro_correlates macro indicator ↔ company (computed)
The computed edges carry the actual correlation as weight, so every path
step through them is evidence ("co-moves, corr 0.72"), not assertion β€”
format_edge below is what the UI shows on paths and expansions.
Ingestion (ingest/finance.py) pulls real daily closes from Yahoo's chart
endpoint for companies, ETFs and macro symbols, merges the curated
relationship seed set, and writes everything into core.store. Tickers are
almost pure structure, hence FUSION_ALPHA["finance"] = 0.8.
"""
from __future__ import annotations
import random
from typing import Optional
from core.source import register
from core.store import StoreBackedSource
_PHRASES = {
"sector_member": "in sector",
"has_member": "sector includes",
"holds": "holds",
"held_by": "held by",
"led_by": "led by",
"leads": "leads",
"based_in": "headquartered in",
"headquarters_of": "home market of",
"supplies": "supplies",
"supplied_by": "supplied by",
"competes_with": "competes with",
"owns_stake": "owns a stake in",
"stake_held_by": "stake held by",
}
_DEMO_PAIRS = [
("NVDA", "Warren Buffett"),
("Tim Cook", "XOM"),
("TSLA", "Crude Oil"),
("SPY", "Taiwan"),
("JPM", "Jensen Huang"),
("F", "US 10-Year Treasury Yield"),
]
class FinanceSource(StoreBackedSource):
name = "finance"
description = ("Financial knowledge graph β€” companies, ETFs, sectors, "
"executives & macro indicators with typed relationships.")
edge_types = ("sector_member", "holds", "led_by", "based_in", "supplies",
"competes_with", "owns_stake", "co_moves", "macro_correlates")
supports_backlinks = True
def format_edge(self, typ: str, weight: float) -> str:
if typ in ("co_moves", "macro_correlates"):
label = "co-moves" if typ == "co_moves" else "macro-linked"
return f"{label} (corr {weight:.2f})"
return _PHRASES.get(typ, typ.replace("_", " "))
async def resolve(self, query: str) -> Optional[object]:
# Tickers are case-insensitive; StoreBackedSource.find_nodes already
# matches on id and title case-insensitively, and ingest uppercases
# ids, so a lowercased query still resolves. Just normalize obvious
# "$NVDA" / "nvda" forms first.
return await super().resolve(query.strip().lstrip("$").upper()
if len(query.strip()) <= 6 else query)
async def sample_pair(self):
if not self.ingested():
return None
return random.choice(_DEMO_PAIRS)
register(FinanceSource())