Serie insider·2026-05-04·7 min de lectura·← todos los posts

El bug de timeout: por qué tres posiciones de usuarios se quedaron abiertas 33 horas

Un suscriptor hizo una pregunta simple: "¿por qué estas posiciones en Binance siguen abiertas después de dos días?". La spec de la estrategia definía un tiempo de hold máximo muy por debajo de eso. Las posiciones llevaban abiertas 33 horas. El post-mortem honesto del bug, el fix y lo que nos costó en confianza, sin exponer cómo funciona el modelo subyacente, porque esa parte no es para publicar.

Qué diremos y qué no

El modelo de señales detrás de las operaciones (la investigación quant + IA propietaria e interna de la firma) no se describe aquí. Los inputs, el scoring y el hold máximo que define la spec quedan deliberadamente sin revelar. Lo que sí está sobre la mesa en este post: la ruta de código de la capa de ejecución, el bug y el fix. Esa parte es ingeniería reproducible, no edge.

El descubrimiento

Tres posiciones largas en la cuenta de un suscriptor, abiertas en la misma ventana de la mañana. La spec de la estrategia define un tiempo de hold máximo, tras el cual la posición se cierra a mercado forzosamente sin importar el P&L (porque la tesis subyacente decae pasado ese punto; por diseño, ese horizonte se queda interno).

El cliente notó que las posiciones seguían apareciendo en Binance mucho después del cierre previsto. Abrió la conversación diciendo "¿por qué siguen abiertas?". Ese es el momento exacto en que una firma quant gana o pierde a un cliente. Si hubiéramos sido de esos que se lavan las manos y le echan la culpa a Binance, habríamos sido otra clase de tienda. Nos pusimos a investigar.

El mecanismo

Flujo de ejecución cuando dispara una señal:

  1. El detector emite una señal con moneda, score, lado y entrada sugerida
  2. El executor lo reparte a (a) la cuenta de la firma, (b) todos los suscriptores Pro con esa estrategia activada
  3. Para cada destino del reparto, coloca la entrada a mercado + un SL de emergencia en Binance
  4. Registra la posición con positionMonitor para el timeout específico de la estrategia

El paso 4 es donde vivía el bug. El executor manejaba las operaciones de la firma y las de los usuarios en rutas de código distintas: las de la firma recibían un registro en positionMonitor; las de los usuarios solo se marcaban como status=filled. Ningún registro de timeout para las cuentas de usuario. Binance mantenía la orden SL, pero si el precio nunca alcanzaba el SL ni ningún TP, la posición se quedaría ahí indefinidamente.

Cómo sobrevivió hasta producción

La ruta de ejecución original era solo para la firma. Cuando añadimos la ejecución por usuario hace dos meses, bifurcamos la ruta pero no propagamos la lógica de registro del timeout. Los tests unitarios que escribimos para la ejecución por usuario cubrían "¿se colocó la orden correctamente?" y "¿se registró el SL en Binance?", pero no "¿dispara el timeout de la spec?", porque un test con sentido de eso lleva horas de tiempo real en correr de extremo a extremo, y nos apoyamos en la producción de la firma como red de seguridad.

La producción de la firma nunca disparó el bug porque las posiciones de la firma siempre habían cerrado vía SL o TP dentro de su ventana, por casualidad. La primera vez que las condiciones se alinearon para mantener una posición viva más allá del timeout de la spec fue en una cuenta de usuario: sin registro, en una sesión donde el precio se quedó en un rango que no tocó ni SL ni TP.

El fix

Añadimos un mapa de hold por estrategia en userPositionGuard.js con una comprobación de cierre forzoso por tick. Los valores de hold reales forman parte de la spec de la estrategia y se quedan privados. El mecanismo es sencillo: cada 60 segundos el guard escanea las operaciones de usuario abiertas, compara la antigüedad contra el máximo definido en la spec de la estrategia y fuerza el cierre vía orden de mercado reduceOnly cuando se cruza el umbral.

Desplegado en menos de 20 minutos desde el reporte del cliente. El siguiente tick cazó las tres posiciones atascadas y las cerró a mercado. El P&L neto de las tres quedó casi plano: el coste en dólares del bug fue simbólico. El coste real fue el de la confianza.

El coste real

Un suscriptor que paga por un sistema que define un hold máximo merece un sistema que respete ese hold, no uno que se desvíe a 33 horas más allá. Le contamos al cliente exactamente qué pasó, desplegamos el fix mientras seguía al teléfono y le mostramos los registros cerrados con el PnL calculado en cuanto aparecieron.

El cliente mantuvo su suscripción. Ese es el resultado correcto solo porque lo cazamos a las pocas horas del reporte. Si el mismo bug hubiera golpeado durante un crash de mercado y una posición hubiera aguantado un drawdown del -25% porque no disparó ningún timeout, la conversación habría sido muy distinta.

Qué cambiamos más allá del fix

Por qué publicamos esto

El bug de paridad firma-vs-usuario en la ejecución es justo el tipo de cosa que otros operadores de bots de cripto esconderían. La mayoría de las plataformas funcionan sobre código cerrado, atribución de P&L opaca y "confía en nosotros, el sistema funciona como se anuncia". Cuando algo sale mal, los clientes lo pagan.

Preferimos publicar el bug, el fix y la lección. El modelo en sí se queda en la caja fuerte: esa parte es la IP de la firma y la razón por la que el servicio existe siquiera. Pero el andamiaje de ingeniería a su alrededor debería ser inspeccionable, y cuando se rompe, el post-mortem debería ser público. Ese es el estándar al que nos sometemos.

Ejecución de nivel producción, con las pruebas en la mano

Hedonist Pro auto-ejecuta nuestros algoritmos de señales propietarios en tu cuenta de Binance. Los modelos se quedan privados; la capa de ejecución se somete a post-mortem en público cuando algo sale mal.

Ver precios de Pro →
Aviso de riesgo. Operar con futuros perpetuos de criptomonedas conlleva un riesgo sustancial de pérdida y no es adecuado para todo inversor. Las cifras de backtest son históricas y se calculan bajo supuestos específicos; el rendimiento pasado no es garantía ni proyección de resultados futuros. Consulta la declaración de riesgo completa antes de suscribirte a cualquier servicio de pago.