Last active
June 23, 2021 20:19
-
-
Save alerque/b9096aeb6829934c2256e80b91530ae0 to your computer and use it in GitHub Desktop.
Makefile snippet to include to fetch prices for all transactions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage: | |
# 1. from your main makefile set `MAIN_LEDGER = <path>` to something that has all your transactions | |
# 2. include this into your main makefile via `include prices.mk` | |
# 3. Have a fixer.io API key exported as FIXERAPIKEY (either in parent shell or makefile) before doing №4 | |
# 4. periodically run `make update_prices` | |
# 5. include reltant price list into your main ledger via `include prices.ledger` | |
# | |
# Caveats: | |
# Fixer.io as an API call limit of 100 per day or something like that. That's per currency, | |
# so if you have 5 currencies in play you need to run this at every less than < 20 days to | |
# stay under the limit. Getting setup with years of history is hard, run once per day until | |
# you hit the limit and then wait until tomorrow. Eeach run as in №4 will make 10 day fetches | |
# so depending on your currency usage you may be able to run it a few times. | |
# | |
# Be sure to adjust the Git commit stuff if you don't want this making automatic commits! | |
# | |
# Requires moreutils (sponge), jq, curl, grep, sed, awk, perl, pcregrep, tee, etc. | |
# | |
# Update to include CODE‹›SYMBOL maps for your currencies | |
# | |
# This changes your makefile processing to use ZSH shell instead of sh. If that's a problem you'll need to adapt the code yourself. | |
SHELL := zsh | |
.SHELLFLAGS := +o nomatch -e -c | |
.ONESHELL: | |
.SECONDEXPANSION: | |
# Function to convert ISO currency codes to localized forms | |
define localcurrency = | |
perl -pne ' | |
s/(\d+),(\d+)(\.\d+)?(?= \p{Lu}{3})/\1\2\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? TRY/₺\1,\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? USD/\$$\1.\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? EUR/€\1.\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? KZT/\1,\3 ₸/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? GBP/₤\1.\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? BGN/\1,\3 лв/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? TND/\1.\3 دت/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? CHF/Fr \1.\3/g; | |
s/(?<=\s)(-?\d+)(\.(\d+))? XOF/CFA \1.\3/g; | |
' | |
endef | |
# Function to localized forms to convert ISO currency codes | |
define isocurrency = | |
perl -pne 's/₺/TRY/g;s/\$$/USD/g;s/€/EUR/g;s/₸/KZT/g;s/₤/GBP/g;s/лв/BGN/g;s/دت/TND/g;s/\bFr /CHF/g;s/CFA/XOF/g;s/(?<=\d) (?=\d)//g if /^ /' | |
endef | |
prices.ledger: dates.json commodities.json | |
apicalls=0 | |
jq -r '.commodities | join(",")' commodities.json | read symbols | |
jq -r '.dates[]' dates.json | | |
sed 's#/#-#g' | | |
awk 'FNR>1 && $$1<"$(shell date +%Y-%m-%d)"' | # Don't fetch today or later because market rates aren't settled | |
tac | # Prioritize API usage for newest dates, historical can be added later | |
while read date; do | |
if ! grep -q "^P $${date}" $@; then | |
if [[ $${apicalls} -lt 10 ]]; then | |
# curl -s "https://api.exchangeratesapi.io/$${date}?base=EUR&symbols=$${symbols}" | |
# curl -s "https://api.ratesapi.io/api/$${date}?base=EUR&symbols=$${symbols}" | |
curl -s "http://data.fixer.io/api/$${date}?access_key=$(FIXERAPIKEY)&symbols=$${symbols}" | |
fi | |
apicalls=$$(($${apicalls}+1)) | |
fi | |
done | | |
jq -rs '.[] | | |
. as $$res | | |
.rates | | |
to_entries[] | | |
[ "P", | |
$$res.date, | |
"USD", | |
(.value / $$res.rates.USD * 10000 | round / 10000 | tostring), | |
.key | |
] | | |
join(" ")' | | |
( tee >($(localcurrency) | sed -e 's/ USD / $$ /') ) | | |
sed -e '/\$$ \$$1/d;s/USD 1 USD/USD $$1/' | | |
hledger -f $@ -f- prices | | |
sponge $@ | |
.PHONY: update_prices | |
update_prices: prices.ledger | |
git diff-index --quiet --cached HEAD || exit 1 # die if anything already staged | |
test -s $< || exit 1 # die if for some reason the prices file ends up empty | |
git add -- $< | |
git diff-index --quiet --cached HEAD || git commit -m "[auto] Update market prices list" | |
dates.json: $(MAIN_LEDGER) | |
hledger -f $< print -I | | |
awk -F'[ =]' '/^[[:digit:]]/ { print $$1 }' | | |
jq -nR '{ "dates": ([inputs] | unique) }' > $@ | |
commodities.json: $(MAIN_LEDGER) | |
hledger -f <(grep -v '^include' $<) commodities -I | | |
pcregrep -x '\p{Lu}{3}' | grep -v '^CFA$$' | | |
jq -nR '{ "commodities": ([inputs] | unique) }' > $@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment