portfolio-performance / portfolio

Track and evaluate the performance of your investment portfolio across stocks, cryptocurrencies, and other assets.
http://www.portfolio-performance.info
Eclipse Public License 1.0
2.98k stars 609 forks source link

JSON Import / Export - Schema Definition #1193

Open buchen opened 5 years ago

buchen commented 5 years ago

Ziel

Definition eines JSON Import und Export Formats für Buchungen.

Die Idee

JSON Schema

{
    "title": "JSON schema for Portfolio Performance Transactions",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "array",
    "items": {
        "description": "Transaction",
        "type": "object",
        "additionalProperties": false,
        "required": [
            "type",
            "date",
            "amount",
            "currency"
        ],
        "properties": {
            "type": {
                "type": "string",
                "enum": [
                    "PURCHASE",
                    "SALE",
                    "INBOUND_DELIVERY",
                    "OUTBOUND_DELIVERY",
                    "SECURITY_TRANSFER",
                    "CASH_TRANSFER",
                    "DEPOSIT",
                    "REMOVAL",
                    "INTEREST",
                    "DIVIDEND",
                    "TAX",
                    "FEE"
                ]
            },
            "account": {
                "type": "string"
            },
            "portfolio": {
                "type": "string"
            },
            "target-account": {
                "type": "string"
            },
            "target-portfolio": {
                "type": "string"
            },
            "date": {
                "type": "string",
                "pattern": "^[1-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$"
            },
            "time": {
                "type": "string",
                "pattern": "[0-2][0-9]:[0-5][0-9]$"
            },
            "amount": {
                "type": "number"
            },
            "currency": {
                "type": "string",
                "pattern": "^[A-Z]{3}$"
            },
            "note": {
                "type": "string"
            },
            "shares": {
                "type": "number"
            },
            "security": {
                "type": "object",
                "additionalProperties": false,
                "minProperties": 1,
                "properties": {
                    "uuid": {
                        "type": "string"
                    },
                    "isin": {
                        "type": "string"
                    },
                    "wkn": {
                        "type": "string"
                    },
                    "name": {
                        "type": "string"
                    }
                }
            },
            "units": {
                "type": "array",
                "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                        "type",
                        "amount"
                    ],
                    "properties": {
                        "type": {
                            "type": "string",
                            "enum": [
                                "GROSS_VALUE",
                                "FEE",
                                "TAX"
                            ]
                        },
                        "amount": {
                            "type": "number"
                        },
                        "exchange-rate": {
                            "type": "number"
                        },
                        "forex": {
                            "type": "number"
                        },
                        "currency": {
                            "type": "string",
                            "pattern": "^[A-Z]{3}$"
                        }
                    }
                }
            }
        }
    }
}

Beispieldatei

[
    {
        "type" : "PURCHASE",

        "account" : "Cash Account",
        "portfolio" : "Security Account",
        "target-account" : "Other Cash Account",
        "target-portfolio" : "Other Securities Account",

        "date" : "2019-01-01",
        "time" : "15:06",
        "amount" : 345.43,
        "currency" : "EUR",

        "note" : "free note",

        "shares" : 1.2929293,

        "security" : {
            "uuid" : "YZW",
            "isin" : "DE...",
            "wkn" : "A0YDZE",
            "name" : "Name"
        },

        "units" : [
            {
                "type" : "FEE",
                "amount" : 224.17,
                "exchange-rate" : 1.120202,
                "forex" : 200.12,
                "currency" : "USD"
            },
            {
                "type" : "TAX",
                "amount" : 12.34
            }
        ]
    }
]

Pflichtfelder / Optional Felder

R = Required / Pflichtfeld
O = Optional
- = nicht erlaubt
O* = Optional mit oder ohne Fremdwährung
C? = Pflichtfeld Wertpapie/Kontowährung unterschiedlich sind
PURCHASE, SALE SECURITY TRANSFER INBOUND, OUTBOUND DELIVERY CASH TRANSFER DEPOSIT, REMOVAL INTEREST TAX, FEE DIVIDEND
type R R R R R R R R
account R - - R R R R R
portfolio R R R - - - - -
target-account - - - R - - - -
target-portfolio - R - - - - - -
date R R R R R R R R
time O O O - - - - -
amount R R R R R R R R
currency R R R R R R R R
note O O O O O O O O
shares R R R - - - - O
security R R R - - - O R
unit GROSS_VALUE C? - C? C? - - - C?
unit FEE O* - O* - - O - -
unit TAX O* - O* - - O - O*

