curl -X GET "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day" \
-H "Authorization: Bearer <YOUR_API_KEY>"fetch("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day", { headers: { "Authorization": "Bearer <YOUR_API_KEY>"} })
.then(response => response.json())
.then(data => console.log(data))require('axios')
.get("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day", { headers: { Authorization: 'Bearer <YOUR_API_KEY>' } })
.then(response => console.log(response))require 'net/http'
uri = URI("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer <YOUR_API_KEY>"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport requests
headers = {'Authorization': 'Bearer <YOUR_API_KEY>'}
url = "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day"
print(requests.get(url, headers=headers).json())<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index")
.header("Authorization", "Bearer <token>")
.asString();{
"status": {
"code": 123,
"message": "<string>"
},
"result": {
"window": "<string>",
"data": [
{
"datetime": "<string>",
"pnl_index": 123,
"bull_bear_indicator": 123
}
]
}
}PnL Index
A composite valuation index built from the MVRV ratio, NUPL, and long-/short-term-holder SOPR.
curl -X GET "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day" \
-H "Authorization: Bearer <YOUR_API_KEY>"fetch("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day", { headers: { "Authorization": "Bearer <YOUR_API_KEY>"} })
.then(response => response.json())
.then(data => console.log(data))require('axios')
.get("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day", { headers: { Authorization: 'Bearer <YOUR_API_KEY>' } })
.then(response => console.log(response))require 'net/http'
uri = URI("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer <YOUR_API_KEY>"
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyimport requests
headers = {'Authorization': 'Bearer <YOUR_API_KEY>'}
url = "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index?asset=btc&window=day"
print(requests.get(url, headers=headers).json())<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.cryptoquant.com/v2/indicator/unrealized-pnl/pnl-index")
.header("Authorization", "Bearer <token>")
.asString();{
"status": {
"code": 123,
"message": "<string>"
},
"result": {
"window": "<string>",
"data": [
{
"datetime": "<string>",
"pnl_index": 123,
"bull_bear_indicator": 123
}
]
}
}What it measures
A composite valuation index built from the MVRV ratio, NUPL, and long-/short-term-holder SOPR. The accompanying bull/bear indicator is the index minus its 365-day moving average, which separates bull regimes (above0) from bear regimes (below 0). The index and its moving average are also published on the community endpoints Bitcoin PnL Index and Bitcoin Bull/Bear Indicator.
Assets and windows
| Asset class | What it covers | Assets | Windows |
|---|---|---|---|
| Bitcoin | the native asset of Bitcoin, asset=btc | btc | day |
day.
Response fields
This endpoint serves onlywindow=day, so the time key is always datetime.
| Field | Type | Description |
|---|---|---|
pnl_index | number | Profit and Loss Index — a composite valuation index built from the MVRV ratio, NUPL, and LTH/STH SOPR. |
bull_bear_indicator | number | The PnL Index minus its 365-day moving average. Above 0 reads as a bull regime, below 0 as a bear regime. |
Authorizations
For each API request, include the Authorization HTTP header with Bearer {access_token}.
Query Parameters
Asset to query, by its CryptoQuant alias (no chain suffix — usdt, not usdt_eth). 1 asset is available on this endpoint, across the asset class btc. Enumerate them with /v2/discovery/endpoints.
Chain the asset lives on. Optional for an asset that exists on exactly one chain, required when the same alias exists on several.
bitcoin Aggregation window. Which windows are valid depends on the asset — see the endpoint page. Defaults to day.
day Inclusive start time, YYYYMMDDTHHMMSS (UTC). If window=day, YYYYMMDD is also accepted.
Inclusive end time, YYYYMMDDTHHMMSS (UTC). If window=day, YYYYMMDD is also accepted.
Maximum rows returned (default 100, max 10000).
x <= 10000Response format: json (default) or csv.
json, csv