Esto cierra una breve serie sobre la construcción de Freya Finance. En lugar de repetir los artículos, esto es lo que realmente me diría a mí mismo al principio, ordenado por cuánto costó aprender cada lección.
El hilo común es incómodo: casi ninguno de estos fallos se anunció a sí mismo. Produjeron números plausibles, órdenes de aspecto válido y pantallas que parecían correctas. En un sistema que actúa sobre el dinero de alguien, el bug que lanza una excepción es del tipo amable.
Puntos clave
- Las API de terceros fallan en silencio. Un HTTP 200 que trae menos datos de los que pediste es el modo de fallo contra el que debes diseñar, no el 500.
- Prueba el simulador antes de probar cualquier cosa que simule. Un simulador roto devuelve números que se ven exactamente igual que los correctos.
- Reporta lo que no pudiste simular. Un resultado con una laguna declarada vale más que un resultado de aspecto impecable que descartó una condición en silencio.
- La precisión es un dominio, no una función de utilidad. Los tamaños de paso, los tamaños de tick y los mínimos difieren según el par, según el exchange y según el tipo de mercado.
- Elige tus restricciones temprano. Decidir no custodiar nunca los fondos del usuario eliminó toda una categoría de problemas en lugar de resolverlos.
- En una interfaz de dinero, audita los gestos que la plataforma trata como ediciones. La rueda del ratón sobre un campo numérico enfocado es uno de ellos.
1. Asume que toda API tiene éxito de forma incorrecta a veces
La suposición más cara que hice fue que una petición fallida se vería como un fallo.
Los exchanges bajo carga devuelven HTTP 200 con menos velas de las solicitadas, sin campo de error, sin advertencia. Uno de nuestros backtests profundos pidió aproximadamente 536,000 velas y recibió 58,000. La misma petición una hora después devolvió el conjunto completo. Nada en la respuesta distinguía a las dos.
Si no lo estás verificando, el motor simula una estrategia sobre una fracción del historial previsto y reporta un número con confianza. Eso es peor que un fallo total, porque un fallo total es honesto.
De ahí salieron dos reglas: valida la forma de una respuesta exitosa, no solo su código de estado, y distingue los fallos transitorios de los permanentes antes de decidir qué hacer. Se ven idénticos en el momento en que ocurren y merecen respuestas opuestas.
Historia completa: lo que subestimé
2. Prueba el simulador, no la estrategia
Todo instinto te empuja a probar la lógica de la estrategia, porque esa es la parte interesante. La trampa es que un simulador roto produce una salida indistinguible de la de uno que funciona. Una ejecución que procesó en silencio una décima parte de los datos igual devuelve un número. Una ejecución cuyas salidas nunca se evaluaron devuelve uno sospechosamente plano.
El cambio que arregló esto fue hacer aserciones sobre cosas que la estrategia no puede cambiar: que las velas procesadas coincidan con las velas obtenidas, que una ejecución sobre un período conocido realmente lo abarque, que una configuración con activación garantizada produzca operaciones.
Cuando esos invariantes se cumplen, un resultado extraño es un hallazgo real. Cuando no se cumplen, el resultado es ruido vestido de traje.
3. Reporta lo que no pudiste simular
Esta es una decisión de diseño más que un bug, y creo que es la más infravalorada.
Algunas condiciones no se pueden reproducir. Una señal externa de webhook no tiene registro histórico. El movimiento tentador es omitirla y evaluar el resto, lo que hace que la salida parezca completa.
Mira lo que eso le hace a una estrategia que requiere A Y B. Si B no se puede simular, A decide sola, así que el bot simulado entra donde el real se habría quedado fuera. El error no es aleatorio: descartar una condición bajo lógica AND solo puede producir más operaciones que la realidad, así que el sesgo apunta a un resultado de mejor apariencia cada vez.
Seguimos ejecutando la simulación, pero el resultado lleva una advertencia explícita que nombra lo que se omitió. Un simulador que no puede fallar de forma ruidosa fallará en silencio, y el fallo silencioso en algo que produce números es el peor modo de fallo que existe.
Historia completa: por qué mienten los backtests
4. Una curva de capital suave es una pregunta, no una respuesta
Relacionado, y vale la pena separarlo porque engaña a los humanos más que al código.
Una escalera de órdenes de seguridad DCA sin stop loss casi nunca materializa una pérdida. Aguanta y añade. Así que las operaciones cerradas son casi todas ganadoras, la tasa de acierto se ve excelente y la curva de capital es una escalera ordenada.
El riesgo no desapareció. Fue diferido, y el aplazamiento tiene un límite rígido: el capital que queda para más órdenes de seguridad. La pregunta útil no es «cuál fue el drawdown» sino «si el precio sigue yendo en contra, ¿en qué punto la estrategia se queda sin margen?».
El drawdown en sí necesita el mismo escepticismo. Se mide contra el capital asignado en su punto máximo, así que la misma pérdida de 200 USDT aparece como 40% sobre una asignación de 500 USDT y 4% sobre 5,000. Dos bots operando de forma idéntica pueden mostrar números tremendamente diferentes.
Historia completa: entender el drawdown
5. La precisión es un dominio, no un ayudante
Archivé «redondear cantidades a pasos válidos» como una sola función de utilidad. Es una categoría de trabajo, y se esconde en un lugar donde los errores cuestan dinero.
El punto flotante lo inicia: escalar 0.29 por un paso de 0.01 da 28.999999999999996, que se redondea hacia abajo un paso completo de más, en silencio, hacia una orden más pequeña.
Luego los exchanges no se ponen de acuerdo sobre las reglas mismas. Uno verifica el valor de la orden en USDT, otro verifica el número de contratos sin ninguna verificación de valor, otro verifica ambos. Nuestro peor bug en esta área vino de inventar un mínimo que un exchange no tiene, y luego rechazar órdenes válidas contra él. La señal, en retrospectiva, era que nuestra versión de la restricción dependía del precio mientras que la real no.
En cualquier lugar donde escribas una sola constante para algo que el exchange define por par, estás escribiendo un bug con una mecha de retardo.
Historia completa: el punto flotante te costará dinero
6. Elige tus restricciones temprano
La última no es un error. Es una decisión cuyas consecuencias subestimé para bien.
Freya nunca custodia los fondos de trading del usuario. Las claves llevan permiso de lectura y de trading, nunca de retiro, y una clave que llega con permiso de retiro se rechaza en lugar de aceptarse e ignorarse. Esa distinción importa más de lo que suena: «no retiraremos» es una afirmación sobre nuestro comportamiento que un usuario no puede verificar, mientras que «la clave no puede retirar» lo impone el exchange y el usuario puede comprobarlo en sus propios ajustes.
Esperaba que esto fuera un argumento de marketing. Resultó ser arquitectónico, e hizo el sistema más pequeño: sin libro mayor de custodia, sin conciliación, sin cola de retiros, sin política de almacenamiento en frío para el capital de trading. Toda una clase de los problemas más difíciles del software financiero está ausente porque nunca asumimos aquello que los crea.
Lo que lo reemplaza es más estrecho y más afilado: el sistema tiene que ser correcto en tiempo real, porque nunca puede deshacer nada. Una orden ejecutada en la cuenta de exchange de otra persona es definitiva.
Historia completa: diseñar trading no custodial
La que no esperaba necesitar
Una lección extra, porque fue la que más me sorprendió: en una interfaz de dinero, el front-end necesita la misma paranoia que el motor.
Un <input type="number"> enfocado incrementa su valor cuando desplazas la rueda sobre él. En un selector de cantidad eso es una molestia. En el apalancamiento, el tamaño de orden y el precio reescribe en silencio lo que el usuario eligió, y el formulario igual valida. Nada de ese bug es visible en una captura de pantalla.
Historia completa: la rueda del ratón está editando tus campos numéricos
Si comprimiera todo en una sola línea
Diseña para los fallos que no se anuncian a sí mismos. Los que lanzan excepciones te encontrarán solos.
