YouMind
Iniciar sesión

Grok Bot desde cero en una noche: configuración completa + filtro de rug pull listo para copiar y pegar

@0xboan
INGLÉS17 oct 2026
126K
139
19
20
439

TL;DR

Esta guía detalla cómo construir un escritorio de trading con Grok Bot desde cero, enfocándose en un riguroso filtro de rug pull de 14 pasos para eliminar tokens estafa antes de ejecutar operaciones. Destaca un flujo de trabajo donde 'el código elimina, Grok analiza y tú firmas', junto con salvaguardas de paper trading.

la mayoría de la gente conoce a Grok Bot por la captura de pantalla de PnL de otra persona, lo abre, lo apunta a un gráfico y pierde los primeros $50 en un token que ya estaba muerto antes de comprarlo. el bot no fue el problema. nadie le explicó cómo se ve algo muerto.

esta es la configuración que volvería a armar esta misma noche si tuviera que empezar de cero. un bot, una carpeta, diez archivos pequeños. no sale a cazar 100x. su trabajo principal es matar tokens, y los pocos que sobreviven igual necesitan que Grok lea X antes de mover un solo dólar.

los pasos del 01 al 07 son la primera noche: el bot, la clave, los límites, las salidas. del 08 al 12 son el filtro de rug pulls, 14 verificaciones, cada una escrita como código. el 13 y el 14 lo ponen en piloto automático, primero en modo paper (simulado).

si leíste mi post sobre el escritorio de ocho agentes, este es el piso sobre el que se sostiene ese escritorio.

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

cómo usar esto: abrí tu Grok Bot, pegá todo este artículo y decile "armá este escritorio en /workspace/desk, modo paper, preguntame antes de que algo toque una wallet". escribe todos los archivos por su cuenta, en su propia computadora.

la división que tenés que grabarte: el código mata, Grok lee X, vos firmás. nadie en el escritorio hace el trabajo de otro.

01. conseguí cuatro cosas antes de empezar

cuatro cosas. cada una explica qué es, qué hacés esta noche y por qué el escritorio la necesita.

1. Grok Bot

qué es. la app donde contratás bots con nombre propio. cada uno trabaja en una computadora en la nube con navegador, archivos y terminal, y sigue funcionando aunque tengas la laptop cerrada.

qué hacés. descargalo en x.ai/bot, iniciá sesión, elegí Create your own (Crear el tuyo).

por qué. todo el escritorio vive en esa computadora. archivos, rutinas, alertas, todo en un solo lugar que podés abrir desde el celular.

2. una API key de xAI

qué es. acceso pago a Grok desde código, con la búsqueda de X integrada.

qué hacés. console.x.ai, API Keys, creá una. todavía no la pegues en ningún lado, el paso 03 dice dónde va.

por qué. una rutina no puede sentarse a pensar sobre cuarenta tokens en un chat. un script que hace una llamada por token sí puede, y registra cada respuesta en el mismo formato.

3. Rugcheck y DexScreener

qué es. dos APIs públicas y gratuitas. Rugcheck lee el contrato: autoridades, LP, holders, insiders, la wallet del dev. DexScreener lee el pool: profundidad, antigüedad, compras contra ventas.

qué hacés. nada. sin registro, sin clave para lecturas.

por qué. los hechos van antes que las opiniones. una autoridad de minteo abierta no es una cuestión de criterio, es un hecho, y los hechos matan primero.

4. una burner wallet, pero no esta noche

qué es. una wallet de Solana nueva que nunca tuvo nada más.

qué hacés. nada todavía. la primera semana corre en modo paper.

por qué. el escritorio nunca guarda una clave. cuando pases a real, te dice qué comprar y lo firmás vos mismo.

02. contratá un bot, no ocho

mi escritorio hoy usa ocho bots. no empezó así, y el tuyo tampoco debería. ocho bots el primer día son ocho cosas para debugear al mismo tiempo. un bot con un solo trabajo te muestra qué van a necesitar los otros siete más adelante.

elegí Create your own y dale esto, palabra por palabra:

text
1Nombre: RUG DESK
2Trabajo: Escritorio de memecoins de Solana, primero en modo paper
3Descripción: Armá y ejecutá el escritorio en /workspace/desk a partir del artículo que te voy a pegar.
4Cada token pasa por check.py, sin excepciones, sin atajos.
5Nunca comprás, vendés, firmás ni movés fondos. Nunca editás config.py salvo que yo te lo pida
6en este chat. Nunca bajás el número de un filtro para dejar pasar un token.
7Reportá cada eliminación con su motivo, no con tu opinión sobre el token.
8Cuando una fuente esté caída, decí cuál y saltala. Nunca adivines un número faltante.

las últimas dos líneas importan más que las primeras cinco. un bot que adivina un número faltante tarde o temprano va a adivinar uno que te va a salir caro.

boan - inline image

03. mantené la clave fuera del chat

todo lo que le escribís a un bot queda guardado en una transcripción. por eso la clave va en un archivo, tipeada por vos, en la computadora del bot.

abre la computadora del bot, hacé clic en Take over (Tomar control), abrí la terminal y corré esto. pide la clave sin mostrarla en pantalla, así tampoco aparece en el historial:

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

después comprobá que la clave funciona antes de hacer cualquier otra cosa. una sola llamada, para que más adelante nunca confundas una clave mala con un prompt malo:

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" ...

hacé clic en I'm done (Terminé) y devolvele la computadora. de acá en adelante el bot puede manejar el escritorio, y sigue sin ver la clave en el chat.

boan - inline image

04. mirá todo el embudo antes de construir algo

ocho filtros. los gratuitos corren primero. solo lo que sobrevive a los filtros gratis cuesta una llamada a Grok, y solo lo que Grok marca como BUY (comprar) cuesta plata. esta semana, ni siquiera eso.

text
10. LEAD un CA de cualquier lado: un aviso, un post, scan.py -> un minteo
21. LIMITS book.py: pérdida diaria, slots abiertos, cooldown -> gratis, sin usar la red
32. FACTS rugcheck.py: 10 eliminaciones duras -> minteo abierto, LP desbloqueado, top 10 pesado mueren acá
43. POOL market.py: profundidad, antigüedad, ventas -> pools chicos y honeypots mueren acá
54. JUDGE grok.py + búsqueda en X, una llamada -> BUY o SKIP, un motivo, un riesgo
65. FILL paper: book.py al precio real -> real: lo firmás vos mismo
76. WATCH watch.py cada 10 minutos -> stop, escalera, trailing, stop por tiempo
87. REPORT report.py a las 21:30 -> qué murió, qué pagó, qué cuestionar

una autoridad de minteo abierta no es una cuestión de criterio. es un hecho, y los hechos son gratis. Grok solo llega a ver los tokens que ya pasaron todas las verificaciones que un script puede hacer.

boan - inline image

05. poné todos los números en un solo archivo

guardalo como config.py. todos los números del escritorio viven acá, así que cuando recalibrás, editás un solo archivo y nada más. estos son los míos, ajustados para tickets de $25. no son una recomendación, son un punto de partida que vas a mover.

