PYield 0.34.2__tar.gz → 0.35.0__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.34.2 → pyield-0.35.0}/PKG-INFO +1 -1
- pyield-0.35.0/pyield/__about__.py +1 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/__init__.py +2 -2
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/__init__.py +2 -2
- pyield-0.34.2/pyield/b3/dif.py → pyield-0.35.0/pyield/b3/di1.py +8 -8
- {pyield-0.34.2 → pyield-0.35.0}/pyield/data_cache.py +9 -1
- {pyield-0.34.2 → pyield-0.35.0}/pyield/retry.py +64 -44
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/ltn.py +2 -2
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/ntnb.py +1 -1
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/ntnf.py +2 -2
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/tools.py +2 -2
- pyield-0.34.2/pyield/__about__.py +0 -1
- {pyield-0.34.2 → pyield-0.35.0}/.gitignore +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/LICENSE +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/README.md +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/ettj.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/ima.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/imaq.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/ipca.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/anbima/tpf.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/di_over.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/futures/common.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/auction.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/bcdata.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/ptax.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/repo.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bc/vna.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/bday.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/conftest.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/date_converter.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/fwd.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/holidays/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/holidays/brholidays.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/ibge/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/ibge/ipca.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/interpolator.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/py.typed +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/__init__.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/lft.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyield/tpf/ntnc.py +0 -0
- {pyield-0.34.2 → pyield-0.35.0}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.35.0"
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from pyield import anbima, b3, bc, bday, ibge
|
|
4
4
|
from pyield.__about__ import __version__
|
|
5
|
-
from pyield.b3 import
|
|
5
|
+
from pyield.b3 import di1, futures
|
|
6
6
|
from pyield.fwd import forward, forwards
|
|
7
7
|
from pyield.interpolator import Interpolator
|
|
8
8
|
from pyield.tpf import lft, ltn, ntnb, ntnc, ntnf
|
|
@@ -11,7 +11,7 @@ __all__ = [
|
|
|
11
11
|
"__version__",
|
|
12
12
|
"anbima",
|
|
13
13
|
"bday",
|
|
14
|
-
"
|
|
14
|
+
"di1",
|
|
15
15
|
"forwards",
|
|
16
16
|
"forward",
|
|
17
17
|
"futures",
|
|
@@ -47,8 +47,8 @@ def data(
|
|
|
47
47
|
if no data is found, the date is invalid, a holiday, or in the future.
|
|
48
48
|
|
|
49
49
|
Examples:
|
|
50
|
-
>>> from pyield import
|
|
51
|
-
>>> df =
|
|
50
|
+
>>> from pyield import di1
|
|
51
|
+
>>> df = di1.data(date="16-10-2024", month_start=True)
|
|
52
52
|
>>> df.iloc[:5, :5] # Show the first five rows and columns
|
|
53
53
|
TradeDate ExpirationDate TickerSymbol BDaysToExp OpenContracts
|
|
54
54
|
0 2024-10-16 2024-11-01 DI1X24 12 1744269
|
|
@@ -295,17 +295,17 @@ def interpolate_rate(
|
|
|
295
295
|
- An interpolation calculation fails.
|
|
296
296
|
|
|
297
297
|
Examples:
|
|
298
|
-
>>> from pyield import
|
|
298
|
+
>>> from pyield import di1
|
|
299
299
|
>>> # Get rate for an existing contract expiration
|
|
300
|
-
>>>
|
|
300
|
+
>>> di1.interpolate_rate("25-04-2025", "01-01-2027")
|
|
301
301
|
0.13901
|
|
302
302
|
|
|
303
303
|
>>> # Get rate for a non-existing contract expiration
|
|
304
|
-
>>>
|
|
304
|
+
>>> di1.interpolate_rate("25-04-2025", "01-11-2027")
|
|
305
305
|
0.13576348733268917
|
|
306
306
|
|
|
307
307
|
>>> # Extrapolate rate for a future expiration date
|
|
308
|
-
>>>
|
|
308
|
+
>>> di1.interpolate_rate("25-04-2025", "01-01-2050", extrapolate=True)
|
|
309
309
|
0.13881
|
|
310
310
|
"""
|
|
311
311
|
|
|
@@ -354,9 +354,9 @@ def eod_dates() -> pd.Series:
|
|
|
354
354
|
for which DI data is available.
|
|
355
355
|
|
|
356
356
|
Examples:
|
|
357
|
-
>>> from pyield import
|
|
357
|
+
>>> from pyield import di1
|
|
358
358
|
>>> # DI Futures series starts from 1995-01-02
|
|
359
|
-
>>>
|
|
359
|
+
>>> di1.eod_dates().head(5)
|
|
360
360
|
0 1995-01-02
|
|
361
361
|
1 1995-01-03
|
|
362
362
|
2 1995-01-04
|
|
@@ -5,6 +5,8 @@ from zoneinfo import ZoneInfo
|
|
|
5
5
|
|
|
6
6
|
import pandas as pd
|
|
7
7
|
|
|
8
|
+
from pyield.retry import default_retry
|
|
9
|
+
|
|
8
10
|
# --- Configurações Centralizadas ---
|
|
9
11
|
TIMEZONE_BZ = ZoneInfo("America/Sao_Paulo")
|
|
10
12
|
|
|
@@ -40,6 +42,12 @@ def _get_today_date_key():
|
|
|
40
42
|
return datetime.now(TIMEZONE_BZ).strftime("%Y-%m-%d")
|
|
41
43
|
|
|
42
44
|
|
|
45
|
+
@default_retry
|
|
46
|
+
def _load_github_file(file_url: str) -> pd.DataFrame:
|
|
47
|
+
"""Carrega um arquivo do GitHub e retorna um DataFrame."""
|
|
48
|
+
return pd.read_parquet(file_url)
|
|
49
|
+
|
|
50
|
+
|
|
43
51
|
@functools.lru_cache(maxsize=len(DATASET_CONFIGS))
|
|
44
52
|
def _get_dataset_with_ttl(dataset_id: str, date_key: str) -> pd.DataFrame:
|
|
45
53
|
"""Carrega o dataset a partir do ID e da chave de data. Cache expira diariamente."""
|
|
@@ -55,7 +63,7 @@ def _get_dataset_with_ttl(dataset_id: str, date_key: str) -> pd.DataFrame:
|
|
|
55
63
|
full_url = f"{BASE_DATA_URL}/{filename}"
|
|
56
64
|
|
|
57
65
|
try:
|
|
58
|
-
df =
|
|
66
|
+
df = _load_github_file(full_url)
|
|
59
67
|
last_date = df[date_column].max().date()
|
|
60
68
|
logger.info(f"Dataset {dataset_name} carregado. Última data: {last_date}")
|
|
61
69
|
return df.copy()
|
|
@@ -19,66 +19,65 @@ from tenacity import RetryCallState
|
|
|
19
19
|
# --- Configuração do Logger ---
|
|
20
20
|
logger = logging.getLogger(__name__)
|
|
21
21
|
|
|
22
|
-
# --- Constantes ---
|
|
23
|
-
DEFAULT_TIMEOUT = (2, 10)
|
|
24
|
-
RETRYABLE_NETWORK_ERRORS = (URLError,)
|
|
25
|
-
RETRYABLE_PARSING_ERRORS = (pd.errors.EmptyDataError, pd.errors.ParserError)
|
|
26
|
-
|
|
27
22
|
|
|
28
23
|
# --- Funções Auxiliares para Tenacity ---
|
|
29
|
-
|
|
30
|
-
|
|
31
24
|
def _log_before_sleep(retry_state: RetryCallState):
|
|
32
25
|
"""
|
|
33
26
|
Loga uma mensagem ANTES de o Tenacity entrar em espera (sleep) entre tentativas.
|
|
34
|
-
|
|
35
|
-
Simplificada para confiar no contrato do Tenacity e usar asserções
|
|
36
|
-
para verificar o estado esperado.
|
|
37
27
|
"""
|
|
38
|
-
# 1. Verificar o resultado (outcome)
|
|
39
28
|
outcome = retry_state.outcome
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
if not outcome or not outcome.failed:
|
|
30
|
+
logger.debug(
|
|
31
|
+
"before_sleep chamada sem 'outcome' ou para 'outcome' bem-sucedido."
|
|
32
|
+
)
|
|
33
|
+
return
|
|
43
34
|
|
|
44
|
-
exception = outcome.exception
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
exception = outcome.exception()
|
|
36
|
+
if not exception:
|
|
37
|
+
logger.debug("before_sleep chamada sem 'exception' real no outcome.")
|
|
38
|
+
return
|
|
47
39
|
|
|
48
|
-
# 2. Verificar a próxima ação (next_action)
|
|
49
40
|
next_action = retry_state.next_action
|
|
50
|
-
|
|
41
|
+
if not next_action or not hasattr(next_action, "sleep"):
|
|
42
|
+
logger.debug(
|
|
43
|
+
"before_sleep chamada sem 'next_action' ou 'sleep' em next_action."
|
|
44
|
+
)
|
|
45
|
+
return
|
|
51
46
|
|
|
52
|
-
# 3. Acessar a duração do sono (sleep)
|
|
53
|
-
# Confiamos que 'next_action' terá '.sleep' neste contexto, pois é antes de dormir.
|
|
54
47
|
sleep_duration = next_action.sleep
|
|
55
48
|
|
|
56
|
-
# Log principal
|
|
57
49
|
logger.warning(
|
|
58
50
|
f"Tentativa {retry_state.attempt_number} falhou com "
|
|
59
|
-
f"{type(exception).__name__}: {exception}. Tentando novamente em "
|
|
51
|
+
f"{type(exception).__name__}: {str(exception)[:150]}. Tentando novamente em "
|
|
60
52
|
f"{sleep_duration:.2f} segundos..."
|
|
61
53
|
)
|
|
62
54
|
|
|
63
55
|
|
|
64
56
|
def should_retry_exception(retry_state: RetryCallState) -> bool:
|
|
65
|
-
"""Determina se uma exceção capturada justifica uma nova tentativa
|
|
57
|
+
"""Determina se uma exceção capturada justifica uma nova tentativa"""
|
|
66
58
|
if not retry_state.outcome or not retry_state.outcome.failed:
|
|
67
59
|
return False
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
61
|
+
exception = retry_state.outcome.exception()
|
|
62
|
+
|
|
63
|
+
if exception is None:
|
|
64
|
+
# Isso não deveria acontecer se outcome.failed é True.
|
|
65
|
+
logger.error(
|
|
66
|
+
"should_retry_exception: outcome.failed é True,"
|
|
67
|
+
"mas exception() retornou None."
|
|
68
|
+
)
|
|
69
|
+
return False
|
|
74
70
|
|
|
75
71
|
attempt_number = retry_state.attempt_number
|
|
72
|
+
# getattr é mais seguro caso a exceção não tenha 'url'
|
|
76
73
|
url = getattr(exception, "url", "N/A")
|
|
77
74
|
|
|
78
75
|
retry_decision = False
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
# Inicializar como None para evitar log default se nenhum case corresponder
|
|
77
|
+
log_message = None
|
|
78
|
+
log_level = logging.ERROR # Default para não retentativa
|
|
81
79
|
|
|
80
|
+
# Usando match/case como originalmente preferido
|
|
82
81
|
match exception:
|
|
83
82
|
case HTTPError(code=404):
|
|
84
83
|
log_message = (
|
|
@@ -88,6 +87,15 @@ def should_retry_exception(retry_state: RetryCallState) -> bool:
|
|
|
88
87
|
retry_decision = False
|
|
89
88
|
log_level = logging.INFO
|
|
90
89
|
|
|
90
|
+
case HTTPError(code=429): # ADICIONADO: Tratamento para Too Many Requests
|
|
91
|
+
log_message = (
|
|
92
|
+
f"Tentativa {attempt_number}: Too Many Requests (429) da API em {url}. "
|
|
93
|
+
f"API pediu para aguardar. Tentando novamente."
|
|
94
|
+
)
|
|
95
|
+
retry_decision = True
|
|
96
|
+
log_level = logging.WARNING
|
|
97
|
+
|
|
98
|
+
# Gateway Timeout, primeira tentativa
|
|
91
99
|
case HTTPError(code=504) if attempt_number == 1:
|
|
92
100
|
log_message = (
|
|
93
101
|
f"Tentativa {attempt_number}: Gateway Timeout (504) da API em {url}. "
|
|
@@ -96,7 +104,7 @@ def should_retry_exception(retry_state: RetryCallState) -> bool:
|
|
|
96
104
|
retry_decision = True
|
|
97
105
|
log_level = logging.WARNING
|
|
98
106
|
|
|
99
|
-
case HTTPError(code=504):
|
|
107
|
+
case HTTPError(code=504): # Gateway Timeout, tentativas subsequentes
|
|
100
108
|
log_message = (
|
|
101
109
|
f"Tentativa {attempt_number}: Gateway Timeout (504) persistiu em {url}."
|
|
102
110
|
f"API parece indisponível. Desistindo."
|
|
@@ -104,41 +112,52 @@ def should_retry_exception(retry_state: RetryCallState) -> bool:
|
|
|
104
112
|
retry_decision = False
|
|
105
113
|
log_level = logging.ERROR
|
|
106
114
|
|
|
107
|
-
case HTTPError() as http_err:
|
|
115
|
+
case HTTPError() as http_err: # Outros erros HTTP
|
|
116
|
+
# Esta regra genérica para HTTPError retentará outros códigos HTTP.
|
|
117
|
+
# Por exemplo, 500, 502, 503 (geralmente bom para retry)
|
|
118
|
+
# mas também 400, 401, 403 (geralmente não bom para retry).
|
|
119
|
+
# Se precisar de mais granularidade, adicione cases específicos acima deste.
|
|
108
120
|
log_message = (
|
|
109
|
-
f"Tentativa {attempt_number}: Erro HTTP {http_err.code}
|
|
110
|
-
f"para {url}.
|
|
121
|
+
f"Tentativa {attempt_number}: Erro HTTP {http_err.code} "
|
|
122
|
+
f"({http_err.reason}) encontrado para {url}. "
|
|
123
|
+
"Pode ser transitório. Tentando novamente."
|
|
111
124
|
)
|
|
112
125
|
retry_decision = True
|
|
113
126
|
log_level = logging.WARNING
|
|
114
127
|
|
|
128
|
+
# Erros de rede mais genéricos (e.g., DNS falhou, conexão recusada)
|
|
115
129
|
case URLError():
|
|
116
130
|
log_message = (
|
|
117
131
|
f"Tentativa {attempt_number}: Erro de rede recuperável "
|
|
118
|
-
f"({type(exception).__name__})
|
|
132
|
+
f"({type(exception).__name__}: {str(exception)[:100]}) para {url}. "
|
|
133
|
+
f"Tentando novamente."
|
|
119
134
|
)
|
|
120
135
|
retry_decision = True
|
|
121
136
|
log_level = logging.WARNING
|
|
122
137
|
|
|
138
|
+
# Usando o operador | para combinar tipos de exceção no case
|
|
123
139
|
case pd.errors.EmptyDataError() | pd.errors.ParserError():
|
|
124
140
|
log_message = (
|
|
125
|
-
f"Tentativa {attempt_number}: Erro de parsing "
|
|
141
|
+
f"Tentativa {attempt_number}: Erro de parsing de dados "
|
|
126
142
|
f"({type(exception).__name__}). Tentando novamente."
|
|
127
143
|
)
|
|
128
144
|
retry_decision = True
|
|
129
145
|
log_level = logging.WARNING
|
|
130
146
|
|
|
131
|
-
case _:
|
|
147
|
+
case _: # Exceção não mapeada/inesperada
|
|
148
|
+
# Mensagem para o log de exceção
|
|
132
149
|
log_message_exc = (
|
|
133
150
|
f"Tentativa {attempt_number}: Erro não recuperável/inesperado "
|
|
134
|
-
f"({type(exception).__name__})
|
|
151
|
+
f"({type(exception).__name__}: {str(exception)[:100]}) "
|
|
152
|
+
f"ao processar {url}. Desistindo."
|
|
135
153
|
)
|
|
136
|
-
|
|
137
|
-
log_level = logging.ERROR
|
|
154
|
+
# Sempre incluir traceback para erros inesperados
|
|
138
155
|
logger.exception(log_message_exc)
|
|
139
|
-
log_message = None
|
|
156
|
+
log_message = None # Evita log duplicado pela seção logger.log abaixo
|
|
157
|
+
retry_decision = False
|
|
158
|
+
log_level = logging.ERROR # Já é o default, mas explícito aqui
|
|
140
159
|
|
|
141
|
-
if log_message:
|
|
160
|
+
if log_message: # Loga a mensagem formatada se uma foi definida
|
|
142
161
|
logger.log(log_level, log_message)
|
|
143
162
|
|
|
144
163
|
return retry_decision
|
|
@@ -147,8 +166,9 @@ def should_retry_exception(retry_state: RetryCallState) -> bool:
|
|
|
147
166
|
# --- Decorador Tenacity Principal ---
|
|
148
167
|
default_retry = tenacity.retry(
|
|
149
168
|
retry=should_retry_exception,
|
|
169
|
+
# Backoff exponencial é bom para 429
|
|
150
170
|
wait=tenacity.wait_exponential(multiplier=1, min=1, max=10),
|
|
151
171
|
stop=(tenacity.stop_after_attempt(3) | tenacity.stop_after_delay(15)),
|
|
152
172
|
before_sleep=_log_before_sleep,
|
|
153
|
-
reraise=True,
|
|
173
|
+
reraise=True, # Importante para propagar o erro final se as tentativas falharem
|
|
154
174
|
)
|
|
@@ -2,7 +2,7 @@ import pandas as pd
|
|
|
2
2
|
|
|
3
3
|
from pyield import anbima, bday
|
|
4
4
|
from pyield import date_converter as dc
|
|
5
|
-
from pyield.b3 import
|
|
5
|
+
from pyield.b3 import di1
|
|
6
6
|
from pyield.date_converter import DateScalar
|
|
7
7
|
from pyield.tpf import tools
|
|
8
8
|
|
|
@@ -223,7 +223,7 @@ def historical_premium(
|
|
|
223
223
|
ltn_rate = float(ltn_rates.iloc[0])
|
|
224
224
|
|
|
225
225
|
# Retrieve DI rate for the reference date and maturity
|
|
226
|
-
di_rate =
|
|
226
|
+
di_rate = di1.interpolate_rate(date=date, expiration=maturity, extrapolate=True)
|
|
227
227
|
if pd.isnull(di_rate): # Check if the DI rate is NaN
|
|
228
228
|
return float("NaN")
|
|
229
229
|
|
|
@@ -463,7 +463,7 @@ def bei_rates(
|
|
|
463
463
|
|
|
464
464
|
Get the DI Futures settlement rates for the same reference date to be used as
|
|
465
465
|
reference for the nominal rates:
|
|
466
|
-
>>> df_di = yd.
|
|
466
|
+
>>> df_di = yd.di1.data("05-09-2024")
|
|
467
467
|
|
|
468
468
|
Calculate the BEI rates considering the settlement at the reference date:
|
|
469
469
|
>>> yd.ntnb.bei_rates(
|
|
@@ -6,7 +6,7 @@ import pandas as pd
|
|
|
6
6
|
from pyield import anbima, bday
|
|
7
7
|
from pyield import date_converter as dc
|
|
8
8
|
from pyield import interpolator as ip
|
|
9
|
-
from pyield.b3 import
|
|
9
|
+
from pyield.b3 import di1
|
|
10
10
|
from pyield.date_converter import DateScalar
|
|
11
11
|
from pyield.tpf import tools
|
|
12
12
|
|
|
@@ -596,7 +596,7 @@ def historical_premium(
|
|
|
596
596
|
df["BYears"] = df["BDToMat"] / 252
|
|
597
597
|
df["ReferenceDate"] = date
|
|
598
598
|
|
|
599
|
-
df["DIRate"] =
|
|
599
|
+
df["DIRate"] = di1.interpolate_rates(
|
|
600
600
|
dates=df["ReferenceDate"],
|
|
601
601
|
expirations=df["PaymentDate"],
|
|
602
602
|
extrapolate=True,
|
|
@@ -5,7 +5,7 @@ import pandas as pd
|
|
|
5
5
|
|
|
6
6
|
from pyield import date_converter as dc
|
|
7
7
|
from pyield.anbima import tpf
|
|
8
|
-
from pyield.b3 import
|
|
8
|
+
from pyield.b3 import di1
|
|
9
9
|
from pyield.date_converter import DateScalar
|
|
10
10
|
|
|
11
11
|
|
|
@@ -77,7 +77,7 @@ def pre_spreads(date: DateScalar) -> pd.DataFrame:
|
|
|
77
77
|
"""
|
|
78
78
|
# Fetch DI rates for the reference date
|
|
79
79
|
converted_date = dc.convert_input_dates(date)
|
|
80
|
-
df_di =
|
|
80
|
+
df_di = di1.data(date=converted_date, month_start=True)
|
|
81
81
|
if "SettlementRate" not in df_di.columns or df_di.empty:
|
|
82
82
|
raise ValueError("DI data is missing the 'SettlementRate' column or is empty.")
|
|
83
83
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.34.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
|
|
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
|