YouMind
登录

一夜之间从零搭建 Grok Bot:完整配置指南 + 可复制粘贴的 Rug 过滤脚本

@0xboan
英语2026年10月17日
126K
139
19
20
439

TL;DR

本指南详细介绍了如何从零开始搭建 Grok Bot 交易台,重点在于通过严格的 14 步 Rug 过滤流程在执行前剔除诈骗代币。它强调“代码执行、Grok 分析、人工确认”的工作流,并配备纸面交易作为安全保障。

大多数人是通过别人的 pnl 截图认识 Grok Bot 的,打开它,对准一张 K 线图,然后把第一个 50 刀亏给一个在他们买入前就已经死掉的代币。问题不在机器人身上。没人告诉过它“死掉”长什么样。

如果让我从头再来,今晚我还会搭这套系统。一个 bot,一个文件夹,十个小文件。它不找百倍币。它的主要工作是杀掉代币,而少数活下来的那些,在动用一美元之前,依然需要 Grok 去读 X。

步骤 01 到 07 是第一个晚上要做的事:bot、密钥、限制、退出。08 到 12 是 rug 过滤器,14 项检查,每一项都写成了代码。13 和 14 把它切到自动驾驶,先从纸上交易开始。

如果你读过我那篇关于八 Agent 交易台的帖子,这就是那个交易台踩着的地板。

https://x.com/0xboan/status/2092226208234647626

怎么用:打开你的 Grok Bot,把整篇文章粘贴进去,然后说“在 /workspace/desk 里搭建这个交易台,纸面模式,任何碰到钱包的操作前先问我。”它会自己在那台电脑上把所有文件写好。

你要记住的分工:代码负责杀,Grok 负责读 X,你负责签名。 交易台上没人替别人干活。

01. 开始前先准备四样东西

四样东西。每一样都会说明它是什么、你今晚要做什么、以及为什么交易台需要它。

1. Grok Bot

它是什么。一个你可以雇佣具名 bot 的应用。每个 bot 都在一台带浏览器、文件和终端的云端电脑上工作,就算你合上笔记本它也会继续跑。

你要做什么。去 x.ai/bot 下载,登录,选择 Create your own(创建你自己的)。

为什么。整个交易台都运行在那台电脑上。文件、例行任务、提醒,全在一个地方,手机也能打开。

2. 一个 xAI API 密钥

它是什么。通过代码付费调用 Grok 的权限,内置了 X 搜索。

你要做什么。去 console.x.ai,API Keys,创建一个。先别贴到任何地方,步骤 03 会告诉你放哪。

为什么。例行任务没法坐在聊天窗口里思考四十个代币。但一个每次只调一次接口的脚本可以,而且它会把每个回答按同样的格式记录下来。

3. Rugcheck 和 DexScreener

它们是什么。两个免费的公开 API。Rugcheck 读合约:权限、LP、持仓者、内部人士、开发者钱包。DexScreener 读池子:深度、年龄、买卖对比。

你要做什么。什么都不用做。不用注册,读取不需要密钥。

为什么。事实先于观点。mint 权限没关不是主观判断,而是事实,而事实最先杀人。

4. 一个一次性钱包,但不是今晚

它是什么。一个全新的、从没拿过其他东西的 Solana 钱包。

你要做什么。暂时什么都不做。第一周只做纸上交易。

为什么。交易台永远不保存私钥。等你上线实盘时,它会告诉你买什么,你自己签名。

02. 雇一个 bot,不是八个

我的交易台现在跑着八个 bot。但一开始不是这样,你的也不该是这样。第一天就上八个 bot,等于同时调试八样东西。一个 bot 干一件事,能让你看清另外七个以后需要什么。

选择 Create your own,然后一字不差地给它这段话:

text
1名称:RUG DESK
2工作:Solana memecoin 交易台,先做纸上交易
3描述:根据我粘贴的文章,在 /workspace/desk 中搭建并运行交易台。
4每个代币都必须经过 check.py,没有例外,没有捷径。
5你永远不要买入、卖出、签名或转移资金。除非我在这个对话里要求,否则你永远不要编辑 config.py。你永远不要为了放行某个代币而调低过滤器的数值。
6报告每一次击杀时都要带上原因,而不是你对这个代币的看法。
7当某个数据源挂了,说出是哪一个然后跳过。永远不要猜缺失的数字。

最后两行比前五行更重要。一个会猜缺失数字的 bot,迟早会猜出一个让你亏钱的数字。

boan - inline image

03. 别让密钥出现在聊天里

你发给 bot 的所有内容都会留在记录里。所以密钥要放进文件,由你在 bot 的电脑上输入。

打开 bot 的电脑,点击 Take over(接管),打开终端运行下面这段。它会询问密钥但不回显,所以历史记录里也不会出现:

bash
1mkdir -p /workspace/desk && cd /workspace/desk
2read -rs -p "xai key: " K && printf 'XAI_API_KEY=%s\n' "$K" > .env && unset K
3chmod 600 .env
4pip install requests

然后在做任何事之前先证明密钥能用。调一次接口,这样你以后就不会把坏密钥和烂提示词搞混:

bash
1curl -s https://api.x.ai/v1/responses \
2 -H "Authorization: Bearer $(cut -d= -f2 .env)" \
3 -H "Content-Type: application/json" \
4 -d '{"model":"grok-4.7","input":"reply with OK"}'
5
6-> ... "type":"output_text","text":"OK" ...

