PYield 0.26.5__tar.gz → 0.26.7__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.26.5 → pyield-0.26.7}/PKG-INFO +1 -1
  2. pyield-0.26.7/pyield/__about__.py +1 -0
  3. pyield-0.26.7/pyield/ima.py +156 -0
  4. pyield-0.26.5/pyield/__about__.py +0 -1
  5. pyield-0.26.5/pyield/ima.py +0 -143
  6. {pyield-0.26.5 → pyield-0.26.7}/.gitignore +0 -0
  7. {pyield-0.26.5 → pyield-0.26.7}/LICENSE +0 -0
  8. {pyield-0.26.5 → pyield-0.26.7}/README.md +0 -0
  9. {pyield-0.26.5 → pyield-0.26.7}/pyield/__init__.py +0 -0
  10. {pyield-0.26.5 → pyield-0.26.7}/pyield/anbima.py +0 -0
  11. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/__init__.py +0 -0
  12. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/common.py +0 -0
  13. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/di.py +0 -0
  14. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/historical.py +0 -0
  15. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/intraday.py +0 -0
  16. {pyield-0.26.5 → pyield-0.26.7}/pyield/b3_futures/xml.py +0 -0
  17. {pyield-0.26.5 → pyield-0.26.7}/pyield/bc/auction.py +0 -0
  18. {pyield-0.26.5 → pyield-0.26.7}/pyield/bday.py +0 -0
  19. {pyield-0.26.5 → pyield-0.26.7}/pyield/conftest.py +0 -0
  20. {pyield-0.26.5 → pyield-0.26.7}/pyield/data_cache.py +0 -0
  21. {pyield-0.26.5 → pyield-0.26.7}/pyield/date_converter.py +0 -0
  22. {pyield-0.26.5 → pyield-0.26.7}/pyield/holidays/__init__.py +0 -0
  23. {pyield-0.26.5 → pyield-0.26.7}/pyield/holidays/br_holidays_new.txt +0 -0
  24. {pyield-0.26.5 → pyield-0.26.7}/pyield/holidays/br_holidays_old.txt +0 -0
  25. {pyield-0.26.5 → pyield-0.26.7}/pyield/holidays/brholidays.py +0 -0
  26. {pyield-0.26.5 → pyield-0.26.7}/pyield/indicators.py +0 -0
  27. {pyield-0.26.5 → pyield-0.26.7}/pyield/interpolator.py +0 -0
  28. {pyield-0.26.5 → pyield-0.26.7}/pyield/projections.py +0 -0
  29. {pyield-0.26.5 → pyield-0.26.7}/pyield/py.typed +0 -0
  30. {pyield-0.26.5 → pyield-0.26.7}/pyield/tools.py +0 -0
  31. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/__init__.py +0 -0
  32. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/lft.py +0 -0
  33. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/ltn.py +0 -0
  34. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/ntnb.py +0 -0
  35. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/ntnf.py +0 -0
  36. {pyield-0.26.5 → pyield-0.26.7}/pyield/tpf/tools.py +0 -0
  37. {pyield-0.26.5 → pyield-0.26.7}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PYield
