Skip to content

geoClink/Savings-Calculator

Repository files navigation

Savings Calculator

An iOS app that helps everyday people explore how savings rates compare to US Treasury rates and inflation. Built with SwiftUI, Swift Charts, WidgetKit, Core ML, and live data from the US Treasury and Federal Reserve APIs. Not financial advice — just data presented in plain English.

Why I Built This

Most finance apps assume you already know what a T-Bill is. This one doesn't. I built this to teach myself how savings rates, Treasury rates, and inflation all connect — and to present that data in plain English so anyone can explore it. It's a learning project, not financial advice.

Features

  • Calculator — Compare Money Market, CD, and Bond Fund returns side by side for any principal and time horizon
  • Visualizer — Swift Charts bar chart of recent T-Bill rates with your rate overlaid as a dashed reference line
  • Live Rates — Real-time Treasury Bill rate from the US Treasury API, shows the exact dollar amount you're leaving on the table annually
  • Compare — Side-by-side bar chart of T-Bills vs T-Bonds vs T-Notes vs TIPS, with plain English explanations of each
  • Inflation Check — FRED API integration shows whether your savings rate is keeping up with CPI inflation
  • History — Save and review past calculations with SwiftData persistence
  • Glossary — Searchable plain English definitions of financial terms (APY, T-Bill, CD, FDIC, etc.)
  • Home Screen Widget — WidgetKit widget showing the current T-Bill rate (small and medium sizes), refreshes every 4 hours
  • ML Rate Forecast — On-device Core ML model predicts the next T-Bill rate using 14 live economic indicators (fed funds rate, CPI, PCE, yield curve, unemployment, oil prices, and more). Shows the prediction alongside the actual rate — no advice, just data.
  • Offline Support — Cached API data loads instantly, fresh data updates in the background

Architecture

The project follows MVVM (Model-View-ViewModel) with a clear separation between UI, business logic, and networking.

Why MVVM?

  • Testability — ViewModels contain all business logic and can be unit tested without any UI. The test suite has 50+ tests covering calculations, recommendations, API parsing, mock networking, and edge cases.
  • Separation of concerns — Views only handle layout and binding. They don't compute returns, decide which product is best, or interact with SwiftData directly.
  • Scalability — Adding the Live Rates and Compare tabs didn't require touching existing ViewModel logic. Each screen owns its data flow.

File Structure

SavingsCalculator/
├── Models.swift                        Shared data models (SavedCalculation, DepositSession, SavingsProduct)
├── RateService.swift                   Networking: Treasury API, FRED API, caching, secrets
├── RateForecastService.swift           Core ML prediction wrapper for RateChecker model
├── RateChecker.mlmodel                 Trained ML model for T-Bill rate estimation
├── SavingsCalculatorViewModel.swift    Calculator logic: product comparison, recommendations, save
├── HistoryViewModel.swift              History deletion logic
├── SavingsCalculatorApp.swift          App entry point + Calculator, ProductCard, History views
├── ContentView.swift                   TabView container (6 tabs)
├── VisualizerView.swift                T-Bill rate chart with Swift Charts
├── LiveRatesView.swift                 Balance gap calculator with live API data + inflation
├── RateComparisonView.swift            Treasury securities comparison with bar chart
├── GlossaryView.swift                  Searchable glossary of financial terms
├── Secrets.plist                       API keys (gitignored, never committed)

RateWidget/
├── RateWidget.swift                    Home screen widget (small + medium)
├── RateWidgetBundle.swift              Widget entry point

SavingsCalculatorTests/
├── SavingsCalculatorViewModelTests.swift   ViewModel + model unit tests
├── LiveRatesViewTests.swift                Rate gap, inflation, and cache tests
├── RateServiceTests.swift                  Async mock network tests (MockURLProtocol)
├── UITests.swift                           Integration tests for end-to-end app flows

Key Technical Decisions

Decision Why
@Observable ViewModels Modern Observation framework — cleaner than ObservableObject/@Published, better performance
Shared savingsProducts array Defined once in Models.swift, used by Calculator and Visualizer — no duplication
RateCache (UserDefaults) Cached API responses load instantly on launch; stale after 4 hours; graceful offline fallback
Injectable URLSession RateService and FREDService accept a session parameter (defaults to .shared) — enables mock network testing without hitting real APIs
Secrets.plist (gitignored) API keys never touch version control; app reads from bundle at runtime
ContentUnavailableView errors Polished error states with retry buttons instead of raw error text
StaticConfiguration widget No user configuration needed — just shows the T-Bill rate
Swift Charts BarMark + RuleMark Visualizer overlays user's rate on top of T-Bill data for instant comparison
Accessibility throughout Every data card and input has accessibilityLabel and accessibilityValue for VoiceOver
Core ML on-device inference RateChecker.mlmodel runs locally — no data leaves the device, no server costs, works offline once inputs are cached
14 FRED series fetched in parallel async let fires all API calls concurrently for fast model input loading

APIs

API What it provides Key required?
US Treasury Fiscal Data T-Bill, T-Bond, T-Note, TIPS rates No
FRED (Federal Reserve) Fed Funds rate, CPI inflation, PCE, unemployment, 10yr/2yr yields, M2, credit spreads, oil, savings rate, industrial production Yes (free)

Getting Started

  1. Clone the repo and open SavingsCalculator.xcodeproj in Xcode
  2. (Optional) Get a free FRED API key at fred.stlouisfed.org
  3. Create SavingsCalculator/Secrets.plist with your key:
    <dict>
        <key>FRED_API_KEY</key>
        <string>your_key_here</string>
    </dict>
  4. Make sure Secrets.plist is in Build Phases > Copy Bundle Resources
  5. Build and run on a simulator or device (iOS 17+)

The Treasury API works immediately with no setup. FRED data (inflation, Fed Funds rate) requires the optional key.

Running Tests

Press Cmd + U in Xcode. All tests use the Swift Testing framework (@Suite, @Test, #expect). Tests cover:

  • Product return calculations (compound interest, edge cases, zero principal)
  • ViewModel defaults, best product selection, recommendation boundaries
  • Treasury API JSON decoding (valid, empty, negative rates)
  • FRED API observation parsing (valid, missing data placeholders)
  • Shared product list validation (ordering, flags, completeness)
  • Async mock network testsMockURLProtocol intercepts URLSession requests with fake JSON, testing success paths, caching, deduplication, invalid JSON, and network failures without hitting real APIs
  • Integration tests — End-to-end flows through the model layer: calculator input → recommendation, cache round-trips, CSV export, and product comparison consistency

Requirements

  • Xcode 16+
  • iOS 17+
  • Swift 5.9+

Disclaimer

For informational purposes only. Not financial advice. Rate data sourced from the US Treasury Fiscal Data API and Federal Reserve Economic Data (FRED).

About

iOS app that compares your savings rate to live US Treasury and Federal Reserve data. Features an on-device Core ML model for rate forecasting, Swift Charts visualizations, inflation tracking, a home screen widget, and a plain English glossary. Built with SwiftUI, WidgetKit, and SwiftData. Not financial advice — just data.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages