la maggior parte delle persone scopre Grok Bot tramite lo screenshot del pnl di qualcun altro, lo apre, lo punta su un grafico e perde i primi 50$ su un token che era già morto prima ancora di comprarlo. il problema non era il bot. nessuno gli aveva spiegato che aspetto ha un token morto.
questa è la configurazione che ricostruirei stasera stessa se dovessi ricominciare da zero. un bot, una cartella, dieci piccoli file. non va a caccia di 100x. il suo compito principale è eliminare token, e quei pochi che sopravvivono hanno comunque bisogno che Grok legga X prima che venga mosso un solo dollaro.
i passaggi da 01 a 07 sono la prima serata: il bot, la chiave, i limiti, le uscite. da 08 a 12 c'è il filtro anti-rug, 14 controlli, ognuno scritto sotto forma di codice. il 13 e il 14 mettono tutto in autopilota, prima solo su carta.
se hai letto il mio post sulla desk a otto agenti, queste sono le fondamenta su cui poggia quella desk.
https://x.com/0xboan/status/2092226208234647626
come usarlo: apri il tuo Grok Bot, incolla questo intero articolo e digita "costruisci questa desk in /workspace/desk, modalità paper, chiedimi prima che qualcosa tocchi un wallet." scriverà ogni file da solo, sul suo computer.
la divisione dei ruoli da tenere a mente: il codice elimina, Grok legge X, tu firmi. nessuno sulla desk fa il lavoro di un altro.
01. procurati quattro cose prima di iniziare
quattro cose. per ognuna ti spiego cos'è, cosa devi fare stasera e perché la desk ne ha bisogno.
1. Grok Bot
cos'è. l'app dove assumi bot con un nome. ognuno lavora su un computer cloud dotato di browser, file e terminale, e continua a lavorare anche con il tuo laptop chiuso.
cosa fare. scaricalo da x.ai/bot, accedi, scegli Crea il tuo (Create your own).
perché. l'intera desk vive su quel computer. file, routine, avvisi, tutto in un unico posto che puoi aprire dal telefono.
2. una chiave API xAI
cos'è. accesso a pagamento a Grok tramite codice, con la ricerca su X integrata.
cosa fare. vai su console.x.ai, API Keys, creane una. non incollarla ancora da nessuna parte, il passaggio 03 spiega dove va messa.
perché. una routine non può starsene seduta a riflettere su quaranta token in una chat. uno script che fa una chiamata per token sì, e registra ogni risposta nello stesso formato.
3. Rugcheck e DexScreener
cosa sono. due API pubbliche gratuite. Rugcheck legge il contratto: autorità, LP, holder, insider, il wallet del dev. DexScreener legge il pool: profondità, età, acquisti rispetto alle vendite.
cosa fare. niente. nessuna registrazione, nessuna chiave per le letture.
perché. i fatti vengono prima delle opinioni. un'autorità di mint aperta non è una questione di giudizio, è un fatto, e i fatti eliminano per primi.
4. un burner wallet, ma non stasera
cos'è. un wallet Solana nuovo di zecca che non ha mai contenuto nient'altro.
cosa fare. per ora niente. la prima settimana si opera su carta.
perché. la desk non detiene mai una chiave. quando andrai live, ti dirà cosa comprare e sarai tu a firmare.
02. assumi un bot, non otto
la mia desk ora fa girare otto bot. non ha iniziato così, e nemmeno la tua dovrebbe farlo. otto bot il primo giorno significano otto cose da debuggare contemporaneamente. un bot con un solo compito ti mostrerà di cosa avranno bisogno gli altri sette più avanti.
scegli Crea il tuo (Create your own) e assegnagli questo, parola per parola:
1Nome: RUG DESK2Lavoro: Desk per memecoin Solana, prima solo su carta3Descrizione: Costruisci e gestisci la desk in /workspace/desk partendo dall'articolo che incollo.4Ogni token passa attraverso check.py, senza eccezioni, senza scorciatoie.5Non compri, vendi, firmi o sposti mai fondi. Non modifichi mai config.py a meno che non te lo chieda6in questa chat. Non abbassi mai il valore di un filtro per far passare un token.7Segnala ogni eliminazione con il relativo motivo, non la tua opinione sul token.8Quando una fonte è offline, dimmi quale e saltala. Non indovinare mai un numero mancante.
le ultime due righe contano più delle prime cinque. un bot che tira a indovinare un numero mancante, prima o poi ne indovinerà uno che ti costerà caro.

