cbrapi 0.1.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.
- cbrapi-0.1.0/PKG-INFO +169 -0
- cbrapi-0.1.0/README.md +150 -0
- cbrapi-0.1.0/cbrapi/__init__.py +23 -0
- cbrapi-0.1.0/cbrapi/cbr_settings.py +15 -0
- cbrapi-0.1.0/cbrapi/currency.py +177 -0
- cbrapi-0.1.0/cbrapi/helpers.py +147 -0
- cbrapi-0.1.0/cbrapi/metals.py +71 -0
- cbrapi-0.1.0/cbrapi/rates.py +171 -0
- cbrapi-0.1.0/cbrapi/reserves.py +81 -0
- cbrapi-0.1.0/cbrapi/ruonia.py +257 -0
- cbrapi-0.1.0/pyproject.toml +25 -0
cbrapi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: cbrapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python interface for Central Bank of Russia (CBR) API
|
|
5
|
+
Author: AAARRRT
|
|
6
|
+
Author-email: artiomsalazov@gmail.com
|
|
7
|
+
Requires-Python: >=3.10,<4.0.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Requires-Dist: lxml
|
|
14
|
+
Requires-Dist: pandas (>=2.3.2,<3.0.0)
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Requires-Dist: suds-py3
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
[](https://www.python.org/)
|
|
21
|
+
[](https://pypi.org/project/okama/)
|
|
22
|
+
[](https://opensource.org/licenses/MIT)
|
|
23
|
+
[](https://pepy.tech/project/cbr-api)
|
|
24
|
+
[](https://github.com/psf/black)
|
|
25
|
+
|
|
26
|
+
# CBRAPI
|
|
27
|
+
|
|
28
|
+
`cbrapi` is a Python client for the Central Bank of Russia's web services.
|
|
29
|
+
|
|
30
|
+
## Table of contents
|
|
31
|
+
|
|
32
|
+
- [CBR-API main features](#cbr-api-main-features)
|
|
33
|
+
- [Core Functions](#core-functions)
|
|
34
|
+
- [CURRENCY](#currency)
|
|
35
|
+
- [METALS](#metals)
|
|
36
|
+
- [RATES](#rates)
|
|
37
|
+
- [RESERVES](#reserves)
|
|
38
|
+
- [RUONIA](#ruonia)
|
|
39
|
+
- [Getting started](#getting-started)
|
|
40
|
+
- [License](#license)
|
|
41
|
+
|
|
42
|
+
## CBRAPI main features
|
|
43
|
+
This client provides structured access to the following key data categories from the CBR:
|
|
44
|
+
- CURRENCY: Official exchange rates of foreign currencies against the Russian Ruble.
|
|
45
|
+
- METALS: Official prices of precious metals.
|
|
46
|
+
- RATES: Key interest rates and interbank lending rates.
|
|
47
|
+
- RESERVES: Data on international reserves and foreign currency liquidity.
|
|
48
|
+
- RUONIA: The Russian Overnight Index Average and related benchmark rates.
|
|
49
|
+
|
|
50
|
+
## Core Functions
|
|
51
|
+
|
|
52
|
+
### CURRENCY
|
|
53
|
+
|
|
54
|
+
#### Get a list of available currencies
|
|
55
|
+
Returns a list of all available currency tickers supported by the API.
|
|
56
|
+
`get_currencies_list()`
|
|
57
|
+
|
|
58
|
+
#### Get an internal CBR currency code for a ticker
|
|
59
|
+
Retrieves the internal CBR currency code for a given currency ticker.
|
|
60
|
+
`get_currency_code(ticker: str)`
|
|
61
|
+
|
|
62
|
+
#### Get currency rate historical data
|
|
63
|
+
Fetches historical exchange rate data for a specified currency and date range.
|
|
64
|
+
`get_time_series(symbol: str, first_date: str, last_date: str, period: str = 'D')`
|
|
65
|
+
|
|
66
|
+
### METALS
|
|
67
|
+
|
|
68
|
+
#### Get precious metals prices time series
|
|
69
|
+
Provides historical prices for precious metals (Gold, Silver, Platinum, Palladium).
|
|
70
|
+
`get_metals_prices(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
71
|
+
|
|
72
|
+
### RATES
|
|
73
|
+
|
|
74
|
+
IBOR: Interbank Offered Rate.
|
|
75
|
+
|
|
76
|
+
#### Get the key rate time series
|
|
77
|
+
Retrieves the historical key rate set by the Central Bank of Russia.
|
|
78
|
+
`get_key_rate(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
79
|
+
|
|
80
|
+
#### Get Interbank Offered Rate and related interbank rates
|
|
81
|
+
Fetches the historical Interbank Offered Rate and related interbank rates.
|
|
82
|
+
`get_ibor(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'M')`
|
|
83
|
+
|
|
84
|
+
### RESERVES
|
|
85
|
+
|
|
86
|
+
MRRF: International Reserves and Foreign Currency Liquidity.
|
|
87
|
+
|
|
88
|
+
#### Get International Reserves and Foreign Currency Liquidity data
|
|
89
|
+
Provides time series data for International Reserves and Foreign Currency Liquidity.
|
|
90
|
+
`get_mrrf(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'M')`
|
|
91
|
+
|
|
92
|
+
### RUONIA
|
|
93
|
+
|
|
94
|
+
RUONIA: Russian Overnight Index Average.
|
|
95
|
+
ROISfix: Russian Overnight Index Swap Fixing.
|
|
96
|
+
|
|
97
|
+
#### Get RUONIA time series data
|
|
98
|
+
Retrieves RUONIA time series data for a specific symbol.
|
|
99
|
+
`get_ruonia_ts(symbol: str, first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
100
|
+
|
|
101
|
+
#### Get RUONIA index and averages time series
|
|
102
|
+
Fetches the historical RUONIA index and averages.
|
|
103
|
+
`get_ruonia_index(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
104
|
+
|
|
105
|
+
#### Get RUONIA overnight value time series
|
|
106
|
+
Provides the historical RUONIA overnight value.
|
|
107
|
+
`get_ruonia_overnight(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
108
|
+
|
|
109
|
+
#### Get ROISfix time series
|
|
110
|
+
Retrieves the historical ROISfix time series data.
|
|
111
|
+
`get_roisfix(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
112
|
+
|
|
113
|
+
## Installation
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pip install cbrapi
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The latest development version can be installed directly from GitHub:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git clone https://github.com/mbk-dev/cbrapi.git
|
|
123
|
+
cd cbrapi
|
|
124
|
+
poetry install
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Getting started
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### 1. Get USD/RUB exchange rate with historical data
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
import cbrapi as cbr
|
|
134
|
+
|
|
135
|
+
usd_rub = cbr.get_currency_rate('USDRUB.CBR', '2024-01-01', '2024-12-31')
|
|
136
|
+
print(usd_rub)
|
|
137
|
+
```
|
|
138
|
+

|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
### 2. Monitor Central Bank's key rate monthly changes
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
key_rate = cbr.get_key_rate('2020-01-01', '2024-12-31', period='M')
|
|
145
|
+
print(key_rate)
|
|
146
|
+
```
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### 3. Track precious metals market trends
|
|
151
|
+
```python
|
|
152
|
+
metals = cbr.get_metals_prices('2024-01-01', '2025-01-31')
|
|
153
|
+
print(metals)
|
|
154
|
+
```
|
|
155
|
+

|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
### 4. Analyze international reserves data
|
|
159
|
+
```python
|
|
160
|
+
reserves = cbr.get_mrrf('2023-01-01', '2024-12-31')
|
|
161
|
+
print(reserves)
|
|
162
|
+
```
|
|
163
|
+

|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
|
169
|
+
|
cbrapi-0.1.0/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
|
|
2
|
+
[](https://www.python.org/)
|
|
3
|
+
[](https://pypi.org/project/okama/)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://pepy.tech/project/cbr-api)
|
|
6
|
+
[](https://github.com/psf/black)
|
|
7
|
+
|
|
8
|
+
# CBRAPI
|
|
9
|
+
|
|
10
|
+
`cbrapi` is a Python client for the Central Bank of Russia's web services.
|
|
11
|
+
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [CBR-API main features](#cbr-api-main-features)
|
|
15
|
+
- [Core Functions](#core-functions)
|
|
16
|
+
- [CURRENCY](#currency)
|
|
17
|
+
- [METALS](#metals)
|
|
18
|
+
- [RATES](#rates)
|
|
19
|
+
- [RESERVES](#reserves)
|
|
20
|
+
- [RUONIA](#ruonia)
|
|
21
|
+
- [Getting started](#getting-started)
|
|
22
|
+
- [License](#license)
|
|
23
|
+
|
|
24
|
+
## CBRAPI main features
|
|
25
|
+
This client provides structured access to the following key data categories from the CBR:
|
|
26
|
+
- CURRENCY: Official exchange rates of foreign currencies against the Russian Ruble.
|
|
27
|
+
- METALS: Official prices of precious metals.
|
|
28
|
+
- RATES: Key interest rates and interbank lending rates.
|
|
29
|
+
- RESERVES: Data on international reserves and foreign currency liquidity.
|
|
30
|
+
- RUONIA: The Russian Overnight Index Average and related benchmark rates.
|
|
31
|
+
|
|
32
|
+
## Core Functions
|
|
33
|
+
|
|
34
|
+
### CURRENCY
|
|
35
|
+
|
|
36
|
+
#### Get a list of available currencies
|
|
37
|
+
Returns a list of all available currency tickers supported by the API.
|
|
38
|
+
`get_currencies_list()`
|
|
39
|
+
|
|
40
|
+
#### Get an internal CBR currency code for a ticker
|
|
41
|
+
Retrieves the internal CBR currency code for a given currency ticker.
|
|
42
|
+
`get_currency_code(ticker: str)`
|
|
43
|
+
|
|
44
|
+
#### Get currency rate historical data
|
|
45
|
+
Fetches historical exchange rate data for a specified currency and date range.
|
|
46
|
+
`get_time_series(symbol: str, first_date: str, last_date: str, period: str = 'D')`
|
|
47
|
+
|
|
48
|
+
### METALS
|
|
49
|
+
|
|
50
|
+
#### Get precious metals prices time series
|
|
51
|
+
Provides historical prices for precious metals (Gold, Silver, Platinum, Palladium).
|
|
52
|
+
`get_metals_prices(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
53
|
+
|
|
54
|
+
### RATES
|
|
55
|
+
|
|
56
|
+
IBOR: Interbank Offered Rate.
|
|
57
|
+
|
|
58
|
+
#### Get the key rate time series
|
|
59
|
+
Retrieves the historical key rate set by the Central Bank of Russia.
|
|
60
|
+
`get_key_rate(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
61
|
+
|
|
62
|
+
#### Get Interbank Offered Rate and related interbank rates
|
|
63
|
+
Fetches the historical Interbank Offered Rate and related interbank rates.
|
|
64
|
+
`get_ibor(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'M')`
|
|
65
|
+
|
|
66
|
+
### RESERVES
|
|
67
|
+
|
|
68
|
+
MRRF: International Reserves and Foreign Currency Liquidity.
|
|
69
|
+
|
|
70
|
+
#### Get International Reserves and Foreign Currency Liquidity data
|
|
71
|
+
Provides time series data for International Reserves and Foreign Currency Liquidity.
|
|
72
|
+
`get_mrrf(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'M')`
|
|
73
|
+
|
|
74
|
+
### RUONIA
|
|
75
|
+
|
|
76
|
+
RUONIA: Russian Overnight Index Average.
|
|
77
|
+
ROISfix: Russian Overnight Index Swap Fixing.
|
|
78
|
+
|
|
79
|
+
#### Get RUONIA time series data
|
|
80
|
+
Retrieves RUONIA time series data for a specific symbol.
|
|
81
|
+
`get_ruonia_ts(symbol: str, first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
82
|
+
|
|
83
|
+
#### Get RUONIA index and averages time series
|
|
84
|
+
Fetches the historical RUONIA index and averages.
|
|
85
|
+
`get_ruonia_index(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
86
|
+
|
|
87
|
+
#### Get RUONIA overnight value time series
|
|
88
|
+
Provides the historical RUONIA overnight value.
|
|
89
|
+
`get_ruonia_overnight(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
90
|
+
|
|
91
|
+
#### Get ROISfix time series
|
|
92
|
+
Retrieves the historical ROISfix time series data.
|
|
93
|
+
`get_roisfix(first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = 'D')`
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install cbrapi
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The latest development version can be installed directly from GitHub:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/mbk-dev/cbrapi.git
|
|
105
|
+
cd cbrapi
|
|
106
|
+
poetry install
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Getting started
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
### 1. Get USD/RUB exchange rate with historical data
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import cbrapi as cbr
|
|
116
|
+
|
|
117
|
+
usd_rub = cbr.get_currency_rate('USDRUB.CBR', '2024-01-01', '2024-12-31')
|
|
118
|
+
print(usd_rub)
|
|
119
|
+
```
|
|
120
|
+

|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### 2. Monitor Central Bank's key rate monthly changes
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
key_rate = cbr.get_key_rate('2020-01-01', '2024-12-31', period='M')
|
|
127
|
+
print(key_rate)
|
|
128
|
+
```
|
|
129
|
+

|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
### 3. Track precious metals market trends
|
|
133
|
+
```python
|
|
134
|
+
metals = cbr.get_metals_prices('2024-01-01', '2025-01-31')
|
|
135
|
+
print(metals)
|
|
136
|
+
```
|
|
137
|
+

|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
### 4. Analyze international reserves data
|
|
141
|
+
```python
|
|
142
|
+
reserves = cbr.get_mrrf('2023-01-01', '2024-12-31')
|
|
143
|
+
print(reserves)
|
|
144
|
+
```
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
MIT
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
5
|
+
from cbrapi.currency import get_currencies_list, get_currency_code, get_time_series
|
|
6
|
+
from cbrapi.helpers import (
|
|
7
|
+
pad_missing_periods,
|
|
8
|
+
calculate_inverse_rate,
|
|
9
|
+
normalize_data,
|
|
10
|
+
guess_date,
|
|
11
|
+
)
|
|
12
|
+
from cbrapi.ruonia import (
|
|
13
|
+
get_ruonia_ts,
|
|
14
|
+
get_ruonia_index,
|
|
15
|
+
get_ruonia_overnight,
|
|
16
|
+
get_roisfix,
|
|
17
|
+
)
|
|
18
|
+
from cbrapi.rates import get_key_rate, get_ibor
|
|
19
|
+
from cbrapi.metals import get_metals_prices
|
|
20
|
+
from cbrapi.reserves import get_mrrf
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# __version__ = version("cbr")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from suds.client import Client
|
|
2
|
+
from suds.xsd.doctor import Import, ImportDoctor
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def make_cbr_client():
|
|
6
|
+
global cbr_client
|
|
7
|
+
imp = Import("http://www.w3.org/2001/XMLSchema") # the schema to import
|
|
8
|
+
imp.filter.add("http://web.cbr.ru/") # the schema to import into
|
|
9
|
+
d = ImportDoctor(imp)
|
|
10
|
+
return Client(
|
|
11
|
+
"http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl",
|
|
12
|
+
doctor=d,
|
|
13
|
+
retxml=True,
|
|
14
|
+
headers={"User-Agent": "Mozilla"},
|
|
15
|
+
)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from datetime import datetime, date
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
8
|
+
from cbrapi.helpers import (
|
|
9
|
+
normalize_data,
|
|
10
|
+
guess_date,
|
|
11
|
+
pad_missing_periods,
|
|
12
|
+
calculate_inverse_rate,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
today = date.today()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_currencies_list() -> pd.DataFrame:
|
|
20
|
+
"""
|
|
21
|
+
Get a list of available currencies from CBR.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
pd.DataFrame
|
|
26
|
+
Combined dataframe with all available currencies for daily and monthly frequencies.
|
|
27
|
+
Contains currency codes, character codes, names, and metadata.
|
|
28
|
+
|
|
29
|
+
Notes
|
|
30
|
+
-----
|
|
31
|
+
The function retrieves two separate lists:
|
|
32
|
+
- Currencies with DAILY time series data
|
|
33
|
+
- Currencies with MONTHLY time series data
|
|
34
|
+
Returns a combined dataframe with all available currencies.
|
|
35
|
+
|
|
36
|
+
Examples
|
|
37
|
+
--------
|
|
38
|
+
>>> get_currencies_list()
|
|
39
|
+
"""
|
|
40
|
+
cbr_client = make_cbr_client()
|
|
41
|
+
# get currency table with DAILY time series
|
|
42
|
+
currencies_daily_xml = cbr_client.service.EnumValutesXML(False)
|
|
43
|
+
df_daily = pd.read_xml(currencies_daily_xml, xpath="//EnumValutes")
|
|
44
|
+
|
|
45
|
+
# get currency table with MONTHLY time series
|
|
46
|
+
currencies_monthly_xml = cbr_client.service.EnumValutesXML(True)
|
|
47
|
+
df_monthly = pd.read_xml(currencies_monthly_xml, xpath="//EnumValutes")
|
|
48
|
+
return pd.concat([df_daily, df_monthly], axis=0, join="outer", copy="false")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def get_currency_code(ticker: str) -> str:
|
|
52
|
+
"""
|
|
53
|
+
Return an internal CBR currency code for a ticker.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
ticker : str
|
|
58
|
+
Currency ticker in format 'CCY1CCY2.CBR' (e.g., 'USDRUB.CBR')
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
str
|
|
63
|
+
Internal CBR currency code (e.g., 'R01235')
|
|
64
|
+
|
|
65
|
+
Raises
|
|
66
|
+
------
|
|
67
|
+
ValueError
|
|
68
|
+
If the currency ticker is not found in the CBR database.
|
|
69
|
+
|
|
70
|
+
Notes
|
|
71
|
+
-----
|
|
72
|
+
Handles cases where multiple currency codes might exist for the same ticker
|
|
73
|
+
by selecting the first available option.
|
|
74
|
+
|
|
75
|
+
Examples
|
|
76
|
+
--------
|
|
77
|
+
>>> get_currency_code('USDRUB.CBR')
|
|
78
|
+
'R01235'
|
|
79
|
+
"""
|
|
80
|
+
cbr_symbol = ticker[:3]
|
|
81
|
+
currencies_list = get_currencies_list()
|
|
82
|
+
# Some tickers has 2 Vcode in CBR database. ILS - "Израильский шекель" and "Новый израильский шекель"
|
|
83
|
+
# First row is taken with .iloc
|
|
84
|
+
row = (
|
|
85
|
+
currencies_list[currencies_list["VcharCode"] == cbr_symbol].iloc[0, :].squeeze()
|
|
86
|
+
)
|
|
87
|
+
try:
|
|
88
|
+
code = row.loc["Vcode"]
|
|
89
|
+
except KeyError as e:
|
|
90
|
+
raise ValueError(f"There is no {ticker} in CBR database.") from e
|
|
91
|
+
return code
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_time_series(
|
|
95
|
+
symbol: str, first_date: str, last_date: str, period: str = "D"
|
|
96
|
+
) -> pd.Series:
|
|
97
|
+
"""
|
|
98
|
+
Get currency rate historical data from CBR.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
symbol : str
|
|
103
|
+
Currency pair symbol in format 'CCY1CCY2.CBR' (e.g., 'USDRUB.CBR')
|
|
104
|
+
first_date : str
|
|
105
|
+
Start date in format 'YYYY-MM-DD' or 'YYYY-MM'
|
|
106
|
+
last_date : str
|
|
107
|
+
End date in format 'YYYY-MM-DD' or 'YYYY-MM'
|
|
108
|
+
period : {'D', 'M'}, default 'D'
|
|
109
|
+
Data frequency: 'D' for daily, 'M' for monthly
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
pd.Series
|
|
114
|
+
Time series of currency exchange rates with datetime index.
|
|
115
|
+
|
|
116
|
+
Raises
|
|
117
|
+
------
|
|
118
|
+
ValueError
|
|
119
|
+
If the CBR data format has changed unexpectedly.
|
|
120
|
+
If date format is invalid.
|
|
121
|
+
If currency symbol is not found.
|
|
122
|
+
|
|
123
|
+
Notes
|
|
124
|
+
-----
|
|
125
|
+
- Supports both direct and inverse rate calculations
|
|
126
|
+
- Handles data normalization and missing period padding
|
|
127
|
+
- Performs resampling for different frequencies
|
|
128
|
+
- Some tickers may return empty data if not available
|
|
129
|
+
|
|
130
|
+
Examples
|
|
131
|
+
--------
|
|
132
|
+
>>> get_time_series('USDRUB.CBR', '2023-01-01', '2023-12-31', 'D')
|
|
133
|
+
>>> get_time_series('EURUSD.CBR', '2023-01', '2023-12', 'M')
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
data1 = datetime.strptime(first_date, "%Y-%m-%d")
|
|
137
|
+
data2 = datetime.strptime(last_date, "%Y-%m-%d")
|
|
138
|
+
except ValueError:
|
|
139
|
+
data1 = datetime.strptime(first_date, "%Y-%m")
|
|
140
|
+
data2 = datetime.strptime(last_date, "%Y-%m")
|
|
141
|
+
symbol = symbol.upper()
|
|
142
|
+
if re.match("RUB", symbol):
|
|
143
|
+
foreign_ccy = re.search(r"^RUB(.*).CBR$", symbol)[1]
|
|
144
|
+
query_symbol = foreign_ccy + "RUB.CBR"
|
|
145
|
+
method = "inverse"
|
|
146
|
+
else:
|
|
147
|
+
query_symbol = symbol
|
|
148
|
+
method = "direct"
|
|
149
|
+
code = get_currency_code(query_symbol)
|
|
150
|
+
cbr_client = make_cbr_client()
|
|
151
|
+
rate_xml = cbr_client.service.GetCursDynamic(data1, data2, code)
|
|
152
|
+
try:
|
|
153
|
+
df = pd.read_xml(rate_xml, xpath="//ValuteCursDynamic")
|
|
154
|
+
except ValueError:
|
|
155
|
+
return pd.Series()
|
|
156
|
+
cbr_cols1 = {"rowOrder", "id", "Vnom", "Vcode", "CursDate", "Vcurs"}
|
|
157
|
+
cbr_cols2 = cbr_cols1.union({"VunitRate"})
|
|
158
|
+
if set(df.columns) not in [cbr_cols1, cbr_cols2]:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"CBR data has different columns. Probably data format is changed."
|
|
161
|
+
)
|
|
162
|
+
df.drop(columns=["id", "rowOrder", "Vcode"], inplace=True)
|
|
163
|
+
if "VunitRate" in list(df.columns):
|
|
164
|
+
df.drop(columns=["VunitRate"], inplace=True)
|
|
165
|
+
df["Vcurs"] /= df["Vnom"]
|
|
166
|
+
df.drop(columns=["Vnom"], inplace=True)
|
|
167
|
+
df = df.astype({"CursDate": "period[D]"}, copy=False)
|
|
168
|
+
df = df.astype({"Vcurs": "float"}, copy=False)
|
|
169
|
+
df.set_index("CursDate", inplace=True, verify_integrity=True)
|
|
170
|
+
df.sort_index(ascending=True, inplace=True)
|
|
171
|
+
s = df.squeeze(axis=1) # all outputs must be pd.Series
|
|
172
|
+
s = pad_missing_periods(s, freq="D")
|
|
173
|
+
s.index.rename("date", inplace=True)
|
|
174
|
+
if period.upper() == "M":
|
|
175
|
+
s = s.resample("M").last()
|
|
176
|
+
s = calculate_inverse_rate(s) if method == "inverse" else s
|
|
177
|
+
return s.rename(symbol)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from datetime import datetime, date
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def pad_missing_periods(
|
|
7
|
+
ts: Union[pd.Series, pd.DataFrame], freq: str = "D"
|
|
8
|
+
) -> Union[pd.Series, pd.DataFrame]:
|
|
9
|
+
"""
|
|
10
|
+
Pad missing dates and values in the time series.
|
|
11
|
+
"""
|
|
12
|
+
name = ts.index.name
|
|
13
|
+
if not isinstance(ts.index, pd.PeriodIndex):
|
|
14
|
+
ts.index = ts.index.to_period(freq)
|
|
15
|
+
ts.sort_index(
|
|
16
|
+
ascending=True, inplace=True
|
|
17
|
+
) # The order should be ascending to make new Period index
|
|
18
|
+
idx = pd.period_range(start=ts.index[0], end=ts.index[-1], freq=freq)
|
|
19
|
+
ts = ts.reindex(idx, method="pad")
|
|
20
|
+
ts.index.rename(name, inplace=True)
|
|
21
|
+
return ts
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def calculate_inverse_rate(close_ts):
|
|
25
|
+
"""
|
|
26
|
+
Inverse close values for currency rate data.
|
|
27
|
+
"""
|
|
28
|
+
return 1.0 / close_ts
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def set_datetime_index(data):
|
|
32
|
+
"""
|
|
33
|
+
Set datetime index for DataFrame by detecting date columns.
|
|
34
|
+
"""
|
|
35
|
+
if not isinstance(data.index, pd.DatetimeIndex):
|
|
36
|
+
for col in data.columns:
|
|
37
|
+
if any(keyword in str(col) for keyword in ["CDate", "DateMet", "D0", "DT"]):
|
|
38
|
+
data[col].str.split("T").str[0]
|
|
39
|
+
data.index = pd.DatetimeIndex(
|
|
40
|
+
pd.to_datetime(data[col], utc=True)
|
|
41
|
+
).tz_convert(None)
|
|
42
|
+
data.index.name = "DATE"
|
|
43
|
+
data.drop(col, axis=1, inplace=True)
|
|
44
|
+
break
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def remove_unnecessary_columns(data):
|
|
49
|
+
"""
|
|
50
|
+
Remove unnecessary columns from DataFrame.
|
|
51
|
+
"""
|
|
52
|
+
data.drop(
|
|
53
|
+
columns=[
|
|
54
|
+
col
|
|
55
|
+
for col in ["id", "rowOrder", "vol", "DateUpdate"]
|
|
56
|
+
if col in data.columns
|
|
57
|
+
],
|
|
58
|
+
inplace=True,
|
|
59
|
+
)
|
|
60
|
+
return data
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def unstack_groups(data, symbol):
|
|
64
|
+
"""
|
|
65
|
+
Unstack grouped data based on symbol type.
|
|
66
|
+
"""
|
|
67
|
+
if symbol == "DrgMet":
|
|
68
|
+
data = data.groupby([data.index, "CodMet"])["price"].first().unstack()
|
|
69
|
+
data.columns.name = None
|
|
70
|
+
|
|
71
|
+
if symbol == "MKR":
|
|
72
|
+
data = (
|
|
73
|
+
data.groupby([data.index, "p1"])[["d1", "d7", "d30", "d90", "d180", "d360"]]
|
|
74
|
+
.first()
|
|
75
|
+
.unstack(level="p1")
|
|
76
|
+
)
|
|
77
|
+
data.columns = data.columns.rename(None, level=1)
|
|
78
|
+
data.columns.name = None
|
|
79
|
+
|
|
80
|
+
return data
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def column_rename(data, level_0, level_1):
|
|
84
|
+
"""
|
|
85
|
+
Rename columns based on mapping dictionaries.
|
|
86
|
+
"""
|
|
87
|
+
if isinstance(data.columns, pd.MultiIndex):
|
|
88
|
+
if level_0:
|
|
89
|
+
new_level_0 = data.columns.levels[0].map(lambda x: level_0.get(str(x), x))
|
|
90
|
+
data.columns = data.columns.set_levels(new_level_0, level=0)
|
|
91
|
+
|
|
92
|
+
if level_1:
|
|
93
|
+
new_level_1 = data.columns.levels[1].map(lambda x: level_1.get(str(x), x))
|
|
94
|
+
data.columns = data.columns.set_levels(new_level_1, level=1)
|
|
95
|
+
|
|
96
|
+
else:
|
|
97
|
+
if level_1 and isinstance(level_1, dict):
|
|
98
|
+
data = data.rename(columns=level_1)
|
|
99
|
+
available_columns = [col for col in level_1.values() if col in data.columns]
|
|
100
|
+
data = data[available_columns] if available_columns else data
|
|
101
|
+
|
|
102
|
+
else:
|
|
103
|
+
if level_1 and not isinstance(level_1, dict):
|
|
104
|
+
if len(data.columns) == 1:
|
|
105
|
+
data = data.rename(columns={data.columns[0]: str(level_1)})
|
|
106
|
+
return data
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def normalize_data(data, period, level_0=None, level_1=None, symbol=None):
|
|
110
|
+
"""
|
|
111
|
+
Normalize time series data through multiple processing steps.
|
|
112
|
+
"""
|
|
113
|
+
if isinstance(data, pd.Series):
|
|
114
|
+
data = data.to_frame()
|
|
115
|
+
|
|
116
|
+
set_datetime_index(data)
|
|
117
|
+
|
|
118
|
+
remove_unnecessary_columns(data)
|
|
119
|
+
|
|
120
|
+
data = unstack_groups(data, symbol)
|
|
121
|
+
|
|
122
|
+
data = column_rename(data, level_0, level_1)
|
|
123
|
+
|
|
124
|
+
data = pad_missing_periods(data)
|
|
125
|
+
|
|
126
|
+
if period.upper() == "M":
|
|
127
|
+
data = data.resample("M").last()
|
|
128
|
+
|
|
129
|
+
if len(data.columns) == 1:
|
|
130
|
+
data = data.squeeze()
|
|
131
|
+
|
|
132
|
+
return data
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def guess_date(input_date, default_value):
|
|
136
|
+
"""
|
|
137
|
+
Create data in datetime format.
|
|
138
|
+
CBR accepts "%Y-%m-%d" format only.
|
|
139
|
+
"""
|
|
140
|
+
if input_date:
|
|
141
|
+
try:
|
|
142
|
+
date = datetime.strptime(input_date, "%Y-%m-%d")
|
|
143
|
+
except ValueError:
|
|
144
|
+
date = datetime.strptime(input_date, "%Y-%m")
|
|
145
|
+
else:
|
|
146
|
+
date = datetime.strptime(default_value, "%Y-%m-%d")
|
|
147
|
+
return date
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
7
|
+
from cbrapi.helpers import normalize_data, guess_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
today = date.today()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_metals_prices(
|
|
14
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "D"
|
|
15
|
+
) -> pd.DataFrame:
|
|
16
|
+
"""
|
|
17
|
+
Get precious metals prices time series from CBR.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
first_date : str, optional
|
|
22
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
23
|
+
'1999-10-01'.
|
|
24
|
+
|
|
25
|
+
last_date : str, optional
|
|
26
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
27
|
+
current date.
|
|
28
|
+
|
|
29
|
+
period : {'D'}, default 'D'
|
|
30
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
pd.DataFrame
|
|
35
|
+
DataFrame with datetime index and the following columns:
|
|
36
|
+
- GOLD : Gold price (RUB per gram)
|
|
37
|
+
- SILVER : Silver price (RUB per gram)
|
|
38
|
+
- PLATINUM : Platinum price (RUB per gram)
|
|
39
|
+
- PALLADIUM : Palladium price (RUB per gram)
|
|
40
|
+
|
|
41
|
+
Notes
|
|
42
|
+
-----
|
|
43
|
+
Prices are provided in Russian Rubles per gram.
|
|
44
|
+
Data is available from October 1999.
|
|
45
|
+
|
|
46
|
+
Examples
|
|
47
|
+
--------
|
|
48
|
+
>>> get_metals_prices('2023-01-01', '2023-12-31')
|
|
49
|
+
>>> get_metals_prices(period='M')
|
|
50
|
+
"""
|
|
51
|
+
cbr_client = make_cbr_client()
|
|
52
|
+
data1 = guess_date(first_date, default_value="1999-10-01")
|
|
53
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
54
|
+
metals_xml = cbr_client.service.DragMetDynamic(data1, data2)
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
df = pd.read_xml(metals_xml, xpath=".//DrgMet")
|
|
58
|
+
except ValueError:
|
|
59
|
+
return pd.Series()
|
|
60
|
+
|
|
61
|
+
level_1_column_mapping = {
|
|
62
|
+
1: "GOLD",
|
|
63
|
+
2: "SILVER",
|
|
64
|
+
3: "PLATINUM",
|
|
65
|
+
4: "PALLADIUM",
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
df = normalize_data(
|
|
69
|
+
data=df, period=period, symbol="DrgMet", level_1=level_1_column_mapping
|
|
70
|
+
)
|
|
71
|
+
return df
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
7
|
+
from cbrapi.helpers import normalize_data, guess_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
today = date.today()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_key_rate(
|
|
14
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "D"
|
|
15
|
+
) -> pd.Series:
|
|
16
|
+
"""
|
|
17
|
+
Get the key rate time series from CBR.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
first_date : str, optional
|
|
22
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
23
|
+
'2013-09-13'.
|
|
24
|
+
|
|
25
|
+
last_date : str, optional
|
|
26
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
27
|
+
current date.
|
|
28
|
+
|
|
29
|
+
period : {'D'}, default 'D'
|
|
30
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
pd.Series
|
|
35
|
+
Time series of key rate values with datetime index.
|
|
36
|
+
Rates are returned as decimals (e.g., 0.075 for 7.5%).
|
|
37
|
+
|
|
38
|
+
Notes
|
|
39
|
+
-----
|
|
40
|
+
The key rate is the main instrument of the Bank of Russia's monetary policy.
|
|
41
|
+
It influences interest rates in the economy and is used for liquidity provision
|
|
42
|
+
and absorption operations.
|
|
43
|
+
|
|
44
|
+
Examples
|
|
45
|
+
--------
|
|
46
|
+
>>> get_key_rate('2023-01-01', '2023-12-31')
|
|
47
|
+
>>> get_key_rate(period='D')
|
|
48
|
+
"""
|
|
49
|
+
cbr_client = make_cbr_client()
|
|
50
|
+
data1 = guess_date(first_date, default_value="2013-09-13")
|
|
51
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
52
|
+
key_rate_xml = cbr_client.service.KeyRate(data1, data2)
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
df = pd.read_xml(key_rate_xml, xpath=".//KR")
|
|
56
|
+
except ValueError:
|
|
57
|
+
return pd.Series()
|
|
58
|
+
|
|
59
|
+
level_1_column_mapping = {"Rate": "KEY_RATE"}
|
|
60
|
+
|
|
61
|
+
df = normalize_data(
|
|
62
|
+
data=df, period=period, symbol="KEY_RATE", level_1=level_1_column_mapping
|
|
63
|
+
)
|
|
64
|
+
return df
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_ibor(
|
|
68
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "M"
|
|
69
|
+
) -> pd.DataFrame:
|
|
70
|
+
"""
|
|
71
|
+
Get Interbank Offered Rate and related interbank rates from CBR.
|
|
72
|
+
|
|
73
|
+
Parameters
|
|
74
|
+
----------
|
|
75
|
+
first_date : str, optional
|
|
76
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
77
|
+
'2013-09-13'.
|
|
78
|
+
|
|
79
|
+
last_date : str, optional
|
|
80
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
81
|
+
current date.
|
|
82
|
+
|
|
83
|
+
period : {'M'}, default 'M'
|
|
84
|
+
Data periodicity. Currently only monthly ('M') frequency is supported.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
pd.DataFrame
|
|
89
|
+
Multi-level DataFrame with datetime index containing interbank rates.
|
|
90
|
+
First level columns represent tenors, second level represents rate types:
|
|
91
|
+
|
|
92
|
+
Available loan terms:
|
|
93
|
+
- D1 : 1 day
|
|
94
|
+
- D7 : 7 days
|
|
95
|
+
- D30 : 30 days
|
|
96
|
+
- D180 : 180 days
|
|
97
|
+
- D360 : 360 days
|
|
98
|
+
|
|
99
|
+
Rate types include:
|
|
100
|
+
- MIBID_RUB : Moscow Interbank Bid Rate (RUB)
|
|
101
|
+
- MIBOR_RUB : Moscow Interbank Offered Rate (RUB)
|
|
102
|
+
- MIACR_RUB : Moscow Interbank Actual Credit Rate (RUB)
|
|
103
|
+
- MIACR_IG_RUB : MIACR for investment grade (RUB)
|
|
104
|
+
- MIACR_RUB_TURNOVER : MIACR turnover (RUB)
|
|
105
|
+
- MIACR_IG_RUB_TURNOVER : MIACR IG turnover (RUB)
|
|
106
|
+
- MIACR_B_RUB : MIACR for banks (RUB)
|
|
107
|
+
- MIACR_B_RUB_TURNOVER : MIACR banks turnover (RUB)
|
|
108
|
+
- MIBID_USD : Moscow Interbank Bid Rate (USD)
|
|
109
|
+
- MIBOR_USD : Moscow Interbank Offered Rate (USD)
|
|
110
|
+
- MIACR_USD : Moscow Interbank Actual Credit Rate (USD)
|
|
111
|
+
- MIACR_IG_USD : MIACR for investment grade (USD)
|
|
112
|
+
- MIACR_USD_TURNOVER : MIACR turnover (USD)
|
|
113
|
+
- MIACR_IG_USD_TURNOVER : MIACR IG turnover (USD)
|
|
114
|
+
- MIACR_B_USD : MIACR for banks (USD)
|
|
115
|
+
- MIACR_B_USD_TURNOVER : MIACR banks turnover (USD)
|
|
116
|
+
|
|
117
|
+
Notes
|
|
118
|
+
-----
|
|
119
|
+
All rates are returned as decimals (e.g., 0.05 for 5%).
|
|
120
|
+
Turnover values represent trading volumes.
|
|
121
|
+
|
|
122
|
+
Examples
|
|
123
|
+
--------
|
|
124
|
+
>>> get_ibor('2023-01-01', '2023-12-31')
|
|
125
|
+
>>> get_ibor(period='M')
|
|
126
|
+
"""
|
|
127
|
+
cbr_client = make_cbr_client()
|
|
128
|
+
data1 = guess_date(first_date, default_value="2013-09-13")
|
|
129
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
130
|
+
mkr_xml = cbr_client.service.MKR(data1, data2)
|
|
131
|
+
|
|
132
|
+
try:
|
|
133
|
+
df = pd.read_xml(mkr_xml, xpath=".//MKR")
|
|
134
|
+
except ValueError:
|
|
135
|
+
return pd.Series()
|
|
136
|
+
|
|
137
|
+
level_0_column_mapping = {
|
|
138
|
+
"d1": "D1",
|
|
139
|
+
"d7": "D7",
|
|
140
|
+
"d30": "D30",
|
|
141
|
+
"d180": "D180",
|
|
142
|
+
"d360": "D360",
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
level_1_column_mapping = {
|
|
146
|
+
"1": "MIBID_RUB",
|
|
147
|
+
"2": "MIBOR_RUB",
|
|
148
|
+
"3": "MIACR_RUB",
|
|
149
|
+
"4": "MIACR_IG_RUB",
|
|
150
|
+
"5": "MIACR_RUB_TURNOVER",
|
|
151
|
+
"6": "MIACR_IG_RUB_TURNOVER",
|
|
152
|
+
"7": "MIACR_B_RUB",
|
|
153
|
+
"8": "MIACR_B_RUB_TURNOVER",
|
|
154
|
+
"9": "MIBID_USD",
|
|
155
|
+
"10": "MIBOR_USD",
|
|
156
|
+
"11": "MIACR_USD",
|
|
157
|
+
"12": "MIACR_IG_USD",
|
|
158
|
+
"13": "MIACR_USD_TURNOVER",
|
|
159
|
+
"14": "MIACR_IG_USD_TURNOVER",
|
|
160
|
+
"15": "MIACR_B_USD",
|
|
161
|
+
"16": "MIACR_B_USD_TURNOVER",
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
df = normalize_data(
|
|
165
|
+
data=df,
|
|
166
|
+
period=period,
|
|
167
|
+
symbol="MKR",
|
|
168
|
+
level_0=level_0_column_mapping,
|
|
169
|
+
level_1=level_1_column_mapping,
|
|
170
|
+
)
|
|
171
|
+
return df
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
7
|
+
from cbrapi.helpers import normalize_data, guess_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
today = date.today()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_mrrf(
|
|
14
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "M"
|
|
15
|
+
) -> pd.DataFrame:
|
|
16
|
+
"""
|
|
17
|
+
Get International Reserves and Foreign Currency Liquidity data from CBR.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
first_date : str, optional
|
|
22
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
23
|
+
'1999-01-01'.
|
|
24
|
+
|
|
25
|
+
last_date : str, optional
|
|
26
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
27
|
+
current date.
|
|
28
|
+
|
|
29
|
+
period : {'M'}, default 'M'
|
|
30
|
+
Data periodicity. Currently only monthly ('M') frequency is supported.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
pd.DataFrame
|
|
35
|
+
DataFrame with datetime index and the following columns:
|
|
36
|
+
- TOTAL_RESERVES : Total international reserves (USD)
|
|
37
|
+
- CURRENCY_RESERVES : Currency reserves (USD)
|
|
38
|
+
- FOREIGN_CURRENCY : Foreign currency holdings (USD)
|
|
39
|
+
- SDR_ACCOUNT : Special Drawing Rights (SDR) account (USD)
|
|
40
|
+
- IMF_RESERVE : Reserve position in IMF (USD)
|
|
41
|
+
- MONETARY_GOLD : Monetary gold holdings (USD)
|
|
42
|
+
|
|
43
|
+
Notes
|
|
44
|
+
-----
|
|
45
|
+
International reserves are external assets that are readily available to and
|
|
46
|
+
controlled by monetary authorities for:
|
|
47
|
+
- Meeting balance of payments financing needs
|
|
48
|
+
- Intervention in exchange markets to affect currency exchange rate
|
|
49
|
+
- Other related purposes
|
|
50
|
+
|
|
51
|
+
All values are reported in US dollars.
|
|
52
|
+
|
|
53
|
+
Examples
|
|
54
|
+
--------
|
|
55
|
+
>>> get_mrrf('2020-01-01', '2023-12-31')
|
|
56
|
+
>>> get_mrrf(period='M')
|
|
57
|
+
"""
|
|
58
|
+
cbr_client = make_cbr_client()
|
|
59
|
+
data1 = guess_date(first_date, default_value="1999-01-01")
|
|
60
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
61
|
+
mrrf_xml = cbr_client.service.mrrf(data1, data2)
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
df = pd.read_xml(mrrf_xml, xpath=".//mr")
|
|
65
|
+
except ValueError:
|
|
66
|
+
return pd.Series()
|
|
67
|
+
|
|
68
|
+
level_1_column_mapping = {
|
|
69
|
+
"p1": "TOTAL_RESERVES",
|
|
70
|
+
"p2": "CURRENCY_RESERVES",
|
|
71
|
+
"p3": "FOREIGN_CURRENCY",
|
|
72
|
+
"p4": "SDR_ACCOUNT",
|
|
73
|
+
"p5": "IMF_RESERVE",
|
|
74
|
+
"p6": "MONETARY_GOLD",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
df = normalize_data(
|
|
78
|
+
data=df, period=period, symbol="mr", level_1=level_1_column_mapping
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return df
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
from datetime import datetime, date
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from cbrapi.cbr_settings import make_cbr_client
|
|
7
|
+
from cbrapi.helpers import normalize_data, guess_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
today = date.today()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_ruonia_ts(
|
|
14
|
+
symbol: str,
|
|
15
|
+
first_date: Optional[str] = None,
|
|
16
|
+
last_date: Optional[str] = None,
|
|
17
|
+
period: str = "D",
|
|
18
|
+
) -> pd.Series:
|
|
19
|
+
"""
|
|
20
|
+
Get RUONIA (Ruble Overnight Index Average) time series data from CBR.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
symbol : str
|
|
25
|
+
Financial instrument symbol. Supported symbols:
|
|
26
|
+
- 'RUONIA.INDX' : RUONIA index
|
|
27
|
+
- 'RUONIA_AVG_1M.RATE' : 1-month average rate
|
|
28
|
+
- 'RUONIA_AVG_3M.RATE' : 3-month average rate
|
|
29
|
+
- 'RUONIA_AVG_6M.RATE' : 6-month average rate
|
|
30
|
+
- Other symbols : return overnight RUONIA rates
|
|
31
|
+
|
|
32
|
+
first_date : str, optional
|
|
33
|
+
Start date in format 'YYYY-MM-DD'. If not specified, returns
|
|
34
|
+
data from the earliest available date.
|
|
35
|
+
|
|
36
|
+
last_date : str, optional
|
|
37
|
+
End date in format 'YYYY-MM-DD'. If not specified, returns
|
|
38
|
+
data up to the most recent available date.
|
|
39
|
+
|
|
40
|
+
period : {'D'}, default 'D'
|
|
41
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
pd.Series
|
|
46
|
+
Time series data for the requested symbol with datetime index.
|
|
47
|
+
Returns empty Series if no data is available for the given parameters.
|
|
48
|
+
|
|
49
|
+
Notes
|
|
50
|
+
-----
|
|
51
|
+
Data is sourced from the Central Bank of Russia (CBR) official statistics.
|
|
52
|
+
The function handles API requests and data parsing from CBR web services.
|
|
53
|
+
|
|
54
|
+
Examples
|
|
55
|
+
--------
|
|
56
|
+
>>> get_ruonia_ts('RUONIA.INDX', '2023-01-01', '2023-12-31')
|
|
57
|
+
>>> get_ruonia_ts('RUONIA_AVG_3M.RATE')
|
|
58
|
+
"""
|
|
59
|
+
cbr_client = make_cbr_client()
|
|
60
|
+
if symbol in [
|
|
61
|
+
"RUONIA.INDX",
|
|
62
|
+
"RUONIA_AVG_1M.RATE",
|
|
63
|
+
"RUONIA_AVG_3M.RATE",
|
|
64
|
+
"RUONIA_AVG_6M.RATE",
|
|
65
|
+
]:
|
|
66
|
+
ticker = (
|
|
67
|
+
symbol.split(".")[0] if symbol.split(".")[1] == "RATE" else "RUONIA_INDEX"
|
|
68
|
+
)
|
|
69
|
+
df = get_ruonia_index(first_date, last_date).loc[:, ticker]
|
|
70
|
+
if symbol != "RUONIA.INDX":
|
|
71
|
+
df /= 100
|
|
72
|
+
return normalize_data(df, period, symbol)
|
|
73
|
+
else:
|
|
74
|
+
return get_ruonia_overnight(first_date, last_date, period)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_ruonia_index(
|
|
78
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "D"
|
|
79
|
+
) -> pd.DataFrame:
|
|
80
|
+
"""
|
|
81
|
+
Get RUONIA index and averages time series from CBR.
|
|
82
|
+
|
|
83
|
+
Parameters
|
|
84
|
+
----------
|
|
85
|
+
first_date : str, optional
|
|
86
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
87
|
+
'2010-01-01'.
|
|
88
|
+
|
|
89
|
+
last_date : str, optional
|
|
90
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
91
|
+
current date.
|
|
92
|
+
|
|
93
|
+
period : {'D'}, default 'D'
|
|
94
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
pd.DataFrame
|
|
99
|
+
DataFrame with datetime index and the following columns:
|
|
100
|
+
- RUONIA_INDEX : RUONIA index value
|
|
101
|
+
- RUONIA_AVG_1M : 1-month average rate (as decimal)
|
|
102
|
+
- RUONIA_AVG_3M : 3-month average rate (as decimal)
|
|
103
|
+
- RUONIA_AVG_6M : 6-month average rate (as decimal)
|
|
104
|
+
|
|
105
|
+
Notes
|
|
106
|
+
-----
|
|
107
|
+
RUONIA (Ruble Overnight Index Average) is the weighted average interest rate
|
|
108
|
+
on interbank loans and deposits. It serves as an indicator of the cost of
|
|
109
|
+
unsecured overnight borrowing.
|
|
110
|
+
|
|
111
|
+
Examples
|
|
112
|
+
--------
|
|
113
|
+
>>> get_ruonia_index('2023-01-01', '2023-12-31')
|
|
114
|
+
>>> get_ruonia_index(period='D')
|
|
115
|
+
"""
|
|
116
|
+
cbr_client = make_cbr_client()
|
|
117
|
+
data1 = guess_date(first_date, default_value="2010-01-01")
|
|
118
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
119
|
+
ruonia_index_xml = cbr_client.service.RuoniaSV(data1, data2)
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
df = pd.read_xml(ruonia_index_xml, xpath=".//ra")
|
|
123
|
+
except ValueError:
|
|
124
|
+
return pd.Series()
|
|
125
|
+
|
|
126
|
+
level_1_column_mapping = {
|
|
127
|
+
"RUONIA_Index": "RUONIA_INDEX",
|
|
128
|
+
"R1W": "RUONIA_AVG_1M",
|
|
129
|
+
"R2W": "RUONIA_AVG_3M",
|
|
130
|
+
"R1M": "RUONIA_AVG_6M",
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
df = normalize_data(
|
|
134
|
+
data=df, period=period, symbol="ra", level_1=level_1_column_mapping
|
|
135
|
+
)
|
|
136
|
+
return df
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def get_ruonia_overnight(
|
|
140
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "D"
|
|
141
|
+
) -> pd.Series:
|
|
142
|
+
"""
|
|
143
|
+
Get RUONIA overnight value time series from CBR.
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
first_date : str, optional
|
|
148
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
149
|
+
'2010-01-01'.
|
|
150
|
+
|
|
151
|
+
last_date : str, optional
|
|
152
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
153
|
+
current date.
|
|
154
|
+
|
|
155
|
+
period : {'D'}, default 'D'
|
|
156
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
pd.Series
|
|
161
|
+
Time series of RUONIA overnight rates with datetime index.
|
|
162
|
+
Rates are returned as decimals (e.g., 0.05 for 5%).
|
|
163
|
+
|
|
164
|
+
Notes
|
|
165
|
+
-----
|
|
166
|
+
RUONIA (Ruble Overnight Index Average) is the weighted average interest rate
|
|
167
|
+
on interbank loans and deposits. It serves as an indicator of the cost of
|
|
168
|
+
unsecured overnight borrowing.
|
|
169
|
+
|
|
170
|
+
Examples
|
|
171
|
+
--------
|
|
172
|
+
>>> get_ruonia_overnight('2023-01-01', '2023-12-31')
|
|
173
|
+
>>> get_ruonia_overnight(period='D')
|
|
174
|
+
"""
|
|
175
|
+
cbr_client = make_cbr_client()
|
|
176
|
+
data1 = guess_date(first_date, default_value="2010-01-01")
|
|
177
|
+
data2 = guess_date(last_date, default_value=str(date.today()))
|
|
178
|
+
ruonia_overnight_xml = cbr_client.service.Ruonia(data1, data2)
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
df = pd.read_xml(ruonia_overnight_xml, xpath="//ro")
|
|
182
|
+
except ValueError:
|
|
183
|
+
return pd.Series()
|
|
184
|
+
|
|
185
|
+
level_1_column_mapping = {
|
|
186
|
+
"ruo": "RUONIA_OVERNIGHT",
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
df = normalize_data(
|
|
190
|
+
data=df, period=period, symbol="ro", level_1=level_1_column_mapping
|
|
191
|
+
)
|
|
192
|
+
df /= 100
|
|
193
|
+
return df
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def get_roisfix(
|
|
197
|
+
first_date: Optional[str] = None, last_date: Optional[str] = None, period: str = "D"
|
|
198
|
+
) -> pd.DataFrame:
|
|
199
|
+
"""
|
|
200
|
+
Get ROISfix (Ruble Overnight Index Swap Fixing) time series from CBR.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
first_date : str, optional
|
|
205
|
+
Start date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
206
|
+
'2011-04-15'.
|
|
207
|
+
|
|
208
|
+
last_date : str, optional
|
|
209
|
+
End date in format 'YYYY-MM-DD'. If not specified, defaults to
|
|
210
|
+
current date.
|
|
211
|
+
|
|
212
|
+
period : {'D'}, default 'D'
|
|
213
|
+
Data periodicity. Currently only daily ('D') frequency is supported.
|
|
214
|
+
|
|
215
|
+
Returns
|
|
216
|
+
-------
|
|
217
|
+
pd.DataFrame
|
|
218
|
+
DataFrame with datetime index and the following columns:
|
|
219
|
+
- RATE_1_WEEK : 1-week ROISfix rate (as decimal)
|
|
220
|
+
- RATE_2_WEEK : 2-week ROISfix rate (as decimal)
|
|
221
|
+
- RATE_1_MONTH : 1-month ROISfix rate (as decimal)
|
|
222
|
+
- RATE_2_MONTH : 2-month ROISfix rate (as decimal)
|
|
223
|
+
- RATE_3_MONTH : 3-month ROISfix rate (as decimal)
|
|
224
|
+
- RATE_6_MONTH : 6-month ROISfix rate (as decimal)
|
|
225
|
+
|
|
226
|
+
Notes
|
|
227
|
+
-----
|
|
228
|
+
ROISfix represents the fixed rate in ruble overnight index swaps.
|
|
229
|
+
|
|
230
|
+
Examples
|
|
231
|
+
--------
|
|
232
|
+
>>> get_roisfix('2023-01-01', '2023-12-31')
|
|
233
|
+
>>> get_roisfix(period='D')
|
|
234
|
+
"""
|
|
235
|
+
cbr_client = make_cbr_client()
|
|
236
|
+
data1 = guess_date(first_date, default_value="2011-04-15")
|
|
237
|
+
data2 = guess_date(last_date, default_value=str(today))
|
|
238
|
+
roisfix_xml = cbr_client.service.ROISfix(data1, data2)
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
df = pd.read_xml(roisfix_xml, xpath=".//rf")
|
|
242
|
+
except ValueError:
|
|
243
|
+
return pd.Series()
|
|
244
|
+
|
|
245
|
+
level_1_column_mapping = {
|
|
246
|
+
"R1W": "RATE_1_WEEK",
|
|
247
|
+
"R2W": "RATE_2_WEEK",
|
|
248
|
+
"R1M": "RATE_1_MONTH",
|
|
249
|
+
"R2M": "RATE_2_MONTH",
|
|
250
|
+
"R3M": "RATE_3_MONTH",
|
|
251
|
+
"R6M": "RATE_6_MONTH",
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
df = normalize_data(
|
|
255
|
+
data=df, period=period, symbol="rf", level_1=level_1_column_mapping
|
|
256
|
+
)
|
|
257
|
+
return df
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "cbrapi"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Python interface for Central Bank of Russia (CBR) API"
|
|
5
|
+
authors = [
|
|
6
|
+
"AAARRRT <artiomsalazov@gmail.com>",
|
|
7
|
+
"MBK Development LLC <info@rostsber.ru>"
|
|
8
|
+
]
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[tool.poetry.dependencies]
|
|
12
|
+
python = ">=3.10,<4.0.0"
|
|
13
|
+
pandas = "^2.3.2"
|
|
14
|
+
requests = "*"
|
|
15
|
+
suds-py3 = "*"
|
|
16
|
+
lxml = "*"
|
|
17
|
+
|
|
18
|
+
[tool.poetry.group.dev.dependencies]
|
|
19
|
+
black = "^25.1.0"
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["poetry-core"]
|
|
23
|
+
build-backend = "poetry.core.masonry.api"
|
|
24
|
+
|
|
25
|
+
|