跳到主要内容

历史回放

全深度流推送的每一个事件也会写入按小时的归档。拉下一个小时,用消费实时 socket 的同一套代码回放它,你就有了一个回测。免费,无需密钥。

https://replay.shrine.trade/pump/YYYY/MM/DD/HH.jsonl.zst

不需要脚本。把某个小时的地址粘贴到浏览器或下载工具里,就能拿到文件:

https://replay.shrine.trade/pump/2026/09/14/12.jsonl.zst

这是 2026 年 9 月 14 日 12:00 到 13:00 UTC。用任意 zstd 工具解压(zstd -d、7-Zip 或 zstandard 包),然后逐行读取。想知道有哪些小时可用,打开 /pump/index.json。

小时按 UTC 计。文件在其小时结束几分钟后出现,归档从开启当天起算;更早的小时不存在。

浏览存储桶​

归档存放在一个公开的 Cloudflare R2 存储桶里。对象存储没有目录列表,所以存储桶自己维护一份:https://replay.shrine.trade/pump/index.json 列出它持有的每一个小时,最早的在前,每次上传后重写。

{ "base": "https://replay.shrine.trade/pump", "pattern": "<base>/<hour>.jsonl.zst", "count": 312, "hours": ["2026/09/11/07", "2026/09/11/08", "…"] }

把 base、hours 里的一项和 .jsonl.zst 拼起来就是一个文件。要拉取全部,遍历 hours;要补一个缺口,找缺失的那一项。

格式​

每行一个 JSON 对象,zstd 压缩。每一行就是实时的 stream 事件,只多一个字段:localTimestamp,即我们的服务器看到这笔交易的毫秒时刻,实时流里没有它。其余的一切——signature、block、timestamp、action、protocol、mint、breakdown、tradersInvolved、储备量和发行权限——都如流页面所述。

一个小时压缩后几百兆,解压后几个 G。流式读取,不要整个加载。

直接复制​

// Node 22.15+ 的 zlib 自带 zstd。更老的 Node:npm install fzstd。
import { createZstdDecompress } from "node:zlib";
import { createInterface } from "node:readline";
import { Readable } from "node:stream";

const url = "https://replay.shrine.trade/pump/2026/09/11/07.jsonl.zst";
const res = await fetch(url);
const lines = createInterface({ input: Readable.fromWeb(res.body).pipe(createZstdDecompress()) });

let buys = 0;
for await (const line of lines) {
const e = JSON.parse(line);
if (e.action === "buy" && e.protocol === "PUMPFUN") buys++;
}
console.log("pump.fun buys that hour:", buys);

说明​

  • 与实时同形。 针对 subscribe_stream 写的代码不用改就能跑在归档上;把行喂给它,而不是 socket 事件。
  • 尽早过滤。 每个发射台上的每一笔交易都在里面。流式读取时只留你关心的协议和动作,其余丢掉。
  • 顺序。 行按事件被看到的顺序排列,也就是区块顺序,偶尔有相邻两行互换。重要时按 block 再按 signature 排序。
  • 完整性。 当一个小时必须可证明地完整时,对比 block 号。