03. tieni la chiave fuori dalla chat
tutto ciò che scrivi a un bot finisce in un registro. quindi la chiave va inserita in un file, digitata da te, sul computer del bot.
apri il computer del bot, clicca su Take over (Prendi il controllo), apri il terminale ed esegui questo. chiederà la chiave senza mostrarla a schermo, così non comparirà nemmeno nella cronologia:
1mkdir -p /workspace/desk && cd /workspace/desk2read -rs -p "xai key: " K && printf 'XAI_API_KEY=%s\n' "$K" > .env && unset K3chmod 600 .env4pip install requests
poi dimostra che la chiave funziona prima di fare qualsiasi altra cosa. una sola chiamata, così non confonderai mai una chiave errata con un prompt sbagliato in seguito:
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"}'56-> ... "type":"output_text","text":"OK" ...
clicca su I'm done (Ho finito) e restituisci il computer. da qui in poi il bot potrà gestire la desk, continuando a non vedere mai la chiave nella chat.

04. visualizza l'intero funnel prima di costruirne una parte
otto passaggi. quelli gratuiti girano per primi. solo ciò che sopravvive ai passaggi gratuiti costa una chiamata a Grok, e solo ciò per cui Grok dice COMPRA costa denaro. questa settimana, nemmeno quello.
10. LEAD un CA da qualsiasi parte: una call, un post, scan.py -> un mint21. LIMITI book.py: perdita giornaliera, slot aperti, cooldown -> gratis, nessuna connessione di rete32. FATTI rugcheck.py: 10 eliminazioni nette -> mint aperto, LP sbloccato, top 10 troppo concentrato muoiono qui43. POOL market.py: profondità, età, vendite -> i pool sottili e le honeypot muoiono qui54. GIUDIZIO grok.py + ricerca X, una chiamata -> COMPRA o SALTA, un motivo, un rischio65. ESECUZIONE carta: book.py al prezzo live -> live: firmi tu stesso76. MONITORAGGIO watch.py ogni 10 minuti -> stop, ladder, trail, time stop87. REPORT report.py alle 21:30 -> cosa è morto, cosa ha pagato, cosa mettere in discussione
un'autorità di mint aperta non è una questione di giudizio. è un fatto, e i fatti sono gratis. Grok vede solo i token che hanno già superato tutti i controlli che uno script può eseguire.

05. metti tutti i numeri in un unico file
salva come config.py. ogni numero della desk vive qui, così quando ricalibri, modifichi un solo file e nient'altro. questi sono i miei, calibrati per un ticket da 25$. non sono una raccomandazione, sono un punto di partenza che sposterai.
1# config.py2# ogni numero della desk vive qui. quando ricalibri, modifichi questo file e nient'altro.34MODEL = "grok-4.7" # controlla console.x.ai -> Models se l'API lo rifiuta5PAPER = True # prima settimana: esecuzioni simulate a prezzi reali. cambialo solo dopo aver letto il log67TICKET_USD = 25 # fisso. mai dimensionato in base all'ultima vincita8MAX_OPEN = 4 # 4 x 25$ = 100$ nel mercato, al massimo9MAX_ENTRIES_PER_DAY = 610DAILY_LOSS_HALT_USD = 50 # se la perdita realizzata oggi raggiunge questo -> nessun nuovo ingresso fino a domani11COOLDOWN_HOURS = 24 # nessun rientro in un token appena lasciato1213FACTS = { # il filtro anti-rug. solo codice, nessun modello14 "max_risk_score": 40, # score_normalised di rugcheck, 0-100, più alto = più rischioso15 "min_lp_locked_pct": 90, # pool più grande: LP bloccato o bruciato16 "max_top10_pct": 30, # top 10 holder, esclusi pool e locker17 "max_dev_pct": 5, # supply ancora ferma nel wallet del creatore18 "max_insiders": 0, # holder segnalati come insider + riscontri nel grafico degli insider19 "min_liquidity_usd": 30000,20 "max_ticket_share": 0.01, # il tuo ticket non è mai superiore all'1% del pool21 "min_age_min": 30, # più giovane di così, ogni report sta ancora tirando a indovinare22 "max_age_hours": 72,23}2425MIN_CONFIDENCE = 0.7 # se Grok dice COMPRA sotto questo valore -> trattato come SALTA2627EXIT = {28 "stop_pct": -35, # stop loss netto dall'ingresso29 "ladder": [(100, 0.50), (200, 0.25)], # +100% vende metà, +200% vende un quarto30 "trail_pct": 30, # il resto: esce quando il prezzo scende del 30% dal picco31 "time_stop_hours": 6, # non sale del 20% dopo 6 ore -> fuori, capitale morto32 "time_stop_min_pct": 20,33 "liq_drop_pct": 40, # liquidità del pool scesa del 40% dall'ingresso -> fuori subito34}3536LOG = "checks.csv"37POSITIONS = "positions.json"38TRADES = "trades.csv"
1TICKET FISSO. la size non cresce solo perché le ultime tre operazioni sono andate bene.2IL BOT LEGGE config.py, NON LO SCRIVE MAI. un numero cambia solo quando lo cambi tu.3UN FILTRO SI ALLARGA SOLO PER ISCRITTO. cambi un numero, spieghi perché in chat, lo stesso giorno.
06. fai girare i limiti prima di qualsiasi altra cosa
salva come book.py. il controllo più economico della desk è quello che non chiama mai un'API. se oggi hai già perso 50$, la desk non guarda nemmeno il token. se ci sono quattro posizioni aperte, idem. questo file è anche la memoria della desk: due file che puoi aprire tu stesso, positions.json e trades.csv.
1# book.py2# posizioni, trade, limiti. la memoria della desk vive in due file che puoi aprire tu stesso.3import csv, json, os, sys, time4from config import (POSITIONS, TRADES, TICKET_USD, MAX_OPEN, MAX_ENTRIES_PER_DAY,5 DAILY_LOSS_HALT_USD, COOLDOWN_HOURS)67def load() -> dict:8 return json.load(open(POSITIONS)) if os.path.exists(POSITIONS) else {}910def save(book: dict):11 json.dump(book, open(POSITIONS, "w"), indent=2)1213def trades() -> list[dict]:14 return list(csv.DictReader(open(TRADES))) if os.path.exists(TRADES) else []1516def 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})2425def 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))2829def guard(mint: str) -> str | None:30 """I limiti girano prima di qualsiasi chiamata di rete. Un ingresso bloccato non costa nulla."""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 None4243def 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")4950def sell(mint, frac_of_original, price, reason) -> float:51 """Vende una frazione della size ORIGINALE (1.0 = tutto ciò che resta). Restituisce il pnl realizzato."""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"] -= q57 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 pnl6364if __name__ == "__main__":65 # modalità live: dopo aver comprato nel tuo wallet -> python book.py add <mint> <usd> <price> <liq_usd>66 # dopo aver venduto a mano -> 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. scrivi l'uscita prima dell'ingresso
la maggior parte delle persone decide quando vendere mentre fissa una candela verde. è il momento peggiore per decidere qualsiasi cosa. su questa desk ogni uscita esiste prima che il token venga comprato, e il bot si limita a controllarla ogni 10 minuti:
- liquidità ritirata del 40% dall'ingresso: fuori, tutta, senza fare domande
- giù del 35%: fuori
- su del 100%: metà esce, il resto sono soldi del mercato
- su del 200%: esce un altro quarto
- dopo il primo take profit, il resto esce quando il prezzo scende del 30% dal picco
- sei ore senza un +20%: fuori, lo slot vale più della speranza
salva come watch.py:
1# watch.py2# ogni posizione aperta, ogni 10 minuti. non stampa nulla se non è cambiato nulla.3import time4from config import EXIT, PAPER5from market import pool6import book78def 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']}: feed del prezzo offline ({e}), mantengo, riproverò")15 continue16 if not m or m["price"] <= 0:17 events.append(f"{p['symbol']}: pool sparito. trattalo come rugged, vendi il possibile")18 book.sell(mint, 1.0, 0.0, "pool_gone")19 continue2021 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) * 10025 hours = (time.time() - s["opened"]) / 36002627 def out(frac, why):28 pnl = book.sell(mint, frac, price, why)29 verb = "venduto" if PAPER else "VENDI ORA nel tuo wallet"30 size = "il resto" if frac >= 1 else f"{int(frac * 100)}%"31 events.append(f"{s['symbol']}: {verb} {size} a {pct:+.0f}% ({why}), pnl ${pnl:+.2f}")3233 if m["liq_usd"] < s["liq0"] * (1 - EXIT["liq_drop_pct"] / 100):34 out(1.0, "liquidity_pulled"); continue35 if pct <= EXIT["stop_pct"]:36 out(1.0, "stop"); continue37 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 continue44 if s["steps"] > 0 and price <= s["peak"] * (1 - EXIT["trail_pct"] / 100):45 out(1.0, "trailing_stop"); continue46 if hours >= EXIT["time_stop_hours"] and pct < EXIT["time_stop_min_pct"]:47 out(1.0, "time_stop")48 return events4950if __name__ == "__main__":51 for e in watch():52 print(e)
1PRIMA LA LIQUIDITÀ. un pool svuotato batte qualsiasi altra regola, anche su una posizione in profitto.2IL TRAILING STOP SI ATTIVA DOPO IL PRIMO TAKE PROFIT. prima di allora, -35% è l'unico pavimento.3IL CAPITALE MORTO È COMUNQUE UNA PERDITA. sei ore piatte liberano lo slot per il token successivo.4IL SILENZIO È UNO STATO. watch.py non stampa nulla se non cambia nulla, quindi una chat silenziosa significa che non devi guardare.

