Skip to main content
Stores markets, events, exchanges, and other entities as nodes. Connects them with typed, weighted edges (correlations, hedges, part-of). Records timestamped facts about each entity. All SQLite, no external dependencies.

Quick Start

from horizon.fund import KnowledgeGraph

kg = KnowledgeGraph()

kg.add_entity("will-trump-win", "market", "Will Trump win?", properties={"exchange": "polymarket"})
kg.add_entity("us-election-2024", "event", "US Election 2024")
kg.add_entity("will-harris-win", "market", "Will Harris win?", properties={"exchange": "polymarket"})

kg.add_relationship("will-trump-win", "us-election-2024", "part_of")
kg.add_relationship("will-harris-win", "us-election-2024", "part_of")
kg.add_relationship("will-trump-win", "will-harris-win", "correlated_with", weight=0.95)

kg.record_fact(
    entity_id="will-trump-win",
    fact_type="edge_detected",
    content="MM strategy shows Sharpe=1.8 in backtest",
    confidence=0.85,
    source="backtest",
    metadata={"sharpe": 1.8, "strategy": "political_mm"},
)

correlated = kg.correlated_markets("will-trump-win", min_weight=0.5)
context = kg.market_context("will-trump-win")
opps = kg.surface_opportunities(min_confidence=0.7, lookback_hours=48.0)

kg.close()
When using FundManager, the graph is created automatically:
fund = FundManager(FundConfig(total_capital=100_000))
kg = fund.knowledge_graph

Schema

entities

Markets, events, categories, exchanges, assets, people, organizations. Each has a type, name, JSON properties, and HMAC signature.

relationships

Directed typed edges between entities. Types: correlated_with, caused_by, part_of, hedges, competes_with, related_to, influences, depends_on. Each has a weight and validity window.

facts

Timestamped assertions about entities. Types: observation, signal, outcome, correlation, price_move, settlement, edge_detected, regime_change. Each has a confidence score and optional expiry.

Entities

Seven types: market, event, category, exchange, asset, person, organization.
# Create or update (upserts on conflict)
kg.add_entity("btc-above-100k", "market", "BTC above $100k by June", properties={"exchange": "kalshi"})

# Lookup
entity = kg.get_entity("btc-above-100k")

# Search by type and/or name
markets = kg.find_entities(entity_type="market", limit=50)
matches = kg.find_entities(name_pattern="trump", limit=20)

# Delete (cascades to relationships and facts)
kg.remove_entity("btc-above-100k")

Relationships

Directed, weighted, temporal. Both endpoints must exist. A unique constraint on (source, target, type, valid_from) prevents duplicates.
rel = kg.add_relationship(
    source_id="will-trump-win",
    target_id="will-harris-win",
    rel_type="correlated_with",
    weight=0.92,
    properties={"correlation": -0.92, "source": "backtest"},
)

# Query by direction
rels = kg.get_relationships("will-trump-win", direction="outgoing", rel_type="correlated_with")
rels = kg.get_relationships("will-trump-win", direction="both", active_only=True)

# Deactivate without deleting
kg.expire_relationship(rel_id=42)
Every relationship has valid_from and valid_to. When valid_to is NULL, it is active. Expiring a relationship sets valid_to = now so the historical record is preserved.

Facts

Assertions about entities with confidence (0.0 to 1.0), source tracking, and optional expiry.
fact = kg.record_fact(
    entity_id="will-trump-win",
    fact_type="signal",
    content="Polling shift: +3% in swing states",
    confidence=0.75,
    source="research",
    metadata={"poll_source": "538", "swing_states": ["PA", "MI", "WI"]},
    expires_at=time.time() + 86400,
)

# Filter by entity, type, source, confidence, time
facts = kg.get_facts(entity_id="will-trump-win", active_only=True)
facts = kg.get_facts(fact_type="signal", source="research", min_confidence=0.7, limit=50)
facts = kg.get_facts(since=time.time() - 86400)
Fills use confidence 1.0. Backtest edges scale confidence with trade count. Price moves expire after 24h.

Graph Queries

# BFS neighbors (depth capped at 3)
result = kg.neighbors("will-trump-win", depth=2, rel_types=["correlated_with", "hedges"])

# Shortest path (depth capped at 5)
path = kg.find_path("will-trump-win", "btc-above-100k", max_depth=4)

# Markets correlated above a threshold
correlated = kg.correlated_markets("will-trump-win", min_weight=0.5)

# Markets linked to an event
opps = kg.event_opportunities("us-election-2024")

Aggregated Queries

# Full context for a market: entity + 2-hop neighbors + facts + correlations
ctx = kg.market_context("will-trump-win")

# Correlation clusters (connected components)
clusters = kg.detect_cross_correlations(min_weight=0.3)

# Recent high-confidence facts
opps = kg.surface_opportunities(fact_types=["edge_detected", "signal"], min_confidence=0.7, lookback_hours=48.0)

Maintenance

# Remove expired facts, old low-confidence data, stale relationships
removed = kg.prune(max_age_days=90.0, min_confidence=0.1)

# Counts by type
stats = kg.stats()

# Export subset for debugging
subgraph = kg.export_subgraph(["will-trump-win", "will-harris-win"])
When running inside FundManager, pruning runs automatically every 200 oversight ticks with a 90-day cutoff.