MMM Savings Rate

MMM Savings Rate is a tool that allows users to calculate and track their monthly savings rates over time. It uses the FI module and plots savings rates with Bokeh.

Key Features: - Graphical User Interface (GUI) - User-friendly interface built with BeeWare/Toga - Automatic File Watching - Plots refresh automatically when spreadsheet files are saved - Command Line Interface (CLI) - Full-featured command line tools - Parse Excel (.xlsx) and CSV spreadsheets with flexible column mapping - Interactive web-based visualizations with Bokeh - JSON-based configuration using TinyDB for easy management - CLI commands for configuration management - Optional FRED integration for US average savings rate comparison - “Enemy” mode for competitive savings rate tracking - Python 3.10+ support with automated code quality checks

Users simply enter their savings and income data into a spreadsheet. Unique spreadsheet column headers are mapped to the application through a JSON configuration file, allowing the utility to be used with any custom spreadsheet. When the simulation runs, the user’s monthly savings rates are plotted on an interactive line graph.

Example savings rates plotted

Example savings rates plotted

Users may also supply secondary, “enemy” spreadsheets. This feature is provided to make the experience fun, game-like, and competitive for people who prefer such an experience. If an enemy spreadsheet is provided, the enemy savings rates are plotted alongside those of the main user. This feature is optional.

MMM Savings Rate was inspired by Mr. Money Mustache. Visit the Mr. Money Mustache website and read this article to learn more.

Installation

This package should generally be installed using pip.

For users (CLI only)

pip install git+https://github.com/bbusenius/MMM_Savings_Rate.git#egg=mmm_savings_rate

For users (CLI + GUI)

pip install "git+https://github.com/bbusenius/MMM_Savings_Rate.git#egg=mmm_savings_rate[gui]"

For developers

# Clone and install in development mode with GUI support
git clone https://github.com/bbusenius/MMM_Savings_Rate.git
cd MMM_Savings_Rate
pip install -e .[gui]

# Install development dependencies for linting
pip install -r requirements-dev.txt
Installation Options: - Core: pip install -e . - CLI functionality only - GUI: pip install -e .[gui] - CLI + GUI functionality
- Development: pip install -e .[gui] -r requirements-dev.txt - Everything + development tools ## Setting up the application

In order to get things going, you’ll only need to take the following steps:

  1. Setup a directory of spreadsheet files with the financial data needed to run the simulation.

  2. Configuration: The application automatically creates a JSON configuration file at ~/.mmm_savings_rate/db.json with default settings.

  3. Customize your configuration using the CLI commands or by editing the JSON file directly.

  4. Run the simulation command.

Spreadsheet files

MMM Savings Rate was designed to be flexible in order to work with a variety of spreadsheets. At the moment, spreadsheets must be saved as .xlsx or .csv files, however, column headers can be unique, so it doesn’t matter what labels you use to categorize things. To get started you’ll need financial data for both income and savings.

This data can exist in a single spreadsheet with other financial data or it can exist in separate spreadsheets. How you set it up is your choice, however, certain data is required. The application will allow you to map your column labels to fields, so you don’t have to name them the same as outlined here. You also might want to split some of these fields over multiple columns in your spreadsheet. Jump to the configuration section to learn how to do this. However you decide to enter the data in your spreadsheet, all of the following fields must be represented in some fashion.

  • Date for pay - the date of your paycheck or date associated with the income being entered. The application can parse most date formats.

  • Gross Pay - the amount of money you made in its entirety before taxes were withdrawn.

  • Employer Match - money contributed to a retirement plan by your employer.

  • Taxes and Fees - any taxes and fees taken out of your paycheck before it was delivered, e.g. FICA, Medicare, etc.

  • Savings Accounts - a dollar amount (mapped to 1 or multiple accounts)

  • Date for savings - the date you saved money into each account.

Note about “Savings Accounts”: you might have multiple savings accounts, e.g. Bank Account, Vanguard Brokerage, Roth. Each one of these would contain a dollar amount representing the quantity of money saved for the month. Mapping will be handled in the configuration stage.

For example spreadsheets please look in the csv directory. This should give you a good idea of how to lay things out.

Configuration

MMM Savings Rate uses a single JSON configuration file to manage all settings. The application automatically creates and manages this file at ~/.mmm_savings_rate/db.json.

Automatic Configuration Setup

When you first run the application, it will automatically: 1. Create the configuration directory at ~/.mmm_savings_rate/ 2. Initialize a db.json file with default settings 3. Set up error logging to ~/.mmm_savings_rate/error.log

