-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathecb.py
171 lines (135 loc) · 6.54 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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import datetime
import os
import requests
from xml.etree import ElementTree as ET
import pandas as pd
FROM_CURRENCIES = ["EUR", "USD", "JPY", "BGN", "CZK", "DKK", "GBP", "HUF", "PLN", "RON", "SEK", "CHF", "ISK", "NOK",
"HRK", "RUB", "TRY", "AUD", "BRL", "CAD", "CNY", "HKD", "IDR", "ILS", "INR", "KRW", "MXN", "MYR",
"NZD", "PHP", "SGD", "THB", "ZAR"]
TO_CURRENCIES = ["EUR", "USD", "JPY", "BGN", "CZK", "DKK", "GBP", "HUF", "PLN", "RON", "SEK", "CHF", "ISK", "NOK",
"HRK", "RUB", "TRY", "AUD", "BRL", "CAD", "CNY", "HKD", "IDR", "ILS", "INR", "KRW", "MXN", "MYR",
"NZD", "PHP", "SGD", "THB", "ZAR"]
FROM_DATE = '2022-04-07'
TO_DATE = '2022-04-09'
def get_ecb_data(from_date, to_date, key):
# The web service entry point is available at the following location:
wsEntryPoint = 'https://sdw-wsrest.ecb.europa.eu/service'
# The resource for data queries is data
resource = 'data'
# A reference to the dataflow describing the data that needs to be returned.
flowRef = 'EXR'
# Base url
request_url = f"{wsEntryPoint}/{resource}/{flowRef}/{key}"
result = ''
while not result:
response = requests.get(request_url,
params={'detail': 'dataonly', 'startPeriod': from_date, 'endPeriod': to_date})
if not response.ok:
raise Exception("The currency rate could not be fetched because the response was incorrect.")
if not response.text:
from_date = datetime.datetime.strptime(from_date, '%Y-%m-%d')
to_date = datetime.datetime.strptime(to_date, '%Y-%m-%d')
new_from_date = (from_date - datetime.timedelta(days=1)).date()
new_to_date = (to_date - datetime.timedelta(days=1)).date()
from_date = new_from_date.strftime("%Y-%m-%d")
to_date = new_to_date.strftime("%Y-%m-%d")
result = response.text
return result
def get_ecb_rates_with_dates(text):
currencies = []
dates = set()
root = ET.fromstring(text)
ns = {'generic': "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic",
'message': "http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message"}
series = root.findall('./message:DataSet/generic:Series', ns)
for index, data in enumerate(series):
currency_type = data.find('./generic:SeriesKey/generic:Value[@id="CURRENCY"]', ns)
from_currency = "EUR"
to_currency = currency_type.get('value')
pair = f"{from_currency}-{to_currency}"
obs_value = data.findall('./generic:Obs/generic:ObsValue', ns)
obs_dimension = data.findall('./generic:Obs/generic:ObsDimension', ns)
for i, dimension in enumerate(obs_dimension):
rate = obs_value[i].get('value')
date = obs_dimension[i].get('value')
dates.add(date)
currencies.append({
"pair": pair,
"from": from_currency,
"to": to_currency,
"rate": rate,
"date": date,
})
return currencies, dates
def calculate_other_currencies(from_currencies, to_currencies, currencies, dates):
new_currencies = []
for from_currency in from_currencies:
for to_currency in to_currencies:
# Exclude EUR cause we are already have it
if from_currency == "EUR" or to_currency == "EUR":
continue
# Exclude same currencies and calculate others
if from_currency != to_currency:
from_rate, to_rate = 0, 0
for date in dates:
for currency in currencies:
if currency.get('to') == from_currency and currency.get('date') == date:
from_rate = float(currency.get('rate'))
if currency.get('to') == to_currency and currency.get('date') == date:
to_rate = float(currency.get('rate'))
if from_rate == 0 or to_rate == 0:
new_currencies.append(
{
"pair": f"{from_currency}-{to_currency}",
"from": from_currency,
"to": to_currency,
"rate": "There is no data for this pair",
"date": date,
}
)
else:
new_currencies.append(
{
"pair": f"{from_currency}-{to_currency}",
"from": from_currency,
"to": to_currency,
"rate": str(round(to_rate / from_rate, 4)),
"date": date,
}
)
return new_currencies
def exchange(from_currencies, to_currencies, from_date, to_date, with_euro=True, format='csv'):
# Separate unique fot this 2 lists` from_currencies and to_currencies and join with + for ECB API
all_unique_currency = set(from_currencies + to_currencies)
all_unique_currency.discard('EUR')
key_component = "+".join(all_unique_currency)
key = 'D.{}.EUR.SP00.A'.format(key_component)
# ECB API responce
response = get_ecb_data(from_date, to_date, key)
# Get dates and currencies against the EUR
currencies, dates = get_ecb_rates_with_dates(response)
# Calculate other currencies pairs
other_currencies = calculate_other_currencies(from_currencies, to_currencies, currencies, dates)
# Collect all data
all_data = currencies + other_currencies if with_euro else other_currencies
# Create a pandas Dataframe with columns
df = pd.DataFrame(all_data, columns=["pair", "from", "to", "rate", "date"])
# Check direction
output_dir = './output'
if not os.path.exists(output_dir):
os.mkdir(output_dir)
if format == 'csv':
fullname = os.path.join(output_dir, f"ecb_{from_date}-{to_date}.csv")
df.to_csv(fullname)
elif format == 'json':
fullname = os.path.join(output_dir, f"ecb_{from_date}-{to_date}.json")
df.to_json(fullname, orient='records')
else:
raise Exception("Incorrect format.")
if __name__ == "__main__":
print("Start")
start = datetime.datetime.now()
exchange(FROM_CURRENCIES, TO_CURRENCIES, FROM_DATE, TO_DATE, with_euro=True, format='csv')
stop = datetime.datetime.now() - start
print('Time: ', stop)
print("END")