Market data providers

Choosing a price feed for the desk — why the WebSocket entitlement is the only thing that matters, what each of the four supported vendors actually sells, and how to test a key before you commit it.

5 min readUpdated 3 August 2026providers, market-data, websocket, twelvedata

The terminal quotes from a WebSocket and from nothing else.

That one sentence decides your provider choice, your budget and most of your support load. There is no REST polling fallback anywhere in this extension. handleQuote — the stream's message handler — is the only writer of a symbol's QUOTING state, and every open and every close is refused while a symbol is not QUOTING. A plan that serves REST beautifully and no socket produces an install where credentials verify, prices render once, and every single order comes back "Pricing is temporarily unavailable for this instrument".

The single-active rule

Exactly one market-data provider is active at a time. Activating one deactivates every other. That is deliberate: one feed owns the marks that fills are priced against, and two feeds disagreeing at the moment of a fill is a dealing-desk hazard, not a redundancy feature.

Two things are not bound by that rule, because a bar is the same bar whoever serves it:

  • Historical candles. The chart back-fill tries the active provider first, then up to two other providers that hold credentials. This is why you can run a feed that streams beautifully but sells no history alongside one that has deep history and no live socket.
  • The economic calendar and market news. Any configured provider capable of serving them is tried. Only the Finnhub adapter implements either, and news is free on its tier — so keeping a Finnhub key configured is worth doing even if Finnhub is not your quote source.

Which provider

The comparison below is the same data the admin Providers page renders, and the costs are the vendors' published list prices — indicative only, and none of them include a redistribution licence.

Provider Streams free Coverage Watch out for
Twelve Data (recommended) No FX, US and global stocks, commodities, indices, crypto The free tier has 8 trial WebSocket credits — enough to test, not to run a desk.
Finnhub No, for FX US equities, FX, crypto, news Forex candles return 403 on free. The free socket carries US equities only.
TraderMade No FX pairs and precious metals No stocks at all. Streaming only on streaming-enabled plans.
Polygon / Massive No NYSE/Nasdaq equities and ETFs, plus currencies and metals on higher plans Entry plans serve daily bars only and answer the forex WebSocket with a plan refusal, which opens the circuit breaker and leaves every symbol unquotable.

None of the four streams on a free tier, and the terminal cannot quote a tradable price without a stream. Budget for a streaming-enabled plan before you plan a launch date: a free key will verify, render a price once, and then refuse every order. Twelve Data is the broadest single-vendor option — FX, equities, indices and crypto from one key — which is why it leads the table.

Every vendor here treats showing their prices to third parties as a separate licence from consuming them yourself. Free and entry tiers generally do not include it. This is a contractual matter between you and the vendor — nothing in the software enforces or waives it.

Test a key before you save it

Configuring a provider used to be a four-step loop with a process restart in the middle: paste the key into .env, restart, click Verify, discover the plan has no WebSocket, start again. The admin Providers page collapses that into one round trip.

Tests an unsaved credential and probes the stream, then discards it

Paste the candidate key into the card and press test. The backend builds a throwaway adapter from it, runs the vendor's credential check, opens the quote stream, waits for the first tick or a connected status, and closes it again. The value is never cached, never persisted and never logged; it exists for the duration of the call.

The stream half is the point. A REST credential check is a plain GET /quote, which a non-streaming plan answers perfectly well. Only the socket probe tells you whether the desk can trade.

Getting each provider's credentials

Register at twelvedata.com, confirm your email, then open Account → API Keys. There is one key per account and it carries whatever plan you are on.

Test it before you save. The free tier answers the REST credential check happily and still cannot stream, and the streaming half is the one that decides whether the desk can trade. Streaming and external display rights both start at the Venture tier.

Set APP_TWELVEDATA_API_KEY and restart.

Register at finnhub.io; the free key is issued immediately. Copy the API key from the dashboard — the plain key, not a webhook secret. Set APP_FINNHUB_API_KEY and restart.

Expect the stream probe to fail on forex. The free WebSocket carries US equities only and /forex/candle answers 403. That is a plan limit, not a bad key. Keep Finnhub configured anyway: its market news is free and feeds the terminal regardless of which provider is active for quotes.

Sign up at tradermade.com; the trial issues a key immediately. Copy it from the dashboard — the WebSocket docs call it a "user key", it is the same value. Set APP_TRADERMADE_API_KEY and restart.

Test the stream explicitly. REST live rates work on the free trial while the WebSocket does not, so a passing credential check alone does not mean the desk can quote. There are no stocks on any TraderMade plan.

Register at polygon.io, then take the key from Dashboard → API Keys. Set APP_POLYGON_API_KEY and restart.

Read your plan carefully. Entry plans serve daily aggregates only, have no WebSocket, and have no real-time forex snapshot — the adapter degrades to previous close, which is not a tradable price. Polygon also answers NOT_AUTHORIZED for recent minute aggregates on entry plans, which is one ordinary chart request away rather than a corner case.

What happens when a provider misbehaves

The manager applies a cool-off rather than hammering a failing vendor, and the scope of that cool-off is chosen deliberately.

Failure Cool-off Scope
Rate limited (429) The vendor's Retry-After, clamped to 1–15 minutes The whole provider
Credential rejected (auth) 1 hour The whole provider
Plan limit (403 on a specific endpoint) 1 hour History only — the live quote feed is untouched

The last row matters. A plan limit means "the key is fine, this data is not sold to you" — an endpoint verdict, not an account verdict. Letting a 403 on one chart timeframe pause the price feed would take the marks that fills are priced against down with it.

Cool-offs are stored in Redis and are per provider, so one vendor's quota exhaustion cannot blind another. Repeated identical states are logged once, not once per symbol per interval.

After changing providers

Switching the active provider does not re-map your instruments. Import never deletes another provider's mapping and never changes a status, because an ACTIVE instrument may hold open client positions.

So the sequence is: activate the new provider, run Import Instrument Catalog again, then read the strandedActive list in the response. Those instruments are live for customers and have no mapping for the feed that is now running — they will go quiet. Either map them by hand under Instruments, or move them to CLOSE_ONLY until they are empty.

Next