finmath-engine
Version:
Motor de cálculos financeiros de alta precisão para o mercado brasileiro
93 lines • 2.9 kB
JavaScript
;
/**
* CET (Custo Efetivo Total) - Versão Básica
* Sprint 4 - H15 (Parte 3)
*
* Escopo MVP: CET com tarifas t0 apenas (sem IOF/seguros)
* Referência: Guia CET — Source of Truth v1.0
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCETBasic = calculateCETBasic;
exports.formatCET = formatCET;
const decimal_js_1 = require("decimal.js");
const brent_1 = require("../irr/brent");
/**
* Calcula CET básico usando solver de Brent
*
* Fórmula (Guia CET - SoT §4):
* 1. CF[0] = +PV - tarifas_t0
* 2. CF[k] = -PMT[k] (k=1..n)
* 3. IRR_m = solveIRR(CF, tolerance=1e-8)
* 4. CET_aa = (1 + IRR_m)^base - 1
*
* @param input - Parâmetros do cálculo
* @returns Resultado com IRR mensal e CET anual
*
* @example
* ```typescript
* const result = calculateCETBasic({
* pv: new Decimal('10000'),
* schedule: [
* new Decimal('946.56'), // PMT_1
* new Decimal('946.56'), // PMT_2
* // ... 12 parcelas
* ],
* feesT0: [new Decimal('85')], // Tarifa de cadastro
* baseAnnual: 12
* });
*
* console.log(result.cetAnnual.toNumber()); // 0.3367 (33.67% a.a.)
* ```
*/
function calculateCETBasic(input) {
const { pv, schedule, feesT0 = [], baseAnnual = 12 } = input;
// Validações
if (schedule.length === 0) {
throw new Error("Schedule cannot be empty");
}
if (pv.lessThanOrEqualTo(0)) {
throw new Error("PV must be positive");
}
if (baseAnnual <= 0) {
throw new Error("baseAnnual must be positive");
}
// 1. Calcular entrada líquida do cliente (t=0)
const totalFeesT0 = feesT0.reduce((sum, fee) => sum.plus(fee), new decimal_js_1.Decimal(0));
const netInflow = pv.minus(totalFeesT0);
if (netInflow.lessThanOrEqualTo(0)) {
throw new Error("Net inflow must be positive (PV > fees)");
}
// 2. Montar fluxo de caixa
const cashflows = [
netInflow, // CF[0]: +PV - tarifas_t0 (entrada do cliente)
...schedule.map((pmt) => pmt.neg()), // CF[k]: -PMT (saídas)
];
// 3. Resolver IRR com Brent
const irrResult = (0, brent_1.solveIRR)(cashflows, {
tolerance: new decimal_js_1.Decimal("1e-8"),
});
if (!irrResult.converged || !irrResult.irr) {
throw new Error(`IRR did not converge. Diagnostics: ${JSON.stringify(irrResult.diagnostics)}`);
}
const irrMonthly = irrResult.irr;
// 4. Converter para CET anual
const cetAnnual = (0, brent_1.convertToAnnual)(irrMonthly, baseAnnual);
return {
irrMonthly,
cetAnnual,
cashflows,
breakdown: {
pv,
totalFeesT0,
netInflow,
},
irrResult,
};
}
/**
* Helper: converte CET para porcentagem formatada
*/
function formatCET(cet, decimals = 2) {
return `${cet.mul(100).toFixed(decimals)}%`;
}
//# sourceMappingURL=basic.js.map