Andere Überlegungen

buchen commented 5 years ago

@Ragas13 @sebasbaumh @lenucksi @ZfT2 Was meint Ihr? Ideen? Kommentare? Meinungen? Verbesserungsvorschläge?

ZfT2 commented 5 years ago

Persönlich arbeite ich bislang am liebsten immer mit dem direkten PDF Import, aber dennoch würde ich sagen, daß das o.g. Format ganz gut aussieht :) Ich würde auch eher sagen, die vorhandenen Buchungstypen sollten beibehalten/weiter verwendet werden, auch wenn man theoretisch mit +/- usw. arbeiten könnte... Ich habe auch https://github.com/buchen/portfolio/issues/1184 gesehen, soll der Weg in Zukunft dahin gehen, nur noch "externe" Skripte zu bauen oder dürfen/sollen auch die bestehenden Importer auf Java Basis weiter entwickelt werden?

Ich weiß nicht, ob es in dieses Thema hier rein passt, aber ich erwähne es mal: Aktuell versuche ich den DeGiro Import weiterzuentwickeln, dabei besteht aktuell das Problem, wie dieser Broker Fremdwährungen behandelt: Bei Dividendenzahlungen in Fremdwährung wird beispielsweise zunächst die Dividende in USD angegeben, dann in USD Steuern abgezogen und das Ergebnis dann erst in EUR umgerechnet.. Aktuell braucht das PP Modell und somit auch das JSON unter

"units": { -> "properties": { -> amount und forex

Jeweils den Betrag auch in EUR, der so aber vom Broker nicht geliefert wird, und rechnet man ihn anhand des Kurses selbst aus, kommt es, gerade bei nur kleinen Beträgen, zu Rundungsfehlern. Könnte man daher JSON (und internes PP Modell) so anpassen, das für TAX und FEEs ggf. auch nur der Forex Betrag erfasst werden kann, wenn es um eine Dividende in Fremdwährung geht?

buchen commented 5 years ago

Ich habe auch #1184 gesehen, soll der Weg in Zukunft dahin gehen, nur noch "externe" Skripte zu bauen oder dürfen/sollen auch die bestehenden Importer auf Java Basis weiter entwickelt werden?

Nein. Erstens bestehen schon viele Importer - die müssen bestehen bleiben. Zweitens glaube ich, dass man bei komplexeren Importen trotzdem mit Java, mit Tests, etc. arbeiten möchte. Ich sehe das als eine weitere Möglichkeit.

Jeweils den Betrag auch in EUR, der so aber vom Broker nicht geliefert wird, und rechnet man ihn anhand des Kurses selbst aus, kommt es, gerade bei nur kleinen Beträgen, zu Rundungsfehlern.

Vielleicht sollten wir das in einem anderen Issue diskutieren. Was mir nicht klar ist: wenn Du nur einen Betrag hast, kannst Du den dann nicht so berechnen und dann setzen, dass der passt. Ansonsten muss PP später umrechnen - und dann entstehen die Rundungsfehler. Wir können auch die Prüfung ein bisschen auflockern - es stimmt schon, dass bei kleinen Werten sehr leicht Abweichungen entstehen können.

ZfT2 commented 5 years ago

Nein. Erstens bestehen schon viele Importer - die müssen bestehen bleiben. Zweitens glaube ich, dass man bei komplexeren Importen trotzdem mit Java, mit Tests, etc. arbeiten möchte. Ich sehe das als eine weitere Möglichkeit.

OK, sehr gut :)

Vielleicht sollten wir das in einem anderen Issue diskutieren. Was mir nicht klar ist: wenn Du nur einen Betrag hast, kannst Du den dann nicht so berechnen und dann setzen, dass der passt. Ansonsten muss PP später umrechnen - und dann entstehen die Rundungsfehler. Wir können auch die Prüfung ein bisschen auflockern - es stimmt schon, dass bei kleinen Werten sehr leicht Abweichungen entstehen können.

Ja, ich mache dafür noch einen separaten Issue/PR auf. Bin gerade im Urlaub und habe kein Eclipse dabei... Genau, das Thema sind hier die Cent-Beträge an Steuern, wenn z.B. 6 US Cent rechnerisch zwar 5 Euro Cent ergeben, im Gesamtbetrag der Abrechnung aber anteilig nur 4 Euro Cent ausmachen. Wollte es nur schon mal prophylaktisch erwähnt haben, bevor das JSON Format "festgezurrt" wird ;)

