← LiquidityWise

池子卡片及其 JSON

以太坊主网

本站有两样东西是为其他网站准备的:一张显示某个池子建议区间的卡片,任何页面都可以把它放进框架里;以及同样数字的 JSON 版本,任何网站的代码都可以读取。两者都不需要密钥或账号。这里按代码实际提供的样子描述它们,并由测试把本页和那份代码绑在一起:本页列出的每个参数,都是读取地址时真正用到的参数;每个字段,都是响应发出前要核对的字段。

卡片

/embed/pool 是一个手写的小页面,不是由网站的框架生成的。它显示交易对及其协议、手续费和网络;建议区间,以及绘制它所用的时间跨度和宽度;当前价格;一行说明这不构成财务建议;以及一个返回本站该池子页面的链接,会在新标签页中打开。区间总是按本站的默认值绘制——30 天、1σ——不管谁自己的设置如何。当前价格在区间外时会加一条提示;对于 hook 可能改变兑换代价的 v4 池子,还会再加一条。

它不含任何脚本和表单,也不加载任何东西:它自己的 Content-Security-Policy 只允许它的内联样式。它的配色就是本站的配色,浅色或深色取决于读者系统的设置。它看不到周围的页面,也没有参数可以选择。

给它一个宽 360 像素、高 220 像素的框架;如果池子的 hook 可能改变兑换代价,高度用 260 像素,因为那张卡片多一行。每个池子的页面在“把这个池子嵌入你的网站”下提供的正是这个,高度已经按该池子调好;提供的框架也永远不会比粘贴进去的那一栏更宽。

这是本站唯一允许其他网站放进框架的页面。其他每个地址(包括本页)发送时都带有 X-Frame-Options: DENY 和 frame-ancestors 'none';卡片发送时不带前者,并带有 frame-ancestors *。

Ethereum 上 0.3% 的 USDC / WETH 池子的框架,与该池子页面提供的一致:
<iframe src="https://liquiditywise.com/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8" title="USDC / WETH on LiquidityWise" width="360" height="220" style="border:0;max-width:100%" loading="lazy"></iframe>
带数字的卡片发送时附带的标头(每个页面都有的标头除外):
Content-Type: text/html; charset=utf-8
Cache-Control: public, max-age=300, s-maxage=300
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors *

参数

卡片和 JSON 接受相同的参数,并像本站自己的页面那样指定池子:v3 池子用它的 address,与 /pool 相同;v4 池子用它的 id,与 /v4 相同。两者必须恰好给出一个,给出的是哪一个,就说明是哪种协议。同一个池子或网络给出两次会被拒绝,而不是从中挑一个值;这里没有列出的参数都会被忽略。

语言只取自地址,从不取自读者的浏览器或 cookie:由放置卡片的网站来选择;同一个地址对每个加载它的人都是同一个响应,这样缓存才能保存它。卡片有本站全部 10 种语言的版本,阿拉伯语版从右往左排。

address
接受 v3 池子的合约地址:0x 加 40 个十六进制数字,大小写均可。
否则 其他任何内容都不指向池子;不读取 v3 的网络(Unichain)上的 v3 池子也一样:400,什么也不读取。
id
接受 v4 池子的 id,即其 PoolKey 的哈希:0x 加 64 个十六进制数字,大小写均可。
否则 其他任何内容都不指向池子:400,什么也不读取。与 address 一起给出的 id 也一样。
chain
接受 下表中某个网络的简称。不给出时,网络为 Ethereum。
否则 本站不读取的简称会被拒绝,绝不会当成 Ethereum 读取:400。
lang
接受 下面列表中的语言代码,用于卡片上的文字和 JSON 的 disclaimer;各语言中的数字完全相同。不给出时为英语。
否则 其他任何值,或给出两次的 lang,都会得到英语。它永远不会被拒绝。

网络,按 chain 接受的简称:

chain网络v3 池子v4 池子
ethereumEthereum读取读取
baseBase读取读取
arbitrumArbitrum One读取读取
unichainUnichain不读取读取
optimismOP Mainnet读取读取
polygonPolygon读取读取

语言,按 lang 接受的代码:

  • enEnglish
  • trTürkçe
  • deDeutsch
  • esEspañol
  • arالعربية
  • hiहिन्दी
  • zh中文
  • ruРусский
  • ptPortuguês
  • zh-Hant繁體中文

JSON

GET /api/embed/pool 用相同的参数,以 JSON 返回卡片上的数字,供宁愿自己绘制的网站使用:同一次读取,保存同样久。每个数字都是 JSON 数值,每个价格都按池子页面的方向书写:一个 price.base 值多少个 price.quote。

