使用说明
MCP金融服务器
MCP服务器,用于市场数据、基本面、筛选器分析、期权分析和Wheel策略工作流。
该项目结合了:
- 盈透证券(实时市场连接)
- 雅虎财经(广泛报道基本面/历史)
- 本地ELT管道(用于可靠LLM查询的规范化+缓存表)
面向LLM的分析的默认市场是 sweden.
核心目标
- 稳定、LLM友好的工具,具有明确的默认值和可预测的响应包络。
- 首先从本地数据库进行可靠的缓存分析,并控制回退。
- 快速回答实际交易问题(筛选器、期权、轮盘)。
- 从原始摄取到精心策划的分析表的清晰数据沿袭。
为什么这台服务器与其他服务器相比
- IBKR实时+雅虎+本地策划缓存(不仅直接读取雅虎API)。
- 轮式优先工具集(放置选择、容量、分配流、覆盖呼叫继续)。
- 带有greeks的选项+IV和筛查的选项指标快照。
- 事件风险建模侧重于车轮碰撞窗口。
- 具有确定性串行作业和MCP友好发现工具的本地管道。
端到端示例1(车轮定位选择)
get_wheel_put_candidates(symbol='Nordea', market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10)analyze_wheel_put_risk(symbol='Nordea', pct_below_spot=5.0, target_dte=7)get_wheel_contract_capacity(symbol='Nordea', capital_sek=200000, market='sweden')
端到端示例2(事件风险窗口)
get_wheel_event_risk_window(ticker='NDA-SE.ST', market='sweden', days_ahead=14)get_corporate_events(ticker='NDA-SE.ST', market='sweden')get_monetary_policy_events(market='sweden')
建筑
MCP-Finance-Server/
├── mcp_server.py # MCP tool registry and entrypoint
├── services/
│ ├── market_service.py # Price lookup and symbol resolution
│ ├── option_service.py # IB option chain + greeks
│ ├── option_screener_service.py # Cached option metrics queries
│ ├── screener_service.py # Stock screener + rankings
│ ├── classification_service.py # Sector/subsector/core business/earnings
│ ├── wheel_service.py # Wheel analytics (puts, calls, risk, stress)
│ └── job_service.py # ELT job controls
├── dataloader/
│ ├── models.py # SQLAlchemy models
│ ├── seed.py # DB seed + default jobs
│ ├── scheduler.py # Cron-like job runner
│ └── scripts/ # Extract/transform/curation scripts
└── README.md
数据模型亮点
MCP工具使用的关键标准化/策划表:
stocks,realtime_prices,historical_pricesfundamentals,dividendsstock_metrics,market_moversoption_metricsoption_iv_snapshots(来自期权指标的IV历史快照)exchanges,market_indicessector_taxonomy,industry_taxonomy,subindustry_taxonomystock_classification_snapshots,company_profilesraw_earnings_events,earnings_eventsraw_market_events,market_eventsstock_intelligence_snapshots(新闻/持有者/推荐/声明的本地缓存)
MCP工具组
市场与基本面
get_stock_price(symbol, exchange=None, currency='USD')get_historical_data(symbol, duration='1 D', bar_size='1 hour', exchange=None, currency='USD')get_historical_data_cached(symbol, period='1y', interval='1d')search_symbol(query)get_fundamentals(symbol)get_dividends(symbol)get_dividend_history(symbol, period='2y')get_company_info(symbol)get_financial_statements(symbol)get_comprehensive_stock_info(symbol)get_exchange_info(symbol)yahoo_search(query)
笔记:
get_stock_price,get_historical_data,search_symbol,get_option_chain,以及get_option_greeks是DB优先(管道支持的快照)。- 账户/投资组合端点和摄入作业仍然需要IB实时连接。
IB账户和投资组合
get_account_summary(masked=True)- 资源:
finance://account/summary(默认情况下被屏蔽) - 资源:
finance://portfolio/positions
股票筛选器
get_stock_screener(market='sweden', sector=None, sort_by='perf_1d', limit=50)get_top_gainers(market='sweden', period='1D', limit=10)get_top_losers(market='sweden', period='1D', limit=10)get_most_active_stocks(market='sweden', period='1D', limit=10)get_top_dividend_payers(market='sweden', sector=None, limit=10)get_technical_signals(market='sweden', signal_type='oversold', limit=20)get_highest_rsi(market='sweden', limit=10)get_lowest_rsi(market='sweden', limit=10)get_fundamental_rankings(market='sweden', metric='market_cap', limit=10, sector=None)
分类和收益
get_companies_by_sector(market='sweden', sector=None, industry=None, subindustry=None, limit=50)get_company_core_business(symbol)get_earnings_events(symbol=None, market='sweden', upcoming_only=False, limit=20)
选项(缓存+实时)
get_option_chain(symbol)get_option_greeks(symbol, last_trade_date, strike, right)get_option_screener(symbol=None, expiry=None, right=None, min_delta=None, max_delta=None, min_iv=None, max_iv=None, has_liquidity=True, limit=50)get_option_chain_snapshot(symbol, expiry=None)get_options_data(symbol, expiration_date=None)
市场情报(本地缓存)
get_news(symbol, limit=10)get_institutional_holders(symbol, limit=50)get_analyst_recommendations(symbol, limit=50)get_technical_analysis(symbol, period='1y')get_sector_performance(symbols)
车轮策略工具
get_wheel_put_candidates(symbol, market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10, limit=5, require_liquidity=True)get_wheel_put_annualized_return(symbol, market='sweden', target_dte=7)get_wheel_contract_capacity(symbol, capital_sek, market='sweden', strike=None, margin_requirement_pct=1.0, cash_buffer_pct=0.0, target_dte=7)analyze_wheel_put_risk(symbol, market='sweden', pct_below_spot=5.0, target_dte=7)get_wheel_assignment_plan(symbol, assignment_strike, premium_received, market='sweden')get_wheel_covered_call_candidates(symbol, average_cost, market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=21, min_upside_pct=1.0, limit=5)compare_wheel_premiums(symbol_a, symbol_b, market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10)evaluate_wheel_iv(symbol, market='sweden', lookback_days=90, high_iv_threshold_percentile=70.0, target_dte=7)simulate_wheel_drawdown(symbol, strike, premium_received, drop_percent=10.0, market='sweden')compare_wheel_start_timing(symbol, market='sweden', wait_drop_percent=3.0, delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10)build_wheel_multi_stock_plan(capital_sek, symbols=None, market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10, margin_requirement_pct=1.0, cash_buffer_pct=0.10)stress_test_wheel_portfolio(capital_sek, sector_drop_percent=20.0, symbols=None, market='sweden', delta_min=0.25, delta_max=0.35, dte_min=4, dte_max=10)
活动日历工具
get_event_calendar(market='sweden', category=None, event_type=None, ticker=None, start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_corporate_events(market='sweden', ticker=None, start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_macro_events(market='sweden', start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_monetary_policy_events(market='sweden', start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_geopolitical_events(market='sweden', start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_market_structure_events(market='sweden', start_date=None, end_date=None, min_volatility_impact='low', limit=50)get_wheel_event_risk_window(ticker, market='sweden', days_ahead=14, limit=100)
本地缓存数据库工具
get_earnings_history(symbol, limit=10)get_earnings_calendar(symbol)query_local_stocks(country=None, sector=None)query_local_fundamentals(symbol)
工作和管道管理
list_jobs()get_job_logs(job_name, limit=5)trigger_job(job_name)toggle_job(job_name, active)get_job_status()run_pipeline_health_check()
能力发现
get_market_capabilities()- 返回分组功能(
methods+examples)因此,法学硕士可以用具体行动回答“你能做什么?”。
- 返回分组功能(
describe_tool(tool_name)- 返回一个工具的参数模式(类型/默认值)、Pydantic JSON模式(如果可用)、docstring摘要和示例。
help_tool(tool_name)- 别名为
describe_tool,适用于要求help.
- 别名为
get_server_health()- 返回相当于的健康有效载荷
/health.
- 返回相当于的健康有效载荷
get_server_metrics(output_format='json'|'prometheus')- 返回等效于的度量有效载荷
/metrics.
- 返回等效于的度量有效载荷
健康和指标资源
- 资源:
finance://status - 资源:
finance://health - 资源:
finance://metrics
LLM服务设计规则
在添加/更新工具时使用这些规则,以便其他代理可以依赖稳定的行为。
- 比起大型工具,更喜欢特定意图的工具。
- 保持安全默认值(
market='sweden',低风险limit,有界的窗户)。 - 钳制限制并规范已知枚举样式字段。
- 返回显式
criteria和empty_reason对于零结果查询。 - 空结果不是系统错误(
success=true,data=[]). - 包含
as_of_date或as_of_datetime当数据基于快照时。 - 不要伪造不可用的后端数据;返回不确定性或数据状态不足。
- 保持响应密钥稳定;避免破坏重命名。
- 尽可能保持表模式稳定;在查询/服务层进化。
- 使用API密钥和严格的脚本路径验证来保护管理端点。
代理指令(MCP友好)
将另一个AI代理连接到此服务器时,请使用以下指令:
- 先打个电话
get_market_capabilities()用于意图路由。 - 对于未知工具,请致电
describe_tool(tool_name)在执行之前。 - 与广泛的查询相比,更喜欢特定意图的工具。
- 始终使用明确的市场默认值(
market='sweden')除非用户覆盖。 - 尊重不确定性:如果后端没有数据,则返回不足的数据响应。
- 切勿推断时间戳;使用
meta.asof从工具响应。 - 在仅雅虎模式下(
IB_ENABLED=false),避免使用IB工具,转而使用本地/Yahoo工具。 - 对于敏感信息,请保留
get_account_summary(masked=True)除非用户在可信环境中明确提出其他请求。 - 如果工具返回
validation_error,修复输入,然后使用更正的参数重试一次。 - 如果电源开路(
circuit_open),在冷却之前避免重复重试。
事件建模规则
在中使用统一事件 market_events 根据这份最低合同:
- 识别:
event_id,event_type,category,subtype - 时间:
event_datetime_utc,timezone,market,is_market_hours,is_pre_market,is_after_market - 范围:
ticker,sector,country,region,affected_markets - 影响:
expected_volatility_impact,systemic_risk_level,is_recurring,confidence_score - 具体数据:
expected_eps,previous_eps,expected_revenue,previous_value,forecast_value,actual_value
支持的类别:
corporatemacromonetary_policygeopoliticalmarket_structure
稳定响应包络
首选形状:
{
"success": true,
"data": {},
"error": {
"code": null,
"message": null,
"details": null
},
"meta": {
"source": "ibkr|yahoo|local_db|pipeline|system|...",
"asof": "2026-02-13T12:34:56.000000+00:00",
"cache_ttl": null,
"request_id": "uuid",
"default_market": "sweden",
"market_timezone": "Europe/Stockholm"
}
}
笔记:
- 信封在
mcp_server.py(tool_endpoint装饰师)。 - 现有服务特定密钥(
count,criteria等等)被保存。
车轮分析公式
用于 wheel_service.py 并通过MCP工具暴露:
- 卖出期回报率(%)=
(premium / strike) * 100 - 年化回报率(%)=
period_return * (365 / DTE) - 每份合同的现金担保资本=
strike * 100 - 容量=
floor((capital * (1-cash_buffer_pct)) / (strike * 100 * margin_requirement_pct)) - 盈亏平衡(空头)=
strike - premium - 分配概率代理=
abs(delta) - 到期时的提款情况=
max(0, break_even - final_price)
笔记:
abs(delta)是一个代理,而不是一个真正的概率模型。- 时间比较工具返回具有显式不确定性(无预测)的情景分析。
数据管道作业(关键)
主要工作岗位 dataloader/seed.py 包括:
- 原始摄取:雅虎价格/基本面、IBKR价格、IBKR工具、期权指标。
- 标准化:价格、基本面、分类分类法、公司简介。
- 策划:收益活动。
- 分析:股票指标、市场推动者、期权IV快照、事件日历。
- 情报缓存:新闻、机构持有人、分析师建议、财务报表快照。
- 加载器:股票列表、参考数据、股息、历史价格、指数表现。
- 验证:管道健康检查。
种子行为(python -m dataloader.seed):
- 默认作业的同步:创建缺失的作业并更新现有作业(description/script/cron/timeout/tables),而不重复行。
- 默认情况下,首次加载完全运行,并且始终以串行方式运行(没有并行作业执行)。
- 加载顺序是基于相位的,以最大限度地提高鲁棒性:
MASTER:参考/股票代码/原始+转换/历史/股息/收益/分类。IB:IBKR提取器/选项(仍然是串行的,可以跳过)。COMPUTE:指标/推动者/事件/情报快照。
- 第一个加载数据集包括:
- 历史价格(5年),
- 股息(5年),
- 收益(10年)+管理,
- 分类规范化+公司简介丰富,
- 股票指标+市场推动者,
- 标准化事件日历生成。
- 市场情报快照。
- 内置回退:如果筛选器基线保持为空,它将重试历史负载+指标/移动器。
- 可选标志:
--skip-first-load:仅初始化DB+同步作业。--skip-ib:在首次加载时跳过IB相关步骤。--warmup:已弃用别名(首次加载已为默认)。
快速开始
5分钟入职培训(即插即用)
pip install -e .
python -m dataloader.seed --skip-ib
IB_ENABLED=false mcp-finance
然后将您的MCP客户端指向此服务器(以下示例)。
码头工人
docker compose up -d
docker compose --profile init run seed
本地
pip install -e .
python -m dataloader.seed
mcp-finance
python -m dataloader.app
运行时配置文件
Yahoo-only:IB_ENABLED=false- 启动时没有IB连接尝试。
- IB工具返回结构化
ib_disabled错误。
IBKR + Yahoo:IB_ENABLED=true(默认)- 需要IB网关/TWS连接和市场数据权限。
环境变量(参考)
IB_ENABLED:true|false(默认值true)
MCP_TRANSPORT:sse|stdio(默认值sse)
MCP_HOST:- 默认
0.0.0.0
- 默认
MCP_PORT:- 默认
8000
- 默认
DEFAULT_MARKET:- 默认
sweden
- 默认
DEFAULT_MARKET_TIMEZONE:- 默认
Europe/Stockholm
- 默认
MCP_TOOL_ALLOWLIST:- 逗号分隔的工具名称;如果设置,则只有列出的工具可调用
CIRCUIT_BREAKER_FAILURE_THRESHOLD:- 默认
4
- 默认
CIRCUIT_BREAKER_COOLDOWN_SECONDS:- 默认
45
- 默认
MCP客户端配置示例
克劳德桌面
{
"mcpServers": {
"finance": {
"command": "mcp-finance",
"env": {
"IB_ENABLED": "false",
"DEFAULT_MARKET": "sweden",
"DEFAULT_MARKET_TIMEZONE": "Europe/Stockholm"
}
}
}
}
光标
{
"mcp": {
"servers": {
"finance": {
"command": "mcp-finance",
"args": [],
"env": {
"IB_ENABLED": "true",
"MCP_TRANSPORT": "stdio"
}
}
}
}
}
帆板运动
{
"mcpServers": [
{
"name": "finance",
"command": "mcp-finance",
"env": {
"IB_ENABLED": "false"
}
}
]
}
最小Python代理
import os
import subprocess
env = os.environ.copy()
env["IB_ENABLED"] = "false"
proc = subprocess.Popen(["mcp-finance"], env=env)
print("MCP Finance server PID:", proc.pid)
安全说明
- 集
DATALOADER_API_KEY用于管理API端点。 - 保持
DATALOADER_ALLOW_INSECURE=true仅限于地方发展。 - 配置CORS
DATALOADER_ALLOWED_ORIGINS. - 可选工具满列表:set
MCP_TOOL_ALLOWLIST=get_market_capabilities,describe_tool,.... - 默认情况下,帐户摘要被屏蔽(
get_account_summary(masked=true)). - 如果通过网络传输运行MCP(
MCP_TRANSPORT=sse),保持主机/防火墙受限,并在MCP客户端网关上使用API/身份验证控件。
威胁模型(此服务器不执行的操作)
- 不下订单。
- 不修改位置。
- 不提交交易。
- 不转移资金。
- 不提供有保证的预测。
按设计只读:仅分析、筛选、事件、账户检查和管道控制。
可观察性和操作性
get_server_health()和资源finance://healthget_server_metrics(output_format='json'|'prometheus')和资源finance://metrics- 每次工具调用的结构化JSON日志(
request_id、工具、来源、延迟、成功) - 带冷却功能的断路器(IBKR/Yahoo/本地组)
- 内置工具级指标:调用/失败/平均延迟/源代码故障
- 通过IB连接运行时快照暴露的速率限制器指标
代码质量和发布
pre-commit已配置挂钩(ruff,black,isort,mypy)- GitHub操作CI(
.github/workflows/ci.yml)运行皮棉、类型检查和测试 - 推荐释放流程:
- 碰撞
version在pyproject.toml - 创建git标签(
vX.Y.Z) - 更新更新日志/发行说明
- 碰撞
操作说明
- 如果筛选器返回空,请运行:
Historical Prices LoaderCalculate Stock MetricsUpdate Market Movers
- 如果Wheel IV分析报告历史记录不足,则运行选项度量作业,并
Snapshot Option IV持续了好几天。 - 如果期权数量稀少,请确保IB市场数据权限和期权订阅处于活动状态。
- 对于宏观/货币/地缘政治事件,保持
dataloader/data/manual_events.json并运行Load Event Calendar. - 要刷新本地新闻/持有者/推荐/声明缓存,请运行
Load Market Intelligence. - 为了避免重复的手动运行,后端和前端都可以防止同一作业的并发触发器:
- 后端返回
"Job '<name>' is already queued/running"当存在开放运行时, - 前端在请求执行过程中禁用运行按钮。
- 后端返回
- 调度器执行模型现在是一个单一的工作队列:
- 所有cron/手动触发器都已排队
status='queued', - 全球一次只有一个作业运行,
- 已对同一作业进行重复数据消除
queued/running. - 在调度器启动时,孤儿
queued/running跑步会自动恢复到failed.
- 所有cron/手动触发器都已排队
- Jobs UI使用应用内通知/祝酒和确认模式(无浏览器
alert()流量)。
故障排除
- 指标种子过程中出错,如
operands could not be broadcast together with shapes (29,) (30,):- 通过使用稳健的返回序列来固定(
pct_change)在波动率计算中,而不是脆性阵列切片。 - 确保你遵守承诺
4d0292f或更新。
- 通过使用稳健的返回序列来固定(
- 如果种子因本地缺失deps而失败,请先安装项目依赖关系:
pip install -e .
许可证
麻省理工学院