MCP server for US stock Maximum Drawdown analytics
Project description
mdd-stock-mcp
An MCP server for Maximum Drawdown (MDD) analytics across US stocks, Korean stocks (KOSPI/KOSDAQ), and cryptocurrencies. Plug it into Claude Desktop and ask questions like "What was SPY's worst drawdown during COVID?" or "비트코인 2022년 MDD 알려줘" — Claude will fetch the data and discuss it conversationally.
Disclaimer: This project uses yfinance, an unofficial Yahoo Finance scraper. Not affiliated with Yahoo, not for production trading systems, not for financial advice. Data may be inaccurate, delayed, or unavailable. Use at your own risk.
What it does
- Calculates Maximum Drawdown for any supported asset over a date range
- Returns OHLCV price history for plotting
- Returns a daily drawdown (underwater) series
- Compares MDD across multiple tickers side-by-side
Supported markets (via the market parameter):
market |
Examples | Notes |
|---|---|---|
us (default) |
AAPL, SPY, QQQ |
NYSE / NASDAQ |
kr |
005930 → 005930.KS (Samsung), 035720.KQ (KOSDAQ) |
6-digit codes auto-append .KS (KOSPI). Use explicit .KQ for KOSDAQ. |
crypto |
BTC → BTC-USD, ETH-USD, BTC-KRW |
Bare symbols auto-append -USD. |
Quickstart (Claude Desktop)
1. Clone the repo:
git clone https://github.com/librarywon/mdd-stock-mcp.git
cd mdd-stock-mcp
2. Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"mdd-stock-mcp": {
"command": "uvx",
"args": ["--from", "/absolute/path/to/mdd-stock-mcp", "mdd-stock-mcp"]
}
}
}
Replace /absolute/path/to/mdd-stock-mcp with the actual path where you cloned the repo (e.g. /Users/yourname/Documents/mdd-stock-mcp).
3. Restart Claude Desktop.
Ask: "Using mdd-stock-mcp, what was AAPL's MDD between 2020-01-01 and 2020-12-31?"
Alternative install (after PyPI publishing)
uvx mdd-stock-mcp
(Placeholder — not yet published to PyPI.)
Tools
| Tool | Description | Example |
|---|---|---|
calculate_mdd |
Single-ticker MDD | calculate_mdd("SPY", "2020-01-01", "2020-12-31") |
get_price_history |
OHLCV time series | get_price_history("005930", "2024-01-01", "2024-06-30", market="kr") |
get_drawdown_series |
Daily drawdown % series | get_drawdown_series("BTC", "2022-01-01", "2022-12-31", market="crypto") |
compare_mdd |
Multi-ticker MDD comparison | compare_mdd(["SPY","QQQ","DIA"], "2020-01-01", "2020-12-31") |
Each tool accepts:
price:"adj_close"(default, dividend/split adjusted) or"close"(raw closing price)market:"us"(default),"kr", or"crypto"— see the supported markets table
Output schemas
calculate_mdd — success response
{
"ticker": "SPY",
"mdd_pct": -0.338915,
"peak_date": "2020-02-19",
"trough_date": "2020-03-23",
"drawdown_duration_days": 33,
"recovered": false,
"recovery_date": null,
"market": "us",
"currency": "USD"
}
calculate_mdd — error response
{
"error": true,
"error_type": "InvalidTickerError",
"message": "InvalidTickerError: Ticker 'XYZFAKE' not found or returned no data from Yahoo Finance."
}
get_price_history — success response
{
"ticker": "AAPL",
"price_basis": "adj_close",
"count": 62,
"data": [
{
"date": "2020-01-02",
"open": 296.239990,
"high": 300.600006,
"low": 295.190002,
"close": 298.829956,
"volume": 33870100
}
]
}
get_drawdown_series — success response
{
"ticker": "SPY",
"price_basis": "adj_close",
"count": 125,
"data": [
{"date": "2020-01-02", "drawdown_pct": 0.0},
{"date": "2020-01-03", "drawdown_pct": -0.007054},
{"date": "2020-03-23", "drawdown_pct": -0.338915}
]
}
compare_mdd — success response (partial failure shown)
{
"price_basis": "adj_close",
"start": "2020-01-01",
"end": "2020-06-30",
"results": [
{
"ticker": "SPY",
"mdd_pct": -0.338915,
"peak_date": "2020-02-19",
"trough_date": "2020-03-23",
"drawdown_duration_days": 33,
"recovered": false,
"recovery_date": null,
"error": null
},
{
"ticker": "XYZFAKE",
"mdd_pct": null,
"peak_date": null,
"trough_date": null,
"drawdown_duration_days": null,
"recovered": null,
"recovery_date": null,
"error": "InvalidTickerError: Ticker 'XYZFAKE' not found or returned no data from Yahoo Finance."
}
]
}
How MDD is calculated
- Formula:
drawdown_t = price_t / max(price_{0..t}) - 1 - MDD =
min(drawdown)over the date range (most negative value) - Peak: argmax of price up to and including the trough date
- Recovery: first date after trough where
price >= peak_price - Note:
recovered=falsemeans "did not recover within the queried window", not "never recovered historically"
All price values use dividend/split-adjusted close by default (price="adj_close"). Pass price="close" for raw unadjusted closing prices.
Example Claude conversation
User: mdd-stock-mcp으로 SPY의 2020년 코로나 폭락 분석해줘
Claude: [calls calculate_mdd] SPY는 2020-02-19 최고점에서 2020-03-23 최저점까지 약 -33.9%의 MDD를 기록했습니다. 회복은 2020-08-18에 완료됐어요. 그래프 그려드릴까요?
User: 응
Claude: [calls get_price_history + get_drawdown_series, draws chart in artifact]
Limitations
- US stocks, Korean stocks (KOSPI/KOSDAQ), and major cryptocurrencies — limited to what Yahoo Finance exposes. Other international exchanges (Tokyo, London, etc.) aren't wired up.
- Daily resolution — No intraday (1m, 5m, etc.) data.
- yfinance is unofficial — Yahoo Finance may rate-limit or change their API without notice. For production use, swap
data.pyfor a paid provider like Polygon.io, Alpha Vantage, or Tiingo. - In-memory cache only — Price data is cached for 5 minutes per process. Cache is lost on server restart.
- No real-time data — All data is end-of-day historical prices.
Development
# Install with dev dependencies
uv pip install -e ".[dev]"
# Run tests
pytest tests/
# Open MCP inspector (interactive tool tester)
fastmcp dev src/stock_mcp/server.py
Project structure:
src/stock_mcp/
server.py — FastMCP app + 4 tool definitions
data.py — yfinance wrapper + TTL cache + price-column selector
mdd.py — Pure MDD math functions
models.py — Pydantic input/output models
errors.py — Custom error types
tests/
test_mdd.py — Offline math tests (no network required)
Claude Desktop config reference
{
"mcpServers": {
"mdd-stock-mcp": {
"command": "uvx",
"args": ["--from", "/Users/jaewon/Documents/mdd-stock-mcp", "mdd-stock-mcp"]
}
}
}
After publishing to PyPI, simplify to:
{
"mcpServers": {
"mdd-stock-mcp": {
"command": "uvx",
"args": ["mdd-stock-mcp"]
}
}
}
Deployment
Local (stdio) — default
The default transport is stdio, which is what Claude Desktop expects. Use the uvx config from the Quickstart section above.
Docker
# Build the image
docker build -t mdd-stock-mcp .
# Run with HTTP transport (e.g. for testing or a hosted setup)
docker run -p 8000:8000 mdd-stock-mcp --transport http
Replace 8000 with any port you prefer. The --transport http flag enables the HTTP/SSE transport mode; omit it for the default stdio mode.
Smithery / hosted
Smithery can host MCP servers so you don't need to run them locally. Once the smithery.yaml configuration is present in the repo root, you can register the server through the Smithery dashboard. See the Smithery documentation for registration instructions.
Roadmap
Planned additions (not yet scheduled — PRs welcome):
- Sharpe / Sortino / CAGR tools — additional risk/return metrics as new MCP tools, following the same patterns as the existing four.
- Optional Polygon.io / Alpha Vantage providers — drop-in replacements for the yfinance backend in
data.py, configurable via environment variable. - Shorter date ranges / intraday support — hourly or intraday resolution for ranges under ~7 days, contingent on a stable data provider.
Contributing
This is a small focused project. PRs are welcome — especially for:
- Additional data providers (Polygon, Alpha Vantage, Tiingo) in
data.py - Additional metrics (Sharpe ratio, CAGR, Sortino) as new tools
- Better error messages and edge-case handling
Please open an issue first for significant changes.
License
MIT — see LICENSE
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mdd_stock_mcp-0.1.0.tar.gz.
File metadata
- Download URL: mdd_stock_mcp-0.1.0.tar.gz
- Upload date:
- Size: 112.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0efcb5d2c67e45f35030a03ae13274050d830807f7d174e856d12519112e2b4
|
|
| MD5 |
324017fea70521e5d46fbfa4b596f501
|
|
| BLAKE2b-256 |
aea0d674acc4521ec28742ba963b0cc78c7fab50e75a260886d506bc83db0d83
|
Provenance
The following attestation bundles were made for mdd_stock_mcp-0.1.0.tar.gz:
Publisher:
publish.yml on librarywon/mdd-stock-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdd_stock_mcp-0.1.0.tar.gz -
Subject digest:
e0efcb5d2c67e45f35030a03ae13274050d830807f7d174e856d12519112e2b4 - Sigstore transparency entry: 1675059477
- Sigstore integration time:
-
Permalink:
librarywon/mdd-stock-mcp@16fbed0771120235612537971dbe354d28fc8152 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/librarywon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@16fbed0771120235612537971dbe354d28fc8152 -
Trigger Event:
release
-
Statement type:
File details
Details for the file mdd_stock_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mdd_stock_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
621c29ef87d1931ab570aaf6807d580675d93b966c5332d69ca9a79bb59bf478
|
|
| MD5 |
a65f2cf1887a68756bf3ebee47926d7d
|
|
| BLAKE2b-256 |
f6fc7d5238c29edc16a4d365cd5d51d7c80c577fa841ef8c63dd2024ce539fa0
|
Provenance
The following attestation bundles were made for mdd_stock_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on librarywon/mdd-stock-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mdd_stock_mcp-0.1.0-py3-none-any.whl -
Subject digest:
621c29ef87d1931ab570aaf6807d580675d93b966c5332d69ca9a79bb59bf478 - Sigstore transparency entry: 1675059487
- Sigstore integration time:
-
Permalink:
librarywon/mdd-stock-mcp@16fbed0771120235612537971dbe354d28fc8152 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/librarywon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@16fbed0771120235612537971dbe354d28fc8152 -
Trigger Event:
release
-
Statement type: