Solana 跟单 API:检测、判断、上链

跟单在 Solana 上到底怎么做:检测目标钱包的 swap、判断值不值得跟、以及在价格跑掉之前把自己那笔送上链。

BoltTx Team··15 min read
solana跟单交易机器人交易上链websocketrpc

跟单听起来像个数据问题。盯着一个钱包,看它买什么,跟着买同一个。

实际上它是个披着数据外衣的延迟问题。等你检测到这笔交易、判断要跟、再把自己的交易送上链,价格已经动了 —— 而它动了多少,就是你的全部利润空间。

没有"跟单 API"这种东西

没有任何接口提供"这个钱包交易了就通知我"。你得自己拼三块:

检测。 盯住一组钱包的 swap 活动。 判断。 决定这一笔值不值得跟。 执行。 构造并送上链你自己的交易。

大多数教程把篇幅花在第一块。★而钱是在第三块流走的。★

如果检测那块已经跑通、只缺执行的一半,免费领个 BoltTx key 改一行就行。这篇剩下的是你得自己写的那些。

检测:三种做法

轮询签名

定时对每个钱包调 getSignaturesForAddress 拉最近签名,和上次比对差异。

async function pollWallet(connection: Connection, wallet: PublicKey, seen: Set<string>) {
  const sigs = await connection.getSignaturesForAddress(wallet, { limit: 10 });
  // ★getSignaturesForAddress 返回的是最新在前 —— 重放要按时间正序★
  const fresh = sigs.filter((s) => !seen.has(s.signature) && !s.err).reverse();
  fresh.forEach((s) => seen.add(s.signature));
  return fresh;
}

简单。但也是最慢的,而且扩展性很差 —— 50 个钱包每秒轮一次,就是每秒 50 个请求,这还没开始解析。

日志订阅

通过 WebSocket 订阅 —— 盯程序活动用 logsSubscribe,盯具体账户用 accountSubscribe —— 让事件推给你,而不是你去问。

const sub = connection.onLogs(
  wallet,
  (logs) => {
    if (logs.err) return; // 失败的交易,没什么可跟的
    handleActivity(logs.signature);
  },
  "processed", // 用 "confirmed" 会白白多花一个 slot 以上,追不回来
);

★用 processed,别用 confirmed。★ 等确认,等的就是你正在抢的那个东西。代价是你要承担"这笔交易可能被丢弃"的风险 —— 这个风险靠动手前先验证来处理,而不是靠等。

Geyser 类流式推送

专门的账户和交易更新流。最快,运维最重,通常要付费。

判断:到底该跟什么

检测给你一个签名。接下来你要知道发生了什么、以及要不要跟。

const tx = await connection.getParsedTransaction(signature, {
  maxSupportedTransactionVersion: 0,
});

// 读余额差比解析指令可靠,
// 因为它在所有 DEX 和路由器上表现一致。
const pre = tx.meta.preTokenBalances ?? [];
const post = tx.meta.postTokenBalances ?? [];

多花一点力气读余额差、而不是去解码指令,是值得的。★每个 DEX 和聚合器都有自己的指令布局,而且会变。余额差不会。★

几个比想象中更重要的过滤条件:

相对于该钱包的仓位大小。 一个交易者拿 0.5% 的仓位买入,和拿 20% 买入,表达的完全不是一回事。两种一视同仁地跟,等于你没读懂这个信号。

这是建仓还是加仓? 买入一个他已经持有的代币是在摊平成本;买入一个全新的是开新仓。含义不同,紧迫性也不同。

代币年龄和流动性。 一笔进入浅流动性池子的交易,你跟进去时价格会往不利方向走 —— 因为你自己这笔就占了池子深度的可观比例。

他之前是不是一直这么干? 一个每小时都在同一个代币上买进卖出的钱包,跑的是你没法靠"跟单笔交易"复制的策略。

执行:利润在这里决出胜负

下面这个算术决定了跟单机器人能不能成立。

你跟的那个交易者在某个价格买入。你在 N 个 slot 之后买入,而价格已经动了 —— 因为他那笔推动了价格,也因为所有跟他的人都在买。

★你的入场价按结构就一定比他差。★ 唯一的问题是差多少,而这是"你落后多少个 slot"的函数。

按 Solana 的出块节奏换算:

落后 slot 落后时间
2 不到一秒
5 约两秒
10 约四秒

对一个刚吃了一笔大买单的代币来说,四秒很长。

要缩短它,靠的还是老三样:priority fee 按实时行情算、重试到 blockhash 过期、以及一条拥堵时不会被降级的提交路径。

import { ComputeBudgetProgram } from "@solana/web3.js";

// 费用按账户竞争。要传你实际会写入的账户。
const recent = await connection.getRecentPrioritizationFees({
  lockedWritableAccounts: writableAccounts,
});
const fees = recent.map((r) => r.prioritizationFee).sort((a, b) => a - b);
const median = fees[Math.floor(fees.length / 2)] ?? 0;

instructions.unshift(
  ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: Math.max(median * 2, 5_000),
  }),
  ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
);

再加上持续重试到 blockhash 过期,以及一条在区块空间被抢时不会被降级的提交路径。

滑点陷阱

跟单有一个特有的失败模式,值得单独点名。

你检测到一笔买入,决定跟,滑点容忍度设了个看起来合理的 1%。但你跟的那笔已经把价格推高了 3%,其他跟单的人又推了 2%。你的交易因滑点失败。

于是你把容忍度放宽到 10%。现在成交了 —— 成交在一个比原钱包差 8% 的价格上,而他可能在 5% 利润时就出场了。

