diff --git a/benchmarks/perp-funding-stability.yml b/benchmarks/perp-funding-stability.yml
new file mode 100644
index 00000000..56a537bc
--- /dev/null
+++ b/benchmarks/perp-funding-stability.yml
@@ -0,0 +1,207 @@
+# OpenChainBench. Bench № 043
+
+slug: perp-funding-stability
+number: "043"
+title: Perp DEX funding stability, 7-day stddev of ETH funding ranked
+seo_title: "Perp DEX funding stability 2026: ETH funding stddev across 12 venues ranked"
+seo_description: "Live 7-day standard deviation of ETH perpetual futures funding rate in bps across 12 major venues. Lower means more stable funding for carry traders."
+subtitle: 7-day standard deviation of ETH funding rate, in basis points per 24h, across the Mobula funding cohort. Lower means funding stays in a tight band, the carry trader's preferred signal.
+category: Trading
+status: live
+metric: 7d ETH funding stddev
+unit: bps
+higher_is_better: false
+
+disclaimer: |
+ Stability is not directionality. A venue with persistently positive but tight-banded funding ranks better here than one that flips between positive and negative every settlement, even if the second venue offers better average carry. Read alongside perp-funding for direction and average level.
+
+seo_intro: |
+ This benchmark ranks perp venues by how tightly their ETH funding
+ rate clusters over the trailing 7 days. Average funding tells you
+ which side gets paid; stability tells you how reliably. A venue
+ whose 24h hold cost wanders 15 bps in a week is harder to carry
+ trade than one that holds within 3 bps even if both average the
+ same number. The bench reads the same normalized series as
+ perp-funding (per-venue hold cost in bps per 24h) and exposes
+ stddev_over_time of that series on a 7 day window for ETH. The
+ Mobula funding cohort is 12 venues: Hyperliquid, Binance, Bybit,
+ OKX, dYdX v4, Paradex, Aster, Drift, Vertex, EdgeX, Extended and
+ Aevo. Lower is better.
+
+abstract: |
+ The bench reuses the normalized 24h ETH funding series from
+ perp-funding and adds a 12-venue cohort: Hyperliquid, Binance,
+ Bybit, OKX, dYdX v4, Paradex, Aster, Drift, Vertex, EdgeX, Extended
+ and Aevo. For each venue it publishes the 7 day rolling standard
+ deviation of the ETH hold-24h gauge, in bps. Sign is preserved on
+ the underlying series; the ranking metric is the magnitude of the
+ swing, not its direction. Lower means the venue's funding stayed in
+ a tight band, the cleanest signal for funding-rate arbitrage and
+ basis trades. Cadence and freshness inherit from the upstream
+ funding scrape (60 second poll, 30 second Prom scrape).
+
+methodology:
+ - "Source. Same upstream as perp-funding: each venue's public funding endpoint polled every 60 seconds, normalized to bps per hour and per 24h hold, sign preserved."
+ - "Metric. stddev_over_time(perp_venue_funding_24h_bps{asset=\"ETH\"}[7d]) per venue. The 7d window smooths intraday noise but reacts to regime shifts within a week."
+ - "Sign handling. The underlying series is signed (positive means longs pay). Stability measures the swing, so the ranking uses the unsigned stddev. Average direction and level are the perp-funding bench."
+ - "Cohort. 12 venues: Hyperliquid, Binance, Bybit, OKX, dYdX v4, Paradex, Aster on the CEX-plus-orderbook side; Drift, Vertex, EdgeX, Extended and Aevo on the onchain-perp side. All quote ETH funding with documented intervals."
+ - "Cadence. The upstream funding harness polls every 60 seconds; Prometheus scrapes every 30 seconds. The 7 day stddev refreshes on every scrape."
+ - "Failures. A venue whose upstream funding feed errors keeps its last gauge value; the perp_venue_health gauge drops to 0 and the leaderboard tags the row stale."
+ - "Reproducibility. The harness emits perp_venue_funding_24h_bps with labels venue and asset; the bench query is the stddev over 7d on that series with asset=ETH pinned."
+
+findings:
+ - "{{best_name}} currently has the tightest ETH funding band at {{best_p50}} stddev (7d)."
+ - "{{name:hyperliquid}} sits at {{p50:hyperliquid}} stddev (7d) on ETH. Hourly settlement means rapid reaction to skew but tight clustering once the book is calm."
+ - "{{name:binance}} sits at {{p50:binance}} stddev (7d). Deepest book in the field anchors the rate."
+ - "Outliers on this bench are the venues to watch for funding arbitrage: a wider band means larger spreads to harvest against the cohort median."
+
+source: https://github.com/ChainBench/OpenChainBench/tree/main/benchmarks/perp-funding-stability.yml
+
+prometheus:
+ window: 24h
+ expected_freshness_seconds: 3600
+
+faq:
+ - q: "What does this benchmark measure?"
+ a: "How tightly each venue's ETH funding rate clusters over the trailing 7 days. The ranking metric is the standard deviation of the normalized 24h hold cost in bps. Lower is better."
+ - q: "Why stddev instead of average?"
+ a: "Average funding is the perp-funding bench. This one ranks stability: a venue whose hold cost swings 20 bps in a week is harder to carry trade than one that holds within 3 bps. Both views matter."
+ - q: "Why 7d window?"
+ a: "Long enough to capture a full funding cycle (typically 8h settlements across 21 cycles), short enough to react to regime shifts within a week. 30d would smooth too much and hide stress windows."
+ - q: "Why only ETH?"
+ a: "ETH is the deepest perp pair on every venue in the cohort. BTC and SOL have noisier feeds on some smaller venues, which would contaminate the cross-venue ranking. BTC and SOL stability are companion panels rather than the headline."
+ - q: "Is a low stddev always good?"
+ a: "Low stddev means predictable funding, which is what most carry traders want. But a stable rate of 0 bps is less useful than a stable rate of negative 10 bps; combine this view with perp-funding to size the actual opportunity."
+
+providers:
+ - slug: hyperliquid
+ name: Hyperliquid
+ tag: HyperBFT L1 perp DEX, hourly funding
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"hyperliquid\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="hyperliquid",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="hyperliquid",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="hyperliquid"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="hyperliquid",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="hyperliquid",asset="ETH"}[7d])
+
+ - slug: binance
+ name: Binance
+ tag: Largest CEX perp book, 8h funding
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"binance\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="binance",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="binance",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="binance"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="binance",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="binance",asset="ETH"}[7d])
+
+ - slug: bybit
+ name: Bybit
+ tag: USDT linear perps, interval per instrument
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"bybit\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="bybit",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="bybit",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="bybit"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="bybit",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="bybit",asset="ETH"}[7d])
+
+ - slug: okx
+ name: OKX
+ tag: USDT swaps, 8h funding
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"okx\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="okx",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="okx",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="okx"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="okx",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="okx",asset="ETH"}[7d])
+
+ - slug: dydx
+ name: dYdX v4
+ tag: Appchain order book perps, hourly funding
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"dydx\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="dydx",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="dydx",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="dydx"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="dydx",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="dydx",asset="ETH"}[7d])
+
+ - slug: paradex
+ name: Paradex
+ tag: Starknet L2 perps, 8h funding
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"paradex\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="paradex",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="paradex",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="paradex"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="paradex",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="paradex",asset="ETH"}[7d])
+
+ - slug: aster
+ name: Aster
+ tag: BNB Chain perps, Binance compatible API
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"aster\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="aster",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="aster",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="aster"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="aster",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="aster",asset="ETH"}[7d])
+
+ - slug: drift
+ name: Drift
+ tag: Solana perp DEX, hybrid AMM and orderbook
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"drift\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="drift",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="drift",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="drift"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="drift",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="drift",asset="ETH"}[7d])
+
+ - slug: vertex
+ name: Vertex
+ tag: Arbitrum perp and spot orderbook
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"vertex\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="vertex",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="vertex",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="vertex"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="vertex",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="vertex",asset="ETH"}[7d])
+
+ - slug: edgex
+ name: EdgeX
+ tag: zkSync perp DEX
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"edgex\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="edgex",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="edgex",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="edgex"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="edgex",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="edgex",asset="ETH"}[7d])
+
+ - slug: extended
+ name: Extended
+ tag: Starknet perp DEX (formerly X10)
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"extended\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="extended",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="extended",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="extended"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="extended",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="extended",asset="ETH"}[7d])
+
+ - slug: aevo
+ name: Aevo
+ tag: OP Stack perp DEX with options
+ formula: "stddev_over_time of perp_venue_funding_24h_bps{venue=\"aevo\",asset=\"ETH\"} over a 7d window."
+ queries:
+ p50: stddev_over_time(perp_venue_funding_24h_bps{venue="aevo",asset="ETH"}[7d])
+ mean: stddev_over_time(perp_venue_funding_24h_bps{venue="aevo",asset="ETH"}[7d])
+ success: avg_over_time(perp_venue_health{venue="aevo"}[24h])
+ sample_size: count_over_time(perp_venue_funding_24h_bps{venue="aevo",asset="ETH"}[24h])
+ series: stddev_over_time(perp_venue_funding_24h_bps{venue="aevo",asset="ETH"}[7d])
diff --git a/benchmarks/perp-open-interest.yml b/benchmarks/perp-open-interest.yml
new file mode 100644
index 00000000..47b24f0d
--- /dev/null
+++ b/benchmarks/perp-open-interest.yml
@@ -0,0 +1,119 @@
+# OpenChainBench. Bench № 042
+
+slug: perp-open-interest
+number: "042"
+title: Perp DEX open interest, live USD notional ranked
+seo_title: "Perp DEX open interest 2026: Hyperliquid, Lighter, GMX, gains.trade ranked"
+seo_description: "Live perpetual futures open interest in USD across Hyperliquid, Lighter, GMX v2 and gains.trade. Public API sourced, refreshed every 5 minutes."
+subtitle: Live aggregate open interest in USD across major decentralized perpetual futures venues. Higher means more notional sits open. Read live from each venue's public API.
+category: Trading
+status: live
+metric: Open interest
+unit: usd
+higher_is_better: true
+
+seo_intro: |
+ This benchmark ranks the major onchain perp venues by aggregate open
+ interest, in USD. Open interest is the canonical depth-of-market
+ number for perpetual futures: it tells you how much notional sits
+ open right now, on every market, on a given venue. We poll each
+ venue's public API every 5 minutes, sum open interest across all
+ listed perps, and publish one gauge per venue. Hyperliquid, Lighter,
+ GMX v2 and gains.trade are the cohort. Headline number is the 24h
+ average of the live OI gauge so a single noisy print does not move
+ the ranking.
+
+abstract: |
+ The bench polls four perp DEX venues every 5 minutes for live open
+ interest and exposes a USD-aggregated gauge per venue. Sources:
+ Hyperliquid info metaAndAssetCtxs (openInterest per asset, summed in
+ USD), Lighter orderBookDetails (open interest per market), GMX
+ Subsquid synthetics-arbitrum (openInterest by market), gains.trade
+ onchain reads aggregated by indexer. Each value carries a freshness
+ timestamp and a health gauge so a stale or errored venue does not
+ poison the leaderboard. Higher is better.
+
+methodology:
+ - "Cadence: every 5 minutes per venue in parallel, 10 second timeout per request."
+ - "Hyperliquid: info metaAndAssetCtxs, openInterest summed across all assets and priced in USD using the venue's own mark price."
+ - "Lighter: orderBookDetails per market, open interest summed across markets in USD."
+ - "GMX v2: synthetics-arbitrum subgraph, openInterestUSD summed across markets."
+ - "gains.trade: onchain indexer over Gains v8 contracts on Base, open interest summed across pairs in USD."
+ - "Headline. avg_over_time of the live OI gauge over the last 24 hours, so a one-print spike does not move the ranking. The Series tab plots the raw gauge."
+ - "Failures. A venue that errors or times out keeps its last gauge value and its perp_venue_health gauge drops to 0; the leaderboard tags it as stale."
+
+findings:
+ - "{{best_name}} currently leads the cohort at {{best_p50}} of open interest (24h average)."
+ - "{{name:hyperliquid}} sits at {{p50:hyperliquid}} of open interest. HyperBFT orderbook is the deepest decentralized perp venue."
+ - "{{name:lighter}} clocks {{p50:lighter}} of open interest. Fully onchain orderbook on zkSync."
+ - "{{name:gmx}} sits at {{p50:gmx}} of open interest. Pool-based execution on Arbitrum and Avalanche."
+ - "{{name:gains}} sits at {{p50:gains}} of open interest. Synthetic perps on Base."
+
+source: https://github.com/ChainBench/OpenChainBench/tree/main/benchmarks/perp-open-interest.yml
+
+prometheus:
+ window: 24h
+ expected_freshness_seconds: 1800
+
+faq:
+ - q: "What does this benchmark measure?"
+ a: "The live aggregate open interest of major perp DEX venues in USD. Headline is the 24h average of the live OI gauge so single prints do not skew the ranking."
+ - q: "How is open interest different from volume?"
+ a: "Volume counts every trade that crosses the book during a window. Open interest counts notional that currently sits open, regardless of when it was opened. A high-volume venue with high turnover can carry lower OI than a slower venue with sticky positions."
+ - q: "Why these four venues?"
+ a: "Hyperliquid, Lighter, GMX v2 and gains.trade are the cohort whose public APIs expose open interest cleanly enough to compare without backfilling. Other venues join as their endpoints document the same series."
+ - q: "Is OI a good proxy for venue health?"
+ a: "It is one of the cleanest. A venue can spike volume with wash trading or incentive programs, but real OI is harder to fake because it ties up margin. Compared against perp-volume-share, persistent OI dominance signals real position-holding flow rather than turnover."
+
+providers:
+ - slug: hyperliquid
+ name: Hyperliquid
+ tag: HyperBFT L1 perp DEX
+ formula: "Open interest from Hyperliquid info metaAndAssetCtxs, summed across all assets and priced in USD using the venue's mark price; headline is the 24h time average."
+ queries:
+ p50: avg_over_time(perp_venue_oi_usd{venue="hyperliquid"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_oi_usd{venue="hyperliquid"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_oi_usd{venue="hyperliquid"}[24h])
+ mean: avg_over_time(perp_venue_oi_usd{venue="hyperliquid"}[24h])
+ success: avg_over_time(perp_venue_health{venue="hyperliquid"}[24h])
+ sample_size: count_over_time(perp_venue_oi_usd{venue="hyperliquid"}[24h])
+ series: perp_venue_oi_usd{venue="hyperliquid"}
+
+ - slug: lighter
+ name: Lighter
+ tag: zk-rollup, zero taker fee
+ formula: "Open interest from Lighter orderBookDetails per market, summed across markets in USD; headline is the 24h time average."
+ queries:
+ p50: avg_over_time(perp_venue_oi_usd{venue="lighter"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_oi_usd{venue="lighter"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_oi_usd{venue="lighter"}[24h])
+ mean: avg_over_time(perp_venue_oi_usd{venue="lighter"}[24h])
+ success: avg_over_time(perp_venue_health{venue="lighter"}[24h])
+ sample_size: count_over_time(perp_venue_oi_usd{venue="lighter"}[24h])
+ series: perp_venue_oi_usd{venue="lighter"}
+
+ - slug: gmx
+ name: GMX v2
+ tag: Synthetics on Arbitrum, oracle-priced
+ formula: "openInterestUSD from the GMX synthetics-arbitrum subgraph summed across markets; headline is the 24h time average."
+ queries:
+ p50: avg_over_time(perp_venue_oi_usd{venue="gmx"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_oi_usd{venue="gmx"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_oi_usd{venue="gmx"}[24h])
+ mean: avg_over_time(perp_venue_oi_usd{venue="gmx"}[24h])
+ success: avg_over_time(perp_venue_health{venue="gmx"}[24h])
+ sample_size: count_over_time(perp_venue_oi_usd{venue="gmx"}[24h])
+ series: perp_venue_oi_usd{venue="gmx"}
+
+ - slug: gains
+ name: gains.trade
+ tag: Synthetic perps on Base
+ formula: "Open interest across Gains v8 pairs on Base, read onchain and summed in USD; headline is the 24h time average."
+ queries:
+ p50: avg_over_time(perp_venue_oi_usd{venue="gains"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_oi_usd{venue="gains"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_oi_usd{venue="gains"}[24h])
+ mean: avg_over_time(perp_venue_oi_usd{venue="gains"}[24h])
+ success: avg_over_time(perp_venue_health{venue="gains"}[24h])
+ sample_size: count_over_time(perp_venue_oi_usd{venue="gains"}[24h])
+ series: perp_venue_oi_usd{venue="gains"}
diff --git a/benchmarks/perp-volume-share.yml b/benchmarks/perp-volume-share.yml
new file mode 100644
index 00000000..752115bb
--- /dev/null
+++ b/benchmarks/perp-volume-share.yml
@@ -0,0 +1,120 @@
+# OpenChainBench. Bench № 041
+
+slug: perp-volume-share
+number: "041"
+title: Perp DEX volume share, live 30-day rolling notional ranked
+seo_title: "Perp DEX volume 2026: Hyperliquid, Lighter, GMX, gains.trade ranked by 30d notional"
+seo_description: "Live 30-day rolling perp DEX volume across Hyperliquid, Lighter, GMX v2 and gains.trade in USD notional. Public API sourced, refreshed every 5 minutes."
+subtitle: 30-day rolling perpetual futures notional volume in USD across major decentralized venues. Higher means more flow. Read live from each venue's public API.
+category: Trading
+status: live
+metric: 30d perp volume
+unit: usd
+higher_is_better: true
+
+seo_intro: |
+ This benchmark ranks the major onchain perp venues by 30-day rolling
+ notional volume, in USD. Volume is the cleanest single-number proxy
+ for where perpetual futures flow actually lives today. We poll each
+ venue's public API every 5 minutes, sum the trailing 30 days of taker
+ notional in USD, and publish a single gauge per venue. Hyperliquid,
+ Lighter, GMX v2 and gains.trade are the cohort. Headline number is
+ the 24h average of the 30d rolling sum, so a single noisy print does
+ not move the ranking. The companion benches price the cost side
+ (perp-fees for opening, perp-funding for holding); this one prices
+ flow.
+
+abstract: |
+ The bench polls four perp DEX venues every 5 minutes for cumulative
+ taker notional and exposes a rolling 30 day USD sum per venue.
+ Sources: Hyperliquid info dayNtlVlm (per-asset day notional, summed
+ and rolled into 30d), Lighter public stats endpoint (24h volume per
+ market, rolled), GMX Subsquid synthetics-arbitrum (positionVolume by
+ day), gains.trade onchain reads aggregated by indexer. Each value
+ carries a freshness timestamp and a health gauge so a stale or
+ errored venue does not poison the leaderboard. Higher is better.
+
+methodology:
+ - "Cadence: every 5 minutes per venue in parallel, 10 second timeout per request."
+ - "Hyperliquid: info dayNtlVlm summed across all assets, rolled into a 30 day window via Prometheus sum_over_time on the daily gauge."
+ - "Lighter: public stats endpoint, 24h volume per market, summed across markets and rolled into 30 days the same way."
+ - "GMX v2: synthetics-arbitrum subgraph, positionVolume aggregated per day across all markets, rolled into 30 days."
+ - "gains.trade: onchain indexer over Gains v8 contracts on Base, taker notional summed per day and rolled."
+ - "Headline. avg_over_time of the rolling 30 day sum over the last 24 hours, so a one-print spike does not move the ranking. The Series tab plots the raw rolling sum."
+ - "Failures. A venue that errors or times out keeps its last gauge value and its perp_venue_health gauge drops to 0; the leaderboard tags it as stale."
+
+findings:
+ - "{{best_name}} currently leads the cohort at {{best_p50}} of 30d notional (24h average)."
+ - "{{name:hyperliquid}} sits at {{p50:hyperliquid}} of 30d notional, the deepest decentralized perp book in the field."
+ - "{{name:lighter}} clocks {{p50:lighter}} of 30d notional. Zero taker fee plus a fully onchain orderbook on zkSync."
+ - "{{name:gmx}} sits at {{p50:gmx}} of 30d notional. Pool-based execution on Arbitrum and Avalanche."
+ - "{{name:gains}} sits at {{p50:gains}} of 30d notional. Synthetic perps on Base with onchain fee reads."
+
+source: https://github.com/ChainBench/OpenChainBench/tree/main/benchmarks/perp-volume-share.yml
+
+prometheus:
+ window: 24h
+ expected_freshness_seconds: 1800
+
+faq:
+ - q: "What does this benchmark measure?"
+ a: "The 30 day rolling notional volume of major perp DEX venues in USD. Headline is the 24h average of the rolling 30d sum so single prints do not skew the ranking."
+ - q: "Why 30 day rolling instead of daily?"
+ a: "Daily perp volume is too noisy for ranking, a single thin Sunday can flip positions. The 30 day window smooths the cycle and matches the cadence at which serious flow makers compare venues."
+ - q: "Why these four venues?"
+ a: "Hyperliquid, Lighter, GMX v2 and gains.trade are the cohort whose public APIs expose taker notional cleanly enough to compare without backfilling. Other venues join as their endpoints document the same series."
+ - q: "Is this the same as DeFiLlama volume?"
+ a: "Methodology is similar in spirit but each venue is queried directly here, not via an aggregator. Numbers should sit close to DeFiLlama on most days, divergences usually mean a downstream feed lagged."
+
+providers:
+ - slug: hyperliquid
+ name: Hyperliquid
+ tag: HyperBFT L1 perp DEX
+ formula: "Sum across all assets of Hyperliquid info dayNtlVlm, rolled into a 30 day window, headline is the 24h average."
+ queries:
+ p50: avg_over_time(perp_venue_volume_30d_usd{venue="hyperliquid"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_volume_30d_usd{venue="hyperliquid"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_volume_30d_usd{venue="hyperliquid"}[24h])
+ mean: avg_over_time(perp_venue_volume_30d_usd{venue="hyperliquid"}[24h])
+ success: avg_over_time(perp_venue_health{venue="hyperliquid"}[24h])
+ sample_size: count_over_time(perp_venue_volume_30d_usd{venue="hyperliquid"}[24h])
+ series: perp_venue_volume_30d_usd{venue="hyperliquid"}
+
+ - slug: lighter
+ name: Lighter
+ tag: zk-rollup, zero taker fee
+ formula: "Sum of 24h volume per market from the Lighter public stats endpoint, rolled into a 30 day window, headline is the 24h average."
+ queries:
+ p50: avg_over_time(perp_venue_volume_30d_usd{venue="lighter"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_volume_30d_usd{venue="lighter"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_volume_30d_usd{venue="lighter"}[24h])
+ mean: avg_over_time(perp_venue_volume_30d_usd{venue="lighter"}[24h])
+ success: avg_over_time(perp_venue_health{venue="lighter"}[24h])
+ sample_size: count_over_time(perp_venue_volume_30d_usd{venue="lighter"}[24h])
+ series: perp_venue_volume_30d_usd{venue="lighter"}
+
+ - slug: gmx
+ name: GMX v2
+ tag: Synthetics on Arbitrum, oracle-priced
+ formula: "positionVolume aggregated per day from the GMX synthetics-arbitrum subgraph, rolled into a 30 day window, headline is the 24h average."
+ queries:
+ p50: avg_over_time(perp_venue_volume_30d_usd{venue="gmx"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_volume_30d_usd{venue="gmx"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_volume_30d_usd{venue="gmx"}[24h])
+ mean: avg_over_time(perp_venue_volume_30d_usd{venue="gmx"}[24h])
+ success: avg_over_time(perp_venue_health{venue="gmx"}[24h])
+ sample_size: count_over_time(perp_venue_volume_30d_usd{venue="gmx"}[24h])
+ series: perp_venue_volume_30d_usd{venue="gmx"}
+
+ - slug: gains
+ name: gains.trade
+ tag: Synthetic perps on Base
+ formula: "Taker notional aggregated per day from the Gains v8 onchain indexer, rolled into a 30 day window, headline is the 24h average."
+ queries:
+ p50: avg_over_time(perp_venue_volume_30d_usd{venue="gains"}[24h])
+ p90: quantile_over_time(0.90, perp_venue_volume_30d_usd{venue="gains"}[24h])
+ p99: quantile_over_time(0.99, perp_venue_volume_30d_usd{venue="gains"}[24h])
+ mean: avg_over_time(perp_venue_volume_30d_usd{venue="gains"}[24h])
+ success: avg_over_time(perp_venue_health{venue="gains"}[24h])
+ sample_size: count_over_time(perp_venue_volume_30d_usd{venue="gains"}[24h])
+ series: perp_venue_volume_30d_usd{venue="gains"}
diff --git a/public/logos/aevo.svg b/public/logos/aevo.svg
new file mode 100644
index 00000000..09e01ae0
--- /dev/null
+++ b/public/logos/aevo.svg
@@ -0,0 +1,11 @@
+
diff --git a/public/logos/aster.svg b/public/logos/aster.svg
new file mode 100644
index 00000000..6559bc7b
--- /dev/null
+++ b/public/logos/aster.svg
@@ -0,0 +1,25 @@
+
diff --git a/public/logos/drift.svg b/public/logos/drift.svg
new file mode 100644
index 00000000..959ac3c9
--- /dev/null
+++ b/public/logos/drift.svg
@@ -0,0 +1,5 @@
+
diff --git a/public/logos/edgex.jpg b/public/logos/edgex.jpg
new file mode 100644
index 00000000..0ecd0f19
Binary files /dev/null and b/public/logos/edgex.jpg differ
diff --git a/public/logos/extended.svg b/public/logos/extended.svg
new file mode 100644
index 00000000..9035442b
--- /dev/null
+++ b/public/logos/extended.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/logos/gains.svg b/public/logos/gains.svg
new file mode 100644
index 00000000..0473bedb
--- /dev/null
+++ b/public/logos/gains.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/logos/grvt.jpg b/public/logos/grvt.jpg
new file mode 100644
index 00000000..3ab8f1ab
Binary files /dev/null and b/public/logos/grvt.jpg differ
diff --git a/public/logos/hyperliquid.png b/public/logos/hyperliquid.png
index 4a48daa3..8acd0ff7 100644
Binary files a/public/logos/hyperliquid.png and b/public/logos/hyperliquid.png differ
diff --git a/public/logos/ostium.png b/public/logos/ostium.png
new file mode 100644
index 00000000..ea2b4c81
Binary files /dev/null and b/public/logos/ostium.png differ
diff --git a/public/logos/pacifica.svg b/public/logos/pacifica.svg
new file mode 100644
index 00000000..8bc16b26
--- /dev/null
+++ b/public/logos/pacifica.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/logos/paradex.svg b/public/logos/paradex.svg
new file mode 100644
index 00000000..4b4e0218
--- /dev/null
+++ b/public/logos/paradex.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/public/logos/variational.png b/public/logos/variational.png
new file mode 100644
index 00000000..d473f3c8
Binary files /dev/null and b/public/logos/variational.png differ
diff --git a/public/logos/vertex.png b/public/logos/vertex.png
new file mode 100644
index 00000000..38d253d1
Binary files /dev/null and b/public/logos/vertex.png differ
diff --git a/src/app/perps/page.tsx b/src/app/perps/page.tsx
new file mode 100644
index 00000000..0a095b27
--- /dev/null
+++ b/src/app/perps/page.tsx
@@ -0,0 +1,330 @@
+import Link from "next/link";
+import { fetchPerpByAssetMatrix, fetchPerpCohort } from "@/lib/perp-stats";
+import { PerpHubTabs } from "@/components/perp-hub-tabs";
+import { pageMetadata } from "@/lib/page-metadata";
+import { safeJsonLd, buildBreadcrumbJsonLd } from "@/lib/jsonld";
+import { SITE } from "@/data/site";
+
+/**
+ * Hub landing page for the perpetual DEX cohort. SSR'd against the
+ * `perp_venue_*` gauges exposed by the cross-venue perp cohort harness
+ * plus the existing perp bench gauges (perp-fees, perp-funding). One
+ * server fetch, one client tab swap between DEX venues and by-asset.
+ *
+ * The page positions OCB as the neutral cross-venue measurement layer
+ * for perp DEXes. Volume and open interest sit alongside the measured
+ * execution-quality benches OCB already runs, on the same timeline and
+ * with the same methodology. Per-venue pages live on /products/
+ * (PerpVenueSection mirrors the PM venue treatment).
+ *
+ * The hub renders gracefully before the harness goes live: every
+ * numeric field is independently nullable, the leaderboard shows a row
+ * of dots for missing data, and the JSON-LD ItemList stays valid
+ * because it lists venue identities, not metric values.
+ */
+
+const DESCRIPTION =
+ "Live volume, open interest, fees, all-in cost and funding rate across 15 perpetual DEXes. Reproducible methodology, refreshed every minute, sources public.";
+
+export const metadata: import("next").Metadata = pageMetadata({
+ path: "/perps",
+ title:
+ "Perpetual DEX leaderboard: Hyperliquid, Lighter, GMX, dYdX, live cross-venue ranking",
+ description: DESCRIPTION,
+});
+
+export const revalidate = 60;
+
+export default async function PerpsHubPage() {
+ // Fetch cohort + per-asset matrix in parallel so the by-asset tab is
+ // hydrated on first paint, no second round-trip when the user flips
+ // the pill. Both helpers are wrapped in unstable_cache so concurrent
+ // requests collapse onto the same Prom roundtrip.
+ const [cohort, byAsset] = await Promise.all([
+ fetchPerpCohort(),
+ fetchPerpByAssetMatrix(),
+ ]);
+
+ const breadcrumbLd = {
+ "@context": "https://schema.org",
+ ...buildBreadcrumbJsonLd([
+ { name: "Home", item: SITE.url },
+ { name: "Perpetuals", item: `${SITE.url}/perps` },
+ ]),
+ };
+
+ // ItemList JSON-LD points at the /products/ page for each
+ // venue. The GMX cohort row keys as gmx-v2 (matching the bench
+ // harness label), but the product page lives at /products/gmx, so
+ // map it here. Keeping this list stable means the SERP card does
+ // not churn if the harness drops a series momentarily.
+ const top15 = cohort ? cohort.venues.slice(0, 15) : [];
+ const itemListLd = cohort
+ ? {
+ "@context": "https://schema.org",
+ "@type": "ItemList",
+ name: "Perpetual DEXes tracked by OpenChainBench",
+ description:
+ "Perpetual DEX venues tracked by OpenChainBench, with cross-venue measurements of volume, open interest, fees, all-in cost and funding rate.",
+ numberOfItems: top15.length,
+ itemListElement: top15.map((r, i) => ({
+ "@type": "ListItem",
+ position: i + 1,
+ name: r.name,
+ url:
+ r.slug === "gmx-v2"
+ ? `${SITE.url}/products/gmx`
+ : `${SITE.url}/products/${r.slug}`,
+ })),
+ }
+ : null;
+
+ return (
+
+
+ {itemListLd && (
+
+ )}
+
+
+
+
+
+ {cohort ? (
+ <>
+
+ 0
+ ? `${cohort.totals.trackedVenues} of ${cohort.venues.length}`
+ : `0 of ${cohort.venues.length}`
+ }
+ accent="#14b8a6"
+ tip="Venues with at least a 30 day volume sample in the current cohort run."
+ />
+
+
+
+
+
+
+
+
+ Sources: live cohort harness perp-cohort-stats (volume, OI,
+ fees, active markets, top market). perp-fees bench (007) for
+ the all-in cost column. perp-funding bench (036) for the
+ funding column. All gauges scraped from the public OCB Prom,
+ refresh interval 60s. Click a venue row to open its
+ dedicated product page.
+
+ >
+ ) : (
+
+ Cohort data is temporarily unavailable. The bench pages are
+ still live at{" "}
+
+ /benchmarks/perp-fees
+ {" "}
+ and{" "}
+
+ /benchmarks/perp-funding
+
+ .
+
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
index 70c80f02..e4e7f57e 100644
--- a/src/app/sitemap.ts
+++ b/src/app/sitemap.ts
@@ -80,6 +80,7 @@ function staticHubRoutes(catalogTs: Date): MetadataRoute.Sitemap {
{ url: `${SITE.url}/products`, lastModified: catalogTs, changeFrequency: "daily", priority: 0.9 },
{ url: `${SITE.url}/hyperliquid`, lastModified: catalogTs, changeFrequency: "hourly", priority: 0.9 },
{ url: `${SITE.url}/prediction-markets`, lastModified: catalogTs, changeFrequency: "hourly", priority: 0.9 },
+ { url: `${SITE.url}/perps`, lastModified: catalogTs, changeFrequency: "hourly", priority: 0.9 },
{ url: `${SITE.url}/mcp`, lastModified: pageMtime("mcp/page.tsx"), changeFrequency: "monthly", priority: 0.8 },
{ url: `${SITE.url}/methodology`, lastModified: pageMtime("methodology/page.tsx"), changeFrequency: "monthly", priority: 0.7 },
{ url: `${SITE.url}/contribute`, lastModified: pageMtime("contribute/page.tsx"), changeFrequency: "monthly", priority: 0.7 },
diff --git a/src/components/perp-by-asset-table.tsx b/src/components/perp-by-asset-table.tsx
new file mode 100644
index 00000000..fb928767
--- /dev/null
+++ b/src/components/perp-by-asset-table.tsx
@@ -0,0 +1,261 @@
+"use client";
+
+import { useMemo, useState } from "react";
+import Link from "next/link";
+import { useRouter } from "next/navigation";
+import { ChevronRight } from "lucide-react";
+import { ProviderLogo } from "@/components/provider-logo";
+import type { PerpAssetRow } from "@/lib/perp-stats";
+
+/**
+ * Per-asset funding matrix for the /perps "By asset" tab. One row per
+ * venue, three funding columns (BTC, ETH, SOL) plus the perp-fees
+ * all-in ETH column. Style mirrors PerpVenuesLeaderboard so the two
+ * tabs feel like one widget: same Th/ThSort/Td primitives, same row
+ * click target, same search affordance.
+ *
+ * Default sort: funding ETH ascending = lowest cost to hold a long
+ * surfaces first, which is what a trader scanning the tab wants.
+ */
+
+type SortKey = "fundingBtc" | "fundingEth" | "fundingSol" | "feeEthBps";
+
+export function PerpByAssetTable({ rows }: { rows: PerpAssetRow[] }) {
+ const router = useRouter();
+ const [sortKey, setSortKey] = useState("fundingEth");
+ const [sortDir, setSortDir] = useState<"desc" | "asc">("asc");
+ const [q, setQ] = useState("");
+
+ const filtered = useMemo(() => {
+ const needle = q.trim().toLowerCase();
+ const out = needle
+ ? rows.filter(
+ (r) =>
+ r.name.toLowerCase().includes(needle) ||
+ r.slug.toLowerCase().includes(needle),
+ )
+ : rows;
+ const factor = sortDir === "desc" ? -1 : 1;
+ return [...out].sort((a, b) => {
+ const av = a[sortKey];
+ const bv = b[sortKey];
+ // Nulls sink under either direction so empty cells never claim
+ // rank #1; matches PerpVenuesLeaderboard sort semantics.
+ if (av == null && bv == null) return 0;
+ if (av == null) return 1;
+ if (bv == null) return -1;
+ return factor * (av - bv);
+ });
+ }, [rows, sortKey, sortDir, q]);
+
+ const setSort = (k: SortKey) => {
+ if (k === sortKey) setSortDir((d) => (d === "desc" ? "asc" : "desc"));
+ else {
+ setSortKey(k);
+ // ETH funding defaults to ascending (best for longs); the other
+ // numeric columns default to descending so the highest cost or
+ // highest fee floats to the top when the user clicks the header.
+ setSortDir(k === "fundingEth" ? "asc" : "desc");
+ }
+ };
+
+ if (rows.length === 0) {
+ return (
+
+
+ Data warming up
+
+
+ The per-asset funding matrix needs a fresh harness scrape
+ across BTC, ETH and SOL. Check back in a minute, or browse the
+ DEX venues tab for the cohort view.
+