a maioria das pessoas conhece o Grok Bot pelo print de PnL de outra pessoa, abre, aponta para um gráfico e perde os primeiros US$ 50 num token que já estava morto antes da compra. o problema não era o bot. ninguém disse a ele como é um token morto.
essa é a estrutura que eu montaria de novo hoje à noite se precisasse recomeçar. um bot, uma pasta, dez arquivos pequenos. ele não caça 100x. o trabalho principal dele é matar tokens, e os poucos que sobrevivem ainda precisam do Grok lendo o X antes que um único dólar se mova.
os passos 01 a 07 são a primeira noite: o bot, a chave, os limites, as saídas. de 08 a 12 vem o filtro de rug, 14 checagens, cada uma delas escrita em código. 13 e 14 colocam tudo no piloto automático, primeiro só no papel.
se você leu meu post sobre a mesa com oito agentes, esse é o chão onde aquela mesa está apoiada.
https://x.com/0xboan/status/2092226208234647626
como usar isso: abra seu Grok Bot, cole este artigo inteiro e diga "monte essa mesa em /workspace/desk, modo paper, me pergunte antes de qualquer coisa tocar uma carteira." ele escreve cada arquivo sozinho, no próprio computador.
a divisão que você precisa guardar: o código mata, o Grok lê o X, você assina. ninguém na mesa faz o trabalho do outro.
01. consiga quatro coisas antes de começar
quatro coisas. cada uma diz o que é, o que você faz hoje à noite e por que a mesa precisa daquilo.
1. Grok Bot
o que é. o app onde você contrata bots com nome. cada um trabalha num computador na nuvem com navegador, arquivos e terminal, e continua funcionando mesmo com seu notebook fechado.
o que você faz. baixe em x.ai/bot, faça login, escolha Create your own.
por quê. a mesa inteira vive naquele computador. arquivos, rotinas, alertas, tudo num lugar só que você pode abrir pelo celular.
2. uma chave de API da xAI
o que é. acesso pago ao Grok via código, com busca no X embutida.
o que você faz. console.x.ai, API Keys, crie uma. não cole em nenhum lugar ainda, o passo 03 diz onde ela entra.
por quê. uma rotina não consegue sentar e pensar sobre quarenta tokens num chat. um script que faz uma chamada por token consegue, e registra cada resposta no mesmo formato.
3. Rugcheck e DexScreener
o que é. duas APIs públicas gratuitas. o Rugcheck lê o contrato: autoridades, LP, holders, insiders, a carteira do dev. o DexScreener lê a pool: profundidade, idade, compras contra vendas.
o que você faz. nada. sem cadastro, sem chave para leituras.
por quê. fatos vêm antes de opiniões. uma autoridade de mint aberta não é questão de julgamento, é um fato, e fatos matam primeiro.
4. uma carteira descartável (burner), mas não hoje
o que é. uma carteira Solana nova que nunca guardou mais nada.
o que você faz. nada por enquanto. a primeira semana roda no papel.
por quê. a mesa nunca guarda uma chave. quando for pra valer, ela te diz o que comprar e você mesmo assina.
02. contrate um bot, não oito
minha mesa roda oito bots agora. não começou assim, e a sua também não deveria. oito bots no primeiro dia são oito coisas para debugar ao mesmo tempo. um bot com uma única tarefa mostra o que os outros sete vão precisar depois.
escolha Create your own e passe isso para ele, palavra por palavra:
1Nome: RUG DESK2Tarefa: Mesa de memecoins Solana, primeiro no modo paper3Descrição: Monte e rode a mesa em /workspace/desk a partir do artigo que vou colar.4Todo token passa pelo check.py, sem exceções, sem atalhos.5Você nunca compra, vende, assina ou move fundos. Você nunca edita o config.py a menos que eu peça6neste chat. Você nunca abaixa o número de um filtro para deixar um token passar.7Reporte cada eliminação com o motivo, não com sua opinião sobre o token.8Quando uma fonte estiver fora do ar, diga qual e pule. Nunca chute um número ausente.
as duas últimas linhas importam mais que as cinco primeiras. um bot que chuta um número ausente vai acabar chutando um que vai te custar caro.

