Org Babel for Currency Prices

84 views
Skip to first unread message

man...@gmail.com

unread,
Jul 7, 2017, 7:54:12 AM7/7/17
to Beancount
I've searched this list and it appears some people use Org Mode for outline hierarchy, I don't see much mention of using the other Org capabilities with beancount.

I've just set up some Org Babel and tables to simplify the process of entering and updating currency positions.

First, a babel bash shell block that converts from one currency to another. The default here is 1 USD to USD, but you can change the "curfrom" and "curto" and "amt" if you want. 

#+NAME: cconv
#+BEGIN_SRC sh :results output :eval no-export :var amt="1", curfrom="USD", curto="USD"
val=$(wget -qO- "http://www.google.com/finance/converter?a=${amt}&from=${curfrom}&to=${curto}" | gsed '/res/!d;s/<[^>]*>//g' | cut -d" " -f4)
echo $val
#+END_SRC
#+RESULTS: cconv
: 1

Then, an inline babel call to test that the function works when passed other arguments

#+CALL: cconv(amt="1", curfrom="USD", curto="CHF")
#+RESULTS:
: 0.9622

Then, an Org Table of all of my currencies I would like to track:

#+NAME: currency_table
| Input | Output |  Value |
|-------+--------+--------|
| USD   | DKK    | 6.5135 |
| USD   | CHF    | 0.9622 |
| DKK   | CAD    | 0.1992 |
#+TBLFM: $3='(org-sbe cconv (amt 1) (curfrom '$1) (curto '$2))

Pressing "C-c C-c" on the #+TBLFM line should update the 3rd column with the current conversion rate of each currency.

Finally, another Babel bash shell block that takes the current conversion rate and prints the appropriate beancount lines.
Note that because we are using NAMED blocks, all of this code can be located anywhere in your document, and the #+RESULTS: prices line located in a separate location, and it will still be updated. Also, "prepend" can be removed if you want to sort by date decreasing.

#+NAME: prices
#+BEGIN_SRC sh :results output raw prepend :eval no-export :var c=currency_table
cc=( $c )
len=$(echo ${#cc[@]})
for (( i=0; i<$len; i+=3 )); do
    line=$(echo $c | cut -d" " -f1-3)   # first three
    c=$(echo $c | cut -d" " -f4-)       # rest of line
    curin=$(echo $line | cut -d" " -f1) # break out first three
    curout=$(echo $line | cut -d" " -f2)
    val=$(echo $line | cut -d" " -f3)
    echo $(date "+%Y-%m-%d") price $curin \\t\\t\\t $val $curout
done
#+END_SRC
#+RESULTS: prices
2017-07-07 price USD 6.5135 DKK
2017-07-07 price USD 0.9622 CHF
2017-07-07 price DKK 0.1992 CAD


Currently this requires evaluating (C-c C-c) the TBLFM and then evaluating the #+NAME:prices code block. I think there is a way to force the code block to update the table when it is evaluated, saving a bit of time, but I am not yet sure how to do that.

I hope this is helpful to someone else,

   -k.


man...@gmail.com

unread,
Jul 7, 2017, 8:02:47 AM7/7/17
to Beancount, man...@gmail.com
Oh! Nevermind. It appears this is invalid beancount syntax. I thought if the line did not begin with a date it was ignored, but that doesn't appear to be the case.
Oh well. It would be nice to be able to embed Org Tables and such into beancount files.

According to the manual, "Any line that does not begin as a valid Beancount syntax directive (e.g. with a date) is silently ignored.".

Is there something I'm missing or a work-around for this?

  -k.

Martin Blais

unread,
Jul 7, 2017, 9:50:44 AM7/7/17
to Beancount
A workaround for which part?
I don't understand your question.


--
You received this message because you are subscribed to the Google Groups "Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beancount+unsubscribe@googlegroups.com.
To post to this group, send email to bean...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/beancount/b6bd803c-d3b0-46a3-8e76-068899359386%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Ken Mankoff

unread,
Jul 7, 2017, 10:21:30 AM7/7/17
to bean...@googlegroups.com

On 2017-07-07 at 13:50, Martin Blais <bl...@furius.ca> wrote:
> A workaround for which part?
> I don't understand your question.

The unclear question was about beancount syntax and embedding Org Babel Code blocks in a beancount Org file.

I'm new to the beancount syntax. Is there a way to have Org tables in a beancount document? Or is "|" invalid as the first character of a line? What about code?

I thought if the line begins with a non-date or non-whitespace, it is a comment, but that doesn't seem to be the case.

In this case, can I put in a feature request for the parser to ignore Org Babel code blocks, (i.e. all lines between "#+BEGIN_SRC" and "#+END_SRC") Org tables (lines that begin with "|"), and Babel Results blocks ("#+RESULTS:" and lines that begin with ":")

I've looked at the lexer and parser code briefly, but it has been decades since I have written a language. I will add this eventually if there is interest in adding this feature to the language.

-k.

Martin Blais

unread,
Jul 7, 2017, 10:39:16 AM7/7/17
to Beancount
On Fri, Jul 7, 2017 at 10:21 AM, Ken Mankoff <man...@gmail.com> wrote:

On 2017-07-07 at 13:50, Martin Blais <bl...@furius.ca> wrote:
> A workaround for which part?
> I don't understand your question.

The unclear question was about beancount syntax and embedding Org Babel Code blocks in a beancount Org file.

I'm new to the beancount syntax. Is there a way to have Org tables in a beancount document? Or is "|" invalid as the first character of a line? What about code?

It should ignore anything that isn't starting with a date or another valid syntax.
That said, the amount of testing for what the bison/flex-generated parser can tolerate is fairly small.
I wouldn't be surprised if you can break it.


I thought if the line begins with a non-date or non-whitespace, it is a comment, but that doesn't seem to be the case.

If you can establish some minimal examples that fail, please report them, I can have a look.

(Note: I'm moving over the next three weeks and then going on an overdue vacation, so I won't have much time to do much until September. Best is to submit a patch, second best is to file a ticket.)



In this case, can I put in a feature request for the parser to ignore Org Babel code blocks, (i.e. all lines between "#+BEGIN_SRC" and "#+END_SRC") Org tables (lines that begin with "|"), and Babel Results blocks ("#+RESULTS:" and lines that begin with ":")

I've looked at the lexer and parser code briefly, but it has been decades since I have written a language. I will add this eventually if there is interest in adding this feature to the language.

  -k.

--
You received this message because you are subscribed to the Google Groups "Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beancount+unsubscribe@googlegroups.com.
To post to this group, send email to bean...@googlegroups.com.

Ken Mankoff

unread,
Jul 7, 2017, 10:51:20 AM7/7/17
to bean...@googlegroups.com
Hi,

Thanks for the quick reply. It turns out it does work and does not break the parser. I checked the syntax with =bean-check=, and it reported a bunch of "Invalid token:". I thought these were errors, but they are just warnings. The parser still works, and I can now embed reports in the Org file too. For example,

* Reports
** Balance Report
#+BEGIN_SRC sh :results verbatim
bean-report ./beancount.org bal
#+END_SRC
#+RESULTS:
#+begin_example
Assets:Cash:USD 42.00 USD
#+end_example


So... syntax is invalid but parser still works. If I adopt this as my finance tool I will discuss with you about making this valid syntax and improving the parser. Although it might not make sense to add Org-specific features. Enjoy your vacation! I'm moving over the next 3 weeks too, international, hence my search for a new finance tool that works outside the US.

-k.

Martin Blais

unread,
Jul 7, 2017, 11:08:03 AM7/7/17
to Beancount
On Fri, Jul 7, 2017 at 10:51 AM, Ken Mankoff <man...@gmail.com> wrote:
Hi,

Thanks for the quick reply. It turns out it does work and does not break the parser. I checked the syntax with =bean-check=, and it reported a bunch of "Invalid token:". I thought these were errors, but they are just warnings. The parser still works, and I can now embed reports in the Org file too. For example,

* Reports
** Balance Report
#+BEGIN_SRC sh :results verbatim
bean-report ./beancount.org bal
#+END_SRC
#+RESULTS:
#+begin_example
Assets:Cash:USD                               42.00   USD
#+end_example


So... syntax is invalid but parser still works. If I adopt this as my finance tool I will discuss with you about making this valid syntax and improving the parser.

The main thing lots of people want in terms of parser changes is support for Unicode/international characters.
That probably requires a hand-coded lexer -- not difficult, but a major change nevertheless.
A new lexer would also remove some of the quirks in the syntax, e.g. limited number of flag characters supported.
It would also do a better job at tokenizing indentation.

 
Although it might not make sense to add Org-specific features. Enjoy your vacation! I'm moving over the next 3 weeks too, international, hence my search for a new finance tool that works outside the US.

Beancount will work with any number of currencies and should do the job. I've used it myself with transactions and investments in two countries for many years, reporting and converting to USD the entire time, tracking cost basis. 

The only "major" limitation that remains is that if you need to account using average cost basis (e.g. as in a 401k or RRSP in Canada), the report needs to aggregate all units and cost (those accounts currently require one to disable booking of reductions (sales) by using the "NONE" booking method, and thus they preserve the entire history of additions and reductions in the account. Summing over the units and/or cost will work, but when reporting the full inventory of those accounts you would see a huge list of transactions. Not a huge problem IMO, but I'd like to do that properly eventually, recalculating the cost basis to a single position automatically as buys / sells occur).




  -k.

--
You received this message because you are subscribed to the Google Groups "Beancount" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beancount+unsubscribe@googlegroups.com.
To post to this group, send email to bean...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages