PYield 0.26.4__tar.gz → 0.26.6__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.4 → pyield-0.26.6}/PKG-INFO +1 -1
  2. pyield-0.26.6/pyield/__about__.py +1 -0
  3. {pyield-0.26.4 → pyield-0.26.6}/pyield/bc/auction.py +98 -90
  4. pyield-0.26.6/pyield/ima.py +154 -0
  5. pyield-0.26.4/pyield/__about__.py +0 -1
  6. pyield-0.26.4/pyield/ima.py +0 -143
  7. {pyield-0.26.4 → pyield-0.26.6}/.gitignore +0 -0
  8. {pyield-0.26.4 → pyield-0.26.6}/LICENSE +0 -0
  9. {pyield-0.26.4 → pyield-0.26.6}/README.md +0 -0
  10. {pyield-0.26.4 → pyield-0.26.6}/pyield/__init__.py +0 -0
  11. {pyield-0.26.4 → pyield-0.26.6}/pyield/anbima.py +0 -0
  12. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/__init__.py +0 -0
  13. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/common.py +0 -0
  14. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/di.py +0 -0
  15. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/historical.py +0 -0
  16. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/intraday.py +0 -0
  17. {pyield-0.26.4 → pyield-0.26.6}/pyield/b3_futures/xml.py +0 -0
  18. {pyield-0.26.4 → pyield-0.26.6}/pyield/bday.py +0 -0
  19. {pyield-0.26.4 → pyield-0.26.6}/pyield/conftest.py +0 -0
  20. {pyield-0.26.4 → pyield-0.26.6}/pyield/data_cache.py +0 -0
  21. {pyield-0.26.4 → pyield-0.26.6}/pyield/date_converter.py +0 -0
  22. {pyield-0.26.4 → pyield-0.26.6}/pyield/holidays/__init__.py +0 -0
  23. {pyield-0.26.4 → pyield-0.26.6}/pyield/holidays/br_holidays_new.txt +0 -0
  24. {pyield-0.26.4 → pyield-0.26.6}/pyield/holidays/br_holidays_old.txt +0 -0
  25. {pyield-0.26.4 → pyield-0.26.6}/pyield/holidays/brholidays.py +0 -0
  26. {pyield-0.26.4 → pyield-0.26.6}/pyield/indicators.py +0 -0
  27. {pyield-0.26.4 → pyield-0.26.6}/pyield/interpolator.py +0 -0
  28. {pyield-0.26.4 → pyield-0.26.6}/pyield/projections.py +0 -0
  29. {pyield-0.26.4 → pyield-0.26.6}/pyield/py.typed +0 -0
  30. {pyield-0.26.4 → pyield-0.26.6}/pyield/tools.py +0 -0
  31. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/__init__.py +0 -0
  32. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/lft.py +0 -0
  33. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/ltn.py +0 -0
  34. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/ntnb.py +0 -0
  35. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/ntnf.py +0 -0
  36. {pyield-0.26.4 → pyield-0.26.6}/pyield/tpf/tools.py +0 -0
  37. {pyield-0.26.4 → pyield-0.26.6}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PYield
3
- Version: 0.26.4
3
+ Version: 0.26.6
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.6"
@@ -1,6 +1,8 @@
1
1
  """
2
2
  Documentação da API do BC
3
- https://olinda.bcb.gov.br/olinda/servico/leiloes_selic/versao/v1/aplicacao#!/recursos/leiloesTitulosPublicos#eyJmb3JtdWxhcmlvIjp7IiRmb3JtYXQiOiJqc29uIiwiJHRvcCI6MTAwfX0=
3
+ https://olinda.bcb.gov.br/olinda/servico/leiloes_selic/versao/v1/aplicacao#!/recursos/leiloesTitulosPublicos#eyJmb3JtdWxhcmlvIjp7IiRmb3JtYXQiOiJqc29uIiwiJHRvcCI6MTAwfX0=
4
+ Exemplo de chamada:
5
+ https://olinda.bcb.gov.br/olinda/servico/leiloes_selic/versao/v1/odata/leiloesTitulosPublicos(dataMovimentoInicio=@dataMovimentoInicio,dataMovimentoFim=@dataMovimentoFim,dataLiquidacao=@dataLiquidacao,codigoTitulo=@codigoTitulo,dataVencimento=@dataVencimento,edital=@edital,tipoPublico=@tipoPublico,tipoOferta=@tipoOferta)?@dataMovimentoInicio='2025-01-30'&@dataMovimentoFim='2025-01-30'&@tipoOferta='Venda'&$top=100&$format=json
4
6
  """
