跳转到 API 参考
Raydium LP Dashboard
BUILD WITH ON-CHAIN DATA

公开 API 文档

查询池目录与成交量,订阅建池、开仓、加仓、减仓和关仓事件。为程序接入和 AI 阅读提供同一份接口参考。

Raydium CLMMOrca Whirlpool可恢复的事件订阅
GET/api/public/pools池目录 ↗GET/api/public/pools/volume全部池成交量 ↗GET/api/public/pools/{poolId}/volume单池成交量 ↗WS/api/public/pool-creations/wsRaydium 新建池 ↗WS/api/public/position-openings/ws按地址订阅仓位变动 ↗
FOR AI & DEVELOPERS

直接读取,无需解析页面

把 /llms.txt 链接交给 AI 作为入口,或使用完整文本一次读取全部字段、示例与订阅协议。所有链接均无需登录。

读取 Node.js 开仓 / 关仓订阅示例 →

公共 API 提供当前监控池目录(Raydium,可选 Orca/Meteora 24h 榜单)、Raydium/Orca 分钟级成交量与实际手续费、单池历史成交量、CLMM 建池 WebSocket 及按创建者地址订阅开仓、加仓、减仓和关仓的 WebSocket。所有接口只读、无需 ADMIN_PASSWORD,并开放跨域 GET 请求。

以下示例使用:

https://your-dashboard.example.com

替换为实际部署域名即可。HTTP 成交量金额单位为 USD,时间使用 UTC ISO 8601;建池事件的 Unix 秒/毫秒字段见第 4 节,仓位原始数量与时间字段见第 5 节。

1. 获取当前监控的池子

GET /api/public/pools?dex={dex}&excludeMeme={boolean}
参数必填默认值说明
dex否raydium池子来源:raydium、orca、meteora
excludeMeme否true是否排除 Meme 池;对 dex=raydium 和 dex=orca 生效。支持 true/false(也兼容 1/0)
  • raydium(默认,与不传 dex 行为一致):返回 Raydium RWA 池目录与手工添加池合并后的当前监控目录。默认 excludeMeme=true,只保留包含 USDC 的池,以及 xStocks/Backpack 股票代币与 USDC、USDG、SOL 或 WSOL 的池;传 excludeMeme=false 可返回全部监控池。manuallyAdded 表示该池是否在 /ops/pool-registry 中手工登记;手工池同样遵循 Meme 过滤参数。
  • orca:返回 Orca RWA 榜单,与交易量监控使用同一个 categories=security TOP 50 接口,按 24h 手续费降序;默认只保留 xStocks / Backpack Securities 与 USDC、USDG、SOL 或 WSOL 组成的池,传 excludeMeme=false 可返回该接口的完整结果。
  • meteora:返回 Meteora RWA 榜单,与 /meteora 菜单页同源,24h 统计窗口、按手续费降序 TOP 50。

excludeMeme 不过滤 Meteora,该 DEX 的榜单始终保持原有返回口径。

curl 'https://your-dashboard.example.com/api/public/pools'
curl 'https://your-dashboard.example.com/api/public/pools?dex=raydium&excludeMeme=false'
curl 'https://your-dashboard.example.com/api/public/pools?dex=orca'

响应示例(dex=raydium):

{
  "data": [
    {
      "id": "POOL_ADDRESS",
      "dex": "raydium",
      "pair": "TOKEN/USDC",
      "baseToken": {
        "symbol": "TOKEN",
        "mint": "BASE_MINT_ADDRESS",
        "decimals": 6,
        "logoURI": "https://example.com/token-logo.png"
      },
      "quoteToken": {
        "symbol": "USDC",
        "mint": "QUOTE_MINT_ADDRESS",
        "decimals": 6,
        "logoURI": "https://example.com/usdc-logo.png"
      },
      "feeRate": 0.0025,
      "feeBps": 25,
      "tvlUsd": 1250000.5,
      "volume24hUsd": null,
      "fees24hUsd": null,
      "manuallyAdded": true,
      "addedAt": "2026-07-15T02:30:00.000Z"
    }
  ],
  "meta": {
    "count": 1,
    "generatedAt": "2026-07-15T03:00:00.000Z"
  }
}

baseToken.logoURI 和 quoteToken.logoURI 来自对应 DEX 的 token metadata;元数据未提供图片地址时返回 null。