Configuration Management

You can manage your configuration in three ways:

Option 1: GUI Configuration

Use the Config tab in the graphical interface for visual configuration editing with validation:

# Launch the GUI
savingsrates-gui

Then navigate to the Config tab to edit all settings with form validation and error checking.

Automatic File Watching (GUI only): The GUI application automatically monitors your income and savings spreadsheet files for changes. When you save updates to your spreadsheets (whether opened through the GUI’s “Open Spreadsheet” button or edited externally), the plot will automatically refresh within 1-2 seconds. This provides a seamless workflow:

  1. Configure your file paths in the Config tab

  2. Click “Open Spreadsheet” to edit your data in your preferred application

  3. Save your spreadsheet - the plot updates automatically (no manual refresh needed!)

Option 2: CLI Commands

# View current configuration
sr-show-config

# Update a setting
sr-update-setting main_user_settings pay "/path/to/income.xlsx"
sr-update-setting main_user_settings savings "/path/to/savings.xlsx"

# Validate configuration
sr-validate-config

Option 3: Editing the JSON directly You can directly edit the ~/.mmm_savings_rate/db.json file. Here’s an example configuration:

{
  "main_user_settings": {
    "pay": "/path/to/income.xlsx",
    "pay_date": "Date",
    "gross_income": "Gross Pay",
    "employer_match": "Employer Match",
    "taxes_and_fees": ["OASDI", "Medicare", "Federal Withholding", "State Tax", "FICA"],
    "savings": "/path/to/savings.xlsx",
    "savings_date": "Date",
    "savings_accounts": ["Vanguard Brokerage", "Vanguard 403b", "Vanguard Roth"],
    "notes": "Notes",
    "show_average": true,
    "war": "off",
    "fred_url": "https://api.stlouisfed.org/fred/series/observations?series_id=PSAVERT&file_type=json",
    "fred_api_key": "",
    "goal": 70.0,
    "fi_number": 1000000,
    "total_balances": "Total Balance",
    "percent_fi_notes": "Total Balance Notes"
  },
  "users": [
    {
      "_id": 1,
      "name": "User",
      "config_ref": "main_user_settings"
    }
  ],
  "enemy_settings": []
}
Main settings

The majority of the main settings are listed under main_user_settings. Settings include:

  • pay - a full path to your income spreadsheet.

  • pay_date - the name of a column header for the dates of income or payment transactions.

  • savings - a full path to your savings spreadsheet (can be the same file used for pay).

  • savings_date - the name of a column header for the dates of income or payment transactions.

  • gross_income - the name of a column header in your spreadsheet representing gross pay.

  • employer_match - the name of a column header in your spreadsheet that represents your employer match.

  • taxes_and_fees - the names of column headers in your spreadsheet containing taxes and fees.

  • savings_accounts - the names of column headers in your spreadsheet that contain savings data from an investment account or accounts.

  • goal - optional setting that allows you to set a savings rate goal that you’re trying to reach.

  • war - allows you to show or hide, “enemy” plots on your graph. Set this to, “off” if you only want to see your own data.

Additional settings

US Average Savings Rates from FRED

Optional settings allow you to plot the average US savings rates alongside your own. This data comes from the Federal Reserve Economic Data (FRED) at the Federal Reserve Bank of St. Louis.

  • fred_url - the url of the FRED API endpoint.

  • fred_api_key - an API token to use FRED.

In order to use these settings, you will need to sign up for an account with FRED and request an API token. This takes about 5 minutes and can be done on their website.

Once you enable FRED, you will be able to see how your savings rates dominate the US average*.

US average savings rates plotted

US average savings rates plotted

*US average savings rates calculated by FRED are generated after removing outlays from personal income. Since outlays include purchases of durable and non-durable goods, these savings rates are inflated. Even so, as a Mustachian you will easily beat these averages.

Notes and goal

If you want to annotate points on your plot with text from your spreadsheet, you can map a notes field. This should match a column header on your spreadsheet. If you’re using separate spreadsheets for savings and income, the application will look for the same column name in both spreadsheets and de-dupe duplicate notes for the same month while displaying all notes from both spreadsheets for the same month if they’re unique.

  • notes - the name of a column header that maps to notes or special events that you want to show on your plot.

A goal can be added to your plot as well.

  • goal - numeric value of a savings rate goal you’d like to reach, e.g. 70.

Savings rates plotted with annotations

Savings rates plotted with annotations

% FI

