PYield 0.37.1__tar.gz → 0.37.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.
Files changed (53) hide show
  1. {pyield-0.37.1 → pyield-0.37.2}/PKG-INFO +1 -1
  2. pyield-0.37.2/pyield/__about__.py +1 -0
  3. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/ima.py +10 -6
  4. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/tpf.py +1 -3
  5. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/di1.py +4 -4
  6. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/futures/historical.py +28 -21
  7. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/futures/intraday.py +14 -11
  8. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/futures/xml.py +4 -4
  9. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/auction.py +1 -4
  10. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/rates.py +5 -3
  11. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/repo.py +6 -2
  12. {pyield-0.37.1 → pyield-0.37.2}/pyield/bday.py +6 -6
  13. {pyield-0.37.1 → pyield-0.37.2}/pyield/fwd.py +4 -4
  14. {pyield-0.37.1 → pyield-0.37.2}/pyield/ibge/ipca.py +1 -1
  15. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/ntnb.py +3 -4
  16. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/ntnf.py +1 -1
  17. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/pre.py +3 -3
  18. pyield-0.37.1/pyield/__about__.py +0 -1
  19. {pyield-0.37.1 → pyield-0.37.2}/.gitignore +0 -0
  20. {pyield-0.37.1 → pyield-0.37.2}/LICENSE +0 -0
  21. {pyield-0.37.1 → pyield-0.37.2}/README.md +0 -0
  22. {pyield-0.37.1 → pyield-0.37.2}/pyield/__init__.py +0 -0
  23. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/__init__.py +0 -0
  24. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/ettj.py +0 -0
  25. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/imaq.py +0 -0
  26. {pyield-0.37.1 → pyield-0.37.2}/pyield/anbima/ipca.py +0 -0
  27. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/__init__.py +0 -0
  28. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/di_over.py +0 -0
  29. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/futures/__init__.py +0 -0
  30. {pyield-0.37.1 → pyield-0.37.2}/pyield/b3/futures/common.py +0 -0
  31. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/__init__.py +0 -0
  32. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/ptax_api.py +0 -0
  33. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/trades_intraday.py +0 -0
  34. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/trades_monthly.py +0 -0
  35. {pyield-0.37.1 → pyield-0.37.2}/pyield/bc/vna.py +0 -0
  36. {pyield-0.37.1 → pyield-0.37.2}/pyield/conftest.py +0 -0
  37. {pyield-0.37.1 → pyield-0.37.2}/pyield/data_cache.py +0 -0
  38. {pyield-0.37.1 → pyield-0.37.2}/pyield/date_converter.py +0 -0
  39. {pyield-0.37.1 → pyield-0.37.2}/pyield/holidays/__init__.py +0 -0
  40. {pyield-0.37.1 → pyield-0.37.2}/pyield/holidays/br_holidays_new.txt +0 -0
  41. {pyield-0.37.1 → pyield-0.37.2}/pyield/holidays/br_holidays_old.txt +0 -0
  42. {pyield-0.37.1 → pyield-0.37.2}/pyield/holidays/brholidays.py +0 -0
  43. {pyield-0.37.1 → pyield-0.37.2}/pyield/ibge/__init__.py +0 -0
  44. {pyield-0.37.1 → pyield-0.37.2}/pyield/interpolator.py +0 -0
  45. {pyield-0.37.1 → pyield-0.37.2}/pyield/py.typed +0 -0
  46. {pyield-0.37.1 → pyield-0.37.2}/pyield/retry.py +0 -0
  47. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/__init__.py +0 -0
  48. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/benchmark.py +0 -0
  49. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/lft.py +0 -0
  50. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/ltn.py +0 -0
  51. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/ntnc.py +0 -0
  52. {pyield-0.37.1 → pyield-0.37.2}/pyield/tn/tools.py +0 -0
  53. {pyield-0.37.1 → pyield-0.37.2}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PYield
