A Python implementation of double-entry bookkeeping inspired by the Medici banking dynasty of Renaissance Florence.
MediciMess is an educational project that demonstrates the fundamental principles of double-entry accounting through a simulation of the Medici Bank's operations in 1397. The implementation uses florins as the currency in honor of the historical Medici banking dynasty.
This project showcases how double-entry accounting works - a system where every financial transaction affects at least two accounts, and the sum of debits must always equal the sum of credits.
Double-entry accounting is a bookkeeping method that records each transaction twice - as both a debit and a credit. This system provides a complete picture of financial transactions and helps maintain the fundamental accounting equation:
Assets = Liabilities + Equity
- Assets: Resources owned by the business (Cash, Accounts Receivable, Land, etc.)
- Liabilities: Debts owed by the business (Loans, Accounts Payable, etc.)
- Equity: Owner's interest in the business (Capital, Retained Earnings)
- Revenue: Income earned by the business (Interest Income, Sales, etc.)
- Expenses: Costs incurred by the business (Wages, Rent, etc.)
- Assets and Expenses: Increased by debits, decreased by credits
- Liabilities, Equity, and Revenue: Increased by credits, decreased by debits
- ✅ Complete double-entry accounting implementation
- ✅ Support for all five main account types
- ✅ Transaction validation (ensures debits equal credits)
- ✅ Trial Balance generation
- ✅ Balance Sheet reporting
- ✅ Income Statement reporting
- ✅ Decimal precision for accurate financial calculations
- ✅ Historical simulation of Medici Bank operations (1397)
- ✅ 20,000 historical transactions dataset (1390-1440) based on real events
- ✅ Import/Export transaction data in CSV and JSON formats
- Python 3.6 or higher
- No external dependencies (uses only Python standard library)
- Clone the repository:
git clone https://github.com/ZipCodeCore/MediciMess.git
cd MediciMess- Run the program:
python3 medici-banking.pyThe main script demonstrates a series of banking transactions from the year 1397:
- Initial Capitalization: Giovanni de' Medici invests 10,000 florins
- Loan Issuance: A 2,000 florin loan to a wool merchant
- Loan Repayment: Partial repayment with interest (200 florins)
- Asset Purchase: Acquisition of land for a new banking house (3,000 florins)
- Operating Expenses: Quarterly wages for bank employees (800 florins)
When you run the script, you'll see:
- Detailed transaction logs showing debits and credits
- A Trial Balance verifying the books are balanced
- A Balance Sheet showing the financial position
- An Income Statement showing profitability
AccountType: Enum defining the five account typesAccount: Represents a single financial account with debit/credit operationsTransactionEntry: Represents a single entry in a transactionTransaction: Represents a complete double-entry transactionLedger: The main ledger managing all accounts and transactions
Account.debit()/Account.credit(): Apply debits and credits to accountsTransaction.is_balanced(): Verify that debits equal creditsTransaction.post(): Apply transaction to account balancesLedger.record_transaction(): Record and validate new transactionsLedger.print_trial_balance(): Generate trial balance reportLedger.print_balance_sheet(): Generate balance sheetLedger.print_income_statement(): Generate income statement
This project is ideal for:
- Learning the fundamentals of double-entry accounting
- Understanding how banking systems track financial transactions
- Exploring the historical context of Renaissance banking
- Studying Python OOP design patterns for financial systems
The Medici family dominated banking in Florence during the 15th century. They pioneered many modern banking practices, including:
- International banking networks
- Bills of exchange
- Double-entry bookkeeping
- Letters of credit
This simulation honors their legacy by implementing the same fundamental accounting principles they used to build one of history's greatest banking dynasties.
This repository includes a dataset of 20,000 historically-themed transactions covering the period 1390-1440, based on actual events from the Medici Bank's operations:
- Western Schism and Papal Banking (1402-1420s)
- Council of Constance - Including the famous 35,000 florin ransom for Pope John XXIII (1415)
- Florentine-Milanese Wars (1390-1402, 1422-1426)
- Wars in Lombardy (1423-1454)
- Alum trade from papal monopoly mines
- Regular banking operations across 8 branch locations
# Generate the transaction dataset
python3 generate_historical_data.py
# Validate the generated data
python3 validate_transactions.pyFor detailed information about the transaction data, see TRANSACTION_DATA.md.
The Medici Bank ledger system supports importing and exporting large volumes of transaction data in both CSV and JSON formats. This makes it easy to:
- Backup your ledger data
- Transfer data between systems
- Analyze transactions in spreadsheets
- Load historical datasets
# Run the import/export demonstration
python3 demo_import_export.pyThis interactive demo will show you how to:
- Export transactions to CSV and JSON files
- Import transactions from CSV and JSON files
- Import the full 20,000 transaction historical dataset
- Verify that all imported data maintains double-entry accounting principles
from medici_banking import Ledger, AccountType, TransactionEntry
from decimal import Decimal
from datetime import date
# Create a ledger with some transactions
ledger = Ledger("My Bank")
cash = ledger.create_account("Cash", AccountType.ASSET)
capital = ledger.create_account("Owner's Capital", AccountType.EQUITY)
ledger.record_transaction(
date(2024, 1, 1),
"Initial investment",
TransactionEntry(cash, Decimal("10000.00")),
TransactionEntry(capital, Decimal("10000.00"))
)
# Export to CSV
ledger.export_transactions_to_csv("my_transactions.csv")
# Export to JSON
ledger.export_transactions_to_json("my_transactions.json")# Create a new ledger
ledger = Ledger("Import Demo")
# Import from CSV (silent mode)
count = ledger.import_transactions_from_csv("my_transactions.csv")
print(f"Imported {count} transactions")
# Import from JSON (verbose mode - prints each transaction)
count = ledger.import_transactions_from_json("my_transactions.json", verbose=True)
# Verify the books are balanced
ledger.print_trial_balance()id,date,description,debit_account,debit_amount,credit_account,credit_amount,credit_account_2,credit_amount_2
1,2024-01-01,Initial investment,Cash,10000.00,Owner's Capital,10000.00,,
2,2024-01-15,Service revenue,Cash,1500.00,Service Revenue,1500.00,,
[
{
"id": 1,
"date": "2024-01-01",
"description": "Initial investment",
"debits": [
{"account": "Cash", "account_type": "ASSET", "amount": "10000.00"}
],
"credits": [
{"account": "Owner's Capital", "account_type": "EQUITY", "amount": "10000.00"}
]
}
]- Automatic Account Creation: Accounts are automatically created during import if they don't exist
- Account Type Inference: For CSV imports, account types are inferred from account names
- Transaction Validation: All imported transactions are validated to ensure debits equal credits
- Batch Processing: Efficiently handles large datasets (tested with 20,000+ transactions)
- Silent/Verbose Modes: Control whether transactions are printed during import
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2025 Zip Code Wilmington Core
This is an educational project. Feel free to fork and experiment with different transaction scenarios or extend the functionality to include more advanced accounting features.