# Crypto Futures vs Spot: Premium by Expiry and Annual Yield (`scrapemint/crypto-futures-basis-tracker`) Actor

Keyless OKX dated futures data: how far above or below the spot index each expiry trades, converted into an annual percentage yield, for BTC, ETH, SOL and gold. Includes the full term structure, a per coin summary with the curve shape, and the rate implied between consecutive expiries. Pay per row.

- **URL**: https://apify.com/scrapemint/crypto-futures-basis-tracker.md
- **Developed by:** [Ken M](https://apify.com/scrapemint) (community)
- **Categories:** Business, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 basis rows

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Crypto Futures vs Spot: Premium by Expiry and Annual Yield

Keyless **dated futures** data from **OKX**. No API key, no account.

A futures contract that settles in three months usually costs more than the coin does today. This measures that gap for every expiry on the board and converts it into an annual percentage: **the return you would lock in by holding the coin and selling the future against it.**

Two very different people want the same number. Carry traders read it as a **yield** they are deciding whether to harvest. Everyone else reads it as a **leverage gauge** — a fat premium means the market is crowded long, and a premium that flips negative means people are paying to get out.

- **Curve** — one row per contract: price, premium over the index in dollars and percent, days to expiry, and the annualized yield.
- **Summary** — one row per coin: front, quarterly and far carry, whether the curve is in premium or discount, how steep it is, and which contract pays best.
- **Spreads** — consecutive expiry pairs with the rate implied between them, which is the position a curve trader actually puts on rather than a comparison against spot.

Covers **BTC** and **ETH** (both coin margined and USD margined, with deep curves), plus **SOL**. OKX also lists **gold (XAU)** futures, but those contracts rarely trade, so they are filtered out by default along with any other untraded expiry.

### Who uses it

- **Basis and carry traders** — the yield on the trade, across every expiry, in one row set.
- **Any leveraged crypto trader** — the premium is a positioning read, the same job funding rates do for perpetuals but across a whole term structure instead of a single instant.
- **Funds and treasury desks** — compare crypto carry against the risk free rate before deciding where cash sits.
- **Analysts and newsletters** — "three month bitcoin carry is paying 4.2%" is a recurring line, and this is the number behind it.

Pairs with our [Crypto Funding Rates & Open Interest Tracker](https://apify.com/scrapemint/crypto-funding-rates-tracker) for perpetuals, [Crypto Liquidations Tracker](https://apify.com/scrapemint/crypto-liquidations-tracker) for when leverage breaks, and the [Deribit Options Tracker](https://apify.com/scrapemint/deribit-options-tracker) for implied volatility.

### Input

| Field | Description |
|-------|-------------|
| `mode` | `curve`, `summary`, or `spreads`. |
| `coins` | Base assets, e.g. `BTC`, `ETH`, `SOL`, `XAU`. Max 30 per run. |
| `marginType` | `both`, `coin`, or `usd`. |
| `minDaysToExpiry` | Drop contracts expiring sooner than this. Default 7, and the default matters (see below). |
| `requireVolume` | Skip expiries with no 24h volume. On by default. |
| `maxRows` | Row cap per run. |

### Output

- **Curve**: `coin`, `family`, `marginType`, `contract`, `label`, `expiry`, `daysToExpiry`, `futuresPrice`, `indexPrice`, `premiumAbsolute`, `premiumPercent`, `annualizedPercent`, `annualizedReliable`, `inPremium`, `priceSource`, `quoteSpreadPercent`, `volume24hContracts`.
- **Summary**: `coin`, `indexPrice`, `contractCount`, `frontLabel`, `frontPremiumPercent`, `frontAnnualizedPercent`, `quarterContract`, `quarterAnnualizedPercent`, `farLabel`, `farPremiumPercent`, `farAnnualizedPercent`, `curveShape`, `allInPremium`, `steepnessPercent`, `bestAnnualizedContract`, `bestAnnualizedPercent`.
- **Spreads**: `nearContract`, `farContract`, `nearDaysToExpiry`, `farDaysToExpiry`, `gapDays`, `nearPrice`, `farPrice`, `spreadAbsolute`, `spreadPercent`, `forwardAnnualizedPercent`.

`label` is the exchange's own name for the expiry: `this_week`, `next_month`, `quarter`, `next_quarter` and so on, so a row is readable without doing date arithmetic.

### Notes on the data

- **Annualizing a nearly expired contract produces nonsense, and that is why `minDaysToExpiry` defaults to 7.** An ETH contract 3.4 days from expiry showed a 0.625% premium, which scales to 66.88% a year. That is a rounding artifact over a tiny denominator, not a rate. Rows that survive the filter still carry `annualizedReliable` so the judgement stays visible rather than hidden.
- **The index price is taken from each contract's own `uly` field**, not guessed from its name. Every family, coin margined and USD margined alike, references the same `{COIN}-USD` index. Substituting a USDT index moves the reference by about 0.1%, which is larger than a front month premium and would swamp the signal entirely.
- **Untraded contracts are excluded by default, and this matters more than it sounds.** OKX lists back months that have never traded. Their `last` price is stale (two different BTC expiries were quoting an identical 65,975.5 at the same moment) or an empty string, and their bid to ask spread runs to 10%. Annualizing that produces yields that do not exist, including a −151% figure in testing. Prices here come from the **mid of the live two sided quote** where one exists, `last` only as a fallback, and `requireVolume` drops expiries with no 24h volume. `priceSource` and `quoteSpreadPercent` are on every row so you can see which is which.
- **Quasi-perpetual `_XPERP` contracts are excluded.** They are aliased `this_five_years` and expire in 2031, so they are not dated futures in any useful sense.
- A healthy market produces a rising premium with a roughly flat annualized figure across expiries. When the annualized numbers diverge sharply between neighbouring expiries, that is usually thin liquidity in the back months, which is what `volume24hContracts` is there to reveal.
- `curveShape` compares the far premium against the front one, so backwardation means the far end trades at a lower premium, not necessarily below spot. `allInPremium` tells you whether every expiry is above spot.

### Pricing

Pay per event: **$0.003 per row**. The first 2 rows of every run are free.

Data source: OKX public API (`okx.com/api/v5`).

# Actor input Schema

## `mode` (type: `string`):

curve = one row per contract with its premium over spot and annualized yield. summary = one row per coin with front, quarterly and far carry plus the curve shape. spreads = consecutive expiry pairs with the rate implied between them.

## `coins` (type: `array`):

Base assets to read, e.g. BTC, ETH, SOL. XAU (gold) is also listed. Maximum 30 per run.

## `marginType` (type: `string`):

Coin margined contracts settle in the coin itself; USD margined ones settle in dollars. Both are listed for BTC and ETH, while SOL and gold are USD margined only.

## `minDaysToExpiry` (type: `integer`):

Drop contracts expiring sooner than this. The default of 7 exists because annualizing a contract a few days from expiry turns rounding noise into a headline yield: a 0.6% premium 3 days out reads as 67% a year.

## `requireVolume` (type: `boolean`):

Skip expiries with no 24h volume. Untraded back months carry a stale last price and a spread up to 10% wide, which annualizes into yields that do not exist. Turn off only if you want the full board including dead contracts.

## `maxRows` (type: `integer`):

Cap on rows returned. Controls total cost.

## Actor input object example

```json
{
  "mode": "curve",
  "coins": [
    "BTC",
    "ETH",
    "SOL"
  ],
  "marginType": "both",
  "minDaysToExpiry": 7,
  "requireVolume": true,
  "maxRows": 200
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "coins": [
        "BTC",
        "ETH",
        "SOL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapemint/crypto-futures-basis-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "coins": [
        "BTC",
        "ETH",
        "SOL",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("scrapemint/crypto-futures-basis-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "coins": [
    "BTC",
    "ETH",
    "SOL"
  ]
}' |
apify call scrapemint/crypto-futures-basis-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapemint/crypto-futures-basis-tracker"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/V4MD5OaGsoqdN6Vwd/builds/Jg9Ev6QC7UzgycK9q/openapi.json
