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、前 10 大持倉太集中,都在這裡出局
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 # 第一週:用真實價格做假成交。讀完 log 後再切換
6
7TICKET_USD = 25 # 固定金額。絕對不要因為上次贏了就加大部位
8MAX_OPEN = 4 # 市場上最多 4 x $25 = $100
9MAX_ENTRIES_PER_DAY = 6
10DAILY_LOSS_HALT_USD = 50 # 今日已實現虧損達到此數值 -> 明天之前不再進場
11COOLDOWN_HOURS = 24 # 剛退出的代幣,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. 在進場之前,先把出場規則寫好

大多數人是在盯著綠色 K 棒時才決定何時賣出。那是做決定最糟的時機。在這個交易台上,每個出場規則都在買進代幣前就存在了,而 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']}: 價格來源掛了 ({e}),繼續持有,稍後重試")
15 continue
16 if not m or m["price"] <= 0:
17 events.append(f"{p['symbol']}: 池子消失了。視為被 rug,能賣多少賣多少")
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 永遠不會看到原始報告,太大的 payload 既花 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 pull 有關
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,只要其中一個說 no 就結束:

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))

你不需要掃描器也能用它。不管是 call 群組裡的 CA、某篇貼文,還是朋友傳來的訊息:只要告訴機器人「check <CA>」,它就會跑完那一行指令。回傳的結果長這樣(範例格式,不是真實代幣):

json
1{
2 "verdict": "SKIP",
3 "confidence": 0.78,
4 "why": "通過所有硬性檢查,但前 30 篇貼文都來自本週建立的帳號,而且措辭一模一樣。",
5 "x_read": "一個真實帳號,加上一大批新帳號,合約地址沒有不一致",
6 "main_risk": "買來的熱度,一旦停止發文買家就會跑掉",
7 "stage": "grok",
8 "symbol": "EXAMPLE",
9 "reason": "通過所有硬性檢查,但前 30 篇貼文都來自本週建立的帳號,而且措辭一模一樣。"
10}
boan - inline image
text
1先看事實,再看意見。Grok 永遠不會去判斷某個 mint 是否開放。
2呼叫失敗就是 SKIP。Rugcheck 掛了、DexScreener 掛了、Grok 掛了、JSON 爛掉了:一律 SKIP。
3NULL 不等於乾淨。沒回傳的欄位會直接殺掉這個代幣,絕對不會讓它過關。
4每個代幣只有一個判定。在它說出 BUY 之前,絕對不要重跑。如果你不同意,那你反對的是 config.py。
5看被殺掉的原因,而不是看買入。買入感覺很爽,但淘汰原因才能告訴你篩選器有沒有用。

13. 三個例行任務,各一句話

不用工作流程建立工具。你只要用一句話把每個例行任務告訴機器人一次,它就會顯示下次執行的時間。以下是我的設定,一字不差:

text
1每 10 分鐘,在 /workspace/desk 執行 python watch.py。
2如果它沒印出任何東西,你就什麼都別說。如果有印出任何東西,就一字不漏地貼到這裡。
text
1每 30 分鐘,在 /workspace/desk 執行 python scan.py。
2只貼出 BUY 的判定:代號、信心度、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} {'(PAPER)' if PAPER else '(LIVE)'}")
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。加入兩條「先詢問」規則,無論任何例行任務怎麼想,它們都會擋下動作並等你確認:

text
1在任何錢包連線、簽名、交換或轉帳之前,都要先詢問。
2在編輯任何名為 config.py 的檔案之前,都要先詢問。
boan - inline image
boan - inline image

14. 在花第一塊錢之前,先模擬一週

PAPER = True 代表 desk 除了錢以外,其他一切都來真的。真實代幣、真實價格、真實出場,只有成交是假的。七天後,打開 checks.csv,像讀陌生人寫的東西一樣去讀它。

你要找的是:哪個檢查淘汰最多代幣、那些 BUY 是不是你真的會買的,以及有沒有哪個 SKIP 理由看起來不對。模擬成交用的是螢幕上的價格,真實成交永遠不會是那個價,所以要把模擬結果當成天花板,而不是預測。

當你準備上實盤時,把 PAPER 改成 False,除了最後一步之外什麼都不會變。check.py 不再自動買入,而是貼出一行核准提示:你自己用錢包買 $25,然後下一道指令把它記進帳本,讓 watch.py 開始守護它。

出問題的時候

這套系統會碰到錢,所以每一種錯誤都要在發生前先寫好解答。

text
1xAI 回傳 401 -> 金鑰錯誤。接管控制權,重寫 .env,再跑一次步驟 03 的 curl。
2xAI 回傳 400 / 404 -> 模型名稱改了。修正 config.py 裡的 MODEL,其他都不用動。
3xAI 回傳 429 -> 觸發速率限制。那個代幣就是 SKIP,下次執行會繼續往下走。絕對不要用迴圈重試。
4關於 x_search 的錯誤 -> 你的 MODEL 無法搜尋 X。到 console.x.ai -> Models 挑一個可以搜的。
5Grok 用散文回答 -> ValueError,記錄下來,SKIP。絕對不要把一段文章變成交易。
6rugcheck 404 或空白 -> 太新還沒被索引。SKIP。新不代表乾淨。
7所有東西都顯示 lp_unlocked -> 有些池子類型根本沒有 LP 代幣。在你動那個數字之前,
8 先自己去 rugcheck 開一個看看,並用文字記錄你的修改。
9no_pool -> 還沒在 DEX 上交易,或不是 Solana。SKIP。
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 轉 𝕏

更多可拆解樣本

近期爆款文章

探索更多爆款文章