dex=orca / dex=meteora 时返回榜单条目,差异如下:

  • manuallyAdded 固定为 false,addedAt 固定为 null。
  • decimals 来自上游 token metadata;上游未提供时为 null。
  • volume24hUsd 和 fees24hUsd 为 24h 窗口的交易量与手续费(USD);dex=raydium 时这两个字段固定为 null。
  • 排序保持上游榜单顺序(24h 手续费降序)。
  • 上游不可用时返回 502。
{
  "data": [
    {
      "id": "POOL_ADDRESS",
      "dex": "orca",
      "pair": "SOL/USDC",
      "baseToken": { "symbol": "SOL", "mint": "BASE_MINT_ADDRESS", "decimals": 9, "logoURI": "https://example.com/sol-logo.png" },
      "quoteToken": { "symbol": "USDC", "mint": "QUOTE_MINT_ADDRESS", "decimals": 6, "logoURI": "https://example.com/usdc-logo.png" },
      "feeRate": 0.0004,
      "feeBps": 4,
      "tvlUsd": 52300000.12,
      "volume24hUsd": 18200000.45,
      "fees24hUsd": 72800.18,
      "manuallyAdded": false,
      "addedAt": null
    }
  ],
  "meta": {
    "count": 1,
    "generatedAt": "2026-07-15T03:00:00.000Z"
  }
}

2. 一次查询全部池成交量

GET /api/public/pools/volume?dex={dex}&interval={interval}&limit={limit}&excludeMeme={boolean}

一次返回当前全部 Raydium 或 Orca 监控池的成交量和手续费时间序列。参数与单池接口一致:

参数必填默认值说明
dex否raydium成交量来源:raydium 或 orca;meteora 暂无链上成交量监控
interval否1h聚合时间段:1m、5m、1h、24h
limit否24每个池返回最近多少个 interval,正整数
excludeMeme否true是否排除 Meme 池;dex=orca 时只保留 xStocks / Backpack Securities 与 USDC、USDG、SOL 或 WSOL 组成的池
curl 'https://your-dashboard.example.com/api/public/pools/volume?interval=1h&limit=24'
curl 'https://your-dashboard.example.com/api/public/pools/volume?dex=orca&interval=1m&limit=60'
curl 'https://your-dashboard.example.com/api/public/pools/volume?interval=5m&limit=12&excludeMeme=false'

响应中的顶层 totals 是全部返回池在查询窗口内的合计;每个池也有自己的 totals 和固定 limit 个时间桶。data 按窗口交易量从高到低排列,交易量相同时按交易对名称排列。

{
  "query": {
    "dex": "raydium",
    "interval": "1h",
    "limit": 24,
    "excludeMeme": true,
    "windowStart": "2026-07-14T04:00:00.000Z",
    "windowEnd": "2026-07-15T03:03:20.000Z"
  },
  "totals": {
    "volumeUsd": 128300.5,
    "feesUsd": 320.75,
    "buyVolumeUsd": 71400.25,
    "sellVolumeUsd": 56900.25,
    "trades": 241,
    "pools": 18
  },
  "data": [
    {
      "pool": {
        "id": "POOL_ADDRESS",
        "dex": "raydium",
        "pair": "TOKEN/USDC",
        "baseToken": { "symbol": "TOKEN", "mint": "BASE_MINT_ADDRESS", "decimals": 6, "logoURI": null },
        "quoteToken": { "symbol": "USDC", "mint": "QUOTE_MINT_ADDRESS", "decimals": 6, "logoURI": null },
        "feeRate": 0.0025,
        "feeBps": 25,
        "tvlUsd": 1250000.5,
        "volume24hUsd": null,
        "fees24hUsd": null,
        "manuallyAdded": false,
        "addedAt": null
      },
      "totals": {
        "volumeUsd": 42150.75,
        "feesUsd": 105.38,
        "buyVolumeUsd": 23700.25,
        "sellVolumeUsd": 18450.5,
        "trades": 86
      },
      "data": [
        {
          "startTime": "2026-07-14T04:00:00.000Z",
          "endTime": "2026-07-14T05:00:00.000Z",
          "complete": true,
          "volumeUsd": 3120.5,
          "feesUsd": 7.8,
          "buyVolumeUsd": 1870.25,
          "sellVolumeUsd": 1250.25,
          "trades": 7
        }
      ]
    }
  ]
}

该接口只返回本服务捕获并持久化的链上成交,不代理上游榜单统计。dex=orca 使用当前 Orca RWA TOP 50 监控目录;dex=meteora 返回 400。即使某个当前监控池在窗口内没有成交,也会返回该池,并以零填充所有时间桶。数据库聚合在一次查询中完成,不会按池逐个查询。

3. 按池 ID 查询成交量

GET /api/public/pools/{poolId}/volume?dex={dex}&interval={interval}&limit={limit}&excludeMeme={boolean}

查询当前监控池的成交量时间序列。

参数必填默认值说明
poolId是-Solana 池地址,且必须位于当前监控目录
dex否raydium池来源:raydium 或 orca
interval否1h聚合时间段:1m、5m、1h、24h
limit否24返回最近多少个 interval,正整数
excludeMeme否true是否排除 Meme 池;dex=orca 时只保留发行方可识别的证券池

例如,以 5 分钟为一段,查询最近 12 段(约 1 小时):

curl 'https://your-dashboard.example.com/api/public/pools/POOL_ADDRESS/volume?interval=5m&limit=12'
curl 'https://your-dashboard.example.com/api/public/pools/ORCA_POOL_ADDRESS/volume?dex=orca&interval=1m&limit=60'
curl 'https://your-dashboard.example.com/api/public/pools/MEME_POOL_ADDRESS/volume?interval=5m&limit=12&excludeMeme=false'

