pynbpapi 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynbpapi-1.0.0/.github/workflows/flake8-lint.yml +26 -0
- pynbpapi-1.0.0/.github/workflows/python-tests.yml +34 -0
- pynbpapi-1.0.0/.gitignore +6 -0
- pynbpapi-1.0.0/LICENSE +17 -0
- pynbpapi-1.0.0/PKG-INFO +197 -0
- pynbpapi-1.0.0/README.md +182 -0
- pynbpapi-1.0.0/pynbpapi/__init__.py +31 -0
- pynbpapi-1.0.0/pynbpapi/ccy.py +36 -0
- pynbpapi-1.0.0/pynbpapi/common.py +37 -0
- pynbpapi-1.0.0/pynbpapi/exceptions.py +17 -0
- pynbpapi-1.0.0/pynbpapi/fx.py +135 -0
- pynbpapi-1.0.0/pynbpapi/gold.py +32 -0
- pynbpapi-1.0.0/pynbpapi/interest_rates.py +62 -0
- pynbpapi-1.0.0/pyproject.toml +25 -0
- pynbpapi-1.0.0/requirements.txt +28 -0
- pynbpapi-1.0.0/tests/__init__.py +0 -0
- pynbpapi-1.0.0/tests/test_common.py +19 -0
- pynbpapi-1.0.0/tests/test_fx.py +13 -0
- pynbpapi-1.0.0/tests/test_gold.py +10 -0
- pynbpapi-1.0.0/tests/test_interest_rates.py +13 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
flake8-lint:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Checkout code
|
|
11
|
+
uses: actions/checkout@v3
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v4
|
|
15
|
+
with:
|
|
16
|
+
python-version: '3.11'
|
|
17
|
+
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: |
|
|
20
|
+
python -m pip install --upgrade pip
|
|
21
|
+
pip install flake8
|
|
22
|
+
pip install -r requirements.txt
|
|
23
|
+
|
|
24
|
+
- name: Run Flake8
|
|
25
|
+
run: |
|
|
26
|
+
flake8 pynbpapi
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
|
|
11
|
+
steps:
|
|
12
|
+
- name: Checkout code
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.11"
|
|
19
|
+
|
|
20
|
+
- name: Install dependencies
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
pip install -r requirements.txt
|
|
24
|
+
pip install pytest pytest-cov
|
|
25
|
+
|
|
26
|
+
- name: Run tests with coverage
|
|
27
|
+
run: |
|
|
28
|
+
pytest --cov=pynbp --cov-report=xml
|
|
29
|
+
|
|
30
|
+
- name: Upload coverage to Codecov
|
|
31
|
+
uses: codecov/codecov-action@v4
|
|
32
|
+
|
|
33
|
+
- name: List files
|
|
34
|
+
run: ls -la
|
pynbpapi-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
Copyright (c) 2026 ARTUR WEGRZYN
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
The above copyright notice and this permission notice shall be included in all
|
|
10
|
+
copies or substantial portions of the Software.
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
12
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
13
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
14
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
15
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
16
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
17
|
+
SOFTWARE.
|
pynbpapi-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pynbpapi
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Tidy downloading of National Bank of Poland interest rates, FX rates and gold price data
|
|
5
|
+
Keywords: NBP,FX,PLN,gold,API,REST-API,FX-rates,zloty
|
|
6
|
+
Author-email: Artur Wegrzyn <awegrzyn17@gmail.com>
|
|
7
|
+
Maintainer-email: Artur Wegrzyn <awegrzyn17@gmail.com>
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: pandas
|
|
12
|
+
Requires-Dist: requests
|
|
13
|
+
Requires-Dist: python-dateutil
|
|
14
|
+
Requires-Dist: loguru
|
|
15
|
+
|
|
16
|
+
# pynbpapi
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+

