@tevaxialu/propcalc
v1.0.0
Published
Real estate investment calculation engines for 10 European and US countries
Maintainers
Readme
@tevaxialu/propcalc
Real estate investment calculation engines for 10 European and US countries.
Part of the PropCalc ecosystem by Tevaxia
Quick Start
npm install @tevaxialu/propcalcimport {
calculateMonthlyPayment,
calculateAcquisitionFees,
calculateNetYield,
getCountryData,
} from '@tevaxialu/propcalc';
// Monthly mortgage payment for a 300,000 EUR loan at 3.5% over 25 years
const monthly = calculateMonthlyPayment(300000, 0.035, 25 * 12);
console.log(`Monthly payment: ${monthly.toFixed(2)} EUR`);
// Acquisition fees in Luxembourg
const lu = getCountryData('lu');
const fees = calculateAcquisitionFees({
propertyPrice: 500000,
countryCode: 'lu',
regionCode: '',
isNew: false,
isPrimaryResidence: true,
isFirstTimeBuyer: false,
loanAmount: 400000,
countryData: lu,
});
console.log(`Total fees: ${fees.total.toFixed(2)} EUR (${fees.totalPercent}%)`);
// Net rental yield
const yield_ = calculateNetYield({
annualRent: 18000,
purchasePrice: 400000,
monthlyCharges: 150,
annualPropertyTax: 800,
annualInsurance: 300,
vacancyRate: 0.05,
managementRate: 0.08,
annualMaintenance: 500,
});
console.log(`Net yield: ${(yield_.netYield * 100).toFixed(2)}%`);Supported Countries
| Code | Country | Currency |
|------|---------------|----------|
| be | Belgium | EUR |
| de | Germany | EUR |
| es | Spain | EUR |
| fr | France | EUR |
| it | Italy | EUR |
| lu | Luxembourg | EUR |
| nl | Netherlands | EUR |
| pt | Portugal | EUR |
| uk | United Kingdom| GBP |
| us | United States | USD |
API Reference
Mortgage
calculateMonthlyPayment(loanAmount, annualRate, durationMonths)
Calculate the monthly payment for a constant annuity mortgage.
- loanAmount
number-- Loan principal - annualRate
number-- Annual interest rate as decimal (e.g.,0.035for 3.5%) - durationMonths
number-- Loan duration in months - Returns
number-- Monthly payment amount
calculateBorrowingCapacity(params)
Calculate maximum borrowing capacity based on income and country rules.
- params.monthlyIncome
number-- Net monthly household income - params.existingDebts
number-- Current monthly debt payments (default0) - params.annualRate
number-- Annual interest rate as decimal - params.durationYears
number-- Loan duration in years - params.downPayment
number-- Available down payment (default0) - params.insuranceRate
number-- Monthly insurance rate as decimal of capital (default0) - params.countryRules
Object-- Country borrowing rules from data JSON - params.residencyStatus
string--'resident'|'nonResident'|'nonEU'(default'resident') - Returns
Object--{ maxLoanAmount, maxPropertyPrice, monthlyPayment, monthlyInsurance, totalMonthly, dtiRatio, maxDTI, ltvApplied, estimatedFees }
Acquisition Fees
calculateAcquisitionFees(params)
Calculate all acquisition fees for a property purchase. Supports country-specific logic for all 10 countries.
- params.propertyPrice
number - params.countryCode
string--'fr','de','uk','lu','be','es','pt','it','nl','us' - params.regionCode
string-- Department/Land/state code - params.isNew
boolean-- New build vs existing property - params.isPrimaryResidence
boolean - params.isFirstTimeBuyer
boolean - params.loanAmount
number - params.buyerAge
number-- Required for PT/NL first-time buyer exemptions - params.countryData
Object-- Full country data JSON (fromgetCountryData) - Returns
Object--{ items: [{ label, amount, rate, details }], total, totalPercent }
calculateNotaryFees(propertyPrice, scale, vatRate)
Calculate notary fees using a sliding scale (France-style brackets).
- propertyPrice
number - scale
Array--[{ upTo, rate }, ...]sorted ascending - vatRate
number-- VAT on notary fees (e.g.,0.20) - Returns
number-- Total notary fees including VAT
calculateStampDuty(propertyPrice, bands, surcharge, isAdditionalProperty)
Calculate stamp duty using progressive bands (UK-style marginal system).
- propertyPrice
number - bands
Array--[{ upTo, rate }, ...]sorted ascending - surcharge
number-- Additional flat rate for second properties - isAdditionalProperty
boolean - Returns
number-- Total stamp duty
Rental Yield & Tax
calculateGrossYield(annualRent, purchasePrice)
- annualRent
number-- Annual gross rent - purchasePrice
number-- Property purchase price - Returns
number-- Gross yield as decimal (e.g.,0.055for 5.5%)
calculateNetYield(params)
Calculate net rental yield before tax.
- params.annualRent
number-- Annual gross rent - params.purchasePrice
number-- Property purchase price - params.monthlyCharges
number-- Monthly condo/maintenance charges (default0) - params.annualPropertyTax
number-- Annual property tax (default0) - params.annualInsurance
number-- Annual landlord insurance (default0) - params.vacancyRate
number-- Vacancy rate as decimal (default0) - params.managementRate
number-- Management fee as % of rent (default0) - params.annualMaintenance
number-- Annual maintenance budget (default0) - Returns
Object--{ grossYield, effectiveRent, totalExpenses, netRent, netYield, expenses }
calculateTaxImpact(params)
Apply a country-specific tax regime to compute after-tax return.
- params.netRent
number-- Net rent before income tax - params.purchasePrice
number - params.annualRent
number - params.countryCode
string - params.taxRegime
string-- Regime code from country JSON - params.marginalRate
number-- Marginal income tax rate (default0.30) - params.socialChargesRate
number-- Social contributions rate (default0) - params.countryData
Object-- Full country data JSON - params.annualMortgageInterest
number-- For interest deduction (default0) - params.annualDepreciation
number-- For depreciation deduction (default0) - Returns
Object--{ taxableIncome, depreciation, mortgageInterestDeduction, incomeTax, socialCharges, totalTax, netAfterTax, netNetYield }
calculateCashOnCash(netAfterTax, annualMortgageCost, totalCashInvested)
Calculate cash-on-cash return for a financed property.
- netAfterTax
number-- Annual net income after all taxes - annualMortgageCost
number-- Annual mortgage payments (P+I) - totalCashInvested
number-- Down payment + acquisition fees - Returns
number-- Cash-on-cash return as decimal
Investor Cash-Flow
calculateInvestorCashFlow(params)
Full investor cash-flow analysis with multi-year projection.
- params.propertyPrice
number-- Purchase price - params.acquisitionFees
number-- Total acquisition fees (default0) - params.downPayment
number-- Cash down payment - params.annualRate
number-- Mortgage annual interest rate - params.loanDurationYears
number-- Mortgage duration in years - params.monthlyRent
number-- Monthly rental income - params.vacancyRate
number-- Annual vacancy rate (default0) - params.monthlyCharges
number-- Monthly condo charges (default0) - params.annualPropertyTax
number-- Annual property tax (default0) - params.annualInsurance
number-- Annual landlord insurance (default0) - params.managementRate
number-- Management fee rate (default0) - params.annualMaintenance
number-- Annual maintenance budget (default0) - params.marginalTaxRate
number-- Marginal income tax rate (default0.30) - params.socialChargesRate
number-- Social charges rate (default0) - params.annualAppreciation
number-- Annual property appreciation (default0.02) - params.countryCode
string-- Country code (default'') - params.countryData
Object-- Country data JSON (defaultnull) - Returns
Object--{ monthlyMortgage, grossAnnualRent, effectiveRent, noi, annualMortgage, annualDepreciation, taxableIncome, cashFlowBeforeTax, incomeTax, socialCharges, cashFlowAfterTax, monthlyCashFlow, grossYield, netYield, cashOnCash, leverageEffect, totalInvestment, cashInvested, loanAmount, projection[] }
Buy vs Rent
compareBuyVsRent(params)
Simulate buying vs renting over a given time horizon.
- params.propertyPrice
number-- Purchase price - params.downPayment
number-- Cash down payment - params.acquisitionFeesRate
number-- Fees as % of price (default0.08) - params.annualRate
number-- Mortgage annual interest rate - params.loanDurationYears
number-- Mortgage duration in years - params.monthlyRent
number-- Current monthly rent - params.annualRentIncrease
number-- Annual rent increase rate (default0.02) - params.annualAppreciation
number-- Annual property appreciation (default0.02) - params.annualOwnerCharges
number-- Annual owner charges (default0) - params.annualRenterCharges
number-- Annual renter charges (default0) - params.alternativeReturnRate
number-- Return on savings if renting (default0.03) - params.horizonYears
number-- Comparison horizon (default20) - params.sellingCostsRate
number-- Agent fees at sale (default0.05) - Returns
Object--{ timeline[], breakeven, summary: { totalBuyerSpent, totalRenterSpent, finalBuyerWealth, finalRenterWealth, advantage, verdict, monthlyMortgage } }
Amortization
generateAmortizationSchedule(params)
Generate a full monthly amortization schedule.
- params.loanAmount
number-- Loan principal - params.annualRate
number-- Annual interest rate as decimal - params.durationMonths
number-- Loan duration in months - params.type
string--'constant'(annuity) |'linear'(constant principal) |'infine'(interest-only) (default'constant') - params.monthlyInsurance
number-- Fixed monthly insurance amount (default0) - Returns
Object--{ schedule: [{ month, payment, principal, interest, insurance, totalPayment, remainingBalance }], summary: { totalPayments, totalInterest, totalInsurance, totalCost, effectiveRate } }
generateYearlySummary(monthlySchedule)
Aggregate a monthly schedule into yearly summaries.
- monthlySchedule
Array-- Theschedulearray fromgenerateAmortizationSchedule - Returns
Array--[{ year, totalPayment, totalPrincipal, totalInterest, totalInsurance, remainingBalance }]
Cross-Border Comparison
compareCountries(params)
Compare a property investment across multiple countries.
- params.budget
number-- Total available budget (down payment + fees) - params.monthlyIncome
number-- Monthly net income (default4000) - params.monthlyRent
number-- Expected monthly rent (default: estimated) - params.annualRate
number-- Assumed mortgage rate (default: country default) - params.durationYears
number-- Loan duration (default25) - params.ltvRatio
number-- LTV ratio (default0.80) - params.residencyStatus
string--'resident'|'nonResident'|'nonEU'(default'resident') - params.marginalTaxRate
number-- Marginal tax rate (default0.30) - params.countriesData
Object--{ fr: frData, de: deData, ... } - params.countryCodes
string[]-- e.g.['fr', 'de', 'uk', ...] - Returns
Array-- Sorted array of country comparison results with{ code, name, flag, currency, propertyPrice, fees, grossYield, netYield, netNetYield, monthlyCashFlow, rank, ... }
Country Data
getCountryData(code)
Get country data by ISO-2 code.
- code
string-- Lowercase country code (e.g.,'lu','fr','de') - Returns
Object|null-- Country data object ornullif not found
getAllCountries()
Get all available countries.
- Returns
Object-- Map of all country data keyed by code:{ be, de, es, fr, it, lu, nl, pt, uk, us }
License
MIT -- Tevaxia