08. impara i 14 modi in cui un token muore
se dovessi buttare via tutto il resto e tenere una sola cosa, sarebbe questa. funziona anche senza alcun bot: fai gli stessi 14 controlli a mano su rugcheck.xyz e dexscreener prima del tuo prossimo acquisto e salterai la maggior parte dei token di cui stavi per pentirti.
13 dei controlli sono codice. confronti, nessun modello, nessuna opinione. il 14° è l'unico che richiede Grok.
#
controllo
elimina quando
perché
1
già rugged
Rugcheck lo segnala come rugged
qualcuno lo ha già fatto
2
mint authority
ancora aperta
il dev può stampare nuova supply nel tuo bag
3
freeze authority
ancora aperta
il dev può congelare i tuoi token, non puoi vendere
4
segnalazioni di pericolo
qualsiasi rischio di livello danger
Rugcheck ha già visto qualcosa che dovresti smentire
5
risk score
superiore a 40/100
i piccoli avvisi si sommano
6
blocco LP
il pool più grande ha meno del 90% bloccato o bruciato
la liquidità sbloccata è un pulsante per il pull
7
top 10 holder
oltre il 30%, esclusi pool e locker
dieci wallet possono chiudere il tuo trade insieme
8
wallet del dev
il creatore detiene ancora oltre il 5%
il dev è il primo a vendere
9
insider / bundle
qualsiasi holder insider o riscontro nel grafico degli insider
i wallet finanziati insieme vendono insieme
10
profondità del pool
meno di 30k$ di liquidità
saresti l'uscita di qualcun altro
11
quota del ticket
i tuoi 25$ sono oltre l'1% del pool
il tuo stesso acquisto muove il prezzo
12
età
meno di 30 min o più di 72h
troppo fresco per qualsiasi report, oppure il movimento è già avvenuto
13
esistono vendite
20+ acquisti nell'ultima ora, zero vendite
è la forma tipica di una honeypot
14
lettura X (Grok)
nessun post, CA copiato, hype comprata, storico di rug
la parte che nessuna API restituisce