点击 I'm done(我完成了)把电脑交还回去。从现在起 bot 就能运行交易台了,而且它在聊天里依然看不到密钥。

boan - inline image

04. 动手之前先看完整条漏斗

八道关卡。免费的先跑。只有通过了免费关卡的才值得花一次 Grok 调用,只有 Grok 喊 BUY 的才花钱。这周连钱都不花。

text
10. LEAD 从任何地方拿到一个 CA:喊单、帖子、scan.py -> 一个 mint
21. LIMITS book.py:日亏损、开仓数、冷却期 -> 免费,完全不联网
32. FACTS rugcheck.py:10 项硬性击杀 -> mint 未关、LP 未锁、前十持仓过重,死在这里
43. POOL market.py:深度、年龄、卖盘 -> 薄池子和貔貅盘死在这里
54. JUDGE grok.py + X 搜索,一次调用 -> BUY 或 SKIP,一个理由,一个风险
65. FILL 纸面:book.py 按实时价格成交 -> 实盘:你自己签名
76. WATCH watch.py 每 10 分钟 -> 止损、分批止盈、追踪止损、时间止损
87. REPORT report.py 在 21:30 -> 谁死了,谁赚钱了,什么该质疑

mint 权限没关不是主观判断。它是事实,而事实是免费的。Grok 只会看到那些已经通过了脚本能做的所有检查的代币。

boan - inline image

05. 把所有数字放进一个文件

保存为 config.py。交易台上的每个数字都在这里,所以当你调参时,只需要改这一个文件,别的都不用动。这些是我的参数,针对 25 美元的仓位调过。它们不是推荐,只是你会不断调整的起点。

python
1# config.py
2# 交易台上的每个数字都在这里。调参时,你只改这个文件,别的不动。
3
4MODEL = "grok-4.7" # 如果 API 拒绝,去 console.x.ai -> Models 查一下
5PAPER = True # 第一周:按真实价格假成交。读完日志再关掉
6
7TICKET_USD = 25 # 固定金额。永远不按上一笔盈利来算仓位
8MAX_OPEN = 4 # 4 x $25 = $100,这是市场里的最大敞口
9MAX_ENTRIES_PER_DAY = 6
10DAILY_LOSS_HALT_USD = 50 # 今日已实现亏损达到这个数 -> 明天之前不再开新仓
11COOLDOWN_HOURS = 24 # 刚离场的代币,这段时间内不再进
12
13FACTS = { # rug 过滤器。纯代码,不用模型
14 "max_risk_score": 40, # rugcheck score_normalised,0-100,越高越危险
15 "min_lp_locked_pct": 90, # 最大的池子:LP 锁定或销毁的比例
16 "max_top10_pct": 30, # 前 10 大持仓者,排除池子和锁仓地址
17 "max_dev_pct": 5, # 还在创建者钱包里的供应量
18 "max_insiders": 0, # 被标记为内部人士的持仓者 + 内部关系图命中数
19 "min_liquidity_usd": 30000,
20 "max_ticket_share": 0.01, # 你的仓位永远不超过池子的 1%
21 "min_age_min": 30, # 比这还新的话,所有报告都只是在猜
22 "max_age_hours": 72,
23}
24
25MIN_CONFIDENCE = 0.7 # Grok 在低于这个值时说 BUY -> 按 SKIP 处理
26
27EXIT = {
28 "stop_pct": -35, # 相对入场价的硬止损
29 "ladder": [(100, 0.50), (200, 0.25)], # +100% 卖一半,+200% 再卖四分之一
30 "trail_pct": 30, # 剩下的:价格从高点回落 30% 就出
31 "time_stop_hours": 6, # 6 小时还没涨 20% -> 出局,死钱
32 "time_stop_min_pct": 20,
33 "liq_drop_pct": 40, # 池子流动性比入场时跌 40% -> 立刻出
34}
35
36LOG = "checks.csv"
37POSITIONS = "positions.json"
38TRADES = "trades.csv"
text
1固定仓位。不会因为连赢三把就加大仓位。
2BOT 只读 config.py,永远不写。数字只有你能改。
3放宽过滤器必须留下文字记录。你改了数字,当天就要在聊天里说明原因。

06. 在做任何事之前先跑限制条件

保存为 book.py。交易台上最便宜的检查,就是那个根本不调 API 的检查。如果今天已经亏了 50 美元,交易台连看都不会看那个代币一眼。如果已经有四个仓位开着,也一样。这个文件也是交易台的记忆:两个你可以自己打开的文件,positions.json 和 trades.csv。

