> ## Documentation Index
> Fetch the complete documentation index at: https://mathematicalcompany.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Research Agent

> Queries fund subsystems and the knowledge graph, produces structured reports.

The ResearchAgent reads from positions, risk metrics, feeds, alpha decay, execution quality, hypotheses, and the knowledge graph. It runs threshold-based rules and returns a list of findings sorted by severity. No LLM calls. Same fund state always produces the same report.

## Quick Start

```python theme={null}
fund = FundManager(FundConfig(total_capital=100_000))
agent = fund.research_agent

report = agent.investigate("Why is strategy political_mm underperforming?")
health = agent.health_check()
diagnosis = agent.explain_underperformance("political_mm")
opportunities = agent.market_research("election markets")
risk = agent.risk_assessment()
```

Works standalone too. Both `fund` and `knowledge_graph` are optional:

```python theme={null}
from horizon.fund import ResearchAgent, KnowledgeGraph

agent = ResearchAgent(fund=fund, knowledge_graph=kg)
agent = ResearchAgent(fund=fund)           # no graph tools
agent = ResearchAgent(knowledge_graph=kg)  # no fund tools
```

## How It Works

<Steps>
  <Step title="Parse intent">
    Keyword matching extracts the focus area, strategy name, and topics from the query.
  </Step>

  <Step title="Plan">
    Each focus area maps to a set of internal tools to call.
  </Step>

  <Step title="Observe">
    Tools query fund subsystems. Failed tools are skipped.
  </Step>

  <Step title="Analyze">
    Analyzers run threshold rules against observations and produce findings.
  </Step>

  <Step title="Report">
    Findings are deduplicated, sorted by severity, and returned as a dict.
  </Step>
</Steps>

## Query Types

| Focus          | Keywords                              | Scope                                             |
| -------------- | ------------------------------------- | ------------------------------------------------- |
| `risk`         | risk, exposure, drawdown, var, stress | VaR, drawdown, concentration, regime, stress test |
| `diagnosis`    | underperform, losing, decline, why is | Performance, execution, alpha decay, feeds, risk  |
| `opportunity`  | opportunity, enter, should we         | Universe, graph, hypotheses, correlations, regime |
| `health`       | health, status, overview, full        | Everything                                        |
| `correlations` | correlation, cross-market, cluster    | Correlations, graph clusters, positions           |
| `alpha`        | alpha, edge, decay, signal            | Alpha decay, hypotheses, performance              |
| `general`      | *(default)*                           | Positions, performance, risk, strategies          |

## Tools

15 internal query tools. Each returns a dict or skips if its subsystem is missing.

<CardGroup cols={3}>
  <Card title="Fund tools">
    `positions`, `markets`, `risk`, `performance`, `feeds`, `strategies`
  </Card>

  <Card title="Quant tools">
    `correlations`, `regime`, `hypotheses`, `alpha_decay`, `execution_quality`, `stress_test`
  </Card>

  <Card title="Graph tools">
    `graph_context`, `graph_opportunities`, `graph_correlations`
  </Card>
</CardGroup>

## Analyzers

12 analyzers with fixed thresholds. All thresholds are class attributes you can override.

| Analyzer                    | What it checks                                  | Thresholds                                 |
| --------------------------- | ----------------------------------------------- | ------------------------------------------ |
| `fund_overview`             | Kill switch, fund drawdown, inactive strategies | 15% critical, 8% high, 3% medium           |
| `risk_exposure`             | VaR budget                                      | 90% critical, 70% high                     |
| `drawdown`                  | Per-strategy drawdown                           | 20% critical, 10% high                     |
| `concentration`             | Correlation alerts                              | Any alert = high                           |
| `regime_risk`               | Market regime                                   | Crisis = critical, stressed = high         |
| `strategy_performance`      | NAV loss, paused strategies                     | NAV below 950 + 5% drawdown = high         |
| `execution`                 | Slippage, fill rate                             | 2% slippage = high, 50% fill rate = medium |
| `alpha_health`              | Edge decay                                      | 30% remaining = high, 50% = medium         |
| `feed_health`               | Stale feeds                                     | 300s = high                                |
| `market_opportunities`      | Graph and hypothesis signals                    | 60% confidence = medium                    |
| `edge_signals`              | Hypothesis lifecycle                            | Validated = info, decaying = medium        |
| `correlation_opportunities` | Graph correlation clusters                      | Cluster found = medium                     |

```python theme={null}
agent.DD_CRITICAL = 0.20
agent.VAR_HIGH = 0.60
agent.FEED_STALE_SECS = 600
```

## Output

Every call returns a dict with `findings`, `data_sources`, `reasoning_trace`, `summary`, `duration_secs`.

Each finding has:

| Field      | Description                                                     |
| ---------- | --------------------------------------------------------------- |
| `category` | `risk`, `opportunity`, `anomaly`, `recommendation`, `insight`   |
| `severity` | `critical` (0), `high` (1), `medium` (2), `low` (3), `info` (4) |
| `title`    | Short description                                               |
| `detail`   | Context and suggested action                                    |
| `evidence` | Raw data backing the finding                                    |

```python theme={null}
report = agent.health_check()

for f in report["findings"]:
    print(f"[{f['severity']}] {f['title']}")

print(report["summary"])
# {"total_findings": 3, "by_severity": {"critical": 1, ...}, "by_category": {"risk": 1, ...}}
```
