From 6595b9bd729282e160f4e9ba381a43482c2b5b0d Mon Sep 17 00:00:00 2001 From: Chris Berkhout Date: Thu, 15 Apr 2021 21:00:25 +0200 Subject: [PATCH] Basic version ECB source. --- src/pricehist/sources/ECB.py | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/pricehist/sources/ECB.py b/src/pricehist/sources/ECB.py index 6b5c0af..ad84105 100644 --- a/src/pricehist/sources/ECB.py +++ b/src/pricehist/sources/ECB.py @@ -1,3 +1,9 @@ +from datetime import datetime, timedelta +from decimal import Decimal +import json +import requests +from xml.etree import ElementTree + class ECB(): @staticmethod @@ -26,3 +32,40 @@ class ECB(): 'HKD', 'HRK', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'JPY', 'KRW', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'USD', 'ZAR'] + + def fetch(self, pair, start, end): + base, quote = pair.split('/') + if base not in self.bases(): + exit(f'Invalid base {base}') + if quote not in self.quotes(): + exit(f'Invalid quote {quote}') + + min_start = '1999-01-04' + if start < min_start: + exit(f'start {start} too early. Minimum is {min_start}') + + almost_90_days_ago = str(datetime.now().date() - timedelta(days=85)) + if start > almost_90_days_ago: + source_url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml' # last 90 days + else: + source_url = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml' # since 1999 + + response = requests.get(source_url) + data = response.content + + # TODO consider changing from xml.etree to lxml + root = ElementTree.fromstring(data) + namespaces = { + 'default': 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref', + 'gesmes': 'http://www.gesmes.org/xml/2002-08-01' + } + all_rows = [] + for day in root.find('default:Cube', namespaces): + date = day.attrib['time'] + rate_xpath = f"./*[@currency='{quote}']" + # TODO what if it's not found for that day? (some quotes aren't in the earliest data) + rate = Decimal(day.find(rate_xpath).attrib['rate']) + all_rows.insert(0, (date, rate)) + selected = [ (d, r) for d, r in all_rows if d >= start and d <= end ] + + return selected