python
1# book.py
2# 仓位、交易、限制。交易台的记忆存在两个你可以自己打开的文件里。
3import csv, json, os, sys, time
4from config import (POSITIONS, TRADES, TICKET_USD, MAX_OPEN, MAX_ENTRIES_PER_DAY,
5 DAILY_LOSS_HALT_USD, COOLDOWN_HOURS)
6
7def load() -> dict:
8 return json.load(open(POSITIONS)) if os.path.exists(POSITIONS) else {}
9
10def save(book: dict):
11 json.dump(book, open(POSITIONS, "w"), indent=2)
12
13def trades() -> list[dict]:
14 return list(csv.DictReader(open(TRADES))) if os.path.exists(TRADES) else []
15
16def record(mint, symbol, action, usd, pnl, reason):
17 new = not os.path.exists(TRADES)
18 with open(TRADES, "a", newline="") as f:
19 w = csv.DictWriter(f, fieldnames=["time", "mint", "symbol", "action", "usd", "pnl", "reason"])
20 if new:
21 w.writeheader()
22 w.writerow({"time": time.strftime("%Y-%m-%d %H:%M"), "mint": mint, "symbol": symbol,
23 "action": action, "usd": round(usd, 2), "pnl": round(pnl, 2), "reason": reason})
24
25def today_pnl() -> float:
26 day = time.strftime("%Y-%m-%d")
27 return sum(float(t["pnl"]) for t in trades() if t["time"].startswith(day))
28
29def guard(mint: str) -> str | None:
30 """限制条件在任何网络请求之前运行。被拦下的入场不花一分钱。"""
31 day = time.strftime("%Y-%m-%d")
32 book = load()
33 if today_pnl() <= -DAILY_LOSS_HALT_USD: return "halted_daily_loss"
34 if mint in book: return "already_open"
35 if len(book) >= MAX_OPEN: return "max_open"
36 opens = [t for t in trades() if t["action"] == "open" and t["time"].startswith(day)]
37 if len(opens) >= MAX_ENTRIES_PER_DAY: return "max_entries_today"
38 cutoff = time.strftime("%Y-%m-%d %H:%M", time.localtime(time.time() - COOLDOWN_HOURS * 3600))
39 if any(t["mint"] == mint and t["action"] == "close" and t["time"] >= cutoff for t in trades()):
40 return "cooldown"
41 return None
42
43def open_position(mint, symbol, price, liq_usd, usd=TICKET_USD):
44 book = load()
45 book[mint] = {"symbol": symbol, "entry": price, "qty0": usd / price, "qty": usd / price,
46 "peak": price, "liq0": liq_usd, "opened": time.time(), "steps": 0}
47 save(book)
48 record(mint, symbol, "open", usd, 0, "entry")
49
50def sell(mint, frac_of_original, price, reason) -> float:
51 """卖出原始仓位的某个比例(1.0 = 全部剩余)。返回已实现盈亏。"""
52 book = load()
53 p = book[mint]
54 q = min(p["qty"], p["qty0"] * frac_of_original)
55 pnl = q * (price - p["entry"])
56 p["qty"] -= q
57 action = "close" if p["qty"] <= p["qty0"] * 1e-6 else "partial"
58 record(mint, p["symbol"], action, q * price, pnl, reason)
59 if action == "close":
60 del book[mint]
61 save(book)
62 return pnl
63
64if __name__ == "__main__":
65 # 实盘模式:在你自己的钱包买入后 -> python book.py add <mint> <usd> <price> <liq_usd>
66 # 手动卖出后 -> python book.py close <mint> <price>
67 cmd = sys.argv[1]
68 if cmd == "add":
69 mint, usd, price, liq = sys.argv[2], float(sys.argv[3]), float(sys.argv[4]), float(sys.argv[5])
70 open_position(mint, mint[:6], price, liq, usd)
71 elif cmd == "close":
72 print(round(sell(sys.argv[2], 1.0, float(sys.argv[3]), "manual"), 2))

07. 在入场之前先写好退出

大多数人是在盯着绿柱子的时候决定什么时候卖的。那是做决定的最差时机。在这个交易台上,每个退出规则都在买入代币之前就存在了,bot 只是每 10 分钟检查一次:

  • 流动性比入场时抽走 40%:出,全出,不问为什么
  • 跌 35%:出
  • 涨 100%:出一半,剩下的是市场的钱
  • 涨 200%:再出四分之一
  • 第一次止盈后,剩下的在价格从高点回落 30% 时离场
  • 六小时还没涨 20%:出,这个仓位坑位比那点希望更值钱

保存为 watch.py:

python
1# watch.py
2# 每 10 分钟检查所有开仓。没变化就不输出任何东西。
3import time
4from config import EXIT, PAPER
5from market import pool
6import book
7
8def watch() -> list[str]:
9 events = []
10 for mint, p in list(book.load().items()):
11 try:
12 m = pool(mint)
13 except Exception as e:
14 events.append(f"{p['symbol']}: price feed down ({e}), holding, will retry")
15 continue
16 if not m or m["price"] <= 0:
17 events.append(f"{p['symbol']}: pool gone. treat as rugged, sell what you can")
18 book.sell(mint, 1.0, 0.0, "pool_gone")
19 continue
20
21 price = m["price"]
22 b = book.load(); s = b[mint]
23 s["peak"] = max(s["peak"], price); book.save(b)
24 pct = (price / s["entry"] - 1) * 100
25 hours = (time.time() - s["opened"]) / 3600
26
27 def out(frac, why):
28 pnl = book.sell(mint, frac, price, why)
29 verb = "sold" if PAPER else "SELL NOW in your wallet"
30 size = "the rest" if frac >= 1 else f"{int(frac * 100)}%"
31 events.append(f"{s['symbol']}: {verb} {size} at {pct:+.0f}% ({why}), pnl ${pnl:+.2f}")
32
33 if m["liq_usd"] < s["liq0"] * (1 - EXIT["liq_drop_pct"] / 100):
34 out(1.0, "liquidity_pulled"); continue
35 if pct <= EXIT["stop_pct"]:
36 out(1.0, "stop"); continue
37 ladder = EXIT["ladder"]
38 if s["steps"] < len(ladder) and pct >= ladder[s["steps"]][0]:
39 out(ladder[s["steps"]][1], f"take_profit_{ladder[s['steps']][0]}")
40 b = book.load()
41 if mint in b:
42 b[mint]["steps"] += 1; book.save(b)
43 continue
44 if s["steps"] > 0 and price <= s["peak"] * (1 - EXIT["trail_pct"] / 100):
45 out(1.0, "trailing_stop"); continue
46 if hours >= EXIT["time_stop_hours"] and pct < EXIT["time_stop_min_pct"]:
47 out(1.0, "time_stop")
48 return events
49
50if __name__ == "__main__":
51 for e in watch():
52 print(e)
text
1流动性优先。池子被抽走这条规则压过一切,哪怕你正赚着。
2追踪止损在第一次止盈后才启动。在那之前,-35% 是唯一的底。
3死钱也是亏损。横盘六小时就把坑位让给下一个代币。
4沉默也是一种状态。没变化时 watch.py 什么都不输出,所以聊天安静就意味着你不用去看。
boan - inline image

