desk

desk

Provides multi-agent equity research for US markets with provenance-backed financial data from SEC EDGAR, technicals, macro, and Alpaca paper trading, enforcing risk limits and journaling theses.

Category
访问服务器

README

Trading Desk

Multi-agent equity research for US markets, running on Claude Code subagents over MCP. Analysis-first: real money is never touched, and order flow goes to an Alpaca paper account.

Why this exists

Financial data is easy to fetch and easy to get wrong. US-GAAP XBRL concepts drift per company and over time, so reading a single hardcoded concept returns figures that are years stale with no error raised:

Ticker Live concept Correct FY revenue Naive Revenues lookup
AAPL RevenueFromContractWithCustomerExcludingAssessedTax $416.2B (FY25) $62.9B — a 2018 figure
NVDA Revenues $215.9B (FY26) correct, coincidentally
MSFT RevenueFromContractWithCustomerExcludingAssessedTax $331.8B (FY26) $16.0B — a 2010 figure

An agent given $62.9B for Apple writes a confident, completely wrong thesis. The whole design follows from preventing that.

Operating rules

  1. Agents never compute and never recall. Every number comes from a tool call; ratios and indicators are calculated in Python.
  2. Every value carries provenance — XBRL concept, period, form, accession, filing date — so any figure can be traced back to the filing.
  3. Stale data raises. A number too old to answer the question is an error, not a footnote.
  4. Concept resolution is code with tests, not a prompt instruction.

Status

Phase 4 complete: research, sizing, a scoreable record, the context around a name, and paper execution that cannot be reached except through an approved thesis.

  • [x] EDGAR client — rate limited, disk cached, no API key required
  • [x] Concept resolver with provenance and staleness enforcement
  • [x] Golden tests (23) pinned to filed 10-Ks
  • [x] desk MCP server, verified over stdio
  • [x] Phase 1 — fundamentals + chartist agents, /analyze
  • [x] Phase 2 — risk (veto) + journal, /journal
  • [x] Phase 3 — filings, macro, screener
  • [x] Phase 4 — pilot, Alpaca paper execution behind risk approval
  • [ ] Phase 5 — /postmortem calibration loop

Setup

uv sync
uv run pytest tests/golden -q     # must be green before any agent work

Credentials

Keys live in the environment, never in the repo — .mcp.json reads them via ${VAR} expansion. Put them in ~/.zshrc so they cannot be committed by accident.

Variable Where to get it Needed by
ALPACA_API_KEY / ALPACA_SECRET_KEY app.alpaca.markets — switch the dashboard to Paper, then API Keys → Generate. Secret shows once. Phase 1 (chartist)
FRED_API_KEY fredaccount.stlouisfed.org/apikeys — instant, free macro agent. Everything else runs without it
SEC_USER_AGENT Your own name email optional; defaults in .mcp.json

Paper trading needs no funding, identity check or approval — that applies only to live accounts.

Verify without exposing anything (the script prints presence and a masked prefix only, never a secret):

uv run python scripts/check_keys.py

Data sources

Source Provides Auth
SEC EDGAR XBRL financials, filings, Form 4 insider none (User-Agent only)
Alpaca Bars, quotes, news, paper orders/positions free API key
FRED Rates, curve, inflation free API key

Deliberately not used: yfinance (unofficial endpoints, silent empty responses) and Stooq (now behind a JS proof-of-work wall). EDGAR is preferred for fundamentals because it is the source of record rather than a scrape of it.

MCP tools

Tool Returns
get_financials Full statement, 17 line items, each with provenance
get_financial_history Historical series for one line item
get_metrics Margins, returns, growth, leverage, cash conversion
get_technicals Trend, momentum, volatility, support and resistance
list_line_items Supported line item keys
get_filings Recent filings, optionally filtered by form
get_filing_text A filing's text as filed, markup stripped, in windows
search_filing_text Verbatim passages around a term in a filing
get_insider_activity Form 4 insider transactions
get_macro_snapshot Rates, curve, inflation, jobs, vol, dollar — with changes
get_macro_series One macro series in detail
get_market_movers / get_most_active Discovery lists from the tape
rank_candidates Orders a symbol list by relative strength
size_position Share count, capital at risk, every limit checked, verdict
get_risk_policy The standing limits, each with its rationale
journal_thesis Records a call with its evidence and falsifiers
list_theses / get_thesis The book, open or closed
close_thesis Resolves a call and computes realised R
get_account Paper account equity, cash, buying power
place_order Sends an approved thesis to the paper broker
get_broker_positions / get_broker_orders Broker state
cancel_order / close_broker_position Unwind
reconcile_positions Broker positions against journalled theses

Risk limits

The risk agent holds a veto and does not exercise judgement about it — the limits are policy, checked in Python, and quoted back with the reason they exist. get_risk_policy returns them at runtime.

Limit Value Why
Risk per trade 1% of equity Ten consecutive losses cost a tenth of the account, which is survivable
Position size 20% of equity A tight stop makes a huge position look cheap; gaps do not respect stops
Portfolio heat 6% of equity The total loss accepted if every open thesis fails at once
Reward:risk 2:1 minimum Below it the strategy needs a win rate nobody here has demonstrated
Stop distance 1.5x ATR(14) A stop inside daily noise is an exit schedule, not protection

Correlation is the one call the checks cannot make: three 1% positions on the same driver are one 3% position in disguise, and the agent is instructed to veto that even when every numeric limit passes.

The journal

Theses are JSON files under theses/, one per call, written at the moment the call is made — greppable, diffable, and reviewable alongside the code that produced them. A thesis will not record without at least one falsifier, and direction="watch" calls are recorded too: a watchlist name that ran away without you is as informative as a trade that failed, and only one of the two tends to get remembered. Realised R is computed on close from the recorded entry and stop, so outcomes compare across positions of different sizes.

Set DESK_THESES_DIR to keep the book somewhere other than the repository.

Execution

Paper only. The base URL is the paper endpoint, hardcoded with no environment variable that redirects it, and the account number is checked for Alpaca's PA prefix before any order is sent — live keys against the paper URL fail closed rather than trading.

The gate is the shape of the function rather than an instruction to an agent:

place_order(thesis_id)      # and nothing else

There is no symbol parameter, no quantity, no price. All of it is read back out of the journal entry, which exists only because the risk officer approved it and only carries a share count the risk officer computed. An agent asked to buy 100 shares of something has no way to express that.

An order is refused when the thesis is closed, is a watch call, carries a vetoed verdict, was sized at zero shares, lacks an entry or stop, or already has an order attached — the last of which is what stops a retried call from opening a second position in the same name.

Orders go out as brackets, so the stop the risk officer sized against is submitted with the entry rather than left to a later call that might never happen. reconcile_positions compares what the broker holds against what the journal knows about, which is the only way to see the untracked exposure that portfolio heat is blind to.

Known limitations

  • Q4 quarterly gaps. Q4 gets no standalone 10-Q; it must be derived as FY minus Q1–Q3. Not yet implemented — quarterly series skip Q4.
  • Alpaca free tier is IEX-only (~2% of consolidated volume), so daily-bar volume is unreliable for swing setups. The price layer sits behind an adapter so Tiingo or another EOD source can be swapped in without touching agent code. Same seam later carries a non-US broker.
  • Non-US-GAAP filers (foreign issuers on IFRS) are not covered by the current concept registry.
  • The screener has no universe. It ranks a list you give it and reads the venue's movers and most-active tables. It cannot screen "all US software above $2B" — there is no fundamental universe behind it, and a themed list assembled by an agent is a recollection, not a screen. The screener agent is instructed to say which it is.
  • Filing text is text. get_filing_text strips markup and returns what was filed. Tables survive as readable rows, but nothing is parsed into figures — a number read out of filing prose has no XBRL concept behind it, so prefer get_financials whenever the figure exists there.
  • Macro needs its own key. Without FRED_API_KEY the macro tools fail with a message saying where to get one. Nothing else on the desk depends on them.
  • A submitted order is not a filled one. A limit entry may never fill, and the position does not exist until it does. The pilot agent is instructed never to describe one as the other.
  • Portfolio heat only sees the journal. A position taken without recording it is invisible to the risk checks, so the heat number is exposure as recorded rather than exposure as held. size_position says so in its limitations on every call.

Not financial advice

A research tool, not a prediction engine. The /postmortem loop exists because calls need to be scored honestly rather than remembered selectively.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选