On this page本页目录
The shortest correct implementation最短的正确实现路径
/stable/quote for one detailed snapshot.
单只股票的完整快照使用 /stable/quote。
Keep the API key on your server, set a timeout, reject empty arrays, validate the response timestamp, cache by market session, and retry only 429 or 5xx responses. Use a historical endpoint for charts—do not assemble a chart from repeated quote calls.
API Key 必须保存在服务端;设置超时;拒绝空数组;验证响应时间戳;按交易时段缓存;只对 429 或 5xx 重试。图表应使用历史端点,不要靠反复调用 quote 拼接。
Developers building dashboards, alerts, research pipelines, AI tools or portfolio features with FMP price data.
使用 FMP 价格数据开发行情面板、预警、研究管线、AI 工具或投资组合功能的开发者。
An FMP API key, a server runtime, an explicit freshness target, and a decision on adjusted versus unadjusted history.
FMP API Key、服务端运行环境、明确的新鲜度目标,以及复权或不复权的历史数据策略。
Pick the endpoint from the job, not the name根据任务选端点,不要只看名字
“Stock price” can mean a latest snapshot, a compact watchlist refresh, daily candles or minute bars. Those are different payloads with different cost and freshness profiles.
“股票价格”可能指最新快照、关注列表的轻量刷新、日线或分钟线。它们的字段、调用成本和时效要求都不同。
| Need需求 | Stable endpoint | Use it when适用场景 | Watch for注意事项 |
|---|---|---|---|
| Detailed latest quote完整最新报价 | /quote?symbol=AAPL | You need price, change, ranges and volume.需要价格、涨跌、区间和成交量。 | Larger payload.返回字段较多。 |
| Compact latest quote轻量最新报价 | /quote-short?symbol=AAPL | You only need symbol, price and volume.只需要代码、价格和成交量。 | Less context for validation.可用于校验的上下文较少。 |
| Many symbols多个股票代码 | /batch-quote/batch-quote-short | Watchlists or scheduled portfolio refreshes.关注列表或组合定时刷新。 | Plan availability and response size.套餐权限与响应体大小。 |
| Daily history日线历史 | /historical-price-eod/full | Charts, returns and backtests.图表、收益计算与回测。 | Adjustment policy.复权策略。 |
| Intraday bars盘中 K 线 | /historical-chart/1min/5min · /15min · /30min · /1hour | Intraday charts and indicators.盘中图表与技术指标。 | Plan, history depth and timezone.套餐、历史深度与时区。 |
| Extended hours盘前盘后 | /aftermarket-quote/aftermarket-trade | You explicitly label extended-session data.明确标注扩展交易时段数据。 | Never blend silently with regular close.不要静默混入正常收盘价。 |
“Real time” is not a single guarantee“实时”并不是一个统一承诺
Exchange entitlement, endpoint, plan and market session determine whether a value is real time, delayed, after-market or end of day. Your UI should never infer freshness from the word “quote.”
交易所授权、端点、套餐和交易时段共同决定数据是实时、延迟、盘后还是日终。界面不能因为接口叫 “quote” 就假设它一定实时。
When the market observation occurred. Use the response timestamp and normalize it to UTC.
市场事件实际发生的时间。读取响应时间戳并统一转换为 UTC。
When your service received it. Store separately so latency and cache age remain measurable.
你的服务收到数据的时间。单独记录,才能衡量延迟与缓存年龄。
A Friday close is expected on Saturday. “Old” is not always “stale”; compare against the exchange calendar.
周六看到周五收盘价是正常的。“旧”不一定是“失效”,要结合交易所日历判断。
Document currency, venue and corporate-action adjustment before combining symbols or computing returns.
合并股票或计算收益前,明确币种、交易场所和公司行动复权规则。
Call the FMP quote API safely安全调用 FMP Quote API
Load FMP_API_KEY from an environment variable or secret manager. FMP supports an apikey header and a query parameter; the header reduces accidental exposure in URLs and logs.
从环境变量或密钥管理器读取 FMP_API_KEY。FMP 支持 apikey 请求头和查询参数;请求头更不容易把密钥泄露到 URL 与日志中。
Set a timeout, encode the symbol, cap concurrency and record endpoint latency.
设置超时、编码股票代码、限制并发,并记录端点延迟。
HTTP 200 is not enough. Reject an empty array, missing symbol, non-finite price or an unacceptable timestamp.
HTTP 200 并不代表业务成功。空数组、缺失代码、非有限价格或不可接受的时间戳都应拒绝。
curl --fail --silent --show-error \
--get "https://financialmodelingprep.com/stable/quote" \
--data-urlencode "symbol=AAPL" \
--header "apikey: $FMP_API_KEY"import os, time, requests
def get_quote(symbol: str) -> dict:
response = requests.get(
"https://financialmodelingprep.com/stable/quote",
params={"symbol": symbol.upper()},
headers={"apikey": os.environ["FMP_API_KEY"]},
timeout=8,
)
response.raise_for_status()
rows = response.json()
if not isinstance(rows, list) or not rows:
raise ValueError(f"No FMP quote returned for {symbol}")
quote = rows[0]
price = float(quote["price"])
event_time = int(quote["timestamp"])
if price <= 0 or time.time() - event_time > 20 * 60:
raise ValueError("Invalid or unexpectedly stale quote")
return {
"symbol": quote["symbol"],
"price": price,
"currency": quote.get("currency"),
"volume": quote.get("volume"),
"eventTime": event_time,
"retrievedAt": int(time.time()),
"source": "fmp",
}type Price = {
symbol: string; price: number; volume?: number;
eventTime: number; retrievedAt: number; source: "fmp";
};
export async function getQuote(symbol: string): Promise<Price> {
const key = process.env.FMP_API_KEY;
if (!key) throw new Error("FMP_API_KEY is missing");
const url = new URL("https://financialmodelingprep.com/stable/quote");
url.searchParams.set("symbol", symbol.toUpperCase());
const response = await fetch(url, {
headers: { apikey: key },
signal: AbortSignal.timeout(8_000),
});
if (!response.ok) throw new Error(\`FMP returned \${response.status}\`);
const rows: unknown = await response.json();
if (!Array.isArray(rows) || !rows.length) {
throw new Error(\`No quote returned for \${symbol}\`);
}
const q = rows[0] as Record<string, unknown>;
if (!Number.isFinite(Number(q.price)) || !Number.isFinite(Number(q.timestamp))) {
throw new Error("Invalid quote payload");
}
return {
symbol: String(q.symbol),
price: Number(q.price),
volume: q.volume == null ? undefined : Number(q.volume),
eventTime: Number(q.timestamp),
retrievedAt: Math.floor(Date.now() / 1000),
source: "fmp",
};
}Normalize a price into evidence把价格标准化为可验证证据
Do not pass the provider payload through your entire application. Create a small internal contract and retain the raw response for debugging or audit where policy permits.
不要让供应商的原始响应贯穿整个应用。建立一个小而稳定的内部契约,并在政策允许时保留原始响应以便排错或审计。
| Field字段 | Why it belongs为什么需要 | Validation校验 |
|---|---|---|
symbol + exchange | A ticker alone can be ambiguous.仅有股票代码可能存在歧义。 | Match requested instrument and venue.匹配请求的标的与市场。 |
price + currency | A number without denomination is unsafe.没有币种的数字无法安全使用。 | Finite, positive and expected currency.有限、正数、币种符合预期。 |
eventTime | Supports freshness and ordering.用于判断新鲜度与排序。 | Valid epoch; compare with session calendar.有效时间戳,并结合交易日历判断。 |
retrievedAt | Measures transport and cache age.衡量传输与缓存年龄。 | Set by your service, not the provider.由你的服务写入,而非供应商。 |
adjustment | Prevents mixed historical series.防止混用不同复权口径。 | Explicit enum: raw, split or dividend adjusted.显式枚举:原始、拆股复权或股息复权。 |
source | Preserves provenance for agents and audits.为 Agent 与审计保留来源。 | Provider + endpoint + request ID if available.供应商、端点,以及可用时的请求 ID。 |
Choose adjustment before you calculate计算之前先确定复权口径
FMP documents full and light end-of-day history, plus non-split-adjusted and dividend-adjusted variants. The right series depends on the question.
FMP 提供完整与轻量日终历史,同时有不做拆股复权和股息复权的版本。应根据分析问题选择序列。
Prefer a consistently adjusted series so splits or distributions do not look like unexplained price crashes.
优先使用口径一致的复权序列,避免拆股或分红在图上表现为无缘无故的暴跌。
Use actual historical traded prices and model splits, dividends, fees and execution separately.
使用当时真实成交价格,并单独建模拆股、股息、费用和执行情况。
Persist the adjustment method, interval, timezone and requested date range with every stored dataset.
每个落库数据集都应保存复权方式、周期、时区与请求日期范围。
Production controls that matter真正重要的生产控制
Use a short TTL for an open-market watchlist, longer TTL outside the session, and immutable caching for completed historical bars.
开盘中的关注列表使用短 TTL;闭市后延长;已完成的历史 K 线可按不可变数据缓存。
Batch reduces request count but increases payload size and blast radius. Split very large universes into bounded chunks.
批量接口可减少调用次数,但响应更大、失败影响更广。超大标的池应分成有上限的批次。
Retry 429 and 5xx with exponential backoff, jitter and a maximum attempt count. Do not retry invalid symbols or authentication failures.
对 429 和 5xx 使用指数退避、随机抖动与最大次数;无效代码或鉴权失败不要重试。
Track latency, status, empty-result rate, quote age, cache hit rate and provider spend. Alert on behavior, not only transport errors.
监控延迟、状态码、空结果率、报价年龄、缓存命中率和供应商成本。告警不能只看网络错误。
Validation checklist上线前验证清单
- API key is absent from browser bundles, URLs, analytics and application logs.API Key 未出现在浏览器包、URL、分析系统或应用日志中。
- A valid symbol returns a non-empty array and the expected symbol.有效代码返回非空数组,且代码与请求一致。
- An invalid symbol, expired key, timeout and 429 all follow tested error paths.无效代码、过期密钥、超时与 429 都有经过测试的错误路径。
- Freshness thresholds account for weekends, holidays and extended sessions.新鲜度阈值考虑周末、节假日与盘前盘后。
- Historical tests cover a known split or dividend and document adjustment behavior.历史测试覆盖一个已知拆股或分红事件,并记录复权行为。
- Displayed or redistributed data complies with the applicable FMP license.展示或再分发数据符合适用的 FMP 许可条款。
Common failure modes常见失败模式
| Symptom现象 | Likely cause可能原因 | What to do处理方式 |
|---|---|---|
| HTTP 200, empty arrayHTTP 200,但数组为空 | Invalid or unsupported symbol.代码无效或不受支持。 | Treat as not found; verify symbol and exchange.按未找到处理,并核验代码与交易所。 |
| 401 / 403 | Missing key, invalid key or plan entitlement.密钥缺失、无效或套餐权限不足。 | Stop retrying; check secret injection and plan.停止重试;检查密钥注入与套餐。 |
| 429 | Rate limit or quota reached.触发速率或配额限制。 | Honor retry guidance, back off, batch and cache.按提示退避,并使用批量与缓存。 |
| Quote looks stale报价看起来过旧 | Closed market, delayed entitlement or cached data.闭市、延迟授权或缓存数据。 | Compare event time with exchange session and retrieval time.将事件时间与交易时段、获取时间比较。 |
| Chart has a sudden cliff图表突然断崖式下跌 | Split/dividend or mixed adjustment policies.拆股、股息或混用复权口径。 | Inspect corporate actions and rebuild one consistent series.检查公司行动,并重建口径一致的序列。 |
| Daily bars shift dates日线日期发生偏移 | UTC/local timezone conversion.UTC 与本地时区转换问题。 | Store UTC plus exchange timezone; format only at the edge.同时保存 UTC 与交易所时区,只在展示层格式化。 |
Use a capability layer when the workflow must choose当工作流需要“选择能力”时,再引入能力层
A direct FMP call is appropriate when the provider and schema are fixed. QVeris becomes useful when an agent must discover an available capability, inspect its current input contract, invoke it consistently, preserve evidence or fall back across providers.
当供应商和数据结构固定时,直接调用 FMP 很合适。当 Agent 需要发现可用能力、检查当前输入契约、统一调用、保存证据或跨供应商降级时,QVeris 才更有价值。
Search for a stock quote or historical-price capability using intent, market and freshness constraints.
根据任务意图、市场与新鲜度要求查找股票报价或历史价格能力。
Read the live schema before calling. Confirm symbol format, required fields and output provenance.
调用前读取实时 Schema,确认代码格式、必填字段与输出来源。
Invoke with validated arguments, then apply the same normalization and freshness rules described above.
使用校验后的参数执行调用,再应用本文同样的标准化与新鲜度规则。
Match the plan to frequency and history根据频率与历史深度选择套餐
FMP pricing changes. As verified on July 30, 2026, the published plans list: Free at 250 calls/day; Starter at $22/month billed annually and 300 calls/minute; Premium at $59/month and 750 calls/minute; Ultimate at $149/month and 3,000 calls/minute. Intraday depth, global coverage, batch access and bandwidth also vary.
FMP 定价会变化。截至 2026 年 7 月 30 日,公开套餐为:免费版每天 250 次;Starter 按年付折算每月 22 美元、每分钟 300 次;Premium 每月 59 美元、每分钟 750 次;Ultimate 每月 149 美元、每分钟 3,000 次。盘中历史深度、全球覆盖、批量权限和带宽也不同。
FMP’s pricing page states that displaying or redistributing data requires an applicable Data Display and Licensing Agreement. Verify the current plan and terms before purchase or launch.
FMP 定价页说明,展示或再分发数据需要适用的数据展示与许可协议。购买或上线前请核验最新套餐和条款。
FMP stock price API questionsFMP 股票价格 API 常见问题
Is the FMP stock price API real time?FMP 股票价格 API 是实时的吗?
It depends on the endpoint, exchange coverage, entitlement and plan. Treat real-time, delayed, after-market and end-of-day data as different contracts, and validate the response timestamp.
这取决于端点、交易所覆盖、数据授权和套餐。应把实时、延迟、盘后和日终视为不同数据契约,并验证响应时间戳。
Which endpoint returns the latest stock price?哪个端点返回最新股票价格?
Use /stable/quote for a detailed current snapshot or /stable/quote-short when you only need symbol, price and volume.
完整快照使用 /stable/quote;只需要代码、价格和成交量时使用 /stable/quote-short。
How do I request prices for multiple stocks?如何一次请求多只股票?
Use batch-quote for full snapshots or batch-quote-short for compact results. Check plan availability and split very large universes into bounded chunks.
完整快照使用 batch-quote,轻量结果使用 batch-quote-short。先确认套餐权限,并将超大标的池分批。
Does FMP provide historical stock prices?FMP 是否提供历史股票价格?
Yes. FMP documents full, light, non-split-adjusted and dividend-adjusted end-of-day endpoints, plus intraday chart intervals from one minute to one hour.
提供。FMP 文档包含完整、轻量、不做拆股复权和股息复权的日终端点,以及 1 分钟至 1 小时的盘中周期。
Should I use adjusted or unadjusted prices?应该使用复权还是不复权价格?
Use a consistently adjusted series for return calculations and chart continuity. Use actual unadjusted traded prices for execution reconstruction, with corporate actions modeled separately.
收益计算和连续图表使用口径一致的复权序列;还原真实交易时使用不复权成交价,并单独处理公司行动。
Can I expose the API key in browser code?可以把 API Key 放到浏览器代码里吗?
No. Keep it in a server-side environment variable or secret manager and proxy requests through your backend.
不可以。把密钥保存在服务端环境变量或密钥管理器中,并通过后端代理请求。
How should I handle FMP rate limits?如何处理 FMP 限流?
Cache identical requests, batch symbols where appropriate, cap concurrency, and retry only transient 429 and 5xx responses with exponential backoff and jitter.
缓存相同请求、适当批量化、限制并发,并只对瞬时 429 和 5xx 使用指数退避与随机抖动重试。
When should I put QVeris in front of FMP?什么时候应该在 FMP 前使用 QVeris?
Use QVeris for capability discovery, inspected schemas, unified invocation or provider fallback. If your integration is permanently tied to one FMP endpoint, a direct server-side call may be simpler.
需要能力发现、Schema 检查、统一调用或供应商降级时使用 QVeris;若永久绑定单一 FMP 端点,直接服务端调用可能更简单。
Verify against the live documentation以最新官方文档为准
Make every price explainable让每一个价格都可解释
Start with the correct FMP endpoint. Add QVeris when the workflow needs discovery, schema inspection or provider-aware capability routing.
先选择正确的 FMP 端点;当工作流需要能力发现、Schema 检查或供应商感知路由时,再接入 QVeris。