03. mantenha a chave fora do chat
tudo o que você digita para um bot vira histórico. então a chave vai para um arquivo, digitada por você, no computador do bot.
abra o computador do bot, clique em Take over, abra o terminal e rode isso. ele pede a chave sem ecoar na tela, então ela nunca aparece no histórico também:
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
depois prove que a chave funciona antes de qualquer outra coisa. uma chamada só, para você nunca confundir uma chave ruim com um prompt ruim mais tarde:
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" ...
clique em I'm done e devolva o computador. daqui em diante o bot pode rodar a mesa, e ele continua sem ver a chave no chat.

04. veja o funil inteiro antes de construir qualquer parte
oito passagens. as gratuitas rodam primeiro. só o que sobrevive às passagens gratuitas custa uma chamada do Grok, e só o que o Grok classifica como BUY custa dinheiro. esta semana, nem isso.
10. LEAD um CA de qualquer lugar: uma call, um post, scan.py -> um mint21. LIMITES book.py: perda diária, slots abertos, cooldown -> grátis, sem rede nenhuma32. FATOS rugcheck.py: 10 eliminações definitivas -> mint aberto, LP destravado, top 10 gordo morrem aqui43. POOL market.py: profundidade, idade, vendas -> pools finas e honeypots morrem aqui54. JUIZ grok.py + busca no X, uma chamada -> BUY ou SKIP, um motivo, um risco65. PREENCHER paper: book.py no preço real -> ao vivo: você mesmo assina76. MONITORAR watch.py a cada 10 minutos -> stop, escadinha, trailing, stop por tempo87. RELATÓRIO report.py às 21:30 -> o que morreu, o que pagou, o que questionar
uma autoridade de mint aberta não é questão de julgamento. é um fato, e fatos são de graça. o Grok só vê tokens que já passaram por todas as checagens que um script consegue fazer.

05. coloque todos os números num único arquivo
salve como config.py. todo número da mesa vive aqui, então quando você recalibrar, edita um arquivo só e mais nada. esses são os meus, ajustados para um ticket de US$ 25. não são uma recomendação, são um ponto de partida que você vai mudar.
1# config.py2# todo número da mesa vive aqui. quando você recalibrar, edite este arquivo e mais nada.34MODEL = "grok-4.7" # confira em console.x.ai -> Models se a API rejeitar5PAPER = True # primeira semana: preenchimentos falsos com preços reais. mude só depois de ler o log67TICKET_USD = 25 # fixo. nunca dimensionado com base na última vitória8MAX_OPEN = 4 # 4 x US$ 25 = US$ 100 no mercado, no máximo9MAX_ENTRIES_PER_DAY = 610DAILY_LOSS_HALT_USD = 50 # perda realizada hoje bate nisso -> sem novas entradas até amanhã11COOLDOWN_HOURS = 24 # sem reentrada num token que você acabou de sair1213FACTS = { # o filtro de rug. só código, sem modelo14 "max_risk_score": 40, # score_normalised do rugcheck, 0-100, maior = mais arriscado15 "min_lp_locked_pct": 90, # maior pool: LP travado ou queimado16 "max_top10_pct": 30, # top 10 holders, excluindo pools e lockers17 "max_dev_pct": 5, # supply ainda parado na carteira do criador18 "max_insiders": 0, # holders marcados como insider + acertos no gráfico de insiders19 "min_liquidity_usd": 30000,20 "max_ticket_share": 0.01, # seu ticket nunca é mais que 1% da pool21 "min_age_min": 30, # mais novo que isso, todo relatório ainda é chute22 "max_age_hours": 72,23}2425MIN_CONFIDENCE = 0.7 # Grok diz BUY abaixo disso -> tratado como SKIP2627EXIT = {28 "stop_pct": -35, # stop definitivo a partir da entrada29 "ladder": [(100, 0.50), (200, 0.25)], # +100% vende metade, +200% vende um quarto30 "trail_pct": 30, # o resto: sai quando o preço cai 30% do topo31 "time_stop_hours": 6, # não subiu 20% depois de 6 horas -> sai, dinheiro morto32 "time_stop_min_pct": 20,33 "liq_drop_pct": 40, # liquidez da pool caiu 40% desde a entrada -> sai agora34}3536LOG = "checks.csv"37POSITIONS = "positions.json"38TRADES = "trades.csv"
1TICKET FIXO. o tamanho nunca cresce porque as três últimas ganharam.2O BOT LÊ config.py, NUNCA ESCREVE NELE. um número só muda quando você muda.3FILTRO SÓ É AFROUXADO POR ESCRITO. você muda um número, explica o porquê no chat, no mesmo dia.
06. rode os limites antes de qualquer outra coisa
salve como book.py. a checagem mais barata da mesa é aquela que nunca chama uma API. se hoje já perdeu US$ 50, a mesa nem olha pro token. se quatro posições estão abertas, mesma coisa. este arquivo também é a memória da mesa: dois arquivos que você mesmo pode abrir, positions.json e trades.csv.
1# book.py2# posições, trades, limites. a memória da mesa vive em dois arquivos que você mesmo pode abrir.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 """Limites rodam antes de qualquer chamada de rede. Uma entrada bloqueada não custa nada."""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 uma fração do tamanho ORIGINAL (1.0 = tudo o que sobrou). Retorna o pnl realizado."""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 # modo ao vivo: depois de comprar na sua própria carteira -> python book.py add <mint> <usd> <preço> <liq_usd>66 # depois de vender manualmente -> python book.py close <mint> <preço>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. escreva a saída antes da entrada
a maioria das pessoas decide quando vender enquanto encara um candle verde. esse é o pior momento para decidir qualquer coisa. nesta mesa, toda saída existe antes de o token ser comprado, e o bot só confere a cada 10 minutos:
- liquidez puxada 40% desde a entrada: sai, tudo, sem perguntas
- queda de 35%: sai
- alta de 100%: metade vai embora, o resto é dinheiro do mercado
- alta de 200%: mais um quarto vai embora
- depois da primeira realização, o resto sai quando o preço cair 30% do topo
- seis horas sem +20%: sai, o slot vale mais que a esperança
salve como watch.py:
1# watch.py2# cada posição aberta, a cada 10 minutos. não imprime nada quando nada mudou.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 de preço fora do ar ({e}), segurando, vou tentar de novo")15 continue16 if not m or m["price"] <= 0:17 events.append(f"{p['symbol']}: pool sumiu. trate como rug, venda o que der")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 = "vendeu" if PAPER else "VENDA AGORA na sua carteira"30 size = "o 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)
1LIQUIDEZ PRIMEIRO. uma pool puxada vence qualquer outra regra, mesmo numa posição no verde.2O TRAILING SÓ ARMA DEPOIS DA PRIMEIRA REALIZAÇÃO. antes disso, -35% é o único piso.3DINHEIRO MORTO TAMBÉM É PREJUÍZO. seis horas paradas liberam o slot para o próximo token.4SILÊNCIO É UM STATUS. watch.py não imprime nada quando nada mudou, então um chat quieto significa que você não precisa olhar.