5
7
 
6
8
  import io
@@ -10,7 +12,7 @@ from typing import Literal
10
12
  import pandas as pd
11
13
  import requests
12
14
 
13
- import pyield as yd
15
+ from pyield import bday
14
16
  from pyield import date_converter as dc
15
17
  from pyield.date_converter import DateScalar
16
18
  from pyield.tpf.ntnb import duration as duration_b
@@ -128,7 +130,7 @@ def _adjust_null_values(df: pd.DataFrame) -> pd.DataFrame:
128
130
 
129
131
 
130
132
  def _add_dv01(df: pd.DataFrame) -> pd.DataFrame:
131
- df["BDToMat"] = yd.bday.count(start=df["Date"], end=df["Maturity"])
133
+ df["BDToMat"] = bday.count(start=df["Date"], end=df["Maturity"])
132
134
 
133
135
  is_accepted = df["AcceptedQuantityFR"] != 0 # noqa
134
136
  df_not_accepted = df.query("~@is_accepted").reset_index(drop=True)
@@ -170,16 +172,6 @@ def _add_dv01(df: pd.DataFrame) -> pd.DataFrame:
170
172
  return df
171
173
 
172
174
 
173
- def _filter_auction_by_type(
174
- df: pd.DataFrame, auction_type: Literal["Sell", "Buy"]
175
- ) -> pd.DataFrame:
176
- auction_type_mapping = {"Venda": "Sell", "Compra": "Buy"}
177
- auction_type = auction_type_mapping.get(auction_type)
178
- if auction_type:
179
- df = df.query(f"AuctionType == '{auction_type}'").reset_index(drop=True)
180
- return df
181
-
182
-
183
175
  def _sort_and_reorder_columns(df: pd.DataFrame) -> pd.DataFrame:
184
176
  column_sequence = [
185
177
  "Date",
@@ -213,17 +205,16 @@ def _sort_and_reorder_columns(df: pd.DataFrame) -> pd.DataFrame:
213
205
  return df[column_sequence].sort_values(by=primary_sort_keys).reset_index(drop=True)
214
206
 
215
207
 
216
- def _fetch_df_from_url(
217
- url: str,
218
- auction_type: Literal["Sell", "Buy"] = None,
219
- ) -> pd.DataFrame:
208
+ def _fetch_df_from_url(url: str) -> pd.DataFrame:
220
209
  try:
221
210
  df = _load_from_url(url)
211
+ if df.empty:
212
+ logging.warning("No auction data found for the specified period.")
213
+ return pd.DataFrame()
222
214
  df = _pre_process_df(df)
223
215
  df = _adjust_null_values(df)
224
216
  df = _process_df(df)
225
217
  df = _add_dv01(df)
226
- df = _filter_auction_by_type(df, auction_type)
227
218
  df = _sort_and_reorder_columns(df)
228
219
  return df
229
220
  except Exception:
@@ -231,92 +222,109 @@ def _fetch_df_from_url(
231
222
  return pd.DataFrame()
232
223
 
233
224
 
234
- def get_all_auctions() -> pd.DataFrame:
235
- """
236
- Retrieves a DataFrame containing all public auction data from the BC.
237
-
238
- This function fetches the complete series of public auctions conducted by the
239
- National Treasury via the BC API and processes it to a standardized DataFrame.
240
-
241
- Returns:
242
- pd.DataFrame: A DataFrame sorted by Date, AuctionType, BondType, and Maturity
243
- containing auction data. In case of an error during data retrieval, an empty
244
- DataFrame is returned and an error message is logged.
245
- """
246
- # URL com toda a série de leilões de títulos públicos do Tesouro Nacional
247
- url = f"{BASE_API_URL}$format=text/csv"
248
-
249
- return _fetch_df_from_url(url)
250
-
251
-
252
225
  def auctions(
253
- start: DateScalar,
226
+ start: DateScalar | None = None,
254
227
  end: DateScalar | None = None,
255
228
  auction_type: Literal["Sell", "Buy"] = None,
256
229
  ) -> pd.DataFrame:
257
230
  """
258
- Retrieves auction data for a given date range and auction type.
259
-
260
- It fetches auction data from the BC API for the specified start and end dates.
261
- If the end date is not provided, it defaults to the start date.
262
- The resulting data is then filtered by the specified auction type ("Sell" or "Buy").
263
- "Sell" auctions are those where the National Treasury sells bonds to the market.
264
- "Buy" auctions are those where the National Treasury buys bonds from the market.
231
+ Recupera dados de leilões para um determinado período e tipo de leilão da API do BC.
232
+
233
+ **Consultas de Período:**
234
+ - Para consultar dados de um intervalo, forneça as datas de `start` e `end`.
235
+ Exemplo: `auctions(start='2024-10-20', end='2024-10-27')`
236
+ - Se apenas `start` for fornecido, a API do BC retornará dados de leilão a partir
237
+ da data de `start` **até a data mais recente disponível**.
238
+ Exemplo: `auctions(start='2024-10-20')`
239
+ - Se apenas `end` for fornecido, a API do BC retornará dados de leilão **desde a
240
+ data mais antiga disponível até a data de `end`**.
241
+ Exemplo: `auctions(end='2024-10-27')`
242
+
243
+ **Série Histórica Completa:**
244
+ - Para recuperar a série histórica completa de leilões (desde 12/11/2012 até o
245
+ último dia útil), chame a função sem fornecer os parâmetros `start` e `end`.
246
+ Exemplo: `auctions()`
247
+
248
+ Busca dados de leilões da API do BC para as datas de início e fim especificadas,
249
+ filtrando os resultados diretamente na API pelo tipo de leilão, se especificado.
250
+ O comportamento da função em relação aos parâmetros `start` e `end` segue o padrão
251
+ da API do Banco Central:
252
+ - Se `start` for fornecido e `end` não, a função retorna dados de `start` até o fim.
253
+ - Se `end` for fornecido e `start` não, a API retorna dados do início até `end`.
254
+ - Se ambos `start` e `end` forem omitidos, a API retorna a série histórica completa.
255
+
256
+ Os dados podem ser filtrados pelo tipo de leilão especificado ("Sell" ou "Buy").
257
+ Leilões de "Sell" são aqueles em que o Tesouro Nacional vende títulos ao mercado.
258
+ Leilões de "Buy" são aqueles em que o Tesouro Nacional compra títulos do mercado.
265
259
 
266
260
  Args:
267
- start (DateScalar): The start date for the auction data query.
268
- end (DateScalar | None, optional): The end date for the auction data query.
269
- If None, the start date is used. Defaults to None.
270
- auction_type (Literal["Sell", "Buy"], optional): The type of auction to filter
271
- by. Defaults to "Sell".
261
+ start (DateScalar, opcional): A data de início para a consulta dos leilões.
262
+ Se `start` for fornecido e `end` for `None`, a API retornará dados de
263
+ leilão a partir de `start` até a data mais recente disponível.
264
+ Se `start` e `end` forem `None`, a série histórica completa será retornada.
265
+ Padrão é `None`.
266
+ end (DateScalar, opcional): A data de fim para a consulta de dados de leilão.
267
+ Se `end` for fornecido e `start` for `None`, a API retornará dados de
268
+ leilão desde a data mais antiga disponível até a data de `end`.
269
+ Se `start` e `end` forem `None`, a série histórica completa será retornada.
270
+ Padrão é `None`.
271
+ auction_type (Literal["Sell", "Buy"], opcional): O tipo de leilão para filtrar
272
+ diretamente na API. Padrão é `None` (retorna todos os tipos de leilão).
272
273
 
273
274
  Returns:
274
- pd.DataFrame: A DataFrame containing auction data for the specified date range
275
- and auction type. In case of an error during data retrieval, an empty
276
- DataFrame is returned and an error message is logged.
275
+ pd.DataFrame: Um DataFrame contendo dados de leilões para o período e tipo
276
+ especificados. Em caso de erro ao buscar os dados, um DataFrame vazio
277
+ é retornado e uma mensagem de erro é registrada no log.
277
278
 
278
279
  Notes:
279
- FR = First Round
280
- SR = Second Round
281
-
282
- The DataFrame has the following columns:
283
- - Date: Date of the auction.
284
- - Settlement: Settlement date of the auction.
285
- - AuctionType: Type of auction (e.g., "Sell" or "Buy").
286
- - Ordinance: Normative ordinance associated with the auction.
287
- - Buyer: Buyer category (e.g., "TodoMercado", "SomenteDealerApto").
288
- - BondType: Category of the bond (e.g., "LTN", "LFT", "NTN-B", "NTN-F").
289
- - Maturity: Bond maturity date.
290
- - SelicCode: Bond code in the Selic system.
291
- - Value: Total value of the auction in R$ (FR + SR).
292
- - ValueFR: First round (FR) value of the auction in R$.
293
- - ValueSR: Value in the second round (SR) in R$.
294
- - OfferedQuantity: Total quantity offered in the auction (FR + SR).
295
- - OfferedQuantityFR: Quantity offered in the first round (FR).
296
- - OfferedQuantitySR: Quantity offered in the second round (SR).
297
- - AcceptedQuantity: Total quantity accepted in the auction (FR + SR).
298
- - AcceptedQuantityFR: Quantity accepted in the first round (FR).
299
- - AcceptedQuantitySR: Quantity accepted in the second round (SR).
300
- - AvgPrice: Average price in the auction.
301
- - CutPrice: Cut-off price.
302
- - AvgRate: Average interest rate.
303
- - CutRate: Cut-off rate.
304
- - BDToMat: Business days to maturity.
305
- - Duration: Duration of the bond.
306
- - MDuration: Modified duration of the bond.
307
- - DV01FR: First Round (FR) dollar value of a 1 bp change in yield in R$.
308
-
280
+ FR = First Round (Primeira Rodada)
281
+ SR = Second Round (Segunda Rodada)
282
+
283
+ O DataFrame possui as seguintes colunas:
284
+ - Date: Data do leilão.
285
+ - Settlement: Data de liquidação do leilão.
286
+ - AuctionType: Tipo de leilão (ex: "Sell" ou "Buy").
287
+ - Ordinance: Edital normativo associado ao leilão.
288
+ - Buyer: Categoria do comprador (ex: "TodoMercado", "SomenteDealerApto").
289
+ - BondType: Categoria do título (ex: "LTN", "LFT", "NTN-B", "NTN-F").
290
+ - Maturity: Data de vencimento do título.
291
+ - SelicCode: Código do título no sistema Selic.
292
+ - Value: Valor total do leilão em R$ (FR + SR).
293
+ - ValueFR: Valor da primeira rodada (FR) do leilão em R$.
294
+ - ValueSR: Valor da segunda rodada (SR) em R$.
295
+ - OfferedQuantity: Quantidade total ofertada no leilão (FR + SR).
296
+ - OfferedQuantityFR: Quantidade ofertada na primeira rodada (FR).
297
+ - OfferedQuantitySR: Quantidade ofertada na segunda rodada (SR).
298
+ - AcceptedQuantity: Quantidade total aceita no leilão (FR + SR).
299
+ - AcceptedQuantityFR: Quantidade aceita na primeira rodada (FR).
300
+ - AcceptedQuantitySR: Quantidade aceita na segunda rodada (SR).
301
+ - AvgPrice: Preço médio no leilão.
302
+ - CutPrice: Preço de corte.
303
+ - AvgRate: Taxa de juros média.
304
+ - CutRate: Taxa de corte.
305
+ - BDToMat: Dias úteis até o vencimento.
306
+ - Duration: Duration (Duração) do título.
307
+ - MDuration: Modified Duration (Duração Modificada) do título.
308
+ - DV01FR: Dollar Value of 1 bp change in yield - Primeira Rodada (FR) em R$.
309
309
  """
310
+ url = BASE_API_URL
311
+ if start:
312
+ start = dc.convert_input_dates(start)
313
+ start_str = start.strftime("%Y-%m-%d")
314
+ url += f"@dataMovimentoInicio='{start_str}'"
310
315
 
311
- start = dc.convert_input_dates(start)
312
316
  if end:
313
317
  end = dc.convert_input_dates(end)
314
- else:
315
- end = start
318
+ end_str = end.strftime("%Y-%m-%d")
319
+ url += f"&@dataMovimentoFim='{end_str}'"
316
320
 
317
- start_str = start.strftime("%Y-%m-%d")
318
- end_str = end.strftime("%Y-%m-%d")
319
- # url = f"https://olinda.bcb.gov.br/olinda/servico/leiloes_selic/versao/v1/odata/leiloesTitulosPublicos(dataMovimentoInicio=@dataMovimentoInicio,dataMovimentoFim=@dataMovimentoFim,dataLiquidacao=@dataLiquidacao,codigoTitulo=@codigoTitulo,dataVencimento=@dataVencimento,edital=@edital,tipoPublico=@tipoPublico,tipoOferta=@tipoOferta)?@dataMovimentoInicio='{start_str}'&@dataMovimentoFim='{end_str}'&$format=text/csv"
320
- url = f"{BASE_API_URL}@dataMovimentoInicio='{start_str}'&@dataMovimentoFim='{end_str}'&$format=text/csv" # noqa
321
+ # Mapeamento do auction_type para o valor esperado pela API
322
+ auction_type_mapping = {"Sell": "Venda", "Buy": "Compra"}
323
+ auction_type_api_value = auction_type_mapping.get(auction_type)
324
+ # Adiciona o parâmetro tipoOferta à URL se auction_type for fornecido
325
+ if auction_type_api_value:
326
+ url += f"&@tipoOferta='{auction_type_api_value}'"
321
327
 
322
- return _fetch_df_from_url(url, auction_type)
328
+ url += "&$format=text/csv" # Adiciona o formato CSV ao final
329
+
330
+ return _fetch_df_from_url(url)
@@ -0,0 +1,154 @@
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
+ return df
81
+
82
+
83
+ def _reorder_last_ima(df: pd.DataFrame) -> pd.DataFrame:
84
+ col_order = [
85
+ "Date",
86
+ "IMAType",
87
+ "BondType",
88
+ "Maturity",
89
+ "SelicCode",
90
+ "ISIN",
91
+ "Weight",
92
+ "IndicativeRate",
93
+ "Price",
94
+ "BDToMat",
95
+ "Duration",
96
+ "PMR",
97
+ "Convexity",
98
+ "TheoreticalQuantity",
99
+ "MarketDV01",
100
+ "MarketQuantity",
101
+ "MarketValue",
102
+ ]
103
+ return df[col_order].reset_index(drop=True)
104
+
105
+
106
+ def ima(ima_type: ima_types | None = None) -> pd.DataFrame:
107
+ """
108
+ Fetch and process the last IMA market data available from ANBIMA.
109
+
110
+ This function processes the data into a structured DataFrame.
111
+ It handles conversion of date formats, renames columns to English, and converts
112
+ certain numeric columns to integer types. In the event of an error during data
113
+ fetching or processing, an empty DataFrame is returned.
114
+
115
+ Args:
116
+ ima_type (str, optional): Type of IMA index to filter the data. If None, all
117
+ IMA indexes are returned. Defaults to None.
118
+
119
+ Returns:
120
+ pd.DataFrame: A DataFrame containing the IMA data with the following columns:
121
+ - Date: Reference date of the data.
122
+ - Index: IMA index.
123
+ - BondType: Type of bond.
124
+ - Maturity: Bond maturity date.
125
+ - SelicCode: Code representing the SELIC rate.
126
+ - ISIN: International Securities Identification Number.
127
+ - Price: Bond price.
128
+ - Weight: Weight of the bond in the index.
129
+ - BDToMat: Business days to maturity.
130
+ - Duration: Duration of the bond in years.
131
+ - PMR: Average repurchase term.
132
+ - Convexity: Convexity of the bond.
133
+ - TheoreticalQuantity: Theoretical quantity.
134
+ - MarketDV01: Market DV01 in R$.
135
+ - MarketQuantity: Market quantity.
136
+ - MarketValue: Market value in R$.
137
+
138
+
139
+ Raises:
140
+ Exception: Logs error and returns an empty DataFrame if any error occurs during
141
+ fetching or processing.
142
+
143
+ """
144
+ try:
145
+ df = _fetch_last_ima()
146
+ df = _process_last_ima(df)
147
+ df = _reorder_last_ima(df)
148
+ if ima_type is not None:
149
+ df = df.query("IMAType == @ima_type").reset_index(drop=True)
150
+ df = df.sort_values(["IMAType", "BondType", "Maturity"]).reset_index(drop=True)
151
+ return df
152
+ except Exception as e:
153
+ logging.exception(f"Error fetching or processing the last IMA data: {e}")
154
+ return pd.DataFrame()
@@ -1 +0,0 @@
1
- __version__ = "0.26.4"
@@ -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