|
|
20
|
+
[](https://codecov.io/github/wegar-2/pycs)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
This trivial package provides simple interface (consisting of three functions described below)
|
|
24
|
+
that allows you to download the selected types of time series made available
|
|
25
|
+
via [National Bank of Poland's REST API](http://api.nbp.pl/en.html).
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
More specifically, the following time series can be downloaded using PyNBP:
|
|
29
|
+
|
|
30
|
+
1. Average daily FX rates for select currencies
|
|
31
|
+
(cf. [NBP's table of daily FX rates against various currencies]()
|
|
32
|
+
for list of currencies for which exchange rates are published).
|
|
33
|
+
2. Table of historical central bank interest rates.
|
|
34
|
+
3. Gold prices in PLN (note: the gold prices published by NBP are prices of 1g of gold).
|
|
35
|
+
4. Downloading of the daily central bank's [FX rates tables](https://nbp.pl/statystyka-i-sprawozdawczosc/kursy/) (A, B and C)
|
|
36
|
+
|
|
37
|
+
Note: the table of historical interest is not *per se* provided via NBP's API.
|
|
38
|
+
|
|
39
|
+
I provide code snippets illustrating how to get the data below.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Import *pynbpapi*
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import pynbpapi
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
or:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from pynbpapi import (
|
|
52
|
+
get_gold_prices, get_interest_rates_table, get_fx_rate,
|
|
53
|
+
get_nbp_fx_tables, get_fx_rates)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### FX Rate For a Single Pair Against PLN
|
|
57
|
+
To download USDPLN daily average FX rates for the dates range 2018-01-03 to 2021-04-05
|
|
58
|
+
(these dates are given in the ISO / %Y-%m-%d format) run:
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from pynbpapi import get_fx_rate
|
|
62
|
+
from datetime import date
|
|
63
|
+
|
|
64
|
+
data = get_fx_rate(ccy="usd", start=date(2018, 1, 3), end=date(2021, 4, 5))
|
|
65
|
+
print(data.head())
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Output:
|
|
69
|
+
```
|
|
70
|
+
date usdpln_rate
|
|
71
|
+
0 2018-01-03 3.4616
|
|
72
|
+
1 2018-01-04 3.4472
|
|
73
|
+
2 2018-01-05 3.4488
|
|
74
|
+
3 2018-01-08 3.4735
|
|
75
|
+
4 2018-01-09 3.4992
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### FX Rates For Multiple Pairs Against PLN
|
|
79
|
+
To download USDPLN, EURPLN and CNYPLN daily average FX rates for the dates
|
|
80
|
+
range 2018-01-03 to 2021-04-05
|
|
81
|
+
(these dates are given in the ISO / %Y-%m-%d format)
|
|
82
|
+
in the long format (alternatively - wide format can be chosen) run:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from pynbpapi import get_fx_rates, Ccy
|
|
86
|
+
from datetime import date
|
|
87
|
+
|
|
88
|
+
data = get_fx_rates(
|
|
89
|
+
ccys=[Ccy.EUR, Ccy.USD, Ccy.CNY],
|
|
90
|
+
start=date(2018, 1, 3),
|
|
91
|
+
end=date(2021, 4, 5),
|
|
92
|
+
fmt="long"
|
|
93
|
+
)
|
|
94
|
+
print(data.head())
|
|
95
|
+
print(data.tail())
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Output - head:
|
|
99
|
+
```
|
|
100
|
+
date rate pair
|
|
101
|
+
0 2018-01-03 4.1673 eurpln
|
|
102
|
+
1 2018-01-04 4.1515 eurpln
|
|
103
|
+
2 2018-01-05 4.1544 eurpln
|
|
104
|
+
3 2018-01-08 4.1647 eurpln
|
|
105
|
+
4 2018-01-09 4.1779 eurpln
|
|
106
|
+
```
|
|
107
|
+
And tail:
|
|
108
|
+
```
|
|
109
|
+
date rate pair
|
|
110
|
+
816 2021-03-29 0.6027 cnypln
|
|
111
|
+
817 2021-03-30 0.6030 cnypln
|
|
112
|
+
818 2021-03-31 0.6053 cnypln
|
|
113
|
+
819 2021-04-01 0.5998 cnypln
|
|
114
|
+
820 2021-04-02 0.5941 cnypln
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
### Table of Historical Interest Rates
|
|
120
|
+
To download the table of historical interest rates set by NBP run:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from pynbpapi import get_interest_rates_table
|
|
124
|
+
from datetime import date
|
|
125
|
+
|
|
126
|
+
data = get_interest_rates_table()
|
|
127
|
+
print(data.tail())
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Output:
|
|
131
|
+
```
|
|
132
|
+
valid_from_date lombard_rate reference_rate rediscount_rate discount_rate deposit_rate
|
|
133
|
+
82 2022-04-07 0.0500 0.0450 0.0455 0.0460 0.0400
|
|
134
|
+
83 2022-05-06 0.0575 0.0525 0.0530 0.0535 0.0475
|
|
135
|
+
84 2022-06-09 0.0650 0.0600 0.0605 0.0610 0.0550
|
|
136
|
+
85 2022-07-08 0.0700 0.0650 0.0655 0.0660 0.0600
|
|
137
|
+
86 2022-09-08 0.0725 0.0675 0.0680 0.0685 0.0625
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
### Gold Prices in PLN
|
|
143
|
+
To download gold prices in PLN for the dates range 2018-01-03 to 2021-04-05 run:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from pynbpapi import get_gold_prices
|
|
147
|
+
from datetime import date
|
|
148
|
+
|
|
149
|
+
data = get_gold_prices(start=date(2018, 1, 3), end=date(2021, 4, 5))
|
|
150
|
+
print(data.head())
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Please keep in mind that the daily prices of gold published by
|
|
154
|
+
NBP are prices of 1g of gold in PLN.
|
|
155
|
+
|
|
156
|
+
Output:
|
|
157
|
+
```
|
|
158
|
+
date price_of_1g_of_gold_in_pln
|
|
159
|
+
0 2018-01-03 145.72
|
|
160
|
+
1 2018-01-04 146.36
|
|
161
|
+
2 2018-01-05 145.68
|
|
162
|
+
3 2018-01-08 146.06
|
|
163
|
+
4 2018-01-09 147.42
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
### Download Daily NBP's FX Rates Tables
|
|
168
|
+
To download FX rates table A for dates range 2026-02-18 to 2026-02-19 run:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from pynbpapi import get_nbp_fx_tables
|
|
172
|
+
from datetime import date
|
|
173
|
+
data = get_nbp_fx_tables(table="A", start=date(2026, 2, 18), end=date(2026, 2, 19))
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Please keep in mind that the daily prices of gold published by
|
|
177
|
+
NBP are prices of 1g of gold in PLN.
|
|
178
|
+
|
|
179
|
+
Output - head:
|
|
180
|
+
```
|
|
181
|
+
currency code mid table no date
|
|
182
|
+
0 bat (Tajlandia) THB 0.1137 A 033/A/NBP/2026 2026-02-18
|
|
183
|
+
1 dolar amerykański USD 3.5610 A 033/A/NBP/2026 2026-02-18
|
|
184
|
+
2 dolar australijski AUD 2.5204 A 033/A/NBP/2026 2026-02-18
|
|
185
|
+
3 dolar Hongkongu HKD 0.4556 A 033/A/NBP/2026 2026-02-18
|
|
186
|
+
4 dolar kanadyjski CAD 2.6078 A 033/A/NBP/2026 2026-02-18
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
And tail:
|
|
190
|
+
```
|
|
191
|
+
currency code mid table no date
|
|
192
|
+
59 rupia indonezyjska IDR 0.000212 A 034/A/NBP/2026 2026-02-19
|
|
193
|
+
60 rupia indyjska INR 0.039242 A 034/A/NBP/2026 2026-02-19
|
|
194
|
+
61 won południowokoreański KRW 0.002472 A 034/A/NBP/2026 2026-02-19
|
|
195
|
+
62 yuan renminbi (Chiny) CNY 0.515200 A 034/A/NBP/2026 2026-02-19
|
|
196
|
+
63 SDR (MFW) XDR 4.909800 A 034/A/NBP/2026 2026-02-19
|
|
197
|
+
```
|
pynbpapi-1.0.0/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# pynbpapi
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
[](https://codecov.io/github/wegar-2/pycs)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
This trivial package provides simple interface (consisting of three functions described below)
|
|
9
|
+
that allows you to download the selected types of time series made available
|
|
10
|
+
via [National Bank of Poland's REST API](http://api.nbp.pl/en.html).
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
More specifically, the following time series can be downloaded using PyNBP:
|
|
14
|
+
|
|
15
|
+
1. Average daily FX rates for select currencies
|
|
16
|
+
(cf. [NBP's table of daily FX rates against various currencies]()
|
|
17
|
+
for list of currencies for which exchange rates are published).
|
|
18
|
+
2. Table of historical central bank interest rates.
|
|
19
|
+
3. Gold prices in PLN (note: the gold prices published by NBP are prices of 1g of gold).
|
|
20
|
+
4. Downloading of the daily central bank's [FX rates tables](https://nbp.pl/statystyka-i-sprawozdawczosc/kursy/) (A, B and C)
|
|
21
|
+
|
|
22
|
+
Note: the table of historical interest is not *per se* provided via NBP's API.
|
|
23
|
+
|
|
24
|
+
I provide code snippets illustrating how to get the data below.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Import *pynbpapi*
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import pynbpapi
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
or:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from pynbpapi import (
|
|
37
|
+
get_gold_prices, get_interest_rates_table, get_fx_rate,
|
|
38
|
+
get_nbp_fx_tables, get_fx_rates)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### FX Rate For a Single Pair Against PLN
|
|
42
|
+
To download USDPLN daily average FX rates for the dates range 2018-01-03 to 2021-04-05
|
|
43
|
+
(these dates are given in the ISO / %Y-%m-%d format) run:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from pynbpapi import get_fx_rate
|
|
47
|
+
from datetime import date
|
|
48
|
+
|
|
49
|
+
data = get_fx_rate(ccy="usd", start=date(2018, 1, 3), end=date(2021, 4, 5))
|
|
50
|
+
print(data.head())
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Output:
|
|
54
|
+
```
|
|
55
|
+
date usdpln_rate
|
|
56
|
+
0 2018-01-03 3.4616
|
|
57
|
+
1 2018-01-04 3.4472
|
|
58
|
+
2 2018-01-05 3.4488
|
|
59
|
+
3 2018-01-08 3.4735
|
|
60
|
+
4 2018-01-09 3.4992
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### FX Rates For Multiple Pairs Against PLN
|
|
64
|
+
To download USDPLN, EURPLN and CNYPLN daily average FX rates for the dates
|
|
65
|
+
range 2018-01-03 to 2021-04-05
|
|
66
|
+
(these dates are given in the ISO / %Y-%m-%d format)
|
|
67
|
+
in the long format (alternatively - wide format can be chosen) run:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from pynbpapi import get_fx_rates, Ccy
|
|
71
|
+
from datetime import date
|
|
72
|
+
|
|
73
|
+
data = get_fx_rates(
|
|
74
|
+
ccys=[Ccy.EUR, Ccy.USD, Ccy.CNY],
|
|
75
|
+
start=date(2018, 1, 3),
|
|
76
|
+
end=date(2021, 4, 5),
|
|
77
|
+
fmt="long"
|
|
78
|
+
)
|
|
79
|
+
print(data.head())
|
|
80
|
+
print(data.tail())
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Output - head:
|
|
84
|
+
```
|
|
85
|
+
date rate pair
|
|
86
|
+
0 2018-01-03 4.1673 eurpln
|
|
87
|
+
1 2018-01-04 4.1515 eurpln
|
|
88
|
+
2 2018-01-05 4.1544 eurpln
|
|
89
|
+
3 2018-01-08 4.1647 eurpln
|
|
90
|
+
4 2018-01-09 4.1779 eurpln
|
|
91
|
+
```
|
|
92
|
+
And tail:
|
|
93
|
+
```
|
|
94
|
+
date rate pair
|
|
95
|
+
816 2021-03-29 0.6027 cnypln
|
|
96
|
+
817 2021-03-30 0.6030 cnypln
|
|
97
|
+
818 2021-03-31 0.6053 cnypln
|
|
98
|
+
819 2021-04-01 0.5998 cnypln
|
|
99
|
+
820 2021-04-02 0.5941 cnypln
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
### Table of Historical Interest Rates
|
|
105
|
+
To download the table of historical interest rates set by NBP run:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from pynbpapi import get_interest_rates_table
|
|
109
|
+
from datetime import date
|
|
110
|
+
|
|
111
|
+
data = get_interest_rates_table()
|
|
112
|
+
print(data.tail())
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Output:
|
|
116
|
+
```
|
|
117
|
+
valid_from_date lombard_rate reference_rate rediscount_rate discount_rate deposit_rate
|
|
118
|
+
82 2022-04-07 0.0500 0.0450 0.0455 0.0460 0.0400
|
|
119
|
+
83 2022-05-06 0.0575 0.0525 0.0530 0.0535 0.0475
|
|
120
|
+
84 2022-06-09 0.0650 0.0600 0.0605 0.0610 0.0550
|
|
121
|
+
85 2022-07-08 0.0700 0.0650 0.0655 0.0660 0.0600
|
|
122
|
+
86 2022-09-08 0.0725 0.0675 0.0680 0.0685 0.0625
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
### Gold Prices in PLN
|
|
128
|
+
To download gold prices in PLN for the dates range 2018-01-03 to 2021-04-05 run:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from pynbpapi import get_gold_prices
|
|
132
|
+
from datetime import date
|
|
133
|
+
|
|
134
|
+
data = get_gold_prices(start=date(2018, 1, 3), end=date(2021, 4, 5))
|
|
135
|
+
print(data.head())
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Please keep in mind that the daily prices of gold published by
|
|
139
|
+
NBP are prices of 1g of gold in PLN.
|
|
140
|
+
|
|
141
|
+
Output:
|
|
142
|
+
```
|
|
143
|
+
date price_of_1g_of_gold_in_pln
|
|
144
|
+
0 2018-01-03 145.72
|
|
145
|
+
1 2018-01-04 146.36
|
|
146
|
+
2 2018-01-05 145.68
|
|
147
|
+
3 2018-01-08 146.06
|
|
148
|
+
4 2018-01-09 147.42
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
### Download Daily NBP's FX Rates Tables
|
|
153
|
+
To download FX rates table A for dates range 2026-02-18 to 2026-02-19 run:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from pynbpapi import get_nbp_fx_tables
|
|
157
|
+
from datetime import date
|
|
158
|
+
data = get_nbp_fx_tables(table="A", start=date(2026, 2, 18), end=date(2026, 2, 19))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Please keep in mind that the daily prices of gold published by
|
|
162
|
+
NBP are prices of 1g of gold in PLN.
|
|
163
|
+
|
|
164
|
+
Output - head:
|
|
165
|
+
```
|
|
166
|
+
currency code mid table no date
|
|
167
|
+
0 bat (Tajlandia) THB 0.1137 A 033/A/NBP/2026 2026-02-18
|
|
168
|
+
1 dolar amerykański USD 3.5610 A 033/A/NBP/2026 2026-02-18
|
|
169
|
+
2 dolar australijski AUD 2.5204 A 033/A/NBP/2026 2026-02-18
|
|
170
|
+
3 dolar Hongkongu HKD 0.4556 A 033/A/NBP/2026 2026-02-18
|
|
171
|
+
4 dolar kanadyjski CAD 2.6078 A 033/A/NBP/2026 2026-02-18
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
And tail:
|
|
175
|
+
```
|
|
176
|
+
currency code mid table no date
|
|
177
|
+
59 rupia indonezyjska IDR 0.000212 A 034/A/NBP/2026 2026-02-19
|
|
178
|
+
60 rupia indyjska INR 0.039242 A 034/A/NBP/2026 2026-02-19
|
|
179
|
+
61 won południowokoreański KRW 0.002472 A 034/A/NBP/2026 2026-02-19
|
|
180
|
+
62 yuan renminbi (Chiny) CNY 0.515200 A 034/A/NBP/2026 2026-02-19
|
|
181
|
+
63 SDR (MFW) XDR 4.909800 A 034/A/NBP/2026 2026-02-19
|
|
182
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from .ccy import Ccy
|
|
2
|
+
from .fx import get_fx_rate, get_fx_rates, get_nbp_fx_tables
|
|
3
|
+
from .gold import get_gold_prices
|
|
4
|
+
from .interest_rates import get_interest_rates_table
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"Ccy",
|
|
8
|
+
"get_fx_rate",
|
|
9
|
+
"get_fx_rates",
|
|
10
|
+
"get_gold_prices",
|
|
11
|
+
"get_interest_rates_table",
|
|
12
|
+
"get_nbp_fx_tables",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def configure_logging():
|
|
19
|
+
console_handler = logging.StreamHandler()
|
|
20
|
+
formatter = logging.Formatter(
|
|
21
|
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
22
|
+
console_handler.setFormatter(formatter)
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger()
|
|
25
|
+
if logger.hasHandlers():
|
|
26
|
+
logger.handlers.clear()
|
|
27
|
+
logger.setLevel(logging.INFO)
|
|
28
|
+
logger.addHandler(console_handler)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
configure_logging()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Ccy(Enum):
|
|
5
|
+
THB = "THB"
|
|
6
|
+
USD = "USD"
|
|
7
|
+
AUD = "AUD"
|
|
8
|
+
HKD = "HKD"
|
|
9
|
+
CAD = "CAD"
|
|
10
|
+
NZD = "NZD"
|
|
11
|
+
SGD = "SGD"
|
|
12
|
+
EUR = "EUR"
|
|
13
|
+
HUF = "HUF"
|
|
14
|
+
CHF = "CHF"
|
|
15
|
+
GBP = "GBP"
|
|
16
|
+
UAH = "UAH"
|
|
17
|
+
JPY = "JPY"
|
|
18
|
+
CZK = "CZK"
|
|
19
|
+
DKK = "DKK"
|
|
20
|
+
ISK = "ISK"
|
|
21
|
+
NOK = "NOK"
|
|
22
|
+
SEK = "SEK"
|
|
23
|
+
RON = "RON"
|
|
24
|
+
BGN = "BGN"
|
|
25
|
+
TRY = "TRY"
|
|
26
|
+
ILS = "ILS"
|
|
27
|
+
CLP = "CLP"
|
|
28
|
+
PHP = "PHP"
|
|
29
|
+
MXN = "MXN"
|
|
30
|
+
ZAR = "ZAR"
|
|
31
|
+
BRL = "BRL"
|
|
32
|
+
MYR = "MYR"
|
|
33
|
+
IDR = "IDR"
|
|
34
|
+
INR = "INR"
|
|
35
|
+
KRW = "KRW"
|
|
36
|
+
CNY = "CNY"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from datetime import date, timedelta
|
|
2
|
+
from json import loads
|
|
3
|
+
from dateutil.relativedelta import relativedelta
|
|
4
|
+
from requests import get
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"get_default_dates_range",
|
|
8
|
+
"run_web_api_query",
|
|
9
|
+
"split_dates_range_into_smaller_chunks"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_default_dates_range() -> tuple[date, date]:
|
|
14
|
+
date_end = date.today() - timedelta(days=1)
|
|
15
|
+
date_start = date_end + relativedelta(years=-1) + timedelta(days=1)
|
|
16
|
+
return date_start, date_end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run_web_api_query(url: str) -> dict:
|
|
20
|
+
return loads(get(url=url, timeout=180).text)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def split_dates_range_into_smaller_chunks(
|
|
24
|
+
start: date,
|
|
25
|
+
end: date
|
|
26
|
+
) -> list[tuple[date, date]]:
|
|
27
|
+
if (end - start).days >= 367:
|
|
28
|
+
temp = start
|
|
29
|
+
out = []
|
|
30
|
+
while temp < end:
|
|
31
|
+
out.append(
|
|
32
|
+
(temp, temp + relativedelta(years=1) - timedelta(days=1))
|
|
33
|
+
)
|
|
34
|
+
temp = temp + relativedelta(years=1)
|
|
35
|
+
out[-1] = (out[-1][0], end)
|
|
36
|
+
return out
|
|
37
|
+
return [(start, end)]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"InvalidStartEndDatesException",
|
|
5
|
+
"InvalidCurrencyException"
|
|
6
|
+
]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class InvalidStartEndDatesException(ValueError):
|
|
10
|
+
def __init__(self, start: date, end: date):
|
|
11
|
+
self.message: str = (f"Inconsistent start={start.isoformat()} and "
|
|
12
|
+
f"end={end.isoformat()} dates! ")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class InvalidCurrencyException(ValueError):
|
|
16
|
+
def __init__(self, ccy: str):
|
|
17
|
+
self.message = f"Encountered invalid currency: {ccy}"
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from functools import reduce
|
|
3
|
+
from typing import Literal, Union
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from pynbpapi.common import (
|
|
8
|
+
split_dates_range_into_smaller_chunks, run_web_api_query)
|
|
9
|
+
from pynbpapi.ccy import Ccy
|
|
10
|
+
from pynbpapi.exceptions import (
|
|
11
|
+
InvalidStartEndDatesException, InvalidCurrencyException)
|
|
12
|
+
|
|
13
|
+
__all__ = ["get_fx_rate", "get_fx_rates", "get_nbp_fx_tables"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _validate_fx_table_code(code: str) -> None:
|
|
17
|
+
if code not in ["A", "B", "C"]:
|
|
18
|
+
raise ValueError(f"Invalid NBP code value {code}")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _validate_start_end_dates(start: date, end: date) -> None:
|
|
22
|
+
if start > end:
|
|
23
|
+
raise InvalidStartEndDatesException(start, end)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _validate_ccys(ccys: list) -> None:
|
|
27
|
+
for i in range(len(ccys)):
|
|
28
|
+
ccy = ccys[i]
|
|
29
|
+
if not (isinstance(ccy, str) or isinstance(ccy, Ccy)):
|
|
30
|
+
raise TypeError(
|
|
31
|
+
f"Encountered ccy of invalid type: {type(ccy)=}"
|
|
32
|
+
)
|
|
33
|
+
try:
|
|
34
|
+
if isinstance(ccy, str):
|
|
35
|
+
ccy = Ccy(ccy)
|
|
36
|
+
except ValueError:
|
|
37
|
+
raise InvalidCurrencyException(ccy=ccy)
|
|
38
|
+
ccys[i] = ccy
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _parse_fx_json(json_) -> pd.DataFrame:
|
|
42
|
+
return pd.DataFrame(data=json_["rates"]).rename(
|
|
43
|
+
columns={"effectiveDate": "date", "mid": "rate"}
|
|
44
|
+
).drop(columns=["no"], inplace=False)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _get_fx_api_query(ccy: Ccy, start: date, end: date) -> str:
|
|
48
|
+
return (f"https://api.nbp.pl/api/exchangerates"
|
|
49
|
+
f"/rates/a/{ccy.name.lower()}/{start.isoformat()}/"
|
|
50
|
+
f"{end.isoformat()}/")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_fx_rate(
|
|
54
|
+
ccy: Ccy | str,
|
|
55
|
+
start: date,
|
|
56
|
+
end: date
|
|
57
|
+
) -> pd.DataFrame:
|
|
58
|
+
_validate_ccys(ccys=[ccy.upper() if isinstance(ccy, str) else ccy])
|
|
59
|
+
if not isinstance(ccy, Ccy):
|
|
60
|
+
ccy = Ccy(ccy.upper())
|
|
61
|
+
chunks = split_dates_range_into_smaller_chunks(start=start, end=end)
|
|
62
|
+
list_dfs = []
|
|
63
|
+
for start_, end_ in chunks:
|
|
64
|
+
list_dfs.append(
|
|
65
|
+
_parse_fx_json(
|
|
66
|
+
json_=run_web_api_query(
|
|
67
|
+
url=_get_fx_api_query(ccy=ccy, start=start_, end=end_)
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
return pd.concat(
|
|
72
|
+
list_dfs,
|
|
73
|
+
axis=0
|
|
74
|
+
).rename(columns={
|
|
75
|
+
"rate": f"{ccy.name.lower()}pln"
|
|
76
|
+
}, inplace=False).reset_index(
|
|
77
|
+
inplace=False,
|
|
78
|
+
drop=True
|
|
79
|
+
).copy(deep=True)[["date", f"{ccy.name.lower()}pln"]]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_fx_rates(
|
|
83
|
+
ccys: Union[str, Ccy, list[Union[str, Ccy]]],
|
|
84
|
+
start: date,
|
|
85
|
+
end: date,
|
|
86
|
+
fmt: Literal["long", "wide"] = "long",
|
|
87
|
+
fill_nas: bool = True
|
|
88
|
+
) -> pd.DataFrame:
|
|
89
|
+
_validate_start_end_dates(start, end)
|
|
90
|
+
if isinstance(ccys, str) or isinstance(ccys, Ccy):
|
|
91
|
+
ccys = [ccys]
|
|
92
|
+
_validate_ccys(ccys)
|
|
93
|
+
|
|
94
|
+
datas: list[pd.DataFrame] = []
|
|
95
|
+
for ccy in ccys:
|
|
96
|
+
data = get_fx_rate(ccy, start, end)
|
|
97
|
+
if fmt == "long":
|
|
98
|
+
pair_name: str = f"{ccy.name.lower()}pln"
|
|
99
|
+
data["pair"] = pair_name
|
|
100
|
+
data = data.rename(columns={pair_name: "rate"})
|
|
101
|
+
datas.append(data)
|
|
102
|
+
|
|
103
|
+
if fmt == "long":
|
|
104
|
+
return pd.concat(datas, axis=0)
|
|
105
|
+
|
|
106
|
+
data = reduce(lambda x, y: pd.merge(x, y, on="date", how="outer"), datas)
|
|
107
|
+
if fill_nas:
|
|
108
|
+
data = data.ffill(axis=0)
|
|
109
|
+
data = data.bfill(axis=0)
|
|
110
|
+
return data.sort_values(by="date", ascending=True)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_nbp_fx_tables(
|
|
114
|
+
table: Literal["A", "B", "C"],
|
|
115
|
+
start: date,
|
|
116
|
+
end: date
|
|
117
|
+
) -> pd.DataFrame:
|
|
118
|
+
_validate_fx_table_code(code=table)
|
|
119
|
+
_validate_start_end_dates(start, end)
|
|
120
|
+
tables = run_web_api_query(
|
|
121
|
+
url=f"https://api.nbp.pl/api/exchangerates/tables/"
|
|
122
|
+
f"{table}/{start.isoformat()}/{end.isoformat()}/"
|
|
123
|
+
)
|
|
124
|
+
parsed_tables: list[pd.DataFrame] = []
|
|
125
|
+
for table_ in tables:
|
|
126
|
+
rates_data = pd.DataFrame(table_["rates"])
|
|
127
|
+
rates_data["table"] = table_["table"]
|
|
128
|
+
rates_data["no"] = table_["no"]
|
|
129
|
+
rates_data["date"] = datetime.strptime(
|
|
130
|
+
table_["effectiveDate"], "%Y-%m-%d").date()
|
|
131
|
+
parsed_tables.append(rates_data)
|
|
132
|
+
|
|
133
|
+
return pd.concat(
|
|
134
|
+
parsed_tables, axis=0
|
|
135
|
+
).reset_index(drop=True)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from pynbpapi.common import (
|
|
4
|
+
run_web_api_query, split_dates_range_into_smaller_chunks)
|
|
5
|
+
|
|
6
|
+
__all__ = ["get_gold_prices"]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _get_gold_prices_url(start: date, end: date) -> str:
|
|
10
|
+
return (f"https://api.nbp.pl/api/cenyzlota/"
|
|
11
|
+
f"{start.isoformat()}/{end.isoformat()}/")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_gold_prices_chunk(start: date, end: date) -> pd.DataFrame:
|
|
15
|
+
return pd.DataFrame(
|
|
16
|
+
data=run_web_api_query(
|
|
17
|
+
url=_get_gold_prices_url(start=start, end=end)
|
|
18
|
+
)
|
|
19
|
+
).rename(
|
|
20
|
+
columns={"data": "date", "cena": "price_of_1g_of_gold_in_pln"},
|
|
21
|
+
inplace=False
|
|
22
|
+
).copy(deep=True)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_gold_prices(start: date, end: date):
|
|
26
|
+
chunks = split_dates_range_into_smaller_chunks(start=start, end=end)
|
|
27
|
+
dfs = []
|
|
28
|
+
for start_, end_ in chunks:
|
|
29
|
+
dfs.append(_get_gold_prices_chunk(start=start_, end=end_))
|
|
30
|
+
return pd.concat(
|
|
31
|
+
dfs, axis=0
|
|
32
|
+
).reset_index(drop=True, inplace=False).copy(deep=True)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
import xml.etree.ElementTree as ET
|
|
4
|
+
import requests
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
__all__ = ["get_interest_rates_table"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
RATES_NAMES_DICT: dict[str, str] = {
|
|
12
|
+
"dys": "discount_rate", "dep": "deposit_rate", "lom": "lombard_rate",
|
|
13
|
+
"ref": "reference_rate", "red": "rediscount_rate"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def get_interest_rates_table() -> pd.DataFrame:
|
|
18
|
+
xml = load_xml()
|
|
19
|
+
data_dict = parse_xml(xml=xml)
|
|
20
|
+
return data_dict_to_dataframe(data_dict)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_xml() -> str:
|
|
24
|
+
response = requests.get( # noqa
|
|
25
|
+
"https://static.nbp.pl/dane/stopy/stopy_procentowe_archiwum.xml",
|
|
26
|
+
timeout=120
|
|
27
|
+
)
|
|
28
|
+
response_text = response.text
|
|
29
|
+
return response_text[response_text.find("<?xml version"):]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def parse_xml(xml: str):
|
|
33
|
+
tree_root = ET.fromstring(xml) # pylint: disable=E1101
|
|
34
|
+
entries = tree_root.findall("pozycje") # noqa
|
|
35
|
+
data_dict: defaultdict = defaultdict(dict)
|
|
36
|
+
for entry in entries:
|
|
37
|
+
rates_list = []
|
|
38
|
+
for el in entry.findall("pozycja"):
|
|
39
|
+
rates_list.append((el.attrib["id"], el.attrib["oprocentowanie"]))
|
|
40
|
+
data_dict[entry.attrib["obowiazuje_od"]] = dict(rates_list)
|
|
41
|
+
rates_to_keep: list = list(RATES_NAMES_DICT.keys())
|
|
42
|
+
out_dict = {}
|
|
43
|
+
for k in data_dict:
|
|
44
|
+
out_dict[k] = {
|
|
45
|
+
el: float(data_dict[k][el].replace(",", "."))/100
|
|
46
|
+
for el in rates_to_keep if el in data_dict[k].keys()
|
|
47
|
+
}
|
|
48
|
+
for rate in rates_to_keep:
|
|
49
|
+
if rate not in out_dict[k].keys():
|
|
50
|
+
out_dict[k][rate] = np.nan
|
|
51
|
+
return out_dict
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def data_dict_to_dataframe(data_dict: dict) -> pd.DataFrame:
|
|
55
|
+
df = pd.DataFrame.from_dict(data=data_dict, orient="index")
|
|
56
|
+
df.index = pd.Index([datetime.strptime(el, "%Y-%m-%d") for el in df.index])
|
|
57
|
+
df.reset_index(inplace=True, drop=False)
|
|
58
|
+
dict_cols_renaming = {
|
|
59
|
+
**RATES_NAMES_DICT, **{"index": "valid_from_date"}
|
|
60
|
+
}
|
|
61
|
+
df.rename(columns=dict_cols_renaming, inplace=True)
|
|
62
|
+
return df
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pynbpapi"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Tidy downloading of National Bank of Poland interest rates, FX rates and gold price data"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
keywords = [
|
|
8
|
+
"NBP", "FX", "PLN", "gold", "API", "REST-API", "FX-rates", "zloty"
|
|
9
|
+
]
|
|
10
|
+
authors = [
|
|
11
|
+
{name = "Artur Wegrzyn", email = "awegrzyn17@gmail.com" }
|
|
12
|
+
]
|
|
13
|
+
maintainers = [
|
|
14
|
+
{name = "Artur Wegrzyn", email = "awegrzyn17@gmail.com" }
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"pandas",
|
|
18
|
+
"requests",
|
|
19
|
+
"python-dateutil",
|
|
20
|
+
"loguru"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["setuptools>=69.0.3", "wheel"]
|
|
25
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
certifi==2022.12.7
|
|
2
|
+
charset-normalizer==3.1.0
|
|
3
|
+
coverage==7.4.1
|
|
4
|
+
flake8==7.3.0
|
|
5
|
+
idna==3.4
|
|
6
|
+
iniconfig==2.0.0
|
|
7
|
+
loguru==0.7.2
|
|
8
|
+
mccabe==0.7.0
|
|
9
|
+
mypy==1.8.0
|
|
10
|
+
mypy-extensions==1.0.0
|
|
11
|
+
numpy==1.26.4
|
|
12
|
+
packaging==23.2
|
|
13
|
+
pandas==2.0.1
|
|
14
|
+
pandas-stubs==2.2.0.240218
|
|
15
|
+
pluggy==1.4.0
|
|
16
|
+
pycodestyle==2.14.0
|
|
17
|
+
pyflakes==3.4.0
|
|
18
|
+
pytest==8.0.1
|
|
19
|
+
python-dateutil==2.8.2
|
|
20
|
+
pytz==2023.3
|
|
21
|
+
requests==2.31.0
|
|
22
|
+
six==1.16.0
|
|
23
|
+
types-python-dateutil==2.8.19.20240106
|
|
24
|
+
types-pytz==2024.1.0.20240203
|
|
25
|
+
types-requests==2.31.0.20240218
|
|
26
|
+
typing_extensions==4.9.0
|
|
27
|
+
tzdata==2023.3
|
|
28
|
+
urllib3==2.2.1
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from datetime import date, timedelta
|
|
2
|
+
from dateutil.relativedelta import relativedelta
|
|
3
|
+
from pynbpapi.common import (get_default_dates_range,
|
|
4
|
+
split_dates_range_into_smaller_chunks)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_get_default_dates_range():
|
|
8
|
+
start, end = get_default_dates_range()
|
|
9
|
+
assert end == date.today() - timedelta(days=1)
|
|
10
|
+
assert start == end + relativedelta(years=-1) + timedelta(days=1)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_split_dates_range_into_smaller_chunks():
|
|
14
|
+
list_ = split_dates_range_into_smaller_chunks(
|
|
15
|
+
start=date(2019, 1, 1), end=date(2022, 9, 30))
|
|
16
|
+
assert isinstance(list_, list)
|
|
17
|
+
assert len(list_) == 4
|
|
18
|
+
assert list_[0][0] == date(2019, 1, 1)
|
|
19
|
+
assert list_[2][1] == date(2021, 12, 31)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from pynbpapi.fx import get_fx_rate
|
|
4
|
+
from pynbpapi.ccy import Ccy
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_get_fx_rates_for_currency_usd():
|
|
8
|
+
data = get_fx_rate(
|
|
9
|
+
ccy=Ccy.USD, start=date(2021, 3, 13), end=date(2022, 4, 15)
|
|
10
|
+
)
|
|
11
|
+
assert isinstance(data, pd.DataFrame)
|
|
12
|
+
assert data.shape[1] == 2
|
|
13
|
+
assert data.iloc[10, 1] == 3.957
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from pynbpapi.gold import get_gold_prices
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_get_gold_prices():
|
|
8
|
+
data = get_gold_prices(start=date(2017, 8, 3), end=date(2021, 3, 13))
|
|
9
|
+
assert isinstance(data, pd.DataFrame)
|
|
10
|
+
assert np.all(data.columns == ["date", "price_of_1g_of_gold_in_pln"])
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from pynbpapi.interest_rates import get_interest_rates_table
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_df_get_interest_rates_archive():
|
|
7
|
+
data = get_interest_rates_table()
|
|
8
|
+
assert isinstance(data, pd.DataFrame)
|
|
9
|
+
assert data.shape[1] == 6
|
|
10
|
+
assert (np.all(data.columns == [
|
|
11
|
+
'valid_from_date', 'lombard_rate', 'reference_rate',
|
|
12
|
+
'rediscount_rate', 'discount_rate', 'deposit_rate']
|
|
13
|
+
))
|