09. lascia che sia il codice a eliminare quelli ovvi
controlli da 1 a 9. recupera un singolo report e conserva solo i campi che la desk legge. Grok non vede mai il report grezzo, un payload pesante costa token e riduce l'accuratezza.
un dettaglio che molti trascurano: il vault del pool stesso e i locker finiscono nella lista dei top holder. contali e ogni token sembrerà un token da whale. il codice li scarta prima di sommare il top 10.
1# rugcheck.py2# un report per token, ridotto ai campi che la desk legge. Grok non vede mai il report grezzo.3import requests4from config import FACTS56RC = "https://api.rugcheck.xyz/v1/tokens"78def 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 {}1415 def is_pool(h): # i vault AMM e i locker sono nei top holder, non sono whale16 tag = known.get(h.get("owner")) or known.get(h.get("address")) or {}17 return str(tag.get("type", "")).upper() in ("AMM", "LOCKER")1819 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 026 risks = d.get("risks") or []2728 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 }4344def fact_kill(t: dict) -> str | None:45 """Confronti semplici. Il primo fallimento vince, il motivo viene registrato."""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

10. controlla il pool, non solo il contratto
controlli da 10 a 13. un contratto può essere perfetto e il pool potrebbe comunque non lasciarti uscire. questo legge il pool più profondo per il token e pone quattro noiose domande: c'è abbastanza dentro, quanto è grande il mio ticket rispetto ad esso, quanti anni ha, e qualcuno sta davvero vendendo.
1# market.py2# il pool in sé: profondità, età, prezzo e se qualcuno può effettivamente vendere.3import time4import requests5from config import FACTS, TICKET_USD67DS = "https://api.dexscreener.com/tokens/v1/solana"89def 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 None17 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 }3031def 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. lascia che Grok legga ciò che il codice non può
controllo 14. questo è il motivo per cui la desk gira su Grok e non su un altro modello: può cercare su X mentre pensa. un token può superare tutti e 13 i controlli ed essere comunque un'imitazione con un indirizzo di contratto diverso, oppure un lancio in cui quaranta account creati la settimana scorsa hanno postato la stessa frase nello stesso minuto. nessuna API lo restituisce. X sì.
salva come grok.py. è l'unico file che legge la chiave e l'unico punto in cui la desk parla con xAI:
1# grok.py2# l'unico file che contiene la chiave e l'unico punto in cui il desk comunica con xAI.3import os, json, datetime, requests4from config import MODEL56URL = "https://api.x.ai/v1/responses"78def _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("nessuna XAI_API_KEY nell'ambiente o in .env")16 return k1718def _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)2829def ask(system: str, payload: dict, read_x: bool = False) -> dict:30 """Una chiamata, JSON in ingresso, JSON in uscita. Tutto ciò che non è JSON genera un errore, e un errore significa SKIP a monte."""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 # due round di ricerca, poi deve rispondere38 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"nessun json nella risposta: {text[:200]}")45 return json.loads(text[start:end + 1])
salva come prompts.py. questo è il file che rileggerai davvero:
1# prompts.py2# l'unico prompt di Grok sul desk. questo è il file che rileggerai davvero.34JUDGE_PROMPT = """5Sei RUG DESK. Una memecoin su Solana ha appena superato tutti i controlli rigidi nel codice:6autorità, LP, holder, wallet del dev, insider, profondità della pool, età.7Non ricontrollare quei numeri. Decidi tu se far entrare un singolo ticket piatto.8Non dimensionerai mai le posizioni, non sceglierai mai le uscite.910INPUT: {"token": {...dati rugcheck...}, "pool": {...dati dexscreener...}}1112STEP 1. Cerca su X il ticker e l'indirizzo del contratto, nelle ultime 72 ore.13STEP 2. Valuta solo ciò che il codice non può vedere:14 - i rischi di livello warn si sommano per creare qualcosa di peggio?15 - chi ha postato per primo: il dev, un account reale con uno storico, oppure un'ondata di account nuovi?16 - organico o comprato: stesse parole, stesso minuto, account senza passato17 - l'indirizzo del contratto in quei post è lo stesso dell'INPUT?18 - questo nome ticker o questo dev sono già stati legati a un rug in passato?1920RESTITUISCI SOLO JSON:21{"verdict": "BUY" | "SKIP", "confidence": 0.0-1.0,22 "why": "massimo due righe", "x_read": "una riga su come appare X",23 "main_risk": "una riga"}2425Zero post su X è già una risposta: nessuno sa che esiste. SKIP.26Un altro indirizzo di contratto sotto lo stesso ticker su X: rischio copycat. SKIP.27NON rispondere MAI BUY quando un campo necessario è null.28NON menzionare MAI target di prezzo. Non li conosci.29"""
12. collega tutto in un unico comando
un indirizzo di contratto in ingresso, un verdetto in uscita. limiti, dati, pool, Grok, in quest'ordine, e il primo che dice no chiude tutto:
1# check.py2# un indirizzo di contratto in ingresso, un verdetto in uscita. viene eseguito ogni volta che un token passa dal tuo desk.3import csv, json, os, sys, time4from config import LOG, MIN_CONFIDENCE, PAPER, TICKET_USD5from rugcheck import report, fact_kill6from market import pool, market_kill7from grok import ask8from prompts import JUDGE_PROMPT9import book1011def 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})1920def check(mint: str) -> dict:21 if (g := book.guard(mint)): # limiti, gratis22 return {"stage": "limits", "verdict": "SKIP", "reason": g}2324 try:25 token = report(mint) # filtro rug, gratis26 except Exception as e:27 return {"stage": "facts", "verdict": "SKIP", "reason": f"rugcheck fallito: {e}"}28 if (k := fact_kill(token)):29 return {"stage": "facts", "verdict": "SKIP", "reason": k, "symbol": token["symbol"]}3031 try:32 m = pool(mint) # pool, gratis33 except Exception as e:34 return {"stage": "pool", "verdict": "SKIP", "reason": f"dexscreener fallito: {e}"}35 if (k := market_kill(m)):36 return {"stage": "pool", "verdict": "SKIP", "reason": k, "symbol": token["symbol"]}3738 try:39 ans = ask(JUDGE_PROMPT, {"token": token, "pool": m}, read_x=True) # l'unico passaggio a pagamento40 except Exception as e:41 return {"stage": "grok", "verdict": "SKIP", "reason": f"grok fallito: {e}"}4243 verdict, conf = ans.get("verdict"), ans.get("confidence") or 044 if verdict == "BUY" and conf < MIN_CONFIDENCE:45 verdict = "SKIP"46 ans["why"] = f"bassa confidenza {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"]}4950if __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"PAPER BUY ${TICKET_USD} a {v['price']}"58 else:59 v["action"] = (f"APPROVAZIONE NECESSARIA: compra ${TICKET_USD} di {v['symbol']} nel tuo wallet, "60 f"poi esegui: python book.py add {mint} {TICKET_USD} <prezzo di esecuzione> {v['liq_usd']}")61 print(json.dumps(v, indent=2))
non ti serve uno scanner per usarlo. un CA da un canale di call, un post, il messaggio di un amico: dici al bot "check <CA>" e lui esegue una riga. quello che torna indietro assomiglia a questo (struttura d'esempio, non un token reale):
1{2 "verdict": "SKIP",3 "confidence": 0.78,4 "why": "supera tutti i controlli rigidi, ma i primi 30 post provengono da account creati questa settimana, con le stesse parole.",5 "x_read": "un account reale, un'ondata di account nuovi, nessuna discrepanza sul CA",6 "main_risk": "hype comprato, i buyer se ne vanno quando smettono di postare",7 "stage": "grok",8 "symbol": "ESEMPIO",9 "reason": "supera tutti i controlli rigidi, ma i primi 30 post provengono da account creati questa settimana, con le stesse parole."10}

1PRIMA I FATTI, POI LE OPINIONI. Grok non decide mai se un mint è aperto.2UNA CHIAMATA FALLITA È UNO SKIP. Rugcheck giù, DexScreener giù, Grok giù, JSON errato: SKIP.3NULL NON SIGNIFICA PULITO. un campo che non è tornato elimina il token, non lo fa mai passare.4UN VERDETTO PER TOKEN. non rieseguire mai finché non dice BUY. se non sei d'accordo, non sei d'accordo con config.py.5LEGGI GLI SCARTI, NON I BUY. i buy fanno sentire bene. i motivi degli scarti ti dicono se il filtro funziona.
13. tre routine, una frase ciascuna
nessun workflow builder. spieghi al bot ogni routine una sola volta, in una frase, e lui ti mostra l'esecuzione successiva. queste sono le mie, parola per parola:
1Ogni 10 minuti, in /workspace/desk esegui python watch.py.2Se non stampa nulla, non dire nulla. Se stampa qualcosa, postalo qui parola per parola.
1Ogni 30 minuti, in /workspace/desk esegui python scan.py.2Posta solo i verdetti BUY: symbol, confidence, x_read.3Se Rugcheck o DexScreener sono giù, dillo una volta sola indicando quale, non a ogni esecuzione.
1Ogni giorno alle 21:30, in /workspace/desk esegui python report.py e posta qui l'output.2Aggiungi una cosa che oggi ha funzionato e un numero in config.py che metteresti in discussione, spiegando perché.3Non modificare mai quel numero da solo.
i due file che quelle routine eseguono. salva come report.py:
1# report.py2# il report serale. tutto ciò che contiene arriva da checks.csv e trades.csv, niente dalla memoria.3import csv, os, time4from collections import Counter5from config import LOG, PAPER6import book78day = 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"]1213by_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"))1718print(f"REPORT SERALE {day} {'(PAPER)' if PAPER else '(LIVE)'}")19print(f"controllati: {len(checks)}")20print(f"eliminati dal filtro rug: {by_stage['facts']} | dalla pool: {by_stage['pool']} | "21 f"da Grok: {by_stage['grok']} | dai limiti: {by_stage['limits']}")22print(f"comprati: {len(buys)} | aperti ora: {len(book.load())}")23print(f"pnl realizzato oggi: ${book.today_pnl():+.2f}")24if done:25 print(f"uscite in verde: {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"migliore: {best['symbol']} ${float(best['pnl']):+.2f} | peggiore: {worst['symbol']} ${float(worst['pnl']):+.2f}")29if reasons:30 top, n = reasons.most_common(1)[0]31 print(f"scarto più comune: {top} ({n}x)")
e scan.py, la fonte di lead opzionale. recupera i token Solana appena usciti che hanno appena pagato per un profilo DexScreener. un profilo a pagamento non è un segnale di qualità, significa solo che il dev ha speso soldi. il resto lo decide il filtro:
1# scan.py2# fonte di lead opzionale: token Solana appena usciti che hanno appena pagato per un profilo DexScreener.3# un profilo a pagamento non è un segnale di qualità, significa solo che il dev ha speso soldi. il filtro decide.4import csv, os, subprocess, sys5import requests6from config import LOG78seen = {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]1314for mint in fresh[:5]: # cinque per esecuzione, così un'ora intensa non prosciuga il budget API15 subprocess.run([sys.executable, "check.py", mint])
ultima cosa per stasera: Settings, General, Auto-review. aggiungi due regole "Ask first" (Chiedi prima): bloccano l'azione e ti aspettano, indipendentemente da ciò che pensa qualsiasi routine:
1Chiedi prima di qualsiasi connessione al wallet, firma, swap o trasferimento.2Chiedi prima di modificare qualsiasi file chiamato config.py.


14. una settimana su carta prima di un singolo dollaro
PAPER = True significa che il desk fa tutto sul serio tranne muovere denaro. token reali, prezzi reali, uscite reali, esecuzioni simulate. dopo sette giorni, apri checks.csv e leggilo come se l'avesse scritto un estraneo.
cosa devi cercare: quale controllo elimina di più, se i BUY sarebbero stati quelli che avresti comprato anche tu, e se qualche motivo di SKIP sembra sbagliato. un'esecuzione simulata avviene al prezzo mostrato a schermo, un'esecuzione live non lo fa mai, quindi tratta il risultato paper come il tetto massimo, non come la previsione.
quando passi al live, cambia PAPER a False e non cambia nient'altro tranne l'ultimo passaggio. check.py smette di comprare e pubblica invece una riga di approvazione: compra tu stesso $25 nel tuo wallet, poi un comando li inserisce nel registro così watch.py inizia a proteggerli.
quando si rompe
questo sistema tocca il denaro, quindi ogni guasto ha una risposta già scritta prima ancora che accada.
1401 da xAI -> chiave errata. Prendi il controllo, riscrivi .env, esegui di nuovo il curl dello step 03.2400 / 404 da xAI -> il nome del modello è cambiato. correggi MODEL in config.py, nient'altro.3429 da xAI -> rate limit. quel token è uno SKIP, l'esecuzione successiva va avanti. non fare mai loop.4errore su x_search -> il tuo MODEL non può cercare su X. scegline uno che può farlo su console.x.ai -> Models.5Grok risponde in prosa -> ValueError, loggato, SKIP. non trasformare mai un paragrafo in un trade.6rugcheck 404 o vuoto -> troppo recente per essere indicizzato. SKIP. recente non significa pulito.7lp_unlocked su tutto -> alcuni tipi di pool non hanno proprio alcun token LP. aprine uno tu stesso su rugcheck8 prima di toccare quel numero, e modificalo per iscritto.9no_pool -> non ancora scambiato su un DEX, o non è Solana. SKIP.10le routine si sono zittite -> Grok Bot mette in pausa le routine dopo che sei stato via a lungo.11 apri Routines e riattivale.
il conto
tutto ciò che precede il giudice è gratuito: i limiti, Rugcheck, DexScreener. l'unico passaggio a pagamento è una chiamata a Grok per ogni token sopravvissuto a tutti i 13 controlli, con la ricerca su X attiva.
1costo_per_token = input_tokens / 1_000_000 * prezzo_per_M_input2 + output_tokens / 1_000_000 * prezzo_per_M_output3 + post_recuperati / 1_000 * 5 # ricerca X: $5 ogni 1.000 post recuperati45max_turns = 2 mantiene la ricerca a due round, così post_recuperati resta basso.6ogni risposta riporta il proprio x_posts_fetched, quindi il primo giorno ti dà il numero reale.78prezzo: [prezzo da console.x.ai]
la parte in cui le persone sbagliano: il conto scala con i sopravvissuti, non con lo scanner. scan.py può fornire al desk 240 token al giorno e la maggior parte di essi viene eliminata gratuitamente prima che Grok ne sappia qualcosa.

parte importante
questa è la mia configurazione, non la tua strategia.
ogni numero in config.py è mio, scelto per un ticket da $25 e per la mia personale tolleranza nel guardare qualcosa andare a zero. la maggior parte delle memecoin finisce a zero, e la maggior parte di chi le tradisce perde soldi. il filtro non rende buono un token. rimuove i modi più ovvi per perdere, e ti costringe a leggere perché ogni token è morto.
fai girare una settimana su carta. leggi gli scarti. sposta per iscritto i numeri con cui non sei d'accordo. copia la struttura, non le costanti. non è consulenza finanziaria.
il codice elimina, Grok legge X, tu firmi. uno script non prende mai decisioni discrezionali, Grok non riceve mai una calcolatrice, e nessuno tranne te mette mai mano al wallet.
salva questo prima del tuo prossimo acquisto. seguimi se hai intenzione di far girare la stessa cosa, ne arriveranno altre 🫶
il mio tg - t.me/+8wAXS0nHWgA2MGEy
il mio github - github.com/0xboan
trada qui - fomo.family/r/0xboan





