Production-ready Swift library for financial analysis, forecasting, and quantitative modeling.
Build DCF models, optimize portfolios, run Monte Carlo simulations, and value securities—with industry-standard implementations (ISDA, Black-Scholes) that work out of the box.
2.6.0 is a correctness release. It changes very few signatures and a great many numbers —
poissonCDF returned P(X ≤ k−1) at every integer argument, normalCDF lost its entire lower
tail to cancellation, DriverProjection.percentile(0.10) returned the p5 value, and one branch of
correctedStdErr had never executed in any released version. The CHANGELOG opens with a table of
every result that moved and by how much; read that before upgrading.
It also breaks compatibility in four places, each small and each worth knowing before you upgrade rather than after:
FormulaErrorgains a case,nestingTooDeep(limit:). A switch over it that was exhaustive no longer compiles. The case exists because a long enough formula —((((…))))or-----…1— overflowed the stack and took the process, which no caller could catch.@MCPTooland@BuilderInitializableare removed. Neither had ever worked: the first generated an extension on a function name and referenced three types this package does not contain, the second an attribute it never emitted.- The validation macros throw
MacroValidationErrorfromBusinessMathMacros. They previously threw a type declared inside the compiler plugin, which vends nothing to compiled code, so@Validatedcould not be used by anyone in any module. VectorNarithmetic on mismatched dimensions returnsNaNinstead of a vector of zeros, andVectorN.zerois now the additive identity rather than an annihilator —zero + vwas[0, 0], which madevar sum = VectorN.zerosilently drop the first element it was given.
| tests | 6,582 in 579 suites, all passing under strict concurrency |
| build | 0 warnings, library and test target |
| documentation coverage | 100% — 6,447 of 6,447 public APIs documented |
| DocC catalogue | 73 articles, every code block compiled against the module |
| toolchain | Swift 6.2 (swift-tools-version: 6.2) |
See what's new: CHANGELOG.md
Type-Safe & Concurrent: Full Swift 6 compliance with generics (TimeSeries<T: Real & Sendable>) and strict concurrency for thread safety. Model closures are @Sendable. As of 2.6.0 the vector and optimizer types require Real & BinaryFloatingPoint rather than Real alone — the conversion that constraint supplies used to be faked with a runtime-cast ladder that answered 0.0 when it failed.
Complete: 73 comprehensive guides, 6,582 tests, and production implementations of valuation models, optimization algorithms, and risk analytics. Every code block in the guides is compiled against the module by the doc-code auditor (quality-gate --check doc-code), so an example that no longer matches the API fails the check rather than the reader.
Accurate: Calendar-aware calculations (365.25 days/year), industry-standard formulas (ISDA CDS pricing, Black-Scholes), and — where a result is an approximation — a measured accuracy recorded in the doc comment rather than an assurance. inverseNormalCDF is 2 ulp over 1e-12 ≤ p ≤ 1 − 1e-12; normalCDF holds ~1e-14 relative down to x = −37. Numbers that changed in 2.6.0 are tabulated in the CHANGELOG with the measurement that found them.
Fast: GPU-accelerated genetic algorithms (10-100× for populations ≥ 1,000 on Apple Silicon), parallel and adaptive optimizer selection, and a benchmarking guide that shows how to measure your own workload rather than trusting a headline number — see Performance Benchmarking and Monte Carlo Performance.
Ergonomic: Fluent APIs that read like financial prose. Risk-aware examples that demonstrate real tradeoffs, not trivial solutions. Clear error messages and comprehensive debugging guides.
import BusinessMath
// Complete investment analysis workflow
let cashFlows = [-100_000.0, 30_000, 40_000, 50_000, 60_000]
// 1. Evaluate profitability
let npvValue = npv(discountRate: 0.10, cashFlows: cashFlows)
// → $38,877 ✓ Positive NPV
let irrValue = try irr(cashFlows: cashFlows)
// → 24.9% return ✓ Exceeds hurdle rate
let pi = profitabilityIndex(rate: 0.10, cashFlows: cashFlows)
// → 1.389 ✓ Good investment (> 1.0)
// 2. Sensitivity analysis: How sensitive is NPV to discount rate?
let rates = [0.05, 0.07, 0.10, 0.12, 0.15]
let sensitivityTable = DataTable<Double, Double>.oneVariable(
inputs: rates,
calculate: { rate in npv(discountRate: rate, cashFlows: cashFlows) }
)
for (rate, npvResult) in sensitivityTable {
print("Rate: \((rate * 100).smartRounded())%: NPV: \(npvResult.currency())")
}
// Shows NPV ranges from $57K (5% rate) to $23K (15% rate)
// 3. Risk assessment: Monte Carlo simulation for uncertain cash flows
//
// Pass a `seed` unless you have a reason not to. If any input can't honor it —
// a custom-closure input, or correlated sampling — `run()` throws
// `SimulationError.seedingUnsupported` rather than quietly handing back a
// non-reproducible answer that looks fine.
var simulation = MonteCarloSimulation(iterations: 10_000, seed: 42) { inputs in
// Model uncertain cash flows with ±20% volatility
let year1 = 30_000 * (1 + inputs[0])
let year2 = 40_000 * (1 + inputs[1])
let year3 = 50_000 * (1 + inputs[2])
let year4 = 60_000 * (1 + inputs[3])
return npv(discountRate: 0.10, cashFlows: [-100_000, year1, year2, year3, year4])
}
// Add uncertainty inputs (normal distribution with 20% std dev).
// `DistributionNormal` conforms to `SeedableDistribution`, so each input draws
// from the run's generator and the seed above actually reaches the samples.
for year in 1...4 {
simulation.addInput(SimulationInput(
name: "Year \(year) Return Variance",
distribution: DistributionNormal(0.0, 0.20)
))
}
let results = try simulation.run()
let var95 = results.valueAtRisk(confidenceLevel: 0.95)
print("\nRisk Analysis:")
print("Expected NPV: \(results.statistics.mean.currency())")
print("95% VaR: \(abs(var95).currency()) (worst case with 95% confidence)")
print("Probability of loss: \((results.probabilityBelow(0) * 100).number())%")
// Reproducibility is guaranteed per execution path: a seeded GPU run and a
// seeded CPU run are each internally reproducible but produce different
// streams, and a GPU failure falls back to the seeded CPU path, recorded in
// `results.executionNotes`. Set `enableGPU: false` to pin one path.
// → Decision: Approve investment ✓
// Strong positive NPV, profitable across rate scenarios, low probability of lossThis shows the power of BusinessMath: calculate, analyze, and decide in one workflow.
Build revenue models, forecast cash flows, and model business scenarios with calendar-aware time series operations. Supports daily through annual periods with fiscal calendar alignment (Apple, Australia, UK, etc.).
→ Guide: Building Revenue Models | Forecasting Guide
Calculate NPV, IRR, MIRR, profitability index, and payback periods. Handle irregular cash flows with XNPV/XIRR. Includes loan amortization with payment breakdowns (PPMT, IPMT).
→ Guide: Investment Analysis | Time Value of Money
Value equities (DCF, DDM, FCFE, residual income), price bonds (duration, convexity, credit spreads), and analyze credit derivatives (CDS pricing with ISDA Standard Model, Merton structural model).
→ Equity Valuation | Bond Valuation | Credit Derivatives
Run Monte Carlo simulations with 15 probability distributions. Calculate VaR/CVaR, perform stress testing, and aggregate portfolio risks. Model uncertainty with scenario analysis.
→ Monte Carlo Guide | Risk Analytics
Optimize portfolios (efficient frontier, Sharpe ratio maximization), solve integer programming problems (branch-and-bound, cutting planes), and allocate capital optimally. GPU-accelerated genetic algorithms provide 10-100× speedup for large-scale optimization (populations ≥ 1,000) with automatic Metal acceleration on Apple Silicon.
→ Portfolio Optimization | Optimization Guide | GPU Acceleration
Add BusinessMath to your Package.swift:
dependencies: [
.package(url: "https://github.com/jpurnell/BusinessMath.git", from: "2.6.0")
]Or in Xcode: File → Add Package Dependencies → Enter repository URL
The package vends three products: BusinessMath (the library), BusinessMathDSL (a declarative result-builder surface for expressing models and scenarios), and BusinessMathMacros (macro declarations backed by a SwiftSyntax plugin; not built on Linux). BusinessMath does not depend on the macros, so a Playground can import it without loading a compiler plugin.
73 comprehensive guides organized into 5 parts (Basics, Analysis, Modeling, Simulation, Optimization):
- Documentation Home - Complete structure and index
- Learning Path Guide - Four specialized tracks:
- Financial Analyst (15-20 hours)
- Risk Manager (12-15 hours)
- Quantitative Developer (20-25 hours)
- General Business (10-12 hours)
- Getting Started - Quick introduction with examples
Detailed examples for common workflows:
- QUICK_START_EXAMPLE.swift - 🚀 Copy-paste investment analysis example (start here!)
- EXAMPLES.md - Time series, forecasting, loans, securities, risk, optimization
- All DocC Tutorials - 73 comprehensive guides with compiled examples
- ✅ Generic time series with calendar-aware operations
- ✅ Time value of money (NPV, IRR, MIRR, XNPV, XIRR, annuities)
- ✅ Forecasting (trend models: linear, exponential, logistic)
- ✅ Seasonal decomposition (additive and multiplicative)
- ✅ Growth modeling (CAGR, trend fitting)
- ✅ Loan amortization (payment schedules, PPMT, IPMT)
- ✅ Financial statements (role-based architecture with multi-statement account support)
- ✅ Securities valuation (equity: DCF, DDM, FCFE; bonds: pricing, duration, convexity; credit: CDS, Merton model)
- ✅ Risk analytics (VaR, CVaR, stress testing)
- ✅ Monte Carlo simulation (15 distributions, sensitivity analysis)
- ✅ Portfolio optimization (efficient frontier, Sharpe ratio, risk parity)
- ✅ Genetic algorithms (GPU-accelerated for populations ≥ 1,000, automatic Metal acceleration)
- ✅ Integer programming (branch-and-bound, cutting planes)
- ✅ Financial ratios (profitability, leverage, efficiency)
- ✅ Real options (Black-Scholes, binomial trees, Greeks)
- ✅ Multiple linear regression (OLS with QR decomposition; CPU, Accelerate, and Metal matrix backends)
- ✅ Data envelopment analysis (CCR and BCC, super-efficiency, async solver)
- ✅ Hypothesis testing (t-tests, chi-square, F-tests, A/B testing)
- ✅ Model validation (fake-data simulation, parameter recovery)
- ✅ Reproducible simulation (
seed: UInt64?orusing: inout Gacross the distribution family, Monte Carlo, scenario generation and the GPU path; unseeded paths are documented as non-reproducible by contract rather than left ambiguous) - ✅ Dependency cycles (detection over formula-holding models, decidable linear/nonlinear classification, and exact solution of linear cycles rather than iteration)
- 📚 73 comprehensive guides (~50,900 lines of DocC documentation), every code block compiled against the module
- ✅ 100% documentation coverage — 6,447 of 6,447 public APIs documented
- ✅ 6,582 tests across 579 test suites (100% pass rate, 0 known issues)
- 📊 Performance benchmarks for typical use cases
- 🎓 Learning paths for different roles
- Swift 6.2 or later — the manifest declares
swift-tools-version: 6.2 - Platforms: iOS 17+, macOS 14+, tvOS 17+, watchOS 10+, visionOS 1+, as declared in
Package.swift. Linux and Android build too, withBusinessMathMacrosexcluded on Linux; Metal-backed GPU paths require Apple Silicon and fall back to CPU elsewhere. - Dependencies: Swift Numerics (for
Real), Swift Collections, swift-docc-plugin, SwiftDeterminism (seeded generators), and swift-crypto — linked only where CryptoKit is absent (Linux, Android)
- Financial Analysts: Revenue forecasting, DCF valuation, scenario analysis
- Risk Managers: VaR/CVaR calculation, Monte Carlo simulation, stress testing
- Corporate Finance: Capital allocation, WACC, financing decisions, lease accounting
- Portfolio Managers: Efficient frontier, Sharpe ratio optimization, risk parity
- Quantitative Developers: Algorithm implementation, model validation, backtesting
- FP&A Teams: Budget planning, KPI tracking, executive dashboards
📢 Release history - Every release back to 1.0.0. The 2.6.0 entry opens with a table of the results that changed, since most of that release moves numbers without moving signatures.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Ensure all tests pass (
swift test) - Add tests for new functionality
- Update documentation
- Open a Pull Request
📖 See CONTRIBUTING.md for detailed guidelines and code standards.
MIT License - see LICENSE for details.
- Documentation: BusinessMath.docc
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Examples: QUICK_START_EXAMPLE.swift | EXAMPLES.md