08. 学会代币死亡的 14 种方式

如果上面那些只能留一样,我会留这个。它甚至不需要任何 bot:下次买入前,在 rugcheck.xyz 和 dexscreener 上手动跑一遍这 14 项检查,你就会避开大部分事后会让你后悔的代币。

其中 13 项是代码。纯比较,不用模型,不带观点。第 14 项是唯一需要 Grok 的。

#

检查项

何时击杀

为什么

1

已经被 rug

Rugcheck 标记为 rugged

别人已经干过了

2

mint 权限

仍然开放

项目方可以往你的袋子里印新币

3

freeze 权限

仍然开放

项目方可以冻结你的代币,你卖不掉

4

危险标记

任何 danger 级别的风险

Rugcheck 已经看到了你得去证伪的东西

5

风险分

高于 40/100

小警告加在一起就是大雷

6

LP 锁定

最大池子锁定或销毁不足 90%

没锁的流动性就是个撤资按钮

7

前 10 大持仓

超过 30%,不含池子和锁仓地址

十个钱包联手就能终结你的交易

8

开发者钱包

创建者仍持有超过 5%

项目方是第一个砸盘的人

9

内部人士 / 捆绑包

任何被标记为内部人士的持仓或关系图命中

一起充值的钱包会一起砸盘

10

池子深度

流动性低于 3 万美元

你就是别人的出口

11

仓位占比

你的 25 美元超过池子的 1%

你自己的买单就会拉动价格

12

年龄

不到 30 分钟或超过 72 小时

太新,任何报告都是猜;或者行情已经走完了

13

有卖盘吗

过去一小时 20+ 笔买入,零卖出

这就是貔貅盘的形状

14

读 X(Grok)

没帖子、山寨 CA、买来的热度、rug 前科

这是任何 API 都给不了的部分

boan - inline image

09. 让代码杀掉那些明显的

检查 1 到 9。它拉一份报告,只保留交易台需要的字段。Grok 永远看不到原始报告,臃肿的数据包既费 token 又降准确率。

一个大家容易忽略的细节:池子自己的金库和锁仓地址也在头部持仓列表里。把它们算进去,每个代币看起来都像巨鲸盘。代码在统计前 10 之前会把它们剔除。

python
1# rugcheck.py
2# 每个代币一份报告,裁剪到交易台需要的字段。Grok 永远看不到原始报告。
3import requests
4from config import FACTS
5
6RC = "https://api.rugcheck.xyz/v1/tokens"
7
8def report(mint: str) -> dict:
9 r = requests.get(f"{RC}/{mint}/report", timeout=20)
10 r.raise_for_status()
11 d = r.json()
12 token = d.get("token") or {}
13 known = d.get("knownAccounts") or {}
14
15 def is_pool(h): # AMM 金库和锁仓地址在头部持仓里,它们不是巨鲸
16 tag = known.get(h.get("owner")) or known.get(h.get("address")) or {}
17 return str(tag.get("type", "")).upper() in ("AMM", "LOCKER")
18
19 holders = [h for h in (d.get("topHolders") or []) if not is_pool(h)]
20 markets = sorted(d.get("markets") or [],
21 key=lambda m: ((m.get("lp") or {}).get("baseUSD") or 0)
22 + ((m.get("lp") or {}).get("quoteUSD") or 0),
23 reverse=True)
24 lp = (markets[0].get("lp") or {}) if markets else {}
25 supply = token.get("supply") or 0
26 risks = d.get("risks") or []
27
28 return {
29 "mint": mint,
30 "symbol": (d.get("tokenMeta") or {}).get("symbol"),
31 "rugged": bool(d.get("rugged")),
32 "risk_score": d.get("score_normalised"),
33 "danger": [x.get("name") for x in risks if x.get("level") == "danger"],
34 "warn": [x.get("name") for x in risks if x.get("level") == "warn"],
35 "mint_authority": token.get("mintAuthority", d.get("mintAuthority")),
36 "freeze_authority": token.get("freezeAuthority", d.get("freezeAuthority")),
37 "lp_locked_pct": lp.get("lpLockedPct", d.get("lpLockedPct")),
38 "top10_pct": round(sum(h.get("pct") or 0 for h in holders[:10]), 2) if holders else None,
39 "dev_pct": round((d.get("creatorBalance") or 0) / supply * 100, 2) if supply else None,
40 "insiders": sum(1 for h in holders if h.get("insider")) + (d.get("graphInsidersDetected") or 0),
41 "holders": d.get("totalHolders"),
42 }
43
44def fact_kill(t: dict) -> str | None:
45 """纯比较。第一个失败就定生死,原因会被记录。"""
46 if t["risk_score"] is None: return "no_report"
47 if t["rugged"]: return "already_rugged"
48 if t["mint_authority"]: return "mint_open"
49 if t["freeze_authority"]: return "freeze_open"
50 if t["danger"]: return "danger:" + t["danger"][0]
51 if t["risk_score"] > FACTS["max_risk_score"]: return "risk_score"
52 if t["lp_locked_pct"] is None or t["lp_locked_pct"] < FACTS["min_lp_locked_pct"]:
53 return "lp_unlocked"
54 if t["top10_pct"] is None or t["top10_pct"] > FACTS["max_top10_pct"]:
55 return "top10_heavy"
56 if t["dev_pct"] is None or t["dev_pct"] > FACTS["max_dev_pct"]:
57 return "dev_holds"
58 if t["insiders"] > FACTS["max_insiders"]: return "insiders"
59 return None
boan - inline image