08. aprenda as 14 formas de um token morrer
se eu tivesse que jogar fora tudo acima e ficar com uma coisa só, seria isso. também funciona sem nenhum bot: rode as mesmas 14 checagens na mão no rugcheck.xyz e no dexscreener antes da sua próxima compra e você vai pular a maioria dos tokens dos quais ia se arrepender.
13 das checagens são código. comparações, sem modelo, sem opinião. a 14ª é a única que precisa do Grok.
#
checagem
elimina quando
por quê
1
já sofreu rug
Rugcheck marca como rugged
alguém já fez isso
2
autoridade de mint
ainda aberta
o dev pode imprimir novo supply na sua bolsa
3
autoridade de freeze
ainda aberta
o dev pode congelar seus tokens, você não consegue vender
4
sinais de perigo
qualquer risco de nível danger
o Rugcheck já viu algo que você teria que provar estar errado
5
pontuação de risco
acima de 40/100
pequenos avisos se somam
6
trava de LP
maior pool com menos de 90% travado ou queimado
liquidez destravada é um botão de puxada
7
top 10 holders
mais de 30%, excluindo pools e lockers
dez carteiras podem acabar com sua trade juntas
8
carteira do dev
criador ainda segura mais de 5%
o dev é o primeiro vendedor
9
insiders / bundles
qualquer holder insider ou acerto no gráfico de insiders
carteiras financiadas juntas vendem juntas
10
profundidade da pool
menos de US$ 30k de liquidez
você seria a saída de alguém
11
fatia do ticket
seus US$ 25 são mais de 1% da pool
sua própria compra mexe no preço
12
idade
menos de 30 min ou mais de 72h
novo demais para qualquer relatório, ou o movimento já aconteceu
13
existem vendas
20+ compras na última hora, zero vendas
esse é o formato de um honeypot
14
leitura do X (Grok)
sem posts, CA copiado, comprou hype, histórico de rug
a parte que nenhuma API retorna

