Package: rbcz
rbcz.pyrbczis a Python library for parsing the plain-text bank statements
that Raiffeisen Bank send out via email. It exposes a simple API to
either parse statements stored on your local filesystem or to search
through your email and retrieve them via IMAP.InstallEither retrieve from pypi using pip:$ pip install rbczor clone this repo, and install usingsetup.py:$ git clone https://github.com/smcl/rbcz.py
$ cd rbcz.py
$ python setup.py installMethodsThere are three simple functions -read_statement,read_statementsandread_statements_from_imap. To parse a single
statement we can use theread_statementfunction, which takes a
single parameter - the path to the bank statement on the local
filesystem - and returns aStatementobject:from rbcz import *
statement = rbcz.read_statement("/path/to/stmt_january_czk.txt")If we have a number of statements locally we can useread_statementswhich accepts a list of filenames to parse, and returns a list ofStatement:from rbcz import *

statement_filenames = [
    "stmt_jan_czk.txt",
    "stmt_feb_czk.txt",
    "stmt_mar_czk.txt"
]

statements = rbcz.read_statements(statement_filenames)If we don’t have all our statements stored locally we can useread_statements_from_imapto connect to an IMAP server and search it
for emails from the “info@rb.cz” address, download and parse the
attachments and return a list ofStatement.from rbcz import *

statements = read_statements_from_imap("imap.gmail.com", "my.email.address@gmail.com", "password123", "inbox")TypesThere are two types -StatementandMovement.StatementAStatementrepresents a monthly statement:account_name- (string) the name of the main account holder (your
name!)account_number- (string) your account numberiban- (string) the IBAN of your accountcurrency- (string) the currency the account holdsnumber- (int) the number of the statement (your first statement
will be1)from_date- (datetime) the opening date of the statementto_date- (datetime) the closing date of the statementopening_balance- (Decimal) the balance at the opening date of
the statementincome- (Decimal) the income you’ve received during the
statement’s reporting periodexpenses- (Decimal) the expenses you’ve paid out during the
statement’s reporting periodclosing_balance- (Decimal) the balance at the closing date of
the statementblocked- (Decimal) amount ringfenced for payments outreceivable- (Decimal) amount received but yet to clear/settleavailable_balance- (Decimal) amount of money available to
withdraw at the closing date of the statementmovements- (List of Movement) the individual cash movements
(payments in or out) during the reporting periodMovementAMovementis an individual transaction - for example an ATM
withdrawal or Debit Card payment. EachStatementwill have a list ofMovementcalledmovementsfor all the transactions during the
reporting period. EachMovementhas the following: *number-
(int) id of the movement in the current statement *amount-
(Decimal) amount of the thing *date_deducted- (datetime) the date
the transaction was submitted originally *date_completed-
(datetime) the date + time the transaction was finalised at *counterparty_account_number- (string) the account the payment was
sent to or received from *counterparty_details- (string)
information about the account the payment was sent to or received from,
if available *narrative- (string) additional information about
the transaction *transaction_type- (string) what type of
transaction occurred *specific_symbol- (string) specific symbol
for movement *variable_symbol- (string) variable symbol for
movement *constant_symbol- (string) constant symbol for movementExampleThe following script will attempt to parse all the statements in the./rbdirectory, then take the closing balance and high/low water
marks of each period and plot it on a graph.#!/usr/bin/python

# system/lib imports
import os
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.dates import YearLocator, MonthLocator, DateFormatter, drange, date2num
from numpy import arange

# rbcz library
from rbcz import *

# load and sort the statements
statements = sorted(
    rbcz.read_statements([ "./rb/" + f for f in os.listdir("./rb") ]),
    key=lambda stmt: stmt.from_date)

# function to deterine high/low-water mark on account
def high_low_water(stmt):
    bal = stmt.opening_balance
    hwm = bal
    lwm = bal
    for m in stmt.movements:
        bal += m.amount
        if bal > hwm:
            hwm = bal
        if bal < lwm:
            lwm = bal
    return (lwm, hwm)

#plt.gca().set_color_cycle(['green', 'black', 'red'])


# extract high/low-water marks
water_marks = [ high_low_water(s) for s in statements ]
low_water_marks = [ wm[0] for wm in water_marks ]
high_water_marks = [ wm[1] for wm in water_marks ]

# extract closing balance and dates
closing_balances = [ s.closing_balance for s in statements ]
dates = date2num([ s.from_date for s in statements ])

# prepare and display the chart using matplotlib
y = arange(len(dates)*1.0)

# plot the data
fig, ax = plt.subplots()
ax.set_color_cycle(['green', 'black', 'red'])
ax.plot_date(dates, high_water_marks, "o-")
ax.plot_date(dates, closing_balances, "o-")
ax.plot_date(dates, low_water_marks, "o-")

# fix up the axes
ax.xaxis.set_major_locator(YearLocator())
ax.xaxis.set_minor_locator(MonthLocator())
ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))

ax.fmt_xdata = DateFormatter('%Y-%m-%d')
fig.autofmt_xdate()

# add a legend
ax.legend(['highest', 'closing', 'lowest'], loc='upper left')

plt.show()Depending on the content of the bank statements this will generate a
graph like the following:rbcz.pngTODOget coverage to 100%decide if error parsing an imap statement should be eaten, printed or
an exceptioncheck if it’s possible to improve the parsing - there are a LOT of
regexes that I throw around and it’s not pretty…check if anyone I know gets Czech statements, see if we can parse
them too. Is there any other languages - German?check if it works for non-Czech-Republic Raiffeisen