10. 检查池子,而不只是合约

检查 10 到 13。合约可以完美无缺,但池子照样让你出不来。这里会读取该代币最深的池子,问四个无聊的问题:里面钱够不够、我的仓位跟它比起来有多大、它多老了、到底有没有人在卖。

python
1# market.py
2# 池子本身:深度、年龄、价格,以及是否真有人能卖得出去。
3import time
4import requests
5from config import FACTS, TICKET_USD
6
7DS = "https://api.dexscreener.com/tokens/v1/solana"
8
9def pool(mint: str) -> dict | None:
10 r = requests.get(f"{DS}/{mint}", timeout=15)
11 r.raise_for_status()
12 data = r.json()
13 pairs = data if isinstance(data, list) else (data.get("pairs") or [])
14 pairs = [p for p in pairs if (p.get("baseToken") or {}).get("address") == mint]
15 if not pairs:
16 return None
17 p = max(pairs, key=lambda x: (x.get("liquidity") or {}).get("usd") or 0)
18 h1 = (p.get("txns") or {}).get("h1") or {}
19 born = p.get("pairCreatedAt")
20 return {
21 "symbol": (p.get("baseToken") or {}).get("symbol"),
22 "price": float(p.get("priceUsd") or 0),
23 "liq_usd": (p.get("liquidity") or {}).get("usd") or 0,
24 "age_min": round((time.time() * 1000 - born) / 60000) if born else None,
25 "buys_1h": h1.get("buys", 0),
26 "sells_1h": h1.get("sells", 0),
27 "vol_1h": (p.get("volume") or {}).get("h1"),
28 "url": p.get("url"),
29 }
30
31def market_kill(m: dict | None) -> str | None:
32 if not m: return "no_pool"
33 if m["price"] <= 0: return "no_price"
34 if m["liq_usd"] < FACTS["min_liquidity_usd"]: return "thin_pool"
35 if TICKET_USD / m["liq_usd"] > FACTS["max_ticket_share"]: return "ticket_too_big"
36 if m["age_min"] is None or m["age_min"] < FACTS["min_age_min"]:
37 return "too_fresh"
38 if m["age_min"] > FACTS["max_age_hours"] * 60: return "too_old"
39 if m["buys_1h"] >= 20 and m["sells_1h"] == 0: return "nobody_can_sell"
40 return None

11. 让 Grok 去读代码读不到的东西

检查 14。这就是交易台跑在 Grok 而不是其他模型上的原因:它能一边思考一边搜 X。一个代币可能通过全部 13 项检查,但依然是个换了合约地址的山寨盘,或者是四十个上周刚建的号在同一分钟发了同一句话的发射局。没有 API 能返回这些。X 可以。

保存为 grok.py。这是唯一读取密钥的文件,也是交易台唯一和 xAI 对话的地方:

python
1# grok.py
2# 唯一保存密钥的文件,也是 desk 与 xAI 通信的唯一地方。
3import os, json, datetime, requests
4from config import MODEL
5
6URL = "https://api.x.ai/v1/responses"
7
8def _key() -> str:
9 k = os.environ.get("XAI_API_KEY")
10 if not k and os.path.exists(".env"):
11 for line in open(".env"):
12 if line.startswith("XAI_API_KEY="):
13 k = line.split("=", 1)[1].strip().strip('"')
14 if not k:
15 raise RuntimeError("环境变量或 .env 中没有 XAI_API_KEY")
16 return k
17
18def _text(resp: dict) -> str:
19 if isinstance(resp.get("output_text"), str):
20 return resp["output_text"]
21 parts = []
22 for item in resp.get("output") or []:
23 if item.get("type") == "message":
24 for c in item.get("content") or []:
25 if c.get("type") in ("output_text", "text"):
26 parts.append(c.get("text") or "")
27 return "\n".join(parts)
28
29def ask(system: str, payload: dict, read_x: bool = False) -> dict:
30 """一次调用,JSON 进,JSON 出。任何非 JSON 都会抛出异常,而抛出异常在上游就意味着跳过(SKIP)。"""
31 body = {"model": MODEL,
32 "input": [{"role": "system", "content": system},
33 {"role": "user", "content": json.dumps(payload)}]}
34 if read_x:
35 since = (datetime.date.today() - datetime.timedelta(days=3)).isoformat()
36 body["tools"] = [{"type": "x_search", "from_date": since}]
37 body["max_turns"] = 2 # 搜索两轮,然后必须给出答案
38 r = requests.post(URL, timeout=180, json=body,
39 headers={"Authorization": f"Bearer {_key()}"})
40 r.raise_for_status()
41 text = _text(r.json())
42 start, end = text.find("{"), text.rfind("}")
43 if start == -1:
44 raise ValueError(f"回答中没有 json:{text[:200]}")
45 return json.loads(text[start:end + 1])

保存为 prompts.py。这才是你真正会反复阅读的文件:

python
1# prompts.py
2# desk 上唯一的 Grok 提示词。这才是你真正会反复阅读的文件。
3
4JUDGE_PROMPT = """
5你是 RUG DESK。一个 Solana memecoin 刚刚通过了代码中的所有硬性检查:
6权限、LP、持有者、开发者钱包、内部人员、池子深度、存续时间。
7不要重新检查那些数字。由你决定是否投入这一张固定金额的票。
8你永远不负责确定仓位大小,也永远不挑选退出时机。
9
10输入:{"token": {...rugcheck 事实...}, "pool": {...dexscreener 事实...}}
11
12步骤 1. 在 X 上搜索该代币符号和合约地址,范围是过去 72 小时。
13步骤 2. 只判断代码看不到的东西:
14 - warn 级别的风险叠加在一起是否会变成更严重的问题
15 - 谁最先发帖:开发者、有历史记录的真实账号,还是一波新注册的账号
16 - 自然流量还是买量:相同的措辞、同一分钟发布、没有历史记录的账号
17 - 这些帖子中的合约地址是否与输入中的一致
18 - 这个代币符号或这个开发者以前是否涉及过跑路(rug)
19
20仅返回 JSON:
21{"verdict": "BUY" | "SKIP", "confidence": 0.0-1.0,
22 "why": "最多两行", "x_read": "一行描述 X 上的情况",
23 "main_risk": "一行"}
24
25X 上零帖子也是一个答案:没人知道它的存在。跳过(SKIP)。
26X 上同一个代币符号下出现了另一个合约地址:仿盘风险。跳过(SKIP)。
27当你需要的某个字段为 null 时,绝对不要回答买入(BUY)。
28绝对不要提及目标价。你不知道目标价。
29"""

12. 把它们串成一条命令

输入一个合约地址,输出一个判定结果。依次经过限额、事实、池子、Grok,第一个说不的环节就会终止流程:

python
1# check.py
2# 输入一个合约地址,输出一个判定结果。每当有代币来到你的 desk 时都会运行。
3import csv, json, os, sys, time
4from config import LOG, MIN_CONFIDENCE, PAPER, TICKET_USD
5from rugcheck import report, fact_kill
6from market import pool, market_kill
7from grok import ask
8from prompts import JUDGE_PROMPT
9import book
10
11def log(row: dict):
12 new = not os.path.exists(LOG)
13 with open(LOG, "a", newline="") as f:
14 w = csv.DictWriter(f, fieldnames=["time", "mint", "symbol", "stage", "verdict",
15 "confidence", "reason"])
16 if new:
17 w.writeheader()
18 w.writerow({k: row.get(k) for k in w.fieldnames})
19
20def check(mint: str) -> dict:
21 if (g := book.guard(mint)): # 限额检查,免费
22 return {"stage": "limits", "verdict": "SKIP", "reason": g}
23
24 try:
25 token = report(mint) # rug 过滤,免费
26 except Exception as e:
27 return {"stage": "facts", "verdict": "SKIP", "reason": f"rugcheck 失败:{e}"}
28 if (k := fact_kill(token)):
29 return {"stage": "facts", "verdict": "SKIP", "reason": k, "symbol": token["symbol"]}
30
31 try:
32 m = pool(mint) # 池子检查,免费
33 except Exception as e:
34 return {"stage": "pool", "verdict": "SKIP", "reason": f"dexscreener 失败:{e}"}
35 if (k := market_kill(m)):
36 return {"stage": "pool", "verdict": "SKIP", "reason": k, "symbol": token["symbol"]}
37
38 try:
39 ans = ask(JUDGE_PROMPT, {"token": token, "pool": m}, read_x=True) # 唯一付费的步骤
40 except Exception as e:
41 return {"stage": "grok", "verdict": "SKIP", "reason": f"grok 失败:{e}"}
42
43 verdict, conf = ans.get("verdict"), ans.get("confidence") or 0
44 if verdict == "BUY" and conf < MIN_CONFIDENCE:
45 verdict = "SKIP"
46 ans["why"] = f"置信度过低 {conf}"
47 return {**ans, "stage": "grok", "verdict": verdict, "symbol": m["symbol"] or token["symbol"],
48 "reason": ans.get("why"), "price": m["price"], "liq_usd": m["liq_usd"], "url": m["url"]}
49
50if __name__ == "__main__":
51 mint = sys.argv[1].strip()
52 v = check(mint)
53 log({"time": time.strftime("%Y-%m-%d %H:%M"), "mint": mint, **v})
54 if v["verdict"] == "BUY":
55 if PAPER:
56 book.open_position(mint, v["symbol"], v["price"], v["liq_usd"])
57 v["action"] = f"模拟买入 ${TICKET_USD},价格 {v['price']}"
58 else:
59 v["action"] = (f"需要批准:在你自己的钱包中买入 ${TICKET_USD} 的 {v['symbol']},"
60 f"然后运行:python book.py add {mint} {TICKET_USD} <成交价格> {v['liq_usd']}")
61 print(json.dumps(v, indent=2))

你不需要扫描器也能用它。从喊单频道、帖子或朋友消息里拿到一个 CA(合约地址):告诉机器人 "check <CA>",它就会跑完整个流程。返回的结果长这样(示例结构,不是真实代币):

json
1{
2 "verdict": "SKIP",
3 "confidence": 0.78,
4 "why": "通过了所有硬性检查,但前 30 个帖子来自本周创建的账号,措辞完全相同。",
5 "x_read": "一个真实账号,一波新注册账号,没有 CA 不一致的情况",
6 "main_risk": "买来的热度,发帖一停买家就跑",
7 "stage": "grok",
8 "symbol": "EXAMPLE",
9 "reason": "通过了所有硬性检查,但前 30 个帖子来自本周创建的账号,措辞完全相同。"
10}
boan - inline image
text
1先看事实,再看观点。Grok 永远不会去判断某个 mint 是否开放。
2调用失败就是跳过。Rugcheck 挂了、DexScreener 挂了、Grok 挂了、JSON 格式错误:全部跳过。
3NULL 不等于干净。某个字段没返回就会直接淘汰该代币,绝不会让它通过。
4每个代币只有一个判定结果。在它显示买入之前,绝不要重复运行。如果你不同意,那你反对的是 config.py。
5看淘汰原因,别看买入记录。买入让人心情好,但淘汰原因才能告诉你过滤器是否有效。

13. 三个例行任务,每个一句话

不需要工作流构建器。你用一句话把每个例行任务告诉机器人一次,它就会给你展示下一次运行的情况。以下是我的原话,一字不差:

text
1每 10 分钟,在 /workspace/desk 目录下运行 python watch.py。
2如果它什么都没输出,你就什么都别说。如果它输出了任何内容,就一字不差地发到这里。
text
1每 30 分钟,在 /workspace/desk 目录下运行 python scan.py。
2只发布判定为买入的结果:代币符号、置信度、x_read。
3如果 Rugcheck 或 DexScreener 挂了,只说一次是哪个挂了,不要每次运行都重复。
text
1每天 21:30,在 /workspace/desk 目录下运行 python report.py,并把输出发到这里。
2补充一件今天奏效的事,以及一个你在 config.py 中想质疑的数字,并说明理由。
3绝对不要自己修改那个数字。

这两个文件就是上述例行任务要运行的脚本。保存为 report.py:

python
1# report.py
2# 晚间报告。里面的所有内容都来自 checks.csv 和 trades.csv,不靠记忆。
3import csv, os, time
4from collections import Counter
5from config import LOG, PAPER
6import book
7
8day = time.strftime("%Y-%m-%d")
9checks = [r for r in csv.DictReader(open(LOG))] if os.path.exists(LOG) else []
10checks = [r for r in checks if r["time"].startswith(day)]
11done = [t for t in book.trades() if t["time"].startswith(day) and t["action"] != "open"]
12
13by_stage = Counter(r["stage"] for r in checks if r["verdict"] == "SKIP")
14buys = [r for r in checks if r["verdict"] == "BUY"]
15wins = [t for t in done if float(t["pnl"]) > 0]
16reasons = Counter(r["reason"] for r in checks if r["stage"] in ("facts", "pool"))
17
18print(f"晚间报告 {day} {'(模拟)' if PAPER else '(实盘)'}")
19print(f"已检查:{len(checks)}")
20print(f"被 rug 过滤器淘汰:{by_stage['facts']} | 被池子淘汰:{by_stage['pool']} | "
21 f"被 Grok 淘汰:{by_stage['grok']} | 被限额拦截:{by_stage['limits']}")
22print(f"已买入:{len(buys)} | 当前持仓:{len(book.load())}")
23print(f"今日已实现盈亏:${book.today_pnl():+.2f}")
24if done:
25 print(f"盈利退出:{len(wins)}/{len(done)}")
26 best = max(done, key=lambda t: float(t["pnl"]))
27 worst = min(done, key=lambda t: float(t["pnl"]))
28 print(f"最佳:{best['symbol']} ${float(best['pnl']):+.2f} | 最差:{worst['symbol']} ${float(worst['pnl']):+.2f}")
29if reasons:
30 top, n = reasons.most_common(1)[0]
31 print(f"最常见的淘汰原因:{top}({n} 次)")

还有 scan.py,可选的线索来源。它会抓取刚刚付费购买了 DexScreener 主页的新鲜 Solana 代币。付费主页并不是质量信号,它只意味着开发者花了钱。剩下的由过滤器决定:

python
1# scan.py
2# 可选的线索来源:刚刚付费购买了 DexScreener 主页的新鲜 Solana 代币。
3# 付费主页不是质量信号,只意味着开发者花了钱。由过滤器来决定。
4import csv, os, subprocess, sys
5import requests
6from config import LOG
7
8seen = {r["mint"] for r in csv.DictReader(open(LOG))} if os.path.exists(LOG) else set()
9r = requests.get("https://api.dexscreener.com/token-profiles/latest/v1", timeout=15)
10r.raise_for_status()
11fresh = [t["tokenAddress"] for t in r.json()
12 if t.get("chainId") == "solana" and t.get("tokenAddress") not in seen]
13
14for mint in fresh[:5]: # 每次运行五个,这样再忙的一个小时也不会耗尽 API 额度
15 subprocess.run([sys.executable, "check.py", mint])

今晚最后一件事:Settings(设置)、General(常规)、Auto-review(自动审查)。添加两条 Ask first(先询问)规则,无论任何例行任务怎么想,它们都会暂停操作并等你确认:

text
1在进行任何钱包连接、签名、兑换或转账之前,先询问我。
2在编辑任何名为 config.py 的文件之前,先询问我。
boan - inline image
boan - inline image

14. 在花第一块钱之前,先模拟跑一周

PAPER = True 意味着 desk 除了不动真金白银之外,其他一切都按真实情况执行。真实的代币、真实的价格、真实的退出,只是成交是假的。七天后,打开 checks.csv,像读陌生人写的东西一样去读它。

你要找的是:哪个检查环节淘汰得最多;那些判定为买入的代币是不是你真的会买的;以及有没有哪个跳过理由看起来不对劲。模拟成交是按屏幕价格算的,而实盘成交永远做不到这一点,所以要把模拟结果当成上限,而不是预测。

当你准备上实盘时,把 PAPER 改成 False,除了最后一步之外什么都不用变。check.py 不再自动买入,而是发出一条审批信息:你自己去钱包里买 $25,然后用一条命令把它记入账本,这样 watch.py 就会开始盯防它。

出问题时怎么办

这涉及到钱,所以每种故障都要在发生前写好唯一的应对方案。

text
1xAI 返回 401 -> 密钥错误。接管控制权,重写 .env,再次运行第 03 步的 curl 命令。
2xAI 返回 400 / 404 -> 模型名称变了。修改 config.py 中的 MODEL,别的都不用动。
3xAI 返回 429 -> 触发速率限制。该代币直接跳过,下次运行继续。绝不要循环重试。
4关于 x_search 的报错 -> 你的 MODEL 无法搜索 X。去 console.x.ai -> Models 选一个能搜的。
5Grok 用散文回答 -> 抛出 ValueError,记录日志,跳过。绝不要把一段话变成一笔交易。
6rugcheck 返回 404 或为空 -> 太新了还没被索引。跳过。新不等于干净。
7所有代币都报 lp_unlocked -> 有些池子类型根本没有 LP 代币。在改这个数字之前,
8 先去 rugcheck 上自己开一个看看,并用文字记录下来。
9no_pool -> 还没在 DEX 上交易,或者不是 Solana 链。跳过。
10例行任务没动静了 -> 你离开太久后,Grok Bot 会暂停例行任务。
11 打开 Routines 重新开启它们。

账单

裁判之前的所有环节都是免费的:限额、Rugcheck、DexScreener。唯一付费的步骤是,对挺过全部 13 项检查的代币调用一次 Grok,并开启 X 搜索。

text
1cost_per_token = input_tokens / 1_000_000 * price_per_M_input
2 + output_tokens / 1_000_000 * price_per_M_output
3 + posts_fetched / 1_000 * 5 # X 搜索:每获取 1,000 个帖子 $5
4
5max_turns = 2 把搜索限制在两轮以内,所以 posts_fetched 会保持很小。
6每次响应都会报告自己的 x_posts_fetched,所以第一天你就能知道真实数字。
7
8价格:[来自 console.x.ai 的价格]

人们最容易搞错的地方:账单规模取决于存活下来的代币数量,而不是扫描器的数量。scan.py 一天可以给 desk 喂 240 个代币,其中大部分在 Grok 听说它们之前就已经被免费淘汰了。

boan - inline image

重要的一点

这是我的配置,不是你的策略。

config.py 里的每一个数字都是我定的,针对 $25 的单笔金额和我自己看着资产归零的承受能力。大多数 memecoin 确实会归零,大多数交易它们的人都在亏钱。过滤器并不能让一个代币变好。它只是剔除了那些显而易见的亏损方式,并逼着你去读懂每个代币死掉的原因。

先模拟跑一周。看看那些淘汰记录。把你不同意的数字改掉,并用文字记录下来。抄它的框架,别照搬它的常量。这不是财务建议。

代码负责淘汰,Grok 负责读 X,你负责签名。脚本永远不做主观判断,Grok 永远拿不到计算器,除了你之外没人能碰钱包。

在下一次买入前把这个存下来。如果你打算跑同样的东西,请关注我,后续还会更新更多 🫶

我的 tg - t.me/+8wAXS0nHWgA2MGEy

我的 github - github.com/0xboan

在这里交易 - fomo.family/r/0xboan

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章