PYield 0.27.2__tar.gz → 0.27.3__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 (39) hide show
  1. {pyield-0.27.2 → pyield-0.27.3}/PKG-INFO +1 -1
  2. pyield-0.27.3/pyield/__about__.py +1 -0
  3. {pyield-0.27.2 → pyield-0.27.3}/pyield/__init__.py +2 -2
  4. {pyield-0.27.2 → pyield-0.27.3}/pyield/anbima/ima.py +32 -28
  5. {pyield-0.27.2 → pyield-0.27.3}/pyield/indicators.py +23 -3
  6. pyield-0.27.2/pyield/__about__.py +0 -1
  7. {pyield-0.27.2 → pyield-0.27.3}/.gitignore +0 -0
  8. {pyield-0.27.2 → pyield-0.27.3}/LICENSE +0 -0
  9. {pyield-0.27.2 → pyield-0.27.3}/README.md +0 -0
  10. {pyield-0.27.2 → pyield-0.27.3}/pyield/anbima/__init__.py +0 -0
  11. {pyield-0.27.2 → pyield-0.27.3}/pyield/anbima/imaq.py +0 -0
  12. {pyield-0.27.2 → pyield-0.27.3}/pyield/anbima/tpf.py +0 -0
  13. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/__init__.py +0 -0
  14. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/common.py +0 -0
  15. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/di.py +0 -0
  16. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/historical.py +0 -0
  17. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/intraday.py +0 -0
  18. {pyield-0.27.2 → pyield-0.27.3}/pyield/b3_futures/xml.py +0 -0
  19. {pyield-0.27.2 → pyield-0.27.3}/pyield/bc/auction.py +0 -0
  20. {pyield-0.27.2 → pyield-0.27.3}/pyield/bc/repos.py +0 -0
  21. {pyield-0.27.2 → pyield-0.27.3}/pyield/bday.py +0 -0
  22. {pyield-0.27.2 → pyield-0.27.3}/pyield/conftest.py +0 -0
  23. {pyield-0.27.2 → pyield-0.27.3}/pyield/data_cache.py +0 -0
  24. {pyield-0.27.2 → pyield-0.27.3}/pyield/date_converter.py +0 -0
  25. {pyield-0.27.2 → pyield-0.27.3}/pyield/holidays/__init__.py +0 -0
  26. {pyield-0.27.2 → pyield-0.27.3}/pyield/holidays/br_holidays_new.txt +0 -0
  27. {pyield-0.27.2 → pyield-0.27.3}/pyield/holidays/br_holidays_old.txt +0 -0
  28. {pyield-0.27.2 → pyield-0.27.3}/pyield/holidays/brholidays.py +0 -0
  29. {pyield-0.27.2 → pyield-0.27.3}/pyield/interpolator.py +0 -0
  30. {pyield-0.27.2 → pyield-0.27.3}/pyield/projections.py +0 -0
  31. {pyield-0.27.2 → pyield-0.27.3}/pyield/py.typed +0 -0
  32. {pyield-0.27.2 → pyield-0.27.3}/pyield/tools.py +0 -0
  33. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/__init__.py +0 -0
  34. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/lft.py +0 -0
  35. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/ltn.py +0 -0
  36. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/ntnb.py +0 -0
  37. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/ntnf.py +0 -0
  38. {pyield-0.27.2 → pyield-0.27.3}/pyield/tpf/tools.py +0 -0
  39. {pyield-0.27.2 → pyield-0.27.3}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PYield
3
- Version: 0.27.2
3
+ Version: 0.27.3
4
4
  Summary: A Python library for analysis of fixed income instruments in Brazil
5
5
  Project-URL: Source, https://github.com/crdcj/PYield
6
6
  Author-email: Carlos Carvalho <cr.cj@outlook.com>
@@ -0,0 +1 @@
1
+ __version__ = "0.27.3"
@@ -2,7 +2,7 @@ import logging
2
2
 