3
- Version: 0.37.1
3
+ Version: 0.37.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>
@@ -0,0 +1 @@
1
+ __version__ = "0.37.2"
@@ -59,7 +59,7 @@ def _fetch_last_ima() -> pd.DataFrame:
59
59
  sep="@",
60
60
  decimal=",",
61
61
  thousands=".",
62
- dtype_backend="numpy_nullable",
62
+ dtype_backend="pyarrow",
63
63
  na_values="--",
64
64
  )
65
65
 
@@ -69,10 +69,12 @@ def _fetch_last_ima() -> pd.DataFrame:
69
69
  def _process_last_ima(df: pd.DataFrame) -> pd.DataFrame:
70
70
  df = df.rename(columns=IMA_COL_MAPPING)[IMA_COL_MAPPING.values()]
71
71
  df["IndicativeRate"] = (df["IndicativeRate"] / 100).round(6)
72
- df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y")
73
- df["Maturity"] = pd.to_datetime(df["Maturity"], format="%d/%m/%Y")
74
- df["MarketQuantity"] = (1000 * df["MarketQuantity"]).astype("Int64")
75
- df["MarketValue"] = (1000 * df["MarketValue"]).round(0).astype("Int64")
72
+ df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y").astype("date32[pyarrow]")
73
+ df["Maturity"] = pd.to_datetime(df["Maturity"], format="%d/%m/%Y").astype(
74
+ "date32[pyarrow]"
75
+ )
76
+ df["MarketQuantity"] = (1000 * df["MarketQuantity"]).astype("int64[pyarrow]")
77
+ df["MarketValue"] = (1000 * df["MarketValue"]).round(0).astype("int64[pyarrow]")
76
78
  df["Price"] = df["Price"].round(6)
77
79
  # Duration is in business days, convert to years
78
80
  df["Duration"] /= 252
@@ -81,7 +83,9 @@ def _process_last_ima(df: pd.DataFrame) -> pd.DataFrame:
81
83
  # LFT DV01 is zero
82
84
  df["DV01"] = df["DV01"].where(df["BondType"] != "LFT", 0)
83
85
  # Since MarketDV01 is the total stock value, we round them to integer
84
- df["MarketDV01"] = (df["DV01"] * df["MarketQuantity"]).round(0).astype("Int64")
86
+ df["MarketDV01"] = (
87
+ (df["DV01"] * df["MarketQuantity"]).round(0).astype("int64[pyarrow]")
88
+ )
85
89
 
86
90
  return df
87
91
 
@@ -107,9 +107,7 @@ def _process_raw_df(df_raw: pd.DataFrame) -> pd.DataFrame:
107
107
 
108
108
 
109
109
  def _process_dv01(df: pd.DataFrame) -> pd.DataFrame:
110
- df["BDToMat"] = bday.count(
111
- start=df["ReferenceDate"], end=df["MaturityDate"]
112
- ).astype("int64[pyarrow]")
110
+ df["BDToMat"] = bday.count(start=df["ReferenceDate"], end=df["MaturityDate"])
113
111
 
114
112
  df["Duration"] = 0.0
115
113
  df["Duration"] = df["Duration"].astype("float64[pyarrow]")
@@ -194,7 +194,7 @@ def interpolate_rates(
194
194
  0 0.13972
195
195
  1 0.134613
196
196
  2 <NA>
197
- dtype: Float64
197
+ dtype: double[pyarrow]
198
198
 
199
199
  >>> # Interpolate rates for a single trade date and multiple expiration dates
200
200
  >>> # There is no DI Contract in 09-05-2025 with expiration 01-01-2050
@@ -206,7 +206,7 @@ def interpolate_rates(
206
206
  ... )
207
207
  0 0.13901
208
208
  1 0.13881
209
- dtype: Float64
209
+ dtype: double[pyarrow]
210
210
 
211
211
  >>> # With extrapolation set to False, the second rate will be NaN
212
212
  >>> # Note: 0.13576348733268917 is shown as 0.135763
@@ -217,7 +217,7 @@ def interpolate_rates(
217
217
  ... )
218
218
  0 0.135763
219
219
  1 <NA>
220
- dtype: Float64
220
+ dtype: double[pyarrow]
221
221
 
222
222
  Notes:
223
223
  - All available settlement rates are used for the flat-forward interpolation.
@@ -250,7 +250,7 @@ def interpolate_rates(
250
250
 
251
251
  # Initialize the interpolated rate column with NaN
252
252
  dfi["irate"] = pd.NA
253
- dfi["irate"] = dfi["irate"].astype("Float64")
253
+ dfi["irate"] = dfi["irate"].astype("float64[pyarrow]")
254
254
 
255
255
  # Load DI rates dataset filtered by the provided reference dates
256
256
  dfr = data(dates=dates)
@@ -127,19 +127,19 @@ def _fetch_url_data(contract_code: str, date: pd.Timestamp) -> pd.DataFrame:
127
127
  thousands=".",
128
128
  decimal=",",
129
129
  na_values=["-"],
130
- dtype_backend="numpy_nullable",
130
+ dtype_backend="pyarrow",
131
131
  encoding="iso-8859-1",
132
132
  )[0]
133
133
 
134
134
  # Remove rows and columns with all NaN values
135
- df = df.dropna(axis=0, how="all").dropna(axis=1, how="all").copy()
135
+ df = df.dropna(axis=0, how="all").dropna(axis=1, how="all").reset_index(drop=True)
136
136
 
137
137
  # Force "VAR. PTOS." to be string, since it can also be read as float
138
- df["VAR. PTOS."] = df["VAR. PTOS."].astype("string")
138
+ df["VAR. PTOS."] = df["VAR. PTOS."].astype("string[pyarrow]")
139
139
 
140
140
  # Force "AJUSTE CORRIG. (4)" to be float, since it can be also read as int
141
141
  if "AJUSTE CORRIG. (4)" in df.columns:
142
- df["AJUSTE CORRIG. (4)"] = df["AJUSTE CORRIG. (4)"].astype("Float64")
142
+ df["AJUSTE CORRIG. (4)"] = df["AJUSTE CORRIG. (4)"].astype("float64[pyarrow]")
143
143
 
144
144
  return df
145
145
 
@@ -180,29 +180,32 @@ def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
180
180
  return df.rename(columns=rename_dict)
181
181
 
182
182
 
183
- def process_df(
184
- input_df: pd.DataFrame, date: pd.Timestamp, contract_code: str
183
+ def _process_df(
184
+ df: pd.DataFrame, date: pd.Timestamp, contract_code: str
185
185
  ) -> pd.DataFrame:
186
- df = input_df.copy()
187
186
  df["TradeDate"] = date
188
- # Convert to datetime64[ns] since it is pandas default type for timestamps
189
- df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
187
+ df["TradeDate"] = df["TradeDate"].astype("date32[pyarrow]")
190
188
  df["TickerSymbol"] = contract_code + df["ExpirationCode"]
191
189
 
192
190
  # Contract code format was changed in 22/05/2006
193
- if date < pd.Timestamp("2006-05-22"):
194
- df["ExpirationDate"] = df["ExpirationCode"].apply(
195
- lambda code: get_old_expiration_date(code, date)
196
- ) # type: ignore
191
+ code_format_change = pd.to_datetime("22-05-2006", dayfirst=True)
192
+ if date < code_format_change:
193
+ df["ExpirationDate"] = (
194
+ df["ExpirationCode"]
195
+ .apply(lambda code: get_old_expiration_date(code, date))
196
+ .astype("date32[pyarrow]")
197
+ )
197
198
  else:
198
199
  expiration_day = 15 if contract_code == "DAP" else 1
199
- df["ExpirationDate"] = df["ExpirationCode"].apply(
200
- lambda code: common.get_expiration_date(code, expiration_day)
201
- ) # type: ignore
200
+ df["ExpirationDate"] = (
201
+ df["ExpirationCode"]
202
+ .apply(lambda code: common.get_expiration_date(code, expiration_day))
203
+ .astype("date32[pyarrow]")
204
+ )
202
205
 
203
206
  df["DaysToExp"] = (df["ExpirationDate"] - date).dt.days
204
207
  # Convert to nullable integer, since it is the default type in the library
205
- df["DaysToExp"] = df["DaysToExp"].astype("Int64")
208
+ df["DaysToExp"] = df["DaysToExp"].astype("int64[pyarrow]")
206
209
 
207
210
  df["BDaysToExp"] = bday.count(date, df["ExpirationDate"])
208
211
 
@@ -218,7 +221,8 @@ def process_df(
218
221
 
219
222
  rate_cols = [col for col in df.columns if "Rate" in col]
220
223
  # Prior to 17/01/2002 (inclusive), DI prices were not converted to rates
221
- if date <= pd.Timestamp("2002-01-17") and contract_code == "DI1":
224
+ switch_date = pd.to_datetime("17-01-2002", dayfirst=True)
225
+ if date <= switch_date and contract_code == "DI1":
222
226
  df = _adjust_older_contracts_rates(df, rate_cols)
223
227
  else:
224
228
  # Remove % and round to 5 (3 in %) dec. places in rate columns
@@ -244,7 +248,10 @@ def process_df(
244
248
  df["DV01"] = 0.0001 * modified_duration * df["SettlementPrice"]
245
249
 
246
250
  if contract_code in {"DI1", "DAP"}: # Calculate forwards for DI1 and DAP contracts
247
- df["ForwardRate"] = forwards(bdays=df["BDaysToExp"], rates=df["SettlementRate"])
251
+ df["ForwardRate"] = forwards(
252
+ bdays=df["BDaysToExp"],
253
+ rates=df["SettlementRate"],
254
+ )
248
255
 
249
256
  return df
250
257
 
@@ -276,7 +283,7 @@ def _select_and_reorder_columns(df: pd.DataFrame):
276
283
  "ForwardRate",
277
284
  ]
278
285
  reordered_columns = [col for col in all_columns if col in df.columns]
279
- return df[reordered_columns]
286
+ return df[reordered_columns].copy()
280
287
 
281
288
 
282
289
  def fetch_bmf_data(contract_code: str, date: pd.Timestamp) -> pd.DataFrame:
@@ -305,6 +312,6 @@ def fetch_bmf_data(contract_code: str, date: pd.Timestamp) -> pd.DataFrame:
305
312
  return pd.DataFrame()
306
313
 
307
314
  df = _rename_columns(df_raw)
308
- df = process_df(df, date, contract_code)
315
+ df = _process_df(df, date, contract_code)
309
316
  df = _select_and_reorder_columns(df)
310
317
  return df
@@ -52,7 +52,7 @@ def _fetch_b3_df(contract_code: str) -> pd.DataFrame:
52
52
  df = pd.json_normalize(r.json()["Scty"])
53
53
 
54
54
  # Convert columns to the most appropriate data type
55
- return df.convert_dtypes()
55
+ return df.convert_dtypes(dtype_backend="pyarrow")
56
56
 
57
57
 
58
58
  def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
@@ -89,10 +89,8 @@ def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
89
89
  return df
90
90
 
91
91
 
92
- def _process_df(raw_df: pd.DataFrame, contract_code: str) -> pd.DataFrame:
92
+ def _process_df(df: pd.DataFrame, contract_code: str) -> pd.DataFrame:
93
93
  """Process the raw DataFrame from B3 API."""
94
- df = raw_df.copy()
95
-
96
94
  # Clean and reformat the DataFrame columns
97
95
  df.columns = (df.columns
98
96
  .str.replace("SctyQtn.", "")
@@ -103,25 +101,30 @@ def _process_df(raw_df: pd.DataFrame, contract_code: str) -> pd.DataFrame:
103
101
  df = _rename_columns(df)
104
102
 
105
103
  # Convert maturity codes to datetime and drop rows with missing values
106
- df["ExpirationDate"] = pd.to_datetime(df["ExpirationDate"], errors="coerce")
107
- df.dropna(subset=["ExpirationDate"], inplace=True)
104
+ df["ExpirationDate"] = pd.to_datetime(df["ExpirationDate"], errors="coerce").astype(
105
+ "date32[pyarrow]"
106
+ )
108
107
 
109
108
  # Sort the DataFrame by maturity code and reset the index
110
- df.sort_values("ExpirationDate", inplace=True, ignore_index=True)
109
+ df = (
110
+ df.dropna(subset=["ExpirationDate"])
111
+ .sort_values("ExpirationDate")
112
+ .reset_index(drop=True)
113
+ )
111
114
 
112
115
  # Get currante date in Brazil
113
116
  df["TradeDate"] = bday.last_business_day()
117
+ df["TradeDate"] = df["TradeDate"].astype("date32[pyarrow]")
114
118
 
115
119
  # Get current date and time
116
- now = pd.Timestamp.now(BZ_TIMEZONE).round("s").tz_localize(None)
120
+ # now = pd.Timestamp.now(BZ_TIMEZONE).round("s").tz_localize(None)
121
+ now = dt.datetime.now(BZ_TIMEZONE)
117
122
  # Subtract 15 minutes from the current time to account for API delay
118
123
  df["LastUpdate"] = now - pd.Timedelta(minutes=15)
119
124
 
120
125
  df["BDaysToExp"] = bday.count(df["TradeDate"], df["ExpirationDate"])
121
126
 
122
127
  df["DaysToExp"] = (df["ExpirationDate"] - df["TradeDate"]).dt.days
123
- # Convert to nullable integer, since it is the default type in the library
124
- df["DaysToExp"] = df["DaysToExp"].astype("Int64")
125
128
 
126
129
  # Remove expired contracts
127
130
  df = df.query("DaysToExp >= 0").reset_index(drop=True)
@@ -136,7 +139,7 @@ def _process_df(raw_df: pd.DataFrame, contract_code: str) -> pd.DataFrame:
136
139
  if contract_code in {"DI1", "DAP"}: # Add LastPrice for DI1 and DAP
137
140
  byears = df["BDaysToExp"] / 252
138
141
  df["LastPrice"] = 100_000 / ((1 + df["LastRate"]) ** byears)
139
- df["LastPrice"] = df["LastPrice"].round(2).astype("Float64")
142
+ df["LastPrice"] = df["LastPrice"].round(2)
140
143
  df["ForwardRate"] = forwards(bdays=df["BDaysToExp"], rates=df["LastRate"])
141
144
 
142
145
  if contract_code == "DI1": # Add DV01 for DI1
@@ -150,7 +150,7 @@ def _create_df_from_data(di1_data: list) -> pd.DataFrame:
150
150
 
151
151
  # Convert to CSV and then back to pandas to get automatic type conversion
152
152
  file = io.StringIO(df.to_csv(index=False))
153
- return pd.read_csv(file, dtype_backend="numpy_nullable")
153
+ return pd.read_csv(file, dtype_backend="pyarrow")
154
154
 
155
155
 
156
156
  def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
@@ -193,18 +193,18 @@ def _rename_columns(df: pd.DataFrame) -> pd.DataFrame:
193
193
  def _process_df(df_raw: pd.DataFrame) -> pd.DataFrame:
194
194
  df = df_raw.copy()
195
195
  # Convert to datetime64[ns] since it is pandas default type for timestamps
196
- df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
196
+ df["TradeDate"] = df["TradeDate"].astype("date32[pyarrow]")
197
197
 
198
198
  expiration_code = df["TickerSymbol"].str[3:]
199
199
  contract_code = df["TickerSymbol"].str[:3].loc[0]
200
200
  expiration_day = 15 if contract_code == "DAP" else 1
201
201
  df["ExpirationDate"] = expiration_code.apply(
202
202
  common.get_expiration_date, args=(expiration_day,)
203
- )
203
+ ).astype("date32[pyarrow]")
204
204
 
205
205
  df["DaysToExp"] = (df["ExpirationDate"] - df["TradeDate"]).dt.days
206
206
  # Convert to nullable integer, since it is the default type in the library
207
- df["DaysToExp"] = df["DaysToExp"].astype("Int64")
207
+ df["DaysToExp"] = df["DaysToExp"].astype("int64[pyarrow]")
208
208
 
209
209
  # Remove expired contracts
210
210
  df = df.query("DaysToExp > 0").reset_index(drop=True)
@@ -153,10 +153,7 @@ def _process_df(df: pd.DataFrame) -> pd.DataFrame:
153
153
  df["AvgPrice"] = df["AvgPrice"].where(keep_avg_price, adjusted_avg_price)
154
154
 
155
155
  # Usar a data de liquidação para calcular o número de dias úteis até o vencimento
156
- df["BDToMat"] = bday.count(
157
- start=df["Settlement"],
158
- end=df["Maturity"],
159
- ).astype("int64[pyarrow]")
156
+ df["BDToMat"] = bday.count(start=df["Settlement"], end=df["Maturity"])
160
157
 
161
158
  return df
162
159
 
@@ -97,8 +97,10 @@ def _fetch_request(
97
97
 
98
98
  df = pd.DataFrame(data, dtype="string")
99
99
  df = df.rename(columns={"data": "Date", "valor": "Value"})
100
- df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y")
101
- df["Value"] = (df["Value"].astype("Float64")) / 100
100
+ df["Date"] = pd.to_datetime(df["Date"], format="%d/%m/%Y").astype(
101
+ "date32[pyarrow]"
102
+ )
103
+ df["Value"] = (df["Value"].astype("float64[pyarrow]")) / 100
102
104
 
103
105
  return df
104
106
 
@@ -240,7 +242,7 @@ def selic_over(date: DateScalar) -> float:
240
242
  df = selic_over_series(date, date)
241
243
  if df.empty:
242
244
  return float("nan")
243
- return float(df.at[0, "Value"])
245
+ return round(df.at[0, "Value"], 4)
244
246
 
245
247
 
246
248
  def selic_target_series(
@@ -44,7 +44,7 @@ def _load_from_url(url: str) -> pd.DataFrame:
44
44
  response.raise_for_status()
45
45
  return pd.read_csv(
46
46
  io.StringIO(response.text),
47
- dtype_backend="numpy_nullable",
47
+ dtype_backend="pyarrow",
48
48
  decimal=",",
49
49
  date_format="%Y-%m-%d",
50
50
  parse_dates=["dataMovimento", "dataLiquidacao", "dataRetorno"],
@@ -58,9 +58,13 @@ def _pre_process_df(df: pd.DataFrame) -> pd.DataFrame:
58
58
 
59
59
 
60
60
  def _process_df(df: pd.DataFrame) -> pd.DataFrame:
61
+ df["Date"] = df["Date"].astype("date32[pyarrow]")
62
+ df["Settlement"] = df["Settlement"].astype("date32[pyarrow]")
61
63
  df["StartTime"] = pd.to_datetime(df["StartTime"], format="%H:%M").dt.time
62
64
  # AcceptedVolume é em milhares de reais -> converter para reais
63
- df["AcceptedVolume"] = (1_000 * df["AcceptedVolume"]).round(0).astype("Int64")
65
+ df["AcceptedVolume"] = (
66
+ (1_000 * df["AcceptedVolume"]).round(0).astype("int64[pyarrow]")
67
+ )
64
68
 
65
69
  # Remove the percentage sign and round to 6 decimal places (4 decimal places in %)
66
70
  df["CutRate"] = (df["CutRate"] / 100).round(6)
@@ -292,19 +292,19 @@ def count(
292
292
  >>> bday.count(start="01-01-2024", end=["01-02-2024", "01-03-2024"])
293
293
  0 22
294
294
  1 41
295
- dtype: Int64
295
+ dtype: int64[pyarrow]
296
296
 
297
297
  The remaining business days in January and February to the end of the year
298
298
  >>> bday.count(["01-01-2024", "01-02-2024"], "01-01-2025")
299
299
  0 253
300
300
  1 231
301
- dtype: Int64
301
+ dtype: int64[pyarrow]
302
302
 
303
303
  The total business days in January and February of 2024
304
304
  >>> bday.count(["01-01-2024", "01-02-2024"], ["01-02-2024", "01-03-2024"])
305
305
  0 22
306
306
  1 19
307
- dtype: Int64
307
+ dtype: int64[pyarrow]
308
308
 
309
309
  Null values are propagated
310
310
  >>> bday.count(pd.NaT, "01-01-2024") # NaT start
@@ -316,7 +316,7 @@ def count(
316
316
  >>> bday.count("01-01-2024", ["01-02-2024", pd.NaT]) # NaT in end array
317
317
  0 22
318
318
  1 <NA>
319
- dtype: Int64
319
+ dtype: int64[pyarrow]
320
320
 
321
321
  Original pandas index is preserved
322
322
  >>> start_dates = pd.Series(
@@ -327,7 +327,7 @@ def count(
327
327
  a 253
328
328
  b 231
329
329
  c 212
330
- dtype: Int64
330
+ dtype: int64[pyarrow]
331
331
  """
332
332
  # Padroniza as entradas para objetos do Pandas
333
333
  start_pd = dc.convert_input_dates(start)
@@ -364,7 +364,7 @@ def count(
364
364
 
365
365
  # Inicializa a série de resultados com o índice correto e tipo que suporta NA.
366
366
  # Nulos nas entradas (start_pd ou end_pd) resultarão em NA aqui.
367
- result = pd.Series(index=start_pd.index, dtype="Int64")
367
+ result = pd.Series(index=start_pd.index, dtype="int64[pyarrow]")
368
368
 
369
369
  # Cria máscaras para linhas não-nulas, divididas pelo calendário de feriados.
370
370
  # A lógica de feriados depende APENAS da data de início.
@@ -67,7 +67,7 @@ def forwards(
67
67
  0 0.05
68
68
  1 0.070095
69
69
  2 0.090284
70
- dtype: Float64
70
+ dtype: double[pyarrow]
71
71
 
72
72
  >>> # Exemplo com agrupamento (a última está isolada em outro grupo)
73
73
  >>> groupby_dates = pd.Series([1, 1, 2])
@@ -75,7 +75,7 @@ def forwards(
75
75
  0 0.05
76
76
  1 0.070095
77
77
  2 0.07
78
- dtype: Float64
78
+ dtype: double[pyarrow]
79
79
 
80
80
  Note:
81
81
  - A função ordena os dados de entrada primeiro por `groupby_dates`,
@@ -83,8 +83,8 @@ def forwards(
83
83
  correta no cálculo das taxas a termo.
84
84
  - Os resultados são retornados na mesma ordem dos dados de entrada.
85
85
  """ # noqa: E501
86
- bdays = bdays.astype("Int64")
87
- rates = rates.astype("Float64")
86
+ bdays = bdays.astype("int64[pyarrow]")
87
+ rates = rates.astype("float64[pyarrow]")
88
88
 
89
89
  # Check if indexes are the same
90
90
  if not bdays.index.equals(rates.index):
@@ -46,7 +46,7 @@ def _process_ipca_dataframe(
46
46
  else:
47
47
  df["Value"] = df["Value"].round(2)
48
48
 
49
- df["Value"] = df["Value"].astype("Float64")
49
+ df["Value"] = df["Value"].astype("float64[pyarrow]")
50
50
  df["Period"] = pd.to_datetime(df["Period"], format="%Y%m").dt.to_period("M")
51
51
 
52
52
  return df
@@ -51,7 +51,6 @@ def data(date: DateScalar) -> pd.DataFrame:
51
51
  11 2024-08-23 NTN-B 2050-08-15 0.06114 4279.434119
52
52
  12 2024-08-23 NTN-B 2055-05-15 0.060892 4355.145036
53
53
  13 2024-08-23 NTN-B 2060-08-15 0.061005 4282.308398
54
-
55
54
  """
56
55
  return anbima.tpf_data(date, "NTN-B")
57
56
 
@@ -410,8 +409,8 @@ def spot_rates(
410
409
  df.at[index, "SpotRate"] = price_factor ** (1 / row["BYears"]) - 1
411
410
 
412
411
  df = df[["MaturityDate", "BDToMat", "SpotRate"]].copy()
413
- # Force Float64 type in float columns to standardize the output
414
- df["SpotRate"] = df["SpotRate"].astype("Float64")
412
+ # Force float64 type in float columns to standardize the output
413
+ df["SpotRate"] = df["SpotRate"].astype("float64[pyarrow]")
415
414
 
416
415
  # Filter the result without the intermediate coupon dates (virtual bonds)
417
416
  if not show_coupons:
@@ -506,7 +505,7 @@ def bei_rates(
506
505
  extrapolate=True,
507
506
  )
508
507
 
509
- df["NIR"] = df["BDToMat"].apply(nir_interplator).astype("Float64")
508
+ df["NIR"] = df["BDToMat"].apply(nir_interplator).astype("float64[pyarrow]")
510
509
  # Calculate Breakeven Inflation Rate (BEI)
511
510
  df["BEI"] = ((df["NIR"] + 1) / (df["RIR"] + 1)) - 1
512
511
 
@@ -322,7 +322,7 @@ def spot_rates( # noqa
322
322
  df.at[index, "SpotRate"] = price_factor ** (1 / row["BYears"]) - 1
323
323
 
324
324
  df = df[["MaturityDate", "BDToMat", "SpotRate"]].copy()
325
- df["SpotRate"] = df["SpotRate"].astype("Float64")
325
+ df["SpotRate"] = df["SpotRate"].astype("float64[pyarrow]")
326
326
 
327
327
  if not show_coupons:
328
328
  df = df.query("MaturityDate in @ntnf_maturities").reset_index(drop=True)
@@ -87,14 +87,14 @@ def spot_rates(date: DateScalar) -> pd.DataFrame:
87
87
  ltn_subset = _process_additional_ltn(date, ltn_not_in_ntnf)
88
88
 
89
89
  # Ensure consistent data types
90
- ltn_subset["BDToMat"] = ltn_subset["BDToMat"].astype("int64")
91
- df_spots["BDToMat"] = df_spots["BDToMat"].astype("int64")
90
+ ltn_subset["BDToMat"] = ltn_subset["BDToMat"].astype("int64[pyarrow]")
91
+ df_spots["BDToMat"] = df_spots["BDToMat"].astype("int64[pyarrow]")
92
92
 
93
93
  # Combine LTN and NTN-F derived spot rates
94
94
  df_combined = pd.concat([df_spots, ltn_subset], ignore_index=True)
95
95
  else:
96
96
  df_combined = df_spots.copy()
97
- df_combined["BDToMat"] = df_combined["BDToMat"].astype("int64")
97
+ df_combined["BDToMat"] = df_combined["BDToMat"].astype("int64[pyarrow]")
98
98
 
99
99
  # Final validation - ensure no NaN values in the result
100
100
  _validate_final_result(df_combined)
@@ -1 +0,0 @@
1
- __version__ = "0.37.1"
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