Tutorial de Bot de Polymarket · Capítulo 20 de 32
Rastrea wallets ballena de Polymarket y haz copy-trading de los mejores desempeños de forma programática: identifica wallets rentables mediante leaderboard y análisis on-chain, y replica sus operaciones con reglas de tamaño y timing.
Qué cubre este capítulo
Copiar wallets ganadoras de Polymarket es una idea popular, pero las ballenas reales en Polymarket en su mayoría hacen arbitraje de cierre de ventana en mercados resueltos, no apuestas direccionales. Este capítulo presenta la investigación honesta a partir de análisis on-chain: qué wallets realmente conviene copiar, por qué la mayoría no vale la pena y cuál es la matemática del dimensionamiento de posición.
- Identificación de wallets rentables
- Detección de operaciones on-chain
- Dimensionamiento de posición en relación con la ballena
- Latencia: qué tan tarde es demasiado tarde
- Filtros: seguir solo wallets con edge verificado
- Código: detectar evento de compra de una ballena, ejecutar una copia dimensionada
Identificación de wallets rentables
La premisa de copiar ballenas es que algunas wallets son consistentemente rentables y copiar sus entradas captura parte de su edge. El análisis on-chain de las principales wallets de Polymarket en 2025-26 produjo un resultado sobrio: la mayoría de las ballenas visibles hacen arbitraje de cierre de ventana en mercados resueltos, no trading direccional.
Perfil que medimos en tres wallets ballena candidatas:
- "hhhhhh6" (98.5% win rate, $n M volume) - 88% de las entradas a precios ≥0.95, timestamp mediano de entrada 226s de una ventana de 300s. Arbitraje puro de rendimiento de cola, no direccional.
- "anonymous" (20% win rate) - jugador degenerado. Copiarlo pierde dinero.
- "Jkim123" (53.5% win rate) - cara o cruz. No es una señal que valga la pena copiar.
0% de las operaciones de estas ballenas ocurrió en los primeros 120s de cualquier ventana de 5 minutos. La señal predictiva (si existe) vendría de entradas grandes en la PRIMERA parte de la ventana, pero esas wallets no son las que están arriba del leaderboard, porque es difícil hacer eso.
Detección de operaciones on-chain
Detectar las operaciones de una wallet objetivo requiere hacer polling al data-api de Polymarket o suscribirse a eventos de transferencia CTF on-chain. La opción del data-api es más simple.
def watch_wallet(wallet_addr, last_seen_ts=0):
while True:
url = f"https://data-api.polymarket.com/activity?user={wallet_addr}&limit=100"
events = requests.get(url).json()
for ev in events:
ts = int(ev.get("timestamp", 0))
if ts <= last_seen_ts: continue
if ev["type"] == "TRADE":
process_whale_trade(ev)
last_seen_ts = max(last_seen_ts, ts)
time.sleep(5)
El polling cada cinco segundos es el piso práctico para el data-api. Menos que eso y te toparás con rate limits. Para detección subsegundo, suscríbete a eventos on-chain ERC-1155 TransferSingle del contrato CTF filtrados por la dirección proxy de la ballena.
Dimensionamiento de posición en relación con la ballena
Si dimensionas tu copia como una fracción constante de la operación de la ballena, heredas su perfil de riesgo. Dos alternativas prácticas.
- Basado en tope: dimensiona cada copia a un monto fijo en dólares ($10-50) sin importar el tamaño de la ballena. Más lento para compounding, pero con pérdida acotada por operación.
- Ponderado por win rate: dimensiona la copia como función del win rate reciente de la ballena. WR de 60%+ → copia de tamaño completo; 40-60% → copia a la mitad; por debajo de 40% → omitir.
El enfoque basado en tope es el despliegue inicial más seguro. Pásate al ponderado por win rate solo después de medir el win rate real de la ballena en TUS copias (que normalmente es peor que su número titular porque llegas tarde).
Latencia: qué tan tarde es demasiado tarde
La operación de la ballena es visible públicamente dentro de 1-2 segundos de ejecutarse. Copiarla requiere una latencia de lectura más rápida que eso, más tu propia latencia al colocar la orden.
Extremo a extremo para un bot de copy típico: polling de 5-10 segundos + 200ms para colocar la orden = 5-15 segundos en total. Para cuando tu copia se dispara, la señal de la ballena ya está incorporada en el precio.
Para el 99% de las copias, esto es demasiado tarde en los mercados estrechos de Polymarket. La entrada de la ballena movió el mid 1-2 centavos; tú pagas esa prima de 1-2 centavos respecto a donde entró. Si su edge era de 3c, la mitad ya se perdió cuando llegas.
Los bots de copy que funcionan o bien (a) apuntan a mercados de movimiento lento donde 30s de latencia no importan, o bien (b) usan suscripción a eventos on-chain para reaccionar en tiempos subsegundo.
Filtros: seguir solo wallets con edge verificado
Tres filtros antes de agregar cualquier wallet a tu lista de copy.
- 30+ operaciones cerradas en el historial de la wallet. Muestras más pequeñas son ruido.
- Win rate de por vida > 60%, O valor esperado positivo por operación basado en precios de entrada. Cualquiera de las dos condiciones; ambas es mejor.
- El patrón NO es arbitraje de cierre de ventana. Revisa los segundos medianos hasta resolución al momento de la entrada; si está cerca de 0, la wallet está haciendo arbitraje de rendimiento de cola que no puedes reproducir.
La mayoría de las ballenas candidatas falla uno de estos tres. El pool de wallets realmente copiables es pequeño. Mantener la lista requiere revalidación periódica: wallets que fueron rentables el mes pasado puede que no lo sean este mes.
Código: detectar evento de compra de una ballena, ejecutar una copia dimensionada
Referencia: detectar un evento TransferSingle de CTF para una ballena monitoreada, disparar una compra copia dimensionada.
from web3 import Web3
w3 = Web3(Web3.WebsocketProvider(POLYGON_WSS))
ctf = w3.eth.contract(address=CTF_ADDR, abi=CTF_ABI)
WHALES = {"0xabc...": {"fraction": 0.05, "cap": 50}}
def on_transfer(event):
to = event.args["to"].lower()
if to not in WHALES: return
cfg = WHALES[to]
token_id = event.args.id
whale_size = event.args.value / 1e6
copy_size = min(cfg["cap"], whale_size * cfg["fraction"])
if copy_size < 5: return # not worth fees
book = fetch_book(str(token_id))
if book.best_ask:
place_fok(str(token_id), "BUY", book.best_ask + 0.01, copy_size)
# subscribe to ERC-1155 TransferSingle events from CTF
filt = ctf.events.TransferSingle.create_filter(fromBlock="latest")
while True:
for ev in filt.get_new_entries(): on_transfer(ev)
time.sleep(0.5)
Distingue compra de venta revisando from (zero address = mint = la ballena compró) vs to (zero address = burn = vendido).





