meuro/meuro.py

126 lines
4.9 KiB
Python
Raw Normal View History

2021-10-30 10:57:43 +02:00
#!/usr/bin/python3
2021-10-30 14:18:14 +02:00
import requests, json, os.path
2021-10-07 17:12:28 +02:00
from datetime import datetime
from dateutil import relativedelta
from dateutil import parser as dparser
from dateutil.parser._parser import ParserError as DateParserError
from collections import defaultdict
2021-10-07 17:12:28 +02:00
2021-10-30 17:56:30 +02:00
# Our inflation-table as a global-var
2021-10-30 14:18:14 +02:00
_years = None
2021-10-07 17:12:28 +02:00
2021-10-07 17:22:22 +02:00
# Gives you the exchange rate between euros and meuros for the given date.
# (Should always be a float < 1)
# date should be either a datetime-object or None (= current date)
2021-10-07 17:12:28 +02:00
def exchangeRate(date=None):
2021-10-30 14:18:14 +02:00
global _years
if _years==None:
2021-10-30 17:56:30 +02:00
reload()
2021-10-07 17:12:28 +02:00
if date==None:
date = datetime.now()
month, year = date.month, date.year
if year < 2001:
raise Exception('µeuro-values for €uro prices before the start of this millenium are undefined.')
akk = 1
for fullYear in range(2001, year):
yearlyInf = 1
2021-10-30 14:18:14 +02:00
for m in _years[fullYear]:
monthlyInf = _years[fullYear][m]
2021-10-07 17:12:28 +02:00
yearlyInf *= monthlyInf
akk *= yearlyInf
for fullMonth in range(1, month):
2021-10-30 14:18:14 +02:00
monthlyInf = _years[year][fullMonth]
2021-10-07 17:12:28 +02:00
akk *= monthlyInf
beginningOfMonth = date.replace(hour=0, minute=0, second=0, microsecond=0, day=1)
endOfMonth = beginningOfMonth + relativedelta.relativedelta(months=1)
fracOfMonth = (date - beginningOfMonth).total_seconds() / (endOfMonth - beginningOfMonth).total_seconds()
2021-10-30 14:18:14 +02:00
inflationThisMonth = 1 + fracOfMonth * (_years[year][month]-1)
2021-10-07 17:12:28 +02:00
akk *= inflationThisMonth
return 1/akk
2021-10-30 14:18:14 +02:00
2021-10-07 17:22:22 +02:00
# Converts the given amount of euros to meuros for the given date. (wholeCents means it rounds to two decimal places)
# date should be either a datetime-object or None (= current date)
2021-10-07 17:12:28 +02:00
def euroToMeuro(eur,date=None,wholeCents=True):
return round(eur * exchangeRate(date),[64,2][wholeCents])
2021-10-07 17:12:28 +02:00
2021-10-07 17:22:22 +02:00
# Converts the given amount of meuros to euros for the given date. (wholeCents means it rounds to two decimal places)
# date should be either a datetime-object or None (= current date)
2021-10-07 17:12:28 +02:00
def meuroToEuro(meur,date=None,wholeCents=True):
return round(meur / exchangeRate(date),[64,2][wholeCents])
2021-10-07 17:12:28 +02:00
2021-10-07 17:22:22 +02:00
# Print the current amount of meuros for the given amunt of euros every <interval>-seconds.
# Comes in handy when you want to watch your life savings slowly fade away thanks to inflation.
2021-10-07 17:12:28 +02:00
def liveValue(eur,interval=10):
import time
while True:
print(str(eur*exchangeRate())+'µ')
time.sleep(interval)
def _extractDate(s):
try:
return dparser.parse(s, fuzzy=True, dayfirst=True)
except DateParserError:
return datetime.now()
2021-10-30 17:56:30 +02:00
def reload(maxCacheSeconds=3600):
global _years
if os.path.isfile('cache.json'):
with open('cache.json', 'r') as f:
cacheUpdate, cacheYears = json.loads(f.read())
if (datetime.now() - dparser.isoparse(cacheUpdate)).total_seconds() < maxCacheSeconds:
# JSON does not allow integers as keys; so we convert them back here
2021-10-30 17:56:30 +02:00
cacheYears = {int(y):{int(m):float(n) for m,n in ms.items()} for y,ms in cacheYears.items()}
# For every month we dont have data for, we assume the ECB nailed their 2%-target
2021-10-30 17:56:30 +02:00
_years = defaultdict(lambda: {m:1 + 0.02/12 for m in range(1,13)}, cacheYears)
return
_years = _loadYearsTableWeb()
def _loadYearsTableWeb():
print('[i] Fetching new data from ECB-Servers...')
#url = 'https://sdw.ecb.europa.eu/quickviewexport.do?SERIES_KEY=122.ICP.M.U2.N.000000.4.ANR&type=csv'
#resp = requests.get(url)
url = 'https://data.ecb.europa.eu/download-api/csv/wide'
resp = requests.post(url, {'serieskeys': ['ICP.M.U2.N.000000.4.ANR']})
2021-10-30 17:56:30 +02:00
lines = resp.text.split('\n')[6:]
years = defaultdict(lambda: {m:1 + 0.02/12 for m in range(1,13)})
for line in lines:
vals = line.split(',')
year = int(vals[0][:4])
month = datetime.strptime(vals[0][4:],'%b').month
inflation = float(vals[1])
years[year][month] = 1 + (inflation/100)/12
with open('cache.json', 'w') as f:
f.write(json.dumps([datetime.now().isoformat(),years]))
return years
def cliInterface():
import sys, re
arg = " ".join(sys.argv[1:]).replace(',','')
reFromEur = re.compile(r'(\d+(.\d\d)?)\W?(€|e|E)')
reFromMeur = re.compile(r'(\d+(.\d\d)?)\W?(μ|m|M)')
if (m := reFromEur.search(arg))!=None:
eurS = m.groups()[0]
date = _extractDate(arg[:m.span()[0]] + '-' + arg[m.span()[1]:])
eur = float(eurS)
meur = euroToMeuro(eur, date)
print('Exchange rate for '+date.strftime("%d.%m.%Y at %H:%M")+':')
print(f'{eur:,.2f}€ = {meur:,.2f}µ')
elif (m:= reFromMeur.search(arg))!=None:
meurS = m.groups()[0]
date = _extractDate(arg[:m.span()[0]] + '-' + arg[m.span()[1]:])
meur = float(meurS)
2021-10-30 13:12:36 +02:00
eur = meuroToEuro(meur, date)
print('Exchange rate for '+date.strftime("%d.%m.%Y at %H:%M")+':')
print(f'{meur:,.2f}µ = {eur:,.2f}')
else:
print('[!] Unable to parse input')
if __name__=='__main__':
cliInterface()