★两种结果都是亏。真正该修的不是容忍度,是 slot 数。★

如果你稳定落后五个以上 slot,任何滑点设置都救不了这个策略。容忍度是症状旋钮,延迟才是真正的变量。

上链应该是什么水平

我们投递节点上的真实交易:中位确认 336 毫秒 —— 不到一个 slot。

两个 slot 就是比你跟的那个钱包晚不到一秒 —— 而这还没算上你自己的检测和判断耗时。这就是你的预算。

怎么衡量有没有效果

盯差距,别盯成交率。一个每笔都以糟糕价格成交的机器人,在成交率看板上很健康,但在亏钱。

log({
  sourceWallet,
  sourceSlot,      // 他那笔落块的 slot
  ourSlot,         // 我们这笔落块的 slot
  slotGap: ourSlot - sourceSlot,
  sourcePrice,
  ourPrice,
  entryGapBps: Math.round(((ourPrice - sourcePrice) / sourcePrice) * 10_000),
});

slotGapentryGapBps 两个放一起,能说明全部问题。★ 如果 slot 差很小、入场差还是很大,说明你跟的这批交易对市场冲击太大、本来就不适合跟。如果 slot 差很大,那是个你能修的执行问题。

BoltTx 在这里的位置

我们做执行那一半。不做检测,不做钱包分析,不做索引。

提交走我们自建的四区域投递节点,带 SWQoS 路由,不暴露公共 mempool —— 交易在落块之前,传输途中观察不到。你在本地签名,我们不托管资金、不代签、不修改交易内容。

tip 带在交易里,从你自己的钱包链上支付。交易 revert 的话 tip 跟着一起 revert —— 这是 Solana 原子交易的机制决定的。只有到达链上的交易才计费。

免费领 API key,没有月费:

// 选离你机器人最近的区域
const connection = new Connection("https://la.bolttx.io/?api-key=YOUR_KEY");

接上之后记录一周的 slotGap,看它有没有变。

常见问题

Solana 有跟单 API 吗? 没有单一接口能做这件事。跟单是由三块拼起来的:盯钱包活动、解析他们交易了什么、以及提交你自己的交易。前两块是对任意 RPC 的读操作,第三块决定你的利润。

怎么实时追踪一个 Solana 钱包的交易? 用 WebSocket 在 processed 承诺级别订阅该钱包的日志。轮询 getSignaturesForAddress 也行,但更慢,而且钱包一多就扩展不动。

跟单要多快才成立? 快到价格还没跑过你的利润空间。落后两个 slot 是不到一秒;落后十个 slot 约四秒 —— 对一个刚吃了大买单的代币来说,通常已经太晚。

为什么我的跟单老是滑点失败? 因为你跟的那笔推动了价格,其他跟单的人也在推。放宽容忍度只会让你在更差的价格成交,而不是解决成因。如果你落后五个以上 slot,slot 数才是问题

怎么知道一个钱包买了什么代币? 从解析后的交易里读 preTokenBalancespostTokenBalances 算差值。这个做法在各个 DEX 和路由器上表现一致,而解码指令则因程序而异、还会变。

该跟一个钱包的每一笔交易吗? 不该。按仓位占比、是建仓还是加仓、以及代币流动性来过滤。把 0.5% 仓位和 20% 仓位同等对待地跟,等于忽略了你本来想读的那个信号。

检测该用哪个承诺级别? processed。等 confirmed 会花掉一个以上你追不回来的 slot。代价是你看到的东西里有一小部分可能被丢弃,而这靠"动手前先验证"来处理,不是靠等。

不自己写机器人能做 Solana 跟单吗? 有托管服务。代价是你继承了他们的延迟和过滤逻辑,而且看不到某笔交易为什么被跟或没被跟。

能同时盯多少个钱包? 用 WebSocket 订阅可以很多 —— 你是在接收推送,不是在发请求。用轮询很快就会撞限流,因为每个钱包每一轮都是一个独立请求。

为什么我成交的价格比被跟的钱包差很多? 你的入场价按结构就更差,因为他那笔在你到达之前就推动了价格。差多少是"落后几个 slot"的函数。把两个 slot 号和价差都记下来,才知道该修哪一段。

跟单适合新上线的代币吗? 那里最难。流动性浅意味着原始交易和你的交易都会显著推动价格,而两者之间的差距,恰好在代币最新的时候最大。

跟单和抢跑有什么区别? 跟单是在一笔交易已经上链之后跟进。抢跑是在交易被收录之前、基于对它的知情去行动。前者用的是公开信息,后者依赖在传输途中看到东西。

怎么避免跟到一个钱包的亏损交易? 事先无法知道。你能做的是按交易特征过滤 —— 仓位大小、是不是新仓、流动性 —— 并且按来源钱包分别统计自己的表现,而不是看总和。

跟单需要 WebSocket 吗? 做检测的话,比轮询快很多,而且钱包一多扩展性好得多。提交自己的交易不需要 —— 那是 HTTP 调用,而且往往走另一个端点。

为什么我的跟单交易都上链了,还是在亏? 去看入场差,别看成交率。一个每笔都比来源钱包差 8% 成交的机器人,在成交率看板上很健康,照样亏钱。

怎么挑要跟的钱包? 上线跟之前,先拿他们的历史做回测。一个在几百笔交易上有稳定实现收益的钱包,和一个靠几笔大赢冲上榜的钱包,是完全不同的东西 —— 而排行榜上后者要常见得多。

延伸阅读

返回博客列表