python
1# config.py
2# todos los números del escritorio viven acá. cuando recalibrás, editás este archivo y nada más.
3
4MODEL = "grok-4.7" # revisá console.x.ai -> Models si la API lo rechaza
5PAPER = True # semana uno: fills falsos a precios reales. cambialo solo después de leer el log
6
7TICKET_USD = 25 # fijo. nunca dimensionado según la última ganancia
8MAX_OPEN = 4 # 4 x $25 = $100 en el mercado, máximo
9MAX_ENTRIES_PER_DAY = 6
10DAILY_LOSS_HALT_USD = 50 # si la pérdida realizada de hoy llega a esto -> no hay nuevas entradas hasta mañana
11COOLDOWN_HOURS = 24 # no reentrar a un token que acabás de dejar
12
13FACTS = { # el filtro de rug pulls. solo código, sin modelo
14 "max_risk_score": 40, # score_normalised de rugcheck, 0-100, más alto = más riesgoso
15 "min_lp_locked_pct": 90, # pool más grande: LP bloqueado o quemado
16 "max_top10_pct": 30, # top 10 de holders, excluyendo pools y lockers
17 "max_dev_pct": 5, # supply que sigue en la wallet del creador
18 "max_insiders": 0, # holders marcados como insider + coincidencias en el grafo de insiders
19 "min_liquidity_usd": 30000,
20 "max_ticket_share": 0.01, # tu ticket nunca es más del 1% del pool
21 "min_age_min": 30, # más joven que esto, cualquier reporte sigue siendo una suposición
22 "max_age_hours": 72,
23}
24
25MIN_CONFIDENCE = 0.7 # si Grok dice BUY por debajo de esto -> se trata como SKIP
26
27EXIT = {
28 "stop_pct": -35, # stop duro desde la entrada
29 "ladder": [(100, 0.50), (200, 0.25)], # +100% vende la mitad, +200% vende un cuarto
30 "trail_pct": 30, # el resto: afuera cuando el precio cae 30% desde su pico
31 "time_stop_hours": 6, # si no sube 20% después de 6 horas -> afuera, plata muerta
32 "time_stop_min_pct": 20,
33 "liq_drop_pct": 40, # si la liquidez del pool cae 40% desde la entrada -> afuera ahora
34}
35
36LOG = "checks.csv"
37POSITIONS = "positions.json"
38TRADES = "trades.csv"
text
1TICKET FIJO. el tamaño nunca crece porque las últimas tres operaciones ganaron.
2EL BOT LEE config.py, NUNCA LO ESCRIBE. un número se mueve cuando vos lo movés.
3UN FILTRO SE AFLOJA POR ESCRITO. si cambiás un número, explicás por qué en el chat, el mismo día.

06. corré los límites antes que cualquier otra cosa

guardalo como book.py. la verificación más barata del escritorio es la que nunca llama a una API. si hoy ya perdiste $50, el escritorio ni siquiera mira el token. si hay cuatro posiciones abiertas, lo mismo. este archivo también es la memoria del escritorio: dos archivos que podés abrir vos mismo, positions.json y trades.csv.

python
1# book.py
2# posiciones, operaciones, límites. la memoria del escritorio vive en dos archivos que podés abrir vos mismo.
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 """Los límites corren antes de cualquier llamada de red. Una entrada bloqueada no cuesta 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 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 """Vende una fracción del tamaño ORIGINAL (1.0 = todo lo que queda). Devuelve el 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"] -= 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 # modo real: después de comprar en tu propia wallet -> python book.py add <mint> <usd> <price> <liq_usd>
66 # después de vender 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. escribí la salida antes que la entrada

la mayoría decide cuándo vender mientras mira una vela verde. ese es el peor momento para decidir cualquier cosa. en este escritorio cada salida existe antes de comprar el token, y el bot solo la revisa cada 10 minutos:

  • liquidez retirada 40% desde la entrada: afuera, todo, sin preguntas
  • baja de 35%: afuera
  • sube 100%: la mitad se va, el resto es plata del mercado
  • sube 200%: otro cuarto se va
  • después de la primera toma de ganancias, el resto sale cuando el precio cae 30% desde su pico
  • seis horas sin +20%: afuera, el slot vale más que la esperanza

guardalo como watch.py:

python
1# watch.py
2# cada posición abierta, cada 10 minutos. no imprime nada si nada cambió.
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']}: feed de precio caído ({e}), manteniendo, va a reintentar")
15 continue
16 if not m or m["price"] <= 0:
17 events.append(f"{p['symbol']}: pool desapareció. tratar como rugged, vendé lo que puedas")
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 = "vendido" if PAPER else "VENDÉ AHORA en tu wallet"
30 size = "el resto" if frac >= 1 else f"{int(frac * 100)}%"
31 events.append(f"{s['symbol']}: {verb} {size} a {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
1LIQUIDEZ PRIMERO. un pool vaciado supera cualquier otra regla, incluso en una posición en verde.
2EL TRAILING SE ACTIVA DESPUÉS DE LA PRIMERA TOMA. antes de eso, -35% es el único piso.
3LA PLATA MUERTA TAMBIÉN ES UNA PÉRDIDA. seis horas planas liberan el slot para el próximo token.
4EL SILENCIO ES UN ESTADO. watch.py no imprime nada si nada cambió, así que un chat silencioso significa que no tenés que mirar.
boan - inline image

08. aprendé las 14 formas en que un token muere

si tuviera que tirar todo lo anterior y quedarme con una sola cosa, sería esto. además funciona sin ningún bot: hacé las mismas 14 verificaciones a mano en rugcheck.xyz y dexscreener antes de tu próxima compra y vas a esquivar la mayoría de los tokens de los que te ibas a arrepentir.

13 de las verificaciones son código. comparaciones, sin modelo, sin opinión. la 14 es la única que necesita a Grok.

#

verificación

mata cuando

por qué

1

ya está ruggeado

Rugcheck lo marca como rugged

alguien ya lo hizo

2

autoridad de minteo

sigue abierta

el dev puede imprimir nuevo supply directo a tu bolsa

3

autoridad de congelamiento

sigue abierta

el dev puede congelar tus tokens, no podés vender

4

banderas de peligro

cualquier riesgo de nivel danger

Rugcheck ya vio algo que tendrías que demostrar que está mal

5

puntaje de riesgo

arriba de 40/100

las advertencias chicas se acumulan

6

bloqueo de LP

el pool más grande tiene menos del 90% bloqueado o quemado

la liquidez desbloqueada es un botón de retiro

7

top 10 de holders

más del 30%, excluyendo pools y lockers

diez wallets pueden terminar tu operación juntas

8

wallet del dev

el creador sigue teniendo más del 5%

el dev es el primer vendedor

9

insiders / bundles

algún holder insider o coincidencia en el grafo de insiders

las wallets fondeadas juntas venden juntas

10

profundidad del pool

menos de $30k de liquidez

serías la salida de alguien

11

participación del ticket

tus $25 son más del 1% del pool

tu propia compra mueve el precio

12

antigüedad

menos de 30 min o más de 72h

demasiado nuevo para cualquier reporte, o el movimiento ya pasó

13

existen ventas

20+ compras en la última hora, cero ventas

esa es la forma de un honeypot

14

lectura de X (Grok)

sin posts, CA copiado, hype comprado, historial de rugs

la parte que ninguna API devuelve

boan - inline image

09. dejá que el código mate a los obvios

verificaciones 1 a 9. trae un solo reporte y se queda únicamente con los campos que el escritorio lee. Grok nunca ve el reporte crudo, un payload gigante gasta tokens y resta precisión.

un detalle que muchos pasan por alto: la bóveda del propio pool y los lockers aparecen en la lista de top holders. si los contás, cualquier token parece un token de ballenas. el código los descarta antes de sumar el top 10.

python
1# rugcheck.py
2# un reporte por token, recortado a los campos que el escritorio lee. Grok nunca ve el reporte crudo.
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): # las bóvedas AMM y los lockers están en el top de holders, no son ballenas
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 """Comparaciones simples. El primer fallo gana, el motivo se registra."""
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. revisá el pool, no solo el contrato

verificaciones 10 a 13. un contrato puede ser perfecto y el pool igual no te deja salir. esto lee el pool más profundo del token y hace cuatro preguntas aburridas: ¿hay suficiente adentro?, ¿qué tan grande es mi ticket al lado?, ¿qué tan viejo es?, y ¿alguien está vendiendo de verdad?

python
1# market.py
2# el pool en sí: profundidad, antigüedad, precio y si alguien realmente puede vender.
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. dejá que Grok lea lo que el código no puede

verificación 14. esta es la razón por la que el escritorio corre sobre Grok y no sobre cualquier otro modelo: puede buscar en X mientras piensa. un token puede pasar las 13 verificaciones y seguir siendo una copia con otra dirección de contrato, o un lanzamiento donde cuarenta cuentas creadas la semana pasada publicaron la misma frase en el mismo minuto. ninguna API devuelve eso. X sí.

guardalo como grok.py. es el único archivo que lee la clave y el único lugar donde el escritorio habla con xAI:

python
1# grok.py
2# el único archivo que guarda la clave y el único lugar donde el desk se comunica con 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("no hay XAI_API_KEY en el entorno ni en .env")
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 """Una sola llamada, entra JSON, sale JSON. Cualquier cosa que no sea JSON lanza un error, y un error es un SKIP aguas arriba."""
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 # dos rondas de búsqueda, luego tiene que responder
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"no hay json en la respuesta: {text[:200]}")
45 return json.loads(text[start:end + 1])

guárdalo como prompts.py. este es el archivo que realmente vas a releer:

python
1# prompts.py
2# el único prompt de Grok en el desk. este es el archivo que realmente vas a releer.
3
4JUDGE_PROMPT = """
5Eres RUG DESK. Una memecoin de Solana acaba de pasar todas las verificaciones estrictas en el código:
6autoridades, LP, holders, wallet del dev, insiders, profundidad del pool, antigüedad.
7No vuelvas a revisar esos números. Tú decides si entra un ticket fijo.
8Nunca defines el tamaño, nunca eliges las salidas.
9
10ENTRADA: {"token": {...datos de rugcheck...}, "pool": {...datos de dexscreener...}}
11
12PASO 1. Busca en X el ticker y la dirección del contrato, últimas 72 horas.
13PASO 2. Juzga solo lo que el código no puede ver:
14 - si los riesgos de nivel warn se acumulan para formar algo peor en conjunto
15 - quién publicó primero: el dev, una cuenta real con historial o una ola de cuentas nuevas
16 - orgánico o comprado: mismas palabras, mismo minuto, cuentas sin pasado
17 - si la dirección del contrato en esas publicaciones es la misma que en la ENTRADA
18 - si este nombre de ticker o este dev han estado vinculados a un rug antes
19
20DEVUELVE SOLO JSON:
21{"verdict": "BUY" | "SKIP", "confidence": 0.0-1.0,
22 "why": "máximo dos líneas", "x_read": "una línea sobre cómo se ve X",
23 "main_risk": "una línea"}
24
25Cero publicaciones en X es una respuesta: nadie sabe que existe. SKIP.
26Otra dirección de contrato bajo el mismo ticker en X: riesgo de imitación. SKIP.
27NUNCA respondas BUY cuando un campo que necesitabas sea null.
28NUNCA menciones objetivos de precio. No los conoces.
29"""

12. conéctalo todo en un solo comando

entra una dirección de contrato, sale un veredicto. límites, datos, pool, Grok, en ese orden, y el primero que diga que no lo termina:

python
1# check.py
2# entra una dirección de contrato, sale un veredicto. se ejecuta cada vez que un token llega a tu 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)): # límites, gratis
22 return {"stage": "limits", "verdict": "SKIP", "reason": g}
23
24 try:
25 token = report(mint) # filtro de rug, gratis
26 except Exception as e:
27 return {"stage": "facts", "verdict": "SKIP", "reason": f"rugcheck falló: {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) # pool, gratis
33 except Exception as e:
34 return {"stage": "pool", "verdict": "SKIP", "reason": f"dexscreener falló: {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) # el único paso de pago
40 except Exception as e:
41 return {"stage": "grok", "verdict": "SKIP", "reason": f"grok falló: {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"confianza baja {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"COMPRA EN PAPEL ${TICKET_USD} a {v['price']}"
58 else:
59 v["action"] = (f"SE REQUIERE APROBACIÓN: compra ${TICKET_USD} de {v['symbol']} en tu propia wallet, "
60 f"luego ejecuta: python book.py add {mint} {TICKET_USD} <precio de llenado> {v['liq_usd']}")
61 print(json.dumps(v, indent=2))

no necesitas un escáner para usarlo. un CA de un canal de llamadas, una publicación, el mensaje de un amigo: dile al bot "check <CA>" y ejecuta una línea. lo que regresa se ve así (forma de ejemplo, no un token real):

json
1{
2 "verdict": "SKIP",
3 "confidence": 0.78,
4 "why": "pasa todas las verificaciones estrictas, pero las primeras 30 publicaciones vinieron de cuentas creadas esta semana, con las mismas palabras.",
5 "x_read": "una cuenta real, una ola de cuentas nuevas, ninguna discrepancia de CA",
6 "main_risk": "hype comprado, los compradores se van cuando dejan de publicar",
7 "stage": "grok",
8 "symbol": "EJEMPLO",
9 "reason": "pasa todas las verificaciones estrictas, pero las primeras 30 publicaciones vinieron de cuentas creadas esta semana, con las mismas palabras."
10}
boan - inline image
text
1DATOS ANTES QUE OPINIONES. Grok nunca decide si un mint está abierto.
2UNA LLAMADA FALLIDA ES UN SKIP. Rugcheck caído, DexScreener caído, Grok caído, JSON malo: SKIP.
3NULL NO SIGNIFICA LIMPIO. un campo que no regresó elimina al token, nunca lo aprueba.
4UN VEREDICTO POR TOKEN. nunca lo vuelvas a ejecutar hasta que diga BUY. si no estás de acuerdo, no estás de acuerdo con config.py.
5LEE LOS KILLS, NO LAS COMPRAS. las compras se sienten bien. los motivos de eliminación te dicen si el filtro funciona.

13. tres rutinas, una oración cada una

sin constructor de flujos de trabajo. le dices al bot cada rutina una vez, en una oración, y te muestra la siguiente ejecución. estas son las mías, palabra por palabra:

text
1Cada 10 minutos, en /workspace/desk ejecuta python watch.py.
2Si no imprime nada, no digas nada. Si imprime algo, publícalo aquí palabra por palabra.
text
1Cada 30 minutos, en /workspace/desk ejecuta python scan.py.
2Publica solo los veredictos BUY: symbol, confidence, x_read.
3Si Rugcheck o DexScreener están caídos, di cuál una sola vez, no en cada ejecución.
text
1Todos los días a las 21:30, en /workspace/desk ejecuta python report.py y publica el resultado aquí.
2Agrega una cosa que funcionó hoy y un número en config.py que cuestionarías, con el motivo.
3Nunca cambies ese número tú mismo.

los dos archivos que ejecutan esas rutinas. guárdalo como report.py:

python
1# report.py
2# el reporte nocturno. todo lo que contiene viene de checks.csv y trades.csv, nada de la memoria.
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"REPORTE NOCTURNO {day} {'(PAPEL)' if PAPER else '(REAL)'}")
19print(f"revisados: {len(checks)}")
20print(f"eliminados por filtro de rug: {by_stage['facts']} | por pool: {by_stage['pool']} | "
21 f"por Grok: {by_stage['grok']} | por límites: {by_stage['limits']}")
22print(f"comprados: {len(buys)} | abiertos ahora: {len(book.load())}")
23print(f"pnl realizado hoy: ${book.today_pnl():+.2f}")
24if done:
25 print(f"salidas en 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"mejor: {best['symbol']} ${float(best['pnl']):+.2f} | peor: {worst['symbol']} ${float(worst['pnl']):+.2f}")
29if reasons:
30 top, n = reasons.most_common(1)[0]
31 print(f"eliminación más común: {top} ({n}x)")

y scan.py, la fuente opcional de leads. extrae tokens nuevos de Solana que acaban de pagar por un perfil en DexScreener. un perfil pagado no es una señal de calidad, solo significa que el dev gastó dinero. el filtro decide el resto:

python
1# scan.py
2# fuente opcional de leads: tokens nuevos de Solana que acaban de pagar por un perfil en DexScreener.
3# un perfil pagado no es una señal de calidad, solo significa que el dev gastó dinero. el filtro decide.
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]: # cinco por ejecución, para que una hora ocupada no agote el presupuesto de la API
15 subprocess.run([sys.executable, "check.py", mint])

última cosa de esta noche: Settings, General, Auto-review. agrega dos reglas de "Ask first" (preguntar primero); detienen la acción y te esperan sin importar lo que piense cualquier rutina:

text
1Pregunta primero antes de cualquier conexión de wallet, firma, swap o transferencia.
2Pregunta primero antes de editar cualquier archivo llamado config.py.
boan - inline image
boan - inline image

14. una semana en papel antes de un solo dólar

PAPER = True significa que el desk hace todo de verdad excepto mover dinero. tokens reales, precios reales, salidas reales, ejecuciones falsas. después de siete días, abre checks.csv y léelo como si lo hubiera escrito un extraño.

lo que buscas: qué verificación elimina más, si los BUY habrían sido tokens que tú comprarías, y si algún motivo de SKIP parece incorrecto. una ejecución en papel ocurre al precio de pantalla, una ejecución real nunca lo hace, así que trata el resultado en papel como el techo, no como el pronóstico.

cuando pases a real, cambia PAPER a False y nada más cambia excepto el último paso. check.py deja de comprar y en su lugar publica una línea de aprobación: compra $25 tú mismo en tu propia wallet, luego un comando lo pone en el libro para que watch.py empiece a protegerlo.

cuando falla

esto toca dinero, así que cada fallo tiene una respuesta escrita antes de que ocurra.

text
1401 de xAI -> clave mala. Toma el control, reescribe .env, ejecuta el curl del paso 03 otra vez.
2400 / 404 de xAI -> el nombre del modelo cambió. corrige MODEL en config.py, nada más.
3429 de xAI -> límite de tasa. ese token es un SKIP, la siguiente ejecución sigue adelante. nunca lo pongas en bucle.
4error sobre x_search -> tu MODEL no puede buscar en X. elige uno que sí pueda en console.x.ai -> Models.
5Grok responde en prosa -> ValueError, registrado, SKIP. nunca conviertas un párrafo en una operación.
6rugcheck 404 o vacío -> demasiado nuevo para indexarse. SKIP. nuevo no significa limpio.
7lp_unlocked en todo -> algunos tipos de pool no tienen token LP en absoluto. abre uno en rugcheck tú mismo
8 antes de tocar ese número, y cámbialo por escrito.
9no_pool -> aún no se negocia en un DEX, o no es Solana. SKIP.
10las rutinas se callaron -> Grok Bot pausa las rutinas después de que llevas mucho tiempo fuera.
11 abre Routines y vuelve a activarlas.

la factura

todo lo anterior al juez es gratis: los límites, Rugcheck, DexScreener. el único paso de pago es una llamada a Grok por cada token que sobrevivió a las 13 verificaciones, con la búsqueda en X activada.

text
1costo_por_token = input_tokens / 1_000_000 * precio_por_M_input
2 + output_tokens / 1_000_000 * precio_por_M_output
3 + posts_obtenidos / 1_000 * 5 # búsqueda en X: $5 por cada 1,000 posts obtenidos
4
5max_turns = 2 mantiene la búsqueda en dos rondas, así que posts_obtenidos se mantiene bajo.
6cada respuesta reporta su propio x_posts_fetched, así que el primer día te dice el número real.
7
8precio: [precio de console.x.ai]

la parte en la que la gente se equivoca: la factura escala con los sobrevivientes, no con el escáner. scan.py puede enviarle al desk 240 tokens al día y la mayoría muere gratis antes de que Grok siquiera se entere de ellos.

boan - inline image

parte importante

esta es mi configuración, no tu estrategia.

cada número en config.py es mío, elegido para un ticket de $25 y mi propia tolerancia a ver algo irse a cero. la mayoría de las memecoins se van a cero, y la mayoría de la gente que las opera pierde dinero. el filtro no hace que un token sea bueno. elimina las formas obvias de perder, y te obliga a leer por qué murió cada token.

corre una semana en papel. lee las eliminaciones. mueve los números con los que no estés de acuerdo, por escrito. copia la estructura, no las constantes. esto no es consejo financiero.

el código elimina, Grok lee X, tú firmas. un script nunca toma una decisión de juicio, Grok nunca recibe una calculadora, y nadie más que tú toca la wallet.

guarda esto antes de tu próxima compra. sígueme si planeas correr lo mismo, viene más de esto 🫶

mi tg - t.me/+8wAXS0nHWgA2MGEy

mi github - github.com/0xboan

opera aquí - fomo.family/r/0xboan

Guardar con un clic

Lee artículos virales en profundidad con IA en YouMind

Guarda la fuente, haz preguntas concretas, resume el argumento y convierte un artículo viral en notas reutilizables en un único espacio de trabajo con IA.

Explora YouMind
Para creadores

Convierte tu Markdown en un artículo de 𝕏 impecable

Cuando publicas tus propios textos largos, dar formato en 𝕏 a imágenes, tablas y bloques de código es un fastidio. YouMind convierte un borrador completo en Markdown en un artículo de 𝕏 impecable y listo para publicar.

Prueba Markdown a 𝕏

Más patrones por descifrar

Artículos virales recientes

Explorar más artículos virales