sifting/io
GET/v1/last/movers/:venue

Market movers

Get the top gainers and top losers across stocks, crypto, FX, and commodities, ranked by percentage change since the last daily close, including symbol, current price, previous close, change, percent change, and day volume. One request returns both lists, or just one with direction.

Format
JSON

Example

request · shell
curl -H "X-API-Key: $KEY" \
  "https://api.sifting.io/v1/last/movers/stocks?limit=2"
200OKapplication/json
{  "data": {    "gainers": [      {        "symbol": "NVDA",        "price": "148.32",        "prev_close": "139.1",        "change": "9.22",        "change_pct": 6.6283,        "day_volume": 18452310,        "prev_day_volume": 21980400      },      {        "symbol": "TSLA",        "price": "271.4",        "prev_close": "256.85",        "change": "14.55",        "change_pct": 5.6648,        "day_volume": 9120455,        "prev_day_volume": 10234100      }    ],    "losers": [      {        "symbol": "INTC",        "price": "21.15",        "prev_close": "22.74",        "change": "-1.59",        "change_pct": -6.9921,        "day_volume": 22100870,        "prev_day_volume": 15870200      },      {        "symbol": "PYPL",        "price": "63.4",        "prev_close": "67.1",        "change": "-3.7",        "change_pct": -5.5142,        "day_volume": 5210330,        "prev_day_volume": 6120900      }    ]  },  "meta": {    "as_of": "2026-10-06T15:42:10Z",    "venue": "stocks",    "limit": 2  }}
Loading runner…
First load only

Parameters

Parameter
venuerequiredenum · path
stocks | crypto | forex | commodities.
limitinteger · query
Rows per list, applied to gainers and losers each. 1–100, default 20. Any other value returns 400.
directionenum · query
gainers | losers | all. Default all, which returns both lists. Case-insensitive. Any other value returns 400.

Response fields

Field
data.gainers[]array
Biggest rise first. Omitted when direction=losers.
data.gainers[].symbolstring
Symbol.
data.gainers[].pricestring
Current price.
data.gainers[].prev_closestring
Previous close the move is measured against, the same value /v1/last/close returns.
data.gainers[].changestring
price minus prev_close. Negative for losers.
data.gainers[].change_pctfloat
Percentage change against prev_close, rounded to 4 decimals. Negative for losers.
data.gainers[].day_volumefloat
Volume so far in the current trading day: the UTC day for crypto, forex, and commodities, the regular session for US stocks. Omitted when no volume is available.
data.gainers[].prev_day_volumefloat
Full volume of the trading day before day_volume's day. Omitted when unavailable.
data.losers[]array
Biggest fall first. Same row shape as data.gainers[]. Omitted when direction=gainers.
meta.as_ofstring
When the response was produced. RFC 3339, UTC.
meta.venuestring
The venue you queried.
meta.limitinteger
Rows per list applied to this response.

Reference

Choosing lists
Both lists
No direction, or direction=all, returns gainers and losers.
One list
direction=gainers returns only the gainers key; direction=losers returns only the losers key. The other key is left out of data entirely.
With limit
limit applies to whichever lists you get. ?direction=gainers&limit=10 returns the top 10 gainers.
Empty vs omitted
A list you asked for that has no rows comes back as []. A list you filtered out is not in the response.
How change is measured
Crypto, forex, commodities
Measured against the close taken at 00:00 UTC each day, so change reads as the move since midnight UTC.
US stocks
Measured against the close taken at the US market close (4:00 PM ET), Monday to Friday. During the session you see the move since the previous close; after the close and overnight, you see after-hours moves against that close.
Weekends
No new close is taken, so the lists show the last session's final state.
Same baseline
prev_close is the same value /v1/last/close/:venue/:symbol serves, so the two always agree.
Volume
Source
Our own aggregated volume, the same that feeds our OHLCV bars.
Trading day
The UTC day for crypto, forex, and commodities; the regular session for US stocks. Not a rolling 24 hours.
Between days
Until the next day's first bar (US stock pre-market, weekends, holidays), day_volume still carries the previous day's full total.
Missing vs zero
An omitted field means no volume is available for that symbol; a 0 is a real zero. Check for the key before using it.
Not a ranking input
Rows are ranked by change_pct only. Volume is there for context, for example to compare day_volume with prev_day_volume or skip thinly traded names.
Freshness & behavior
Refresh
Rankings refresh about once a minute: near real-time, not tick by tick. For tick-level prices use /v1/last/trade or the WebSocket.
What's listed
Symbols with both a current price and a previous close. Unchanged symbols appear in neither list, so a list can be shorter than limit, and a quiet market returns 200 with empty arrays, not an error.
Ties
Equal moves are ordered by symbol, so rows never reshuffle between calls.
Prices
From the same fair-price feed as the rest of our live data. Very small or thinly traded stocks can post large percentage moves; filter on price or day_volume client-side if you only want liquid names.
Scope
Ranked by percentage change on the current state. A most-active (volume-ranked) list, history, and price or sector filters are not part of this endpoint.
Access
Follows the live-data access for the market: a plan that includes live stocks includes stock movers, and so on.
Prices are strings, cast before math
Why
price, prev_close, and change come back as JSON strings to preserve exact precision. change_pct, day_volume, and prev_day_volume are plain numbers.
The trap
Math on the raw string fields breaks: Python raises TypeError, JavaScript + silently joins the strings instead of adding.
Python
top = data["data"]["gainers"][0]; price = float(top["price"])
JavaScript
const top = data.data.gainers[0]; const price = Number(top.price);
cURL / jq
Cast in jq too: jq '.data.gainers[] | { symbol, price: (.price|tonumber), change_pct }'

Error responses

  • 400invalid_limit

    limit is not an integer between 1 and 100.

    { "error": "limit must be an integer between 1 and 100" }
  • 400invalid_direction

    direction is not gainers, losers, or all (for example up, both, or gainers,losers).

    { "error": "direction must be gainers, losers or all" }
  • 403not_entitled

    Your subscription doesn't include live data for this market, the same gate as /v1/last/trade.

    {  "error": "no active subscription for this market",  "market_id": "us_stocks",  "feature": "live_stocks"}
  • 404unknown_venue

    Venue path segment isn't one of stocks | crypto | forex | commodities.

    { "error": "unknown venue" }
  • 404venue_not_supported

    dex is a valid venue but has no movers ranking.

    { "error": "movers not available for this venue" }
  • 503market_data_unavailable

    Live data for this market is temporarily unavailable. Retry shortly.

    { "error": "market data unavailable" }

More in Live market data

See all