09. deixe o código matar os óbvios
checagens 1 a 9. ele busca um relatório e mantém só os campos que a mesa lê. o Grok nunca vê o relatório bruto, um payload gordo custa tokens e custa precisão.
um detalhe que o pessoal deixa passar: o vault da própria pool e os lockers ficam na lista de maiores holders. conte-os e todo token parece token de baleia. o código descarta eles antes de somar o top 10.
1# rugcheck.py2# um relatório por token, cortado para os campos que a mesa lê. o Grok nunca vê o relatório bruto.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): # vaults AMM e lockers ficam nos top holders, não são baleias16 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 """Comparações simples. A primeira falha vence, o motivo é registrado."""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. cheque a pool, não só o contrato
checagens 10 a 13. um contrato pode ser perfeito e a pool ainda assim não te deixar sair. isso lê a pool mais profunda do token e faz quatro perguntas chatas: tem o suficiente nela, qual o tamanho do meu ticket perto dela, qual a idade, e alguém está realmente vendendo.
1# market.py2# a pool em si: profundidade, idade, preço e se alguém consegue mesmo vender.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. deixe o Grok ler o que o código não consegue
checagem 14. esse é o motivo de a mesa rodar no Grok e não em qualquer outro modelo: ele consegue buscar no X enquanto pensa. um token pode passar nas 13 checagens e ainda ser uma cópia com endereço de contrato diferente, ou um lançamento onde quarenta contas criadas na semana passada postaram a mesma frase no mesmo minuto. nenhuma API retorna isso. o X retorna.
salve como grok.py. é o único arquivo que lê a chave e o único lugar onde a mesa fala com a xAI:
1# grok.py2# o único arquivo que guarda a chave e o único lugar onde a mesa fala com a 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("no XAI_API_KEY in the environment or 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 """Uma chamada, JSON entra, JSON sai. Qualquer coisa que não seja JSON gera erro, e um erro é um SKIP lá em cima."""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 # duas rodadas de busca, depois ele tem que responder38 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"no json in answer: {text[:200]}")45 return json.loads(text[start:end + 1])
salve como prompts.py. este é o arquivo que você vai realmente reler:
1# prompts.py2# o único prompt do Grok na mesa. este é o arquivo que você vai realmente reler.34JUDGE_PROMPT = """5Você é o RUG DESK. Uma memecoin da Solana acabou de passar por todas as verificações rigorosas no código:6autoridades, LP, holders, carteira do dev, insiders, profundidade da pool, idade.7Não verifique esses números de novo. Você decide se um ticket fixo entra.8Você nunca define tamanho de posição, nunca escolhe saídas.910ENTRADA: {"token": {...fatos do rugcheck...}, "pool": {...fatos do dexscreener...}}1112PASSO 1. Pesquise no X pelo ticker e pelo endereço do contrato, nas últimas 72 horas.13PASSO 2. Julgue apenas o que o código não consegue ver:14 - os riscos de nível warn se acumulam em algo pior juntos?15 - quem postou primeiro: o dev, uma conta real com histórico ou uma onda de contas novas?16 - orgânico ou comprado: mesmo texto, mesmo minuto, contas sem passado17 - o endereço do contrato nessas postagens é o mesmo da ENTRADA?18 - esse nome de ticker ou esse dev já esteve ligado a algum rug antes?1920RETORNE APENAS JSON:21{"verdict": "BUY" | "SKIP", "confidence": 0.0-1.0,22 "why": "máximo duas linhas", "x_read": "uma linha sobre como o X está",23 "main_risk": "uma linha"}2425Zero posts no X é uma resposta: ninguém sabe que existe. SKIP.26Outro endereço de contrato com o mesmo ticker no X: risco de cópia. SKIP.27NUNCA responda BUY quando um campo necessário for null.28NUNCA mencione alvos de preço. Você não os conhece.29"""
12. conecte tudo em um único comando
um endereço de contrato entra, um veredito sai. limites, fatos, pool, Grok, nessa ordem, e o primeiro que disser não encerra o processo:
1# check.py2# um endereço de contrato entra, um veredito sai. roda toda vez que um token passa pela sua mesa.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)): # limites, grátis22 return {"stage": "limits", "verdict": "SKIP", "reason": g}2324 try:25 token = report(mint) # filtro de rug, grátis26 except Exception as e:27 return {"stage": "facts", "verdict": "SKIP", "reason": f"rugcheck failed: {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, grátis33 except Exception as e:34 return {"stage": "pool", "verdict": "SKIP", "reason": f"dexscreener failed: {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) # o único passo pago40 except Exception as e:41 return {"stage": "grok", "verdict": "SKIP", "reason": f"grok failed: {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"low confidence {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} at {v['price']}"58 else:59 v["action"] = (f"APPROVAL NEEDED: buy ${TICKET_USD} of {v['symbol']} in your own wallet, "60 f"then run: python book.py add {mint} {TICKET_USD} <fill price> {v['liq_usd']}")61 print(json.dumps(v, indent=2))
você não precisa de um scanner para usar isso. um CA vindo de um canal de calls, um post, a mensagem de um amigo: diga ao bot "check <CA>" e ele roda uma linha. o que volta se parece com isso (formato de exemplo, não é um token real):
1{2 "verdict": "SKIP",3 "confidence": 0.78,4 "why": "passa em todas as verificações rigorosas, mas os primeiros 30 posts vieram de contas criadas esta semana, com o mesmo texto.",5 "x_read": "uma conta real, uma onda de contas novas, nenhuma divergência de CA",6 "main_risk": "hype comprado, os compradores somem quando as postagens param",7 "stage": "grok",8 "symbol": "EXAMPLE",9 "reason": "passa em todas as verificações rigorosas, mas os primeiros 30 posts vieram de contas criadas esta semana, com o mesmo texto."10}

