DEV Community

Jesus Corredor
Jesus Corredor

Posted on

El día que descubrí que mi bot no tenía las protecciones que creía tener

Diario de un bot que opera con dinero real — Entrada #3

Durante varios días, mi bot de trading creyó tener órdenes de stop-loss que en realidad no existían en el exchange.

No fallaban de forma visible. En los registros, cada posición tenía su stop "gestionado". El bot estaba convencido de que cada operación tenía su red de seguridad. Pero esa red no estaba donde debía estar: en Binance.

En ese tiempo, posiciones apalancadas —donde una caída fuerte puede liquidarte— operaron sin la protección que yo creía activa. Si el bot se caía en el momento equivocado, no había nada abajo.

Esta es la tercera entrada de la serie, y la más inquietante. No fue un bug ruidoso ni un componente fantasma. Fue peor: la plataforma cambió las reglas —lo anunció, pero yo no lo vi— y mi bot siguió reportando que todo estaba bajo control mientras, en el exchange, las posiciones corrían desnudas.

El síntoma: un error que no debería existir

Todo comenzó con un mensaje nuevo en los registros al intentar colocar un stop:
HTTP 400 | code: -4120 | Order type not supported for this endpoint.
Please use the Algo Order API endpoints instead.

Mi código enviaba la orden de la forma que, según tutoriales y ejemplos, era la correcta. Entonces, ¿por qué Binance rechazaba algo que medio internet daba por válido?

La pista incómoda: mi código estaba bien escrito, pero el contrato había cambiado. Cuando tu petición es correcta y aun así la rechazan, el problema no está solo en tu lado: está en que las reglas del otro extremo ya no son las mismas.
La investigación: lo que el bot creía vs. lo que pasaba


Binance había migrado las órdenes condicionales (stop-loss, take-profit, trailing stop) al nuevo "Algo Order API". El endpoint viejo quedó bloqueado para esos casos. El cambio estaba en el changelog oficial semanas antes, pero yo no lo vi.

(Nota: no fui el único en chocar con esto. Cuando Binance hizo el cambio —a finales de 2025—, frameworks de trading enteros como Freqtrade y nautilus_trader amanecieron con exactamente este error, documentado en sus repos de GitHub. En mi caso llegué tarde a la fiesta: mi bot empezó a operar después del cambio, así que heredé el problema sin saberlo. Mi código enviaba las órdenes al endpoint viejo —que ya no servía para stops— desde el primer día, y yo creía que las protecciones se colocaban. Hasta que un día revisé de verdad y descubrí que nunca habían estado ahí.)

Lo más grave no era el error -4120 visible. Era lo que pasaba por debajo: el bot sí calculaba y llevaba el stop en su propio estado interno —tenía su nivel de salida bien definido—, pero ese stop vivía solo en la memoria del bot, no en el exchange. En la interfaz de Binance, el campo de protección de esas posiciones decía, literalmente, -- / --. Mientras el bot corriera, la gestión interna disimulaba el problema. Pero un reinicio, una caída, un corte de red en el momento equivocado, y la posición se quedaba sin absolutamente nada que la protegiera. Yo creía tener una red de seguridad en dos capas; en realidad tenía media.
Por qué esto es peor que un bug normal

Un bug propio lo puedes leer, probar y arreglar. Pero cuando dependes de una API externa, una parte de tu sistema vive en un servidor que no controlas. Pueden cambiar un endpoint, un parámetro o una validación, y tu código —sin modificar una sola línea— empieza a comportarse distinto.

El fallo más peligroso no es el error claro, sino la falsa confianza: cuando crees que tienes una protección y en realidad no está donde importa. Un stop que vive solo en tu código, pero no en el exchange, es exactamente eso — una red pintada en el suelo.
El fix: migrar y verificar de verdad

La solución tuvo dos pasos.

Migrar al nuevo endpoint: reescribir la lógica de stops y trailing para usar /algoOrder, con los parámetros que ahora espera. Marqué cada cambio con la etiqueta [ALGO-MIGRATION] para que en el futuro yo —o quien lea el código— sepa qué se movió y por qué. Para las posiciones que ya estaban corriendo sin stop nativo, escribí un script que las recorrió una por una y les colocó retroactivamente la protección que les faltaba.

Verificar la existencia real de la orden: dejar de confiar en que "el bot lo tiene gestionado" o en que "no dio error" signifique que la protección existe. Ahora el bot consulta directamente al exchange si la orden está viva. Solo cuando Binance confirma que el stop está ahí, el bot lo da por colocado. Hay una diferencia enorme entre "mi petición no dio error" y "la orden está viva en el exchange". El bug vivía justo en esa brecha.

La lección para llevarte

"No dio error" no es lo mismo que "funcionó". Verifica el efecto, no la ausencia de queja.

Si construyes sobre APIs de terceros —y hoy casi todo software lo hace—, esta historia deja tres recordatorios:

No controlas tus dependencias externas. El código que llama a una API vive a medias en un servidor ajeno. Pueden cambiar las reglas —a veces lo avisan en un changelog que nadie lee, a veces el aviso pasa desapercibido— y tu código intacto empezará a comportarse distinto. Cuando el comportamiento cambia pero tu código no, mira hacia afuera: al otro extremo de la conexión, y a los canales donde esa plataforma anuncia sus cambios.

Lee los changelogs de tu exchange — no hacerlo es un error muy común. Binance (y cualquier exchange serio) publica sus cambios de API en un changelog oficial, a veces con semanas de aviso. Este cambio estaba anunciado ahí. Pero casi nadie lo lee: montas el bot, funciona, y te olvidas de que del otro lado hay un equipo cambiando cosas. Yo no lo leía. Freqtrade y nautilus_trader tienen equipos enteros y aun así los pilló. La información estaba disponible; solo que nadie la miró a tiempo. Revisar el changelog cada cierto tiempo —o, mejor, automatizar una alerta cuando cambie— convierte una sorpresa silenciosa en un aviso con margen para reaccionar.

Verifica el efecto, no la respuesta. No asumas que algo se hizo porque la llamada no lanzó una excepción, ni porque tu propio código "lo tiene controlado". Si la operación importa —una orden de protección, un pago, un cambio de permisos— confirma que el efecto realmente ocurrió en el sistema externo, no en tu versión de la realidad.

Ese día entendí que lo más frágil de mi sistema no era mi código, sino el supuesto de que la API seguiría igual que la última vez que la revisé —y que mi estado interno reflejaba el del exchange. Ninguna de las dos cosas era cierta. Y mi bot había estado operando con una red de seguridad imaginaria.

En la próxima entrada empieza la parte más incómoda de todo el viaje. Descubrí que mi herramienta de backtest —la que usaba para decidir si una estrategia servía— me estaba mintiendo. Tenía un "edge" fabuloso… en un horario en el que el bot ni siquiera operaba. Cómo una sola línea mal ajustada en el tiempo puede convertir meses de "resultados prometedores" en un espejismo.

¿Alguna vez una API de terceros cambió bajo tus pies y te enteraste tarde? ¿Cómo lo detectaste? Cuéntamelo en los comentarios.

Top comments (0)