3
- Version: 0.26.5
3
+ Version: 0.26.7
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.26.7"
@@ -0,0 +1,156 @@
1
+ import io
2
+ import logging
3
+ from typing import Literal
4
+
5
+ import pandas as pd
6
+ import requests
7
+
8
+ ima_types = Literal[
9
+ "IRF-M 1",
10
+ "IRF-M 1+",
11
+ "IRF-M",
12
+ "IMA-B 5",
13
+ "IMA-B 5+",
14
+ "IMA-B",
15
+ "IMA-S",
16
+ "IMA-GERAL-EX-C",
17
+ "IMA-GERAL",
18
+ ]
19
+
20
+ LAST_IMA_COL_MAPPING = {
21
+ # "2",
22
+ "Data de Referência": "Date",
23
+ "INDICE": "IMAType",
24
+ "Títulos": "BondType",
25
+ "Data de Vencimento": "Maturity",
26
+ "Código SELIC": "SelicCode",
27
+ "Código ISIN": "ISIN",
28
+ "Taxa Indicativa (% a.a.)": "IndicativeRate",
29
+ "PU (R$)": "Price",
30
+ # "PU de Juros (R$)": "InterestPrice",
31
+ "Quantidade (1.000 títulos)": "MarketQuantity",
32
+ "Quantidade Teórica (1.000 títulos)": "TheoreticalQuantity",
33
+ "Carteira a Mercado (R$ mil)": "MarketValue",
34
+ "Peso (%)": "Weight",
35
+ "Prazo (d.u.)": "BDToMat",
36
+ "Duration (d.u.)": "Duration",
37
+ # "Número de Operações *": "NumberOfOperations",
38
+ # "Quant. Negociada (1.000 títulos) *": "NegotiatedQuantity",
39
+ # "Valor Negociado (R$ mil) *": "NegotiatedValue",
40
+ "PMR": "PMR", # Prazmo médio de repactuação
41
+ "Convexidade": "Convexity",
42
+ }
43
+
44
+
45
+ LAST_IMA_URL = "https://www.anbima.com.br/informacoes/ima/arqs/ima_completo.txt"
46
+
47
+
48
+ def _fetch_last_ima() -> pd.DataFrame:
49
+ r = requests.get(LAST_IMA_URL)
50
+ r.raise_for_status()
51
+ r.encoding = "latin1"
52
+ text = r.text.split("2@COMPOSIÇÃO DE CARTEIRA")[1].strip()
53
+ string_io_buffer = io.StringIO(text)
54
+
55
+ df = pd.read_csv(
56
+ string_io_buffer,
57
+ sep="@",
58
+ decimal=",",
59
+ thousands=".",
60
+ dtype_backend="numpy_nullable",
61
+ )
62
+
63
+ return df
64
+
65
+
66
+ def _process_last_ima(df: pd.DataFrame) -> pd.DataFrame:
67
+ df = df.rename(columns=LAST_IMA_COL_MAPPING)[LAST_IMA_COL_MAPPING.values()]
68
+ df["IndicativeRate"] = (df["IndicativeRate"] / 100).round(6)
69
+ df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y")
70
+ df["Maturity"] = pd.to_datetime(df["Maturity"], format="%d/%m/%Y")
71
+ df["MarketQuantity"] = (1000 * df["MarketQuantity"]).astype("Int64")
72
+ df["Price"] = df["Price"].round(6)
73
+ # Duration is in business days, convert to years
74
+ df["Duration"] /= 252
75
+ mduration = df["Duration"] / (1 + df["IndicativeRate"])
76
+ dv01 = 0.0001 * df["Price"] * mduration * df["MarketQuantity"]
77
+ # Since DV01 and MarketValue are total stock values, we round them to integers
78
+ df["MarketDV01"] = dv01.round(0).astype("Int64")
79
+ df["MarketValue"] = (1000 * df["MarketValue"]).round(0).astype("Int64")
80
+ # LFT DV01 is zero
81
+ df["MarketDV01"] = df["MarketDV01"].where(df["BondType"] != "LFT", 0)
82
+ return df
83
+
84
+
85
+ def _reorder_last_ima(df: pd.DataFrame) -> pd.DataFrame:
86
+ col_order = [
87
+ "Date",
88
+ "IMAType",
89
+ "BondType",
90
+ "Maturity",
91
+ "SelicCode",
92
+ "ISIN",
93
+ "Weight",
94
+ "IndicativeRate",
95
+ "Price",
96
+ "BDToMat",
97
+ "Duration",
98
+ "PMR",
99
+ "Convexity",
100
+ "TheoreticalQuantity",
101
+ "MarketDV01",
102
+ "MarketQuantity",
103
+ "MarketValue",
104
+ ]
105
+ return df[col_order].reset_index(drop=True)
106
+
107
+
108
+ def ima(ima_type: ima_types | None = None) -> pd.DataFrame:
109
+ """
110
+ Fetch and process the last IMA market data available from ANBIMA.
111
+
112
+ This function processes the data into a structured DataFrame.
113
+ It handles conversion of date formats, renames columns to English, and converts
114
+ certain numeric columns to integer types. In the event of an error during data
115
+ fetching or processing, an empty DataFrame is returned.
116
+
117
+ Args:
118
+ ima_type (str, optional): Type of IMA index to filter the data. If None, all
119
+ IMA indexes are returned. Defaults to None.
120
+
121
+ Returns:
122
+ pd.DataFrame: A DataFrame containing the IMA data with the following columns:
123
+ - Date: Reference date of the data.
124
+ - Index: IMA index.
125
+ - BondType: Type of bond.
126
+ - Maturity: Bond maturity date.
127
+ - SelicCode: Code representing the SELIC rate.
128
+ - ISIN: International Securities Identification Number.
129
+ - Price: Bond price.
130
+ - Weight: Weight of the bond in the index.
131
+ - BDToMat: Business days to maturity.
132
+ - Duration: Duration of the bond in years.
133
+ - PMR: Average repurchase term.
134
+ - Convexity: Convexity of the bond.
135
+ - TheoreticalQuantity: Theoretical quantity.
136
+ - MarketDV01: Market DV01 in R$.
137
+ - MarketQuantity: Market quantity.
138
+ - MarketValue: Market value in R$.
139
+
140
+
141
+ Raises:
142
+ Exception: Logs error and returns an empty DataFrame if any error occurs during
143
+ fetching or processing.
144
+
145
+ """
146
+ try:
147
+ df = _fetch_last_ima()
148
+ df = _process_last_ima(df)
149
+ df = _reorder_last_ima(df)
150
+ if ima_type is not None:
151
+ df = df.query("IMAType == @ima_type").reset_index(drop=True)
152
+ df = df.sort_values(["IMAType", "BondType", "Maturity"]).reset_index(drop=True)
153
+ return df
154
+ except Exception as e:
155
+ logging.exception(f"Error fetching or processing the last IMA data: {e}")
156
+ return pd.DataFrame()
@@ -1 +0,0 @@
1
- __version__ = "0.26.5"
@@ -1,143 +0,0 @@
1
- import io
2
- import logging
3
- import re
4
- import warnings
5
-
6
- import pandas as pd
7
- import requests
8
- from bs4 import XMLParsedAsHTMLWarning
9
-
10
- from pyield import date_converter as dc
11
- from pyield.date_converter import DateScalar
12
-
13
- IMA_URL = "https://www.anbima.com.br/informacoes/ima/ima-quantidade-mercado.asp"
14
- COLUMN_MAPPING = {
15
- "Data Referência": "Date",
16
- "Título": "BondType",
17
- "Data de Vencimento": "Maturity",
18
- "Codigo Selic": "SelicCode",
19
- "Código ISIN": "ISIN",
20
- "PU (R$)": "Price",
21
- "Quantidade em Mercado (1.000 Títulos)": "MarketQuantity",
22
- "Valor de Mercado (R$ Mil)": "MarketValue",
23
- "Variação da Quantidade (1.000 Títulos)": "QuantityVariation",
24
- "Status do Titulo": "BondStatus",
25
- }
26
-
27
-
28
- def _fetch_url_tables(target_date: pd.Timestamp) -> pd.DataFrame:
29
- # Warning supression for BeautifulSoup, as the text is valid HTML and not XML
30
- warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning)
31
-
32
- target_date_str = target_date.strftime("%d/%m/%Y")
33
- payload = {
34
- "Tipo": "",
35
- "DataRef": "",
36
- "Pai": "ima",
37
- "Dt_Ref_Ver": "20250117",
38
- "Dt_Ref": f"{target_date_str}",
39
- }
40
-
41
- r = requests.post(IMA_URL, data=payload, timeout=10)
42
- r.raise_for_status()
43
- r.encoding = "iso-8859-1"
44
- if "Não há dados disponíveis" in r.text:
45
- logging.warning("No data found. Returning empty DataFrame.")
46
- return pd.DataFrame()
47
-
48
- string_io_buffer = io.StringIO(r.text)
49
-
50
- dfs = pd.read_html(
51
- string_io_buffer,
52
- flavor="html5lib",
53
- attrs={"width": "100%"},
54
- header=0,
55
- thousands=".",
56
- decimal=",",
57
- displayed_only=True,
58
- dtype_backend="numpy_nullable",
59
- )
60
-
61
- df = (
62
- pd.concat(dfs)
63
- .query("`Data de Vencimento`.notnull()")
64
- .query("Título!='Título'")
65
- .drop_duplicates(subset="Código ISIN")
66
- .reset_index(drop=True)
67
- )
68
-
69
- # Convert to CSV and then back to pandas to get automatic type conversion
70
- csv_buffer = io.StringIO(df.to_csv(index=False))
71
- df = pd.read_csv(csv_buffer, dtype_backend="numpy_nullable")
72
-
73
- # Expressão regular para datas no formato dd/mm/ano
74
- date_pattern = r"\b(\d{2}/\d{2}/\d{4})\b"
75
-
76
- # Busca pela primeira data
77
- match = re.search(date_pattern, r.text)
78
-
79
- if match:
80
- anbima_date_str = match.group(1)
81
- anbima_date = pd.to_datetime(anbima_date_str, format="%d/%m/%Y")
82
- else:
83
- logging.warning("No date found. Returning empty DataFrame.")
84
- return pd.DataFrame()
85
-
86
- df["Data Referência"] = anbima_date
87
-
88
- return df
89
-
90
-
91
- def _process_df(df: pd.DataFrame) -> pd.DataFrame:
92
- df = df.rename(columns=COLUMN_MAPPING)[COLUMN_MAPPING.values()]
93
- df["Maturity"] = pd.to_datetime(df["Maturity"], format="%d/%m/%Y")
94
- # Converter a valores para inteiros
95
- df["MarketQuantity"] = (1000 * df["MarketQuantity"]).astype("Int64")
96
- df["MarketValue"] = (1000 * df["MarketValue"]).astype("Int64")
97
- df["QuantityVariation"] = (1000 * df["QuantityVariation"]).astype("Int64")
98
-
99
- return df
100
-
101
-
102
- def ima(date: DateScalar) -> pd.DataFrame:
103
- """
104
- Fetch and process IMA market data for a given date.
105
-
106
- This function retrieves IMA market data for the specified date from ANBIMA,
107
- processes the data into a structured DataFrame, and returns the resulting DataFrame.
108
- It handles conversion of date formats, renames columns to English, and converts
109
- certain numeric columns to integer types. In the event of an error during data
110
- fetching or processing, an empty DataFrame is returned.
111
-
112
- Args:
113
- date (DateScalar): A date-like object representing the target date for fetching
114
- the data.
115
-
116
- Returns:
117
- pd.DataFrame: A DataFrame containing the IMA data with the following columns:
118
- - Date: Reference date of the data.
119
- - BondType: Type of bond.
120
- - Maturity: Bond maturity date.
121
- - SelicCode: Code representing the SELIC rate.
122
- - ISIN: International Securities Identification Number.
123
- - Price: Bond price.
124
- - MarketQuantity: Market quantity (in units of 1000 bonds).
125
- - MarketValue: Market value (in units of 1000 reais).
126
- - QuantityVariation: Variation in quantity (in units of 1000 bonds).
127
- - BondStatus: Status of the bond.
128
-
129
- Raises:
130
- Exception: Logs error and returns an empty DataFrame if any error occurs during
131
- fetching or processing.
132
-
133
- """
134
- try:
135
- date = dc.convert_input_dates(date)
136
- df = _fetch_url_tables(date)
137
- df = _process_df(df)
138
- return df
139
- except Exception as e:
140
- date_str = date.strftime("%d/%m/%Y")
141
- logging.error(f"Error fetching IMA for {date_str}. Returning empty DataFrame.")
142
- logging.error(f"Error message: {e}", exc_info=True)
143
- return pd.DataFrame()
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