If you want to plot your progress towards FI as a percentage of your FI number, you can enable this with the following settings in your db.json:

  • fi_number - your FI number.

  • total_balances - a spreadsheet heading that maps to a column where you track the total monthly balance of all your accounts.

  • percent_fi_notes - a spreadsheet heading that maps to a column with text that you want to show on the % FI plot. Entries will appear as event dots on the plot and will display tooltips with the notes on hover.

This doesn’t take into account liabilities so, if you have them, you can just as easily map these configurations to a column that tracks net worth instead.

Percent FI plotted with annotations

Percent FI plotted with annotations

Running the simulation

Once you have your spreadsheet files ready and have configured your settings, you can run the application:

  1. First run: The application will automatically create the configuration file with defaults:

    savingsrates
    
  2. Configure your settings using CLI commands:

    # Update file paths to point to your spreadsheets
    sr-update-setting main_user_settings pay "/path/to/your/income.xlsx"
    sr-update-setting main_user_settings savings "/path/to/your/savings.xlsx"
    
    # Update column mappings as needed
    sr-update-setting main_user_settings savings_accounts '["Account1", "Account2"]'
    
  3. Run the application:

    savingsrates
    

When you run the command, a plot of your monthly savings rates will open in a browser window.

CLI Options

The savingsrates command supports the following optional arguments:

  • -u, --user USER_ID - Specify which user to analyze (default: 1)

  • -o, --output OUTPUT_PATH - Specify where to save the HTML plot file (default: savings-rates.html)

Usage Examples:

# Generate plot with default settings (saves to savings-rates.html)
savingsrates

# Analyze a different user and save to a custom location
savingsrates --user 2 --output my-savings-report.html

# Save plot to a specific directory (directories will be created if needed)
savingsrates -o ~/.mmm_savings_rate/plots/monthly-report.html

# Save to an absolute path
savingsrates -o /tmp/reports/savings-$(date +%Y%m%d).html

# Get help and see all available options
savingsrates --help

CLI Management Commands

The application now includes dedicated CLI commands for configuration management:

  • sr-show-config - Display current configuration

  • sr-validate-config - Validate configuration and report any errors

  • sr-update-setting <table> <field> <value> - Update specific settings

Using the GUI

MMM Savings Rate includes a full-featured graphical user interface built with BeeWare/Toga.

Installing the GUI

Option 1: Python Package (pip)

# Install with GUI support
pip install "git+https://github.com/bbusenius/MMM_Savings_Rate.git#egg=mmm_savings_rate[gui]"

Option 2: OS Package Installer

# Command line installation (Ubuntu/Debian)
sudo dpkg -i mmm-savings-rate-2.0.0-1.deb

# Or double-click the .deb file to install via Ubuntu App Center

Note: Currently only .deb packages for Ubuntu/Debian are available. Other OS package formats may be added in future releases.

Launching the GUI

If installed via .deb package: - Launch like any other application from your desktop environment (Activities menu, application launcher, etc.) - Or run from command line: savingsrates-gui

If installed via pip:

# Start the GUI application
savingsrates-gui

GUI Features

The GUI provides an intuitive interface with four main tabs:

📊 Plot Tab (Default)

  • Interactive Bokeh plots displayed directly in the application

  • Automatic simulation runs on startup with your current configuration

  • Automatic refresh when configuration is saved or files are modified

  • Responsive plots that adapt to window size

  • No browser required - plots display within the GUI

GUI Plot Tab

GUI Plot Tab

⚙️ Config Tab

  • Visual configuration editor for all settings

  • Organized sections: File Paths, Column Mappings, Account Lists, Display Options, FRED API, Notes & Goals

  • Form validation with error checking and helpful messages

  • Save & Validate buttons to apply changes

  • Manual Refresh Plot button for edge cases (plots auto-refresh when config is saved)

  • Automatic field type handling (text, numbers, lists, checkboxes)

  • Shares configuration with CLI tools via ~/.mmm_savings_rate/db.json

GUI Config Tab

GUI Config Tab

💳 Income Tab

  • Read-only table view of your income spreadsheet data

  • Last 10 entries displayed in reverse chronological order (most recent first)

  • All spreadsheet columns visible with scrollable table

  • File information showing path, last modified date, and total rows

  • Reload Data button to refresh after external spreadsheet changes

  • Open Spreadsheet button to edit files in external applications (Excel, LibreOffice, etc.)

GUI Income Tab

GUI Income Tab

💰 Savings Tab

  • Read-only table view of your savings spreadsheet data

  • Last 10 entries displayed in reverse chronological order (most recent first)

  • All spreadsheet columns visible with scrollable table

  • File information showing path, last modified date, and total rows

  • Reload Data button to refresh after external spreadsheet changes

  • Open Spreadsheet button to edit files in external applications

