PYield 0.8.5__tar.gz → 0.9.2__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.8.5 → pyield-0.9.2}/PKG-INFO +14 -14
- {pyield-0.8.5 → pyield-0.9.2}/README.md +13 -13
- pyield-0.9.2/pyield/__about__.py +1 -0
- pyield-0.9.2/pyield/__init__.py +20 -0
- {pyield-0.8.5 → pyield-0.9.2}/pyield/bday.py +13 -13
- {pyield-0.8.5 → pyield-0.9.2}/pyield/date_validator.py +1 -1
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/anbima.py +48 -39
- pyield-0.9.2/pyield/fetchers/futures/__init__.py +59 -0
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/common.py +2 -2
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/historical.py +13 -13
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/intraday.py +4 -4
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/xml.py +1 -1
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/indicators.py +53 -11
- {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/projections.py +11 -1
- pyield-0.9.2/pyield/holidays/__init__.py +3 -0
- pyield-0.8.5/pyield/holidays/core.py → pyield-0.9.2/pyield/holidays/holidays_manager.py +2 -1
- {pyield-0.8.5 → pyield-0.9.2}/pyield/ntnb.py +26 -27
- pyield-0.9.2/pyield/spreads.py +96 -0
- {pyield-0.8.5 → pyield-0.9.2}/pyproject.toml +15 -10
- pyield-0.9.2/tests/__init__.py +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/tests/test_bday.py +6 -6
- {pyield-0.8.5 → pyield-0.9.2}/tests/test_futures.py +2 -2
- {pyield-0.8.5 → pyield-0.9.2}/tests/test_futures_xml.py +4 -4
- pyield-0.8.5/pyield/__about__.py +0 -1
- pyield-0.8.5/pyield/__init__.py +0 -22
- pyield-0.8.5/pyield/data_access.py +0 -186
- pyield-0.8.5/pyield/futures/__init__.py +0 -4
- pyield-0.8.5/pyield/holidays/__init__.py +0 -3
- pyield-0.8.5/pyield/spreads.py +0 -56
- {pyield-0.8.5 → pyield-0.9.2}/LICENSE +0 -0
- {pyield-0.8.5/tests → pyield-0.9.2/pyield/fetchers}/__init__.py +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/pyield/holidays/br_holidays_old.txt +0 -0
- /pyield-0.8.5/pyield/interpolator.py → /pyield-0.9.2/pyield/interpolators.py +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/pyield/py.typed +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/tests/data/SPRD231222.zip +0 -0
- {pyield-0.8.5 → pyield-0.9.2}/tests/data/SPRD240426.zip +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PYield
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.2
|
|
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>
|
|
@@ -74,23 +74,23 @@ pip install pyield
|
|
|
74
74
|
|
|
75
75
|
# Count the number of business days between two dates
|
|
76
76
|
# Start date is included, end date is excluded
|
|
77
|
-
>>> yd.
|
|
77
|
+
>>> yd.bday.count(start='29-12-2023', end='02-01-2024')
|
|
78
78
|
1
|
|
79
79
|
|
|
80
80
|
# Get the next business day after a given date (offset=1)
|
|
81
|
-
>>> yd.
|
|
81
|
+
>>> yd.bday.offset(dates="29-12-2023", offset=1)
|
|
82
82
|
Timestamp('2024-01-02 00:00:00')
|
|
83
83
|
|
|
84
84
|
# Get the next business day if it is not a business day (offset=0)
|
|
85
|
-
>>> yd.
|
|
85
|
+
>>> yd.bday.offset(dates="30-12-2023", offset=0)
|
|
86
86
|
Timestamp('2024-01-02 00:00:00')
|
|
87
87
|
|
|
88
88
|
# Since 2023-12-29 is a business day, it returns the same date (offset=0)
|
|
89
|
-
>>> yd.
|
|
89
|
+
>>> yd.bday.offset(dates="29-12-2023", offset=0)
|
|
90
90
|
Timestamp('2023-12-29 00:00:00')
|
|
91
91
|
|
|
92
92
|
# Generate a pandas series with the business days between two dates
|
|
93
|
-
>>> yd.
|
|
93
|
+
>>> yd.bday.generate(start='29-12-2023', end='03-01-2024')
|
|
94
94
|
0 2023-12-29
|
|
95
95
|
1 2024-01-02
|
|
96
96
|
2 2024-01-03
|
|
@@ -100,7 +100,7 @@ dtype: datetime64[ns]
|
|
|
100
100
|
### Futures Data
|
|
101
101
|
```python
|
|
102
102
|
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
103
|
-
>>> yd.
|
|
103
|
+
>>> yd.futures(contract_code="DI1")
|
|
104
104
|
TradeTime TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate CurrentRate
|
|
105
105
|
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
106
106
|
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
@@ -111,7 +111,7 @@ TradeTime TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate La
|
|
|
111
111
|
2024-04-21 13:37:39 DI1F39 2039-01-03 3683 ... <NA> <NA> <NA> <NA>
|
|
112
112
|
|
|
113
113
|
# Fetch historical DI Futures data from B3
|
|
114
|
-
>>> yd.
|
|
114
|
+
>>> yd.futures(contract_code="DI1", reference_date='08-03-2024')
|
|
115
115
|
TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastBidRate SettlementRate
|
|
116
116
|
2024-03-08 DI1J24 2024-04-01 15 ... 10.952 10.952 10.956 10.956
|
|
117
117
|
2024-03-08 DI1K24 2024-05-02 37 ... 10.776 10.774 10.780 10.777
|
|
@@ -127,7 +127,7 @@ TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastB
|
|
|
127
127
|
# Fetch a DataFrame with the NTN-B data from ANBIMA
|
|
128
128
|
# Anbima data is available for the last 5 working days
|
|
129
129
|
# Obs: Anbima members have access to the full history
|
|
130
|
-
>>> yd.
|
|
130
|
+
>>> yd.anbima(reference_date='12-04-2024', bond_type='NTN-B')
|
|
131
131
|
|
|
132
132
|
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
133
133
|
NTN-B 2024-04-12 2024-08-15 0.07540 0.07504 0.07523 4,271.43565
|
|
@@ -142,7 +142,7 @@ BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
|
142
142
|
### Spreads Calculation
|
|
143
143
|
```python
|
|
144
144
|
# Calculate the spread between two DI Futures contracts and the pre-fix bonds
|
|
145
|
-
>>> yd.
|
|
145
|
+
>>> yd.spread(spread_type="di_pre", reference_date="11-04-2024")
|
|
146
146
|
|
|
147
147
|
BondType ReferenceDate MaturityDate DISpread
|
|
148
148
|
LTN 2024-04-11 2024-07-01 -20.28
|
|
@@ -157,22 +157,22 @@ BondType ReferenceDate MaturityDate DISpread
|
|
|
157
157
|
### Indicators Data
|
|
158
158
|
```python
|
|
159
159
|
# Fetch the SELIC target rate from the Central Bank of Brazil
|
|
160
|
-
>>> yd.
|
|
160
|
+
>>> yd.indicator(indicator_code="SELIC", reference_date='12-04-2024')
|
|
161
161
|
0.1075 # 10.75%
|
|
162
162
|
|
|
163
163
|
# Fetch the IPCA monthly inflation rate from IBGE
|
|
164
|
-
>>> yd.
|
|
164
|
+
>>> yd.indicator(indicator_code="IPCA", reference_date='18-03-2024')
|
|
165
165
|
0.16 # 0.16%
|
|
166
166
|
|
|
167
167
|
# If no data is yet available for the indicator, the function returns None
|
|
168
|
-
>>> yd.
|
|
168
|
+
>>> yd.indicator(indicator_code="IPCA", reference_date='10-04-2024')
|
|
169
169
|
None
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
### Projections Data
|
|
173
173
|
```python
|
|
174
174
|
# Fetch current month projection for IPCA from IBGE API
|
|
175
|
-
>>> ipca = yd.
|
|
175
|
+
>>> ipca = yd.projection(projection_code="IPCA_CM")
|
|
176
176
|
>>> print(ipca)
|
|
177
177
|
IndicatorProjection(
|
|
178
178
|
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
@@ -31,23 +31,23 @@ pip install pyield
|
|
|
31
31
|
|
|
32
32
|
# Count the number of business days between two dates
|
|
33
33
|
# Start date is included, end date is excluded
|
|
34
|
-
>>> yd.
|
|
34
|
+
>>> yd.bday.count(start='29-12-2023', end='02-01-2024')
|
|
35
35
|
1
|
|
36
36
|
|
|
37
37
|
# Get the next business day after a given date (offset=1)
|
|
38
|
-
>>> yd.
|
|
38
|
+
>>> yd.bday.offset(dates="29-12-2023", offset=1)
|
|
39
39
|
Timestamp('2024-01-02 00:00:00')
|
|
40
40
|
|
|
41
41
|
# Get the next business day if it is not a business day (offset=0)
|
|
42
|
-
>>> yd.
|
|
42
|
+
>>> yd.bday.offset(dates="30-12-2023", offset=0)
|
|
43
43
|
Timestamp('2024-01-02 00:00:00')
|
|
44
44
|
|
|
45
45
|
# Since 2023-12-29 is a business day, it returns the same date (offset=0)
|
|
46
|
-
>>> yd.
|
|
46
|
+
>>> yd.bday.offset(dates="29-12-2023", offset=0)
|
|
47
47
|
Timestamp('2023-12-29 00:00:00')
|
|
48
48
|
|
|
49
49
|
# Generate a pandas series with the business days between two dates
|
|
50
|
-
>>> yd.
|
|
50
|
+
>>> yd.bday.generate(start='29-12-2023', end='03-01-2024')
|
|
51
51
|
0 2023-12-29
|
|
52
52
|
1 2024-01-02
|
|
53
53
|
2 2024-01-03
|
|
@@ -57,7 +57,7 @@ dtype: datetime64[ns]
|
|
|
57
57
|
### Futures Data
|
|
58
58
|
```python
|
|
59
59
|
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
60
|
-
>>> yd.
|
|
60
|
+
>>> yd.futures(contract_code="DI1")
|
|
61
61
|
TradeTime TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate CurrentRate
|
|
62
62
|
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
63
63
|
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
@@ -68,7 +68,7 @@ TradeTime TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate La
|
|
|
68
68
|
2024-04-21 13:37:39 DI1F39 2039-01-03 3683 ... <NA> <NA> <NA> <NA>
|
|
69
69
|
|
|
70
70
|
# Fetch historical DI Futures data from B3
|
|
71
|
-
>>> yd.
|
|
71
|
+
>>> yd.futures(contract_code="DI1", reference_date='08-03-2024')
|
|
72
72
|
TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastBidRate SettlementRate
|
|
73
73
|
2024-03-08 DI1J24 2024-04-01 15 ... 10.952 10.952 10.956 10.956
|
|
74
74
|
2024-03-08 DI1K24 2024-05-02 37 ... 10.776 10.774 10.780 10.777
|
|
@@ -84,7 +84,7 @@ TradeDate TickerSymbol ExpirationDate BDaysToExp ... LastRate LastAskRate LastB
|
|
|
84
84
|
# Fetch a DataFrame with the NTN-B data from ANBIMA
|
|
85
85
|
# Anbima data is available for the last 5 working days
|
|
86
86
|
# Obs: Anbima members have access to the full history
|
|
87
|
-
>>> yd.
|
|
87
|
+
>>> yd.anbima(reference_date='12-04-2024', bond_type='NTN-B')
|
|
88
88
|
|
|
89
89
|
BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
90
90
|
NTN-B 2024-04-12 2024-08-15 0.07540 0.07504 0.07523 4,271.43565
|
|
@@ -99,7 +99,7 @@ BondType ReferenceDate MaturityDate BidRate AskRate IndicativeRate Price
|
|
|
99
99
|
### Spreads Calculation
|
|
100
100
|
```python
|
|
101
101
|
# Calculate the spread between two DI Futures contracts and the pre-fix bonds
|
|
102
|
-
>>> yd.
|
|
102
|
+
>>> yd.spread(spread_type="di_pre", reference_date="11-04-2024")
|
|
103
103
|
|
|
104
104
|
BondType ReferenceDate MaturityDate DISpread
|
|
105
105
|
LTN 2024-04-11 2024-07-01 -20.28
|
|
@@ -114,22 +114,22 @@ BondType ReferenceDate MaturityDate DISpread
|
|
|
114
114
|
### Indicators Data
|
|
115
115
|
```python
|
|
116
116
|
# Fetch the SELIC target rate from the Central Bank of Brazil
|
|
117
|
-
>>> yd.
|
|
117
|
+
>>> yd.indicator(indicator_code="SELIC", reference_date='12-04-2024')
|
|
118
118
|
0.1075 # 10.75%
|
|
119
119
|
|
|
120
120
|
# Fetch the IPCA monthly inflation rate from IBGE
|
|
121
|
-
>>> yd.
|
|
121
|
+
>>> yd.indicator(indicator_code="IPCA", reference_date='18-03-2024')
|
|
122
122
|
0.16 # 0.16%
|
|
123
123
|
|
|
124
124
|
# If no data is yet available for the indicator, the function returns None
|
|
125
|
-
>>> yd.
|
|
125
|
+
>>> yd.indicator(indicator_code="IPCA", reference_date='10-04-2024')
|
|
126
126
|
None
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
### Projections Data
|
|
130
130
|
```python
|
|
131
131
|
# Fetch current month projection for IPCA from IBGE API
|
|
132
|
-
>>> ipca = yd.
|
|
132
|
+
>>> ipca = yd.projection(projection_code="IPCA_CM")
|
|
133
133
|
>>> print(ipca)
|
|
134
134
|
IndicatorProjection(
|
|
135
135
|
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.9.2"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from . import bday, interpolators, ntnb
|
|
2
|
+
from .__about__ import __version__
|
|
3
|
+
from .fetchers.anbima import anbima
|
|
4
|
+
from .fetchers.futures import futures
|
|
5
|
+
from .fetchers.indicators import indicator
|
|
6
|
+
from .fetchers.projections import projection
|
|
7
|
+
from .spreads import spread
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"__version__",
|
|
11
|
+
"anbima",
|
|
12
|
+
"bday",
|
|
13
|
+
"ntnb",
|
|
14
|
+
"indicator",
|
|
15
|
+
"projection",
|
|
16
|
+
"spread",
|
|
17
|
+
"futures",
|
|
18
|
+
"interpolators",
|
|
19
|
+
"spread",
|
|
20
|
+
]
|
|
@@ -45,7 +45,7 @@ def _normalize_input_dates(
|
|
|
45
45
|
raise ValueError("Invalid date format.")
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
def
|
|
48
|
+
def is_business_day(date: SingleDateTypes | None = None) -> bool:
|
|
49
49
|
"""
|
|
50
50
|
Checks if the input date is a business day.
|
|
51
51
|
|
|
@@ -64,7 +64,7 @@ def is_bday(date: SingleDateTypes | None = None) -> bool:
|
|
|
64
64
|
"""
|
|
65
65
|
normalized_date = _normalize_input_dates(date)
|
|
66
66
|
# Shift the date if it is not a business day
|
|
67
|
-
adjusted_date =
|
|
67
|
+
adjusted_date = offset(normalized_date, 0)
|
|
68
68
|
return normalized_date == adjusted_date
|
|
69
69
|
|
|
70
70
|
|
|
@@ -87,7 +87,7 @@ def _convert_to_numpy_date(
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
@overload
|
|
90
|
-
def
|
|
90
|
+
def offset(
|
|
91
91
|
dates: SingleDateTypes | None = None,
|
|
92
92
|
offset: int = 0,
|
|
93
93
|
roll: Literal["forward", "backward"] = "forward",
|
|
@@ -96,7 +96,7 @@ def offset_bdays(
|
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
@overload
|
|
99
|
-
def
|
|
99
|
+
def offset(
|
|
100
100
|
dates: SeriesDateTypes,
|
|
101
101
|
offset: int = 0,
|
|
102
102
|
roll: Literal["forward", "backward"] = "forward",
|
|
@@ -104,7 +104,7 @@ def offset_bdays(
|
|
|
104
104
|
) -> pd.Series: ...
|
|
105
105
|
|
|
106
106
|
|
|
107
|
-
def
|
|
107
|
+
def offset(
|
|
108
108
|
dates: SingleDateTypes | SeriesDateTypes | None = None,
|
|
109
109
|
offset: int = 0,
|
|
110
110
|
roll: Literal["forward", "backward"] = "forward",
|
|
@@ -176,15 +176,15 @@ def offset_bdays(
|
|
|
176
176
|
# Force to datetime[ns] if the input was a single date
|
|
177
177
|
result = result.as_unit("ns")
|
|
178
178
|
else:
|
|
179
|
-
|
|
179
|
+
result_dti = pd.to_datetime(offsetted_dates_np)
|
|
180
180
|
# Force the result to be a Series if the input was not a single date
|
|
181
|
-
result = pd.Series(
|
|
181
|
+
result = pd.Series(result_dti).astype("datetime64[ns]")
|
|
182
182
|
|
|
183
183
|
return result
|
|
184
184
|
|
|
185
185
|
|
|
186
186
|
@overload
|
|
187
|
-
def
|
|
187
|
+
def count(
|
|
188
188
|
start: SingleDateTypes | None = None,
|
|
189
189
|
end: SingleDateTypes | None = None,
|
|
190
190
|
holiday_list: Literal["old", "new", "infer"] = "infer",
|
|
@@ -192,7 +192,7 @@ def count_bdays(
|
|
|
192
192
|
|
|
193
193
|
|
|
194
194
|
@overload
|
|
195
|
-
def
|
|
195
|
+
def count(
|
|
196
196
|
start: SeriesDateTypes,
|
|
197
197
|
end: SingleDateTypes | None,
|
|
198
198
|
holiday_list: Literal["old", "new", "infer"] = "infer",
|
|
@@ -200,7 +200,7 @@ def count_bdays(
|
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
@overload
|
|
203
|
-
def
|
|
203
|
+
def count(
|
|
204
204
|
start: SingleDateTypes | None,
|
|
205
205
|
end: SeriesDateTypes,
|
|
206
206
|
holiday_list: Literal["old", "new", "infer"] = "infer",
|
|
@@ -208,14 +208,14 @@ def count_bdays(
|
|
|
208
208
|
|
|
209
209
|
|
|
210
210
|
@overload
|
|
211
|
-
def
|
|
211
|
+
def count(
|
|
212
212
|
start: SeriesDateTypes,
|
|
213
213
|
end: SeriesDateTypes,
|
|
214
214
|
holiday_list: Literal["old", "new", "infer"] = "infer",
|
|
215
215
|
) -> pd.Series: ...
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
def
|
|
218
|
+
def count(
|
|
219
219
|
start: SingleDateTypes | SeriesDateTypes | None = None,
|
|
220
220
|
end: SingleDateTypes | SeriesDateTypes | None = None,
|
|
221
221
|
holiday_list: Literal["old", "new", "infer"] = "infer",
|
|
@@ -285,7 +285,7 @@ def count_bdays(
|
|
|
285
285
|
return pd.Series(result_np, dtype="Int64")
|
|
286
286
|
|
|
287
287
|
|
|
288
|
-
def
|
|
288
|
+
def generate(
|
|
289
289
|
start: SingleDateTypes | None = None,
|
|
290
290
|
end: SingleDateTypes | None = None,
|
|
291
291
|
inclusive: Literal["both", "neither", "left", "right"] = "both",
|
|
@@ -41,7 +41,7 @@ def normalize_date(input_date: str | pd.Timestamp | None = None) -> pd.Timestamp
|
|
|
41
41
|
elif input_date is None:
|
|
42
42
|
# If no date is provided, use the last available business day
|
|
43
43
|
today = pd.Timestamp.today().normalize()
|
|
44
|
-
normalized_date = bday.
|
|
44
|
+
normalized_date = bday.offset(dates=today, offset=0, roll="backward")
|
|
45
45
|
else:
|
|
46
46
|
raise ValueError(f"Date format not recognized: {input_date}")
|
|
47
47
|
|
|
@@ -3,12 +3,17 @@ import io
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
|
+
from .. import date_validator as dv
|
|
7
|
+
|
|
6
8
|
# URL Constants
|
|
7
9
|
ANBIMA_URL = "https://www.anbima.com.br/informacoes/merc-sec/arqs/"
|
|
8
10
|
# URL example: https://www.anbima.com.br/informacoes/merc-sec/arqs/ms240614.txt
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def _get_file_content(
|
|
13
|
+
def _get_file_content(
|
|
14
|
+
reference_date: pd.Timestamp,
|
|
15
|
+
remote_access: dict | None = None,
|
|
16
|
+
) -> str:
|
|
12
17
|
url_date = reference_date.strftime("%y%m%d")
|
|
13
18
|
filename = f"ms{url_date}.txt"
|
|
14
19
|
|
|
@@ -55,15 +60,6 @@ def _read_raw_df(file_content: str) -> pd.DataFrame:
|
|
|
55
60
|
|
|
56
61
|
|
|
57
62
|
def _process_raw_df(df_raw: pd.DataFrame) -> pd.DataFrame:
|
|
58
|
-
"""
|
|
59
|
-
Process raw data from ANBIMA by renaming columns and adjusting data formats.
|
|
60
|
-
|
|
61
|
-
Parameters:
|
|
62
|
-
df (pd.DataFrame): Raw DataFrame to process.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
pd.DataFrame: Processed DataFrame.
|
|
66
|
-
"""
|
|
67
63
|
# Filter selected columns and rename them
|
|
68
64
|
selected_columns_dict = {
|
|
69
65
|
"Titulo": "BondType",
|
|
@@ -94,50 +90,63 @@ def _process_raw_df(df_raw: pd.DataFrame) -> pd.DataFrame:
|
|
|
94
90
|
return df.sort_values(["BondType", "MaturityDate"], ignore_index=True)
|
|
95
91
|
|
|
96
92
|
|
|
97
|
-
def
|
|
98
|
-
reference_date: pd.Timestamp
|
|
93
|
+
def anbima(
|
|
94
|
+
reference_date: str | pd.Timestamp | None = None,
|
|
95
|
+
bond_type: str | list[str] | None = None,
|
|
96
|
+
remote_access: dict | None = None,
|
|
99
97
|
) -> pd.DataFrame:
|
|
100
98
|
"""
|
|
101
99
|
Fetches indicative treasury rates from ANBIMA for a specified reference date.
|
|
102
100
|
|
|
103
|
-
This function retrieves the indicative rates for Brazilian treasury securities
|
|
104
|
-
|
|
101
|
+
This function retrieves the indicative rates for Brazilian treasury securities from
|
|
102
|
+
ANBIMA, processing them into a structured pandas DataFrame.
|
|
105
103
|
|
|
106
|
-
|
|
107
|
-
reference_date (pd.Timestamp): The date for which to
|
|
104
|
+
Args:
|
|
105
|
+
reference_date (str | pd.Timestamp | None, optional): The date for which to
|
|
106
|
+
fetch the indicative rates. If a string is provided, it should be in the
|
|
107
|
+
format 'dd-mm-yyyy'. Defaults last business day if None.
|
|
108
|
+
bond_type (str, optional): The type of bond to filter by. Defaults to None.
|
|
109
|
+
remote_access (dict, optional): Dictionary containing remote access parameters.
|
|
110
|
+
Defaults to None.
|
|
108
111
|
|
|
109
112
|
Returns:
|
|
110
113
|
pd.DataFrame: A DataFrame containing the processed indicative rates for the
|
|
111
|
-
|
|
114
|
+
given reference date.
|
|
112
115
|
|
|
116
|
+
Raises:
|
|
117
|
+
ValueError: If the data could not be fetched for the given reference date or if
|
|
118
|
+
an unsupported bond type is provided.
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
# Fetch ANBIMA data for all bonds using the last business day available
|
|
122
|
+
>>> yd.anbima("18-06-2024")
|
|
123
|
+
# Fetch ANBIMA data for NTN-B bonds using a specific reference date
|
|
124
|
+
>>> yd.anbima("18-06-2024", "NTN-B")
|
|
113
125
|
"""
|
|
114
|
-
|
|
126
|
+
# Normalize the reference date
|
|
127
|
+
normalized_date = dv.normalize_date(reference_date)
|
|
128
|
+
file_content = _get_file_content(normalized_date, remote_access)
|
|
115
129
|
|
|
116
|
-
if file_content
|
|
117
|
-
date_str =
|
|
130
|
+
if not file_content:
|
|
131
|
+
date_str = normalized_date.strftime("%d-%m-%Y")
|
|
118
132
|
raise ValueError(f"Could not fetch ANBIMA data for {date_str}.")
|
|
119
133
|
|
|
120
134
|
df = _read_raw_df(file_content)
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
df = _process_raw_df(df)
|
|
124
137
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
"""
|
|
129
|
-
Fetches indicative treasury rates from ANBIMA for a specified reference date.
|
|
130
|
-
|
|
131
|
-
This function retrieves the indicative rates for Brazilian treasury securities
|
|
132
|
-
from ANBIMA, processing them into a structured pandas DataFrame.
|
|
138
|
+
# If bond type is not specified, return the full DataFrame
|
|
139
|
+
if bond_type is None:
|
|
140
|
+
return df
|
|
133
141
|
|
|
134
|
-
|
|
135
|
-
|
|
142
|
+
# Format bond type as a list of uppercase strings
|
|
143
|
+
if isinstance(bond_type, str):
|
|
144
|
+
bond_list = [bond_type]
|
|
145
|
+
elif isinstance(bond_type, list):
|
|
146
|
+
bond_list = bond_type
|
|
147
|
+
else:
|
|
148
|
+
msg = "Invalid bond type format. Must be a string or a list of strings."
|
|
149
|
+
raise ValueError(msg)
|
|
150
|
+
bond_list = [bt.upper() for bt in bond_list]
|
|
136
151
|
|
|
137
|
-
|
|
138
|
-
pd.DataFrame: A DataFrame containing the processed indicative rates for the
|
|
139
|
-
given reference date.
|
|
140
|
-
|
|
141
|
-
"""
|
|
142
|
-
df = fetch_data(reference_date, remote_access)
|
|
143
|
-
return df[["BondType", "MaturityDate", "IndicativeRate"]].copy()
|
|
152
|
+
return df.query("BondType in @bond_list").reset_index(drop=True)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from ... import date_validator as dv
|
|
4
|
+
from .historical import fetch_historical_df
|
|
5
|
+
from .intraday import fetch_intraday_df
|
|
6
|
+
|
|
7
|
+
SUPPORTED_FUTURES = ["DI1", "DDI", "FRC", "DAP", "DOL", "WDO", "IND", "WIN"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def futures(
|
|
11
|
+
contract_code: str,
|
|
12
|
+
reference_date: str | pd.Timestamp | None = None,
|
|
13
|
+
) -> pd.DataFrame:
|
|
14
|
+
"""
|
|
15
|
+
Fetches data for a specified futures contract based on type and reference date.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
future_code (str): The futures contract code identifying the type of financial
|
|
19
|
+
asset.
|
|
20
|
+
Supported options:
|
|
21
|
+
- "DI1": One-day Interbank Deposit Futures (Futuro de DI) from B3.
|
|
22
|
+
- "DDI": DI x U.S. Dollar Spread Futures (Futuro de Cupom Cambial) from B3.
|
|
23
|
+
- "FRC": Forward Rate Agreement (FRA) from B3.
|
|
24
|
+
- "DAP": DI x IPCA Spread Futures.
|
|
25
|
+
- "DOL": U.S. Dollar Futures from B3.
|
|
26
|
+
- "WDO": Mini U.S. Dollar Futures from B3.
|
|
27
|
+
- "IND": Ibovespa Futures from B3.
|
|
28
|
+
- "WIN": Mini Ibovespa Futures from B3.
|
|
29
|
+
reference_date (str | None): The reference date for which data is fetched.
|
|
30
|
+
Defaults to the last business day if None. If the reference date is a
|
|
31
|
+
string, it should be in 'DD-MM-YYYY' format.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
pd.DataFrame: A DataFrame containing the fetched data for the specified futures
|
|
35
|
+
contract.
|
|
36
|
+
|
|
37
|
+
Raises:
|
|
38
|
+
ValueError: If the futures contract code is not recognized or supported.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
>>> yd.futures.data("DI1", "31-05-2024")
|
|
42
|
+
>>> yd.futures.data("DDI", "31-05-2024")
|
|
43
|
+
"""
|
|
44
|
+
contract_code = contract_code.upper()
|
|
45
|
+
if contract_code not in SUPPORTED_FUTURES:
|
|
46
|
+
raise ValueError("Futures contract not supported.")
|
|
47
|
+
|
|
48
|
+
normalized_date = dv.normalize_date(reference_date)
|
|
49
|
+
|
|
50
|
+
today = pd.Timestamp.today().normalize()
|
|
51
|
+
if normalized_date == today:
|
|
52
|
+
df = fetch_intraday_df(contract_code)
|
|
53
|
+
else:
|
|
54
|
+
df = fetch_historical_df(contract_code, normalized_date)
|
|
55
|
+
|
|
56
|
+
return df
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["futures"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from ... import bday
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def get_expiration_date(expiration_code: str, expiration_day: int = 1) -> pd.Timestamp:
|
|
@@ -59,7 +59,7 @@ def get_expiration_date(expiration_code: str, expiration_day: int = 1) -> pd.Tim
|
|
|
59
59
|
expiration = pd.Timestamp(year, month, expiration_day)
|
|
60
60
|
|
|
61
61
|
# Adjust to the next business day when expiration date is not a business day
|
|
62
|
-
adj_expiration = bday.
|
|
62
|
+
adj_expiration = bday.offset(expiration, offset=0)
|
|
63
63
|
|
|
64
64
|
return adj_expiration
|
|
65
65
|
|
|
@@ -3,7 +3,7 @@ import io
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from ... import bday
|
|
7
7
|
from . import common
|
|
8
8
|
|
|
9
9
|
COUNT_CONVENTIONS = {
|
|
@@ -73,13 +73,13 @@ def get_old_expiration_date(
|
|
|
73
73
|
expiration_date = pd.Timestamp(year, month, 1)
|
|
74
74
|
# Adjust to the next business day when the date is a weekend or a holiday.
|
|
75
75
|
# Must use old holiday list, since this contract code was used until 2006.
|
|
76
|
-
return bday.
|
|
76
|
+
return bday.offset(expiration_date, offset=0, holiday_list="old")
|
|
77
77
|
|
|
78
78
|
except (KeyError, ValueError):
|
|
79
79
|
return pd.NaT # type: ignore
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def
|
|
82
|
+
def _convert_prices_to_rates(
|
|
83
83
|
prices: pd.Series, days_to_expiration: pd.Series, count_convention: int
|
|
84
84
|
) -> pd.Series:
|
|
85
85
|
"""
|
|
@@ -105,7 +105,7 @@ def convert_prices_to_rates(
|
|
|
105
105
|
return rates.round(5)
|
|
106
106
|
|
|
107
107
|
|
|
108
|
-
def
|
|
108
|
+
def _fetch_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
109
109
|
"""
|
|
110
110
|
Fetch the historical futures data from B3 for a specific trade date. If the data is
|
|
111
111
|
not available, an empty DataFrame is returned.
|
|
@@ -153,7 +153,7 @@ def fetch_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
|
153
153
|
|
|
154
154
|
def _adjust_older_contracts_rates(df: pd.DataFrame, rate_cols: list) -> pd.DataFrame:
|
|
155
155
|
for col in rate_cols:
|
|
156
|
-
df[col] =
|
|
156
|
+
df[col] = _convert_prices_to_rates(df[col], df["BDaysToExp"], 252)
|
|
157
157
|
|
|
158
158
|
# Invert low and high prices
|
|
159
159
|
df["MinRate"], df["MaxRate"] = df["MaxRate"], df["MinRate"]
|
|
@@ -161,7 +161,7 @@ def _adjust_older_contracts_rates(df: pd.DataFrame, rate_cols: list) -> pd.DataF
|
|
|
161
161
|
return df
|
|
162
162
|
|
|
163
163
|
|
|
164
|
-
def
|
|
164
|
+
def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
165
165
|
all_columns = {
|
|
166
166
|
"VENCTO": "ExpirationCode",
|
|
167
167
|
"CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
|
|
@@ -212,7 +212,7 @@ def process_df(
|
|
|
212
212
|
# Convert to nullable integer, since it is the default type in the library
|
|
213
213
|
df["DaysToExp"] = df["DaysToExp"].astype(pd.Int64Dtype())
|
|
214
214
|
|
|
215
|
-
df["BDaysToExp"] = bday.
|
|
215
|
+
df["BDaysToExp"] = bday.count(trade_date, df["ExpirationDate"])
|
|
216
216
|
|
|
217
217
|
# Remove expired contracts
|
|
218
218
|
df.query("DaysToExp > 0", inplace=True)
|
|
@@ -233,13 +233,13 @@ def process_df(
|
|
|
233
233
|
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
234
234
|
|
|
235
235
|
if COUNT_CONVENTIONS[asset_code] == 252:
|
|
236
|
-
df["SettlementRate"] =
|
|
236
|
+
df["SettlementRate"] = _convert_prices_to_rates(
|
|
237
237
|
prices=df["SettlementPrice"],
|
|
238
238
|
days_to_expiration=df["BDaysToExp"],
|
|
239
239
|
count_convention=252,
|
|
240
240
|
)
|
|
241
241
|
elif COUNT_CONVENTIONS[asset_code] == 360:
|
|
242
|
-
df["SettlementRate"] =
|
|
242
|
+
df["SettlementRate"] = _convert_prices_to_rates(
|
|
243
243
|
prices=df["SettlementPrice"],
|
|
244
244
|
days_to_expiration=df["DaysToExp"],
|
|
245
245
|
count_convention=360,
|
|
@@ -248,7 +248,7 @@ def process_df(
|
|
|
248
248
|
return df
|
|
249
249
|
|
|
250
250
|
|
|
251
|
-
def
|
|
251
|
+
def _select_and_reorder_columns(df: pd.DataFrame):
|
|
252
252
|
all_columns = [
|
|
253
253
|
"TradeDate",
|
|
254
254
|
"TickerSymbol",
|
|
@@ -292,10 +292,10 @@ def fetch_historical_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFra
|
|
|
292
292
|
Returns:
|
|
293
293
|
pd.DataFrame: A Pandas pd.DataFrame containing processed futures data.
|
|
294
294
|
"""
|
|
295
|
-
df_raw =
|
|
295
|
+
df_raw = _fetch_raw_df(asset_code=asset_code, trade_date=trade_date)
|
|
296
296
|
if df_raw.empty:
|
|
297
297
|
return df_raw
|
|
298
|
-
df =
|
|
298
|
+
df = _rename_columns(df_raw)
|
|
299
299
|
df = process_df(df, trade_date, asset_code)
|
|
300
|
-
df =
|
|
300
|
+
df = _select_and_reorder_columns(df)
|
|
301
301
|
return df
|
|
@@ -3,11 +3,11 @@ from io import StringIO
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from ... import bday
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
# Função para salvar DataFrame em CSV e ler com read_csv
|
|
10
|
-
def
|
|
10
|
+
def _convert_with_read_csv(df):
|
|
11
11
|
buffer = StringIO()
|
|
12
12
|
df.to_csv(buffer, index=False)
|
|
13
13
|
buffer.seek(0) # Reposiciona o cursor no início do buffer
|
|
@@ -45,7 +45,7 @@ def _fetch_b3_df(future_code: str) -> pd.DataFrame:
|
|
|
45
45
|
df = pd.json_normalize(r.json()["Scty"])
|
|
46
46
|
|
|
47
47
|
# Convert DataFrame to use nullable data types for better type consistency
|
|
48
|
-
return
|
|
48
|
+
return _convert_with_read_csv(df)
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
@@ -111,7 +111,7 @@ def _process_df(raw_df: pd.DataFrame) -> pd.DataFrame:
|
|
|
111
111
|
trade_ts = now - pd.Timedelta(minutes=15)
|
|
112
112
|
df["TradeTime"] = trade_ts
|
|
113
113
|
|
|
114
|
-
df["BDaysToExp"] = bday.
|
|
114
|
+
df["BDaysToExp"] = bday.count(df["TradeDate"], df["ExpirationDate"])
|
|
115
115
|
|
|
116
116
|
df["DaysToExp"] = (df["ExpirationDate"] - df["TradeDate"]).dt.days
|
|
117
117
|
# Convert to nullable integer, since it is the default type in the library
|