Exporting from Homebank and Importing into Ledger
I am using Homebank to keep track of my financial situation. Recently, I thought about switching to Ledger (which belongs to a family of plaintext accounting tools). Homebank does not offer any decent export features, so I had to come up with my own strategies to transfer my data into the Ledger format.
The following Python script transforms a Homebank file into CSV:
#!/usr/bin/env python3 import argparse import datetime from decimal import Decimal import xml.etree.ElementTree as ET def convert_homebank_date(serial_date): start_date = datetime.datetime(1, 1, 1, 0, 0) new_date = start_date + datetime.timedelta(serial_date - 1) return new_date.strftime("%Y-%m-%d") def attrib_or_empty(node, attribute_name): if attribute_name in node.attrib: return node.attrib[attribute_name] else: return '' def build_lookup(root, node_name): lookup = { '' : '' } for node in root.iter(node_name): lookup[node.attrib['key']] = node.attrib['name'] return lookup def to_decimal(number_string): return Decimal(number_string).quantize(Decimal('.01')) def parse_homebank(file_name): root = ET.parse(file_name).getroot() category_lookup = build_lookup(root, 'cat') account_lookup = build_lookup(root, 'account') print('date,src_account,dst_account,category,amount,payee,text') for transfer_node in root.iter('ope'): date = convert_homebank_date(int(transfer_node.attrib['date'])) src_account = account_lookup[transfer_node.attrib['account']] dst_account = account_lookup[attrib_or_empty( transfer_node, 'dst_account')] amount = to_decimal(transfer_node.attrib['amount']) wording = attrib_or_empty( transfer_node, 'wording').replace(";", "").replace(",", "") category = category_lookup[attrib_or_empty(transfer_node, 'category')] info = attrib_or_empty(transfer_node, 'info') print('{},{},{},{},€{},{},{}'.format( date, src_account, dst_account, category, amount, wording, info)) def main(): parser = argparse.ArgumentParser( description='Converts a homebank .xhb file into a csv output') parser.add_argument('source', help='The homebank .xhb file') args = parser.parse_args() parse_homebank(args.source) if __name__ == '__main__': main()
I'm not using Homebank's payee field, which is why the created CSV output does
not contain this information. Ledger's convert
command expects a few
predefined headers to create new records. Every other (unknown) header is added
as a comment. There are still a few minor points to watch out for:
- De-duplication: The Homebank CSV export might contain duplicate entries for situations in which an amount is transferred between two accounts (e.g. transferring money from a checking account into a savings account).
- Accounts mapping: Homebank's categories have to be "translated" (or "mapped") into Ledger accounts. This task can be simplified if you are using an editor which supports macros.
- Account inference: Ledger can be configured to infer an account based on the Payee field. This feature can speed up the above step about mapping Homebank categories to Ledger accounts. Here's an example:
account Expenses:Food payee (Walmart|Whole Foods) 2019/01/01 * Thanks for shopping at Walmart Expenses:Food $ -25 Bank:Checking
Converting my Homebank file (which contains data for +3 years) into a Ledger file took me about one hour. I'm not sure if I'll stick with Ledger, so I'm maintaining both files until I've made a decision.