Perp vs Dated Carry
Compare the funding a perpetual is expected to pay until a dated contract expires against the dated contract's basis to that perp. Short the perp and buy the dated contract when funding beats the basis (Perp Carry); buy the perp and short the dated contract when the basis beats funding (Dated Cash-and-Carry).
List perp-dated carry rows
Each row pairs a perp (Binance, OKX, Bybit, Bitget, Hyperliquid, Aster, Kraken, Deribit and other funding venues) with a dated contract of the same coin and margin type. The legs are usually on two venues (crossVenue: true): two accounts, each collateralized separately, and the board does not price moving collateral between them.
The dated leg comes from the 5-minute dated-quotes snapshot (dataset arbitrage_dated_quotes, written by the arbitrage-boards cron with top-20 book walks) for every venue whose quotes there are at most 10 minutes old, else from the hourly term-structure snapshot (stale after 2 hours); the perp leg from the funding book and its 7-day sums, and the perp's book from the venue's bulk ticker. The answer's as_of is its oldest input; its SLA is the dated-quotes snapshot's 600 seconds (cached up to s-maxage=100, stale-while-revalidate=200) when that snapshot priced it, else the term structure's 7,200 seconds. When the stored snapshot is past its one-hour pairing window, empty, or reference-only, the scanner reads the venues live (meta.source: "live") and merges per venue. A failed data-store read returns 503 (service_unavailable, Retry-After: 30).
Order: rows at least 3 days from expiry first, then nearExpiry rows; within each group executable rows, then rows executable on a live read (indicativeReason: snapshot_quote), then every other indicative row, each by netCarryAprPct, highest first.
Query parameters
- Name
coin- Type
- string
- Description
- Optional base coin.
- Name
exchanges- Type
- string
- Description
- Comma-separated exchange filter applied to funding and dated-futures venues.
- Name
minApr- Type
- number
- Description
- Minimum
netCarryAprPct(the fee-adjusted annualized net carry, not the edge to expiry) in percentage points.
- Name
minOiUsd- Type
- number
- Description
- Minimum open interest in USD when available.
- Name
minVolumeUsd- Type
- number
- Description
- Minimum 24h futures volume in USD when available.
- Name
minDepthUsd- Type
- number
- Description
- Minimum executable depth in USD when depth is available.
- Name
marginType- Type
- string
- Description
- Futures margin filter:
linear,inverse, orboth.
- Name
notional- Type
- number
- Description
- Position notional in USD. Defaults to 10000. A row is
executableonly when the depth on both sides the trade hits, any reported open interest and the dated contract's 24h volume are at least this notional.minDepthUsdfilters rows out instead.
- Name
limit- Type
- integer
- Description
- Rows per page. Defaults to 100.
- Name
cursor- Type
- string
- Description
- Opaque cursor from the previous page.
Request
curl -G https://www.sharpe.ai/api/v1/arbitrage/perp-dated-carry \
-H "Authorization: Bearer sk_live_your_key_here" \
-d coin=ETH \
-d exchanges=Bybit
Response
{
"data": {
"rows": [
{
"rank": 1,
"coin": "ETH",
"perpVenue": "Bybit",
"datedVenue": "Bybit",
"datedContract": "ETHUSDT-27MAR27",
"expiry": "2027-03-27T08:00:00.000Z",
"days": 180.979167,
"perpFundingAprPct": 10.95,
"expectedFundingToExpiryPct": 4.912857,
"datedBasisPct": 2.963969,
"carryEdgePct": 1.948888,
"netCarryEdgePct": 1.728888,
"grossCarryAprPct": 3.930531,
"netCarryAprPct": 3.486834,
"bestLeg": "Perp Carry",
"nextFunding": "2026-09-27T10:30:00.000Z",
"funding7dStabilityPct": 0.19,
"executableDepthUsd": 120000,
"minOpenInterestUsd": 60000000,
"oiDepthUsd": 120000,
"executionStatus": "indicative",
"indicativeReason": "snapshot_quote",
"direction": "Short perp / Long dated",
"crossVenue": false,
"nearExpiry": false,
"currentFundingAprPct": 10.95,
"funding7dAprPct": 9.907143,
"funding7dCumulativePct": 0.19,
"fundingProjection": "7d_average",
"fundingIntervalHours": 8,
"fundingSettlementsToExpiry": 543,
"datedLegPrice": 4120.412,
"perpLegPrice": 4001.7999,
"feesPct": 0.22,
"updatedAt": "2026-09-27T08:03:00.000Z",
"isStale": false
}
],
"scannerMeta": {
"kind": "perp-dated-carry",
"status": "ok",
"source": "supabase",
"freshnessSlaSeconds": 7200,
"notionalUsd": 10000
},
"pagination": { "cursor": null, "has_more": false, "total": 1 }
},
"meta": {
"request_id": "req_abc123def456ghij",
"timestamp": "2026-09-27T08:30:00.000Z",
"elapsed_ms": 16
}
}
Formula
The basis is measured against the perp, not spot, at the sides the chosen trade hits:
- Perp Carry (short perp / long dated):
datedBasisPct = (F_ask / P_bid − 1) × 100 - Dated Cash-and-Carry (long perp / short dated):
datedBasisPct = (F_bid / P_ask − 1) × 100
Without a book for the perp's own contract, mark or last prices stand in and the row is indicative no_perp_book.
currentFundingAprPct = fundingRate × 8760 / fundingIntervalHours × 100 (the perp's own interval; perpFundingAprPct is the same number). funding7dAprPct = acc_7d × 365 / 7 × 100, the 7-day realised funding annualized.
expectedFundingToExpiryPct = projected rate per settlement × fundingSettlementsToExpiry, the settlements on the perp's own grid from its next settlement to the expiry instant. The projected rate is the 7-day realised average (fundingProjection: 7d_average); under 3 days to expiry, or without a current 7-day sum, it is the current print (current_print).
carryEdgePct = expectedFundingToExpiryPct − datedBasisPct
feesPct = (2 × perp taker fee + 2 × dated taker fee) × 100, each at its venue's standard rate. Not annualized.
netCarryEdgePct = carryEdgePct − feesPct for Perp Carry, −carryEdgePct − feesPct for Dated Cash-and-Carry. bestLeg and direction name the trade with the larger edge.
netCarryAprPct = netCarryEdgePct × 365 / days; grossCarryAprPct is the edge before fees, annualized. Both may be negative. minApr and ranking use netCarryAprPct.
executableDepthUsd is the smaller of the depth on the dated side and the perp side the trade hits; null when the perp has no book. minOpenInterestUsd is the smaller of the two legs' open interest. oiDepthUsd remains only as a backward-compatible mixed fallback. funding7dStabilityPct is a deprecated alias of funding7dCumulativePct (the 7-day cumulative funding, never a stability figure).
Before 2026-09-30, datedBasisPct was measured against spot and expectedFundingToExpiryPct extrapolated the current funding print (perpFundingAprPct × days / 365).
A row is executable only when all of these hold; otherwise it is indicative and indicativeReason names the first check that failed:
indicativeReason | The check that failed |
|---|---|
stale_snapshot | Both legs are inside the 2-hour freshness SLA. |
no_perp_book | The perp has a bid and ask for its own contract. |
no_depth | The depth on both sides the trade hits is known. |
depth_below_notional | That depth is at least notional. |
oi_below_notional | The smaller leg's open interest, when reported, is at least notional. |
no_volume | The dated contract's 24h volume is known and at least notional. |
snapshot_quote | Every other check passes, but a quote is older than 10 minutes: executable on a live read. |
Rows under 3 days to expiry are served with nearExpiry: true and ranked after every other row. Borrow cost, the cost of moving collateral between two venues, and market impact beyond the displayed depth are not modelled.