跳到主要内容

构建狙击机器人

狙击机器人做四件事:看到发射、决策、买入、退出。本指南用大约一百行代码构建一个:发射流提供信号,Lightspeed 负责买入,交易流负责退出;然后展示只需改动一处,就能借助 Ultra Fast Stream(超快流) 把发射信号提前一个区块。

你需要什么​

  • Node.js 22 或更新版本(内置 WebSocket),npm install socket.io-client。
  • 一个已充值 SOL 的 Lightspeed 账户。它的密钥负责为买入签名。
  • 把机器人跑在 API 旁边,也就是法兰克福(见区域)。

脚本​

import { io } from "socket.io-client";

// ─── 改这些 ───────────────────────────────────────────
const LS_KEY = "ls_…"; // 你的 Lightspeed 账户密钥
const BUY_SOL = 0.05; // 每次发射买入的数量
const SLIPPAGE = 20; // 百分比;发射时价格变化很快
const TIP = 0.001; // 每份提供商副本的小费(SOL),只有落地的那份实际支付一次
const TAKE_PROFIT = 2.0; // 2 倍时卖出
const STOP_LOSS = 0.6; // ……或者 -40% 时
const MAX_HOLD_S = 120; // ……或者两分钟后
const MAX_OPEN = 3;
const MIN_DEV_BUY = 0.5; // 跳过创建者买入少于此数(SOL)的发射
const DRY_RUN = true;
// ──────────────────────────────────────────────────────

const API = "https://sol.shrine.trade";
const open = new Map(); // mint -> { entry, since, pool }

async function lightspeed(body) {
if (DRY_RUN) { console.log(" dry-run", body); return { success: true }; }
const r = await (await fetch(`${API}/api/lightspeed`, {
method: "POST", headers: { "content-type": "application/json", "x-api-key": LS_KEY }, body: JSON.stringify(body),
})).json();
if (!r.success) throw new Error(`${r.error}: ${r.message}`);
return r;
}

const socket = io(API, { transports: ["websocket"] });

socket.on("connect", () => {
socket.emit("subscribe_new_tokens", { protocols: ["PUMPFUN"] });
console.log("watching launches");
});

// 1. 一次发射。先筛选,再买入。
socket.on("new_token", async (t) => {
if (open.size >= MAX_OPEN || open.has(t.mint)) return;
const devBuy = t.initialBuy?.quoteAmount ?? 0;
if (devBuy < MIN_DEV_BUY) return; // 创建者没有给它背书
if (t.mintAuthority || t.freezeAuthority) return; // 还能增发或冻结:跳过
console.log(`launch ${t.symbol} ${t.mint} dev buy ${devBuy} SOL`);
try {
const r = await lightspeed({ action: "buy", mint: t.mint, amount: BUY_SOL, slippage: SLIPPAGE, tip: TIP });
open.set(t.mint, { entry: null, since: Date.now(), pool: t.pool });
socket.emit("subscribe_trades", { pool: t.pool }); // 2. 跟踪它的价格,用于退出
console.log(` bought ${t.symbol}: ${r.signature ?? "dry"}`);
} catch (e) {
console.error(` buy failed: ${e.message}`);
}
});

// 3. 根据实时交易退出:买入后看到的第一个价格就是入场价。
socket.on("trade", async (tr) => {
const pos = open.get(tr.mint);
if (!pos) return;
if (pos.entry === null) { pos.entry = tr.price; return; }
const x = tr.price / pos.entry;
const age = (Date.now() - pos.since) / 1000;
const why = x >= TAKE_PROFIT ? "take profit" : x <= STOP_LOSS ? "stop loss" : age >= MAX_HOLD_S ? "timer" : null;
if (!why) return;
open.delete(tr.mint);
socket.emit("unsubscribe_trades", { pool: pos.pool });
try {
await lightspeed({ action: "sell", mint: tr.mint, amount: "100%", slippage: SLIPPAGE, tip: TIP });
console.log(` sold ${tr.mint} (${why}, ${x.toFixed(2)}x)`);
} catch (e) {
console.error(` sell failed: ${e.message}`);
open.set(tr.mint, pos); // 保留仓位;下一笔交易时再试
}
});

先用 DRY_RUN = true 跑一遍;它会打印出每一个它本会买入的发射和每一次它本会执行的退出。

每个部分做什么​

  • 筛选是优势所在。发射事件带有创建者自己的买入(initialBuy)、权限和代币扩展、名称和 URI;创建者什么都没买,或者保留了增发权限,这样的发射就该跳过。再加上你自己的规则:名称的最小长度、URI 能够解析、你见过的创建者。
  • 买入只是一次请求。Lightspeed 从它自己缓存的每条曲线构建并签名,途中不读取任何链上数据,副本同时向每个落地提供商发起竞速;只有一份成交。tip 是在拥挤的 slot(槽位)里买到优先权的东西。
  • 退出来自池子的交易:买入后的第一个价格就是你的入场价,之后的每笔交易都拿来对照目标价、止损和时钟。一次卖出请求就关闭仓位,不管成交了多少,"100%" 都能卖光。

快速版本:Ultra Fast Stream​

上面的发射流是已执行的流:创建已经运行,并由节点提供出来。Ultra Fast Stream 在分片一到达、区块执行之前就送出同一个创建事件,而且已经带有 mint。只换掉发射来源,其他保持不变:

const uf = new WebSocket(`wss://sol.shrine.trade/api/ultrafast/stream?key=${UF_KEY}&creates=1`);
uf.onmessage = async (m) => {
const e = JSON.parse(m.data);
if (e.type !== "create") return;
// e.mint、e.symbol、e.name、e.creator、e.bondingCurve 在区块存在之前就已知。
// 开发者的买入随后作为一笔 createBuy: true 的交易出现在同一个 socket 上。
// ……同样的筛选,同样的 lightspeed({ action: "buy", mint: e.mint, ... }),和上面一样
};

这样买入会比 PumpPortal 上的机器人看到发射早 100 多毫秒发出,比同一区域里使用我们自己已执行流的机器人早 6 毫秒。退出仍然留在已执行流上,那里的价格才是真实的。

时间花在哪里​

步骤耗时
发射从 Ultra Fast Stream 到你在法兰克福的机器人约 1 毫秒
你的筛选取决于你
Lightspeed 构建与签名约 1 毫秒
第一个提供商确认10 到 20 毫秒
落地通常是下一个 slot

机器人在欧洲其他地方每个方向多 10 到 30 毫秒;在美国的应当使用纽约区域,而不是跨越大西洋。这就是第一个 slot 和第三个 slot 的差别。