高级数据流
你点名的 Pons 代币,每一笔交易、每一次流动性变动,上链即推送。一条连接覆盖代币的整个生命周期:
- 内盘上 - Pons v2 联合曲线上的每一笔买入和卖出,曲线费用和创作者税、开盘狙击税分别列出。
- 毕业后的 Uniswap v4 - 代币池子里的每一笔兑换,以及每一个流动性头寸的开仓和平仓。
- Uniswap V3 - Pons v1 代币的同类事件,它们发射即进 V3 池子。
可以用来做实时成交带、钱包追踪、成交量与持有者分析,或者让机器人对别人的动作做出反应,而不只是对发射。实时发射 告诉你一个代币存在了;这条流告诉你它后来发生了什么。
这条流需要密钥。密钥免费。加入 Telegram 群,说一句你在做什么,就能拿到。它存在的唯一目的是让这么大的数据流有个名字对应,不计量,不收费。
WS wss://api.shrine.trade/rh/api/stream/ws?key=你的密钥&tokens=0x…,0x…
WS wss://api.shrine.trade/rh/api/stream/ws?key=你的密钥&wallets=0x…,0x…
跟踪代币,收到发生在它们身上的一切;跟踪钱包,收到它们在任何 Pons 代币上的一切动作;两者可以在同一条连接上同时用。
直接复制
- JavaScript
- Python
const KEY = "sk_…"; // 从 Telegram 群拿到
const TOKENS = ["0x94FDe7626988Ae15E406E89C2277cd1a820dfbD0"]; // 任意 Pons 代币
const ws = new WebSocket(`wss://api.shrine.trade/rh/api/stream/ws?key=${KEY}&tokens=${TOKENS.join(",")}`);
ws.onmessage = (e) => {
const m = JSON.parse(e.data);
if (m.type === "websocket_active") { console.log("正在跟踪", m.tokens.length, "个代币,起始区块", m.block); return; }
if (m.type === "trade") console.log(`${m.side === "buy" ? "买入" : "卖出"} ${m.tokenAmountFormatted} ${m.symbol},${m.quoteAmountFormatted} ${m.quoteSymbol},场所 ${m.venue},钱包 ${m.origin}`);
if (m.type === "liquidity") console.log(`流动性 ${m.action === "add" ? "增加" : "撤出"} ${m.symbol},场所 ${m.venue}:${m.liquidityDelta}`);
if (m.type === "lagged") console.warn("读取太慢,错过了", m.dropped, "个事件");
};
// 不断线也能改跟踪列表。
// ws.send(JSON.stringify({ subscribe: ["0x…"], unsubscribe: ["0x…"] }));
Node 22+ 自带 WebSocket;更老的 Node 需要 npm install ws。
import json, websocket # pip install websocket-client
KEY = "sk_…" # 从 Telegram 群拿到
TOKENS = ["0x94FDe7626988Ae15E406E89C2277cd1a820dfbD0"] # 任意 Pons 代币
def on_message(ws, raw):
m = json.loads(raw)
if m["type"] == "websocket_active":
print("正在跟踪", len(m["tokens"]), "个代币,起始区块", m["block"])
elif m["type"] == "trade":
print(f'{"买入" if m["side"] == "buy" else "卖出"} {m["tokenAmountFormatted"]} {m["symbol"]},{m["quoteAmountFormatted"]} {m["quoteSymbol"]},场所 {m["venue"]},钱包 {m.get("origin")}')
elif m["type"] == "liquidity":
print(f'流动性 {"增加" if m["action"] == "add" else "撤出"} {m["symbol"]},场所 {m["venue"]}:{m["liquidityDelta"]}')
elif m["type"] == "lagged":
print("读取太慢,错过了", m["dropped"], "个事件")
url = f"wss://api.shrine.trade/rh/api/stream/ws?key={KEY}&tokens={','.join(TOKENS)}"
websocket.WebSocketApp(url, on_message=on_message).run_forever()
你会收到什么
连接后先收到一条 websocket_active,确认正在跟踪什么:
{
"type": "websocket_active",
"stream": "advanced",
"tokens": ["0x94FDe7626988Ae15E406E89C2277cd1a820dfbD0"],
"wallets": [],
"unknown": [],
"maxTokens": 50,
"maxWallets": 50,
"block": 57705543,
"upstream": "open"
}
unknown 列出你要求但无法跟踪的东西,并给出原因:不是 Pons 代币的地址,或者根本不是地址。之后的连接内容全是事件。
upstream 为 open 表示节点日志正在流入;为 connecting 表示订阅还在建立中(第一个连接的客户端会触发它),通常一两秒。跟踪的代币一直没动静时,先看这个字段,再判断是不是代币本身安静。
交易
{
"type": "trade",
"venue": "pons_curve",
"side": "buy",
"token": "0x94FDe7626988Ae15E406E89C2277cd1a820dfbD0",
"symbol": "LAPTOP",
"protocol": "PONS_V2",
"quoteToken": "0x…",
"quoteSymbol": "PLTR",
"origin": "0xf0816aa238BaA4774D41B88556292413A6059B75",
"caller": "0xEc20E594D28a17511264dc73a84cd4AA957B0ABc",
"tokenAmount": "885663926228359252587",
"tokenAmountFormatted": "885.663926228359252587",
"quoteAmount": "21060197598119",
"quoteAmountFormatted": "0.000021060197598119",
"price": "0.000000023779",
"curveFee": "210601975981",
"tax": "0",
"priceAfter": "0.000000023779",
"marketCap": "23.779",
"tokenReserve": "807536513474090402491482633",
"tokenReserveFormatted": "807536513.474090402491482633",
"quoteReserve": "2080401284608788604",
"quoteReserveFormatted": "2.080401284608788604",
"reservesSource": "curve",
"block": 55978479,
"timestamp": 1788550107,
"tx": "0xcf9c…",
"logIndex": 8
}
| 字段 | 含义 |
|---|---|
venue | pons_curve(内盘)、uniswap_v4(毕业后的 v2 代币池子)或 uniswap_v3(v1 代币的池子)。 |
side | buy:计价资产进、代币出。sell:反过来。 |
quoteToken / quoteSymbol | 代币的计价资产:ETH(零地址)、USDG、代币化股票。金额都以它计。 |
origin | 发送交易的钱包。大多数交易经过路由合约(我们的、Uniswap 的、Pons 官网的),所以 caller 是合约,origin 才是人。追踪钱包看这个字段。极少数情况下节点没能及时返回交易,此字段会缺失。 |
caller | 调用场所的一方:路由合约,或者直接交易时的钱包本身。 |
tokenAmount / quoteAmount | 最小单位,各配一个 …Formatted 小数。在内盘上是曲线收到和付出的数量。 |
price | 每个代币的计价资产价格,由这笔交易自己的两个金额算出。 |
curveFee / tax | 仅内盘交易:曲线费用,以及从计价资产一侧扣走的创作者税或开盘狙击税,最小单位。 |
priceAfter | 这笔交易完成后每个代币的计价资产价格:池子交易是池子价格,内盘交易是这笔交易自己的价格。 |
marketCap | priceAfter 乘以代币总供应量,以计价资产计。想换算成美元,再乘计价资产自己的价格。 |
tokenReserve / quoteReserve | 交易后场所持有的数量,最小单位加 …Formatted。内盘上是曲线的真实储备;池子里是活跃区间的虚拟储备,由这次兑换报告的流动性和价格推出,也就是下一笔交易的定价依据。reservesSource 说明是哪一种:curve 或 pool_virtual。 |
sqrtPriceX96 / tick | 仅池子交易:兑换后池子的价格,Uniswap 自己的单位。 |
block / timestamp / tx / logIndex | 发生位置。block 加 logIndex 可以精确排序。 |
流动性
{
"type": "liquidity",
"venue": "uniswap_v4",
"action": "add",
"token": "0x…",
"symbol": "CONTRA",
"protocol": "PONS_V2",
"quoteToken": "0x0000000000000000000000000000000000000000",
"quoteSymbol": "ETH",
"origin": "0x…",
"caller": "0x…",
"liquidityDelta": "184467440737095516",
"tickLower": -887220,
"tickUpper": 887220,
"block": 57708240,
"timestamp": 1788779311,
"tx": "0x…",
"logIndex": 3
}
| 字段 | 含义 |
|---|---|
action | add(增加)或 remove(撤出)。 |
liquidityDelta | 增加(正数)或撤出(负数)的流动性数量,Uniswap 自己的计量。 |
tokenAmount / quoteAmount | V3 池子会报告两种资产各动了多少;v4 池子只报告流动性变化,所以这两个字段在 v4 上没有。 |
tickLower / tickUpper | 头寸的价格区间。Pons 池子里的全区间头寸就是 Pons 毕业时自己建的那个。 |
跟踪钱包
在 URL 里传 wallets=,或发送 subscribeWallets,这些钱包发出的每一笔交易和流动性变动都会推过来,不管在哪个代币上,并且标明代币。匹配看 origin(交易发送者)或 caller,所以钱包经过路由合约(我们的、Pons 官网的)交易也能抓到。适合跟单、盯大户、或者盯创作者自己的钱包。
一个限制:钱包在 Uniswap v4 池子里的兑换,只有当这条流启动后见过该池子、或者有人在跟踪该代币时才能标明代币。内盘交易永远能标明。如果你在意某个已毕业的代币,把代币也跟踪上。
控制消息
发送 JSON 文本帧修改跟踪列表;回复是一条 subscribed,带完整的当前列表:
{ "subscribe": ["0x…", "0x…"], "unsubscribe": ["0x…"] }
{ "subscribeWallets": ["0x…"], "unsubscribeWallets": ["0x…"] }
{ "ping": true }
在 URL 后加 &pretty=1,每一帧都会缩进并以换行结尾,用 curl 看成交带很方便。
{"type":"lagged","dropped":n} 表示你的客户端读得太慢,n 个事件被跳过而不是无限排队。处理快一点,或者少跟踪几个代币。
说明
- 必须过滤。 这条链每天有一百多万笔交易。每条连接最多点名 50 个代币和 50 个钱包,只有它们的事件会推过来。没有"全部"模式。
- 实时。 事件由节点订阅推送,出块后一秒内到达,和 实时发射 一样。
- 只有实时。 不存储,不回放。需要数据之前就连上,并保持连接。
- 只支持 Pons 代币。 v2(内盘,然后 Uniswap v4)和 v1(Uniswap V3)。不是 Pons 发射的代币会在
unknown里报告。 - 限制。 每条连接 50 个代币和 50 个钱包,每个密钥、每个 IP 一条连接。想跟踪更多就在同一条连接上加,而不是开第二条;需要更多就开口。
- 密钥可以关停。 被滥用的密钥会失效;已打开的连接在断开后不能再连。