响应示例:

{
  "pool": {
    "id": "POOL_ADDRESS",
    "dex": "raydium",
    "pair": "TOKEN/USDC",
    "baseToken": { "symbol": "TOKEN", "mint": "BASE_MINT_ADDRESS", "decimals": 6, "logoURI": "https://example.com/token-logo.png" },
    "quoteToken": { "symbol": "USDC", "mint": "QUOTE_MINT_ADDRESS", "decimals": 6, "logoURI": "https://example.com/usdc-logo.png" },
    "feeRate": 0.0025,
    "feeBps": 25,
    "tvlUsd": 1250000.5,
    "volume24hUsd": null,
    "fees24hUsd": null,
    "manuallyAdded": true,
    "addedAt": "2026-07-15T02:30:00.000Z"
  },
  "query": {
    "dex": "raydium",
    "interval": "5m",
    "limit": 12,
    "excludeMeme": true,
    "windowStart": "2026-07-15T02:05:00.000Z",
    "windowEnd": "2026-07-15T03:03:20.000Z"
  },
  "totals": {
    "volumeUsd": 42150.75,
    "feesUsd": 105.38,
    "buyVolumeUsd": 23700.25,
    "sellVolumeUsd": 18450.5,
    "trades": 86
  },
  "data": [
    {
      "startTime": "2026-07-15T02:05:00.000Z",
      "endTime": "2026-07-15T02:10:00.000Z",
      "complete": true,
      "volumeUsd": 3120.5,
      "feesUsd": 7.8,
      "buyVolumeUsd": 1870.25,
      "sellVolumeUsd": 1250.25,
      "trades": 7
    }
  ]
}

时间和数据口径

  • 时间段按 UTC 自然边界对齐。例如 5m 使用 10:00–10:05、10:05–10:10;24h 使用 UTC 自然日。
  • 返回数组固定包含 limit 个时间段,无成交的时间段补零。
  • 最后一段通常仍在进行,此时 complete 为 false。query.windowEnd 是服务器实际查询时间。
  • volumeUsd 来自监控服务捕获的 Swap,以 1 分钟蜡烛聚合;加池和撤池不计入成交量。
  • feesUsd 是新捕获成交的链上实际手续费。Orca 使用 Traded 事件的 lp_fee + protocol_fee,动态费率池也可按实际值统计;历史 Raydium 蜡烛未回填实际手续费时可能为 0。
  • dex=raydium 默认不返回被 Meme 规则排除的池,显式传 excludeMeme=false 后可查询;dex=orca 默认只返回 xStocks / Backpack Securities 证券池,传 excludeMeme=false 后可查询其他当前监控池。
  • dex=orca 从服务启动后开始累积本地成交,不扫描上线前历史;退榜池返回 404。
  • 服务默认保留 90 天蜡烛数据,可通过 CANDLE_RETENTION_DAYS 修改。单次最多返回 1000 段,并且不能超过当前保留期;超出时返回 400。

错误响应

{
  "error": {
    "message": "interval must be one of: 1m, 5m, 1h, 24h",
    "parameter": "interval"
  }
}
HTTP 状态码含义
400池地址或查询参数无效
404池不在当前监控目录,或被默认 Meme 过滤规则排除(可传 excludeMeme=false 查询)
500服务内部错误
502dex=orca / dex=meteora 上游数据服务不可用

OpenAPI 3.1 机器可读定义见 docs/openapi.yaml。

4. WebSocket:订阅 Raydium CLMM 新建池

wss://your-dashboard.example.com/api/public/pool-creations/ws
wss://your-dashboard.example.com/api/public/pool-creations/ws?after=0

这是标准 WebSocket(RFC 6455),不是 SSE 或 Solana logsSubscribe。与其他公共 API 一样,只读、无需鉴权,可从浏览器跨域连接。不要传 ADMIN_PASSWORD,此接口不需要签名密钥。

  • 只发布本项目捕获的成功 Raydium CLMM 建池事件,不包含 CPMM、Orca、Meteora 或失败交易。
  • 新池发现独立于 RWA / 手工池目录,包含普通代币新池;本接口不提供 excludeMeme 或 dex 参数。
  • 发送时过滤已拉黑的池及已知黑名单创建者。已发送的事件不会因之后拉黑而撤回;创建者未知时为 null。
  • 复用现有链上订阅及 SQLite 事件,不为每个客户端增加 RPC 或链上 WebSocket。元数据在服务端统一补充;失败最多尝试 3 次后发布可用字段,名称、创建者等可能为 null。
  • 事件正式发布后分配持久化游标,后续不再更新同一事件的 payload。元数据补充较慢的池可能晚于其他池发布,因此游标顺序不等同于 slot 或建池时间顺序。
  • 建池事件仅通过 WebSocket 分享。byreal-copy 使用已有 RAYDIUM_DASHBOARD_API_BASE 自动订阅此接口,首次 after=0,后续按持久化游标续传。

连接参数与补发

参数必填默认说明
after否连接时的最新游标十进制非负整数,以字符串保存,最大 9007199254740991。从该游标之后开始补发,再持续推送新事件

不传 after 只接收之后发布的事件;after=0 从数据库保存的第一条可见事件开始补发。每个连接每秒最多扫描 100 条记录,积压会逐批追上。没有订阅指令,握手成功即开始推送;不要发送 JSON subscribe 消息。

游标与本实例的 SQLite 数据库绑定,重启后仍有效。持久化卷丢失、还原旧备份或改连另一份数据库时,应重新确定起点。游标大于数据库当前最大值会在握手阶段返回 409,不会静默忽略。

服务端目前不按时间清理建池 feed。黑名单会使游标出现跳号。客户端应在成功处理事件后保存游标,并按 data.eventId 幂等入库;重连补发可能重复已接收但未提交游标的事件。此机制只能重放已经捕获并持久化的事件,不能补齐链上 WS 断线期间从未收到的新池。

服务端消息

1. ready: 握手后的第一条消息。

{"type":"ready","version":1,"cursor":"120","latestCursor":"150","heartbeatSeconds":25}

cursor 是本次读取起点,latestCursor 是握手时的最新位置。请求 after=120 时仍需处理 121~150,不能直接保存 latestCursor 跳过补发。不传 after 时两者相同,可保存 cursor 作为初始重连起点。

2. pool.created: WebSocket 外层消息包裹 v1 建池事件。

{
  "type": "pool.created",
  "cursor": "121",
  "data": {
    "version": 1,
    "type": "raydium.pool.created",
    "eventId": "SIGNATURE:pool:POOL_ADDRESS",
    "signature": "SIGNATURE",
    "slot": 350000000,
    "blockTime": null,
    "detectedAt": 1789084800000,
    "programId": "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK",
    "poolType": "clmm",
    "poolAddress": "POOL_ADDRESS",
    "creator": null,
    "ammConfig": null,
    "sqrtPriceX64": "18446744073709551616",
    "tick": 0,
    "tickSpacing": 60,
    "vaultA": "VAULT_A",
    "vaultB": "VAULT_B",
    "tokenA": {"mint":"MINT_A","symbol":"AAPLx","name":"Apple xStock","icon":null,"decimals":6},
    "tokenB": {"mint":"MINT_B","symbol":"USDC","name":"USD Coin","icon":null,"decimals":6}
  }
}
字段类型 / 含义
外层 cursor持久化发布序号,十进制字符串,不是 slot
version / type固定为 1 / raydium.pool.created
eventId${signature}:pool:${poolAddress};一笔交易多个池有不同 ID
signature / slot交易签名与确认时所在 slot;commitment 为 confirmed
blockTimeUnix 秒或 null;实时日志没有精确区块时间,通常为 null
detectedAt本项目发现事件的 Unix 毫秒,不是池开盘时间
programId / poolTypeRaydium CLMM 程序地址 / clmm
poolAddress新池地址
creator / ammConfig从池账户补充的创建者 / 配置地址;不可用时为 null
sqrtPriceX64创建时链上 Q64.64 平方根价格,u128 十进制字符串;不得转换为 JS Number 后再持久化
tick / tickSpacing初始 tick / 池 tick 间距
vaultA / vaultB两侧 token vault 地址
tokenA / tokenB保持链上 token0 / token1 顺序;含 mint、symbol、name、icon、decimals,除 mint 外均可为 null

该事件不包含初始加池金额、TVL 或实际开仓:CLMM 创建池与添加流动性是不同操作。价格参数保持链上原始口径,未应用 Token-2022 ScaledUiAmount 倍率。

3. checkpoint: 一批扫描完成,可在前面的事件都处理成功后保存此游标。它也会跨过被黑名单隐藏的记录。

{"type":"checkpoint","cursor":"150"}

JavaScript 重连示例

let cursor = localStorage.getItem('raydium-pool-cursor');
let retryMs = 1000;

function connect() {
  const url = new URL('wss://your-dashboard.example.com/api/public/pool-creations/ws');
  if (cursor !== null) url.searchParams.set('after', cursor);
  const ws = new WebSocket(url);
  ws.onopen = () => { retryMs = 1000; };
  ws.onmessage = ({ data }) => {
    const message = JSON.parse(data);
    if (message.type === 'pool.created') {
      // 示例同步处理;生产消费者按 eventId 幂等提交后才推进游标。
      console.log(message.data);
    }
    if (['ready', 'pool.created', 'checkpoint'].includes(message.type)) {
      cursor = message.cursor; // ready 用 cursor,不能用 latestCursor
      localStorage.setItem('raydium-pool-cursor', cursor);
    }
  };
  ws.onclose = () => {
    const wait = retryMs + Math.random() * 500;
    retryMs = Math.min(retryMs * 2, 30000);
    setTimeout(connect, wait);
  };
}
connect();