GUI Savings Tab

GUI Savings Tab

GUI Workflow

First-Run Experience

When you first launch the GUI without any configuration, you’ll see a placeholder message prompting you to configure your settings:

GUI First Run - No Plot Available

GUI First Run - No Plot Available

After clicking “Cancel”, the GUI automatically creates default configuration and takes you to the Config tab to get started:

GUI First Run - Default Config

GUI First Run - Default Config

Typical Workflow

  1. First Run: The GUI automatically creates default configuration at ~/.mmm_savings_rate/db.json

  2. Configure: Use the Config tab to set your spreadsheet file paths and column mappings

  3. View Data: Check Income and Savings tabs to verify your data is loading correctly

  4. Generate Plot: Return to Plot tab to view your savings rate visualization (automatically generated)

  5. Iterate: Make configuration changes - plots refresh automatically when you save config

GUI Error Handling

The GUI includes error handling with user-friendly dialogs:

  • Configuration errors automatically redirect to the Config tab with specific error messages

  • File not found errors provide clear guidance on fixing file paths

  • Data format errors help identify spreadsheet formatting issues

  • Validation errors highlight specific fields that need correction

CLI and GUI Integration

The GUI and CLI tools work seamlessly together:

  • Shared configuration: Both use the same ~/.mmm_savings_rate/db.json file

  • CLI commands work: Use sr-show-config, sr-validate-config, etc. alongside the GUI

  • Plot compatibility: GUI and CLI generate identical Bokeh plots

  • No conflicts: You can switch between GUI and CLI freely

Requirements

This utility requires Python 3.10 or higher (tested on Python 3.10, 3.11, and 3.12). All additional dependencies should be automatically downloaded and included during installation.

Dependencies

Development

Documentation

This project uses Sphinx to generate documentation hosted on Read the Docs.

The documentation is automatically generated from this README file. To update the documentation:

Prerequisites: - Install pandoc for converting Markdown to reStructuredText

Process: 1. Update this README.md with any changes 2. Convert to Sphinx format: bash    cd docs    make update-readme  # Converts README.md to index.rst using pandoc    make html          # Builds the documentation (optional - for local preview)

The documentation will automatically rebuild on Read the Docs when changes are pushed to the repository.

Running tests

This project uses a modern Python package structure with source code in src/. The recommended way to run tests is using Briefcase, which handles the package environment correctly.

Recommended: Using Briefcase

# Install briefcase if not already installed
pip install briefcase

# Run tests with proper package setup
briefcase dev --test

Alternative: Using pytest

# Install pytest and run tests
pip install pytest
pytest tests/ -v

Note: The GitHub Actions workflow uses pytest for CI (core dependencies only), while local development can use Briefcase for full testing.

Code Quality and Linting

This project uses automated code formatting and linting:

# Install development dependencies
pip install -r requirements-dev.txt

# Check code formatting
black --check .

# Format code automatically
black .

# Check import sorting
isort --check-only .

# Fix import sorting
isort .

# Run linting
flake8 .

# Run all checks (same as CI)
flake8 . && black --check . && isort --check-only .

Adding Enemies to db.json

To add an enemy for competitive plotting, edit db.json by adding entries to the enemy_settings and users tables. Ensure the _id is unique and matches between tables. Example:

"enemy_settings": [
  {
    "_id": 2,
    "pay": "/path/to/your/income-joe.xlsx",
    "pay_date": "Date",
    "gross_income": "Gross Pay",
    "employer_match": "Employer Match",
    "taxes_and_fees": ["Federal Tax", "State Tax"],
    "savings": "/path/to/your/savings-joe.xlsx",
    "savings_date": "Date",
    "savings_accounts": ["Savings Account"],
    "notes": "",
    "show_average": true,
    "war": "on",
    "fred_url": "https://api.stlouisfed.org/fred/series/observations?series_id=PSAVERT&file_type=json",
    "fred_api_key": "",
    "goal": null,
    "fi_number": null,
    "total_balances": "",
    "percent_fi_notes": ""
  }
],
"users": [
  {"_id": 1, "name": "User", "config_ref": "main_user_settings"},
  {"_id": 2, "name": "Joe", "config_ref": "enemy_2"}
]

Ensure the config_ref in users (e.g., “enemy_2”) uniquely identifies the enemy’s settings in enemy_settings.

Warning: Maintain JSON validity during manual edits. Use sr-validate-config to check for errors.