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
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
pip install -e . - CLI
functionality only - GUI: pip install -e .[gui] - CLI + GUI
functionalitypip install -e .[gui] -r requirements-dev.txt -
Everything + development tools ## Setting up the applicationIn order to get things going, you’ll only need to take the following steps:
Setup a directory of spreadsheet files with the financial data needed to run the simulation.
Configuration: The application automatically creates a JSON configuration file at
~/.mmm_savings_rate/db.jsonwith default settings.Customize your configuration using the CLI commands or by editing the JSON file directly.
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:
Configure your file paths in the Config tab
Click “Open Spreadsheet” to edit your data in your preferred application
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 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
% 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
Running the simulation
Once you have your spreadsheet files ready and have configured your settings, you can run the application:
First run: The application will automatically create the configuration file with defaults:
savingsrates
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"]'
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 configurationsr-validate-config- Validate configuration and report any errorssr-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
.debpackages 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
⚙️ 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
💳 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
💰 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 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
After clicking “Cancel”, the GUI automatically creates default configuration and takes you to the Config tab to get started:
GUI First Run - Default Config
Typical Workflow
First Run: The GUI automatically creates default configuration at
~/.mmm_savings_rate/db.jsonConfigure: Use the Config tab to set your spreadsheet file paths and column mappings
View Data: Check Income and Savings tabs to verify your data is loading correctly
Generate Plot: Return to Plot tab to view your savings rate visualization (automatically generated)
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.jsonfileCLI commands work: Use
sr-show-config,sr-validate-config, etc. alongside the GUIPlot 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
Runtime dependencies: See requirements.txt
Development dependencies: See requirements-dev.txt (includes linting tools: flake8, black, isort)
Build configuration: See pyproject.toml
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.