37.1 Objetivo del proyecto
Construiremos una calculadora capaz de recibir distintas cotizaciones financieras, transformarlas a una representación común, trasladar un capital entre fechas y consolidar varios flujos en una fecha focal.
El proyecto no consiste solo en obtener números. Debe conservar unidades, rechazar datos fuera de dominio, explicar las convenciones utilizadas y permitir comprobar cada resultado.
Decisión de diseño: todas las operaciones compartirán un factor efectivo anual positivo. Esta representación canónica evita programar una fórmula distinta para cada combinación posible.
37.2 Tres capacidades integradas
Normalizar tasas
Convertir interés, descuento, tasas nominales y fuerza a un factor anual.
Trasladar capitales
Llevar un importe hacia adelante o atrás entre dos fechas.
Valuar carteras
Sumar flujos firmados después de ubicarlos en una fecha focal común.
37.3 Alcance y convenciones
Las fechas se expresan en años y las frecuencias indican subperíodos por año. Las tasas ingresadas se muestran como porcentajes, pero el motor las convierte a tanto por uno.
Los capitales positivos representan cobros o activos; los negativos, pagos o pasivos. El modelo supone una ley multiplicativa constante durante el horizonte analizado.
37.4 Flujo de información
Cada etapa recibe una salida ya validada de la anterior. Si la cotización no produce un factor admisible, ninguna valuación posterior debe ejecutarse.
37.5 El factor anual como representación canónica
Definimos F como el monto que produce una unidad monetaria después de un año:
Con crecimiento positivo, F>1; sin variación, F=1; con disminución, 0<F<1. Una vez conocido F, todas las cotizaciones equivalentes describen el mismo crecimiento anual.
37.6 Tasa efectiva de interés subperiódica
Si i es efectiva por subperíodo y hay m subperíodos por año:
El dominio exige i>−1. Una tasa mensual efectiva se carga con frecuencia 12; una trimestral, con frecuencia 4.
37.7 Tasa efectiva de descuento subperiódica
Si d es descuento efectivo por subperíodo:
Se requiere d<1. La base 1−d es el factor de actualización por subperíodo, no el factor de acumulación.
37.8 Tasa nominal anual vencida
Para una tasa nominal anual j(m) convertible m veces al año:
La división por la frecuencia obtiene la tasa efectiva de cada conversión. La tasa nominal no se introduce directamente como tasa periódica.
37.9 Tasa nominal anual anticipada
Para una nominal de descuento f(m) convertible m veces:
Su dominio exige f(m)/m<1. La frecuencia forma parte inseparable de la cotización.
37.10 Fuerza de interés
Con fuerza anual constante δ:
La frecuencia no interviene. A la inversa, cualquier factor anual positivo tiene una fuerza equivalente δ=ln(F).
37.11 Cotizaciones equivalentes de salida
Elegida una frecuencia objetivo q, el motor puede reconstruir:
iq=F1/q−1 · j(q)=q·iq
dq=1−F−1/q · f(q)=q·dq
Todas estas salidas son equivalentes porque reconstruyen exactamente el mismo F.
37.12 Ejemplo de normalización
Una TNA vencida del 36 % convertible mensualmente produce:
TEA≈42,576089 %
Ese factor, y no el 36 % aislado, es la entrada común para los módulos de capitales y carteras.
37.13 Factor entre dos fechas
Si t₀ y t₁ se miden en años:
Un exponente positivo capitaliza, uno negativo actualiza y uno nulo deja el importe sin cambios. Esta fórmula única evita ramificaciones innecesarias.
37.14 Capital equivalente
El capital C₀ situado en t₀ equivale en t₁ a:
Para verificar, se traslada el resultado hacia atrás: C₁F^(t₀−t₁) debe reconstruir C₀ dentro de la tolerancia numérica.
37.15 Carteras de flujos firmados
Una cartera se representa como pares {importe, fecha}. Su valor en la fecha focal f es:
Cada flujo conserva su signo. Solo después de trasladar todas las contribuciones a la misma fecha se realiza la suma.
37.16 Capital único sustituto
El valor focal V(f) es, por construcción, el capital único ubicado en f que sustituye a toda la cartera.
Si resulta negativo, el sustituto es un pago neto; si es positivo, un cobro neto. Cambiar el signo para mostrar un número positivo alteraría el sentido financiero.
37.17 Ejemplo integrado
Con la TNA del 36 % convertible mensualmente se valúan en el año 1,5 cuatro flujos: $100.000 en 0, −$30.000 en 0,5, $80.000 en 1,25 y −$25.000 en 2.
+80.000F0,25−25.000F−0,5
La calculadora del apartado 37.28 reproduce el resultado y muestra cada contribución para poder auditar la suma.
37.18 Invariancia de la fecha focal
Bajo una ley multiplicativa, el valor de la cartera calculado en otra fecha debe ser el traslado global del primero:
Esta propiedad proporciona una prueba potente. No significa que los importes focales sean iguales: significa que son equivalentes.
37.19 Coherencia temporal
La aplicación adopta años como unidad canónica. Una fecha de 18 meses debe ingresarse como 1,5 años. Si se prefieren meses, todas las fechas y el factor deben transformarse de manera coherente.
Asignar frecuencia 12 no convierte automáticamente las fechas ingresadas en meses. La frecuencia describe la cotización; la unidad de las fechas pertenece al módulo de valuación.
37.20 Validación por modalidad
| Cotización | Restricción | Motivo |
|---|---|---|
| Interés efectivo | i>−1 | La base debe ser positiva. |
| Descuento efectivo | d<1 | El factor de actualización debe ser positivo. |
| Nominal vencida | j/m>−1 | La tasa por conversión define la base. |
| Nominal anticipada | f/m<1 | El descuento por conversión debe ser menor que uno. |
| Fuerza | Finita | exp(δ) siempre es positivo. |
37.21 Valores finitos y desbordamientos
Superar una validación algebraica no garantiza que el resultado quepa en un número de JavaScript. Tasas, frecuencias o horizontes extremos pueden producir Infinity o un valor tan pequeño que pierda precisión.
Después de cada transformación se comprueba Number.isFinite. El sistema informa el problema y no presenta un resultado parcial como válido.
37.22 Precisión y formato
El motor conserva números sin redondear. La interfaz aplica formato porcentual o monetario únicamente al mostrar. Así, una salida puede alimentar otro módulo sin incorporar el redondeo visible.
Para importes se muestran centavos; para tasas y factores, más decimales. Una aplicación contractual podría permitir configurar ambas precisiones.
37.23 Separación entre cálculo e interfaz
Funciones puras como factorAnual, cotizacionesDesdeFactor y valorFocal no deberían leer controles ni modificar la página. Reciben datos y devuelven resultados.
La capa de interfaz se ocupa de leer, convertir porcentajes, capturar errores y renderizar. Esta separación facilita pruebas y reutilización.
37.24 Modelo de datos
Una cotización completa necesita tipo, tasa y frecuencia. Un flujo necesita importe, fecha y, en una aplicación mayor, identificador y descripción.
const cotizacion = {
tipo: "nominal-interest",
tasa: 0.36,
frecuencia: 12
};
const flujos = [
{ importe: 100000, fecha: 0 },
{ importe: -30000, fecha: 0.5 },
{ importe: 80000, fecha: 1.25 }
];Los nombres explícitos reducen errores de posición que aparecen al usar arreglos anónimos como [0.36,12,"n"].
37.25 Actualización reactiva
Todos los controles disparan una misma actualización. El proceso vuelve a leer los datos, normaliza la cotización y reconstruye los módulos dependientes.
Como el cálculo es pequeño, no hace falta optimización prematura. La prioridad es evitar estados incoherentes donde una sección conserve resultados pertenecientes a entradas anteriores.
37.26 Accesibilidad y comunicación
Cada control tiene una etiqueta asociada; las tablas poseen encabezados y el estado final utiliza aria-live. Los errores se comunican con texto, no solo mediante color.
Las unidades aparecen en los rótulos. Los resultados indican si representan tasas, factores, años o importes monetarios.
37.27 Estrategia de manejo de errores
- Leer todos los controles y rechazar campos vacíos.
- Validar frecuencia, dominio de la modalidad y fechas.
- Construir el factor anual y verificar que sea positivo y finito.
- Calcular las cotizaciones equivalentes.
- Trasladar el capital y verificar el viaje de regreso.
- Valuar cada flujo antes de sumar la cartera.
- Si algo falla, limpiar todas las salidas dependientes.
37.28 Laboratorio: calculadora integradora
La cotización elegida alimenta simultáneamente los tres módulos. Las fechas se expresan en años y la frecuencia objetivo solo controla cómo se muestran las tasas equivalentes.
Motor de equivalencias financieras
Una cotización, un factor canónico y varias operaciones verificables.
1. Cotización y equivalencias
2. Traslado de un capital
3. Cartera y capital único
| Flujo | Importe | Fecha | Exponente | Factor | Valor focal |
|---|---|---|---|---|---|
| Capital único en la fecha focal | $193.951,53 | ||||
La cotización fue normalizada y todas las equivalencias fueron verificadas.
37.29 Núcleo de cálculo en JavaScript
function factorAnual({ tipo, tasa, frecuencia = 1 }) {
if (!Number.isFinite(tasa) || !Number.isFinite(frecuencia) || frecuencia <= 0) {
throw new RangeError("Cotización no válida");
}
let factor;
if (tipo === "effective-interest" && tasa > -1)
factor = Math.exp(frecuencia * Math.log1p(tasa));
else if (tipo === "effective-discount" && tasa < 1)
factor = Math.exp(-frecuencia * Math.log1p(-tasa));
else if (tipo === "nominal-interest" && tasa / frecuencia > -1)
factor = Math.exp(frecuencia * Math.log1p(tasa / frecuencia));
else if (tipo === "nominal-discount" && tasa / frecuencia < 1)
factor = Math.exp(-frecuencia * Math.log1p(-tasa / frecuencia));
else if (tipo === "force")
factor = Math.exp(tasa);
else
throw new RangeError("Tasa fuera del dominio de la modalidad");
if (!Number.isFinite(factor) || factor <= 0)
throw new RangeError("El factor anual no es representable");
return factor;
}
function trasladar(capital, origen, destino, factor) {
return capital * Math.exp((destino - origen) * Math.log(factor));
}
function valorFocal(flujos, foco, factor) {
return flujos.reduce(
(total, flujo) => total + trasladar(flujo.importe, flujo.fecha, foco, factor),
0
);
}
const F = factorAnual({ tipo: "nominal-interest", tasa: 0.36, frecuencia: 12 });
console.log({ F, equivalente: trasladar(100000, 0.25, 1.5, F) });37.30 Pruebas indispensables
- Identidad: trasladar entre la misma fecha devuelve el capital original.
- Ida y vuelta: trasladar a otra fecha y regresar reconstruye el importe.
- Equivalencia: cada cotización de salida recompone el mismo factor anual.
- Fuerza cero: produce factor uno y tasa efectiva cero.
- Cartera vacía: tiene valor focal cero.
- Signos opuestos: dos flujos equivalentes se cancelan en el foco.
- Dominios: las fronteras de −100 % o 100 % se rechazan según la modalidad.
- Valores extremos: ningún resultado infinito llega a la presentación.
37.31 Extensiones posibles
El núcleo puede crecer para admitir fechas calendario y bases de días, tasas por tramos, curvas de descuento, importación de flujos, monedas, inflación, cálculo de incógnitas y exportación de auditorías.
Cada extensión debería preservar el contrato actual de las funciones o incorporarse como una estrategia explícita. Agregar condiciones aisladas dentro de una función única vuelve difícil verificar el sistema.
37.32 Errores frecuentes del proyecto
- Usar el porcentaje como factor: 36 % no equivale a
1,36en todas las modalidades. - Perder la frecuencia: una tasa nominal queda incompleta.
- Mezclar años y meses: altera los exponentes temporales.
- Actualizar todos los capitales: los anteriores al foco deben capitalizarse.
- Eliminar signos negativos: cambia la posición neta de la cartera.
- Redondear el factor común: hace divergir módulos que deberían coincidir.
- Dejar resultados anteriores tras un error: muestra un estado incoherente.
- Probar solo el caso feliz: no cubre fronteras ni datos no finitos.
37.33 Ejercicio final
Ingresá una tasa nominal anual anticipada del 32 % convertible trimestralmente y frecuencia objetivo 12. Convertíla a TEA, descuento efectivo anual, fuerza anual y nominal vencida mensual. Luego trasladá $250.000 del año 0,5 al año 2 y valuá en el año 1 una cartera formada por $120.000 en 0, −$75.000 en 0,75 y $160.000 en 1,5.
Guía de solución
const f = 0.32;
const m = 4;
const F = (1 - f / m) ** (-m);
const tea = F - 1;
const descuentoAnual = 1 - 1 / F;
const fuerza = Math.log(F);
const nominalMensual = 12 * (F ** (1 / 12) - 1);
const capital = 250000 * F ** 1.5;
const cartera = 120000 * F
- 75000 * F ** 0.25
+ 160000 * F ** -0.5;
console.log({ F, tea, descuentoAnual, fuerza, nominalMensual, capital, cartera });Verificá cada resultado reconstruyendo el factor anual y trasladando tanto el capital como el valor de la cartera a una segunda fecha.
37.34 Para recordar
- Una representación canónica reduce la cantidad de conversiones necesarias.
- El factor anual conecta interés, descuento, nominales y fuerza.
- Un exponente firmado traslada capitales en ambas direcciones.
- Los flujos se suman únicamente después de llevarlos a una fecha común.
- Las funciones de cálculo deben estar separadas de la interfaz.
- Validar dominio y finitud es parte del algoritmo financiero.
- La precisión se conserva internamente y el formato se aplica al final.
- Todo resultado importante debe admitir una verificación independiente.