cryptomoney rechaza floats y obliga a declarar el redondeo al parsear importes
La librería de Python trata cada cantidad como texto hostil: si el activo no puede representarla, el parser falla, y redondear exige nombrar el modo en el punto de llamada.

Hay una decisión que casi todo el código que maneja dinero toma sin darse cuenta: qué hacer cuando la cantidad que llega no cabe en el activo. La librería cryptomoney, escrita en Python, la resuelve en el parser y su respuesta por defecto es negarse. Si alguien escribe 0,000000001 BTC, parse_amount lanza ParseError en vez de truncar a ocho decimales por el camino hacia la columna NUMERIC(18, 8).
El autor lleva desde 2018 construyendo carteras custodiales, rampas fiat-cripto y libros de órdenes, y su tesis es que el redondeo es una política que se declara antes de calcular, no un residuo que aparece después. La diferencia entre lo pedido y lo registrado acaba saliendo mucho más tarde como descuadre de conciliación que nadie sabe atribuir.
El redondeo se nombra donde se llama
La librería acepta lo que llega en una petición real: espacios, signo, separadores de miles, notación exponencial y el símbolo del activo delante, detrás o pegado al número. parse_amount("1.25e3", USDT) devuelve 1250 USDT. Lo que no acepta es texto que no describa exactamente una cantidad de un activo, ni una cantidad más fina de lo que el activo admite. Redondear sí se puede, pero no es gratis: hay que nombrar el modo en el punto de llamada, con rounding=ROUND_DOWN, en la ruta de código donde se sabe qué significa esa cantidad. Un motor de cotizaciones que trunca un tipo mostrado y un endpoint de retirada que no puede crear valor de la nada son dos sitios distintos y no deberían heredar el valor por defecto que eligió el autor de la librería.
Los float se rechazan
parse_amount(0.5, BTC) lanza TypeError, y el motivo no es el purismo. Ese float viene de un decodificador JSON que convirtió el texto del emisor en un doble binario antes de que el código lo viera; los dígitos originales ya no están, y con ellos se fue la capacidad de saber si la cantidad era representable. Un parser que acepta float no está parseando, está blanqueando una decisión que ya se tomó mal más arriba. La misma regla vale al construir un Money: Money(0.1, BTC) falla, y Money("1", BTC) + Money("1", ETH) lanza CurrencyMismatch.
La precisión es una propiedad del activo, así que el activo es un objeto de valor congelado (symbol, decimals) que valida lo que recibe y no admite que decimals sea None. El paquete trae un registro de activos comunes, pero es una comodidad, no una autoridad: el mismo símbolo tiene precisiones distintas según dónde se emita. El parser también limita la longitud de la entrada y el rango del exponente, porque un exponente sin tope en aritmética decimal es una forma de que un solo campo reserve una cantidad enorme de memoria. Cualquier parser que vaya a correr contra entrada pública necesita el equivalente.
Lo que esto le pide al código de frontera es incómodo y pequeño: entregar el texto crudo. En HTTP, un decodificador configurado para dejar los números como cadenas, o un esquema que declare el campo como string. Fricción en un único sitio a cambio de que cada Money del sistema haya sido comprobado contra su activo al nacer.

