YouMind
Iniciar sesión

Grok Bot desde cero en una noche: configuración completa + filtro de rug pull 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, centrándose en un riguroso filtro de rug pull de 14 pasos para eliminar tokens fraudulentos antes de ejecutar operaciones. Enfatiza un flujo de trabajo donde 'el código elimina, Grok lee y tú firmas', junto con salvaguardas de paper trading.

la mayoría de la gente conoce a Grok Bot por la captura 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 pull, 14 comprobaciones, cada una escrita como código. el 13 y el 14 lo ponen en piloto automático, primero en modo simulación (paper).

si leíste mi publicación 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: abre tu Grok Bot, pega todo este artículo y dile "construye este escritorio en /workspace/desk, modo paper, pregúntame antes de que algo toque una wallet". él mismo escribe cada archivo, en su propia computadora.

la regla que debes grabarte: el código mata, Grok lee X, tú firmas. nadie en el escritorio hace el trabajo de otro.

01. consigue cuatro cosas antes de empezar

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

1. Grok Bot

qué es. la app donde contratas 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é haces. descárgala en x.ai/bot, inicia sesión, elige Create your own.

por qué. todo el escritorio vive en esa computadora. archivos, rutinas, alertas, todo en un solo lugar que puedes abrir desde el teléfono.

2. una clave API de xAI

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

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

por qué. una rutina no puede sentarse a pensar en cuarenta tokens dentro de 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 gratuitas. Rugcheck lee el contrato: autoridades, LP, holders, insiders, la wallet del desarrollador. DexScreener lee el pool: profundidad, antigüedad, compras contra ventas.

qué haces. nada. sin registro, sin clave para lecturas.

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

4. una wallet desechable, pero no esta noche

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

qué haces. nada por ahora. la primera semana funciona en papel.

por qué. el escritorio nunca guarda una clave. cuando pases a real, te dirá qué comprar y tú lo firmas.

02. contrata un bot, no ocho

mi escritorio usa ocho bots ahora. no empezó así, y el tuyo tampoco debería. ocho bots el primer día son ocho cosas que depurar a la vez. un bot con un solo trabajo te muestra lo que necesitarán los otros siete más adelante.

elige 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: Construye y ejecuta el escritorio en /workspace/desk a partir del artículo que pegaré.
4Cada token pasa por check.py, sin excepciones, sin atajos.
5Nunca compras, vendes, firmas ni mueves fondos. Nunca editas config.py a menos que yo lo pida
6en este chat. Nunca reduces el valor de un filtro para dejar pasar un token.
7Reporta cada eliminación con su motivo, no con tu opinión sobre el token.
8Cuando una fuente esté caída, di cuál y omítela. 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 terminará adivinando uno que te cueste dinero.

boan - inline image

03. mantén la clave fuera del chat

todo lo que le escribes a un bot queda en un historial. así que la clave va a un archivo, escrita por ti, en la computadora del bot.

abre la computadora del bot, haz clic en Take over, abre la terminal y ejecuta esto. pide la clave sin mostrarla en pantalla, así que 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

luego demuestra que la clave funciona antes de cualquier otra cosa. una sola llamada, para que después 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" ...

haz clic en I'm done y devuélvele la computadora. de aquí en adelante el bot puede ejecutar el escritorio, y aun así nunca ve la clave en el chat.

boan - inline image

04. visualiza todo el embudo antes de construir nada

ocho pasadas. las gratuitas van primero. solo lo que sobrevive a las pasadas gratuitas cuesta una llamada a Grok, y solo lo que Grok marca como BUY cuesta dinero. esta semana, ni siquiera eso.

text
10. CANDIDATO un CA de cualquier parte: una llamada, un post, scan.py -> una acuñación
21. LÍMITES book.py: pérdida diaria, slots abiertos, cooldown -> gratis, sin red en absoluto
32. HECHOS rugcheck.py: 10 eliminaciones duras -> mint abierta, LP desbloqueada, top 10 concentrado mueren aquí
43. POOL market.py: profundidad, antigüedad, ventas -> pools finos y honeypots mueren aquí
54. JUEZ grok.py + búsqueda en X, una llamada -> BUY o SKIP, un motivo, un riesgo
65. EJECUCIÓN paper: book.py al precio real -> real: lo firmas tú mismo
76. VIGILANCIA watch.py cada 10 minutos -> stop, escalonado, trailing, stop por tiempo
87. REPORTE report.py a las 21:30 -> qué murió, qué pagó, qué cuestionar

una autoridad de acuñación abierta no es una cuestión de criterio. es un hecho, y los hechos son gratis. Grok solo ve tokens que ya pasaron todas las comprobaciones que un script puede hacer.

boan - inline image

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

guárdalo como config.py. todos los números del escritorio viven aquí, así que cuando reajustes, editas un solo archivo y nada más. estos son los míos, ajustados para una entrada de $25. no son una recomendación, son un punto de partida que vas a modificar.

python
1# config.py
2# todos los números del escritorio viven aquí. cuando reajustes, editas este archivo y nada más.
3
4MODEL = "grok-4.7" # revisa console.x.ai -> Models si la API lo rechaza
5PAPER = True # semana uno: ejecuciones falsas a precios reales. cámbialo 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 hoy llega a esto -> no hay nuevas entradas hasta mañana
11COOLDOWN_HOURS = 24 # no volver a entrar a un token que acabas de dejar
12
13FACTS = { # el filtro de rug pull. solo código, sin modelo
14 "max_risk_score": 40, # score_normalised de rugcheck, 0-100, mayor = 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, # suministro que aún está 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 entrada nunca es más del 1% del pool
21 "min_age_min": 30, # más joven que esto, todo 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 loss 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: salida cuando el precio cae 30% desde su máximo
31 "time_stop_hours": 6, # si no sube 20% tras 6 horas -> fuera, dinero muerto
32 "time_stop_min_pct": 20,
33 "liq_drop_pct": 40, # si la liquidez del pool cae 40% desde la entrada -> fuera de inmediato
34}
35
36LOG = "checks.csv"
37POSITIONS = "positions.json"
38TRADES = "trades.csv"
text
1ENTRADA FIJA. el tamaño nunca crece porque las últimas tres ganaron.
2EL BOT LEE config.py, NUNCA LO ESCRIBE. un número cambia cuando tú lo cambias.
3UN FILTRO SE RELAJA POR ESCRITO. si cambias un número, explicas por qué en el chat, el mismo día.

06. ejecuta los límites antes que cualquier otra cosa

guárdalo como book.py. la comprobació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 puedes abrir tú mismo, positions.json y trades.csv.

python
1# book.py
2# posiciones, operaciones, límites. la memoria del escritorio vive en dos archivos que puedes abrir tú 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 se ejecutan 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 manualmente -> 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. escribe la salida antes que la entrada

la mayoría decide cuándo vender mientras mira fijamente 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 comprueba cada 10 minutos:

  • liquidez retirada 40% desde la entrada: fuera, todo, sin preguntas
  • baja 35%: fuera
  • sube 100%: la mitad se va, el resto es dinero 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 máximo
  • seis horas sin +20%: fuera, el slot vale más que la esperanza

guárdalo 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, reintentaré")
15 continue
16 if not m or m["price"] <= 0:
17 events.append(f"{p['symbol']}: pool desaparecido. tratar como rug pull, vende 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 "VENDE 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 TRAS LA PRIMERA TOMA DE GANANCIAS. antes de eso, -35% es el único piso.
3EL DINERO MUERTO TAMBIÉN ES UNA PÉRDIDA. seis horas planas liberan el slot para el siguiente token.
4EL SILENCIO ES UN ESTADO. watch.py no imprime nada si nada cambió, así que un chat silencioso significa que no tienes que mirar.
boan - inline image

08. aprende las 14 formas en que muere un token

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

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

#

comprobación

mata cuando

por qué

1

ya es rug pull

Rugcheck lo marca como rugged

alguien ya lo hizo

2

autoridad de acuñación

sigue abierta

el desarrollador puede imprimir nuevo suministro en tu bolsa

3

autoridad de congelación

sigue abierta

el desarrollador puede congelar tus tokens, no puedes vender

4

banderas de peligro

cualquier riesgo de nivel danger

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

5

puntuación de riesgo

por encima de 40/100

las pequeñas advertencias 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 salida

7

top 10 de holders

más del 30%, excluyendo pools y lockers

diez wallets pueden acabar con tu operación juntas

8

wallet del desarrollador

el creador aún tiene más del 5%

el desarrollador es el primer vendedor

9

insiders / paquetes

cualquier holder insider o coincidencia en el grafo de insiders

las wallets financiadas juntas venden juntas

10

profundidad del pool

menos de $30k de liquidez

serías la salida de alguien

11

peso de tu entrada

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 ocurrió

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 rug pulls

la parte que ninguna API devuelve

boan - inline image

09. deja que el código mate a los obvios

comprobaciones 1 a 9. obtiene un solo reporte y conserva únicamente los campos que el escritorio lee. Grok nunca ve el reporte crudo, un payload pesado cuesta tokens y cuesta precisión.

un detalle que la gente pasa por alto: la bóveda del propio pool y los lockers aparecen en la lista de principales holders. si los cuentas, todo 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. comprueba el pool, no solo el contrato

comprobaciones 10 a 13. un contrato puede ser perfecto y el pool aun así no dejarte salir. esto lee el pool más profundo del token y hace cuatro preguntas aburridas: ¿hay suficiente en él?, ¿qué tan grande es mi entrada comparada?, ¿qué antigüedad tiene? y ¿alguien está vendiendo realmente?

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

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

guárdalo 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 contiene 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 comprobaciones estrictas en el código:
6autoridades, LP, holders, wallet del dev, insiders, profundidad del pool, antigüedad.
7No vuelvas a comprobar esos números. Tú decides si entra un ticket fijo.
8Nunca calculas 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 juntos
15 - quién publicó primero: el dev, una cuenta real con historial o una oleada 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 cruza 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 NECESITA 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 devuelve se ve así (forma de ejemplo, no un token real):

json
1{
2 "verdict": "SKIP",
3 "confidence": 0.78,
4 "why": "pasa todas las comprobaciones estrictas, pero las primeras 30 publicaciones vinieron de cuentas creadas esta semana, con las mismas palabras.",
5 "x_read": "una cuenta real, una oleada 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 comprobaciones 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 incorrecto: SKIP.
3NULL NO SIGNIFICA LIMPIO. un campo que no regresó elimina el 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 sientan bien. los motivos de eliminación te dicen si el filtro funciona.

13. tres rutinas, una frase cada una

sin constructor de flujos de trabajo. le dices al bot cada rutina una vez, en una frase, 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í.
2Añade 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 informe 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"INFORME NOCTURNO {day} {'(PAPEL)' if PAPER else '(REAL)'}")
19print(f"comprobados: {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 de pago 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 de pago 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 intensa no agote el presupuesto de la API
15 subprocess.run([sys.executable, "check.py", mint])

última cosa de esta noche: Settings, General, Auto-review. añade 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 desconocido.

lo que buscas: qué comprobació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 la previsión.

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 incorrecta. 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 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 cotiza en un DEX, o no es Solana. SKIP.
10las rutinas se silenciaron -> Grok Bot pausa las rutinas después de que lleves 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 comprobaciones, con la búsqueda en X activada.

text
1costo_por_token = tokens_entrada / 1_000_000 * precio_por_M_entrada
2 + tokens_salida / 1_000_000 * precio_por_M_salida
3 + publicaciones_obtenidas / 1_000 * 5 # búsqueda en X: $5 por cada 1,000 publicaciones obtenidas
4
5max_turns = 2 mantiene la búsqueda en dos rondas, así que publicaciones_obtenidas se mantiene bajo.
6cada respuesta informa sus propios x_posts_fetched, así que el primer día te da 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 supervivientes, no con el escáner. scan.py puede alimentar al desk con 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.

ejecútalo 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. no es consejo financiero.

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

guarda esto antes de tu próxima compra. sígueme si planeas montar lo mismo, habrá 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