Better logging of critical exceptions. Isolate tests and error handling for ECB.

This commit is contained in:
Chris Berkhout 2021-07-11 15:50:59 +02:00
parent 2aa4319dbb
commit c0c7e546a3
6 changed files with 604 additions and 66 deletions

View file

@ -1,6 +1,9 @@
import logging
import sys
from datetime import date, datetime, timedelta
from pricehist import exceptions
def fetch(series, source, output, invert: bool, quantize: int, fmt) -> str:
if series.start < source.start():
@ -9,7 +12,12 @@ def fetch(series, source, output, invert: bool, quantize: int, fmt) -> str:
f"source start date of {source.start()}."
)
series = source.fetch(series)
try:
series = source.fetch(series)
except exceptions.SourceError as e:
logging.debug("Critical exception encountered", exc_info=e)
logging.critical(str(e))
sys.exit(1)
if len(series.prices) == 0:
logging.warn(f"No data found for the interval [{series.start}--{series.end}].")

View file

@ -4,11 +4,18 @@ import sys
class Formatter(logging.Formatter):
def format(self, record):
message = record.msg % record.args if record.args else record.msg
if record.levelno == logging.INFO:
return message
else:
return f"{record.levelname} {message}"
s = record.msg % record.args if record.args else record.msg
if record.exc_info:
record.exc_text = self.formatException(record.exc_info)
if s[-1:] != "\n":
s = s + "\n"
s = s + "\n".join([f" {line}" for line in record.exc_text.splitlines()])
if record.levelno != logging.INFO:
s = "\n".join([f"{record.levelname} {line}" for line in s.splitlines()])
return s
def init():

View file

@ -1,13 +1,11 @@
import dataclasses
import logging
import sys
from datetime import datetime, timedelta
from decimal import Decimal
import requests
from lxml import etree
from pricehist import isocurrencies
from pricehist import exceptions, isocurrencies
from pricehist.price import Price
from .basesource import BaseSource
@ -36,19 +34,17 @@ class ECB(BaseSource):
return ""
def symbols(self):
root = self._data(more_than_90_days=True)
nodes = root.cssselect("[currency]")
currencies = sorted(set([n.attrib["currency"] for n in nodes]))
quotes = self._quotes()
iso = isocurrencies.by_code()
return [(f"EUR/{c}", f"Euro against {iso[c].name}") for c in currencies]
return [
(f"EUR/{c}", f"Euro against {iso[c].name if c in iso else c}")
for c in quotes
]
def fetch(self, series):
if series.base != "EUR": # EUR is the only valid base.
logging.critical(
f"Invalid pair '{'/'.join([series.base, series.quote])}'. "
f"Run 'pricehist source {self.id()} --symbols' to list valid pairs."
)
sys.exit(1)
if series.base != "EUR" or not series.quote: # EUR is the only valid base.
raise exceptions.InvalidPair(series.base, series.quote, self)
almost_90_days_ago = (datetime.now().date() - timedelta(days=85)).isoformat()
root = self._data(series.start < almost_90_days_ago)
@ -58,12 +54,24 @@ class ECB(BaseSource):
for row in day.cssselect(f"[currency='{series.quote}']"):
rate = Decimal(row.attrib["rate"])
all_rows.insert(0, (date, rate))
if not all_rows and series.quote not in self._quotes():
raise exceptions.InvalidPair(series.base, series.quote, self)
selected = [
Price(d, r) for d, r in all_rows if d >= series.start and d <= series.end
]
return dataclasses.replace(series, prices=selected)
def _quotes(self):
root = self._data(more_than_90_days=True)
nodes = root.cssselect("[currency]")
quotes = sorted(set([n.attrib["currency"] for n in nodes]))
if not quotes:
raise exceptions.ResponseParsingError("Expected data not found")
return quotes
def _data(self, more_than_90_days=False):
url_base = "https://www.ecb.europa.eu/stats/eurofxref"
if more_than_90_days:
@ -71,6 +79,19 @@ class ECB(BaseSource):
else:
source_url = f"{url_base}/eurofxref-hist-90d.xml" # last 90 days
response = self.log_curl(requests.get(source_url))
root = etree.fromstring(response.content)
try:
response = self.log_curl(requests.get(source_url))
except Exception as e:
raise exceptions.RequestError(str(e)) from e
try:
response.raise_for_status()
except Exception as e:
raise exceptions.BadResponse(str(e)) from e
try:
root = etree.fromstring(response.content)
except Exception as e:
raise exceptions.ResponseParsingError(str(e)) from e
return root

View file

@ -1,14 +1,18 @@
import logging
import os
from datetime import datetime, timedelta
from decimal import Decimal
from pathlib import Path
import pytest
import requests
import responses
from pricehist import exceptions, isocurrencies
from pricehist.price import Price
from pricehist.series import Series
from pricehist.sources.ecb import ECB
# import responses
# @responses.activate
def in_log(caplog, levelname, substr):
return any(
@ -26,73 +30,204 @@ def type(src):
return src.types()[0]
@pytest.fixture
def xml():
dir = Path(os.path.splitext(__file__)[0])
return (dir / "eurofxref-hist-partial.xml").read_text()
@pytest.fixture
def empty_xml():
dir = Path(os.path.splitext(__file__)[0])
return (dir / "eurofxref-hist-empty.xml").read_text()
@pytest.fixture
def requests_mock():
with responses.RequestsMock() as mock:
yield mock
@pytest.fixture
def response_ok(requests_mock, xml):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml",
body=xml,
status=200,
)
yield requests_mock
@pytest.fixture
def response_ok_90d(requests_mock, xml):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml",
body=xml,
status=200,
)
yield requests_mock
@pytest.fixture
def response_empty_xml(requests_mock, empty_xml):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml",
body=empty_xml,
status=200,
)
yield requests_mock
def test_normalizesymbol(src):
assert src.normalizesymbol("eur") == "EUR"
assert src.normalizesymbol("symbol") == "SYMBOL"
@pytest.mark.live
def test_known_pair(src, type):
series = src.fetch(Series("EUR", "AUD", type, "2021-01-11", "2021-01-22"))
assert series.prices[0] == Price("2021-01-11", Decimal("1.5783"))
assert series.prices[-1] == Price("2021-01-22", Decimal("1.577"))
assert len(series.prices) == 10
def test_metadata(src):
assert isinstance(src.id(), str)
assert len(src.id()) > 0
assert isinstance(src.name(), str)
assert len(src.name()) > 0
assert isinstance(src.description(), str)
assert len(src.description()) > 0
assert isinstance(src.source_url(), str)
assert src.source_url().startswith("http")
assert datetime.strptime(src.start(), "%Y-%m-%d")
assert isinstance(src.types(), list)
assert len(src.types()) > 0
assert isinstance(src.types()[0], str)
assert len(src.types()[0]) > 0
assert isinstance(src.notes(), str)
@pytest.mark.live
def test_long_hist_from_start(src, type):
series = src.fetch(Series("EUR", "AUD", type, src.start(), "2021-07-01"))
def test_symbols(src, response_ok):
syms = src.symbols()
assert ("EUR/AUD", "Euro against Australian Dollar") in syms
assert len(syms) > 40
def test_requests_logged_for_symbols(src, response_ok, caplog):
with caplog.at_level(logging.DEBUG):
src.symbols()
assert in_log(caplog, "DEBUG", " curl ")
def test_symbols_not_in_iso_data(src, response_ok, monkeypatch):
iso = isocurrencies.by_code()
del iso["AUD"]
monkeypatch.setattr(isocurrencies, "by_code", lambda: iso)
syms = src.symbols()
assert ("EUR/AUD", "Euro against AUD") in syms
def test_symbols_not_found(src, response_empty_xml):
with pytest.raises(exceptions.ResponseParsingError) as e:
src.symbols()
assert "data not found" in str(e.value)
def test_known_pair(src, type, response_ok):
series = src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2021-01-08"))
assert series.prices[0] == Price("2021-01-04", Decimal("1.5928"))
assert series.prices[-1] == Price("2021-01-08", Decimal("1.5758"))
assert len(series.prices) == 5
def test_requests_logged_for_fetch(src, response_ok, caplog):
with caplog.at_level(logging.DEBUG):
src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2021-01-08"))
assert in_log(caplog, "DEBUG", " curl ")
def test_recent_interval_uses_90d_data(src, type, response_ok_90d):
today = datetime.now().date()
start = (today - timedelta(days=80)).isoformat()
end = today.isoformat()
src.fetch(Series("EUR", "AUD", type, start, end))
assert len(response_ok_90d.calls) > 0
def test_long_hist_from_start(src, type, response_ok):
series = src.fetch(Series("EUR", "AUD", type, src.start(), "2021-01-08"))
assert series.prices[0] == Price("1999-01-04", Decimal("1.91"))
assert series.prices[-1] == Price("2021-07-01", Decimal("1.5836"))
assert len(series.prices) == 5759
assert series.prices[-1] == Price("2021-01-08", Decimal("1.5758"))
assert len(series.prices) > 9
@pytest.mark.live
def test_from_before_start(src, type):
def test_from_before_start(src, type, response_ok):
series = src.fetch(Series("EUR", "AUD", type, "1998-12-01", "1999-01-10"))
assert series.prices[0] == Price("1999-01-04", Decimal("1.91"))
assert series.prices[-1] == Price("1999-01-08", Decimal("1.8406"))
assert len(series.prices) == 5
@pytest.mark.live
def test_to_future(src, type):
series = src.fetch(Series("EUR", "AUD", type, "2021-07-01", "2100-01-01"))
def test_to_future(src, type, response_ok):
series = src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2100-01-01"))
assert len(series.prices) > 0
@pytest.mark.live
def test_known_pair_no_data(src, type):
series = src.fetch(Series("EUR", "ROL", type, "2020-01-01", "2021-01-01"))
def test_known_pair_no_data(src, type, response_ok):
series = src.fetch(Series("EUR", "ROL", type, "2021-01-04", "2021-02-08"))
assert len(series.prices) == 0
def test_non_eur_base(src, type, caplog):
with pytest.raises(SystemExit) as e:
src.fetch(Series("USD", "AUD", type, "2021-01-01", "2021-02-01"))
assert e.value.code == 1
assert in_log(caplog, "CRITICAL", "Invalid pair")
def test_non_eur_base(src, type):
with pytest.raises(exceptions.InvalidPair):
src.fetch(Series("USD", "AUD", type, "2021-01-04", "2021-01-08"))
@pytest.mark.xfail
@pytest.mark.live
def test_unknown_quote(src, type, caplog):
with pytest.raises(SystemExit) as e:
src.fetch(Series("EUR", "XZY", type, "2021-01-01", "2021-02-01"))
assert e.value.code == 1
assert in_log(caplog, "CRITICAL", "Invalid pair")
def test_unknown_quote(src, type, response_ok):
with pytest.raises(exceptions.InvalidPair):
src.fetch(Series("EUR", "XZY", type, "2021-01-04", "2021-01-08"))
@pytest.mark.xfail
def test_no_quote(src, type, caplog):
with pytest.raises(SystemExit) as e:
src.fetch(Series("EUR", "", type, "2021-01-01", "2021-02-01"))
assert e.value.code == 1
assert in_log(caplog, "CRITICAL", "Invalid pair")
def test_no_quote(src, type):
with pytest.raises(exceptions.InvalidPair):
src.fetch(Series("EUR", "", type, "2021-01-04", "2021-01-08"))
def test_unknown_pair(src, type, caplog):
with pytest.raises(SystemExit) as e:
src.fetch(Series("ABC", "XZY", type, "2021-01-01", "2021-02-01"))
assert e.value.code == 1
assert in_log(caplog, "CRITICAL", "Invalid pair")
def test_unknown_pair(src, type):
with pytest.raises(exceptions.InvalidPair):
src.fetch(Series("ABC", "XZY", type, "2021-01-04", "2021-01-08"))
def test_network_issue(src, type, requests_mock):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml",
body=requests.exceptions.ConnectionError("Network issue"),
)
with pytest.raises(exceptions.RequestError) as e:
src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2021-01-08"))
assert "Network issue" in str(e.value)
def test_bad_status(src, type, requests_mock):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml",
status=500,
)
with pytest.raises(exceptions.BadResponse) as e:
src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2021-01-08"))
assert "Server Error" in str(e.value)
def test_parsing_error(src, type, requests_mock):
requests_mock.add(
responses.GET,
"https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.xml",
body="NOT XML",
)
with pytest.raises(exceptions.ResponseParsingError) as e:
src.fetch(Series("EUR", "AUD", type, "2021-01-04", "2021-01-08"))
assert "while parsing data" in str(e.value)

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
</Cube>
</gesmes:Envelope>