如果处理是异步的,须按收到的顺序串行完成事件和 checkpoint,不能让后续 checkpoint 先提交。数据库被重置导致 409 时,人工选择清除本地游标(从实时开始)或改用 after=0(全部重放),不要无限重试旧游标。Node 客户端可使用 ws 包,浏览器使用内置 WebSocket。

心跳、错误与部署

  • 每 25 秒发送 WebSocket 协议 ping;浏览器和 ws 默认自动 pong,无须发送 JSON 心跳。下一次检查仍未 pong 时终止连接。
  • 默认每个进程最多 200 个连接,可通过 POOL_CREATION_WS_MAX_CONNECTIONS 调整;超过上限返回 503。
  • 握手 400:非法、重复或不支持的参数;409:游标超前;503:存储尚未准备好、mock 模式或连接已满。普通 HTTP GET 返回 426 Upgrade Required。
  • 连接后关闭码 1008:发送了应用消息或数据库回退导致游标失效;1011:存储不可用。慢客户端发送缓冲超过 1 MiB 时终止连接,客户端通常看到 1006,应从最后成功处理的游标重连。
  • 启动必须使用 pnpm start(node server.mjs),开发使用 pnpm dev。直接运行 next start 不提供此 WebSocket。Dockerfile 已同步复制入口及 transport,监听与网页相同的 3000 端口。
  • EasyPanel / Nginx 必须转发 Upgrade 和 Connection;公网用 HTTPS / WSS。代理空闲超时建议大于 60 秒。多个实例必须各自使用一致的事件存储和游标范围;不要把本地 SQLite 游标用于另一份独立数据库。

Nginx 示例(按实际 upstream 调整):

location /api/public/pool-creations/ws {
    proxy_pass http://dashboard:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 75s;
}

部署方式参考 Next.js Custom Server,协议处理使用 ws。OpenAPI 文件描述握手及 x-websocket 消息协议;普通 OpenAPI HTTP 客户端生成器不会自动生成 WebSocket 订阅代码。

5. WebSocket:按创建者地址订阅新建仓位与关仓

wss://your-dashboard.example.com/api/public/position-openings/ws?creator=CREATOR_ADDRESS
wss://your-dashboard.example.com/api/public/position-openings/ws?creator=CREATOR_ADDRESS&dex=orca&after=120
wss://your-dashboard.example.com/api/public/position-openings/ws?creator=ADDRESS_A&creator=ADDRESS_B&dex=all

标准只读 WebSocket,无需密码;连接后自动订阅,不发送 subscribe 消息。支持 Raydium CLMM / Orca Whirlpool,范围为本服务已有监控池(Raydium RWA/手工池目录、Orca RWA TOP 50),不是该钱包的全链交易监听。增加客户端不会增加链上 RPC 或链上订阅。

参数必填默认说明
creator是—开仓时仓位持有人的 Solana 地址,不是出资人或手续费支付人。可重复传入 1–100 个参数,如 creator=A&creator=B;每个值必须是一个有效完整地址,不接受逗号分隔。重复地址去重,只推送一次;数量限制按去重前参数个数计算
dex否allall、raydium 或 orca
after否连接时最新发布游标非负十进制整数字符串,最大 9007199254740991;从此游标之后续传。0 补发仍保留的历史事件

一个连接合并所有订阅地址的开仓、加仓、减仓与关仓事件,按全局发布游标升序推送,data.creator 标明事件所属地址。dex 统一作用于整组地址。只有一条 after / checkpoint 游标,无需为组内各地址分别续传;单地址 URL 保持兼容。

发布条件: 已捕获创建事件、已首次注入非零代币数量、已知创建者,并且保存了原始 tick/金额。Raydium 直接使用开仓日志;Orca 等开仓交易中的持有人补齐后再发布,空仓创建和首次入金可以是两笔交易。后续加仓发布为 position.increased,不重复发布新开仓。创建者补齐失败、旧版记录缺少原始参数时不发布,不能从展示价格猜测 tick。

事件先与仓位一起持久化,再分配独立发布游标;同一开仓事件只发布一次。延迟补齐的 Orca 创建者获得新的发布游标,因此不会被已经推进的订阅游标漏掉。按当前池/创建者黑名单过滤。

消息与跟单参数

第一条消息:

{"type":"ready","version":1,"creator":"CREATOR_ADDRESS","creators":["CREATOR_ADDRESS"],"dex":"all","scope":"monitored-pools","retentionDays":10,"cursor":"120","latestCursor":"125","heartbeatSeconds":25}

ready.creators 总是返回按字典序排序、去重后的完整地址数组;ready.creator 为兼容旧客户端保留,只有一个地址时为该地址,多地址时为 null。事件中的 data.creator 始终是该事件的单个原始持有人地址。

多地址 ready 示例:

{"type":"ready","version":1,"creator":null,"creators":["ADDRESS_A","ADDRESS_B"],"dex":"all","scope":"monitored-pools","retentionDays":10,"cursor":"120","latestCursor":"125","heartbeatSeconds":25}

cursor 是本次续传起点;不要把 latestCursor 保存为已处理游标。after=0 时 cursor 可能是已经清理的历史边界。

新开仓消息(以下地址为占位示例):

{
  "type": "position.opened",
  "cursor": "121",
  "data": {
    "version": 1,
    "type": "position.opened",
    "eventId": "orca:OPEN_SIGNATURE:open:0",
    "dex": "orca",
    "programId": "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
    "poolAddress": "POOL_ADDRESS",
    "creator": "CREATOR_ADDRESS",
    "signature": "OPEN_SIGNATURE",
    "eventIndex": 0,
    "slot": 454600000,
    "openedAt": 1791504000000,
    "fundingSignature": "FUNDING_SIGNATURE",
    "fundingSlot": 454600001,
    "fundedAt": 1791504000400,
    "publishedAt": 1791504002000,
    "commitment": "confirmed",
    "positionAddress": "POSITION_PDA",
    "nftMint": "POSITION_NFT_MINT",
    "tickLower": -120,
    "tickUpper": 240,
    "tickSpacing": 60,
    "tokenA": {"mint":"MINT_A","symbol":"TOKEN","decimals":6,"amountRaw":"1000000"},
    "tokenB": {"mint":"MINT_B","symbol":"USDC","decimals":6,"amountRaw":"100000000"},
    "amountUsd": 200,
    "display": {"baseMint":"MINT_A","quoteMint":"MINT_B","priceLower":0.9880723,"priceUpper":1.0242891}
  }
}
字段用途与口径
eventId${dex}:${signature}:open:${eventIndex},幂等键;同一交易多个仓位分别发布
dex / programId / poolAddress选择 DEX SDK、程序和目标池
creator原始开仓持有人;Orca 组合仓位从该交易的组合 NFT token balance 识别,不把代理权限地址当成持有人
tickLower / tickUpper链上原始整数 tick,保持 token A/B 方向;展示交易对反转也不改变这两个值,不从价格反推
tickSpacingOrca 池目录中的 tick 间距;Raydium 当前未保存该元数据,返回 null,消费者可随池状态读取
tokenA / tokenB链上 token0/token1 或 Whirlpool A/B 顺序,含 mint、symbol、decimals、首次注入的原始数量 amountRaw
amountRawu64 最小单位十进制字符串,应使用 BigInt/BN;没有 ScaledUiAmount 展示倍率,也不是已含滑点的 maximum amount。转账费按对应 DEX/Token-2022 规则处理
amountUsd初次入金数量乘当时缓存价格的 USD 估值;缺少价格可能为 0,不是下单预算或保证成交金额
display仅供显示的 base/quote 价格区间,可能反向且已应用 ScaledUiAmount;不要用于还原链上 tick
signature / slot创建仓位交易;eventIndex 为该 DEX 解码事件中的序号,不是 instruction index
fundingSignature / fundingSlot首次入金交易;Raydium 与开仓一致,Orca 可能不同
openedAt / fundedAtUnix 毫秒;实时路径使用本服务收到日志的时间,补漏路径使用区块时间,并非精确成交时间
publishedAt本服务正式发布的 Unix 毫秒,可能晚于开仓/首次入金
positionAddress / nftMint原始仓位身份,Raydium 日志缺失时为 null;跟单者创建自己的仓位/NFT,不复用原仓位身份
commitmentconfirmed;事件不是 finalized 通知,也不发送链回滚撤销事件

消费者可以按原始数量或自定比例/预算跟单,使用返回的目标池与原始 tick 区间。执行前仍需通过对应 DEX SDK 读取当前池状态,计算当前所需数量、滑点上限、账户与 Token-2022 转账费;接口提供开仓信号和原始条件,不返回已签名交易,也不代替消费者下单。

加仓与减仓消息

同一订阅连接新增两种消息:position.increased(后续增加流动性)和 position.decreased(减少流动性)。订阅地址、DEX 过滤、单一游标、幂等与十天回放规则不变。旧客户端需要处理这两种类型后再提交后续 checkpoint。

  • 第一次入金记为 position.opened;Orca 的空仓创建后第一次入金不重复算加仓,同笔交易之后再次增加流动性才算加仓。
  • 只有流动性变化量大于零才发布;纯领取手续费/奖励不是减仓。减到零但账户尚未关闭仍只是减仓,后续账户关闭单独发布 position.closed。同笔交易内同一仓位先减仓再关仓,只发布一次 position.closed,不再发布该仓位的 position.decreased;同笔交易中其他未关闭仓位的减仓仍正常推送。识别到关仓日志时,减仓会等待现有关仓交易查询确认对应 PDA,复用查询结果,不为此新增 RPC。
  • creator 始终是原始开仓持有人,不是本次操作签名者;NFT 转手后仍按原持有人订阅。openingEventId 用于关联自己的跟单仓位,不能仅按地址/池匹配。
  • 仅覆盖已有监控池内、能关联到仍保留开仓快照且已知创建者/原始参数的仓位;不会扫描全链或补造上线前缺失的开仓。未知创建者的 Orca 变动先持久化,待身份补齐后发布。
  • 事件来自成功程序调用;失败交易和被上层回滚的 CPI 不发布。同笔交易多次变动各有不同 ID,WS 与补漏重放去重。金额保持事件原始整数,不改变开仓快照为“当前余额”,LP 变动也不计入 Swap 成交量。
{
  "type": "position.decreased",
  "cursor": "123",
  "data": {
    "version": 1,
    "type": "position.decreased",
    "eventId": "orca:CHANGE_SIGNATURE:liquidity:0",
    "dex": "orca",
    "programId": "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
    "poolAddress": "POOL_ADDRESS",
    "creator": "CREATOR_ADDRESS",
    "positionAddress": "POSITION_PDA",
    "nftMint": "POSITION_NFT_MINT",
    "openingEventId": "orca:OPEN_SIGNATURE:open:0",
    "openingSignature": "OPEN_SIGNATURE",
    "signature": "CHANGE_SIGNATURE",
    "eventIndex": 0,
    "slot": 454600100,
    "occurredAt": 1791504100000,
    "publishedAt": 1791504101000,
    "commitment": "confirmed",
    "liquidityDelta": "12345678901234567890",
    "tickLower": -120,
    "tickUpper": 240,
    "tickSpacing": 60,
    "tokenA": {"mint":"MINT_A","symbol":"TOKEN","decimals":6,"amountRaw":"500000","feeAmountRaw":"0","transferFeeRaw":"0"},
    "tokenB": {"mint":"MINT_B","symbol":"USDC","decimals":6,"amountRaw":"50000000","feeAmountRaw":"0","transferFeeRaw":"0"}
  }
}

加仓消息字段相同,内外层 type 均为 position.increased。

字段含义
eventId${dex}:${signature}:liquidity:${eventIndex},按事件幂等;不是开仓事件 ID
eventIndex当前 DEX 交易日志中加/减流动性事件的序号,从 0 开始;Orca 的首次入金也占序号,但不作为加仓发布。不同于开仓序号与 instruction index
liquidityDeltau128 十进制字符串,非零、无符号的流动性变动绝对值;方向由消息类型决定。不是剩余流动性或增减仓比例,不能据此推断“已全部减仓”
tokenA/B.amountRaw链上事件的本次流动性对应原始代币数量,u64 字符串。Raydium 减仓的独立手续费字段不并入该数量;不是滑点上限或保证净到账量
tokenA/B.feeAmountRawRaydium 减仓事件单独报告的已领取手续费;其他事件为 "0"。不包含奖励;Orca 独立领取手续费/奖励指令不在此事件内
tokenA/B.transferFeeRaw事件报告的 Token-2022 转账费,旧版 Raydium 日志没有该字段时为 null。Raydium 减仓转账费可能对应本金与手续费合并转出,不能直接当作本金净额扣除
tickLower/Upper原始链上 token A/B 方向;Orca 使用本次事件的 tick,Raydium 使用关联开仓快照的 tick
occurredAtUnix 毫秒;实时接收时间或补漏交易区块时间
slot变动事件所在 slot(实时日志 context 或完整交易 slot)
openingEventId / openingSignature原开仓事件 ID 与签名;用于精确关联

跟单程序应读取当前目标仓位/池状态,自行计算加减仓比例、数量、滑点和转账费。liquidityDelta、原始数量不能当成当前仓位余额;不要重复使用 openedAt/开仓金额表示本次变动。本消息不提供保证成交报价或盈亏。

Orca 复用现有日志及已保存仓位;Raydium 变动日志只有 NFT 标识,未建立关联时会异步查询已识别的变动交易,先过滤监控池,再沿该 PDA 历史精确关联仍保留的开仓。关联和非监控池结果会缓存;重试最多 8 次,新增订阅客户端不增加 RPC。监控范围仍为现有池和十天仓位保留期。

事件字段依据 Raydium 仓位事件定义 与 Orca 事件定义。

关仓消息

同一连接推送 position.opened、position.increased、position.decreased 和 position.closed,使用同一条发布游标;接口路径与 creator / dex / after 参数不变。订阅程序通过 openingEventId 查找自己记录的跟单仓位映射。

{
  "type": "position.closed",
  "cursor": "122",
  "data": {
    "version": 1,
    "type": "position.closed",
    "eventId": "orca:CLOSE_SIGNATURE:close:POSITION_PDA",
    "dex": "orca",
    "programId": "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc",
    "poolAddress": "POOL_ADDRESS",
    "creator": "CREATOR_ADDRESS",
    "signature": "CLOSE_SIGNATURE",
    "slot": 454601000,
    "closedAt": 1791504400000,
    "publishedAt": 1791504401500,
    "commitment": "confirmed",
    "positionAddress": "POSITION_PDA",
    "nftMint": "POSITION_NFT_MINT",
    "openingEventId": "orca:OPEN_SIGNATURE:open:0",
    "openingSignature": "OPEN_SIGNATURE"
  }
}
  • eventId 为 ${dex}:${关闭交易签名}:close:${仓位PDA},重试和断线重放按此幂等;同一交易关闭多个仓位分别发布。
  • openingEventId 与开仓消息的 eventId 一致;openingSignature 是原开仓签名。旧版仅有 PDA 的快照无法还原开仓 ID 时,这两个字段为 null,可使用 positionAddress 匹配。不要只按创建者/池地址关掉所有跟单仓位。
  • creator 保持原始开仓持有人,因此 NFT 后来转手、由其他地址关闭时,原订阅仍按同一地址接收;该字段不是关仓签名者。
  • signature / slot 属于关仓交易;closedAt 为该交易区块时间的 Unix 毫秒,区块时间不可用时取本地处理时间。publishedAt 为发布时刻。
  • 只对成功的 Raydium ClosePosition、Orca ClosePosition / ClosePositionWithTokenExtensions / CloseBundledPosition 指令发布。部分撤流动性、把流动性降为零但未关闭账户、本地保留期清理都不属于关仓消息。
  • 复用现有关仓日志/补漏和持久化重试,不新增客户端专属 RPC。Raydium 通过原有 PDA 创建历史解析精确开仓 ID;Orca 按 PDA 和 slot 防止旧关仓误删后来复用的组合仓位。
  • 关仓发布与删除原仓位在同一个数据库事务中完成,发布失败会保留仓位待重试。必须能关联本服务仍保留的仓位快照(开仓快照保留十天)且已知原创建者;不扫描全链历史、不补发升级前已删除的仓位,也不凭空猜测未知创建者。
  • 关仓消息不返回撤回金额或盈亏;关闭账户指令本身不提供这些数量,不能把原开仓金额当成实际赎回金额。

续传、保留与示例程序

{"type":"checkpoint","cursor":"125"}

只在前序事件处理成功后持久化 checkpoint。服务按创建者索引读取,每连接每秒最多处理整组地址合计 100 条候选记录(不是每个地址 100 条);checkpoint 可直接跨过其他地址、DEX 或黑名单记录,不能用游标差判断漏单数量。

  • 发布记录保留十天(启动/每小时清理)。记录是历史开仓/关仓信号,关闭后保留原开仓消息并追加关仓消息;旧开仓消息不表示此刻仍持仓;消费者应检查事件新鲜度、需要时确认原仓位状态。
  • 不传 after 从实时开始;after=0 会重放历史,消费者必须按 eventId 幂等,避免重连重复跟单。API 上线前缺少原始参数的仓位不回填。
  • 游标与数据库及订阅条件绑定。游标必须绑定同一地址集合、dex 和部署实例;调整地址顺序或重复同一地址不改变订阅集合。增加、删除地址或更换 dex 时需重连,并使用新的游标文件/订阅状态:不传 after 从实时开始,或显式 after=0 重放仍保留的历史并按 eventId 去重。不能直接取多个旧单地址游标的最大值合并,否则会跳过其他地址尚未处理的事件。不支持连接内动态发送增删地址指令。
  • 400:地址无效、缺少地址、creator 参数超过 100 个、DEX/游标格式错误、重复 dex / after 或未知参数;409:游标超过当前数据库最大值;410:游标已超出保留期,需要调用者选择新起点;426:普通 HTTP GET;503:数据库未就绪、mock 模式或连接已满。
  • 连接后游标回退/过期或收到应用消息关闭码 1008;存储异常 1011;慢客户端缓冲超过 1 MiB 会被终止。每 25 秒协议 ping,未回复 pong 的连接被清理。
  • 默认最多 200 个开仓订阅连接,可通过 POSITION_OPENING_WS_MAX_CONNECTIONS 修改。使用既有 server.mjs / pnpm start,端口与网页相同;反向代理对该路径启用 WebSocket Upgrade,超时大于 60 秒。

仓库提供可运行示例 examples/subscribe-position-openings.mjs,串行处理事件、原子保存游标、断线退避重连,并区分订阅条件。示例只打印信号;将 handleOpening / handleLiquidityChange / handleClose 替换为按 eventId 幂等的持久化处理函数;先保存开仓事件到自有仓位的映射,关仓时按 openingEventId 查询该映射。

CURSOR_FILE=./my-wallet-orca-cursor.json node examples/subscribe-position-openings.mjs \
  https://your-dashboard.example.com CREATOR_ADDRESS orca

# 示例程序的命令行支持逗号分隔,内部会转换为重复 creator 参数
CURSOR_FILE=./my-wallets-cursor.json node examples/subscribe-position-openings.mjs \
  https://your-dashboard.example.com ADDRESS_A,ADDRESS_B all