PYield 0.7.8__tar.gz → 0.7.9__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 (34) hide show
  1. {pyield-0.7.8 → pyield-0.7.9}/PKG-INFO +1 -1
  2. pyield-0.7.9/pyield/__about__.py +1 -0
  3. {pyield-0.7.8 → pyield-0.7.9}/pyield/__init__.py +6 -2
  4. {pyield-0.7.8 → pyield-0.7.9}/pyield/data_access.py +53 -27
  5. pyield-0.7.9/pyield/futures/__init__.py +4 -0
  6. pyield-0.7.8/pyield/futures/historical/common.py → pyield-0.7.9/pyield/futures/historical.py +90 -7
  7. pyield-0.7.8/pyield/futures/intraday/trading_data.py → pyield-0.7.9/pyield/futures/intraday.py +1 -1
  8. pyield-0.7.9/pyield/spreads.py +56 -0
  9. {pyield-0.7.8 → pyield-0.7.9}/pyield/treasuries.py +0 -52
  10. {pyield-0.7.8 → pyield-0.7.9}/pyproject.toml +1 -1
  11. pyield-0.7.8/pyield/futures/historical/di_xml.py → pyield-0.7.9/tests/xml.py +3 -3
  12. pyield-0.7.8/pyield/__about__.py +0 -1
  13. pyield-0.7.8/pyield/data_analysis.py +0 -33
  14. pyield-0.7.8/pyield/futures/historical/__init__.py +0 -6
  15. pyield-0.7.8/pyield/futures/historical/dap.py +0 -62
  16. pyield-0.7.8/pyield/futures/historical/ddi.py +0 -80
  17. pyield-0.7.8/pyield/futures/historical/di.py +0 -91
  18. pyield-0.7.8/pyield/futures/historical/frc.py +0 -60
  19. pyield-0.7.8/pyield/futures/intraday/__init__.py +0 -3
  20. pyield-0.7.8/tests/__init__.py +0 -0
  21. {pyield-0.7.8 → pyield-0.7.9}/LICENSE +0 -0
  22. {pyield-0.7.8 → pyield-0.7.9}/README.md +0 -0
  23. {pyield-0.7.8 → pyield-0.7.9}/pyield/bday.py +0 -0
  24. {pyield-0.7.8 → pyield-0.7.9}/pyield/holidays/__init__.py +0 -0
  25. {pyield-0.7.8 → pyield-0.7.9}/pyield/holidays/br_holidays_new.txt +0 -0
  26. {pyield-0.7.8 → pyield-0.7.9}/pyield/holidays/br_holidays_old.txt +0 -0
  27. {pyield-0.7.8 → pyield-0.7.9}/pyield/holidays/core.py +0 -0
  28. {pyield-0.7.8 → pyield-0.7.9}/pyield/indicators.py +0 -0
  29. {pyield-0.7.8 → pyield-0.7.9}/pyield/projections.py +0 -0
  30. {pyield-0.7.8 → pyield-0.7.9}/pyield/py.typed +0 -0
  31. {pyield-0.7.8 → pyield-0.7.9}/pyield/utils.py +0 -0
  32. {pyield-0.7.8/pyield/futures → pyield-0.7.9/tests}/__init__.py +0 -0
  33. {pyield-0.7.8 → pyield-0.7.9}/tests/test_bday.py +0 -0
  34. {pyield-0.7.8 → pyield-0.7.9}/tests/test_futures.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PYield
3
- Version: 0.7.8
3
+ Version: 0.7.9
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>
@@ -0,0 +1 @@
1
+ __version__ = "0.7.9"
@@ -1,7 +1,11 @@
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, fetch_projection
4
- from .data_analysis import calculate_spreads
3
+ from .data_access import (
4
+ calculate_spreads,
5
+ fetch_asset,
6
+ fetch_indicator,
7
+ fetch_projection,
8
+ )
5
9
 
6
10
  __all__ = [
7
11
  "__version__",
@@ -1,17 +1,15 @@
1
1
  import pandas as pd
2
2
 
3
+ from . import futures as ft
3
4
  from . import indicators as it
4
5
  from . import projections as pr
6
+ from . import spreads as sp
5
7
  from . import treasuries as tr
6
- from .futures import historical as fh
7
- from .futures import intraday as fi
8
8
  from .utils import _normalize_date
9
9
 
10
10
 
11
11
  def fetch_asset(
12
- asset_code: str,
13
- reference_date: str | pd.Timestamp | None = None,
14
- **kwargs,
12
+ asset_code: str, reference_date: str | pd.Timestamp | None = None
15
13
  ) -> pd.DataFrame:
16
14
  """
17
15
  Fetches data for a specified asset based on type and reference date.
@@ -25,7 +23,11 @@ def fetch_asset(
25
23
  - "DI1": One-day Interbank Deposit Futures (Futuro de DI) from B3.
26
24
  - "DDI": DI x U.S. Dollar Spread Futures (Futuro de Cupom Cambial) from B3.
27
25
  - "FRC": Forward Rate Agreement (FRA) from B3.
28
- - "DAP": DI x IPCA Spread Futures
26
+ - "DAP": DI x IPCA Spread Futures.
27
+ - "DOL": U.S. Dollar Futures from B3.
28
+ - "WDO": Mini U.S. Dollar Futures from B3.
29
+ - "IND": Ibovespa Futures from B3.
30
+ - "WIN": Mini Ibovespa Futures from B3.
29
31
  reference_date (str | pd.Timestamp | None): The reference date for which data is
30
32
  fetched. Defaults to the last business day if None.
31
33
  **kwargs: Additional keyword arguments, specifically:
@@ -42,31 +44,26 @@ def fetch_asset(
42
44
  >>> fetch_asset('TRB', '2023-04-01')
43
45
  >>> fetch_asset('DI1', '2023-04-01', return_raw=True)
44
46
  """
45
- return_raw = kwargs.get("return_raw", False)
47
+ SUPPORTED_BONDS = ["LTN", "LFT", "NTN-F", "NTN-B"]
48
+ SUPPORTED_FUTURES = ["DI1", "DDI", "FRC", "DAP", "DOL", "WDO", "IND", "WIN"]
49
+
46
50
  normalized_date = _normalize_date(reference_date)
47
51
 
48
52
  today = pd.Timestamp.today().normalize()
49
53
  if normalized_date == today:
50
- return fi.fetch_intraday(future_code=asset_code.upper())
54
+ return ft.fetch_intraday_df(future_code=asset_code.upper())
51
55
 
52
- if asset_code.lower() == "trb":
53
- return tr.fetch_bonds(reference_date=normalized_date, return_raw=return_raw)
56
+ if asset_code.upper() == "TRB":
57
+ return tr.fetch_bonds(reference_date=normalized_date)
54
58
 
55
- if asset_code.lower() in ["ltn", "lft", "ntn-f", "ntn-b"]:
59
+ if asset_code.upper() in SUPPORTED_BONDS:
56
60
  df = tr.fetch_bonds(reference_date=normalized_date)
57
61
  return df.query(f"BondType == '{asset_code.upper()}'")
58
62
 
59
- if asset_code.lower() == "di1":
60
- return fh.fetch_di(trade_date=normalized_date, return_raw=return_raw)
61
-
62
- if asset_code.lower() == "ddi":
63
- return fh.fetch_ddi(trade_date=normalized_date, return_raw=return_raw)
64
-
65
- if asset_code.lower() == "frc":
66
- return fh.fetch_frc(trade_date=normalized_date, return_raw=return_raw)
67
-
68
- if asset_code.lower() == "dap":
69
- return fh.fetch_dap(trade_date=normalized_date, return_raw=return_raw)
63
+ if asset_code.upper() in SUPPORTED_FUTURES:
64
+ return ft.fetch_historical_df(
65
+ asset_code=asset_code.upper(), trade_date=normalized_date
66
+ )
70
67
 
71
68
  raise ValueError("Asset type not supported.")
72
69
 
@@ -107,13 +104,13 @@ def fetch_indicator(
107
104
  """
108
105
  normalized_date = _normalize_date(reference_date)
109
106
 
110
- if indicator_code.lower() == "selic":
107
+ if indicator_code.upper() == "SELIC":
111
108
  return it.fetch_selic_target(reference_date=normalized_date)
112
- elif indicator_code.lower() == "ipca":
109
+ elif indicator_code.upper() == "IPCA":
113
110
  return it.fetch_ipca_mr(reference_date=normalized_date)
114
- elif indicator_code.lower() == "di":
111
+ elif indicator_code.upper() == "DI":
115
112
  return it.fetch_di(reference_date=normalized_date)
116
- elif indicator_code.lower() == "vna_lft":
113
+ elif indicator_code.upper() == "VNA_LFT":
117
114
  return it.fetch_vna_selic(reference_date=normalized_date)
118
115
  else:
119
116
  raise ValueError("Indicator type not supported.")
@@ -150,7 +147,36 @@ def fetch_projection(projection_code: str) -> pr.IndicatorProjection:
150
147
  )
151
148
  """
152
149
 
153
- if projection_code.lower() == "ipca_cm":
150
+ if projection_code.upper() == "IPCA_CM":
154
151
  return pr.fetch_current_month_ipca_projection()
155
152
  else:
156
153
  raise ValueError("Projection type not supported.")
154
+
155
+
156
+ def calculate_spreads(
157
+ spread_type: str, reference_date: str | pd.Timestamp | None = None
158
+ ) -> pd.DataFrame:
159
+ """
160
+ Calculates spreads between assets based on the specified spread type.
161
+ If no reference date is provided, the function uses the previous business day.
162
+
163
+ Parameters:
164
+ spread_type (str): The type of spread to calculate. Available options are:
165
+ - "DI_vs_PRE": the spread between DI Futures and Treasury Pre-Fixed bonds.
166
+ reference_date (str | pd.Timestamp, optional): The reference date for the
167
+ spread calculation. If None or not provided, defaults to the previous
168
+ business day according to the Brazilian calendar.
169
+
170
+ Returns:
171
+ pd.DataFrame: A DataFrame containing the calculated spread in basis points.
172
+ The data is sorted by asset type and maturity/expiration date.
173
+
174
+ Raises:
175
+ ValueError: If an invalid spread type is provided.
176
+ """
177
+ # Normalize the reference date
178
+ normalized_date = _normalize_date(reference_date)
179
+ if spread_type.upper() == "DI_VS_PRE":
180
+ return sp.calculate_di_spreads(normalized_date)
181
+ else:
182
+ raise ValueError("Invalid spread type.")
@@ -0,0 +1,4 @@
1
+ from .historical import fetch_historical_df
2
+ from .intraday import fetch_intraday_df
3
+
4
+ __all__ = ["fetch_historical_df", "fetch_intraday_df"]
@@ -3,7 +3,18 @@ import io
3
3
  import pandas as pd
4
4
  import requests
5
5
 
6
- from ... import bday
6
+ from .. import bday
7
+
8
+ COUNT_CONVENTIONS = {
9
+ "DAP": 252,
10
+ "DI1": 252,
11
+ "DDI": 360,
12
+ "FRC": None,
13
+ "DOL": None,
14
+ "WDO": None,
15
+ "IND": None,
16
+ "WIN": None,
17
+ }
7
18
 
8
19
 
9
20
  def get_expiration_date(expiration_code: str) -> pd.Timestamp:
@@ -141,12 +152,17 @@ def convert_prices_to_rates(
141
152
  prices (pd.Series): The futures prices to be converted.
142
153
  days_to_expiration (pd.Series): The number of days to expiration for each price.
143
154
  count_convention (int): The count convention for the DI futures contract.
144
- Normally, it is 252 business days or 360 calendar days.
155
+ Can be 252 business days or 360 calendar days.
145
156
 
146
157
  Returns:
147
158
  pd.Series: A pd.Series containing the futures rates.
148
159
  """
149
- rates = (100_000 / prices) ** (count_convention / days_to_expiration) - 1
160
+ if count_convention == 252:
161
+ rates = (100_000 / prices) ** (252 / days_to_expiration) - 1
162
+ elif count_convention == 360:
163
+ rates = (100_000 / prices - 1) * (360 / days_to_expiration)
164
+ else:
165
+ raise ValueError("Invalid count_convention. Must be 252 or 360.")
150
166
 
151
167
  # Round to 5 (3 in %) dec. places (contract's current max. precision)
152
168
  return rates.round(5)
@@ -198,6 +214,16 @@ def fetch_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
198
214
  return df
199
215
 
200
216
 
217
+ def _adjust_older_contracts_rates(df: pd.DataFrame, rate_cols: list) -> pd.DataFrame:
218
+ for col in rate_cols:
219
+ df[col] = convert_prices_to_rates(df[col], df["BDaysToExp"], 252)
220
+
221
+ # Invert low and high prices
222
+ df["MinRate"], df["MaxRate"] = df["MaxRate"], df["MinRate"]
223
+
224
+ return df
225
+
226
+
201
227
  def rename_columns(df: pd.DataFrame) -> pd.DataFrame:
202
228
  all_columns = {
203
229
  "VENCTO": "ExpirationCode",
@@ -224,11 +250,11 @@ def rename_columns(df: pd.DataFrame) -> pd.DataFrame:
224
250
  return df.rename(columns=rename_dict)
225
251
 
226
252
 
227
- def process_raw_df(
228
- df: pd.DataFrame, trade_date: pd.Timestamp, asset_code: str
253
+ def process_df(
254
+ df: pd.DataFrame,
255
+ trade_date: pd.Timestamp,
256
+ asset_code: str,
229
257
  ) -> pd.DataFrame:
230
- df = rename_columns(df)
231
-
232
258
  df["TradeDate"] = trade_date
233
259
  # Convert to datetime64[ns] since it is pandas default type for timestamps
234
260
  df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
@@ -243,6 +269,14 @@ def process_raw_df(
243
269
  else:
244
270
  df["ExpirationDate"] = df["ExpirationCode"].apply(get_expiration_date)
245
271
 
272
+ df["DaysToExp"] = (df["ExpirationDate"] - trade_date).dt.days
273
+ # Convert to nullable integer, since it is the default type in the library
274
+ df["DaysToExp"] = df["DaysToExp"].astype(pd.Int64Dtype())
275
+ # Remove expired contracts
276
+ df.query("DaysToExp > 0", inplace=True)
277
+
278
+ df["BDaysToExp"] = bday.count_bdays(trade_date, df["ExpirationDate"])
279
+
246
280
  # Columns where 0 means NaN
247
281
  cols_with_nan = [col for col in df.columns if "Rate" in col]
248
282
  if "SettlementPrice" in df.columns:
@@ -250,6 +284,27 @@ def process_raw_df(
250
284
  # Replace 0 with NaN in these columns
251
285
  df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
252
286
 
287
+ rate_cols = [col for col in df.columns if "Rate" in col]
288
+ # Prior to 17/01/2002 (inclusive), DI prices were not converted to rates
289
+ if trade_date <= pd.Timestamp("2002-01-17") and asset_code == "DI1":
290
+ df = _adjust_older_contracts_rates(df, rate_cols)
291
+ else:
292
+ # Remove % and round to 5 (3 in %) dec. places in rate columns
293
+ df[rate_cols] = df[rate_cols].div(100).round(5)
294
+
295
+ if COUNT_CONVENTIONS[asset_code] == 252:
296
+ df["SettlementRate"] = convert_prices_to_rates(
297
+ prices=df["SettlementPrice"],
298
+ days_to_expiration=df["BDaysToExp"],
299
+ count_convention=252,
300
+ )
301
+ elif COUNT_CONVENTIONS[asset_code] == 360:
302
+ df["SettlementRate"] = convert_prices_to_rates(
303
+ prices=df["SettlementPrice"],
304
+ days_to_expiration=df["DaysToExp"],
305
+ count_convention=360,
306
+ )
307
+
253
308
  return df
254
309
 
255
310
 
@@ -279,3 +334,31 @@ def reorder_columns(df: pd.DataFrame):
279
334
  ]
280
335
  reordered_columns = [col for col in all_columns if col in df.columns]
281
336
  return df[reordered_columns]
337
+
338
+
339
+ def fetch_historical_df(
340
+ asset_code: str,
341
+ trade_date: pd.Timestamp,
342
+ ) -> pd.DataFrame:
343
+ """
344
+ Fetchs the futures data for a given date from B3.
345
+
346
+ This function fetches and processes the futures data from B3 for a specific
347
+ trade date. It's the primary external interface for accessing futures data.
348
+
349
+ Args:
350
+ asset_code (str): The asset code to fetch the futures data.
351
+ trade_date (pd.Timestamp): The trade date to fetch the futures data.
352
+ count_convention (int): The count convention for the DI futures contract.
353
+ Can be 252 business days or 360 calendar days.
354
+
355
+ Returns:
356
+ pd.DataFrame: A Pandas pd.DataFrame containing processed futures data.
357
+ """
358
+ df_raw = fetch_raw_df(asset_code=asset_code, trade_date=trade_date)
359
+ if df_raw.empty:
360
+ return df_raw
361
+ df = rename_columns(df_raw)
362
+ df = process_df(df, trade_date, asset_code)
363
+ df = reorder_columns(df)
364
+ return df
@@ -96,7 +96,7 @@ def _process_raw_df(raw_df: pd.DataFrame) -> pd.DataFrame:
96
96
  return df[rename_dict.values()]
97
97
 
98
98
 
99
- def fetch_intraday(future_code: str) -> pd.DataFrame:
99
+ def fetch_intraday_df(future_code: str) -> pd.DataFrame:
100
100
  """
101
101
  Fetch the latest DI futures data from B3.
102
102
 
@@ -0,0 +1,56 @@
1
+ import pandas as pd
2
+
3
+ from . import treasuries as tr
4
+ from .futures import historical as fh
5
+
6
+ # Constant for conversion to basis points
7
+ BPS_CONVERSION_FACTOR = 10_000
8
+
9
+
10
+ def calculate_di_spreads(reference_date: pd.Timestamp) -> pd.DataFrame:
11
+ """
12
+ Calculates the DI spread for Brazilian treasury bonds (LTN and NTN-F) based on
13
+ ANBIMA's indicative rates.
14
+
15
+ This function fetches the indicative rates for Brazilian treasury securities (LTN
16
+ and NTN-F bonds) and the DI futures rates for a specified reference date,
17
+ calculating the spread between these rates in basis points. If no reference date is
18
+ provided, the function uses the previous business day.
19
+
20
+ Parameters:
21
+ reference_date (str | pd.Timestamp, optional): The reference date for the DI
22
+ spread calculation.
23
+
24
+ Returns:
25
+ pd.DataFrame: A DataFrame containing the bond type, reference date, maturity
26
+ date, and the calculated DI spread in basis points. The data is sorted by
27
+ bond type and maturity date.
28
+ """
29
+ # Fetch DI rates for the reference date
30
+ df_di = fh.fetch_historical_df(asset_code="DI1", trade_date=reference_date)[
31
+ ["ExpirationDate", "SettlementRate"]
32
+ ]
33
+
34
+ # Renaming the columns to match the ANBIMA structure
35
+ df_di.rename(columns={"ExpirationDate": "MaturityDate"}, inplace=True)
36
+
37
+ # Adjusting maturity date to match bond data format
38
+ df_di["MaturityDate"] = df_di["MaturityDate"].dt.to_period("M").dt.to_timestamp()
39
+
40
+ # Fetch bond rates, filtering for LTN and NTN-F types
41
+ df_anbima = tr.fetch_bonds(reference_date, False)
42
+ df_anbima.query("BondType in ['LTN', 'NTN-F']", inplace=True)
43
+
44
+ # Merge bond and DI rates by maturity date to calculate spreads
45
+ df_final = pd.merge(df_anbima, df_di, how="left", on="MaturityDate")
46
+
47
+ # Calculate the DI spread as the difference between indicative and settlement rates
48
+ df_final["DISpread"] = df_final["IndicativeRate"] - df_final["SettlementRate"]
49
+
50
+ # Convert spread to basis points for clarity
51
+ df_final["DISpread"] = (BPS_CONVERSION_FACTOR * df_final["DISpread"]).round(2)
52
+
53
+ # Prepare and return the final sorted DataFrame
54
+ select_columns = ["BondType", "ReferenceDate", "MaturityDate", "DISpread"]
55
+ df_final = df_final[select_columns].copy()
56
+ return df_final.sort_values(["BondType", "MaturityDate"], ignore_index=True)
@@ -3,15 +3,10 @@ import io
3
3
  import pandas as pd
4
4
  import requests
5
5
 
6
- from .futures import historical as fh
7
-
8
6
  # URL Constants
9
7
  ANBIMA_NON_MEMBER_URL = "https://www.anbima.com.br/informacoes/merc-sec/arqs/"
10
8
  ANBIMA_MEMBER_URL = "http://www.anbima.associados.rtm/merc_sec/arqs/"
11
9
 
12
- # Constant for conversion to basis points
13
- BPS_CONVERSION_FACTOR = 10_000
14
-
15
10
 
16
11
  def _get_anbima_content(reference_date: pd.Timestamp) -> str:
17
12
  url_date = reference_date.strftime("%y%m%d")
@@ -128,50 +123,3 @@ def fetch_bonds(reference_date: pd.Timestamp, return_raw=False) -> pd.DataFrame:
128
123
  df = _process_raw_df(df)
129
124
 
130
125
  return df
131
-
132
-
133
- def calculate_di_spreads(reference_date: pd.Timestamp) -> pd.DataFrame:
134
- """
135
- Calculates the DI spread for Brazilian treasury bonds (LTN and NTN-F) based on
136
- ANBIMA's indicative rates.
137
-
138
- This function fetches the indicative rates for Brazilian treasury securities (LTN
139
- and NTN-F bonds) and the DI futures rates for a specified reference date,
140
- calculating the spread between these rates in basis points. If no reference date is
141
- provided, the function uses the previous business day.
142
-
143
- Parameters:
144
- reference_date (str | pd.Timestamp, optional): The reference date for the DI
145
- spread calculation.
146
-
147
- Returns:
148
- pd.DataFrame: A DataFrame containing the bond type, reference date, maturity
149
- date, and the calculated DI spread in basis points. The data is sorted by
150
- bond type and maturity date.
151
- """
152
- # Fetch DI rates and adjust the maturity date format for compatibility
153
- df_di = fh.fetch_di(reference_date)[["ExpirationDate", "SettlementRate"]]
154
-
155
- # Renaming the columns to match the ANBIMA structure
156
- df_di.rename(columns={"ExpirationDate": "MaturityDate"}, inplace=True)
157
-
158
- # Adjusting maturity date to match bond data format
159
- df_di["MaturityDate"] = df_di["MaturityDate"].dt.to_period("M").dt.to_timestamp()
160
-
161
- # Fetch bond rates, filtering for LTN and NTN-F types
162
- df_anbima = fetch_bonds(reference_date, False)
163
- df_anbima.query("BondType in ['LTN', 'NTN-F']", inplace=True)
164
-
165
- # Merge bond and DI rates by maturity date to calculate spreads
166
- df_final = pd.merge(df_anbima, df_di, how="left", on="MaturityDate")
167
-
168
- # Calculate the DI spread as the difference between indicative and settlement rates
169
- df_final["DISpread"] = df_final["IndicativeRate"] - df_final["SettlementRate"]
170
-
171
- # Convert spread to basis points for clarity
172
- df_final["DISpread"] = (BPS_CONVERSION_FACTOR * df_final["DISpread"]).round(2)
173
-
174
- # Prepare and return the final sorted DataFrame
175
- select_columns = ["BondType", "ReferenceDate", "MaturityDate", "DISpread"]
176
- df_final = df_final[select_columns].copy()
177
- return df_final.sort_values(["BondType", "MaturityDate"], ignore_index=True)
@@ -32,7 +32,7 @@ dependencies = [
32
32
  "requests>=2.31.0",
33
33
  ]
34
34
  dynamic = []
35
- version = "0.7.8"
35
+ version = "0.7.9"
36
36
 
37
37
  [project.license]
38
38
  file = "LICENSE"
@@ -7,8 +7,8 @@ import requests
7
7
  from lxml import etree
8
8
  from pandas import DataFrame, Timestamp
9
9
 
10
- from ... import bday
11
- from . import common as cm
10
+ from ..pyield import bday
11
+ from ..pyield.futures import historical as ht
12
12
 
13
13
 
14
14
  def _get_file_from_url(trade_date: Timestamp, source_type: str) -> io.BytesIO:
@@ -229,7 +229,7 @@ def _process_di_df(df_raw: DataFrame) -> DataFrame:
229
229
  # Convert to datetime64[ns] since it is pandas default type for timestamps
230
230
  df["TradDt"] = df["TradDt"].astype("datetime64[ns]")
231
231
 
232
- expiration = df["TckrSymb"].str[3:].apply(cm.get_expiration_date)
232
+ expiration = df["TckrSymb"].str[3:].apply(ht.get_expiration_date)
233
233
  df.insert(2, "ExpirationDate", expiration)
234
234
 
235
235
  business_days = bday.count_bdays(df["TradDt"], df["ExpirationDate"])
@@ -1 +0,0 @@
1
- __version__ = "0.7.8"
@@ -1,33 +0,0 @@
1
- import pandas as pd
2
-
3
- from . import treasuries as tr
4
- from .utils import _normalize_date
5
-
6
-
7
- def calculate_spreads(
8
- spread_type: str, reference_date: str | pd.Timestamp | None = None
9
- ) -> pd.DataFrame:
10
- """
11
- Calculates spreads between assets based on the specified spread type.
12
- If no reference date is provided, the function uses the previous business day.
13
-
14
- Parameters:
15
- spread_type (str): The type of spread to calculate. Available options are:
16
- - "DI_vs_PRE": the spread between DI Futures and Treasury Pre-Fixed bonds.
17
- reference_date (str | pd.Timestamp, optional): The reference date for the
18
- spread calculation. If None or not provided, defaults to the previous
19
- business day according to the Brazilian calendar.
20
-
21
- Returns:
22
- pd.DataFrame: A DataFrame containing the calculated spread in basis points.
23
- The data is sorted by asset type and maturity/expiration date.
24
-
25
- Raises:
26
- ValueError: If an invalid spread type is provided.
27
- """
28
- # Normalize the reference date
29
- normalized_date = _normalize_date(reference_date)
30
- if spread_type.lower() == "di_vs_pre":
31
- return tr.calculate_di_spreads(normalized_date)
32
- else:
33
- raise ValueError("Invalid spread type.")
@@ -1,6 +0,0 @@
1
- from .dap import fetch_dap
2
- from .ddi import fetch_ddi
3
- from .di import fetch_di
4
- from .frc import fetch_frc
5
-
6
- __all__ = ["fetch_di", "fetch_ddi", "fetch_frc", "fetch_dap"]
@@ -1,62 +0,0 @@
1
- import pandas as pd
2
-
3
- from ... import bday as bd
4
- from . import common as cm
5
-
6
-
7
- def _process_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
8
- """
9
- Internal function to process and transform raw DI futures data.
10
-
11
- Args:
12
- df (pd.DataFrame): the raw DI DataFrame.
13
- trade_date: a datetime-like object representing the trade date.
14
-
15
- Returns:
16
- pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
17
- """
18
- df["BDaysToExp"] = bd.count_bdays(trade_date, df["ExpirationDate"])
19
-
20
- # Remove expired contracts
21
- df.query("BDaysToExp > 0", inplace=True)
22
-
23
- rate_cols = [col for col in df.columns if "Rate" in col]
24
- # Remove % and round to 5 (3 in %) dec. places in rate columns
25
- df[rate_cols] = df[rate_cols].div(100).round(5)
26
-
27
- # Calculate SettlementRate
28
- df["SettlementRate"] = cm.convert_prices_to_rates(
29
- prices=df["SettlementPrice"],
30
- days_to_expiration=df["BDaysToExp"],
31
- count_convention=252,
32
- )
33
-
34
- return df
35
-
36
-
37
- def fetch_dap(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
38
- """
39
- Fetchs the DI futures data for a given date from B3.
40
-
41
- This function fetches and processes the DI futures data from B3 for a specific
42
- trade date. It's the primary external interface for accessing DI data. If the data
43
- is not available, an empty DataFrame is returned.
44
-
45
- Args:
46
- trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
47
- return_raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
48
- Defaults to False.
49
-
50
- Returns:
51
- pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
52
-
53
- Notes:
54
- - BDaysToExp: number of business days to ExpirationDate.
55
- - OpenContracts: number of open contracts at the start of the trading day.
56
- """
57
- df_raw = cm.fetch_raw_df(asset_code="DI1", trade_date=trade_date)
58
- if return_raw or df_raw.empty:
59
- return df_raw
60
- df = cm.process_raw_df(df_raw, trade_date, asset_code="DI1")
61
- df = _process_df(df, trade_date)
62
- return cm.reorder_columns(df)
@@ -1,80 +0,0 @@
1
- import pandas as pd
2
-
3
- from . import common as cm
4
-
5
-
6
- def _convert_prices_to_rates(prices: pd.Series, n_days: pd.Series) -> pd.Series:
7
- """
8
- Internal function to convert DDI futures prices to rates.
9
-
10
- Args:
11
- prices (pd.Series): A pd.Series containing DDI futures prices.
12
- bd (pd.Series): A serie containing the number of days to expiration.
13
-
14
- Returns:
15
- pd.Series: A pd.Series containing DDI futures rates.
16
- """
17
- rates = (100_000 / prices - 1) * (360 / n_days)
18
- # Round to 5 (3 in %) dec. places (contract's current max. precision)
19
- return rates.round(5)
20
-
21
-
22
- def _process_ddi_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
23
- """
24
- Internal function to process and transform raw DI futures data.
25
-
26
- Args:
27
- df (pd.DataFrame): the raw DI DataFrame.
28
- trade_date: a datetime-like object representing the trade date.
29
-
30
- Returns:
31
- pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
32
- """
33
- df["DaysToExp"] = (df["ExpirationDate"] - trade_date).dt.days
34
- # Convert to nullable integer, since it is the default type in the library
35
- df["DaysToExp"] = df["DaysToExp"].astype(pd.Int64Dtype())
36
-
37
- # Remove expired contracts
38
- df.query("DaysToExp > 0", inplace=True)
39
-
40
- # Columns where 0 means NaN
41
- rate_cols = [col for col in df.columns if "Rate" in col]
42
- df[rate_cols] = df[rate_cols].div(100).round(5)
43
-
44
- # Calculate SettlementRate
45
- df["SettlementRate"] = _convert_prices_to_rates(
46
- df["SettlementPrice"], df["DaysToExp"]
47
- )
48
-
49
- return df
50
-
51
-
52
- def fetch_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
53
- """
54
- Fetchs the DDI futures data for a given date from B3.
55
-
56
- This function fetches and processes the DI futures data from B3 for a specific
57
- trade date. It's the primary external interface for accessing DI data.
58
-
59
- Args:
60
- trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
61
- raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
62
- Defaults to False.
63
-
64
- Returns:
65
- pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
66
-
67
- Examples:
68
- >>> from pyield.futures import di
69
- >>> di.fetch_ddi(pd.Timestamp("2021-01-04"))
70
-
71
- Notes:
72
- - DaysToExp: number of business days to ExpirationDate.
73
- - OpenContracts: number of open contracts at the start of the trading day.
74
- """
75
- df_raw = cm.fetch_raw_df(asset_code="DDI", trade_date=trade_date)
76
- if return_raw or df_raw.empty:
77
- return df_raw
78
- df = cm.process_raw_df(df_raw, trade_date, asset_code="DDI")
79
- df = _process_ddi_df(df, trade_date)
80
- return cm.reorder_columns(df)
@@ -1,91 +0,0 @@
1
- import pandas as pd
2
-
3
- from ... import bday as bd
4
- from . import common as cm
5
-
6
-
7
- def _convert_prices_to_rates(prices: pd.Series, bd: pd.Series) -> pd.Series:
8
- """
9
- Internal function to convert DI futures prices to rates.
10
-
11
- Args:
12
- prices (pd.Series): A pd.Series containing DI futures prices.
13
- bd (pd.Series): A serie containing the number of business days to expiration.
14
-
15
- Returns:
16
- pd.Series: A pd.Series containing DI futures rates.
17
- """
18
- rates = (100_000 / prices) ** (252 / bd) - 1
19
-
20
- # Round to 5 (3 in %) dec. places (contract's current max. precision)
21
- return rates.round(5)
22
-
23
-
24
- def _adjust_older_contracts_rates(df: pd.DataFrame, rate_cols: list) -> pd.DataFrame:
25
- for col in rate_cols:
26
- df[col] = _convert_prices_to_rates(df[col], df["BDaysToExp"])
27
-
28
- # Invert low and high prices
29
- df["MinRate"], df["MaxRate"] = df["MaxRate"], df["MinRate"]
30
-
31
- return df
32
-
33
-
34
- def _process_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
35
- """
36
- Internal function to process and transform raw DI futures data.
37
-
38
- Args:
39
- df (pd.DataFrame): the raw DI DataFrame.
40
- trade_date: a datetime-like object representing the trade date.
41
-
42
- Returns:
43
- pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
44
- """
45
- df["BDaysToExp"] = bd.count_bdays(trade_date, df["ExpirationDate"])
46
-
47
- # Remove expired contracts
48
- df.query("BDaysToExp > 0", inplace=True)
49
-
50
- rate_cols = [col for col in df.columns if "Rate" in col]
51
- # Prior to 17/01/2002 (inclusive), prices were not converted to rates
52
- if trade_date > pd.Timestamp("2002-01-17"):
53
- # Remove % and round to 5 (3 in %) dec. places in rate columns
54
- df[rate_cols] = df[rate_cols].div(100).round(5)
55
- else:
56
- df = _adjust_older_contracts_rates(df, rate_cols)
57
-
58
- # Calculate SettlementRate
59
- df["SettlementRate"] = _convert_prices_to_rates(
60
- df["SettlementPrice"], df["BDaysToExp"]
61
- )
62
-
63
- return df
64
-
65
-
66
- def fetch_di(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
67
- """
68
- Fetchs the DI futures data for a given date from B3.
69
-
70
- This function fetches and processes the DI futures data from B3 for a specific
71
- trade date. It's the primary external interface for accessing DI data. If the data
72
- is not available, an empty DataFrame is returned.
73
-
74
- Args:
75
- trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
76
- return_raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
77
- Defaults to False.
78
-
79
- Returns:
80
- pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
81
-
82
- Notes:
83
- - BDaysToExp: number of business days to ExpirationDate.
84
- - OpenContracts: number of open contracts at the start of the trading day.
85
- """
86
- df_raw = cm.fetch_raw_df(asset_code="DI1", trade_date=trade_date)
87
- if return_raw or df_raw.empty:
88
- return df_raw
89
- df = cm.process_raw_df(df_raw, trade_date, asset_code="DI1")
90
- df = _process_df(df, trade_date)
91
- return cm.reorder_columns(df)
@@ -1,60 +0,0 @@
1
- import pandas as pd
2
-
3
- from . import common as cm
4
-
5
-
6
- def _process_frc_df(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
- df = cm.rename_columns(df)
18
-
19
- df["TradeDate"] = trade_date
20
- # Convert to datetime64[ns] since it is pandas default type for timestamps
21
- df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
22
-
23
- # Contract code format was changed in 22/05/2006
24
- if trade_date < pd.Timestamp("2006-05-22"):
25
- df["ExpirationDate"] = df["ExpirationCode"].apply(
26
- cm.get_old_expiration_date, args=(trade_date,)
27
- )
28
- else:
29
- df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
30
-
31
- # Replace 0 values in rate columns with pd.NA and remove percentage
32
- rate_cols = [col for col in df.columns if "Rate" in col]
33
- # Round to 5 decimal places (3 in %) since it is the contract's precision
34
- df[rate_cols] = df[rate_cols].replace(0, pd.NA).div(100).round(5)
35
-
36
- return df
37
-
38
-
39
- def fetch_frc(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
40
- """
41
- Fetchs the DI futures data for a given date from B3.
42
-
43
- This function fetches and processes the DI futures data from B3 for a specific
44
- trade date. It's the primary external interface for accessing DI data.
45
-
46
- Args:
47
- trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
48
- raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
49
- Defaults to False.
50
-
51
- Returns:
52
- pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
53
- """
54
- df_raw = cm.fetch_raw_df(asset_code="FRC", trade_date=trade_date)
55
- if return_raw or df_raw.empty:
56
- return df_raw
57
- # Filter and order columns
58
- df = cm.process_raw_df(df_raw, trade_date, asset_code="FRC")
59
- df = _process_frc_df(df, trade_date)
60
- return cm.reorder_columns(df)
@@ -1,3 +0,0 @@
1
- from .trading_data import fetch_intraday
2
-
3
- __all__ = ["fetch_intraday"]
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