PYield 0.7.3__tar.gz → 0.7.5__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.
- {pyield-0.7.3 → pyield-0.7.5}/PKG-INFO +53 -26
- {pyield-0.7.3 → pyield-0.7.5}/README.md +51 -25
- pyield-0.7.5/pyield/__about__.py +1 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/__init__.py +2 -1
- pyield-0.7.5/pyield/data_access.py +148 -0
- pyield-0.7.5/pyield/futures/__init__.py +13 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/futures/common.py +7 -5
- {pyield-0.7.3 → pyield-0.7.5}/pyield/futures/ddi.py +7 -44
- {pyield-0.7.3 → pyield-0.7.5}/pyield/futures/di.py +19 -38
- pyield-0.7.5/pyield/futures/frc.py +98 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/indicators.py +58 -4
- pyield-0.7.5/pyield/projections.py +87 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/treasuries.py +1 -1
- {pyield-0.7.3 → pyield-0.7.5}/pyield/utils.py +10 -10
- {pyield-0.7.3 → pyield-0.7.5}/pyproject.toml +2 -1
- {pyield-0.7.3 → pyield-0.7.5}/tests/test_futures.py +5 -5
- pyield-0.7.3/pyield/__about__.py +0 -1
- pyield-0.7.3/pyield/data_access.py +0 -95
- pyield-0.7.3/pyield/futures/__init__.py +0 -11
- {pyield-0.7.3 → pyield-0.7.5}/LICENSE +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/bday.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/data_analysis.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/futures/di_xml.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/holidays/__init__.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/holidays/core.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/pyield/py.typed +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/tests/__init__.py +0 -0
- {pyield-0.7.3 → pyield-0.7.5}/tests/test_bday.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PYield
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.5
|
|
4
4
|
Summary: A Python library for analysis of fixed income instruments in Brazil
|
|
5
5
|
Keywords: fixed-income, brazil, finance, analysis, bonds
|
|
6
6
|
Author-Email: Carlos Carvalho <cr.cj@outlook.com>
|
|
@@ -38,13 +38,14 @@ Requires-Dist: numpy
|
|
|
38
38
|
Requires-Dist: beautifulsoup4
|
|
39
39
|
Requires-Dist: html5lib
|
|
40
40
|
Requires-Dist: lxml
|
|
41
|
+
Requires-Dist: python-calamine>=0.2.0
|
|
41
42
|
Description-Content-Type: text/markdown
|
|
42
43
|
|
|
43
44
|
[](https://pypi.python.org/pypi/pyield)
|
|
44
45
|
[](https://python.org "Go to Python homepage")
|
|
45
46
|
[](#license)
|
|
46
47
|
|
|
47
|
-
# PYield: Fixed Income
|
|
48
|
+
# PYield: Brazilian Fixed Income Toolkit
|
|
48
49
|
|
|
49
50
|
## Introduction
|
|
50
51
|
|
|
@@ -98,17 +99,27 @@ dtype: datetime64[ns]
|
|
|
98
99
|
|
|
99
100
|
### Futures Data
|
|
100
101
|
```python
|
|
101
|
-
# Fetch
|
|
102
|
+
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
103
|
+
>>> yd.fetch_asset(asset_code="DI1")
|
|
104
|
+
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate LastRate
|
|
105
|
+
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
106
|
+
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
107
|
+
2024-04-21 13:37:39 DI1N24 2024-07-01 48 ... 0.10480 0.10456 0.10462 0.10460
|
|
108
|
+
... ... ... ... ... ... ... ... ...
|
|
109
|
+
2024-04-21 13:37:39 DI1F37 2037-01-02 3183 ... <NA> <NA> 0.11600 <NA>
|
|
110
|
+
2024-04-21 13:37:39 DI1F38 2038-01-04 3432 ... <NA> <NA> 0.11600 <NA>
|
|
111
|
+
2024-04-21 13:37:39 DI1F39 2039-01-03 3683 ... <NA> <NA> <NA> <NA>
|
|
112
|
+
|
|
113
|
+
# Fetch historical DI Futures data from B3
|
|
102
114
|
>>> yd.fetch_asset(asset_code="DI1", reference_date='2024-03-08')
|
|
103
|
-
|
|
104
115
|
TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastBidRate SettlementRate
|
|
105
|
-
2024-03-08
|
|
106
|
-
2024-03-08
|
|
107
|
-
2024-03-08
|
|
108
|
-
...
|
|
109
|
-
2024-03-08
|
|
110
|
-
2024-03-08
|
|
111
|
-
2024-03-08
|
|
116
|
+
2024-03-08 DI1J24 2024-04-01 15 ... 10.952 10.952 10.956 10.956
|
|
117
|
+
2024-03-08 DI1K24 2024-05-02 37 ... 10.776 10.774 10.780 10.777
|
|
118
|
+
2024-03-08 DI1M24 2024-06-03 58 ... 10.604 10.602 10.604 10.608
|
|
119
|
+
... ... ... ... ... ... ... ... ...
|
|
120
|
+
2024-03-08 DI1F37 2037-01-02 3213 ... <NA> <NA> <NA> 10.859
|
|
121
|
+
2024-03-08 DI1F38 2038-01-04 3462 ... <NA> <NA> <NA> 10.859
|
|
122
|
+
2024-03-08 DI1F39 2039-01-03 3713 ... <NA> <NA> <NA> 10.85
|
|
112
123
|
```
|
|
113
124
|
|
|
114
125
|
### Treasury Bonds Data
|
|
@@ -118,14 +129,14 @@ TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastB
|
|
|
118
129
|
# Obs: Anbima members have access to the full history
|
|
119
130
|
>>> yd.fetch_asset(asset_code="NTN-B", reference_date='2024-04-12')
|
|
120
131
|
|
|
121
|
-
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate
|
|
122
|
-
NTN-B 2024-04-12
|
|
123
|
-
NTN-B 2024-04-12
|
|
124
|
-
NTN-B 2024-04-12
|
|
125
|
-
...
|
|
126
|
-
NTN-B 2024-04-12
|
|
127
|
-
NTN-B 2024-04-12
|
|
128
|
-
NTN-B 2024-04-12
|
|
132
|
+
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
133
|
+
NTN-B 2024-04-12 2024-08-15 0.07540 0.07504 0.07523 4,271.43565
|
|
134
|
+
NTN-B 2024-04-12 2025-05-15 0.05945 0.05913 0.05930 4,361.34391
|
|
135
|
+
NTN-B 2024-04-12 2026-08-15 0.05927 0.05897 0.05910 4,301.40082
|
|
136
|
+
... ... ... ... ... ... ...
|
|
137
|
+
NTN-B 2024-04-12 2050-08-15 0.06039 0.06006 0.06023 4,299.28233
|
|
138
|
+
NTN-B 2024-04-12 2055-05-15 0.06035 0.05998 0.06017 4,367.13360
|
|
139
|
+
NTN-B 2024-04-12 2060-08-15 0.06057 0.06016 0.06036 4,292.26323
|
|
129
140
|
```
|
|
130
141
|
|
|
131
142
|
### Spreads Calculation
|
|
@@ -134,13 +145,13 @@ NTN-B 2024-04-12 2060-08-15 0.06057 0.06016 0.06036 4,292.26323
|
|
|
134
145
|
>>> yd.calculate_spreads(spread_type="di_vs_pre", reference_date="2024-4-11")
|
|
135
146
|
|
|
136
147
|
BondType ReferenceDate MaturityDate DISpread
|
|
137
|
-
LTN
|
|
138
|
-
LTN
|
|
139
|
-
LTN
|
|
140
|
-
... ... ... ...
|
|
141
|
-
NTN-F 2024-04-11
|
|
142
|
-
NTN-F 2024-04-11
|
|
143
|
-
NTN-F 2024-04-11
|
|
148
|
+
LTN 2024-04-11 2024-07-01 -20.28
|
|
149
|
+
LTN 2024-04-11 2024-10-01 -10.19
|
|
150
|
+
LTN 2024-04-11 2025-01-01 -15.05
|
|
151
|
+
... ... ... ...
|
|
152
|
+
NTN-F 2024-04-11 2031-01-01 -0.66
|
|
153
|
+
NTN-F 2024-04-11 2033-01-01 -5.69
|
|
154
|
+
NTN-F 2024-04-11 2035-01-01 -1.27
|
|
144
155
|
```
|
|
145
156
|
|
|
146
157
|
### Indicators Data
|
|
@@ -157,3 +168,19 @@ NTN-F 2024-04-11 2035-01-01 -1.27000
|
|
|
157
168
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-04-10')
|
|
158
169
|
None
|
|
159
170
|
```
|
|
171
|
+
|
|
172
|
+
### Projections Data
|
|
173
|
+
```python
|
|
174
|
+
# Fetch current month projection for IPCA from IBGE API
|
|
175
|
+
>>> ipca = yd.fetch_projection(projection_code="IPCA_CM")
|
|
176
|
+
>>> print(ipca)
|
|
177
|
+
IndicatorProjection(
|
|
178
|
+
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
179
|
+
reference_month_ts=Timestamp('2024-04-01 00:00:00'),
|
|
180
|
+
reference_month_br='ABR/2024',
|
|
181
|
+
projected_value=0.0035
|
|
182
|
+
)
|
|
183
|
+
>>> ipca.projected_value
|
|
184
|
+
0.0035
|
|
185
|
+
```
|
|
186
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
[](https://python.org "Go to Python homepage")
|
|
3
3
|
[](#license)
|
|
4
4
|
|
|
5
|
-
# PYield: Fixed Income
|
|
5
|
+
# PYield: Brazilian Fixed Income Toolkit
|
|
6
6
|
|
|
7
7
|
## Introduction
|
|
8
8
|
|
|
@@ -56,17 +56,27 @@ dtype: datetime64[ns]
|
|
|
56
56
|
|
|
57
57
|
### Futures Data
|
|
58
58
|
```python
|
|
59
|
-
# Fetch
|
|
59
|
+
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
60
|
+
>>> yd.fetch_asset(asset_code="DI1")
|
|
61
|
+
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate LastRate
|
|
62
|
+
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
63
|
+
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
64
|
+
2024-04-21 13:37:39 DI1N24 2024-07-01 48 ... 0.10480 0.10456 0.10462 0.10460
|
|
65
|
+
... ... ... ... ... ... ... ... ...
|
|
66
|
+
2024-04-21 13:37:39 DI1F37 2037-01-02 3183 ... <NA> <NA> 0.11600 <NA>
|
|
67
|
+
2024-04-21 13:37:39 DI1F38 2038-01-04 3432 ... <NA> <NA> 0.11600 <NA>
|
|
68
|
+
2024-04-21 13:37:39 DI1F39 2039-01-03 3683 ... <NA> <NA> <NA> <NA>
|
|
69
|
+
|
|
70
|
+
# Fetch historical DI Futures data from B3
|
|
60
71
|
>>> yd.fetch_asset(asset_code="DI1", reference_date='2024-03-08')
|
|
61
|
-
|
|
62
72
|
TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastBidRate SettlementRate
|
|
63
|
-
2024-03-08
|
|
64
|
-
2024-03-08
|
|
65
|
-
2024-03-08
|
|
66
|
-
...
|
|
67
|
-
2024-03-08
|
|
68
|
-
2024-03-08
|
|
69
|
-
2024-03-08
|
|
73
|
+
2024-03-08 DI1J24 2024-04-01 15 ... 10.952 10.952 10.956 10.956
|
|
74
|
+
2024-03-08 DI1K24 2024-05-02 37 ... 10.776 10.774 10.780 10.777
|
|
75
|
+
2024-03-08 DI1M24 2024-06-03 58 ... 10.604 10.602 10.604 10.608
|
|
76
|
+
... ... ... ... ... ... ... ... ...
|
|
77
|
+
2024-03-08 DI1F37 2037-01-02 3213 ... <NA> <NA> <NA> 10.859
|
|
78
|
+
2024-03-08 DI1F38 2038-01-04 3462 ... <NA> <NA> <NA> 10.859
|
|
79
|
+
2024-03-08 DI1F39 2039-01-03 3713 ... <NA> <NA> <NA> 10.85
|
|
70
80
|
```
|
|
71
81
|
|
|
72
82
|
### Treasury Bonds Data
|
|
@@ -76,14 +86,14 @@ TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastB
|
|
|
76
86
|
# Obs: Anbima members have access to the full history
|
|
77
87
|
>>> yd.fetch_asset(asset_code="NTN-B", reference_date='2024-04-12')
|
|
78
88
|
|
|
79
|
-
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate
|
|
80
|
-
NTN-B 2024-04-12
|
|
81
|
-
NTN-B 2024-04-12
|
|
82
|
-
NTN-B 2024-04-12
|
|
83
|
-
...
|
|
84
|
-
NTN-B 2024-04-12
|
|
85
|
-
NTN-B 2024-04-12
|
|
86
|
-
NTN-B 2024-04-12
|
|
89
|
+
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
90
|
+
NTN-B 2024-04-12 2024-08-15 0.07540 0.07504 0.07523 4,271.43565
|
|
91
|
+
NTN-B 2024-04-12 2025-05-15 0.05945 0.05913 0.05930 4,361.34391
|
|
92
|
+
NTN-B 2024-04-12 2026-08-15 0.05927 0.05897 0.05910 4,301.40082
|
|
93
|
+
... ... ... ... ... ... ...
|
|
94
|
+
NTN-B 2024-04-12 2050-08-15 0.06039 0.06006 0.06023 4,299.28233
|
|
95
|
+
NTN-B 2024-04-12 2055-05-15 0.06035 0.05998 0.06017 4,367.13360
|
|
96
|
+
NTN-B 2024-04-12 2060-08-15 0.06057 0.06016 0.06036 4,292.26323
|
|
87
97
|
```
|
|
88
98
|
|
|
89
99
|
### Spreads Calculation
|
|
@@ -92,13 +102,13 @@ NTN-B 2024-04-12 2060-08-15 0.06057 0.06016 0.06036 4,292.26323
|
|
|
92
102
|
>>> yd.calculate_spreads(spread_type="di_vs_pre", reference_date="2024-4-11")
|
|
93
103
|
|
|
94
104
|
BondType ReferenceDate MaturityDate DISpread
|
|
95
|
-
LTN
|
|
96
|
-
LTN
|
|
97
|
-
LTN
|
|
98
|
-
... ... ... ...
|
|
99
|
-
NTN-F 2024-04-11
|
|
100
|
-
NTN-F 2024-04-11
|
|
101
|
-
NTN-F 2024-04-11
|
|
105
|
+
LTN 2024-04-11 2024-07-01 -20.28
|
|
106
|
+
LTN 2024-04-11 2024-10-01 -10.19
|
|
107
|
+
LTN 2024-04-11 2025-01-01 -15.05
|
|
108
|
+
... ... ... ...
|
|
109
|
+
NTN-F 2024-04-11 2031-01-01 -0.66
|
|
110
|
+
NTN-F 2024-04-11 2033-01-01 -5.69
|
|
111
|
+
NTN-F 2024-04-11 2035-01-01 -1.27
|
|
102
112
|
```
|
|
103
113
|
|
|
104
114
|
### Indicators Data
|
|
@@ -115,3 +125,19 @@ NTN-F 2024-04-11 2035-01-01 -1.27000
|
|
|
115
125
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-04-10')
|
|
116
126
|
None
|
|
117
127
|
```
|
|
128
|
+
|
|
129
|
+
### Projections Data
|
|
130
|
+
```python
|
|
131
|
+
# Fetch current month projection for IPCA from IBGE API
|
|
132
|
+
>>> ipca = yd.fetch_projection(projection_code="IPCA_CM")
|
|
133
|
+
>>> print(ipca)
|
|
134
|
+
IndicatorProjection(
|
|
135
|
+
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
136
|
+
reference_month_ts=Timestamp('2024-04-01 00:00:00'),
|
|
137
|
+
reference_month_br='ABR/2024',
|
|
138
|
+
projected_value=0.0035
|
|
139
|
+
)
|
|
140
|
+
>>> ipca.projected_value
|
|
141
|
+
0.0035
|
|
142
|
+
```
|
|
143
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.5"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .__about__ import __version__
|
|
2
2
|
from .bday import count_bdays, generate_bdays, is_bday, offset_bdays
|
|
3
|
-
from .data_access import fetch_asset, fetch_indicator
|
|
3
|
+
from .data_access import fetch_asset, fetch_indicator, fetch_projection
|
|
4
4
|
from .data_analysis import calculate_spreads
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
@@ -11,5 +11,6 @@ __all__ = [
|
|
|
11
11
|
"count_bdays",
|
|
12
12
|
"fetch_asset",
|
|
13
13
|
"fetch_indicator",
|
|
14
|
+
"fetch_projection",
|
|
14
15
|
"calculate_spreads",
|
|
15
16
|
]
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from . import futures as ft
|
|
4
|
+
from . import indicators as it
|
|
5
|
+
from . import projections as pr
|
|
6
|
+
from . import treasuries as tr
|
|
7
|
+
from .utils import _normalize_date
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def fetch_asset(
|
|
11
|
+
asset_code: str,
|
|
12
|
+
reference_date: str | pd.Timestamp | None = None,
|
|
13
|
+
**kwargs,
|
|
14
|
+
) -> pd.DataFrame:
|
|
15
|
+
"""
|
|
16
|
+
Fetches data for a specified asset based on type and reference date.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
asset_code (str): The asset code identifying the type of financial asset.
|
|
20
|
+
Supported options:
|
|
21
|
+
- "TRB": Treasury bonds (indicative rates from ANBIMA).
|
|
22
|
+
- "LTN", "LFT", "NTN-F", "NTN-B": Specific types of Brazilian treasury bonds
|
|
23
|
+
(indicative rates from ANBIMA).
|
|
24
|
+
- "DI1": One-day Interbank Deposit Futures (Futuro de DI) from B3.
|
|
25
|
+
- "DDI": DI x U.S. Dollar Spread Futures (Futuro de Cupom Cambial) from B3.
|
|
26
|
+
- "FRC": Forward Rate Agreement (FRA) from B3.
|
|
27
|
+
reference_date (str | pd.Timestamp | None): The reference date for which data is
|
|
28
|
+
fetched. Defaults to the last business day if None.
|
|
29
|
+
**kwargs: Additional keyword arguments, specifically:
|
|
30
|
+
- return_raw (bool): Whether to return raw data without processing. Defaults
|
|
31
|
+
to False.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
pd.DataFrame: A DataFrame containing the fetched data for the specified asset.
|
|
35
|
+
|
|
36
|
+
Raises:
|
|
37
|
+
ValueError: If the asset code is not recognized or supported.
|
|
38
|
+
|
|
39
|
+
Examples:
|
|
40
|
+
>>> fetch_asset('TRB', '2023-04-01')
|
|
41
|
+
>>> fetch_asset('DI1', '2023-04-01', return_raw=True)
|
|
42
|
+
"""
|
|
43
|
+
return_raw = kwargs.get("return_raw", False)
|
|
44
|
+
normalized_date = _normalize_date(reference_date)
|
|
45
|
+
|
|
46
|
+
if asset_code.lower() == "trb":
|
|
47
|
+
return tr.fetch_bonds(reference_date=normalized_date, return_raw=return_raw)
|
|
48
|
+
elif asset_code.lower() in ["ltn", "lft", "ntn-f", "ntn-b"]:
|
|
49
|
+
df = tr.fetch_bonds(reference_date=normalized_date)
|
|
50
|
+
return df.query(f"BondType == '{asset_code.upper()}'")
|
|
51
|
+
|
|
52
|
+
elif asset_code.lower() == "di1":
|
|
53
|
+
today = pd.Timestamp.today().normalize()
|
|
54
|
+
if normalized_date == today:
|
|
55
|
+
return ft.fetch_last_di()
|
|
56
|
+
else:
|
|
57
|
+
return ft.fetch_past_di(trade_date=normalized_date, return_raw=return_raw)
|
|
58
|
+
elif asset_code.lower() == "ddi":
|
|
59
|
+
return ft.fetch_past_ddi(trade_date=normalized_date, return_raw=return_raw)
|
|
60
|
+
elif asset_code.lower() == "frc":
|
|
61
|
+
return ft.fetch_past_frc(trade_date=normalized_date, return_raw=return_raw)
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError("Asset type not supported.")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def fetch_indicator(
|
|
67
|
+
indicator_code: str,
|
|
68
|
+
reference_date: str | pd.Timestamp | None = None,
|
|
69
|
+
) -> float | None:
|
|
70
|
+
"""
|
|
71
|
+
Fetches data for a specified economic indicator and reference date.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
indicator_code (str): The code for the economic indicator. Supported options:
|
|
75
|
+
- "SELIC": SELIC target rate from the Central Bank of Brazil, expressed as
|
|
76
|
+
an annual rate (p.a.).
|
|
77
|
+
- "DI": Interbank Deposit rate (DI) from B3 expressed as a daily rate,
|
|
78
|
+
calculated on a daily basis and expressed per diem (p.d.).
|
|
79
|
+
- "IPCA": IPCA monthly inflation rate from IBGE, expressed per month (p.m.).
|
|
80
|
+
- "VNA_LFT": VNA (Valor Nominal Atualizado) of LFT (Letra Financeira do
|
|
81
|
+
Tesouro), which reflects updated nominal values for these bonds.
|
|
82
|
+
- reference_date (str | pd.Timestamp | None): The reference date for which data
|
|
83
|
+
is fetched. Defaults to the last business day if None.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
float | None: The value of the specified economic indicator for the reference
|
|
87
|
+
date. Returns None if data is not found.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ValueError: If the indicator code is not recognized or supported.
|
|
91
|
+
|
|
92
|
+
Examples:
|
|
93
|
+
>>> fetch_indicator('SELIC', '2023-04-01')
|
|
94
|
+
0.1075 # Indicates a SELIC target rate of 10.75% p.a.
|
|
95
|
+
>>> fetch_indicator('IPCA', '2023-03-10')
|
|
96
|
+
0.0016 # Indicates an IPCA monthly rate of 0.16% p.m.
|
|
97
|
+
>>> fetch_indicator('DI', '2023-04-17')
|
|
98
|
+
0.00040168 # Indicates a DI daily rate of 0.02% p.d.
|
|
99
|
+
"""
|
|
100
|
+
normalized_date = _normalize_date(reference_date)
|
|
101
|
+
|
|
102
|
+
if indicator_code.lower() == "selic":
|
|
103
|
+
return it.fetch_selic_target(reference_date=normalized_date)
|
|
104
|
+
elif indicator_code.lower() == "ipca":
|
|
105
|
+
return it.fetch_ipca_mr(reference_date=normalized_date)
|
|
106
|
+
elif indicator_code.lower() == "di":
|
|
107
|
+
return it.fetch_di(reference_date=normalized_date)
|
|
108
|
+
elif indicator_code.lower() == "vna_lft":
|
|
109
|
+
return it.fetch_vna_selic(reference_date=normalized_date)
|
|
110
|
+
else:
|
|
111
|
+
raise ValueError("Indicator type not supported.")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def fetch_projection(projection_code: str) -> dict:
|
|
115
|
+
"""
|
|
116
|
+
Fetches a financial projection for a specified code and reference date.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
projection_code (str): The code for the financial projection. Supported options:
|
|
120
|
+
- "IPCA_CM": IPCA projection for the current month from ANBIMA.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
IndicatorProjection: An instance of IndicatorProjection containing:
|
|
124
|
+
- last_updated (pd.Timestamp): The datetime when the projection was last
|
|
125
|
+
updated.
|
|
126
|
+
- reference_month_ts (pd.Timestamp): The month to which the projection
|
|
127
|
+
applies.
|
|
128
|
+
- reference_month_br (str): The formatted month as a string formatted using
|
|
129
|
+
the pt_BR locale.
|
|
130
|
+
- projected_value (float): The projected indicator value.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If the projection code is not recognized or supported.
|
|
134
|
+
|
|
135
|
+
Examples:
|
|
136
|
+
>>> fetch_projection('IPCA_CM')
|
|
137
|
+
IndicatorProjection(
|
|
138
|
+
last_updated=pd.Timestamp('2024-04-19 18:55:00'),
|
|
139
|
+
reference_month_ts=pd.Timestamp('2024-04-01 00:00:00'),
|
|
140
|
+
reference_month_br='ABR/2024',
|
|
141
|
+
projected_value=0.35
|
|
142
|
+
)
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
if projection_code.lower() == "ipca_cm":
|
|
146
|
+
return pr.fetch_current_month_ipca_projection()
|
|
147
|
+
else:
|
|
148
|
+
raise ValueError("Projection type not supported.")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .common import get_expiration_date, get_old_expiration_date
|
|
2
|
+
from .ddi import fetch_past_ddi
|
|
3
|
+
from .di import fetch_last_di, fetch_past_di
|
|
4
|
+
from .frc import fetch_past_frc
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"fetch_past_di",
|
|
8
|
+
"fetch_last_di",
|
|
9
|
+
"fetch_past_ddi",
|
|
10
|
+
"fetch_past_frc",
|
|
11
|
+
"get_expiration_date",
|
|
12
|
+
"get_old_expiration_date",
|
|
13
|
+
]
|
|
@@ -131,9 +131,10 @@ def get_old_expiration_date(
|
|
|
131
131
|
return pd.NaT # type: ignore
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def
|
|
134
|
+
def fetch_past_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
135
135
|
"""
|
|
136
|
-
Fetch the historical futures data from B3 for a specific trade date.
|
|
136
|
+
Fetch the historical futures data from B3 for a specific trade date. If the data is
|
|
137
|
+
not available, an empty DataFrame is returned.
|
|
137
138
|
|
|
138
139
|
Args:
|
|
139
140
|
trade_date (pd.Timestamp): The trade date for which the data should be fetched.
|
|
@@ -148,7 +149,7 @@ def fetch_past_data(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
148
149
|
|
|
149
150
|
text = r.text
|
|
150
151
|
if "AJUSTE" not in text:
|
|
151
|
-
|
|
152
|
+
return pd.DataFrame()
|
|
152
153
|
|
|
153
154
|
df = pd.read_html(
|
|
154
155
|
io.StringIO(text),
|
|
@@ -170,12 +171,13 @@ def fetch_past_data(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
170
171
|
df["VAR. PTOS."] = df["VAR. PTOS."].astype(pd.StringDtype())
|
|
171
172
|
|
|
172
173
|
# Force "AJUSTE CORRIG. (4)" to be float, since it can be also read as int
|
|
173
|
-
|
|
174
|
+
if "AJUSTE CORRIG. (4)" in df.columns:
|
|
175
|
+
df["AJUSTE CORRIG. (4)"] = df["AJUSTE CORRIG. (4)"].astype(pd.Float64Dtype())
|
|
174
176
|
|
|
175
177
|
return df
|
|
176
178
|
|
|
177
179
|
|
|
178
|
-
def
|
|
180
|
+
def fetch_last_raw_df(future_code: str) -> pd.DataFrame:
|
|
179
181
|
"""
|
|
180
182
|
Fetch the latest data for a given future code from B3 derivatives quotation API.
|
|
181
183
|
|
|
@@ -20,26 +20,6 @@ def _convert_prices_to_rates(prices: pd.Series, n_days: pd.Series) -> pd.Series:
|
|
|
20
20
|
return 100 * rates
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def _convert_prices_in_older_contracts(df: pd.DataFrame) -> pd.DataFrame:
|
|
24
|
-
# Prior to 01/01/2002, prices were not converted to rates
|
|
25
|
-
convert_cols = [
|
|
26
|
-
"FirstRate",
|
|
27
|
-
"MinRate",
|
|
28
|
-
"MaxRate",
|
|
29
|
-
"AvgRate",
|
|
30
|
-
"LastRate",
|
|
31
|
-
"LastBidRate",
|
|
32
|
-
"LastAskRate",
|
|
33
|
-
]
|
|
34
|
-
for col in convert_cols:
|
|
35
|
-
df[col] = _convert_prices_to_rates(df[col], df["DaysToExpiration"])
|
|
36
|
-
|
|
37
|
-
# Invert low and high prices
|
|
38
|
-
df["MinRate"], df["MaxRate"] = df["MaxRate"], df["MinRate"]
|
|
39
|
-
|
|
40
|
-
return df
|
|
41
|
-
|
|
42
|
-
|
|
43
23
|
def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
44
24
|
"""
|
|
45
25
|
Internal function to process and transform raw DI futures data.
|
|
@@ -96,33 +76,16 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
96
76
|
# Remove expired contracts
|
|
97
77
|
df.query("DaysToExpiration > 0", inplace=True)
|
|
98
78
|
|
|
99
|
-
# Columns where 0 means NaN
|
|
100
|
-
cols_with_nan = [
|
|
101
|
-
"SettlementPrice",
|
|
102
|
-
"FirstRate",
|
|
103
|
-
"MinRate",
|
|
104
|
-
"MaxRate",
|
|
105
|
-
"AvgRate",
|
|
106
|
-
"LastRate",
|
|
107
|
-
"LastBidRate",
|
|
108
|
-
"LastAskRate",
|
|
109
|
-
]
|
|
110
|
-
for col in cols_with_nan:
|
|
111
|
-
df[col] = df[col].replace(0, pd.NA)
|
|
112
|
-
|
|
113
|
-
# Prior to 17/01/2002 (incluive), prices were not converted to rates
|
|
114
|
-
if trade_date <= pd.Timestamp("2002-01-17"):
|
|
115
|
-
df = _convert_prices_in_older_contracts(df)
|
|
116
|
-
|
|
117
79
|
df["SettlementRate"] = _convert_prices_to_rates(
|
|
118
80
|
df["SettlementPrice"], df["DaysToExpiration"]
|
|
119
81
|
)
|
|
120
82
|
|
|
121
|
-
# Remove percentage in all rate columns and round to 5 decimal places since it's the
|
|
122
|
-
# precision used by B3. Obs: 5 decimal places = 3 decimal places in percentage
|
|
123
83
|
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
124
|
-
|
|
125
|
-
|
|
84
|
+
cols_with_nan = rate_cols + ["SettlementPrice"]
|
|
85
|
+
# Columns where 0 means NaN
|
|
86
|
+
df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
|
|
87
|
+
# Remove % and round to 5 dec. places (3 in %) since it is the contract's precision
|
|
88
|
+
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
126
89
|
|
|
127
90
|
# Filter and order columns
|
|
128
91
|
ordered_cols = [
|
|
@@ -149,7 +112,7 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
149
112
|
return df[ordered_cols]
|
|
150
113
|
|
|
151
114
|
|
|
152
|
-
def
|
|
115
|
+
def fetch_past_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
153
116
|
"""
|
|
154
117
|
Fetchs the DDI futures data for a given date from B3.
|
|
155
118
|
|
|
@@ -172,7 +135,7 @@ def fetch_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFram
|
|
|
172
135
|
- DaysToExpiration: number of business days to ExpirationDate.
|
|
173
136
|
- OpenContracts: number of open contracts at the start of the trading day.
|
|
174
137
|
"""
|
|
175
|
-
df_raw = common.
|
|
138
|
+
df_raw = common.fetch_past_raw_df(asset_code="DDI", trade_date=trade_date)
|
|
176
139
|
if return_raw:
|
|
177
140
|
return df_raw
|
|
178
141
|
return _process_raw_df(df_raw, trade_date)
|
|
@@ -41,7 +41,7 @@ def _convert_prices_in_older_contracts(df: pd.DataFrame) -> pd.DataFrame:
|
|
|
41
41
|
return df
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
def
|
|
44
|
+
def _process_past_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
45
45
|
"""
|
|
46
46
|
Internal function to process and transform raw DI futures data.
|
|
47
47
|
|
|
@@ -52,10 +52,6 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
|
|
|
52
52
|
Returns:
|
|
53
53
|
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
54
54
|
"""
|
|
55
|
-
# Check if the pd.DataFrame is empty
|
|
56
|
-
if df.empty:
|
|
57
|
-
return df
|
|
58
|
-
|
|
59
55
|
rename_dict = {
|
|
60
56
|
"VENCTO": "ExpirationCode",
|
|
61
57
|
"CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
|
|
@@ -95,20 +91,6 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
|
|
|
95
91
|
# Remove expired contracts
|
|
96
92
|
df.query("BDaysToExp > 0", inplace=True)
|
|
97
93
|
|
|
98
|
-
# Columns where 0 means NaN
|
|
99
|
-
cols_with_nan = [
|
|
100
|
-
"SettlementPrice",
|
|
101
|
-
"FirstRate",
|
|
102
|
-
"MinRate",
|
|
103
|
-
"MaxRate",
|
|
104
|
-
"AvgRate",
|
|
105
|
-
"CloseRate",
|
|
106
|
-
"CloseBidRate",
|
|
107
|
-
"CloseAskRate",
|
|
108
|
-
]
|
|
109
|
-
for col in cols_with_nan:
|
|
110
|
-
df[col] = df[col].replace(0, pd.NA)
|
|
111
|
-
|
|
112
94
|
# Prior to 17/01/2002 (incluive), prices were not converted to rates
|
|
113
95
|
if trade_date <= pd.Timestamp("2002-01-17"):
|
|
114
96
|
df = _convert_prices_in_older_contracts(df)
|
|
@@ -117,11 +99,12 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
|
|
|
117
99
|
df["SettlementPrice"], df["BDaysToExp"]
|
|
118
100
|
)
|
|
119
101
|
|
|
120
|
-
# Remove percentage in all rate columns and round to 5 decimal places since it's the
|
|
121
|
-
# precision used by B3. Obs: 5 decimal places = 3 decimal places in percentage
|
|
122
102
|
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
123
|
-
|
|
124
|
-
|
|
103
|
+
cols_with_nan = rate_cols + ["SettlementPrice"]
|
|
104
|
+
# Columns where 0 means NaN
|
|
105
|
+
df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
|
|
106
|
+
# Remove % and round to 5 dec. places (3 in %) since it is the contract's precision
|
|
107
|
+
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
125
108
|
|
|
126
109
|
df["TickerSymbol"] = "DI1" + df["ExpirationCode"]
|
|
127
110
|
|
|
@@ -151,7 +134,7 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
|
|
|
151
134
|
return df[ordered_cols]
|
|
152
135
|
|
|
153
136
|
|
|
154
|
-
def
|
|
137
|
+
def _process_last_raw_di_df(raw_df: pd.DataFrame) -> pd.DataFrame:
|
|
155
138
|
df = raw_df.copy()
|
|
156
139
|
|
|
157
140
|
# Columns to be renamed
|
|
@@ -188,43 +171,41 @@ def _process_last_di_data(raw_df: pd.DataFrame) -> pd.DataFrame:
|
|
|
188
171
|
return df[rename_columns.values()]
|
|
189
172
|
|
|
190
173
|
|
|
191
|
-
def
|
|
174
|
+
def fetch_last_di() -> pd.DataFrame:
|
|
192
175
|
"""
|
|
193
176
|
Fetch the latest DI futures data from B3.
|
|
194
177
|
|
|
195
178
|
Returns:
|
|
196
179
|
pd.DataFrame: A Pandas pd.DataFrame containing the latest DI futures data.
|
|
197
180
|
"""
|
|
198
|
-
raw_df = common.
|
|
199
|
-
return
|
|
181
|
+
raw_df = common.fetch_last_raw_df(future_code="DI1")
|
|
182
|
+
return _process_last_raw_di_df(raw_df)
|
|
200
183
|
|
|
201
184
|
|
|
202
|
-
def
|
|
203
|
-
trade_date: pd.Timestamp, return_raw: bool = False
|
|
204
|
-
) -> pd.DataFrame:
|
|
185
|
+
def fetch_past_di(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
205
186
|
"""
|
|
206
187
|
Fetchs the DI futures data for a given date from B3.
|
|
207
188
|
|
|
208
189
|
This function fetches and processes the DI futures data from B3 for a specific
|
|
209
|
-
trade date. It's the primary external interface for accessing DI data.
|
|
190
|
+
trade date. It's the primary external interface for accessing DI data. If the data
|
|
191
|
+
is not available, an empty DataFrame is returned.
|
|
210
192
|
|
|
211
193
|
Args:
|
|
212
194
|
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
213
|
-
|
|
195
|
+
return_raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
214
196
|
Defaults to False.
|
|
215
197
|
|
|
216
198
|
Returns:
|
|
217
199
|
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
218
200
|
|
|
219
|
-
Examples:
|
|
220
|
-
>>> from pyield.futures import di
|
|
221
|
-
>>> di.fetch_di(pd.Timestamp("2021-01-04"))
|
|
222
|
-
|
|
223
201
|
Notes:
|
|
224
202
|
- BDaysToExp: number of business days to ExpirationDate.
|
|
225
203
|
- OpenContracts: number of open contracts at the start of the trading day.
|
|
226
204
|
"""
|
|
227
|
-
df_raw = common.
|
|
205
|
+
df_raw = common.fetch_past_raw_df(asset_code="DI1", trade_date=trade_date)
|
|
228
206
|
if return_raw:
|
|
229
207
|
return df_raw
|
|
230
|
-
|
|
208
|
+
if df_raw.empty:
|
|
209
|
+
return pd.DataFrame()
|
|
210
|
+
else:
|
|
211
|
+
return _process_past_raw_df(df_raw, trade_date)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from . import common
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
7
|
+
"""
|
|
8
|
+
Internal function to process and transform raw DI futures data.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
df (pd.DataFrame): the raw DI DataFrame.
|
|
12
|
+
trade_date: a datetime-like object representing the trade date.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
16
|
+
"""
|
|
17
|
+
# Check if the pd.DataFrame is empty
|
|
18
|
+
if df.empty:
|
|
19
|
+
return df
|
|
20
|
+
|
|
21
|
+
rename_dict = {
|
|
22
|
+
"VENCTO": "ExpirationCode",
|
|
23
|
+
"NÚM. NEGOC.": "TradeCount",
|
|
24
|
+
"CONTR. NEGOC.": "TradeVolume",
|
|
25
|
+
"VOL.": "FinancialVolume",
|
|
26
|
+
"AJUSTE DE REF.": "SettlementRate",
|
|
27
|
+
"PREÇO ABERTU.": "FirstRate",
|
|
28
|
+
"PREÇO MÍN.": "MinRate",
|
|
29
|
+
"PREÇO MÉD.": "AvgRate",
|
|
30
|
+
"PREÇO MÁX.": "MaxRate",
|
|
31
|
+
"ÚLT. PREÇO": "CloseRate",
|
|
32
|
+
"VAR. PTOS.": "PointsVariation",
|
|
33
|
+
# Attention: bid/ask rates are inverted
|
|
34
|
+
"ÚLT.OF. COMPRA": "CloseAskRate",
|
|
35
|
+
"ÚLT.OF. VENDA": "CloseBidRate",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
df = df.rename(columns=rename_dict)
|
|
39
|
+
|
|
40
|
+
df["TradeDate"] = trade_date
|
|
41
|
+
# Convert to datetime64[ns] since it is pandas default type for timestamps
|
|
42
|
+
df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
|
|
43
|
+
|
|
44
|
+
# Contract code format was changed in 22/05/2006
|
|
45
|
+
if trade_date < pd.Timestamp("2006-05-22"):
|
|
46
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(
|
|
47
|
+
common.get_old_expiration_date, args=(trade_date,)
|
|
48
|
+
)
|
|
49
|
+
else:
|
|
50
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(common.get_expiration_date)
|
|
51
|
+
|
|
52
|
+
# Replace 0 values in rate columns with pd.NA and remove percentage
|
|
53
|
+
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
54
|
+
# Round to 5 decimal places (3 in %) since it is the contract's precision
|
|
55
|
+
df[rate_cols] = df[rate_cols].replace(0, pd.NA).div(100).round(5)
|
|
56
|
+
|
|
57
|
+
df["TickerSymbol"] = "FRC" + df["ExpirationCode"]
|
|
58
|
+
|
|
59
|
+
# Filter and order columns
|
|
60
|
+
ordered_cols = [
|
|
61
|
+
"TradeDate",
|
|
62
|
+
"TickerSymbol",
|
|
63
|
+
# "ExpirationCode",
|
|
64
|
+
"ExpirationDate",
|
|
65
|
+
"TradeCount",
|
|
66
|
+
"TradeVolume",
|
|
67
|
+
"FinancialVolume",
|
|
68
|
+
"SettlementRate",
|
|
69
|
+
"FirstRate",
|
|
70
|
+
"MinRate",
|
|
71
|
+
"AvgRate",
|
|
72
|
+
"MaxRate",
|
|
73
|
+
"CloseAskRate",
|
|
74
|
+
"CloseBidRate",
|
|
75
|
+
"CloseRate",
|
|
76
|
+
]
|
|
77
|
+
return df[ordered_cols]
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def fetch_past_frc(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
81
|
+
"""
|
|
82
|
+
Fetchs the DI futures data for a given date from B3.
|
|
83
|
+
|
|
84
|
+
This function fetches and processes the DI futures data from B3 for a specific
|
|
85
|
+
trade date. It's the primary external interface for accessing DI data.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
89
|
+
raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
90
|
+
Defaults to False.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
94
|
+
"""
|
|
95
|
+
df_raw = common.fetch_past_raw_df(asset_code="FRC", trade_date=trade_date)
|
|
96
|
+
if return_raw:
|
|
97
|
+
return df_raw
|
|
98
|
+
return _process_past_data(df_raw, trade_date)
|
|
@@ -41,7 +41,7 @@ def fetch_ipca_mr(reference_date: pd.Timestamp) -> float | None:
|
|
|
41
41
|
# Extract and return the IPCA monthly growth rate if data is available
|
|
42
42
|
if data:
|
|
43
43
|
ipca_str = data[0]["resultados"][0]["series"][0]["serie"][ipca_date]
|
|
44
|
-
return float(ipca_str)
|
|
44
|
+
return round(float(ipca_str) / 100, 4)
|
|
45
45
|
else:
|
|
46
46
|
return None
|
|
47
47
|
|
|
@@ -52,8 +52,62 @@ def fetch_selic_target(reference_date: pd.Timestamp) -> float | None:
|
|
|
52
52
|
api_url = f"https://api.bcb.gov.br/dados/serie/bcdata.sgs.432/dados?formato=json&dataInicial={selic_date}&dataFinal={selic_date}"
|
|
53
53
|
response = requests.get(api_url)
|
|
54
54
|
response.raise_for_status()
|
|
55
|
-
|
|
56
|
-
if
|
|
57
|
-
|
|
55
|
+
|
|
56
|
+
if selic_date in response.text:
|
|
57
|
+
data = response.json()
|
|
58
|
+
return round(float(data[0]["valor"]) / 100, 4)
|
|
58
59
|
else:
|
|
59
60
|
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def fetch_di(reference_date: pd.Timestamp) -> float | None:
|
|
64
|
+
# https://api.bcb.gov.br/dados/serie/bcdata.sgs.11/dados?formato=json&dataInicial=12/04/2024&dataFinal=12/04/2024
|
|
65
|
+
di_date = reference_date.strftime("%d/%m/%Y")
|
|
66
|
+
api_url = f"https://api.bcb.gov.br/dados/serie/bcdata.sgs.11/dados?formato=json&dataInicial={di_date}&dataFinal={di_date}"
|
|
67
|
+
response = requests.get(api_url)
|
|
68
|
+
response.raise_for_status()
|
|
69
|
+
|
|
70
|
+
if di_date in response.text:
|
|
71
|
+
data = response.json()
|
|
72
|
+
return round(float(data[0]["valor"]) / 100, 8)
|
|
73
|
+
else:
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def fetch_vna_selic(reference_date: pd.Timestamp) -> float | None:
|
|
78
|
+
# url example: https://www3.bcb.gov.br/novoselic/rest/arquivosDiarios/pub/download/3/20240418APC238
|
|
79
|
+
|
|
80
|
+
url_base = "https://www3.bcb.gov.br/novoselic/rest/arquivosDiarios/pub/download/3/"
|
|
81
|
+
url_file = f"{reference_date.strftime("%Y%m%d")}APC238"
|
|
82
|
+
url_vna = url_base + url_file
|
|
83
|
+
response = requests.get(url_vna)
|
|
84
|
+
response.raise_for_status()
|
|
85
|
+
file_text = response.text
|
|
86
|
+
|
|
87
|
+
# Finding the part that contains the table
|
|
88
|
+
start_of_table = file_text.find("EMISSAO")
|
|
89
|
+
end_of_table = file_text.find("99999999*")
|
|
90
|
+
|
|
91
|
+
# Extracting the table
|
|
92
|
+
table_text = file_text[start_of_table:end_of_table].strip()
|
|
93
|
+
table_lines = table_text.splitlines()
|
|
94
|
+
|
|
95
|
+
# Remove empty lines
|
|
96
|
+
table_lines = [line.strip() for line in table_lines if line.strip()]
|
|
97
|
+
|
|
98
|
+
# Remove first line
|
|
99
|
+
body_lines = table_lines[1:]
|
|
100
|
+
|
|
101
|
+
vnas = []
|
|
102
|
+
for line in body_lines:
|
|
103
|
+
vna_str = line.split()[-1].replace(",", ".")
|
|
104
|
+
vna_float = float(vna_str)
|
|
105
|
+
vnas.append(vna_float)
|
|
106
|
+
|
|
107
|
+
# Raise error if all values are not the same
|
|
108
|
+
vna_value = vnas[0]
|
|
109
|
+
if any(vna_value != vna for vna in vnas):
|
|
110
|
+
bcb_url = "https://www.bcb.gov.br/estabilidadefinanceira/selicbaixar"
|
|
111
|
+
raise ValueError(f"VNA values are not the same. Please check data at {bcb_url}")
|
|
112
|
+
|
|
113
|
+
return vna_value
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import locale
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import python_calamine as pc
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class IndicatorProjection:
|
|
12
|
+
last_updated: pd.Timestamp # Date and time of the last update
|
|
13
|
+
reference_month_ts: pd.Timestamp # Timestamp to which the projection applies
|
|
14
|
+
reference_month_br: str # Brazilian formatted month (e.g., "ABR/2024")
|
|
15
|
+
projected_value: float # Projected value
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def fetch_current_month_ipca_projection() -> IndicatorProjection:
|
|
19
|
+
"""
|
|
20
|
+
Fetches the current month's IPCA projection from the ANBIMA website and returns it
|
|
21
|
+
as an IndicatorProjection instance.
|
|
22
|
+
|
|
23
|
+
This function retrieves and parses the Excel file that contains economic indicators,
|
|
24
|
+
specifically looking for the IPCA projection. It extracts the date of the last
|
|
25
|
+
update and the IPCA projection for the reference month.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
None
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
IndicatorProjection: An instance of IndicatorProjection containing:
|
|
32
|
+
- last_updated (pd.Timestamp): The datetime when the data was last updated.
|
|
33
|
+
- reference_month_ts (pd.Timestamp): The month to which the IPCA projection
|
|
34
|
+
applies.
|
|
35
|
+
- reference_month_br (str): The formatted month as a string
|
|
36
|
+
(e.g., "ABR/2024") using the pt_BR locale.
|
|
37
|
+
- projected_value (float): The projected IPCA value.
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
>>> projection = fetch_current_month_ipca_projection()
|
|
41
|
+
>>> print(projection)
|
|
42
|
+
IndicatorProjection(
|
|
43
|
+
last_updated=pd.Timestamp('2024-04-19 18:55:00'),
|
|
44
|
+
reference_month_ts=pd.Timestamp('2024-04-01 00:00:00'),
|
|
45
|
+
reference_month_br='ABR/2024',
|
|
46
|
+
projected_value=0.35
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
Data file format example after parsing:
|
|
50
|
+
- ['Data e Hora da Última Atualização: 19/04/2024 - 18:55 h', '', '']
|
|
51
|
+
- ...
|
|
52
|
+
- ['IPCA1', 'Projeção (abr/24)', 0.35]
|
|
53
|
+
- ...
|
|
54
|
+
"""
|
|
55
|
+
# Define the URL and get the data
|
|
56
|
+
url = "https://www.anbima.com.br/informacoes/indicadores/arqs/indicadores.xls"
|
|
57
|
+
response = requests.get(url)
|
|
58
|
+
excel_data = io.BytesIO(response.content)
|
|
59
|
+
|
|
60
|
+
# Load the workbook and select the first sheet
|
|
61
|
+
workbook = pc.load_workbook(excel_data)
|
|
62
|
+
first_sheet = workbook.sheet_names[0]
|
|
63
|
+
data = workbook.get_sheet_by_name(first_sheet).to_python(skip_empty_area=True)
|
|
64
|
+
|
|
65
|
+
# Extract projection update date and time from the first row
|
|
66
|
+
last_update_str = data[0][0].split("Atualização:")[-1].strip()
|
|
67
|
+
last_updated = pd.to_datetime(last_update_str, format="%d/%m/%Y - %H:%M h")
|
|
68
|
+
|
|
69
|
+
# Find the row containing the IPCA projection and extract its data
|
|
70
|
+
ipca_data = next(line for line in data if "IPCA1" in line)
|
|
71
|
+
|
|
72
|
+
# Convert the last element of the IPCA data row to float for the projection value
|
|
73
|
+
ipca_value = round(float(ipca_data[-1]) / 100, 4)
|
|
74
|
+
|
|
75
|
+
# Extract and format the reference month
|
|
76
|
+
month_text = ipca_data[1].split("(")[-1].split(")")[0]
|
|
77
|
+
locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8")
|
|
78
|
+
ipca_month_ts = pd.to_datetime(month_text, format="%b/%y")
|
|
79
|
+
ipca_month_br = ipca_month_ts.strftime("%b/%Y").upper()
|
|
80
|
+
locale.setlocale(locale.LC_TIME, "") # Reset locale to default
|
|
81
|
+
|
|
82
|
+
return IndicatorProjection(
|
|
83
|
+
last_updated=last_updated,
|
|
84
|
+
reference_month_ts=ipca_month_ts,
|
|
85
|
+
reference_month_br=ipca_month_br,
|
|
86
|
+
projected_value=ipca_value,
|
|
87
|
+
)
|
|
@@ -150,7 +150,7 @@ def calculate_di_spreads(reference_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
150
150
|
bond type and maturity date.
|
|
151
151
|
"""
|
|
152
152
|
# Fetch DI rates and adjust the maturity date format for compatibility
|
|
153
|
-
df_di = ft.
|
|
153
|
+
df_di = ft.fetch_past_di(reference_date)[["ExpirationDate", "SettlementRate"]]
|
|
154
154
|
|
|
155
155
|
# Renaming the columns to match the ANBIMA structure
|
|
156
156
|
df_di.rename(columns={"ExpirationDate": "MaturityDate"}, inplace=True)
|
|
@@ -3,7 +3,7 @@ import pandas as pd
|
|
|
3
3
|
from . import bday
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def _normalize_date(
|
|
6
|
+
def _normalize_date(input_date: str | pd.Timestamp | None = None) -> pd.Timestamp:
|
|
7
7
|
"""
|
|
8
8
|
Normalizes the given date to ensure it is a past business day at midnight. If no
|
|
9
9
|
date is provided, it defaults to the last business day.
|
|
@@ -31,25 +31,25 @@ def _normalize_date(reference_date: str | pd.Timestamp | None = None) -> pd.Time
|
|
|
31
31
|
>>> _normalize_date(pd.Timestamp('2023-04-01 15:30'))
|
|
32
32
|
>>> _normalize_date()
|
|
33
33
|
"""
|
|
34
|
-
if isinstance(
|
|
34
|
+
if isinstance(input_date, str):
|
|
35
35
|
# Convert string date to Timestamp and normalize to midnight
|
|
36
|
-
normalized_date = pd.Timestamp(
|
|
37
|
-
elif isinstance(
|
|
36
|
+
normalized_date = pd.Timestamp(input_date).normalize()
|
|
37
|
+
elif isinstance(input_date, pd.Timestamp):
|
|
38
38
|
# Normalize Timestamp to midnight
|
|
39
|
-
normalized_date =
|
|
40
|
-
elif
|
|
39
|
+
normalized_date = input_date.normalize()
|
|
40
|
+
elif input_date is None:
|
|
41
41
|
# If no date is provided, use the last available business day
|
|
42
42
|
today = pd.Timestamp.today().normalize()
|
|
43
43
|
normalized_date = bday.offset_bdays(dates=today, offset=0, roll="backward")
|
|
44
44
|
else:
|
|
45
|
-
raise ValueError("
|
|
45
|
+
raise ValueError(f"Date format not recognized: {input_date}")
|
|
46
46
|
|
|
47
|
+
error_date = normalized_date.strftime("%d-%m-%Y")
|
|
47
48
|
# Validate that the date is not in the future
|
|
48
49
|
if normalized_date > pd.Timestamp.today().normalize():
|
|
49
|
-
raise ValueError("
|
|
50
|
-
|
|
50
|
+
raise ValueError(f"Date {error_date} is in the future")
|
|
51
51
|
# Validate that the date is a business day
|
|
52
52
|
if not bday.is_bday(normalized_date):
|
|
53
|
-
raise ValueError("
|
|
53
|
+
raise ValueError(f"Date {error_date} is not a business day")
|
|
54
54
|
|
|
55
55
|
return normalized_date
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
-
import pytest
|
|
3
2
|
|
|
4
3
|
from pyield import futures as ft
|
|
5
4
|
|
|
@@ -43,7 +42,7 @@ def test_settlement_rate_with_old_holiday_list():
|
|
|
43
42
|
|
|
44
43
|
# 22-12-2023 is before the new holiday calendar
|
|
45
44
|
test_date = pd.Timestamp("2023-12-22")
|
|
46
|
-
df = ft.
|
|
45
|
+
df = ft.fetch_past_di(trade_date=test_date)
|
|
47
46
|
tickers = list(settlement_rates.keys()) # noqa: F841
|
|
48
47
|
result = df.query("TickerSymbol in @tickers")["SettlementRate"].to_list()
|
|
49
48
|
assert result == list(settlement_rates.values())
|
|
@@ -68,7 +67,7 @@ def test_settlement_rates_with_current_holiday_list():
|
|
|
68
67
|
"DI1F33": 0.10331,
|
|
69
68
|
}
|
|
70
69
|
test_date = pd.Timestamp("2023-12-26")
|
|
71
|
-
df = ft.
|
|
70
|
+
df = ft.fetch_past_di(trade_date=test_date)
|
|
72
71
|
tickers = list(settlement_rates.keys()) # noqa: F841
|
|
73
72
|
results = df.query("TickerSymbol in @tickers")["SettlementRate"].to_list()
|
|
74
73
|
assert results == list(settlement_rates.values())
|
|
@@ -76,5 +75,6 @@ def test_settlement_rates_with_current_holiday_list():
|
|
|
76
75
|
|
|
77
76
|
def test_non_business_day():
|
|
78
77
|
non_business_day = pd.Timestamp("2023-12-24")
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
# Test if it an empty DataFrame is returned
|
|
79
|
+
df = ft.fetch_past_di(trade_date=non_business_day)
|
|
80
|
+
assert df.empty
|
pyield-0.7.3/pyield/__about__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.3"
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
|
|
3
|
-
from . import futures as ft
|
|
4
|
-
from . import indicators as it
|
|
5
|
-
from . import treasuries as tr
|
|
6
|
-
from .utils import _normalize_date
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def fetch_asset(
|
|
10
|
-
asset_code: str,
|
|
11
|
-
reference_date: str | pd.Timestamp | None = None,
|
|
12
|
-
**kwargs,
|
|
13
|
-
) -> pd.DataFrame:
|
|
14
|
-
"""
|
|
15
|
-
Fetches data for a specified asset based on type and reference date.
|
|
16
|
-
|
|
17
|
-
Args:
|
|
18
|
-
asset_code (str): The asset code identifying the type of financial asset.
|
|
19
|
-
Supported options:
|
|
20
|
-
- "TRB": Treasury bonds (indicative rates from ANBIMA).
|
|
21
|
-
- "LTN", "LFT", "NTN-F", "NTN-B": Specific types of Brazilian treasury bonds
|
|
22
|
-
(indicative rates from ANBIMA).
|
|
23
|
-
- "DI1": One-day Interbank Deposit Futures (Futuro de DI) from B3.
|
|
24
|
-
- "DDI": DI x U.S. Dollar Spread Futures (Futuro de Cupom Cambial) from B3.
|
|
25
|
-
reference_date (str | pd.Timestamp | None): The reference date for which data is
|
|
26
|
-
fetched. Defaults to the last business day if None.
|
|
27
|
-
**kwargs: Additional keyword arguments, specifically:
|
|
28
|
-
- return_raw (bool): Whether to return raw data without processing. Defaults
|
|
29
|
-
to False.
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
pd.DataFrame: A DataFrame containing the fetched data for the specified asset.
|
|
33
|
-
|
|
34
|
-
Raises:
|
|
35
|
-
ValueError: If the asset code is not recognized or supported.
|
|
36
|
-
|
|
37
|
-
Examples:
|
|
38
|
-
>>> fetch_asset('TRB', '2023-04-01')
|
|
39
|
-
>>> fetch_asset('DI1', '2023-04-01', return_raw=True)
|
|
40
|
-
"""
|
|
41
|
-
return_raw = kwargs.get("return_raw", False)
|
|
42
|
-
normalized_date = _normalize_date(reference_date)
|
|
43
|
-
|
|
44
|
-
if asset_code.lower() == "trb":
|
|
45
|
-
return tr.fetch_bonds(reference_date=normalized_date, return_raw=return_raw)
|
|
46
|
-
elif asset_code.lower() in ["ltn", "lft", "ntn-f", "ntn-b"]:
|
|
47
|
-
df = tr.fetch_bonds(reference_date=normalized_date)
|
|
48
|
-
return df.query(f"BondType == '{asset_code.upper()}'")
|
|
49
|
-
|
|
50
|
-
elif asset_code.lower() == "di1":
|
|
51
|
-
today = pd.Timestamp.today().normalize()
|
|
52
|
-
if normalized_date == today:
|
|
53
|
-
return ft.fetch_last_di_data()
|
|
54
|
-
else:
|
|
55
|
-
return ft.fetch_past_di_data(
|
|
56
|
-
trade_date=normalized_date, return_raw=return_raw
|
|
57
|
-
)
|
|
58
|
-
elif asset_code.lower() == "ddi":
|
|
59
|
-
return ft.fetch_ddi(trade_date=normalized_date, return_raw=return_raw)
|
|
60
|
-
else:
|
|
61
|
-
raise ValueError("Asset type not supported.")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def fetch_indicator(
|
|
65
|
-
indicator_code: str,
|
|
66
|
-
reference_date: str | pd.Timestamp | None = None,
|
|
67
|
-
) -> float | None:
|
|
68
|
-
"""
|
|
69
|
-
Fetches data for a specified economic indicator and reference date.
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
indicator_code (str): The code for the economic indicator. Supported options:
|
|
73
|
-
- "SELIC": SELIC target rate from the Central Bank of Brazil.
|
|
74
|
-
- "IPCA": IPCA monthly inflation rate from IBGE.
|
|
75
|
-
reference_date (str | pd.Timestamp | None): The reference date for which data is
|
|
76
|
-
fetched. Defaults to the last business day if None.
|
|
77
|
-
|
|
78
|
-
Returns:
|
|
79
|
-
pd.Series: A Series containing the fetched data for the specified indicator.
|
|
80
|
-
|
|
81
|
-
Raises:
|
|
82
|
-
ValueError: If the indicator code is not recognized or supported.
|
|
83
|
-
|
|
84
|
-
Examples:
|
|
85
|
-
>>> fetch_indicator('SELIC', '2023-04-01')
|
|
86
|
-
>>> fetch_indicator('IPCA', '2023-04-01')
|
|
87
|
-
"""
|
|
88
|
-
normalized_date = _normalize_date(reference_date)
|
|
89
|
-
|
|
90
|
-
if indicator_code.lower() == "selic":
|
|
91
|
-
return it.fetch_selic_target(reference_date=normalized_date)
|
|
92
|
-
elif indicator_code.lower() == "ipca":
|
|
93
|
-
return it.fetch_ipca_mr(reference_date=normalized_date)
|
|
94
|
-
else:
|
|
95
|
-
raise ValueError("Indicator type not supported.")
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from .common import get_expiration_date, get_old_expiration_date
|
|
2
|
-
from .ddi import fetch_ddi
|
|
3
|
-
from .di import fetch_last_di_data, fetch_past_di_data
|
|
4
|
-
|
|
5
|
-
__all__ = [
|
|
6
|
-
"fetch_past_di_data",
|
|
7
|
-
"fetch_last_di_data",
|
|
8
|
-
"fetch_ddi",
|
|
9
|
-
"get_expiration_date",
|
|
10
|
-
"get_old_expiration_date",
|
|
11
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|