PYield 0.40.0__tar.gz → 0.40.2__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.40.0 → pyield-0.40.2}/PKG-INFO +13 -13
- {pyield-0.40.0 → pyield-0.40.2}/README.md +12 -12
- pyield-0.40.2/pyield/__about__.py +1 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/di1.py +7 -7
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/di_over.py +3 -3
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/futures/__init__.py +1 -1
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/ptax_api.py +4 -4
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/rates.py +10 -10
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/vna.py +3 -3
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/core.py +104 -75
- pyield-0.40.2/pyield/data_cache.py +88 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/fwd.py +28 -19
- {pyield-0.40.0 → pyield-0.40.2}/pyield/interpolator.py +12 -13
- {pyield-0.40.0 → pyield-0.40.2}/pyield/retry.py +20 -27
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/lft.py +6 -6
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/ltn.py +9 -9
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/ntnb.py +11 -11
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/ntnc.py +9 -9
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/ntnf.py +191 -146
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/tools.py +32 -3
- {pyield-0.40.0 → pyield-0.40.2}/pyield/types.py +12 -12
- pyield-0.40.0/pyield/__about__.py +0 -1
- pyield-0.40.0/pyield/data_cache.py +0 -83
- {pyield-0.40.0 → pyield-0.40.2}/.gitignore +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/LICENSE +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/difusao.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/ettj_intraday.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/ettj_last.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/ima.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/imaq.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/anbima/tpf.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/futures/common.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/futures/historical.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/futures/intraday.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/b3/futures/xml.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/auction.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/repo.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/trades_intraday.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bc/trades_monthly.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/holidays/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/holidays/br_holidays_new.txt +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/holidays/br_holidays_old.txt +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/bday/holidays/brholidays.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/config.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/conftest.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/converters.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/ipca/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/ipca/historical.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/ipca/projected.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/py.typed +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/__init__.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/auctions.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/benchmark.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyield/tn/pre.py +0 -0
- {pyield-0.40.0 → pyield-0.40.2}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PYield
|
|
3
|
-
Version: 0.40.
|
|
3
|
+
Version: 0.40.2
|
|
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>
|
|
@@ -49,9 +49,9 @@ Description-Content-Type: text/markdown
|
|
|
49
49
|
PYield is a Python library designed for the analysis of Brazilian fixed income instruments. Leveraging the power of popular Python libraries like Polars, Pandas, Numpy and Requests, PYield simplifies the process of obtaining and processing data from key sources such as ANBIMA, BCB, IBGE and B3.
|
|
50
50
|
|
|
51
51
|
---
|
|
52
|
-
### ✅ Polars
|
|
52
|
+
### ✅ Polars migration from version 0.40.0 onwards:
|
|
53
53
|
|
|
54
|
-
All public functions now return **Polars DataFrames or Series** as the canonical format. This provides stronger typing, faster execution and more reliable date/rate handling.
|
|
54
|
+
All public functions now return **Polars DataFrames or Series** as the canonical format. This provides stronger typing, faster execution and more reliable date/rate handling. The last version to return Pandas objects by default was **0.39.xx**.
|
|
55
55
|
|
|
56
56
|
Need Pandas? Convert explicitly:
|
|
57
57
|
```python
|
|
@@ -171,16 +171,16 @@ Series: 'bdays' [i64]
|
|
|
171
171
|
# Get ANBIMA LTN data for a given date
|
|
172
172
|
>>> ltn.data("23-08-2024")
|
|
173
173
|
shape: (13, 14)
|
|
174
|
-
|
|
174
|
+
┌──────────────┬─────────┬──────────┬──────────────┬───┬─────────┬─────────┬───────────────┬────────┐
|
|
175
175
|
│ ReferenceDate│ BondType│ SelicCode│ IssueBaseDate│ … │ BidRate │ AskRate │ IndicativeRate│ DIRate │
|
|
176
176
|
│ --- │ --- │ --- │ --- │ │ --- │ --- │ --- │ --- │
|
|
177
177
|
│ date │ str │ i64 │ date │ │ f64 │ f64 │ f64 │ f64 │
|
|
178
|
-
|
|
178
|
+
├──────────────┼─────────┼──────────┼──────────────┼───┼─────────┼─────────┼───────────────┼────────┤
|
|
179
179
|
│ 2024-08-23 │ LTN │ 100000 │ 2022-07-08 │ … │ 0.10459 │ 0.104252│ 0.104416 │ 0.10472│
|
|
180
180
|
│ 2024-08-23 │ LTN │ 100000 │ 2018-02-01 │ … │ 0.107366│ 0.107016│ 0.107171 │ 0.10823│
|
|
181
181
|
│ 2024-08-23 │ LTN │ 100000 │ 2023-01-06 │ … │ 0.110992│ 0.110746│ 0.110866 │ 0.11179│
|
|
182
182
|
│ … │ … │ … │ … │ … │ … │ … │ … │ … │
|
|
183
|
-
|
|
183
|
+
└──────────────┴─────────┴──────────┴──────────────┴───┴─────────┴─────────┴───────────────┴────────┘
|
|
184
184
|
|
|
185
185
|
# Calculate the quotation of an NTN-B bond (base 100, truncated to 4 decimals)
|
|
186
186
|
>>> ntnb.quotation("31-05-2024", "15-05-2035", 0.061490)
|
|
@@ -191,17 +191,17 @@ shape: (13, 14)
|
|
|
191
191
|
# DI Spreads: IndicativeRate - SettlementRate (bps=True multiplies by 10_000)
|
|
192
192
|
>>> ntnf.di_spreads("30-05-2025", bps=True)
|
|
193
193
|
shape: (5, 3)
|
|
194
|
-
|
|
194
|
+
┌─────────┬─────────────┬──────────┐
|
|
195
195
|
│ BondType│ MaturityDate│ DISpread │
|
|
196
196
|
│ --- │ --- │ --- │
|
|
197
197
|
│ str │ date │ f64 │
|
|
198
|
-
|
|
198
|
+
├─────────┼─────────────┼──────────┤
|
|
199
199
|
│ NTN-F │ 2027-01-01 │ -3.31 │
|
|
200
200
|
│ NTN-F │ 2029-01-01 │ 14.21 │
|
|
201
201
|
│ NTN-F │ 2031-01-01 │ 21.61 │
|
|
202
202
|
│ NTN-F │ 2033-01-01 │ 11.51 │
|
|
203
203
|
│ NTN-F │ 2035-01-01 │ 22.0 │
|
|
204
|
-
|
|
204
|
+
└─────────┴─────────────┴──────────┘
|
|
205
205
|
```
|
|
206
206
|
|
|
207
207
|
### Business Days Tools (Brazilian holidays automatically considered)
|
|
@@ -244,16 +244,16 @@ Series: '' [date]
|
|
|
244
244
|
# Fetch DI1 futures (historical)
|
|
245
245
|
>>> futures("DI1", "31-05-2024")
|
|
246
246
|
shape: (40, 20)
|
|
247
|
-
|
|
247
|
+
┌────────────┬──────────────┬───────────────┬────────────┬───┬──────────────┬──────────┬───────────────┬─────────────┐
|
|
248
248
|
│ TradeDate ┆ TickerSymbol ┆ ExpirationDate┆ BDaysToExp ┆ … ┆ CloseBidRate ┆ CloseRate┆ SettlementRate┆ ForwardRate │
|
|
249
249
|
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
|
|
250
250
|
│ date ┆ str ┆ date ┆ i64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
|
|
251
|
-
|
|
251
|
+
├────────────┼──────────────┼───────────────┼────────────┼───┼──────────────┼──────────┼───────────────┼─────────────┤
|
|
252
252
|
│ 2024-05-31 ┆ DI1M24 ┆ 2024-06-03 ┆ 1 ┆ … ┆ 0.10404 ┆ 0.10404 ┆ 0.10399 ┆ 0.10399 │
|
|
253
253
|
│ 2024-05-31 ┆ DI1N24 ┆ 2024-07-01 ┆ 21 ┆ … ┆ 0.1039 ┆ 0.10386 ┆ 0.1039 ┆ 0.103896 │
|
|
254
254
|
│ 2024-05-31 ┆ DI1Q24 ┆ 2024-08-01 ┆ 44 ┆ … ┆ 0.10374 ┆ 0.10374 ┆ 0.1037 ┆ 0.103517 │
|
|
255
|
-
│ … ┆ … ┆ …
|
|
256
|
-
|
|
255
|
+
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
|
|
256
|
+
└────────────┴──────────────┴───────────────┴────────────┴───┴──────────────┴──────────┴───────────────┴─────────────┘
|
|
257
257
|
```
|
|
258
258
|
|
|
259
259
|
### Indicators Data
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
PYield is a Python library designed for the analysis of Brazilian fixed income instruments. Leveraging the power of popular Python libraries like Polars, Pandas, Numpy and Requests, PYield simplifies the process of obtaining and processing data from key sources such as ANBIMA, BCB, IBGE and B3.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
|
-
### ✅ Polars
|
|
10
|
+
### ✅ Polars migration from version 0.40.0 onwards:
|
|
11
11
|
|
|
12
|
-
All public functions now return **Polars DataFrames or Series** as the canonical format. This provides stronger typing, faster execution and more reliable date/rate handling.
|
|
12
|
+
All public functions now return **Polars DataFrames or Series** as the canonical format. This provides stronger typing, faster execution and more reliable date/rate handling. The last version to return Pandas objects by default was **0.39.xx**.
|
|
13
13
|
|
|
14
14
|
Need Pandas? Convert explicitly:
|
|
15
15
|
```python
|
|
@@ -129,16 +129,16 @@ Series: 'bdays' [i64]
|
|
|
129
129
|
# Get ANBIMA LTN data for a given date
|
|
130
130
|
>>> ltn.data("23-08-2024")
|
|
131
131
|
shape: (13, 14)
|
|
132
|
-
|
|
132
|
+
┌──────────────┬─────────┬──────────┬──────────────┬───┬─────────┬─────────┬───────────────┬────────┐
|
|
133
133
|
│ ReferenceDate│ BondType│ SelicCode│ IssueBaseDate│ … │ BidRate │ AskRate │ IndicativeRate│ DIRate │
|
|
134
134
|
│ --- │ --- │ --- │ --- │ │ --- │ --- │ --- │ --- │
|
|
135
135
|
│ date │ str │ i64 │ date │ │ f64 │ f64 │ f64 │ f64 │
|
|
136
|
-
|
|
136
|
+
├──────────────┼─────────┼──────────┼──────────────┼───┼─────────┼─────────┼───────────────┼────────┤
|
|
137
137
|
│ 2024-08-23 │ LTN │ 100000 │ 2022-07-08 │ … │ 0.10459 │ 0.104252│ 0.104416 │ 0.10472│
|
|
138
138
|
│ 2024-08-23 │ LTN │ 100000 │ 2018-02-01 │ … │ 0.107366│ 0.107016│ 0.107171 │ 0.10823│
|
|
139
139
|
│ 2024-08-23 │ LTN │ 100000 │ 2023-01-06 │ … │ 0.110992│ 0.110746│ 0.110866 │ 0.11179│
|
|
140
140
|
│ … │ … │ … │ … │ … │ … │ … │ … │ … │
|
|
141
|
-
|
|
141
|
+
└──────────────┴─────────┴──────────┴──────────────┴───┴─────────┴─────────┴───────────────┴────────┘
|
|
142
142
|
|
|
143
143
|
# Calculate the quotation of an NTN-B bond (base 100, truncated to 4 decimals)
|
|
144
144
|
>>> ntnb.quotation("31-05-2024", "15-05-2035", 0.061490)
|
|
@@ -149,17 +149,17 @@ shape: (13, 14)
|
|
|
149
149
|
# DI Spreads: IndicativeRate - SettlementRate (bps=True multiplies by 10_000)
|
|
150
150
|
>>> ntnf.di_spreads("30-05-2025", bps=True)
|
|
151
151
|
shape: (5, 3)
|
|
152
|
-
|
|
152
|
+
┌─────────┬─────────────┬──────────┐
|
|
153
153
|
│ BondType│ MaturityDate│ DISpread │
|
|
154
154
|
│ --- │ --- │ --- │
|
|
155
155
|
│ str │ date │ f64 │
|
|
156
|
-
|
|
156
|
+
├─────────┼─────────────┼──────────┤
|
|
157
157
|
│ NTN-F │ 2027-01-01 │ -3.31 │
|
|
158
158
|
│ NTN-F │ 2029-01-01 │ 14.21 │
|
|
159
159
|
│ NTN-F │ 2031-01-01 │ 21.61 │
|
|
160
160
|
│ NTN-F │ 2033-01-01 │ 11.51 │
|
|
161
161
|
│ NTN-F │ 2035-01-01 │ 22.0 │
|
|
162
|
-
|
|
162
|
+
└─────────┴─────────────┴──────────┘
|
|
163
163
|
```
|
|
164
164
|
|
|
165
165
|
### Business Days Tools (Brazilian holidays automatically considered)
|
|
@@ -202,16 +202,16 @@ Series: '' [date]
|
|
|
202
202
|
# Fetch DI1 futures (historical)
|
|
203
203
|
>>> futures("DI1", "31-05-2024")
|
|
204
204
|
shape: (40, 20)
|
|
205
|
-
|
|
205
|
+
┌────────────┬──────────────┬───────────────┬────────────┬───┬──────────────┬──────────┬───────────────┬─────────────┐
|
|
206
206
|
│ TradeDate ┆ TickerSymbol ┆ ExpirationDate┆ BDaysToExp ┆ … ┆ CloseBidRate ┆ CloseRate┆ SettlementRate┆ ForwardRate │
|
|
207
207
|
│ --- ┆ --- ┆ --- ┆ --- ┆ ┆ --- ┆ --- ┆ --- ┆ --- │
|
|
208
208
|
│ date ┆ str ┆ date ┆ i64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ f64 │
|
|
209
|
-
|
|
209
|
+
├────────────┼──────────────┼───────────────┼────────────┼───┼──────────────┼──────────┼───────────────┼─────────────┤
|
|
210
210
|
│ 2024-05-31 ┆ DI1M24 ┆ 2024-06-03 ┆ 1 ┆ … ┆ 0.10404 ┆ 0.10404 ┆ 0.10399 ┆ 0.10399 │
|
|
211
211
|
│ 2024-05-31 ┆ DI1N24 ┆ 2024-07-01 ┆ 21 ┆ … ┆ 0.1039 ┆ 0.10386 ┆ 0.1039 ┆ 0.103896 │
|
|
212
212
|
│ 2024-05-31 ┆ DI1Q24 ┆ 2024-08-01 ┆ 44 ┆ … ┆ 0.10374 ┆ 0.10374 ┆ 0.1037 ┆ 0.103517 │
|
|
213
|
-
│ … ┆ … ┆ …
|
|
214
|
-
|
|
213
|
+
│ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … ┆ … │
|
|
214
|
+
└────────────┴──────────────┴───────────────┴────────────┴───┴──────────────┴──────────┴───────────────┴─────────────┘
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
### Indicators Data
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.40.2"
|
|
@@ -255,7 +255,7 @@ def interpolate_rates(
|
|
|
255
255
|
0.13881
|
|
256
256
|
]
|
|
257
257
|
|
|
258
|
-
>>> # With extrapolation set to False, the second rate will be
|
|
258
|
+
>>> # With extrapolation set to False, the second rate will be NaN
|
|
259
259
|
>>> # Note: 0.13576348733268917 is shown as 0.135763
|
|
260
260
|
>>> di1.interpolate_rates(
|
|
261
261
|
... dates="25-04-2025",
|
|
@@ -266,7 +266,7 @@ def interpolate_rates(
|
|
|
266
266
|
Series: 'FlatFwdRate' [f64]
|
|
267
267
|
[
|
|
268
268
|
0.135763
|
|
269
|
-
|
|
269
|
+
NaN
|
|
270
270
|
]
|
|
271
271
|
|
|
272
272
|
Raises:
|
|
@@ -331,7 +331,7 @@ def interpolate_rate(
|
|
|
331
331
|
date: DateScalar,
|
|
332
332
|
expiration: DateScalar,
|
|
333
333
|
extrapolate: bool = False,
|
|
334
|
-
) -> float
|
|
334
|
+
) -> float:
|
|
335
335
|
"""
|
|
336
336
|
Interpolates or retrieves the DI rate for a single expiration date.
|
|
337
337
|
|
|
@@ -349,8 +349,8 @@ def interpolate_rate(
|
|
|
349
349
|
expirations for the given `date`. Defaults to False.
|
|
350
350
|
|
|
351
351
|
Returns:
|
|
352
|
-
float
|
|
353
|
-
date and expiration. Returns `
|
|
352
|
+
float: The exact or interpolated DI settlement rate for the specified
|
|
353
|
+
date and expiration. Returns `float("nan")` if:
|
|
354
354
|
- No DI data is found for the `date`.
|
|
355
355
|
- The `expiration` is outside range and `extrapolate` is False.
|
|
356
356
|
- An interpolation calculation fails.
|
|
@@ -371,7 +371,7 @@ def interpolate_rate(
|
|
|
371
371
|
"""
|
|
372
372
|
if has_null_args(date, expiration):
|
|
373
373
|
logger.warning("Both 'date' and 'expiration' must be provided. Returning NaN.")
|
|
374
|
-
return
|
|
374
|
+
return float("nan")
|
|
375
375
|
|
|
376
376
|
converted_date = cv.convert_dates(date)
|
|
377
377
|
converted_expiration = cv.convert_dates(expiration)
|
|
@@ -385,7 +385,7 @@ def interpolate_rate(
|
|
|
385
385
|
df = _get_data(dates=converted_date)
|
|
386
386
|
|
|
387
387
|
if df.is_empty():
|
|
388
|
-
return
|
|
388
|
+
return float("nan")
|
|
389
389
|
|
|
390
390
|
ff_interp = interpolator.Interpolator(
|
|
391
391
|
method="flat_forward",
|
|
@@ -10,7 +10,7 @@ logger = logging.getLogger(__name__)
|
|
|
10
10
|
DI_OVER_DECIMAL_PLACES = 4
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def di_over(date: DateScalar) -> float
|
|
13
|
+
def di_over(date: DateScalar) -> float:
|
|
14
14
|
"""
|
|
15
15
|
Gets the DI (Interbank Deposit) rate for a specific date from B3/CETIP FTP server.
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ def di_over(date: DateScalar) -> float | None:
|
|
|
18
18
|
date (str): Date in DD/MM/YYYY format
|
|
19
19
|
|
|
20
20
|
Returns:
|
|
21
|
-
float
|
|
21
|
+
float: DI rate for the specified date or float("nan") if no data is found.
|
|
22
22
|
|
|
23
23
|
Raises:
|
|
24
24
|
ValueError: If date is not in the correct format
|
|
@@ -30,7 +30,7 @@ def di_over(date: DateScalar) -> float | None:
|
|
|
30
30
|
0.1315
|
|
31
31
|
"""
|
|
32
32
|
if has_null_args(date):
|
|
33
|
-
return
|
|
33
|
+
return float("nan")
|
|
34
34
|
ftp = None
|
|
35
35
|
try:
|
|
36
36
|
# Convert date to file format
|
|
@@ -181,7 +181,7 @@ def futures(
|
|
|
181
181
|
# Existe a chance de que os dados consolidados estejam disponíveis após as 20h
|
|
182
182
|
if time >= HISTORICAL_START_TIME:
|
|
183
183
|
df_hist = _get_historical_data(selected_contract, trade_date)
|
|
184
|
-
if not df_hist.
|
|
184
|
+
if not df_hist.is_empty():
|
|
185
185
|
logger.info("Consolidated data is already available and will be used.")
|
|
186
186
|
return df_hist
|
|
187
187
|
|
|
@@ -241,7 +241,7 @@ def ptax_series(
|
|
|
241
241
|
return pl.DataFrame()
|
|
242
242
|
|
|
243
243
|
|
|
244
|
-
def ptax(date: DateScalar) -> float
|
|
244
|
+
def ptax(date: DateScalar) -> float:
|
|
245
245
|
"""Busca a cotação PTAX média de fechamento para uma data específica.
|
|
246
246
|
|
|
247
247
|
Esta função é um wrapper para a função `ptax_series`, otimizada para
|
|
@@ -263,8 +263,8 @@ def ptax(date: DateScalar) -> float | None:
|
|
|
263
263
|
5.4389
|
|
264
264
|
|
|
265
265
|
>>> # Busca a PTAX para um fim de semana (sem dados)
|
|
266
|
-
>>> bc.ptax("23-08-2025")
|
|
267
|
-
|
|
266
|
+
>>> bc.ptax("23-08-2025")
|
|
267
|
+
nan
|
|
268
268
|
"""
|
|
269
269
|
# Reutiliza a função ptax_series para buscar os dados para o dia específico.
|
|
270
270
|
# Definir start e end com a mesma data busca a cotação para aquele dia.
|
|
@@ -274,7 +274,7 @@ def ptax(date: DateScalar) -> float | None:
|
|
|
274
274
|
# Isso ocorre em fins de semana, feriados ou datas futuras.
|
|
275
275
|
if df_ptax.is_empty():
|
|
276
276
|
logger.warning(f"No PTAX data found for date: {date}")
|
|
277
|
-
return
|
|
277
|
+
return float("nan")
|
|
278
278
|
|
|
279
279
|
# A API retorna uma única linha para a cotação de fechamento de um dia.
|
|
280
280
|
# A coluna "MidRate" representa a PTAX de fechamento.
|
|
@@ -245,7 +245,7 @@ def selic_over_series(
|
|
|
245
245
|
return df.with_columns(pl.col("Value").round(DECIMAL_PLACES_ANNUALIZED))
|
|
246
246
|
|
|
247
247
|
|
|
248
|
-
def selic_over(date: DateScalar) -> float
|
|
248
|
+
def selic_over(date: DateScalar) -> float:
|
|
249
249
|
"""
|
|
250
250
|
Fetches the SELIC Over rate value for a specific date.
|
|
251
251
|
|
|
@@ -264,10 +264,10 @@ def selic_over(date: DateScalar) -> float | None:
|
|
|
264
264
|
0.104
|
|
265
265
|
"""
|
|
266
266
|
if has_null_args(date):
|
|
267
|
-
return
|
|
267
|
+
return float("nan")
|
|
268
268
|
df = selic_over_series(date, date)
|
|
269
269
|
if df.is_empty():
|
|
270
|
-
return
|
|
270
|
+
return float("nan")
|
|
271
271
|
return df["Value"].item(0)
|
|
272
272
|
|
|
273
273
|
|
|
@@ -312,7 +312,7 @@ def selic_target_series(
|
|
|
312
312
|
return df
|
|
313
313
|
|
|
314
314
|
|
|
315
|
-
def selic_target(date: DateScalar) -> float
|
|
315
|
+
def selic_target(date: DateScalar) -> float:
|
|
316
316
|
"""
|
|
317
317
|
Fetches the SELIC Target rate value for a specific date.
|
|
318
318
|
|
|
@@ -331,10 +331,10 @@ def selic_target(date: DateScalar) -> float | None:
|
|
|
331
331
|
0.105
|
|
332
332
|
"""
|
|
333
333
|
if has_null_args(date):
|
|
334
|
-
return
|
|
334
|
+
return float("nan")
|
|
335
335
|
df = selic_target_series(date, date)
|
|
336
336
|
if df.is_empty():
|
|
337
|
-
return
|
|
337
|
+
return float("nan")
|
|
338
338
|
return df["Value"].item(0)
|
|
339
339
|
|
|
340
340
|
|
|
@@ -397,7 +397,7 @@ def di_over_series(
|
|
|
397
397
|
return df
|
|
398
398
|
|
|
399
399
|
|
|
400
|
-
def di_over(date: DateScalar, annualized: bool = True) -> float
|
|
400
|
+
def di_over(date: DateScalar, annualized: bool = True) -> float:
|
|
401
401
|
"""
|
|
402
402
|
Fetches the DI Over rate value for a specific date.
|
|
403
403
|
|
|
@@ -410,7 +410,7 @@ def di_over(date: DateScalar, annualized: bool = True) -> float | None:
|
|
|
410
410
|
days per year), otherwise returns the daily rate.
|
|
411
411
|
|
|
412
412
|
Returns:
|
|
413
|
-
The DI Over rate as a float or
|
|
413
|
+
The DI Over rate as a float or float("nan") if not available.
|
|
414
414
|
|
|
415
415
|
Examples:
|
|
416
416
|
>>> from pyield import bc
|
|
@@ -421,8 +421,8 @@ def di_over(date: DateScalar, annualized: bool = True) -> float | None:
|
|
|
421
421
|
0.00045513
|
|
422
422
|
"""
|
|
423
423
|
if has_null_args(date):
|
|
424
|
-
return
|
|
424
|
+
return float("nan")
|
|
425
425
|
df = di_over_series(date, date, annualized)
|
|
426
426
|
if df.is_empty():
|
|
427
|
-
return
|
|
427
|
+
return float("nan")
|
|
428
428
|
return df["Value"].item(0)
|
|
@@ -59,7 +59,7 @@ def _validate_vna_values(vnas: list[float]) -> float:
|
|
|
59
59
|
return vna_value
|
|
60
60
|
|
|
61
61
|
|
|
62
|
-
def vna_lft(date: DateScalar) -> float
|
|
62
|
+
def vna_lft(date: DateScalar) -> float:
|
|
63
63
|
"""Retrieves the VNA (Valor Nominal Atualizado) from the BCB for a given date.
|
|
64
64
|
|
|
65
65
|
This function fetches daily data from the BCB website, extracts the
|
|
@@ -73,7 +73,7 @@ def vna_lft(date: DateScalar) -> float | None:
|
|
|
73
73
|
`convert_input_dates` function.
|
|
74
74
|
|
|
75
75
|
Returns:
|
|
76
|
-
float
|
|
76
|
+
float: The VNA (Valor Nominal Atualizado) value for the specified date,
|
|
77
77
|
or None if the date is invalid or data is not available.
|
|
78
78
|
|
|
79
79
|
Examples:
|
|
@@ -93,7 +93,7 @@ def vna_lft(date: DateScalar) -> float | None:
|
|
|
93
93
|
"""
|
|
94
94
|
if has_null_args(date):
|
|
95
95
|
logger.warning("No valid date provided. Returning NaN.")
|
|
96
|
-
return
|
|
96
|
+
return float("nan")
|
|
97
97
|
text = _get_text(date)
|
|
98
98
|
table_text = _extract_vna_table_text(text)
|
|
99
99
|
table_lines = _parse_vna_table_lines(table_text)
|
|
@@ -34,43 +34,37 @@ def count(
|
|
|
34
34
|
end: DateScalar | DateArray,
|
|
35
35
|
) -> int | pl.Series | None:
|
|
36
36
|
"""
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
the
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
Count business days between `start` (inclusive) and `end` (exclusive) with
|
|
38
|
+
Brazilian holiday adjustment and per-row holiday regime selection.
|
|
39
|
+
|
|
40
|
+
ORDER PRESERVATION (critical): The output order ALWAYS matches the element-wise
|
|
41
|
+
order of the original inputs. No sorting, deduplication, alignment or reshaping is
|
|
42
|
+
performed. If you pass arrays, the i-th result corresponds to the i-th pair of
|
|
43
|
+
(`start`, `end`) after broadcasting. This guarantees safe assignment back to the
|
|
44
|
+
originating DataFrame.
|
|
45
|
+
|
|
46
|
+
Holiday regime: For each `start` value, the holiday list (old vs. new) is chosen
|
|
47
|
+
based on the transition date 2023-12-26 (`TRANSITION_DATE`). Starts before the
|
|
48
|
+
transition use the old list for that row's count; starts on/after use the new list.
|
|
49
|
+
|
|
50
|
+
Null propagation: If any scalar argument is null, returns `None`. Nulls inside
|
|
51
|
+
array inputs yield nulls in corresponding result positions.
|
|
52
|
+
|
|
53
|
+
Return type: If both inputs are scalars (non-null) an `int` is returned; otherwise
|
|
54
|
+
a `polars.Series` of int counts (name: 'bdays'). If a null scalar short-circuits,
|
|
55
|
+
`None` is returned.
|
|
48
56
|
|
|
49
57
|
Args:
|
|
50
|
-
start
|
|
51
|
-
|
|
52
|
-
period between `start` and `end` is determined solely by the `start` date's
|
|
53
|
-
relation to the holiday transition date (2023-12-26). If `start` is before
|
|
54
|
-
this date, the old holiday list is used for the whole count, even if `end`
|
|
55
|
-
is after it. If `start` is on or after this date, new holiday list is used.
|
|
56
|
-
end (DateScalar | DateArray): The end date(s) for counting (exclusive).
|
|
58
|
+
start: Single date or collection (inclusive boundary).
|
|
59
|
+
end: Single date or collection (exclusive boundary).
|
|
57
60
|
|
|
58
61
|
Returns:
|
|
59
62
|
int | pl.Series | None: Returns an integer or None if `start` and `end` are
|
|
60
63
|
single dates, or a Series if any of them is an array of dates.
|
|
61
64
|
|
|
62
65
|
Notes:
|
|
63
|
-
- This function is a wrapper around `
|
|
64
|
-
|
|
65
|
-
- It supports flexible date inputs, including single dates, lists, Series, and
|
|
66
|
-
more, for both `start` and `end` parameters.
|
|
67
|
-
- The return type depends on the input types: single dates return an int, while
|
|
68
|
-
arrays of dates return a pl.Series with the count for each date range.
|
|
69
|
-
- The `start` date determines the holiday list, ensuring consistency with the
|
|
70
|
-
applicable calendar at the time.
|
|
71
|
-
- See `numpy.busday_count` documentation for more details on how holidays are
|
|
72
|
-
handled and how business day counts are calculated:
|
|
73
|
-
https://numpy.org/doc/stable/reference/generated/numpy.busday_count.html.
|
|
66
|
+
- This function is a wrapper around `polars.business_day_count`.
|
|
67
|
+
- The holiday list is determined per-row based on the `start` date.
|
|
74
68
|
|
|
75
69
|
Examples:
|
|
76
70
|
>>> from pyield import bday
|
|
@@ -157,7 +151,7 @@ def count(
|
|
|
157
151
|
|
|
158
152
|
s_bdays = df.select(result_expr.alias("bdays"))["bdays"]
|
|
159
153
|
|
|
160
|
-
# Se a
|
|
154
|
+
# Se a série resultante tem tamanho 1, retorna o valor escalar
|
|
161
155
|
if len(s_bdays) == 1:
|
|
162
156
|
return s_bdays.item()
|
|
163
157
|
|
|
@@ -184,37 +178,56 @@ def offset(
|
|
|
184
178
|
roll: Literal["forward", "backward"] = "forward",
|
|
185
179
|
) -> dt.date | pl.Series | None:
|
|
186
180
|
"""
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
181
|
+
Offset date(s) by a number of business days with per-row Brazilian holiday
|
|
182
|
+
regime selection. The operation is performed in two steps per element:
|
|
183
|
+
1) ROLL: If the original date falls on a weekend or holiday, move it according
|
|
184
|
+
to ``roll`` ("forward" -> next business day; "backward" -> previous).
|
|
185
|
+
2) ADD: Apply the signed business-day ``offset`` (positive forward, negative
|
|
186
|
+
backward, zero = stay on the rolled date).
|
|
187
|
+
|
|
188
|
+
ORDER PRESERVATION (critical): Output ordering strictly matches the element-wise
|
|
189
|
+
pairing after broadcasting between ``dates`` and ``offset``. No sorting,
|
|
190
|
+
deduplication or shape changes occur. The i-th result corresponds to the i-th
|
|
191
|
+
(date, offset) pair, enabling safe assignment back into the originating DataFrame.
|
|
192
|
+
|
|
193
|
+
Holiday regime: For EACH date the appropriate holiday list (old vs. new) is
|
|
194
|
+
chosen based on the transition date ``2023-12-26`` (``TRANSITION_DATE``). Dates
|
|
195
|
+
before the transition use the *old* list; dates on/after use the *new* list.
|
|
196
|
+
|
|
197
|
+
Roll semantics: ``roll`` only acts when the original date is not already a
|
|
198
|
+
business day under its regime. After rolling, the subsequent business-day
|
|
199
|
+
addition is applied from that rolled anchor. An ``offset`` of 0 therefore
|
|
200
|
+
returns either the original date (if already a business day) or the rolled
|
|
201
|
+
business day.
|
|
202
|
+
|
|
203
|
+
Null propagation: If any scalar argument is null, the function short-circuits
|
|
204
|
+
to ``None``. Nulls inside array inputs propagate to their corresponding output
|
|
205
|
+
positions.
|
|
206
|
+
|
|
207
|
+
Broadcasting: ``dates`` and ``offset`` may be scalars or array-like. Standard
|
|
208
|
+
Polars broadcasting rules apply when constructing the per-row pairs.
|
|
209
|
+
|
|
210
|
+
Return type: If both inputs are non-null scalars a ``datetime.date`` is returned.
|
|
211
|
+
Otherwise a ``polars.Series`` of dates named ``'result'`` is produced. Null scalar
|
|
212
|
+
inputs yield ``None``.
|
|
197
213
|
|
|
198
214
|
Args:
|
|
199
|
-
dates
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
while dates on or after 2023-12-26 use the new list.
|
|
206
|
-
offset (int | Series | np.ndarray | list[int] | tuple[int], optional):
|
|
207
|
-
The number of business days to offset the dates. Positive for future dates,
|
|
208
|
-
negative for past dates. Zero will return the same date if it's a business
|
|
209
|
-
day, or the next/previous business day otherwise, according to `roll`.
|
|
210
|
-
roll (Literal["forward", "backward"], optional): Direction to roll the date if
|
|
211
|
-
it falls on a holiday or weekend. 'forward' to the next business day,
|
|
212
|
-
'backward' to the previous. Defaults to 'forward'.
|
|
215
|
+
dates: Single date or collection of dates to be rolled (if needed) and then
|
|
216
|
+
offset. Each date independently selects the holiday regime.
|
|
217
|
+
offset: Signed count of business days to apply after rolling. Positive moves
|
|
218
|
+
forward, negative backward, zero keeps the rolled anchor.
|
|
219
|
+
roll: Direction to roll a non-business starting date ("forward" or
|
|
220
|
+
"backward"). Defaults to "forward".
|
|
213
221
|
|
|
214
222
|
Returns:
|
|
215
|
-
dt.date | pl.Series | None:
|
|
216
|
-
|
|
217
|
-
|
|
223
|
+
dt.date | pl.Series | None: A Python ``date`` for scalar inputs, a Polars
|
|
224
|
+
Series of dates for any array input, or ``None`` if a null scalar argument
|
|
225
|
+
was provided.
|
|
226
|
+
|
|
227
|
+
Notes:
|
|
228
|
+
- Wrapper around ``polars.Expr.dt.add_business_days`` applied conditionally.
|
|
229
|
+
- Holiday regime is decided per element by comparing to ``TRANSITION_DATE``.
|
|
230
|
+
- Weekends are always treated as non-business days.
|
|
218
231
|
|
|
219
232
|
Examples:
|
|
220
233
|
>>> from pyield import bday
|
|
@@ -337,7 +350,7 @@ def offset(
|
|
|
337
350
|
# Executa a expressão e obtém a série de resultados
|
|
338
351
|
result_series = df.select(result_expr.alias("result"))["result"]
|
|
339
352
|
|
|
340
|
-
# Se a
|
|
353
|
+
# Se a série resultante tem tamanho 1, retorna o valor escalar
|
|
341
354
|
if len(result_series) == 1:
|
|
342
355
|
return result_series.item()
|
|
343
356
|
|
|
@@ -419,7 +432,7 @@ def generate(
|
|
|
419
432
|
holidays=applicable_holidays,
|
|
420
433
|
)
|
|
421
434
|
s_pd = pd.Series(result_dti.values).astype("date32[pyarrow]")
|
|
422
|
-
return pl.
|
|
435
|
+
return pl.from_pandas(s_pd)
|
|
423
436
|
|
|
424
437
|
|
|
425
438
|
@overload
|
|
@@ -427,25 +440,40 @@ def is_business_day(dates: DateScalar) -> bool | None: ...
|
|
|
427
440
|
@overload
|
|
428
441
|
def is_business_day(dates: DateArray) -> pl.Series: ...
|
|
429
442
|
def is_business_day(dates: DateScalar | DateArray) -> bool | pl.Series | None:
|
|
430
|
-
"""
|
|
443
|
+
"""Determine whether date(s) are Brazilian business days with per-element
|
|
444
|
+
holiday regime selection.
|
|
445
|
+
|
|
446
|
+
PER-ROW HOLIDAY REGIME: For EACH input date the appropriate holiday list
|
|
447
|
+
("old" vs. "new") is selected by comparing to the transition date
|
|
448
|
+
``2023-12-26`` (``TRANSITION_DATE``). Dates strictly before the transition
|
|
449
|
+
use the old list; dates on or after it use the new list. This mirrors the
|
|
450
|
+
behavior of ``count`` and ``offset`` which apply regime logic element-wise.
|
|
451
|
+
|
|
452
|
+
ORDER & SHAPE PRESERVATION: The output preserves the original element order.
|
|
453
|
+
No sorting, deduplication, reshaping or alignment is performed; the i-th
|
|
454
|
+
result corresponds to the i-th provided date after broadcasting (if any
|
|
455
|
+
broadcasting occurred from a scalar input elsewhere in the call chain).
|
|
456
|
+
|
|
457
|
+
NULL PROPAGATION: A null scalar argument short-circuits to ``None``. Null
|
|
458
|
+
values inside array-like inputs produce nulls at the corresponding output
|
|
459
|
+
positions.
|
|
431
460
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
holiday list.
|
|
461
|
+
RETURN TYPE: If the (non-null) input resolves to a single element a Python
|
|
462
|
+
``bool`` is returned. If that lone element is null, ``None`` is returned.
|
|
463
|
+
Otherwise a ``polars.Series`` of booleans named ``'is_bday'`` is produced.
|
|
436
464
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
``None`` for null input) is returned; otherwise a ``polars.Series`` of booleans
|
|
440
|
-
is returned with nulls propagated.
|
|
465
|
+
WEEKENDS: Saturdays and Sundays are never business days regardless of the
|
|
466
|
+
holiday regime.
|
|
441
467
|
|
|
442
468
|
Args:
|
|
443
|
-
dates:
|
|
444
|
-
|
|
469
|
+
dates: Single date or collection (list/tuple/ndarray/Polars/Pandas
|
|
470
|
+
Series). May include nulls which propagate. Null scalar input
|
|
471
|
+
returns ``None``.
|
|
445
472
|
|
|
446
473
|
Returns:
|
|
447
|
-
bool | pl.Series | None: ``True`` if business day, ``False``
|
|
448
|
-
for null scalar input
|
|
474
|
+
bool | pl.Series | None: ``True`` if business day, ``False`` otherwise
|
|
475
|
+
for scalar input; ``None`` for null scalar input; or a Polars boolean
|
|
476
|
+
Series (name: ``'is_bday'``) for array inputs.
|
|
449
477
|
|
|
450
478
|
Examples:
|
|
451
479
|
>>> from pyield import bday
|
|
@@ -462,9 +490,10 @@ def is_business_day(dates: DateScalar | DateArray) -> bool | pl.Series | None:
|
|
|
462
490
|
]
|
|
463
491
|
|
|
464
492
|
Notes:
|
|
465
|
-
-
|
|
466
|
-
-
|
|
467
|
-
- Weekends
|
|
493
|
+
- Transition date defined in ``TRANSITION_DATE``.
|
|
494
|
+
- Mirrors per-row logic used in ``count`` and ``offset``.
|
|
495
|
+
- Weekends always evaluate to ``False``.
|
|
496
|
+
- Null elements propagate.
|
|
468
497
|
"""
|
|
469
498
|
# Validate and normalize inputs
|
|
470
499
|
if has_null_args(dates):
|