37. Proyecto integrador: calculadora de tasas, descuentos y capitales equivalentes

El cierre del curso reúne las conversiones y ecuaciones de valor en una aplicación que usa un factor común, valida dominios y deja cada resultado listo para ser verificado.

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

1

Normalizar tasas

Convertir interés, descuento, tasas nominales y fuerza a un factor anual.

2

Trasladar capitales

Llevar un importe hacia adelante o atrás entre dos fechas.

3

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

Cotizacióntipo, tasa y frecuencia
→
Factor anualrepresentación común
→
Factor temporalsegún distancia de fechas
→
Valor equivalentecapital o cartera

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:

F=a(1) > 0

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:

F=(1+i)m

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:

F=(1−d)−m

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:

F=(1+j(m)/m)m

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:

F=(1−f(m)/m)−m

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 δ:

F=eδ

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:

TEA=F−1  ·  da=1−1/F  ·  δ=ln(F)
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:

F=(1+0,36/12)12≈1,425760887
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:

A(t₀,t₁)=Ft₁−t₀

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:

C₁=C₀Ft₁−t₀

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:

V(f)=Σ CkFf−tk

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.

V(1,5)=100.000F1,5−30.000F1
+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:

V(g)=V(f)Fg−f

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ónRestricciónMotivo
Interés efectivoi>−1La base debe ser positiva.
Descuento efectivod<1El factor de actualización debe ser positivo.
Nominal vencidaj/m>−1La tasa por conversión define la base.
Nominal anticipadaf/m<1El descuento por conversión debe ser menor que uno.
FuerzaFinitaexp(δ) 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

  1. Leer todos los controles y rechazar campos vacíos.
  2. Validar frecuencia, dominio de la modalidad y fechas.
  3. Construir el factor anual y verificar que sea positivo y finito.
  4. Calcular las cotizaciones equivalentes.
  5. Trasladar el capital y verificar el viaje de regreso.
  6. Valuar cada flujo antes de sumar la cartera.
  7. 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

Factor efectivo anual1,425760887
Tasa efectiva anual42,576089 %
Descuento efectivo anual29,862 %
Fuerza anual0,354706
Interés efectivo objetivo9,2727 %
Nominal vencida objetivo37,0908 %
Descuento efectivo objetivo8,4859 %
Nominal anticipada objetivo33,9436 %

2. Traslado de un capital

Distancia firmada1,250000 años
Factor del traslado1,557967417
Capital equivalente$155.796,74
Error al regresar$0,00

3. Cartera y capital único

Flujo 1
Flujo 2
Flujo 3
Flujo 4
FlujoImporteFechaExponenteFactorValor 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,36 en 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
Los resultados se calculan al cargar la página.
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.