PYield 0.35.7__tar.gz → 0.35.8__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.7 → pyield-0.35.8}/PKG-INFO +1 -1
- pyield-0.35.8/pyield/__about__.py +1 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bday.py +104 -46
- {pyield-0.35.7 → pyield-0.35.8}/pyield/date_converter.py +12 -3
- {pyield-0.35.7 → pyield-0.35.8}/pyield/holidays/brholidays.py +2 -1
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/auction.py +2 -2
- pyield-0.35.7/pyield/__about__.py +0 -1
- {pyield-0.35.7 → pyield-0.35.8}/.gitignore +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/LICENSE +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/README.md +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/ettj.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/ima.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/imaq.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/ipca.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/anbima/tpf.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/di1.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/di_over.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/futures/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/futures/common.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/auction.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/bcdata.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/ptax.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/repo.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/bc/vna.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/conftest.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/data_cache.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/fwd.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/holidays/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/ibge/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/ibge/ipca.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/interpolator.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/py.typed +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/retry.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/__init__.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/lft.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/ltn.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/ntnb.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/ntnc.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/ntnf.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyield/tn/tools.py +0 -0
- {pyield-0.35.7 → pyield-0.35.8}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.35.8"
|
|
@@ -135,6 +135,21 @@ def offset(
|
|
|
135
135
|
1 2024-09-23
|
|
136
136
|
dtype: datetime64[ns]
|
|
137
137
|
|
|
138
|
+
Null values are propagated
|
|
139
|
+
|
|
140
|
+
>>> bday.offset(pd.NaT, 1) # NaT input
|
|
141
|
+
NaT
|
|
142
|
+
|
|
143
|
+
>>> bday.offset(pd.NaT, [1, 2]) # NaT input with a list of offsets
|
|
144
|
+
0 NaT
|
|
145
|
+
1 NaT
|
|
146
|
+
dtype: datetime64[ns]
|
|
147
|
+
|
|
148
|
+
>>> bday.offset(["19-09-2024", pd.NaT], 1) # NaT in a list of dates
|
|
149
|
+
0 2024-09-20
|
|
150
|
+
1 NaT
|
|
151
|
+
dtype: datetime64[ns]
|
|
152
|
+
|
|
138
153
|
Note:
|
|
139
154
|
This function uses `numpy.busday_offset` under the hood, which means it follows
|
|
140
155
|
the same conventions and limitations for business day calculations. For detailed
|
|
@@ -144,6 +159,14 @@ def offset(
|
|
|
144
159
|
"""
|
|
145
160
|
dates_pd = dc.convert_input_dates(dates)
|
|
146
161
|
|
|
162
|
+
# Antecipate NaT handling
|
|
163
|
+
if dates_pd is pd.NaT:
|
|
164
|
+
if isinstance(offset, (list, tuple, np.ndarray, pd.Series)):
|
|
165
|
+
# If offset is a list, return a Series of NaT with the same length
|
|
166
|
+
return pd.Series([pd.NaT] * len(offset), dtype="datetime64[ns]")
|
|
167
|
+
else:
|
|
168
|
+
return pd.NaT
|
|
169
|
+
|
|
147
170
|
if isinstance(dates_pd, pd.Series):
|
|
148
171
|
# Divide the input in order to apply the correct holiday list
|
|
149
172
|
old_dates = dates_pd[dates_pd < br_holidays.TRANSITION_DATE]
|
|
@@ -216,7 +239,7 @@ def count(start: DateScalar, end: DateArray) -> pd.Series: ...
|
|
|
216
239
|
def count(start: DateArray, end: DateArray) -> pd.Series: ...
|
|
217
240
|
|
|
218
241
|
|
|
219
|
-
def count(
|
|
242
|
+
def count( # noqa
|
|
220
243
|
start: DateScalar | DateArray,
|
|
221
244
|
end: DateScalar | DateArray,
|
|
222
245
|
) -> int | pd.Series:
|
|
@@ -278,65 +301,100 @@ def count(
|
|
|
278
301
|
0 22
|
|
279
302
|
1 19
|
|
280
303
|
dtype: Int64
|
|
304
|
+
|
|
305
|
+
Null values are propagated
|
|
306
|
+
|
|
307
|
+
>>> bday.count(pd.NaT, "01-01-2024") # NaT start
|
|
308
|
+
<NA>
|
|
309
|
+
|
|
310
|
+
>>> bday.count("01-01-2024", pd.NaT) # NaT end
|
|
311
|
+
<NA>
|
|
312
|
+
|
|
313
|
+
>>> bday.count("01-01-2024", ["01-02-2024", pd.NaT]) # NaT in end array
|
|
314
|
+
0 22
|
|
315
|
+
1 <NA>
|
|
316
|
+
dtype: Int64
|
|
317
|
+
|
|
318
|
+
Original pandas index is preserved
|
|
319
|
+
|
|
320
|
+
>>> start_dates = pd.Series(
|
|
321
|
+
... ["01-01-2024", "01-02-2024", "01-03-2024"],
|
|
322
|
+
... index=["a", "b", "c"],
|
|
323
|
+
... )
|
|
324
|
+
>>> bday.count(start_dates, "01-01-2025")
|
|
325
|
+
a 253
|
|
326
|
+
b 231
|
|
327
|
+
c 212
|
|
328
|
+
dtype: Int64
|
|
281
329
|
"""
|
|
330
|
+
# Padroniza as entradas para objetos do Pandas
|
|
282
331
|
start_pd = dc.convert_input_dates(start)
|
|
283
332
|
end_pd = dc.convert_input_dates(end)
|
|
284
333
|
|
|
285
|
-
#
|
|
334
|
+
# 1. VALIDAÇÃO ESTRUTURAL
|
|
286
335
|
if isinstance(start_pd, pd.Series) and isinstance(end_pd, pd.Series):
|
|
287
|
-
if start_pd
|
|
336
|
+
if len(start_pd) != len(end_pd):
|
|
288
337
|
raise ValueError("Input Series must have the same length.")
|
|
338
|
+
if not start_pd.index.equals(end_pd.index):
|
|
339
|
+
raise ValueError("Input dates have different indices!")
|
|
289
340
|
|
|
290
|
-
#
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
start2 = start_pd[start_pd >= br_holidays.TRANSITION_DATE]
|
|
295
|
-
start3 = start_pd[start_pd.isna()]
|
|
296
|
-
|
|
297
|
-
# If end is a Series, it must be divided as well
|
|
298
|
-
if isinstance(end_pd, pd.Series):
|
|
299
|
-
end1 = end_pd[start1.index]
|
|
300
|
-
end2 = end_pd[start2.index]
|
|
301
|
-
else:
|
|
302
|
-
end1 = end_pd
|
|
303
|
-
end2 = end_pd
|
|
304
|
-
|
|
305
|
-
result1 = np.busday_count(
|
|
306
|
-
begindates=dc.to_numpy_date_type(start1),
|
|
307
|
-
enddates=dc.to_numpy_date_type(end1),
|
|
308
|
-
holidays=OLD_HOLIDAYS_ARRAY,
|
|
309
|
-
)
|
|
310
|
-
result2 = np.busday_count(
|
|
311
|
-
begindates=dc.to_numpy_date_type(start2),
|
|
312
|
-
enddates=dc.to_numpy_date_type(end2),
|
|
313
|
-
holidays=NEW_HOLIDAYS_ARRAY,
|
|
314
|
-
)
|
|
315
|
-
|
|
316
|
-
# Prepare results to be rejoined
|
|
317
|
-
result1 = pd.Series(result1, dtype="Int64")
|
|
318
|
-
result2 = pd.Series(result2, dtype="Int64")
|
|
319
|
-
# Convert the third result from NaT to NA
|
|
320
|
-
result3 = pd.Series(pd.NA, index=start3.index, dtype="Int64")
|
|
321
|
-
|
|
322
|
-
# Old index is used to rejoin the results
|
|
323
|
-
result1.index = start1.index
|
|
324
|
-
result2.index = start2.index
|
|
341
|
+
# 2. LÓGICA PRINCIPAL
|
|
342
|
+
is_scalar_input = not (
|
|
343
|
+
isinstance(start_pd, pd.Series) or isinstance(end_pd, pd.Series)
|
|
344
|
+
)
|
|
325
345
|
|
|
326
|
-
|
|
327
|
-
|
|
346
|
+
# --- CASO 1: AMBAS AS ENTRADAS SÃO ESCALARES ---
|
|
347
|
+
if is_scalar_input:
|
|
348
|
+
if pd.isna(start_pd) or pd.isna(end_pd):
|
|
349
|
+
return pd.NA
|
|
328
350
|
|
|
329
|
-
|
|
351
|
+
holidays = br_holidays.get_holiday_array(start_pd)
|
|
330
352
|
result = np.busday_count(
|
|
331
353
|
begindates=dc.to_numpy_date_type(start_pd),
|
|
332
354
|
enddates=dc.to_numpy_date_type(end_pd),
|
|
333
|
-
holidays=
|
|
355
|
+
holidays=holidays,
|
|
334
356
|
)
|
|
335
|
-
|
|
357
|
+
return int(result)
|
|
336
358
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
359
|
+
# --- CASO 2: PELO MENOS UMA ENTRADA É UMA SÉRIE ---
|
|
360
|
+
else:
|
|
361
|
+
# Garante que ambas as variáveis sejam Series para alinhamento automático.
|
|
362
|
+
# O Pandas faz o "broadcast" do escalar para o tamanho da Series.
|
|
363
|
+
if not isinstance(start_pd, pd.Series):
|
|
364
|
+
# start escalar e end Series: cria uma Series de start com o índice de end.
|
|
365
|
+
start_pd = pd.Series(start_pd, index=end_pd.index)
|
|
366
|
+
if not isinstance(end_pd, pd.Series):
|
|
367
|
+
# end escalar e start Series: cria uma Series de end com o índice de start.
|
|
368
|
+
end_pd = pd.Series(end_pd, index=start_pd.index)
|
|
369
|
+
|
|
370
|
+
# Inicializa a série de resultados com o índice correto e tipo que suporta NA.
|
|
371
|
+
# Nulos nas entradas (start_pd ou end_pd) resultarão em NA aqui.
|
|
372
|
+
result = pd.Series(index=start_pd.index, dtype="Int64")
|
|
373
|
+
|
|
374
|
+
# Cria máscaras para linhas não-nulas, divididas pelo calendário de feriados.
|
|
375
|
+
# A lógica de feriados depende APENAS da data de início.
|
|
376
|
+
not_null_mask = start_pd.notna() & end_pd.notna()
|
|
377
|
+
mask_old_holidays = not_null_mask & (start_pd < br_holidays.TRANSITION_DATE)
|
|
378
|
+
mask_new_holidays = not_null_mask & (start_pd >= br_holidays.TRANSITION_DATE)
|
|
379
|
+
|
|
380
|
+
# Calcula e atribui os resultados para o subconjunto "OLD"
|
|
381
|
+
if mask_old_holidays.any():
|
|
382
|
+
result.loc[mask_old_holidays] = np.busday_count(
|
|
383
|
+
begindates=dc.to_numpy_date_type(start_pd[mask_old_holidays]),
|
|
384
|
+
enddates=dc.to_numpy_date_type(end_pd[mask_old_holidays]),
|
|
385
|
+
holidays=OLD_HOLIDAYS_ARRAY,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
# Calcula e atribui os resultados para o subconjunto "NEW"
|
|
389
|
+
if mask_new_holidays.any():
|
|
390
|
+
result.loc[mask_new_holidays] = np.busday_count(
|
|
391
|
+
begindates=dc.to_numpy_date_type(start_pd[mask_new_holidays]),
|
|
392
|
+
enddates=dc.to_numpy_date_type(end_pd[mask_new_holidays]),
|
|
393
|
+
holidays=NEW_HOLIDAYS_ARRAY,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
# As linhas onde not_null_mask era False já contêm o valor <NA> default.
|
|
397
|
+
return result
|
|
340
398
|
|
|
341
399
|
|
|
342
400
|
def generate(
|
|
@@ -32,6 +32,12 @@ def convert_input_dates(dates: DateArray) -> pd.Series: ...
|
|
|
32
32
|
def convert_input_dates(
|
|
33
33
|
dates: DateScalar | DateArray,
|
|
34
34
|
) -> pd.Timestamp | pd.Series:
|
|
35
|
+
# Capturar apenas escalares nulos: a verificação `is True` é crucial,
|
|
36
|
+
# pois `pd.isna()` retorna um array booleano para entradas de array,
|
|
37
|
+
# e um array nunca é idêntico ao objeto singleton `True`.
|
|
38
|
+
if pd.isna(dates) is True:
|
|
39
|
+
return pd.NaT
|
|
40
|
+
|
|
35
41
|
match dates:
|
|
36
42
|
case str():
|
|
37
43
|
validate_date_format(dates)
|
|
@@ -41,6 +47,7 @@ def convert_input_dates(
|
|
|
41
47
|
return pd.Timestamp(dates).normalize()
|
|
42
48
|
|
|
43
49
|
case pd.Series() | np.ndarray() | list() | tuple():
|
|
50
|
+
# Preserve input values making a copy
|
|
44
51
|
result = pd.Series(dates)
|
|
45
52
|
|
|
46
53
|
if result.empty:
|
|
@@ -48,14 +55,14 @@ def convert_input_dates(
|
|
|
48
55
|
|
|
49
56
|
if pd.api.types.is_string_dtype(result):
|
|
50
57
|
# Check first element to validate date format
|
|
51
|
-
validate_date_format(result[0])
|
|
58
|
+
validate_date_format(result.iloc[0])
|
|
52
59
|
|
|
53
60
|
return pd.to_datetime(result, dayfirst=True).astype("datetime64[ns]")
|
|
54
61
|
|
|
55
62
|
case pd.DatetimeIndex():
|
|
56
63
|
return pd.Series(dates).astype("datetime64[ns]")
|
|
57
64
|
|
|
58
|
-
case _:
|
|
65
|
+
case _:
|
|
59
66
|
raise ValueError("Invalid input type for 'dates'.")
|
|
60
67
|
|
|
61
68
|
|
|
@@ -71,7 +78,9 @@ def to_numpy_date_type(
|
|
|
71
78
|
Returns:
|
|
72
79
|
np.datetime64 | np.ndarray: The input dates in a numpy datetime64[D] format.
|
|
73
80
|
"""
|
|
74
|
-
if
|
|
81
|
+
if pd.isna(dates) is True:
|
|
82
|
+
return np.datetime64("NaT")
|
|
83
|
+
elif isinstance(dates, pd.Timestamp) or dates is pd.NaT:
|
|
75
84
|
return np.datetime64(dates, "D")
|
|
76
85
|
elif isinstance(dates, pd.Series):
|
|
77
86
|
return dates.to_numpy().astype("datetime64[D]")
|
|
@@ -58,7 +58,8 @@ class BrHolidays:
|
|
|
58
58
|
if isinstance(dates, pd.Timestamp):
|
|
59
59
|
earliest_date = dates
|
|
60
60
|
else:
|
|
61
|
-
|
|
61
|
+
# NaN values will be ignored for min date calculation
|
|
62
|
+
earliest_date = dates.min(skipna=True)
|
|
62
63
|
|
|
63
64
|
if earliest_date < BrHolidays.TRANSITION_DATE:
|
|
64
65
|
holidays = self.old_holidays
|
|
@@ -61,12 +61,12 @@ def benchmarks(include_history: bool = False) -> pd.DataFrame:
|
|
|
61
61
|
>>> # Get historical benchmarks
|
|
62
62
|
>>> df_history = tn.benchmarks(include_history=True)
|
|
63
63
|
>>> df_history.head()
|
|
64
|
-
Benchmark
|
|
64
|
+
Benchmark MaturityDate BondType StartDate EndDate
|
|
65
65
|
0 LFT 6 anos 2020-03-01 LFT 2014-01-01 2014-06-30
|
|
66
66
|
1 LFT 6 anos 2020-09-01 LFT 2014-07-01 2014-12-31
|
|
67
67
|
2 LFT 6 anos 2021-03-01 LFT 2015-01-01 2015-04-30
|
|
68
68
|
3 LFT 6 anos 2021-09-01 LFT 2015-05-01 2015-12-31
|
|
69
|
-
4
|
|
69
|
+
4 LFT 6 anos 2022-03-01 LFT 2016-01-01 2016-06-30
|
|
70
70
|
"""
|
|
71
71
|
session = requests.Session()
|
|
72
72
|
include_history_param_value = "S" if include_history else "N"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.35.7"
|
|
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
|