1FATOS ANTES DE OPINIÕES. O Grok nunca decide se um mint está aberto.2UMA CHAMADA COM FALHA É UM SKIP. Rugcheck fora do ar, DexScreener fora do ar, Grok fora do ar, JSON ruim: SKIP.3NULL NÃO É LIMPO. Um campo que não voltou elimina o token, nunca aprova.4UM VEREDITO POR TOKEN. Nunca rode de novo até que diga BUY. Se você discordar, está discordando do config.py.5LEIA OS KILLS, NÃO OS BUYS. Os buys dão uma sensação boa. Os motivos dos kills mostram se o filtro funciona.
13. três rotinas, uma frase cada
sem construtor de workflow. você diz cada rotina ao bot uma vez, em uma frase, e ele mostra a próxima execução. estas são as minhas, palavra por palavra:
1A cada 10 minutos, em /workspace/desk rode python watch.py.2Se não imprimir nada, não diga nada. Se imprimir qualquer coisa, poste aqui palavra por palavra.
1A cada 30 minutos, em /workspace/desk rode python scan.py.2Poste apenas vereditos BUY: symbol, confidence, x_read.3Se o Rugcheck ou o DexScreener estiverem fora do ar, diga qual deles uma vez, não em cada execução.
1Todos os dias às 21:30, em /workspace/desk rode python report.py e poste a saída aqui.2Adicione uma coisa que funcionou hoje e um número no config.py que você questionaria, com o motivo.3Nunca altere esse número por conta própria.
os dois arquivos que essas rotinas executam. salve como report.py:
1# report.py2# o relatório da noite. tudo nele vem de checks.csv e trades.csv, nada da memória.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"EVENING REPORT {day} {'(PAPER)' if PAPER else '(LIVE)'}")19print(f"checked: {len(checks)}")20print(f"killed by rug filter: {by_stage['facts']} | by pool: {by_stage['pool']} | "21 f"by Grok: {by_stage['grok']} | by limits: {by_stage['limits']}")22print(f"bought: {len(buys)} | open now: {len(book.load())}")23print(f"realized pnl today: ${book.today_pnl():+.2f}")24if done:25 print(f"green exits: {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: {best['symbol']} ${float(best['pnl']):+.2f} | worst: {worst['symbol']} ${float(worst['pnl']):+.2f}")29if reasons:30 top, n = reasons.most_common(1)[0]31 print(f"most common kill: {top} ({n}x)")
e scan.py, a fonte opcional de leads. ele puxa tokens novos da Solana que acabaram de pagar por um perfil no DexScreener. um perfil pago não é sinal de qualidade, só significa que o dev gastou dinheiro. o filtro decide o resto:
1# scan.py2# fonte opcional de leads: tokens novos da Solana que acabaram de pagar por um perfil no DexScreener.3# um perfil pago não é sinal de qualidade, só significa que o dev gastou dinheiro. o 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]: # cinco por execução, para que uma hora movimentada não esgote o orçamento da API15 subprocess.run([sys.executable, "check.py", mint])
última coisa de hoje: Settings, General, Auto-review. adicione duas regras "Ask first" (perguntar antes); elas interrompem a ação e esperam por você, não importa o que qualquer rotina ache:
1Pergunte antes de qualquer conexão de carteira, assinatura, swap ou transferência.2Pergunte antes de editar qualquer arquivo chamado config.py.