View file

@ -0,0 +1,358 @@
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time="2021-01-08">
<Cube currency="USD" rate="1.225"/>
<Cube currency="JPY" rate="127.26"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="26.163"/>
<Cube currency="DKK" rate="7.4369"/>
<Cube currency="GBP" rate="0.90128"/>
<Cube currency="HUF" rate="359.62"/>
<Cube currency="PLN" rate="4.5113"/>
<Cube currency="RON" rate="4.8708"/>
<Cube currency="SEK" rate="10.051"/>
<Cube currency="CHF" rate="1.0827"/>
<Cube currency="ISK" rate="155.5"/>
<Cube currency="NOK" rate="10.2863"/>
<Cube currency="HRK" rate="7.569"/>
<Cube currency="RUB" rate="90.8"/>
<Cube currency="TRY" rate="9.0146"/>
<Cube currency="AUD" rate="1.5758"/>
<Cube currency="BRL" rate="6.5748"/>
<Cube currency="CAD" rate="1.5543"/>
<Cube currency="CNY" rate="7.9184"/>
<Cube currency="HKD" rate="9.4982"/>
<Cube currency="IDR" rate="17247.33"/>
<Cube currency="ILS" rate="3.8981"/>
<Cube currency="INR" rate="89.7975"/>
<Cube currency="KRW" rate="1337.9"/>
<Cube currency="MXN" rate="24.4718"/>
<Cube currency="MYR" rate="4.9359"/>
<Cube currency="NZD" rate="1.6883"/>
<Cube currency="PHP" rate="58.947"/>
<Cube currency="SGD" rate="1.6228"/>
<Cube currency="THB" rate="36.848"/>
<Cube currency="ZAR" rate="18.7212"/>
</Cube>
<Cube time="2021-01-07">
<Cube currency="USD" rate="1.2276"/>
<Cube currency="JPY" rate="127.13"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="26.147"/>
<Cube currency="DKK" rate="7.4392"/>
<Cube currency="GBP" rate="0.9019"/>
<Cube currency="HUF" rate="357.79"/>
<Cube currency="PLN" rate="4.4998"/>
<Cube currency="RON" rate="4.8712"/>
<Cube currency="SEK" rate="10.0575"/>
<Cube currency="CHF" rate="1.0833"/>
<Cube currency="ISK" rate="155.3"/>
<Cube currency="NOK" rate="10.3435"/>
<Cube currency="HRK" rate="7.566"/>
<Cube currency="RUB" rate="91.2"/>
<Cube currency="TRY" rate="8.9987"/>
<Cube currency="AUD" rate="1.5836"/>
<Cube currency="BRL" rate="6.5172"/>
<Cube currency="CAD" rate="1.5601"/>
<Cube currency="CNY" rate="7.9392"/>
<Cube currency="HKD" rate="9.5176"/>
<Cube currency="IDR" rate="17259.99"/>
<Cube currency="ILS" rate="3.9027"/>
<Cube currency="INR" rate="90.0455"/>
<Cube currency="KRW" rate="1342.29"/>
<Cube currency="MXN" rate="24.2552"/>
<Cube currency="MYR" rate="4.957"/>
<Cube currency="NZD" rate="1.6907"/>
<Cube currency="PHP" rate="59.043"/>
<Cube currency="SGD" rate="1.6253"/>
<Cube currency="THB" rate="36.859"/>
<Cube currency="ZAR" rate="18.7919"/>
</Cube>
<Cube time="2021-01-06">
<Cube currency="USD" rate="1.2338"/>
<Cube currency="JPY" rate="127.03"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="26.145"/>
<Cube currency="DKK" rate="7.4393"/>
<Cube currency="GBP" rate="0.90635"/>
<Cube currency="HUF" rate="357.86"/>
<Cube currency="PLN" rate="4.516"/>
<Cube currency="RON" rate="4.872"/>
<Cube currency="SEK" rate="10.0653"/>
<Cube currency="CHF" rate="1.0821"/>
<Cube currency="ISK" rate="156.3"/>
<Cube currency="NOK" rate="10.381"/>
<Cube currency="HRK" rate="7.5595"/>
<Cube currency="RUB" rate="90.8175"/>
<Cube currency="TRY" rate="9.0554"/>
<Cube currency="AUD" rate="1.5824"/>
<Cube currency="BRL" rate="6.5119"/>
<Cube currency="CAD" rate="1.564"/>
<Cube currency="CNY" rate="7.9653"/>
<Cube currency="HKD" rate="9.5659"/>
<Cube currency="IDR" rate="17168.2"/>
<Cube currency="ILS" rate="3.9289"/>
<Cube currency="INR" rate="90.204"/>
<Cube currency="KRW" rate="1339.3"/>
<Cube currency="MXN" rate="24.3543"/>
<Cube currency="MYR" rate="4.9482"/>
<Cube currency="NZD" rate="1.6916"/>
<Cube currency="PHP" rate="59.296"/>
<Cube currency="SGD" rate="1.6246"/>
<Cube currency="THB" rate="36.921"/>
<Cube currency="ZAR" rate="18.5123"/>
</Cube>
<Cube time="2021-01-05">
<Cube currency="USD" rate="1.2271"/>
<Cube currency="JPY" rate="126.25"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="26.227"/>
<Cube currency="DKK" rate="7.4387"/>
<Cube currency="GBP" rate="0.90333"/>
<Cube currency="HUF" rate="360.27"/>
<Cube currency="PLN" rate="4.5473"/>
<Cube currency="RON" rate="4.8721"/>
<Cube currency="SEK" rate="10.057"/>
<Cube currency="CHF" rate="1.0803"/>
<Cube currency="ISK" rate="156.1"/>
<Cube currency="NOK" rate="10.4713"/>
<Cube currency="HRK" rate="7.5588"/>
<Cube currency="RUB" rate="91.6715"/>
<Cube currency="TRY" rate="9.0694"/>
<Cube currency="AUD" rate="1.5927"/>
<Cube currency="BRL" rate="6.5517"/>
<Cube currency="CAD" rate="1.5651"/>
<Cube currency="CNY" rate="7.9315"/>
<Cube currency="HKD" rate="9.5136"/>
<Cube currency="IDR" rate="17075.1"/>
<Cube currency="ILS" rate="3.9277"/>
<Cube currency="INR" rate="89.867"/>
<Cube currency="KRW" rate="1335.85"/>
<Cube currency="MXN" rate="24.586"/>
<Cube currency="MYR" rate="4.9293"/>
<Cube currency="NZD" rate="1.7036"/>
<Cube currency="PHP" rate="59.02"/>
<Cube currency="SGD" rate="1.618"/>
<Cube currency="THB" rate="36.776"/>
<Cube currency="ZAR" rate="18.4194"/>
</Cube>
<Cube time="2021-01-04">
<Cube currency="USD" rate="1.2296"/>
<Cube currency="JPY" rate="126.62"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="26.141"/>
<Cube currency="DKK" rate="7.4379"/>
<Cube currency="GBP" rate="0.9016"/>
<Cube currency="HUF" rate="361.32"/>
<Cube currency="PLN" rate="4.5475"/>
<Cube currency="RON" rate="4.8713"/>
<Cube currency="SEK" rate="10.0895"/>
<Cube currency="CHF" rate="1.0811"/>
<Cube currency="ISK" rate="156.1"/>
<Cube currency="NOK" rate="10.444"/>
<Cube currency="HRK" rate="7.5565"/>
<Cube currency="RUB" rate="90.342"/>
<Cube currency="TRY" rate="9.0579"/>
<Cube currency="AUD" rate="1.5928"/>
<Cube currency="BRL" rate="6.3241"/>
<Cube currency="CAD" rate="1.5621"/>
<Cube currency="CNY" rate="7.9484"/>
<Cube currency="HKD" rate="9.533"/>
<Cube currency="IDR" rate="17062.67"/>
<Cube currency="ILS" rate="3.943"/>
<Cube currency="INR" rate="89.789"/>
<Cube currency="KRW" rate="1332.03"/>
<Cube currency="MXN" rate="24.3031"/>
<Cube currency="MYR" rate="4.9264"/>
<Cube currency="NZD" rate="1.7065"/>
<Cube currency="PHP" rate="59.058"/>
<Cube currency="SGD" rate="1.6198"/>
<Cube currency="THB" rate="36.728"/>
<Cube currency="ZAR" rate="17.9214"/>
</Cube>
<Cube time="2021-06-25">
<Cube currency="USD" rate="1.195"/>
<Cube currency="JPY" rate="132.27"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="25.487"/>
<Cube currency="DKK" rate="7.4363"/>
<Cube currency="GBP" rate="0.8595"/>
<Cube currency="HUF" rate="351.88"/>
<Cube currency="PLN" rate="4.5132"/>
<Cube currency="RON" rate="4.9263"/>
<Cube currency="SEK" rate="10.1103"/>
<Cube currency="CHF" rate="1.0956"/>
<Cube currency="ISK" rate="147.1"/>
<Cube currency="NOK" rate="10.136"/>
<Cube currency="HRK" rate="7.4975"/>
<Cube currency="RUB" rate="86.188"/>
<Cube currency="TRY" rate="10.3887"/>
<Cube currency="AUD" rate="1.5726"/>
<Cube currency="BRL" rate="5.8635"/>
<Cube currency="CAD" rate="1.4696"/>
<Cube currency="CNY" rate="7.7139"/>
<Cube currency="HKD" rate="9.2751"/>
<Cube currency="IDR" rate="17245.4"/>
<Cube currency="ILS" rate="3.8811"/>
<Cube currency="INR" rate="88.6824"/>
<Cube currency="KRW" rate="1346.35"/>
<Cube currency="MXN" rate="23.6766"/>
<Cube currency="MYR" rate="4.9664"/>
<Cube currency="NZD" rate="1.6881"/>
<Cube currency="PHP" rate="57.96"/>
<Cube currency="SGD" rate="1.6035"/>
<Cube currency="THB" rate="38.013"/>
<Cube currency="ZAR" rate="16.8359"/>
</Cube>
<Cube time="1999-01-08">
<Cube currency="USD" rate="1.1659"/>
<Cube currency="JPY" rate="130.09"/>
<Cube currency="CYP" rate="0.58187"/>
<Cube currency="CZK" rate="34.938"/>
<Cube currency="DKK" rate="7.4433"/>
<Cube currency="EEK" rate="15.6466"/>
<Cube currency="GBP" rate="0.7094"/>
<Cube currency="HUF" rate="250.15"/>
<Cube currency="LTL" rate="4.6643"/>
<Cube currency="LVL" rate="0.6654"/>
<Cube currency="MTL" rate="0.4419"/>
<Cube currency="PLN" rate="4.0363"/>
<Cube currency="ROL" rate="13143"/>
<Cube currency="SEK" rate="9.165"/>
<Cube currency="SIT" rate="188.84"/>
<Cube currency="SKK" rate="42.56"/>
<Cube currency="CHF" rate="1.6138"/>
<Cube currency="ISK" rate="80.99"/>
<Cube currency="NOK" rate="8.59"/>
<Cube currency="TRL" rate="371830"/>
<Cube currency="AUD" rate="1.8406"/>
<Cube currency="CAD" rate="1.7643"/>
<Cube currency="HKD" rate="9.0302"/>
<Cube currency="KRW" rate="1366.73"/>
<Cube currency="NZD" rate="2.1557"/>
<Cube currency="SGD" rate="1.9537"/>
<Cube currency="ZAR" rate="6.7855"/>
</Cube>
<Cube time="1999-01-07">
<Cube currency="USD" rate="1.1632"/>
<Cube currency="JPY" rate="129.43"/>
<Cube currency="CYP" rate="0.58187"/>
<Cube currency="CZK" rate="34.886"/>
<Cube currency="DKK" rate="7.4431"/>
<Cube currency="EEK" rate="15.6466"/>
<Cube currency="GBP" rate="0.70585"/>
<Cube currency="HUF" rate="250.09"/>
<Cube currency="LTL" rate="4.6548"/>
<Cube currency="LVL" rate="0.6627"/>
<Cube currency="MTL" rate="0.4413"/>
<Cube currency="PLN" rate="4.0165"/>
<Cube currency="ROL" rate="13092"/>
<Cube currency="SEK" rate="9.18"/>
<Cube currency="SIT" rate="188.8"/>
<Cube currency="SKK" rate="42.765"/>
<Cube currency="CHF" rate="1.6165"/>
<Cube currency="ISK" rate="81.06"/>
<Cube currency="NOK" rate="8.6295"/>
<Cube currency="TRL" rate="370147"/>
<Cube currency="AUD" rate="1.8474"/>
<Cube currency="CAD" rate="1.7602"/>
<Cube currency="HKD" rate="9.0131"/>
<Cube currency="KRW" rate="1337.16"/>
<Cube currency="NZD" rate="2.1531"/>
<Cube currency="SGD" rate="1.9436"/>
<Cube currency="ZAR" rate="6.8283"/>
</Cube>
<Cube time="1999-01-06">
<Cube currency="USD" rate="1.1743"/>
<Cube currency="JPY" rate="131.42"/>
<Cube currency="CYP" rate="0.582"/>
<Cube currency="CZK" rate="34.85"/>
<Cube currency="DKK" rate="7.4452"/>
<Cube currency="EEK" rate="15.6466"/>
<Cube currency="GBP" rate="0.7076"/>
<Cube currency="HUF" rate="250.67"/>
<Cube currency="LTL" rate="4.6994"/>
<Cube currency="LVL" rate="0.6649"/>
<Cube currency="MTL" rate="0.442"/>
<Cube currency="PLN" rate="4.0065"/>
<Cube currency="ROL" rate="13168"/>
<Cube currency="SEK" rate="9.305"/>
<Cube currency="SIT" rate="188.7"/>
<Cube currency="SKK" rate="42.778"/>
<Cube currency="CHF" rate="1.6116"/>
<Cube currency="ISK" rate="81.54"/>
<Cube currency="NOK" rate="8.7335"/>
<Cube currency="TRL" rate="372188"/>
<Cube currency="AUD" rate="1.882"/>
<Cube currency="CAD" rate="1.7711"/>
<Cube currency="HKD" rate="9.101"/>
<Cube currency="KRW" rate="1359.54"/>
<Cube currency="NZD" rate="2.189"/>
<Cube currency="SGD" rate="1.9699"/>
<Cube currency="ZAR" rate="6.7307"/>
</Cube>
<Cube time="1999-01-05">
<Cube currency="USD" rate="1.179"/>
<Cube currency="JPY" rate="130.96"/>
<Cube currency="CYP" rate="0.5823"/>
<Cube currency="CZK" rate="34.917"/>
<Cube currency="DKK" rate="7.4495"/>
<Cube currency="EEK" rate="15.6466"/>
<Cube currency="GBP" rate="0.7122"/>
<Cube currency="HUF" rate="250.8"/>
<Cube currency="LTL" rate="4.7174"/>
<Cube currency="LVL" rate="0.6657"/>
<Cube currency="MTL" rate="0.4432"/>
<Cube currency="PLN" rate="4.0245"/>
<Cube currency="ROL" rate="13168"/>
<Cube currency="SEK" rate="9.4025"/>
<Cube currency="SIT" rate="188.775"/>
<Cube currency="SKK" rate="42.848"/>
<Cube currency="CHF" rate="1.6123"/>
<Cube currency="ISK" rate="81.53"/>
<Cube currency="NOK" rate="8.7745"/>
<Cube currency="TRL" rate="372816"/>
<Cube currency="AUD" rate="1.8944"/>
<Cube currency="CAD" rate="1.7965"/>
<Cube currency="HKD" rate="9.1341"/>
<Cube currency="KRW" rate="1373.01"/>
<Cube currency="NZD" rate="2.2011"/>
<Cube currency="SGD" rate="1.9655"/>
<Cube currency="ZAR" rate="6.7975"/>
</Cube>
<Cube time="1999-01-04">
<Cube currency="USD" rate="1.1789"/>
<Cube currency="JPY" rate="133.73"/>
<Cube currency="CYP" rate="0.58231"/>
<Cube currency="CZK" rate="35.107"/>
<Cube currency="DKK" rate="7.4501"/>
<Cube currency="EEK" rate="15.6466"/>
<Cube currency="GBP" rate="0.7111"/>
<Cube currency="HUF" rate="251.48"/>
<Cube currency="LTL" rate="4.717"/>
<Cube currency="LVL" rate="0.6668"/>
<Cube currency="MTL" rate="0.4432"/>
<Cube currency="PLN" rate="4.0712"/>
<Cube currency="ROL" rate="13111"/>
<Cube currency="SEK" rate="9.4696"/>
<Cube currency="SIT" rate="189.045"/>
<Cube currency="SKK" rate="42.991"/>
<Cube currency="CHF" rate="1.6168"/>
<Cube currency="ISK" rate="81.48"/>
<Cube currency="NOK" rate="8.855"/>
<Cube currency="TRL" rate="372274"/>
<Cube currency="AUD" rate="1.91"/>
<Cube currency="CAD" rate="1.8004"/>
<Cube currency="HKD" rate="9.1332"/>
<Cube currency="KRW" rate="1398.59"/>
<Cube currency="NZD" rate="2.2229"/>
<Cube currency="SGD" rate="1.9554"/>
<Cube currency="ZAR" rate="6.9358"/>
</Cube>
</Cube>
</gesmes:Envelope>