PYield 0.35.6__tar.gz → 0.35.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.
- {pyield-0.35.6 → pyield-0.35.7}/PKG-INFO +1 -1
- pyield-0.35.7/pyield/__about__.py +1 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/di1.py +2 -2
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/auction.py +4 -2
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/auction.py +60 -21
- pyield-0.35.6/pyield/__about__.py +0 -1
- {pyield-0.35.6 → pyield-0.35.7}/.gitignore +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/LICENSE +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/README.md +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/ettj.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/ima.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/imaq.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/ipca.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/anbima/tpf.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/di_over.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/futures/common.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/bcdata.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/ptax.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/repo.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bc/vna.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/bday.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/conftest.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/data_cache.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/date_converter.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/fwd.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/holidays/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/holidays/brholidays.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/ibge/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/ibge/ipca.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/interpolator.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/py.typed +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/retry.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/__init__.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/lft.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/ltn.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/ntnb.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/ntnc.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/ntnf.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyield/tn/tools.py +0 -0
- {pyield-0.35.6 → pyield-0.35.7}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.35.7"
|
|
@@ -63,9 +63,9 @@ def data(
|
|
|
63
63
|
|
|
64
64
|
df = get_cached_dataset("di1").query("TradeDate in @dates").reset_index(drop=True)
|
|
65
65
|
|
|
66
|
-
today = dt.now(TIMEZONE_BZ)
|
|
66
|
+
today = dt.now(TIMEZONE_BZ).date()
|
|
67
67
|
last_bday = bday.last_business_day()
|
|
68
|
-
is_trading_day = today
|
|
68
|
+
is_trading_day = today == last_bday.date()
|
|
69
69
|
if is_trading_day and last_bday in df["TradeDate"]:
|
|
70
70
|
logger.info("Trying to get DI Futures data for today.")
|
|
71
71
|
df_intraday = b3.futures(contract_code="DI1", date=last_bday)
|
|
@@ -19,6 +19,8 @@ from pyield.retry import default_retry
|
|
|
19
19
|
from pyield.tn.ntnb import duration as duration_b
|
|
20
20
|
from pyield.tn.ntnf import duration as duration_f
|
|
21
21
|
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
22
24
|
"""
|
|
23
25
|
Dicionário com o mapeamento das colunas da API do BC para o DataFrame final
|
|
24
26
|
Chaves com comentário serão descartadas ao final do processamento
|
|
@@ -233,7 +235,7 @@ def _fetch_df_from_url(url: str) -> pd.DataFrame:
|
|
|
233
235
|
try:
|
|
234
236
|
df = _load_from_url(url)
|
|
235
237
|
if df.empty:
|
|
236
|
-
|
|
238
|
+
logger.warning("No auction data found for the specified period.")
|
|
237
239
|
return pd.DataFrame()
|
|
238
240
|
df = _pre_process_df(df)
|
|
239
241
|
df = _adjust_null_values(df)
|
|
@@ -244,7 +246,7 @@ def _fetch_df_from_url(url: str) -> pd.DataFrame:
|
|
|
244
246
|
df = _sort_and_reorder_columns(df)
|
|
245
247
|
return df
|
|
246
248
|
except Exception:
|
|
247
|
-
|
|
249
|
+
logger.exception("Error fetching auction data from BC API.")
|
|
248
250
|
return pd.DataFrame()
|
|
249
251
|
|
|
250
252
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Manual da API: https://portal-conhecimento.tesouro.gov.br/catalogo-componentes/api-leil%C3%B5es
|
|
3
|
-
Financeiro é sempre o financeiro aceito.
|
|
4
|
-
Os dados do BCB só existem na API do TN.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
1
|
import logging
|
|
2
|
+
from datetime import datetime as dt
|
|
3
|
+
from zoneinfo import ZoneInfo
|
|
8
4
|
|
|
9
5
|
import pandas as pd
|
|
10
6
|
import requests
|
|
11
7
|
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
TIMEZONE_BZ = ZoneInfo("America/Sao_Paulo")
|
|
11
|
+
|
|
12
12
|
BENCHMARKS_COLUMN_MAPPING = {
|
|
13
13
|
"BENCHMARK": "Benchmark",
|
|
14
14
|
"VENCIMENTO": "MaturityDate",
|
|
@@ -18,7 +18,10 @@ BENCHMARKS_COLUMN_MAPPING = {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
API_BASE_URL = (
|
|
22
|
+
"https://apiapex.tesouro.gov.br/aria/v1/api-leiloes-pub/custom/benchmarks"
|
|
23
|
+
)
|
|
24
|
+
API_HISTORY_PARAM = "incluir_historico"
|
|
22
25
|
|
|
23
26
|
|
|
24
27
|
def benchmarks(include_history: bool = False) -> pd.DataFrame:
|
|
@@ -51,12 +54,12 @@ def benchmarks(include_history: bool = False) -> pd.DataFrame:
|
|
|
51
54
|
* Rows with any `NaN` values are dropped before returning the DataFrame.
|
|
52
55
|
|
|
53
56
|
Examples:
|
|
54
|
-
>>> # Get current benchmarks
|
|
57
|
+
>>> # Get current benchmarks (default behavior)
|
|
55
58
|
>>> from pyield import tn
|
|
56
59
|
>>> df_current = tn.benchmarks()
|
|
57
60
|
|
|
58
61
|
>>> # Get historical benchmarks
|
|
59
|
-
>>> df_history = benchmarks(include_history=True)
|
|
62
|
+
>>> df_history = tn.benchmarks(include_history=True)
|
|
60
63
|
>>> df_history.head()
|
|
61
64
|
Benchmark MaturityDate BondType StartDate EndDate
|
|
62
65
|
0 LFT 6 anos 2020-03-01 LFT 2014-01-01 2014-06-30
|
|
@@ -66,26 +69,62 @@ def benchmarks(include_history: bool = False) -> pd.DataFrame:
|
|
|
66
69
|
4 LFT 1 ano 2022-03-01 LFT 2020-10-15 2021-03-31
|
|
67
70
|
"""
|
|
68
71
|
session = requests.Session()
|
|
69
|
-
|
|
70
|
-
api_endpoint =
|
|
72
|
+
include_history_param_value = "S" if include_history else "N"
|
|
73
|
+
api_endpoint = f"{API_BASE_URL}?{API_HISTORY_PARAM}={include_history_param_value}"
|
|
74
|
+
|
|
71
75
|
try:
|
|
72
76
|
stn_benchmarks = session.get(api_endpoint)
|
|
77
|
+
stn_benchmarks.raise_for_status()
|
|
73
78
|
except requests.exceptions.SSLError as e:
|
|
74
|
-
|
|
79
|
+
logger.error(
|
|
75
80
|
f"SSL error encountered: {e}. Retrying without certificate verification."
|
|
76
81
|
)
|
|
77
82
|
stn_benchmarks = session.get(api_endpoint, verify=False)
|
|
83
|
+
stn_benchmarks.raise_for_status()
|
|
84
|
+
except requests.exceptions.RequestException as e:
|
|
85
|
+
logger.error(f"Error fetching benchmarks from API: {e}")
|
|
86
|
+
return pd.DataFrame()
|
|
87
|
+
|
|
78
88
|
response_dict = stn_benchmarks.json()
|
|
89
|
+
|
|
90
|
+
# 1a verificação: Verifica se a resposta da API contém dados válidos de registros
|
|
91
|
+
if not response_dict or not response_dict.get("registros"):
|
|
92
|
+
logger.warning("API response did not contain 'registros' key or it was empty.")
|
|
93
|
+
return pd.DataFrame()
|
|
94
|
+
|
|
95
|
+
# Tenta criar o DataFrame. O .dropna() pode resultar em um DF vazio.
|
|
79
96
|
df = pd.DataFrame(response_dict["registros"]).dropna()
|
|
80
97
|
df = df.convert_dtypes()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
98
|
+
|
|
99
|
+
# 2a verificação: Verifica se o DataFrame resultante (pós-dropna) está vazio
|
|
100
|
+
# Esta verificação é importante porque .dropna() pode remover todas as linhas.
|
|
101
|
+
if df.empty:
|
|
102
|
+
logger.warning(
|
|
103
|
+
"No valid benchmark data found after initial processing"
|
|
104
|
+
"(e.g., all rows had NaNs and were dropped).",
|
|
105
|
+
)
|
|
106
|
+
return pd.DataFrame()
|
|
107
|
+
|
|
108
|
+
# Se chegamos até aqui, o DataFrame tem dados e pode ser processado.
|
|
109
|
+
df["VENCIMENTO"] = pd.to_datetime(df["VENCIMENTO"])
|
|
110
|
+
df["TERMINO"] = pd.to_datetime(df["TERMINO"])
|
|
111
|
+
df["INÍCIO"] = pd.to_datetime(df["INÍCIO"])
|
|
112
|
+
df["BENCHMARK"] = df["BENCHMARK"].str.strip()
|
|
113
|
+
df["TÍTULO"] = df["TÍTULO"].str.strip()
|
|
114
|
+
|
|
115
|
+
if not include_history:
|
|
116
|
+
# Em tese, a API já retorna apenas benchmarks ativos,
|
|
117
|
+
# mas vamos garantir que o DataFrame só contenha benchmarks ativos
|
|
118
|
+
# considerando o período atual.
|
|
119
|
+
today = dt.now(TIMEZONE_BZ).date()
|
|
120
|
+
today = pd.Timestamp(today)
|
|
121
|
+
df = df.query("INÍCIO <= @today <= TERMINO").reset_index(drop=True)
|
|
122
|
+
|
|
123
|
+
# Verifica novamente se o DataFrame ficou vazio *após o filtro condicional*
|
|
124
|
+
# (apenas se `include_history` for False)
|
|
125
|
+
if df.empty and not include_history:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"No current benchmark data found after filtering by active period."
|
|
128
|
+
)
|
|
90
129
|
|
|
91
130
|
return df.rename(columns=BENCHMARKS_COLUMN_MAPPING)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.35.6"
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|