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.
Files changed (37) hide show
  1. {pyield-0.8.5 → pyield-0.9.2}/PKG-INFO +14 -14
  2. {pyield-0.8.5 → pyield-0.9.2}/README.md +13 -13
  3. pyield-0.9.2/pyield/__about__.py +1 -0
  4. pyield-0.9.2/pyield/__init__.py +20 -0
  5. {pyield-0.8.5 → pyield-0.9.2}/pyield/bday.py +13 -13
  6. {pyield-0.8.5 → pyield-0.9.2}/pyield/date_validator.py +1 -1
  7. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/anbima.py +48 -39
  8. pyield-0.9.2/pyield/fetchers/futures/__init__.py +59 -0
  9. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/common.py +2 -2
  10. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/historical.py +13 -13
  11. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/intraday.py +4 -4
  12. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/futures/xml.py +1 -1
  13. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/indicators.py +53 -11
  14. {pyield-0.8.5/pyield → pyield-0.9.2/pyield/fetchers}/projections.py +11 -1
  15. pyield-0.9.2/pyield/holidays/__init__.py +3 -0
  16. pyield-0.8.5/pyield/holidays/core.py → pyield-0.9.2/pyield/holidays/holidays_manager.py +2 -1
  17. {pyield-0.8.5 → pyield-0.9.2}/pyield/ntnb.py +26 -27
  18. pyield-0.9.2/pyield/spreads.py +96 -0
  19. {pyield-0.8.5 → pyield-0.9.2}/pyproject.toml +15 -10
  20. pyield-0.9.2/tests/__init__.py +0 -0
  21. {pyield-0.8.5 → pyield-0.9.2}/tests/test_bday.py +6 -6
  22. {pyield-0.8.5 → pyield-0.9.2}/tests/test_futures.py +2 -2
  23. {pyield-0.8.5 → pyield-0.9.2}/tests/test_futures_xml.py +4 -4
  24. pyield-0.8.5/pyield/__about__.py +0 -1
  25. pyield-0.8.5/pyield/__init__.py +0 -22
  26. pyield-0.8.5/pyield/data_access.py +0 -186
  27. pyield-0.8.5/pyield/futures/__init__.py +0 -4
  28. pyield-0.8.5/pyield/holidays/__init__.py +0 -3
  29. pyield-0.8.5/pyield/spreads.py +0 -56
  30. {pyield-0.8.5 → pyield-0.9.2}/LICENSE +0 -0
  31. {pyield-0.8.5/tests → pyield-0.9.2/pyield/fetchers}/__init__.py +0 -0
  32. {pyield-0.8.5 → pyield-0.9.2}/pyield/holidays/br_holidays_new.txt +0 -0
  33. {pyield-0.8.5 → pyield-0.9.2}/pyield/holidays/br_holidays_old.txt +0 -0
  34. /pyield-0.8.5/pyield/interpolator.py → /pyield-0.9.2/pyield/interpolators.py +0 -0
  35. {pyield-0.8.5 → pyield-0.9.2}/pyield/py.typed +0 -0
  36. {pyield-0.8.5 → pyield-0.9.2}/tests/data/SPRD231222.zip +0 -0
  37. {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.8.5
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.count_bdays(start='29-12-2023', end='02-01-2024')
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.offset_bdays(dates="29-12-2023", offset=1)
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.offset_bdays(dates="30-12-2023", offset=0)
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.offset_bdays(dates="29-12-2023", offset=0)
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.generate_bdays(start='29-12-2023', end='03-01-2024')
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.fetch_asset(asset_code="DI1")
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.fetch_asset(asset_code="DI1", reference_date='08-03-2024')
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.fetch_asset(asset_code="NTN-B", reference_date='12-04-2024')
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.calculate_spreads(spread_type="di_pre", reference_date="11-04-2024")
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.fetch_indicator(indicator_code="SELIC", reference_date='12-04-2024')
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.fetch_indicator(indicator_code="IPCA", reference_date='18-03-2024')
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.fetch_indicator(indicator_code="IPCA", reference_date='10-04-2024')
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.fetch_projection(projection_code="IPCA_CM")
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.count_bdays(start='29-12-2023', end='02-01-2024')
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.offset_bdays(dates="29-12-2023", offset=1)
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.offset_bdays(dates="30-12-2023", offset=0)
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.offset_bdays(dates="29-12-2023", offset=0)
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.generate_bdays(start='29-12-2023', end='03-01-2024')
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.fetch_asset(asset_code="DI1")
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.fetch_asset(asset_code="DI1", reference_date='08-03-2024')
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.fetch_asset(asset_code="NTN-B", reference_date='12-04-2024')
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.calculate_spreads(spread_type="di_pre", reference_date="11-04-2024")
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.fetch_indicator(indicator_code="SELIC", reference_date='12-04-2024')
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.fetch_indicator(indicator_code="IPCA", reference_date='18-03-2024')
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.fetch_indicator(indicator_code="IPCA", reference_date='10-04-2024')
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.fetch_projection(projection_code="IPCA_CM")
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 is_bday(date: SingleDateTypes | None = None) -> bool:
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 = offset_bdays(normalized_date, 0)
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 offset_bdays(
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 offset_bdays(
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 offset_bdays(
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
- result = pd.to_datetime(offsetted_dates_np)
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(result).astype("datetime64[ns]")
181
+ result = pd.Series(result_dti).astype("datetime64[ns]")
182
182
 
183
183
  return result
184
184
 
185
185
 
186
186
  @overload
187
- def count_bdays(
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 count_bdays(
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 count_bdays(
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 count_bdays(
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 count_bdays(
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 generate_bdays(
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.offset_bdays(dates=today, offset=0, roll="backward")
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(reference_date: pd.Timestamp, remote_access: dict = None) -> str:
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 fetch_data(
98
- reference_date: pd.Timestamp, remote_access: dict = None
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
- from ANBIMA, processing them into a structured pandas DataFrame.
101
+ This function retrieves the indicative rates for Brazilian treasury securities from
102
+ ANBIMA, processing them into a structured pandas DataFrame.
105
103
 
106
- Parameters:
107
- reference_date (pd.Timestamp): The date for which to fetch the indicative rates.
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
- given reference date.
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
- file_content = _get_file_content(reference_date, remote_access)
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 = reference_date.strftime("%d-%m-%Y")
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
- return _process_raw_df(df)
123
-
136
+ df = _process_raw_df(df)
124
137
 
125
- def fetch_rates(
126
- reference_date: pd.Timestamp, remote_access: dict = None
127
- ) -> pd.DataFrame:
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
- Parameters:
135
- reference_date (pd.Timestamp): The date for which to fetch the indicative rates.
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
- Returns:
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 .. import bday
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.offset_bdays(expiration, offset=0)
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 .. import bday
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.offset_bdays(expiration_date, offset=0, holiday_list="old")
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 convert_prices_to_rates(
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 fetch_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
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] = convert_prices_to_rates(df[col], df["BDaysToExp"], 252)
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 rename_columns(df: pd.DataFrame) -> pd.DataFrame:
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.count_bdays(trade_date, df["ExpirationDate"])
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"] = convert_prices_to_rates(
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"] = convert_prices_to_rates(
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 select_and_reorder_columns(df: pd.DataFrame):
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 = fetch_raw_df(asset_code=asset_code, trade_date=trade_date)
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 = rename_columns(df_raw)
298
+ df = _rename_columns(df_raw)
299
299
  df = process_df(df, trade_date, asset_code)
300
- df = select_and_reorder_columns(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 .. import bday
6
+ from ... import bday
7
7
 
8
8
 
9
9
  # Função para salvar DataFrame em CSV e ler com read_csv
10
- def convert_with_read_csv(df):
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 convert_with_read_csv(df)
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.count_bdays(df["TradeDate"], df["ExpirationDate"])
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