MoneyWarp โ Bend time. Model cash.
Project description
MoneyWarp ๐ฐโฐ
Bend time. Model cash.
โ ๏ธ Development Stage Notice
MoneyWarp is currently in active development and should be considered alpha/pre-release software. While the core functionality is implemented and tested, the API may change between versions. Use in production environments at your own risk.
- โ Core classes (
Money,InterestRate,CashFlow,Loan) are stable- โ Comprehensive test suite with 700+ tests
- โ ๏ธ API may evolve based on user feedback
- โ Published to PyPI
- ๐ง Additional features and schedulers in development
MoneyWarp is a Python library for working with the time value of money. It treats loans, annuities, and investments as simple cash flows through time โ and gives you the tools to warp them back and forth between present, future, and everything in between.
๐ Features
- ๐ฐ๏ธ Time Machine (Warp) - Travel to any date and see loan state as of that moment
- ๐ข Calculate PMT, NPV, IRR, MIRR and other core finance functions with scipy
- โณ Track loans and repayments as evolving cash-flow streams
- ๐ Explore "what if" timelines by bending payments across time
- ๐ฐ High-precision calculations using Decimal arithmetic
- ๐ Progressive Price Schedules (French amortization system)
- ๐ Inverted Price Schedules (Constant Amortization System - SAC)
- ๐ฏ Flexible payment scheduling with irregular due dates
- ๐ Easy date generation with smart month-end handling via python-dateutil
- ๐ Type-safe interest rates with explicit percentage handling
- ๐งฎ Robust numerics powered by scipy for IRR and financial calculations
- โ๏ธ Fine engine with fines, mora interest, and configurable grace periods
- ๐ญ Sugar payment methods โ
pay_installment()andanticipate_payment()for natural workflows - ๐ง๐ท Tax module โ Brazilian IOF with pluggable tax strategy, grossup, and preset rates
๐ฆ Installation
pip install money-warp
Or with Poetry:
poetry add money-warp
๐ฏ Quick Start
Basic Loan Analysis
from datetime import datetime
from money_warp import Money, InterestRate, Loan, generate_monthly_dates
# Create a $10,000 loan at 5% annual interest
principal = Money("10000.00")
rate = InterestRate("5% a") # 5% annually
# Generate monthly payment dates easily
start_date = datetime(2024, 1, 15)
due_dates = generate_monthly_dates(start_date, 12)
# Generate the loan
loan = Loan(principal, rate, due_dates)
# Get the payment schedule
schedule = loan.get_amortization_schedule()
print(f"Monthly payment: {schedule[0].payment_amount}")
print(f"Total interest: {schedule.total_interest}")
# Track actual payments
loan.record_payment(Money("856.07"), datetime(2024, 2, 1))
print(f"Remaining balance: {loan.current_balance}")
Cash Flow Analysis
from money_warp import CashFlow, CashFlowItem, Money
from datetime import datetime
# Create cash flow items
items = [
CashFlowItem(Money("1000.00"), datetime(2024, 1, 1), "Initial deposit", "deposit"),
CashFlowItem(Money("-50.00"), datetime(2024, 2, 1), "Monthly fee", "fee"),
CashFlowItem(Money("200.00"), datetime(2024, 3, 1), "Interest payment", "interest"),
]
# Analyze the cash flow
cash_flow = CashFlow(items)
print(f"Net cash flow: {cash_flow.net_present_value()}")
print(f"Total deposits: {cash_flow.query.filter_by(category='deposit').sum_amounts()}")
# Filter by date range
recent = cash_flow.query.filter_by(datetime__gte=datetime(2024, 2, 1))
print(f"Recent activity: {recent.sum_amounts()}")
High-Precision Money Handling
from money_warp import Money
from decimal import Decimal
# Create money with high internal precision
money = Money("100.123456789")
print(f"Internal precision: {money.raw_amount}") # 100.123456789
print(f"Real money (2 decimals): {money.real_amount}") # 100.12
print(f"Display: {money}") # 100.12
# Arithmetic maintains precision internally
result = money * 3 / 7
print(f"Calculation result: {result}") # Precise to 2 decimals for display
Time Machine - Warp to Any Date ๐ฐ๏ธ
Core Philosophy: The loan is always time sensitive... it always filters based on present date regardless if it is warped or not... the warp just changes the present date.
from money_warp import Warp, Loan, Money, InterestRate
from datetime import datetime
# Create a loan and make some payments
loan = Loan(Money("10000"), InterestRate("5% a"), [datetime(2024, 1, 15)])
loan.record_payment(Money("500"), datetime(2024, 1, 10), "Payment 1")
loan.record_payment(Money("600"), datetime(2024, 2, 10), "Payment 2")
loan.record_payment(Money("700"), datetime(2024, 3, 10), "Payment 3")
print(f"Current balance: {loan.current_balance}") # All payments applied
# Warp to the past - only see payments made by that date
with Warp(loan, datetime(2024, 1, 20)) as past_loan:
print(f"Balance on Jan 20: {past_loan.current_balance}") # Only first payment
print(f"Payments made: {len(past_loan._actual_payments)}") # 2 items (interest + principal)
# Warp to the future - see all payments up to that date
with Warp(loan, datetime(2025, 1, 1)) as future_loan:
print(f"Balance in future: {future_loan.current_balance}") # All payments applied
print(f"Days since last payment: {future_loan.days_since_last_payment()}") # From warped date
# Original loan unchanged
print(f"Back to present: {loan.current_balance}")
Key Features:
- ๐ฐ๏ธ Natural time filtering: Loans automatically show state as of any date
- ๐ Safe cloning: Original loan never modified during time travel
- ๐ Flexible date formats: Accepts strings, datetime objects, or date objects
- ๐ซ No nested warps: Prevents dangerous time paradoxes
- โก Instant calculations: Balance and payment history update automatically
Interest Rate Conversions
from money_warp import InterestRate, CompoundingFrequency, YearSize
# Create rates with explicit formats
annual_rate = InterestRate("5.25% a") # 5.25% annually
monthly_rate = InterestRate("0.4167% m") # 0.4167% monthly
daily_rate = InterestRate("3% d") # 3% daily (extreme example)
# Convert between frequencies
print(f"Annual: {annual_rate}")
print(f"As monthly: {annual_rate.to_monthly()}")
print(f"As daily: {annual_rate.to_daily()}")
# Safe decimal/percentage handling
print(f"As decimal: {annual_rate.as_decimal}") # 0.0525
print(f"As percentage: {annual_rate.as_percentage}") # 5.25
# Abbreviated notation (Brazilian/LatAm convention)
rate = InterestRate("5.25% a.a.") # parsed as 5.25% annually
print(rate) # "5.250% a.a." โ round-trips automatically
# Or set the style explicitly on numeric rates
rate = InterestRate(1.5, CompoundingFrequency.MONTHLY, as_percentage=True, str_style="abbrev")
print(rate) # "1.500% a.m."
# Day-count convention: commercial (365 days, default) or banker (360 days)
commercial = InterestRate("10% a", year_size=YearSize.commercial)
banker = InterestRate("10% a", year_size=YearSize.banker)
print(f"Commercial daily: {commercial.to_daily()}") # 365-day year
print(f"Banker daily: {banker.to_daily()}") # 360-day year โ slightly higher
Easy Date Generation ๐
Simplified with python-dateutil for robust date handling:
from datetime import datetime
from money_warp import (
generate_monthly_dates,
generate_biweekly_dates,
generate_weekly_dates,
generate_quarterly_dates,
generate_annual_dates,
generate_custom_interval_dates,
)
# Monthly payments (handles end-of-month intelligently)
monthly_dates = generate_monthly_dates(datetime(2024, 1, 31), 12)
print(f"Jan 31 โ Feb 29 โ Mar 31...") # Anchors to original day (31st)
# Bi-weekly payments (every 14 days)
biweekly_dates = generate_biweekly_dates(datetime(2024, 1, 1), 26)
print(f"26 payments over ~1 year")
# Weekly payments
weekly_dates = generate_weekly_dates(datetime(2024, 1, 1), 52)
# Quarterly payments
quarterly_dates = generate_quarterly_dates(datetime(2024, 1, 15), 4)
# Annual payments
annual_dates = generate_annual_dates(datetime(2024, 1, 1), 30) # 30-year loan
# Custom intervals (every N days)
custom_dates = generate_custom_interval_dates(datetime(2024, 1, 1), 10, 45) # Every 45 days
# Use with loans immediately
loan = Loan(
principal=Money("50000"),
interest_rate=InterestRate("3.5% annual"),
due_dates=monthly_dates # Just plug in the generated dates!
)
Key Features:
- ๐๏ธ Smart date handling: Uses
python-dateutilfor robust month arithmetic - ๐ End-of-month intelligence: Jan 31 โ Feb 29 โ Mar 31 (anchors to original day)
- ๐ฏ Simple API: Just
datetimeandintparameters, no complex options - โก Instant integration: Generated dates work directly with
Loanobjects - ๐ Type-safe: Full type annotations and validation
### Present Value and IRR Analysis ๐งฎ
**Powered by scipy for robust numerical calculations:**
```python
from money_warp import CashFlow, CashFlowItem, Money, InterestRate
from money_warp import present_value, irr, modified_internal_rate_of_return
from datetime import datetime
# Create an investment cash flow
items = [
CashFlowItem(Money("-10000"), datetime(2024, 1, 1), "Initial investment", "investment"),
CashFlowItem(Money("3000"), datetime(2024, 12, 31), "Year 1 return", "return"),
CashFlowItem(Money("4000"), datetime(2025, 12, 31), "Year 2 return", "return"),
CashFlowItem(Money("5000"), datetime(2026, 12, 31), "Year 3 return", "return"),
]
cash_flow = CashFlow(items)
# Calculate Present Value at 8% discount rate
discount_rate = InterestRate("8% annual")
pv = present_value(cash_flow, discount_rate)
print(f"Present Value at 8%: {pv}")
# Calculate Internal Rate of Return
investment_irr = irr(cash_flow)
print(f"IRR: {investment_irr}") # Should be ~9.7%
# Calculate Modified IRR with different reinvestment assumptions
finance_rate = InterestRate("10% annual") # Cost of capital
reinvestment_rate = InterestRate("6% annual") # Reinvestment rate
mirr = modified_internal_rate_of_return(cash_flow, finance_rate, reinvestment_rate)
print(f"MIRR: {mirr}")
# Loan IRR (borrower's perspective)
loan = Loan(Money("10000"), InterestRate("5% annual"), [datetime(2024, 12, 31)])
loan_irr = loan.irr() # Sugar syntax using loan's expected cash flow
print(f"Loan IRR: {loan_irr}") # Should be ~5% (loan's own rate)
# Present Value of loan using different discount rate
loan_pv = loan.present_value(InterestRate("8% annual"))
print(f"Loan PV at 8%: {loan_pv}") # Negative from borrower's perspective
Key Features:
- ๐ฌ Scipy-powered: Uses
scipy.optimize.brentqfor robust root finding - ๐ Automatic bracketing: Finds IRR solutions reliably across complex cash flows
- ๐ฐ๏ธ Time Machine integration: Use
Warpto calculate IRR from any date - ๐ญ Sugar syntax:
loan.irr()andloan.present_value()convenience methods - ๐ฐ High precision: Maintains decimal precision throughout calculations
### Tax & Grossup (Brazilian IOF) ๐ง๐ท
**Pluggable tax system with built-in IOF support and grossup for financed taxes:**
```python
from datetime import datetime
from money_warp import (
Money, InterestRate, Loan, IndividualIOF, CorporateIOF,
grossup_loan, PriceScheduler, generate_monthly_dates,
)
# Use preset rates for individual borrowers (PF)
iof = IndividualIOF() # daily=0.0082%, additional=0.38%
# Or for corporate borrowers (PJ)
iof_pj = CorporateIOF() # daily=0.0041%, additional=0.38%
# Attach tax to a loan for reporting
due_dates = generate_monthly_dates(datetime(2024, 2, 1), 12)
loan = Loan(
Money("10000"), InterestRate("1% m"), due_dates,
disbursement_date=datetime(2024, 1, 1),
taxes=[iof],
)
print(f"Total IOF: {loan.total_tax}")
print(f"Net disbursement: {loan.net_disbursement}") # principal - tax
# Grossup: borrower wants to receive exactly 10,000 after tax
grossed_loan = grossup_loan(
requested_amount=Money("10000"),
interest_rate=InterestRate("1% m"),
due_dates=due_dates,
disbursement_date=datetime(2024, 1, 1),
scheduler=PriceScheduler,
taxes=[iof],
)
print(f"Grossed-up principal: {grossed_loan.principal}") # > 10,000
print(f"Net to borrower: {grossed_loan.net_disbursement}") # ~= 10,000
Key Features:
- ๐ Pluggable taxes: Implement
BaseTaxfor any tax type - ๐ง๐ท IOF built-in: Brazilian IOF with daily + additional rate components
- ๐ค Presets:
IndividualIOF()andCorporateIOF()with standard rates (overridable) - ๐ Grossup: Scipy-powered solver finds the principal so
principal - tax = requested_amount - ๐ Rounding modes:
PRECISE(default) orPER_COMPONENTto match external systems
๐๏ธ Architecture
MoneyWarp is built around five core concepts:
๐ฐ Money
High-precision monetary amounts using Python's Decimal for accuracy:
- Internal precision: Stores full decimal precision
- Display precision: Shows 2 decimal places for "real money"
- Arithmetic safety: No floating-point errors
๐ InterestRate
Type-safe interest rate handling with explicit conversions:
- Clear representation: Eliminates 0.05 vs 5% confusion
- Frequency conversion: Annual โ Monthly โ Daily โ Quarterly
- String parsing:
"5.25% annual"or"0.004167 monthly" - Abbreviated notation:
"5.25% a.a.","1.5% a.m."(Brazilian/LatAm convention) - Day-count convention:
YearSize.commercial(365) orYearSize.banker(360)
๐ธ CashFlow
Container for cash flow analysis with SQLAlchemy-style querying:
- CashFlowItem: Individual transactions with amount, date, description, category
- CashFlow: Collection with filtering, summing, and analysis methods
- Query interface:
cashflow.query.filter_by(category='interest').sum_amounts()
๐ฆ Loan
State machine for loan analysis with configurable schedulers:
- Expected vs Actual: Compare planned payments with reality
- Payment allocation: Fines โ Interest โ Principal priority
- Fine engine: Automatic fines and mora interest for overdue payments
- Sugar methods:
pay_installment()andanticipate_payment()for natural workflows - Flexible scheduling: Any list of due dates, not just monthly
- Multiple schedulers: PMT-based, fixed payment, custom algorithms
๐ง๐ท Tax
Pluggable tax strategy with Brazilian IOF and grossup:
- BaseTax interface: Implement
calculate()for any tax type - IOF: Daily rate + additional rate components with configurable rounding
- Presets:
IndividualIOF(PF) andCorporateIOF(PJ) with standard rates - Grossup: Scipy-powered solver for financed tax calculations
๐ Supported Calculations
Loan Schedules
- Progressive Price Schedule (French amortization system)
- Inverted Price Schedule (Constant Amortization System - SAC)
- Fixed payment amounts with interest/principal allocation
- Irregular payment dates with daily compounding
- Bullet loans (single payment at maturity)
Time Value of Money Functions
- Present Value (PV): Discount future cash flows to present value
- Net Present Value (NPV): Sum of discounted cash flows
- Internal Rate of Return (IRR): Rate where NPV equals zero
- Modified IRR (MIRR): IRR with different financing/reinvestment rates
- Present Value of Annuities: Regular payment streams
- Present Value of Perpetuities: Infinite payment streams
- Discount Factors: Time value calculations
Financial Functions
- PMT: Payment calculation for loans and annuities
- Daily compounding: Precise interest calculations
- Amortization schedules: Complete payment breakdowns
- Balance tracking: Outstanding principal over time
- Robust numerics: Scipy-powered calculations for complex scenarios
Tax Calculations
- IOF (Brazilian): Daily + additional rate on each installment's principal
- Grossup: Find the principal so borrower receives the exact requested amount
- Per-installment breakdown: Tax detail for every installment in the schedule
- Rounding modes: Precise (sum-then-round) or per-component (round-then-sum)
- Custom taxes: Extend
BaseTaxfor any jurisdiction or tax type
๐งช Testing & Validation
MoneyWarp includes comprehensive test coverage with validation against established financial libraries:
- 700+ total tests with 100% core functionality coverage
- Reference validation against cartaorobbin/loan-calculator
- External IOF validation against a production Brazilian lending platform
- Edge case handling: Zero interest, irregular schedules, high precision
- Property-based testing: Parametrized tests across various scenarios
๐ฏ Use Cases
Personal Finance
- Mortgage analysis: Compare different loan terms and rates
- Payment tracking: Monitor actual vs expected payments
- Refinancing decisions: Calculate savings from rate changes
Investment Analysis
- Cash flow modeling: Track investment returns over time
- Scenario analysis: "What if" calculations with different assumptions
- Performance measurement: Calculate actual returns vs projections
Financial Planning
- Loan comparison: Evaluate different lending options
- Payment scheduling: Optimize payment timing for cash flow
- Interest calculation: Precise daily compounding for any scenario
๐ฎ Roadmap
- โ Time Machine (Warp): Travel to any date and analyze loan state - COMPLETED
- โ Inverted Price Scheduler: Constant Amortization System (SAC) - COMPLETED
- โ Present Value Functions: PV, NPV, annuities, perpetuities - COMPLETED
- โ IRR Functions: IRR, MIRR with scipy-powered numerics - COMPLETED
- โ Date Generation Utilities: Smart payment scheduling - COMPLETED
- โ Fine Engine: Fines, mora interest, grace periods - COMPLETED
- โ
Payment Sugar Methods:
pay_installment(),anticipate_payment()- COMPLETED - โ Tax Module: Brazilian IOF, grossup, pluggable tax strategy - COMPLETED
- Additional Schedulers: Custom schedules, balloon payments
- Performance optimization: Vectorized calculations for large datasets
- Advanced TVM: Bond pricing, option valuation
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Inspired by the time value of money concepts and validated against cartaorobbin/loan-calculator
- Built with modern Python practices using Poetry, pytest, and pre-commit hooks
- Follows the Zen of Python: "Beautiful is better than ugly. Explicit is better than implicit."
MoneyWarp - Because time is money, and money should bend to your will. ๐ฐโฐ
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file money_warp-0.1.4.tar.gz.
File metadata
- Download URL: money_warp-0.1.4.tar.gz
- Upload date:
- Size: 43.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
144d0d7513b46c07391e104d7ddea3a31d675e285c6a0222158d6b84fe8546d7
|
|
| MD5 |
ad19f43133adc0c244a329ee38219047
|
|
| BLAKE2b-256 |
20d88c07b9761595a296f1ad54162e8cbc4268f4ce77f279648c31b6f6149621
|
Provenance
The following attestation bundles were made for money_warp-0.1.4.tar.gz:
Publisher:
on-release-pypi.yml on tomascorrea/money-warp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
money_warp-0.1.4.tar.gz -
Subject digest:
144d0d7513b46c07391e104d7ddea3a31d675e285c6a0222158d6b84fe8546d7 - Sigstore transparency entry: 983866779
- Sigstore integration time:
-
Permalink:
tomascorrea/money-warp@01a031b894bddb0cce403bfd0b8add11ed4150db -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/tomascorrea
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
on-release-pypi.yml@01a031b894bddb0cce403bfd0b8add11ed4150db -
Trigger Event:
release
-
Statement type:
File details
Details for the file money_warp-0.1.4-py3-none-any.whl.
File metadata
- Download URL: money_warp-0.1.4-py3-none-any.whl
- Upload date:
- Size: 46.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34f8313bb72169fcb09a4353afd9fd8c3ae35a397162a5091cece07ec6e9fcf1
|
|
| MD5 |
2ab27e85e6493b771a4ec720f5f0a672
|
|
| BLAKE2b-256 |
22508aab4d1ce65794fccab0bf76079b96d8393742d813190217967d86010e78
|
Provenance
The following attestation bundles were made for money_warp-0.1.4-py3-none-any.whl:
Publisher:
on-release-pypi.yml on tomascorrea/money-warp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
money_warp-0.1.4-py3-none-any.whl -
Subject digest:
34f8313bb72169fcb09a4353afd9fd8c3ae35a397162a5091cece07ec6e9fcf1 - Sigstore transparency entry: 983866792
- Sigstore integration time:
-
Permalink:
tomascorrea/money-warp@01a031b894bddb0cce403bfd0b8add11ed4150db -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/tomascorrea
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
on-release-pypi.yml@01a031b894bddb0cce403bfd0b8add11ed4150db -
Trigger Event:
release
-
Statement type: