Free ETF Price API
Quotes, OHLCV & Python
Find a free ETF price API for current quotes or historical OHLCV, then verify coverage, delay, quotas, licensing, and response fields before you build.
TL;DR
A free API for ETF prices that returns a current quote, historical bars, or both in a documented response.
Usually a limited tier: delayed data, restricted exchanges, small request quotas, or personal-use licensing.
Coverage, timestamps, adjustment rules, latency, rate limits, redistribution rights, and error behavior.
QVeris helps agents discover and inspect relevant financial-data capabilities before calling them.
Free ETF price API data: quotes versus OHLCV
An ETF quote API commonly returns the latest trade or close, change, currency, volume, and a timestamp. An ETF OHLCV API returns open, high, low, close, and volume by interval. Treat “real time” as a claim to verify: free plans may be delayed or limited to specific venues.
Decide which market observation the application needs. A last trade can be old, a midpoint depends on a valid bid and ask, an official close follows venue rules, and a bar aggregates transactions under a stated session and interval. Premarket, regular, and after-hours data should not be merged without explicit session labels and comparable volume definitions.
Current ETF quote fields
Check price, previous close, bid/ask when available, volume, exchange, currency, market status, and an explicit provider timestamp.
Historical ETF price API fields
For charts and backtests, confirm interval support, OHLCV history depth, split and dividend adjustments, timezone, and missing-session behavior.
Real-time, delayed, or end-of-day
Record the documented delay for every exchange. A fast HTTP response does not prove that the underlying market observation is live.
Symbol and exchange identity
A ticker can be ambiguous across venues. Prefer a stable instrument identifier plus exchange code when the API supports it.
Trade and quote conditions
Preserve last trade time, bid, ask, sizes, quote time, condition codes, market status, and halt state. Out-of-sequence, corrected, auction, or odd-lot prints may not represent the current executable market.
Raw, adjusted, and total-return history
Keep raw OHLCV separate from split-adjusted, distribution-adjusted, and total-return series. Document whether distributions are reinvested, how volume is adjusted, and when corporate actions become effective.
Fund and listing identity
Separate legal fund, share class, exchange listing, trading currency, and ticker history. Multiple listings may represent the same strategy but have different prices, sessions, FX exposure, liquidity, and data rights.
How to compare a free ETF market data API
| Requirement | What to inspect | Why it matters | Failure signal |
|---|---|---|---|
| Coverage | ETF universe, exchanges, currencies, delisted symbols. | Determines whether your symbols resolve consistently. | “Global” with no venue list. |
| Freshness | Real-time entitlement, delay, update cadence, timestamp. | Prevents stale values from being shown as live. | No source timestamp. |
| Quota | Requests per minute/day, symbol cost, 429 behavior. | Defines feasible polling and caching. | “Unlimited” without policy. |
| License | Personal, commercial, display, storage, redistribution. | Market-data rights differ from API access. | No written usage terms. |
| Sessions | Premarket, regular, after-hours, auctions, holidays. | Controls baselines, bars, and displayed freshness. | All prints share one unlabeled timeline. |
| Conditions | Trade and quote conditions, corrections, halts, sequence. | Separates valid market state from exceptional prints. | No way to identify stale or corrected values. |
| Adjustments | Splits, distributions, raw versus adjusted fields, version. | Prevents false returns and broken histories. | Only one unexplained close series. |
ETF price API for Python: a safe integration path
Map the provider response into the fields below before displaying a quote. This validator treats the source timestamp—not HTTP arrival speed—as the freshness clock and returns a midpoint only for a non-crossed, sufficiently recent market.
from datetime import datetime, timezone
from decimal import Decimal, InvalidOperation
def parse_time(value: str) -> datetime:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
if parsed.tzinfo is None:
raise ValueError("source timestamp must include a timezone")
return parsed
def validate_etf_quote(quote: dict, max_age_seconds: int = 60) -> dict:
required = {
"instrument_id", "symbol", "exchange", "currency",
"session", "market_status", "source_timestamp", "bid", "ask"
}
missing = required - quote.keys()
if missing:
raise ValueError(f"missing quote fields: {sorted(missing)}")
try:
bid = Decimal(str(quote["bid"]))
ask = Decimal(str(quote["ask"]))
last = None if quote.get("last") is None else Decimal(str(quote["last"]))
except InvalidOperation as exc:
raise ValueError("quote contains a non-numeric price") from exc
if bid <= 0 or ask <= 0 or (last is not None and last <= 0):
raise ValueError("prices must be positive")
if bid > ask:
raise ValueError("crossed market: bid is above ask")
source_time = parse_time(quote["source_timestamp"])
now = datetime.now(timezone.utc)
age_seconds = (now - source_time.astimezone(timezone.utc)).total_seconds()
if age_seconds < 0:
raise ValueError("source timestamp is in the future")
is_live_session = quote["market_status"] == "open"
is_stale = is_live_session and age_seconds > max_age_seconds
return {
"instrument_id": quote["instrument_id"],
"midpoint": (bid + ask) / Decimal("2"),
"last_trade": last,
"spread": ask - bid,
"source_time": source_time,
"age_seconds": age_seconds,
"is_stale": is_stale,
"session": quote["session"],
}
Do not silently substitute values. If the quote is stale or the market is crossed, return that state and preserve the last trade separately. Falling back from bid/ask to last without changing the label turns a validation failure into a plausible but misleading “current price.”
1. Confirm the ETF symbol and venue
Resolve the instrument first. Store the exchange, currency, and provider identifier instead of relying only on a display ticker.
2. Request one quote and one OHLCV series
Use the provider’s documented Python or HTTP example. Start with one symbol and inspect the unmodified JSON before building a mapper.
3. Validate timestamps and numeric fields
Parse timestamps with timezone awareness; reject missing prices; distinguish null from zero; and keep raw plus adjusted close separate.
4. Add caching, backoff, and provenance
Respect documented quotas, back off after 429 responses, cache by data cadence, and retain provider and retrieval timestamps.
5. Rebuild bars and returns on event days
Test distributions, splits, ticker changes, listing moves, halts, auctions, and half sessions. Recompute returns from raw and adjusted data and verify that intraday bars use the intended session and timezone.
6. Monitor quote quality and continuity
Flag crossed or locked markets, stale timestamps, impossible OHLC relationships, duplicate bars, missing sessions, negative volume, and discontinuities not explained by corporate actions. Preserve condition codes for investigation.
7. Store point-in-time evidence
Keep the raw response, provider timestamp, receipt time, entitlement, session, listing ID, condition codes, adjustment version, and retrieval code. Historical revisions should not silently overwrite the values used by earlier research.
Use QVeris to discover ETF quote API capabilities
QVeris is a capability-routing layer, not an ETF exchange or a promise of free real-time entitlements. It can help an agent search for relevant financial-data capabilities, inspect their inputs and outputs, and call a selected tool under that tool’s documented terms.
- Open the QVeris provider details for quote and historical-price capabilities.
- Inspect identifiers, venue, session, quote or bar type, timestamps, condition codes, adjustment policy, response schema, and stated limitations before calling.
- Require the exact listing, currency, data type, interval, session, freshness tolerance, and raw-versus-adjusted choice in the tool request.
- Use the QVeris documentation to connect the selected capability while preserving source evidence and safe failure states.
Free ETF price API FAQ
Is there a free API for ETF prices?
Yes. Some services offer free tiers for ETF quotes or historical prices. Verify supported exchanges, delay, request limits, and usage rights because “free” rarely means unrestricted.
Can I get real-time ETF prices via API?
Sometimes, but exchange entitlements and plan rules vary. Confirm the provider’s written latency and timestamp rather than inferring freshness from response speed.
Which API provides historical ETF prices?
Several market-data APIs expose ETF OHLCV history. Choose by exchange coverage, interval, depth, adjustment method, quota, and license—not by history length alone.
What should I compare in a free ETF API?
Compare coverage, quote fields, OHLCV intervals, timestamps, corporate-action adjustments, limits, authentication, reliability, storage, display, and redistribution terms.
Is the last ETF trade the current price?
It is the most recent reported transaction, which may be old or carry a special condition. For an executable view, inspect current bid, ask, sizes, quote time, session, and halt status alongside the last trade.
Should ETF historical prices be adjusted for distributions?
It depends on the task. Preserve raw prices for market reconstruction and a separately documented adjusted or total-return series for performance analysis; never replace one with the other without a label.
Why do two ETF price APIs show different closes?
They may use different venues, official versus last-trade closes, sessions, timestamps, correction states, consolidation rules, or adjustment versions. Compare the listing and raw event records first.