14. uma semana no papel antes de um único dólar
PAPER = True significa que a mesa faz tudo de verdade, exceto mexer no dinheiro. tokens reais, preços reais, saídas reais, preenchimentos falsos. depois de sete dias, abra o checks.csv e leia como se tivesse sido escrito por um estranho.
o que você está procurando: qual verificação mais elimina, se os BUYs seriam aqueles que você compraria, e se algum motivo de SKIP parece errado. um preenchimento no papel acontece no preço da tela, um preenchimento real nunca acontece assim, então trate o resultado no papel como teto, não como previsão.
quando for para o modo real, mude PAPER para False e nada mais muda, exceto o último passo. o check.py para de comprar e posta uma linha de aprovação: compre $25 você mesmo na sua própria carteira, depois um comando coloca isso no livro para que o watch.py comece a proteger.
quando quebrar
isso envolve dinheiro, então cada falha tem uma resposta anotada antes de acontecer.
1401 da xAI -> chave ruim. Assuma o controle, reescreva o .env, rode o curl do passo 03 de novo.2400 / 404 da xAI -> o nome do modelo mudou. corrija o MODEL no config.py, nada mais.3429 da xAI -> limite de taxa. esse token é um SKIP, a próxima execução segue em frente. nunca faça loop nisso.4erro sobre x_search -> seu MODEL não pode pesquisar no X. escolha um que possa em console.x.ai -> Models.5Grok responde em prosa -> ValueError, registrado, SKIP. nunca transforme um parágrafo em uma operação.6rugcheck 404 ou vazio -> novo demais para indexar. SKIP. novo não é limpo.7lp_unlocked em tudo -> alguns tipos de pool não têm token de LP nenhum. Abra uma no rugcheck você mesmo8 antes de mexer nesse número, e altere por escrito.9no_pool -> ainda não negociado em uma DEX, ou não é Solana. SKIP.10rotinas ficaram quietas -> o Grok Bot pausa as rotinas depois que você fica muito tempo ausente.11 abra Routines e ligue-as de novo.
a conta
tudo antes do juiz é grátis: os limites, o Rugcheck, o DexScreener. o único passo pago é uma chamada do Grok por token que sobreviveu a todas as 13 verificações, com a pesquisa no X ativada.
1custo_por_token = tokens_de_entrada / 1_000_000 * preco_por_M_entrada2 + tokens_de_saida / 1_000_000 * preco_por_M_saida3 + posts_busca / 1_000 * 5 # Busca no X: $5 por 1.000 posts buscados45max_turns = 2 mantém a pesquisa em duas rodadas, então posts_busca continua pequeno.6cada resposta informa seu próprio x_posts_fetched, então o dia um já te dá o número real.78preço: [preço de console.x.ai]
a parte que as pessoas entendem errado: a conta escala com os sobreviventes, não com o scanner. o scan.py pode alimentar a mesa com 240 tokens por dia e a maioria deles morre de graça antes que o Grok sequer ouça falar neles.

parte importante
esta é a minha configuração, não a sua estratégia.
cada número no config.py é meu, escolhido para um ticket de $25 e para a minha própria tolerância a ver algo ir a zero. a maioria das memecoins vai a zero, e a maioria das pessoas que as opera perde dinheiro. o filtro não torna um token bom. ele remove as formas óbvias de perder e te obriga a ler por que cada token morreu.
rode uma semana no papel. leia os kills. mude os números onde você discordar, por escrito. copie a estrutura, não as constantes. não é conselho financeiro.
o código elimina, o Grok lê o X, você assina. um script nunca toma uma decisão de julgamento, o Grok nunca ganha uma calculadora, e ninguém além de você chega à carteira.
salve isso antes da sua próxima compra. siga se você planeja rodar a mesma coisa, vem mais disso por aí 🫶
meu tg - t.me/+8wAXS0nHWgA2MGEy
meu github - github.com/0xboan
opere aqui - fomo.family/r/0xboan





