Beancount advancement Thread

How is your plugin different from beancount.plugins.forecast that I posted above?

it allows me to distribute a bill also backwards, or to any time window
I can also define where the intermittend balance should go

interesting, i can find forecast.py in my beancount/plugins folder, but not on

anybody knows why?

Master is beancount 3 work in progress where a lot of stuff was moved out.

1 Like

ahhhh thanks, makes sense.

hey, given i have my old beancount setup, do you know about what changes I will have to make in order to switch to beancount 3?

I think beancount 3 is not ready yet. But the main text file should be probably usable without much tweaking. The whole idea is to rewrite the core in c++ to make it much faster. I’ve noticed the speed problem already. The python-based beancount 2 takes a few seconds to load all of my transactions.

Sorry if that has been shared already, but does someone know how to export the right data using BQL to produce net-worth plots in the style of this thread?

I’m interested in making a stacked plot with monthly progression of net worth, converted to one currency.

That looks great and exactly what I need. Is it possible to install it through pip ?

I was also thinking about making a plugin with the idea of showing monthly income according to stock price changes (incl. dividends). I am not aware that beancount could do this?

Dear all
i just found out that Finpension.ch offers exportable (.csv) activity statements. This calls for an Finpension importer for beancount!

however the question is on how to ge price quotes for those CSIF products. Take for example
Name: CSIF (CH) III Equity World ex CH Blue -Pension Fund Plus ZB
ISIN: CH0429081620
Ticker: CSWPPZA SW

yahoo does not have it. I could only find quotes on bloomberg. does anyone have an idea how i can obtain quotes programmatically, like via the yfinance python package?

Anybody else having issues with bean-price recently? mine takes forever to fetch the prices…

I guess it depends on your price sources, which ones are you using?

Yeah I figured it out. Wanted to read DOT-USD prices which for some reason have a incomplete history on Yahoo. Switched to coinbase and that worked.

hiall
i am observing strange patterns in all my commodity prices. For example, with VXUS:

the data i just pulled yesterday via yfinance
those marked peaks coincide with trades I did.

The question is: Why do I see these peaks?

So far I figured out that my IB trades come with commodity prices attached. The cost basis in my IB pdf reports are onsistent with the peak values. And I expect that IB does not have a spread of 10% on VXUS :wink:

So could it be that the yf data is somehow different? Could there be something like the yf data is/is not reflecting distributions?

Ideas welcome!

could this be a currency conversion issue?

has anyone of the beancount activists come across an importer for neon or zak?^^

here you go

3 Likes

i should have thought about you, @tarioch! why, again, is your repo a requirement in my conda env? :smiley:
Thanks!

1 Like

here is my importer for Finpension: drnuke-bean/finpension.py at master · Dr-Nuke/drnuke-bean · GitHub

and som helping documentation in the readme.md drnuke-bean/README.md at master · Dr-Nuke/drnuke-bean · GitHub

feedback appreciated :slight_smile:

1 Like

I also revised my automated Postfinance importer narration cleanup. It is not perfect and hardcoded to the german delivery of the csv files, but might still be useful for some of you!

Best,
nugget

def automatic_fixes(d):
    """
    This function allows the user to specify multiple automatic manipulations of the 
    ingested bank statement data. Its return will be the input for the
    data.Transaction() object to be created from that line of the statement
    d: dict() with keys of a future statement, i.e. 'narration', 'payee',...
    """

    monthstring = d['date'].strftime('%b %Y')

    amount = d['amount']
    account = d['account']
    meta = d['meta']
    flag = d['flag']
    narration = d['narration']
    payee = d['payee']
    date = d['date']
    postings = d['postings']

    # preformatting
    re_auftraggeber = r"(.*) (AUFTRAGGEBER|ABSENDER):\s(.*)\sMITTEILUNGEN:\s(.*)\sREFERENZEN:\s(.*)"
    re_auftraggeber2 = r"(.*) AUFTRAGGEBER:\s(.*)\sREFERENZEN:\s(.*)"
    re_kauf = r'KAUF/(DIENSTLEISTUNG|ONLINE-SHOPPING) VOM \d\d.\d\d.\d{4} KARTEN NR. \w{8}\s'
    # re_sender_ref = r"(.*)\sSENDER REFERENZ:\s(.*)"
    
    if bool(re.search(re_kauf, narration, re.IGNORECASE)):
        narration = re.sub(re_kauf, '', narration)
        narration = re.sub(' zürich schweiz','',narration,flags=re.IGNORECASE)
        payee = ''        
        
    elif re.search(re_auftraggeber, narration, re.IGNORECASE) is not None:
        match = re.search(re_auftraggeber, narration, re.IGNORECASE)
        payee = match.groups()[2]
        narration = f"{match.groups()[3]} {match.groups()[4]}"
        
    elif re.search(re_auftraggeber2, narration, re.IGNORECASE) is not None:
        match = re.search(re_auftraggeber2, narration, re.IGNORECASE)
        payee = match.groups()[1]
        narration = f"{match.groups()[2]}"
    
#     elif re.search(re_sender_ref, narration, re.IGNORECASE) is not None:
#         match = re.search(re_sender_ref, narration, re.IGNORECASE)
#         payee = match.groups()[0]
#         narration = match.groups()[1]
        
    # remove notprovided flags
    narration = re.sub(r"\s?NOTPROVIDED\s\S{14,16}\s\S{14,16}",'',narration)
    
    # trim left side of narration
    regex_iban = r"[A-Z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?!(?:[ ]?[0-9]){3})(?:[ ]?[0-9]{1,2})?\s?R?"
    trim_list=[
        r"ESR\s\d\d-\d{5}-\d ", # regex for "Postkonto"
        r"ESR DAUERAUFTRAG: ",
        r"LASTSCHRIFT DAUERAUFTRAG: ",
        r"LASTSCHRIFT " + regex_iban,
        r"LASTSCHRIFT "
    ]
 
    trim = f'({"|^".join(trim_list)})'
    narration = re.sub(trim, "",narration, re.IGNORECASE) 
    
    # trim right side from long digit "20220913000800242513572"
    narration = re.sub(r"\s?\d{23}\s?$","",narration)    
    
    # IBAN + SENDER  REFERENZ
    iban_sender = f"(.*) {regex_iban} (.*) SENDER REFERENZ:(.*)"
    match = re.search(iban_sender, narration, re.IGNORECASE)
    if match is not None:
        payee = match.groups()[1]
        narration = match.groups()[2]
    
    # only SENDER REFERENZ:
    match = re.search("(.*)\s?SENDER REFERENZ:\s?(.*)", narration, re.IGNORECASE)
    if match is not None:
        payee = match.groups()[0]
        narration = match.groups()[1]

    # if still nothing in payee, most likely the remaining narration _is_ the payee
    if narration and not payee:
        payee, narration = narration, payee

    # add your personal automated fixes here

    return dict(amount=amount,
                account=account,
                meta=meta,
                flag=flag,
                narration=narration,
                payee=payee,
                date=date,
                postings=postings,
                )
2 Likes

Hi all :smiley:
for those living in the Kanton of Zurich and normal taxation regime, i wrote a tax forecast plugin that will predict the tax load of a ongoing or past fiscal year and add monthly tax liabilities accordingly:

this plugin greatly benefits from @the_p’s shared api queries to the Steuerrechner of the Kanton Zurich.

based on your taxable income accounts, it extrapolates your current income to the full year, queries the according tax load at the Steuerrechner, and adds the resulting tax debt as a liability to your ledger

Warning: this is totally immature and needs some more work :smiley: but it basically works:

room for improvement:

  • add Vermögenssteuer
  • add deductables (accounts, lump sum,…), as it currently strongly overestimates the due taxes
  • switch to the ESTV Steuerrechner, which should work for all Kantons
  • add more choices & options support
  • reflect on any feedback here :smiley:
  • i cant get behind some things in beancount, probaby there are some really poor workarounds in the source…
  • add tax credit (Witholding etc.)
5 Likes