3
3
  from pyield import bday
4
4
  from pyield.__about__ import __version__
5
- from pyield.anbima.ima import ima
5
+ from pyield.anbima.ima import last_ima
6
6
  from pyield.anbima.imaq import imaq
7
7
  from pyield.anbima.tpf import anbima_tpf_data, anbima_tpf_rates, tpf_pre_maturities
8
8
  from pyield.b3_futures import futures
@@ -26,7 +26,7 @@ __all__ = [
26
26
  "DIFutures",
27
27
  "forward_rates",
28
28
  "futures",
29
- "ima",
29
+ "last_ima",
30
30
  "imaq",
31
31
  "indicator",
32
32
  "Interpolator",
@@ -5,6 +5,8 @@ from typing import Literal
5
5
  import pandas as pd
6
6
  import requests
7
7
 
8
+ logger = logging.getLogger(__name__)
9
+
8
10
  ima_types = Literal[
9
11
  "IRF-M 1",
10
12
  "IRF-M 1+",
@@ -74,11 +76,12 @@ def _process_last_ima(df: pd.DataFrame) -> pd.DataFrame:
74
76
  # Duration is in business days, convert to years
75
77
  df["Duration"] /= 252
76
78
  mduration = df["Duration"] / (1 + df["IndicativeRate"])
77
- df["DV01"] = 0.0001 * df["Price"] * mduration * df["MarketQuantity"]
78
- # Since MarketDV01 is the total stock value, we round them to integer
79
- df["MarketDV01"] = df["DV01"].round(0).astype("Int64")
79
+ df["DV01"] = 0.0001 * mduration * df["Price"]
80
80
  # LFT DV01 is zero
81
- df["MarketDV01"] = df["MarketDV01"].where(df["BondType"] != "LFT", 0)
81
+ df["DV01"] = df["DV01"].where(df["BondType"] != "LFT", 0)
82
+ # Since MarketDV01 is the total stock value, we round them to integer
83
+ df["MarketDV01"] = (df["DV01"] * df["MarketQuantity"]).round(0).astype("Int64")
84
+
82
85
  return df
83
86
 
84
87
 
@@ -91,14 +94,14 @@ def _reorder_last_ima(df: pd.DataFrame) -> pd.DataFrame:
91
94
  "SelicCode",
92
95
  "ISIN",
93
96
  "Weight",
94
- "IndicativeRate",
95
- "Price",
97
+ "TheoreticalQuantity",
98
+ "PMR",
99
+ "Convexity",
96
100
  "BDToMat",
97
101
  "Duration",
102
+ "IndicativeRate",
103
+ "Price",
98
104
  "DV01",
99
- "PMR",
100
- "Convexity",
101
- "TheoreticalQuantity",
102
105
  "MarketDV01",
103
106
  "MarketQuantity",
104
107
  "MarketValue",
@@ -106,7 +109,7 @@ def _reorder_last_ima(df: pd.DataFrame) -> pd.DataFrame:
106
109
  return df[col_order].reset_index(drop=True)
107
110
 
108
111
 
109
- def ima(ima_type: ima_types | None = None) -> pd.DataFrame:
112
+ def last_ima(ima_type: ima_types | None = None) -> pd.DataFrame:
110
113
  """
111
114
  Fetch and process the last IMA market data available from ANBIMA.
112
115
 
@@ -121,23 +124,24 @@ def ima(ima_type: ima_types | None = None) -> pd.DataFrame:
121
124
 
122
125
  Returns:
123
126
  pd.DataFrame: A DataFrame containing the IMA data with the following columns:
124
- - Date: Reference date of the data.
125
- - Index: IMA index.
126
- - BondType: Type of bond.
127
- - Maturity: Bond maturity date.
128
- - SelicCode: Code representing the SELIC rate.
129
- - ISIN: International Securities Identification Number.
130
- - Price: Bond price.
131
- - Weight: Weight of the bond in the index.
132
- - BDToMat: Business days to maturity.
133
- - Duration: Duration of the bond in years.
134
- - PMR: Average repurchase term.
135
- - Convexity: Convexity of the bond.
136
- - TheoreticalQuantity: Theoretical quantity.
137
- - MarketDV01: Market DV01 in R$.
138
- - MarketQuantity: Market quantity.
139
- - MarketValue: Market value in R$.
140
-
127
+ - Date: reference date of the data.
128
+ - IMAType: type of IMA index.
129
+ - BondType: type of bond.
130
+ - Maturity: bond maturity date.
131
+ - SelicCode: bond code in the SELIC system.
132
+ - ISIN: international Securities Identification Number.
133
+ - Weight: weight of the bond in the index.
134
+ - TheoreticalQuantity: theoretical quantity.
135
+ - PMR: average repurchase term.
136
+ - Convexity: convexity of the bond.
137
+ - BDToMat: business days to maturity.
138
+ - Duration: duration of the bond in years.
139
+ - IndicativeRate: indicative rate in percentage
140
+ - Price: bond price.
141
+ - DV01: DV01 in R$.
142
+ - MarketDV01: market DV01 in R$.
143
+ - MarketQuantity: market quantity.
144
+ - MarketValue: market value in R$.
141
145
 
142
146
  Raises:
143
147
  Exception: Logs error and returns an empty DataFrame if any error occurs during
@@ -153,5 +157,5 @@ def ima(ima_type: ima_types | None = None) -> pd.DataFrame:
153
157
  df = df.sort_values(["IMAType", "BondType", "Maturity"]).reset_index(drop=True)
154
158
  return df
155
159
  except Exception as e:
156
- logging.exception(f"Error fetching or processing the last IMA data: {e}")
160
+ logger.exception(f"Error fetching or processing the last IMA data: {e}")
157
161
  return pd.DataFrame()
@@ -263,14 +263,34 @@ def _fetch_with_retry(
263
263
  return process_response(data)
264
264
 
265
265
  except RequestException as e:
266
- msg = f"Erro ao buscar {error_message} (tentativa {attempt + 1}): {e}"
266
+ msg = f"Erro ao buscar {error_message} (tentativa {attempt + 1}): "
267
+
268
+ if hasattr(e, "response"):
269
+ response = e.response
270
+ if response is not None: # Verificação extra se response não é None
271
+ status_code = response.status_code
272
+ msg += f"Status Code: {status_code}, "
273
+ if status_code == requests.codes.not_found:
274
+ msg = f"Sem dado para {error_message} na data solicitada."
275
+ msg += f"API URL é: {api_url}"
276
+ logger.warning(msg)
277
+ return float("nan")
278
+ else:
279
+ status_code = "N/A (response is None ou response attribute não existe)"
280
+
281
+ msg += f"Exceção: {e}, Tipo da Exceção: {type(e)}"
282
+ msg += f" , Response Object Existe? {hasattr(e, 'response')}"
283
+
267
284
  logger.error(msg)
268
285
 
269
- except Exception as unhandled_error: # Outros erros - LÓGICA INESPERADA!
286
+ except Exception as unhandled_error:
270
287
  msg = f"Erro INESPERADO ao buscar {error_message}: {unhandled_error}"
271
288
  logger.exception(msg) # Loga stack trace completo para debug
289
+ break
272
290
 
273
291
  attempt += 1
274
292
  time.sleep(1.2**attempt) # Backoff exponencial
275
293
 
276
- raise ValueError(f"Falha ao buscar {error_message} após {MAX_ATTEMPTS} tentativas")
294
+ msg = f"Falha ao buscar {error_message} após {MAX_ATTEMPTS} tentativas."
295
+ msg += f" API URL: {api_url}"
296
+ raise ValueError(msg)
@@ -1 +0,0 @@
1
- __version__ = "0.27.2"
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
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