lenucksi commented 5 years ago

Hi, danke für das Proposal. Mir fallen folgende Dinge ein:

ghost commented 5 years ago

Der Ansatz hört sich vielversprechend an, wenn man Schnittstellen für andere Programme vorbereiten möchte und bspw nicht alle Transaktionen Wertpapier für Wertpapier separat importieren / exportieren möchte. :+1:

Was den Punkt mit den Buchungskomponenten wie Kauf/Verkauf betrifft, so würde ich zwar auch gezielt diese ansteuern. Wobei das Vorzeichen entsprechend angefangen werden sollte. Nicht das ein Storno als Kauf mit -5 Stück eingebuck5 wird

buchen commented 5 years ago

Da anzunehmen ist dass sich das JSON Format über Zeit mal ändern könnte, schlage ich vor eine Versionsfeld zu inkludieren

Das Versionsfeld heißt habe auch, die Buchungen einen Ebene tiefer zu schieben (ich will nicht bei jeder Buchung die Version haben). Ist aber vielleicht auch keine so schlechte Idee, weil man später weitere Importe aufnehmen könnte (Konten, Depots, ...).

{
    "version" : 1,
    "transactions" : [
        {
            "type" : "PURCHASE"
        }
    ]
}

Ich fand den +/- Ansatz recht praktisch, habe da aber keine starke Meinung.

An diesem Punkt bin ich noch unsicher.

Also INTEREST ist relative klar: positiver Betrag ist eine Zinszahlung, ein negativer Betrag ist eine Zinsbelastung.

Dann FEE: Positiver Betrag ist eine Gebühr, negativer Betragt ist eine Gebührenrückerstattung. Da muss man schon etwas Gedankengymnastik machen.

Natürlich könnte man sagen: FEE muss negativ sein, wenn es eine Gebühr ist. Aber das müsste man der konsistenzhalber auch bei den Units und allen anderen Buchungen machen.

Ich tendiere dazu: alle Beträge ohne Minuszeichen, über den Typ aufgeschlüsselt um welche Buchung es sich handelt, also INTEREST und INTEREST_CHARGE

buchen commented 5 years ago

Ich habe mal den Export eingebaut: Unter "Alle Buchungen" kann man oben rechts alle (oder die gerade selektierten) Buchungen nach JSON exportieren. Im Prinzip sollte das dem Schema oben entsprechen (bis auf: nested element "transactions", statt "target-account" habe ich es "other-account" genannt, und die forex Felder heißen fxCurrency, fxAmount, fxRateToBase).

Da ich eine Abhängigkeit zu GSON hinzugefügt habt, müsst Ihr ggf. die Target Platform neu laden und die Run Configurations anpassen (für macOS habe ich das gemacht).

Feedback wie immer willkommen!

lenucksi commented 5 years ago

Mit Blick auf #1195 und dahingehend, dass man ohnehin die Version mit aufnimmt stelle ich mal die Frage in den Raum ob es sich nicht auch lohnen würde Metadaten für die erwarteten Quelldateien einzubinden.

Was der beste Ansatz hierfür ist, sei jetzt mal dahingestellt, aber dank der Versionierung kann man da ja iterieren...

lenucksi commented 5 years ago
MrMarvin commented 3 years ago

Hi :wave:, gibt es ähnliche Überlegungen einen strukturierten .json Import auch für die anderen Modelle zu definieren? Ich beschäftige mich aktuell damit Securities automatisiert zu aktualisieren, also alles außer den Kursen eigentlich. Hintergrund: Bei Fonds deren Index sich vierteljährig umverteilt, veraltet eine eventuelle Taxonomy in Regions, Industries etc. Das per Hand durchzugehen ist ist aufwendiger als ein frischer Import, denke ich.

marco-eckstein commented 3 years ago

Für amount, shares etc. sollte besser string statt number verwendet werden, um potenzielle Rundungsfehler zu vermeiden. Zum Vergleich: Das Rest-API der Kryptobörse Binance verwendet größtenteils Strings für Bruchzahlen.

marco-eckstein commented 3 years ago

Verwandtes Thema: #2085

pfalcon commented 1 year ago

Related: https://github.com/buchen/portfolio/issues/3417 - instead of adding yet another import/export format, make standard XML to be of interchange format, not just internal serialization format.

pfalcon commented 1 year ago

Also related: https://github.com/buchen/portfolio/issues/2216#issuecomment-1597780143 - export/import from a database.