响应发出前会与其 schema 核对,不符合的不会发出:这时池子会被回答为无法读取。所以状态为 200 的响应总是恰好包含下面这些字段,不多也不少。

任何网站的脚本都可以读取它。每个响应(包括错误和拒绝)发送时都带有 Access-Control-Allow-Origin: *。它不设置 cookie,也不需要凭证。普通的 GET 不需要预检(preflight),而且不会回应任何预检,所以请不要附加自定义标头。

带数字的响应发送时附带的标头(每个页面都有的标头除外):
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=300, s-maxage=300
Access-Control-Allow-Origin: *

200 响应的每个字段及其 JSON 类型:

protocol"v3" | "v4"
用 address 指定的池子为 v3,用 id 指定的为 v4。
chain.idinteger > 0
网络的 chain id。
chain.slugstring
网络的简称,即 chain 接受的写法。
chain.namestring
网络的名称。
poolstring
池子的地址(v3)或 id(v4),小写。
pair.token0string
池子第一个代币的符号,按其合约所写:这是来自任何人都能部署的合约的文本,放进页面前请先转义。
pair.token1string
第二个代币的符号,同上。
lpFeePpminteger ≥ 0 | null
池子在每笔兑换中付给流动性提供者的手续费,以百万分之一计:3000 即 0.3%。当 v4 池子的 hook 逐笔设定手续费时为 null。
price.basestring
每个价格以其一个单位为准的代币。
price.quotestring
每个价格所用的计价代币。
price.currentnumber > 0
读取时池子的价格。
range.lowernumber > 0
建议区间的下沿,以价格表示。
range.uppernumber > 0
建议区间的上沿。
range.currentInRangeboolean
当前价格是否在区间内。不在时,卡片会加一条提示。
range.lowerTruncatedboolean
当池子的 tick 网格够不到价格带下沿、区间因此在它之前就截止时为 true。
range.upperTruncatedboolean
同上,针对上沿。
parameters.horizonDaysinteger > 0
绘制区间所用的时间跨度,以天计:始终是默认值 30。
parameters.standardDeviationMultipliernumber > 0
绘制区间所用的宽度,以标准差计:始终是默认值 1σ。
hookMayAlterSwapsboolean
对于 hook 可能改变兑换代价的 v4 池子为 true,从 hook 的地址读出;对于 v3、没有 hook 的 v4 池子,以及权限不涉及兑换的 hook,为 false。为 true 时卡片会带一条提示。
analysedAtstring (ISO 8601)
价格被读取的时间,UTC,精确到毫秒——不是这次响应发出的时间,后者可能晚几分钟。
poolUrlstring
该池子在本站的页面,使用相同的时间跨度和宽度。
disclaimerstring
这些数字是什么、不是什么,使用 lang 指定的语言。
示例中那个池子的一个响应。其中的数字只是示例:由本站自己的代码根据一个样本月份的价格算出,而不是从池子读取的;有一项测试检查代码对那个月份仍然恰好返回这些内容:
{
  "protocol": "v3",
  "chain": {
    "id": 1,
    "slug": "ethereum",
    "name": "Ethereum"
  },
  "pool": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
  "pair": {
    "token0": "USDC",
    "token1": "WETH"
  },
  "lpFeePpm": 3000,
  "price": {
    "base": "WETH",
    "quote": "USDC",
    "current": 3000
  },
  "range": {
    "lower": 2824.2704157479307,
    "upper": 3184.336896959513,
    "currentInRange": true,
    "lowerTruncated": false,
    "upperTruncated": false
  },
  "parameters": {
    "horizonDays": 30,
    "standardDeviationMultiplier": 1
  },
  "hookMayAlterSwaps": false,
  "analysedAt": "2026-08-21T09:15:00.000Z",
  "poolUrl": "https://liquiditywise.com/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8&days=30&sigma=1",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

状态码与错误

卡片和 JSON 使用相同的状态码。两者都从不以本站自己的错误页面或内部出错的细节作答:卡片显示一句话和返回链接,JSON 则返回一个脚本可以检测的 error,以及 disclaimer——拒绝除外,它带的是等待时间。

JSON 的响应,以及可以保存多久:

200

数字:带数字的卡片,或上面的 JSON。

Cache-Control: public, max-age=300, s-maxage=300

400 not-a-pool

地址没有指向本站读取的池子:既没有 address 也没有 id,或两者都有,或其中一个格式错误或出现两次,或是本站不读取的网络,或是只读取 v4 的网络(Unichain)上的 v3 池子。什么也没有读取,再问一次也不会改变答案。

Cache-Control: public, max-age=3600, s-maxage=3600

{
  "error": "not-a-pool",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

503 unreadable

格式正确、但此刻无法读取的池子:某个数据源没有及时回应,或该网络上没有这个池子。poolUrl 仍然指向它的页面。一分钟后再问,也许就能读到。

Cache-Control: public, max-age=60, s-maxage=60

{
  "error": "unreadable",
  "poolUrl": "https://liquiditywise.com/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8&days=30&sigma=1",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

429 rate-limited

同一客户端的请求过多:见下文的请求限制。Retry-After 和 retryAfterSeconds 都说明要等待多少秒。卡片会用一个简短页面以自己的语言说明这一点。

Cache-Control: no-store
Retry-After: 42

{
  "error": "rate-limited",
  "retryAfterSeconds": 42
}

缓存与请求限制

每个响应都说明自己可以被保存多久,对浏览器和共享缓存都一样:数字为 300 秒;无法读取的池子为 60 秒,以免恢复的池子长时间显示为无法读取;不指向池子的地址为 3,600 秒,因为以后任何时候都不会改变。拒绝从不保存。用同一个地址询问的每个人得到的响应都相同,这正是保存它是安全的原因。

在此之后,服务器会把每个池子的数字从读取那一刻起保存 300 秒,卡片和 JSON 共用,所有语言共用:同一个池子的每张卡片,无论放在哪个页面上,在过期之前都是同一次读取。无法读取的池子不保存,下一次请求时会重新读取。所以响应中的价格可能比响应本身更早:analysedAt 说明它是何时读取的。

指向格式正确的池子的请求会读取该池子,因此会计入与本站自己的池子页面相同的额度:每个客户端在 60 秒的窗口内最多 10 次请求,窗口从该客户端的第一次请求开始;客户端以请求到达本站时的 IP 地址区分。超出后,响应为 429,并附 Retry-After。每个到达本站的此类请求都会计数,包括由服务器保存的数据作答的请求;不指向池子的请求不计数。

在浏览器中,卡片或 fetch 计入加载它的读者,而不是放置它的网站——所以一个放了超过 10 张卡片的页面,超出的部分会对每位读者被拒绝。在服务器上,你发出的所有请求共用该服务器的同一个额度:请按响应允许的 300 秒保存每个响应,这几乎没有代价,因为在这段时间的大部分里,服务器本来也会用你手上那次读取作答。这个限制是为了压低读取池子的成本,本页没有任何内容承诺它会保持不变。

示例

在终端里读取数字:
curl -s "https://liquiditywise.com/api/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8"
在页面自己的脚本里,或在服务器上,并处理每种响应:
const response = await fetch(
  "https://liquiditywise.com/api/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
);
const body = await response.json();

if (response.ok) {
  // The range, in body.price.quote per one body.price.base
  console.log(body.range.lower, body.range.upper, body.price.quote, body.price.base);
  console.log(body.disclaimer);
} else if (response.status === 429) {
  console.log(`Asked too often: wait ${body.retryAfterSeconds} seconds`);
} else {
  console.log(body.error); // "not-a-pool" or "unreadable"
}
把卡片放到页面上:
<iframe src="https://liquiditywise.com/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8" title="USDC / WETH on LiquidityWise" width="360" height="220" style="border:0;max-width:100%" loading="lazy"></iframe>

单击即可选中整个代码块,方便复制。

条款,用大白话说

这些数字是测量,不是建议。区间是根据池子价格在过去 30 天里的波动幅度算出的:它不是预测,也不是推荐,每个响应都会自己说明这一点——卡片写在正面,JSON 写在 disclaimer 里。每个数字是怎么算出来的、各自漏掉了什么,见“工作原理”页面。

卡片带有自己的返回链接“由 LiquidityWise 分析”。JSON 没有署名字段,代码中也没有任何要求署名的内容;它带的是 poolUrl(该池子在本站的页面)和 disclaimer。把这两项放在数字旁边,读者就能知道数字从哪里来、是什么。

没有版本号,没有密钥,也不承诺响应的结构会保持不变,或网站在任何时刻都能访问。能保证的要窄得多:响应在发出前会与其 schema 核对,而测试把本页与该 schema 以及读取地址的代码绑在一起,所以本页描述的是当前实际提供的内容。两者的任何改动都会出现在代码的公开历史里。

代码是开源的,采用 MIT 许可证。

工作原理代码(GitHub)MIT 许可证