I analyzed my fiscal year 2019 in Javascript

Using my fintech project for personal accounts

As year 2019 went by, I figured I could look into my financial data of last year. I started a project called Pecuniator a while ago and now I want to bring it to good use. You can run this on any data export, but I have choosen the “fiscal year 2019” just for the catchy title.

Getting my data

I started by exporting the CAMT.052 files from the online banking interface of my bank. Thanks to PSD2, any European bank should offer an export of transaction data in the CAMT standard format as XML. Thanks to PSD2 I had to enter two TANS just for this, but I got my data. At first I was surprised that this was a compressed folder with many files instead of a few larger ones.

What is Pecuniator?

Let’s get to Pecuniator now. Pecuniator is an open source project, that was started to make it easier for private users (developers) to work with financial data. Right now Pecuniator is a web app which let’s you import your transaction history and write scripts for working with that data. Everything happens in the browser and the app never posts anything to any server. You can find the app at web.pecuniator.com. We may publish a desktop version (with Electron) from time to time, but the web app works just better and can be updated more easily.

Pecuniator let’s you write your own scripts with an API to your imported data. Our design goal is to make a well defined API and an awesome developer experience. It provides an editor with autocomplete to use the objects with ease.

Start going through my data

I hacked together a script with the existing Pecuniator API to put my transcations into categories. So please check out this script. It is the default script for pecuniator right now, but you can just copy and paste it into the web app.

/** @type {Pecuniator} */
const pecuniator = api;
/**
Your data is available with the `pecuniator` variable. Use autocomplete for assistance
You can find documentaion for all available objects here: https://docs.pecuniator.com/modules/_interface_.html
**/
const acc = pecuniator.accounts[0];
this.console.info('Script', acc.currency);
const firstTransaction = pecuniator.entries[0];

const categories = { //Add you categories here with id, title and search query.
    saving: {
        remittanceInformation: ["DEPOT"],
        amount: 0,
        title: "Savings"    
    },
    fuel: {
        creditorName: ["Tank"],
        amount: 0,
        title: "Tank"   
    },
    insu: {
        remittanceInformation: ["Versicherung"],
        amount: 0,
        title: "Insurance"   
    },
    online: {
        creditorName: ["Paypal"],
        amount: 0,
        title: "Online"   
    },
    cell: {
        creditorName: ["Drillisch", "Telekom"],
        amount: 0,
        title: "Cellphone"   
    },
};
if (!firstTransaction) {
    this.postMessage({ error: 'No transaction' })
} else {
    for (const entry of pecuniator.entries) {
        entry.found = []
        checkCategories(entry);         
    }

    for(const name in categories) {
        const cat = categories[name];
        this.postMessage({ textAppend: `|| ${cat.title} - ${cat.amount}€ ||` });
    }
}
/** @type {PecuniatorEntry} */
function checkCategories(tmp) {
    /** @type {PecuniatorEntry} */
    const entry = tmp;
    for(const catname in categories) {
        const cat = categories[catname];
        for(const check in cat) {
            if(check !== "amount" && check !== "title" && typeof entry[check] !== "undefined") {
                if (typeof entry[check] === "string"){
                    entry[check] = [entry[check]];
                }
                for (const test of cat[check]) {
                    if (!entry.found.includes(catname) && entry[check].toString().toLowerCase().includes(test.toLowerCase())) {
                        cat.amount += new Number(entry.amount);
                        entry.found.push(catname);
                    }
                }
            }
        }
    }
}

Let’s dig into what happens in this script. The checkCategories function does the job of putting transactions in categories you define. The function is hard to understand but it does its job and that’s the goal for Pecuniator scripts.

The variable categories is the one you want to customize to analyze your data. You can add new categories by copying the old ones and changing id and title. All other properties of these category objects are properties of entries in Pecuniator that are checked with include(). For example remittanceInformation: ["Insurance"] checks every transaction if the subject (Verwendungszweck in German) contains the string “Insurance”. If so this transaction increases the amount for the corresponding category. You can find more about the properties of entries/transactions in the docs.

You can play around with the objects in the editor and customize the script to your needs. We would love to see new scripts, too. You may find out that it’s easy to create something for your data and use case. If yes please send us your scripts. We would like to curate them and/or create a marketplace for sharing later. If you have problems let us know how to improve or create a pull request.

We want this project to become a full open source project. Right now it is just an rough idea and some proof of concept code. To make it usable we need to create docs, a stable API, scripts, convenience functions and more with your help. If something is unclear or buggy please create an issue on Github.

Just jump to web.pecuniator.com and try it yourself

Vision

What you can use now is an early concept on what the Pecuniator project could be. Exporting your data and running analysis afterwards is not that practical. Ideally the Pecuniator app would not need exported files with historical transaction data, but get access to the customers live data via the XS2A banking APIs introduced with PSD2. We did a few experiments with XS2A, but to take this project in this direction we would need a partner or sufficient funds because access to production banking APIs is subject to regulatory approval. If you want to learn more about this or want to help, please talk to us. You can email us directly via [email protected], use the mailing list [email protected] or go to this form. We are looking for partners to make this possible!