This repository was archived by the owner on Dec 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathecb.py
98 lines (79 loc) · 2.9 KB
/
ecb.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
import ssl
import sys
try:
from lxml import etree as ET
except ImportError:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
from decimal import Decimal
from urllib.error import HTTPError
from urllib.request import urlopen
_URL = 'https://www.ecb.europa.eu/stats/eurofxref/'
_URL_TODAY = _URL + 'eurofxref-daily.xml'
_URL_90 = _URL + 'eurofxref-hist-90d.xml'
_URL_HIST = _URL + 'eurofxref-hist.xml'
_START_DATE = dt.date(1999, 1, 4)
_CUBE_TAG = '{http://www.ecb.int/vocabulary/2002-08-01/eurofxref}Cube'
class RatesNotAvailableError(Exception):
pass
class UnsupportedCurrencyError(Exception):
pass
def _parse_time(time):
return dt.datetime.strptime(time, '%Y-%m-%d').date()
def _find_time(source, time=None):
for _, element in ET.iterparse(source):
if element.tag == _CUBE_TAG and 'time' in element.attrib:
if time and _parse_time(element.attrib.get('time')) <= time:
return element
elif time is None:
return element
element.clear()
def get_rates(currency='EUR', date=None):
if date is None:
date = dt.date.today()
if date < _START_DATE:
date = _START_DATE
context = ssl.create_default_context()
try:
with urlopen(_URL_TODAY, context=context) as response:
element = _find_time(response)
last_date = _parse_time(element.attrib['time'])
if last_date < date:
raise RatesNotAvailableError()
elif last_date == date:
return _compute_rates(element, currency, date)
if last_date - date < dt.timedelta(days=90):
url = _URL_90
else:
url = _URL_HIST
with urlopen(url, context=context) as response:
element = _find_time(response, date)
return _compute_rates(element, currency, date)
except HTTPError as e:
raise RatesNotAvailableError() from e
def _compute_rates(element, currency, date):
currencies = {}
for cur in element:
currencies[cur.attrib['currency']] = Decimal(cur.attrib['rate'])
if currency != 'EUR':
currencies['EUR'] = Decimal(1)
try:
base_rate = currencies.pop(currency)
except KeyError:
raise UnsupportedCurrencyError(f'{currency} is not available')
for cur, rate in currencies.items():
currencies[cur] = (rate / base_rate).quantize(Decimal('.0001'))
return currencies
if __name__ == '__main__':
currency = 'EUR'
if len(sys.argv) > 1:
currency = sys.argv[1]
date = None
if len(sys.argv) > 2:
date = dt.datetime.strptime(sys.argv[2], '%Y-%m-%d').date()
print(get_rates(currency, date))