This example demonstrates how to programmatically build Beancount transactions from CSV bank statement data using the ast builder functions.
The importer reads a CSV file containing bank transactions and converts each row into a properly formatted Beancount transaction. It showcases:
- Using
encoding/csvfrom Go's standard library to parse CSV files - Building AST nodes with the functional options pattern (
ast.NewTransaction,ast.NewPosting) - Automatic expense categorization based on payee names
- Error handling for invalid dates and amounts
- Formatting transactions with the
formatterpackage
The input CSV file should have the following columns:
Date,Payee,Amount
2024-01-15,Whole Foods Market,-125.43
2024-02-01,Acme Corp Payroll,3500.00- Date: YYYY-MM-DD format
- Payee: Transaction description
- Amount: Positive for income, negative for expenses
Run the importer with a CSV file:
go run main.go transactions.csvThis will output Beancount transactions to stdout:
; Imported from transactions.csv
; Generated by csv_importer example
2024-01-15 * "Whole Foods Market"
Expenses:Groceries 125.43 USD
Assets:Checking
2024-02-01 * "Acme Corp Payroll"
Assets:Checking 3500.00 USD
Income:Salary
You can redirect the output to a file:
go run main.go transactions.csv > imported.beancountEdit the categorizeExpense() function to add custom categorization rules:
case strings.Contains(payeeLower, "amazon"),
strings.Contains(payeeLower, "ebay"):
return "Expenses:Shopping"Modify the checkingAccount variable in recordToTransaction():
checkingAccount, _ := ast.NewAccount("Assets:BankOfAmerica:Checking")Use additional builder options when creating transactions:
txn := ast.NewTransaction(date, record.Payee,
ast.WithFlag("*"),
ast.WithTags("imported", "needs-review"),
ast.WithPostings(postings...),
)This example shows the key features of the ast builder API:
- Validated constructors:
ast.NewDate()andast.NewAccount()return errors for invalid input - Functional options:
ast.NewTransaction()andast.NewPosting()use the options pattern for flexibility - Builder composition: Postings are built separately and passed to transactions
- Formatting: The
formatterpackage outputs clean, aligned Beancount syntax
For more complex scenarios, you might want to:
- Add support for costs and prices (for investment accounts)
- Handle multiple currencies
- Parse additional CSV columns (category, tags, account overrides)
- Implement interactive categorization prompts
- Store categorization rules in a configuration file