PYield 0.7.5__tar.gz → 0.7.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. {pyield-0.7.5 → pyield-0.7.7}/PKG-INFO +1 -1
  2. pyield-0.7.7/pyield/__about__.py +1 -0
  3. {pyield-0.7.5 → pyield-0.7.7}/pyield/data_access.py +1 -1
  4. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/common.py +82 -0
  5. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/ddi.py +26 -66
  6. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/di.py +33 -84
  7. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/frc.py +8 -45
  8. {pyield-0.7.5 → pyield-0.7.7}/pyield/projections.py +7 -4
  9. {pyield-0.7.5 → pyield-0.7.7}/pyproject.toml +1 -1
  10. pyield-0.7.5/pyield/__about__.py +0 -1
  11. {pyield-0.7.5 → pyield-0.7.7}/LICENSE +0 -0
  12. {pyield-0.7.5 → pyield-0.7.7}/README.md +0 -0
  13. {pyield-0.7.5 → pyield-0.7.7}/pyield/__init__.py +0 -0
  14. {pyield-0.7.5 → pyield-0.7.7}/pyield/bday.py +0 -0
  15. {pyield-0.7.5 → pyield-0.7.7}/pyield/data_analysis.py +0 -0
  16. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/__init__.py +0 -0
  17. {pyield-0.7.5 → pyield-0.7.7}/pyield/futures/di_xml.py +0 -0
  18. {pyield-0.7.5 → pyield-0.7.7}/pyield/holidays/__init__.py +0 -0
  19. {pyield-0.7.5 → pyield-0.7.7}/pyield/holidays/br_holidays_new.txt +0 -0
  20. {pyield-0.7.5 → pyield-0.7.7}/pyield/holidays/br_holidays_old.txt +0 -0
  21. {pyield-0.7.5 → pyield-0.7.7}/pyield/holidays/core.py +0 -0
  22. {pyield-0.7.5 → pyield-0.7.7}/pyield/indicators.py +0 -0
  23. {pyield-0.7.5 → pyield-0.7.7}/pyield/py.typed +0 -0
  24. {pyield-0.7.5 → pyield-0.7.7}/pyield/treasuries.py +0 -0
  25. {pyield-0.7.5 → pyield-0.7.7}/pyield/utils.py +0 -0
  26. {pyield-0.7.5 → pyield-0.7.7}/tests/__init__.py +0 -0
  27. {pyield-0.7.5 → pyield-0.7.7}/tests/test_bday.py +0 -0
  28. {pyield-0.7.5 → pyield-0.7.7}/tests/test_futures.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PYield
3
- Version: 0.7.5
3
+ Version: 0.7.7
4
4
  Summary: A Python library for analysis of fixed income instruments in Brazil
5
5
  Keywords: fixed-income, brazil, finance, analysis, bonds
6
6
  Author-Email: Carlos Carvalho <cr.cj@outlook.com>
@@ -0,0 +1 @@
1
+ __version__ = "0.7.7"
@@ -111,7 +111,7 @@ def fetch_indicator(
111
111
  raise ValueError("Indicator type not supported.")
112
112
 
113
113
 
114
- def fetch_projection(projection_code: str) -> dict:
114
+ def fetch_projection(projection_code: str) -> pr.IndicatorProjection:
115
115
  """
116
116
  Fetches a financial projection for a specified code and reference date.
117
117
 
@@ -5,6 +5,28 @@ import requests
5
5
 
6
6
  from .. import bday
7
7
 
8
+ COLUMNS_MAPPING = {
9
+ "VENCTO": "ExpirationCode",
10
+ "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
11
+ "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
12
+ "NÚM. NEGOC.": "TradeCount",
13
+ "CONTR. NEGOC.": "TradeVolume",
14
+ "VOL.": "FinancialVolume",
15
+ "AJUSTE": "SettlementPrice",
16
+ "AJUSTE ANTER. (3)": "PrevSettlementRate",
17
+ "AJUSTE CORRIG. (4)": "AdjSettlementRate",
18
+ "AJUSTE DE REF.": "SettlementRate", # FRC
19
+ "PREÇO MÍN.": "MinRate",
20
+ "PREÇO MÉD.": "AvgRate",
21
+ "PREÇO MÁX.": "MaxRate",
22
+ "PREÇO ABERTU.": "FirstRate",
23
+ "ÚLT. PREÇO": "CloseRate",
24
+ "VAR. PTOS.": "PointsVariation",
25
+ # Attention: bid/ask rates are inverted
26
+ "ÚLT.OF. COMPRA": "CloseAskRate",
27
+ "ÚLT.OF. VENDA": "CloseBidRate",
28
+ }
29
+
8
30
 
9
31
  def get_expiration_date(expiration_code: str) -> pd.Timestamp:
10
32
  """
@@ -228,3 +250,63 @@ def fetch_last_raw_df(future_code: str) -> pd.DataFrame:
228
250
  df = df.convert_dtypes(dtype_backend="numpy_nullable")
229
251
 
230
252
  return df
253
+
254
+
255
+ def rename_columns(df: pd.DataFrame):
256
+ all_columns = {
257
+ "VENCTO": "ExpirationCode",
258
+ "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
259
+ "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
260
+ "NÚM. NEGOC.": "TradeCount",
261
+ "CONTR. NEGOC.": "TradeVolume",
262
+ "VOL.": "FinancialVolume",
263
+ "AJUSTE": "SettlementPrice",
264
+ "AJUSTE ANTER. (3)": "PrevSettlementRate",
265
+ "AJUSTE CORRIG. (4)": "AdjSettlementRate",
266
+ "AJUSTE DE REF.": "SettlementRate", # FRC
267
+ "PREÇO MÍN.": "MinRate",
268
+ "PREÇO MÉD.": "AvgRate",
269
+ "PREÇO MÁX.": "MaxRate",
270
+ "PREÇO ABERTU.": "FirstRate",
271
+ "ÚLT. PREÇO": "CloseRate",
272
+ "VAR. PTOS.": "PointsVariation",
273
+ # Attention: bid/ask rates are inverted
274
+ "ÚLT.OF. COMPRA": "CloseAskRate",
275
+ "ÚLT.OF. VENDA": "CloseBidRate",
276
+ }
277
+ rename_dict = {}
278
+ for col in all_columns:
279
+ if col in df.columns:
280
+ rename_dict[col] = all_columns[col]
281
+ return df.rename(columns=rename_dict)
282
+
283
+
284
+ def reorder_columns(df: pd.DataFrame):
285
+ all_columns = [
286
+ "TradeDate",
287
+ "TickerSymbol",
288
+ # "ExpirationCode",
289
+ "ExpirationDate",
290
+ "BDaysToExp",
291
+ "DaysToExp",
292
+ "OpenContracts",
293
+ # "OpenContractsEndSession" since there is no OpenContracts at the end of the
294
+ # day in XML data, it will be removed to avoid confusion with XML data
295
+ "TradeCount",
296
+ "TradeVolume",
297
+ "FinancialVolume",
298
+ "SettlementPrice",
299
+ "SettlementRate",
300
+ "FirstRate",
301
+ "MinRate",
302
+ "AvgRate",
303
+ "MaxRate",
304
+ "CloseAskRate",
305
+ "CloseBidRate",
306
+ "CloseRate",
307
+ ]
308
+ reordered_columns = []
309
+ for col in all_columns:
310
+ if col in df.columns:
311
+ reordered_columns.append(col)
312
+ return df[reordered_columns]
@@ -1,6 +1,6 @@
1
1
  import pandas as pd
2
2
 
3
- from . import common
3
+ from . import common as cm
4
4
 
5
5
 
6
6
  def _convert_prices_to_rates(prices: pd.Series, n_days: pd.Series) -> pd.Series:
@@ -15,9 +15,8 @@ def _convert_prices_to_rates(prices: pd.Series, n_days: pd.Series) -> pd.Series:
15
15
  pd.Series: A pd.Series containing DDI futures rates.
16
16
  """
17
17
  rates = (100_000 / prices - 1) * (360 / n_days)
18
-
19
- # Return rates as percentage
20
- return 100 * rates
18
+ # Round to 5 (3 in %) dec. places (contract's current max. precision)
19
+ return rates.round(5)
21
20
 
22
21
 
23
22
  def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
@@ -31,32 +30,7 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
31
30
  Returns:
32
31
  pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
33
32
  """
34
- # Check if the pd.DataFrame is empty
35
- if df.empty:
36
- return df
37
-
38
- rename_dict = {
39
- "VENCTO": "ExpirationCode",
40
- "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
41
- "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
42
- "NÚM. NEGOC.": "TradeCount",
43
- "CONTR. NEGOC.": "TradeVolume",
44
- "VOL.": "FinancialVolume",
45
- "AJUSTE": "SettlementPrice",
46
- "AJUSTE ANTER. (3)": "PrevSettlementRate",
47
- "AJUSTE CORRIG. (4)": "AdjSettlementRate",
48
- "PREÇO MÍN.": "MinRate",
49
- "PREÇO MÉD.": "AvgRate",
50
- "PREÇO MÁX.": "MaxRate",
51
- "PREÇO ABERTU.": "FirstRate",
52
- "ÚLT. PREÇO": "LastRate",
53
- "VAR. PTOS.": "PointsVariation",
54
- # Attention: bid/ask rates are inverted
55
- "ÚLT.OF. COMPRA": "LastAskRate",
56
- "ÚLT.OF. VENDA": "LastBidRate",
57
- }
58
-
59
- df = df.rename(columns=rename_dict)
33
+ df = cm.rename_columns(df)
60
34
 
61
35
  df["TradeDate"] = trade_date
62
36
  # Convert to datetime64[ns] since it is pandas default type for timestamps
@@ -65,51 +39,37 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
65
39
  # Contract code format was changed in 22/05/2006
66
40
  if trade_date < pd.Timestamp("2006-05-22"):
67
41
  df["ExpirationDate"] = df["ExpirationCode"].apply(
68
- common.get_old_expiration_date, args=(trade_date,)
42
+ cm.get_old_expiration_date, args=(trade_date,)
69
43
  )
70
44
  else:
71
- df["ExpirationDate"] = df["ExpirationCode"].apply(common.get_expiration_date)
45
+ df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
72
46
 
73
- df["DaysToExpiration"] = (df["ExpirationDate"] - trade_date).dt.days
47
+ df["DaysToExp"] = (df["ExpirationDate"] - trade_date).dt.days
74
48
  # Convert to nullable integer, since other columns use this data type
75
- df["DaysToExpiration"] = df["DaysToExpiration"].astype(pd.Int64Dtype())
76
- # Remove expired contracts
77
- df.query("DaysToExpiration > 0", inplace=True)
49
+ df["DaysToExp"] = df["DaysToExp"].astype(pd.Int64Dtype())
78
50
 
79
- df["SettlementRate"] = _convert_prices_to_rates(
80
- df["SettlementPrice"], df["DaysToExpiration"]
81
- )
51
+ # Remove expired contracts
52
+ df.query("DaysToExp > 0", inplace=True)
82
53
 
54
+ # Columns where 0 means NaN
83
55
  rate_cols = [col for col in df.columns if "Rate" in col]
84
56
  cols_with_nan = rate_cols + ["SettlementPrice"]
85
- # Columns where 0 means NaN
57
+ # Replace 0 with NaN in these columns
86
58
  df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
87
- # Remove % and round to 5 dec. places (3 in %) since it is the contract's precision
59
+
88
60
  df[rate_cols] = df[rate_cols].div(100).round(5)
89
61
 
62
+ # Calculate SettlementRate
63
+ df["SettlementRate"] = _convert_prices_to_rates(
64
+ df["SettlementPrice"], df["DaysToExp"]
65
+ )
66
+
67
+ df["TickerSymbol"] = "DI1" + df["ExpirationCode"]
68
+
90
69
  # Filter and order columns
91
- ordered_cols = [
92
- "TradeDate",
93
- "ExpirationCode",
94
- "ExpirationDate",
95
- "DaysToExpiration",
96
- "OpenContracts",
97
- # "OpenContractsEndSession" since there is no OpenContracts at the end of the
98
- # day in XML data, it will be removed to avoid confusion with XML data
99
- "TradeCount",
100
- "TradeVolume",
101
- "FinancialVolume",
102
- "SettlementPrice",
103
- "MinRate",
104
- "AvgRate",
105
- "MaxRate",
106
- "FirstRate",
107
- "LastRate",
108
- "LastAskRate",
109
- "LastBidRate",
110
- "SettlementRate",
111
- ]
112
- return df[ordered_cols]
70
+ df = cm.reorder_columns(df)
71
+
72
+ return df
113
73
 
114
74
 
115
75
  def fetch_past_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
@@ -132,10 +92,10 @@ def fetch_past_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.Dat
132
92
  >>> di.fetch_ddi(pd.Timestamp("2021-01-04"))
133
93
 
134
94
  Notes:
135
- - DaysToExpiration: number of business days to ExpirationDate.
95
+ - DaysToExp: number of business days to ExpirationDate.
136
96
  - OpenContracts: number of open contracts at the start of the trading day.
137
97
  """
138
- df_raw = common.fetch_past_raw_df(asset_code="DDI", trade_date=trade_date)
139
- if return_raw:
98
+ df_raw = cm.fetch_past_raw_df(asset_code="DDI", trade_date=trade_date)
99
+ if return_raw or df_raw.empty:
140
100
  return df_raw
141
101
  return _process_raw_df(df_raw, trade_date)
@@ -1,7 +1,7 @@
1
1
  import pandas as pd
2
2
 
3
- from .. import bday
4
- from . import common
3
+ from .. import bday as bd
4
+ from . import common as cm
5
5
 
6
6
 
7
7
  def _convert_prices_to_rates(prices: pd.Series, bd: pd.Series) -> pd.Series:
@@ -17,22 +17,12 @@ def _convert_prices_to_rates(prices: pd.Series, bd: pd.Series) -> pd.Series:
17
17
  """
18
18
  rates = (100_000 / prices) ** (252 / bd) - 1
19
19
 
20
- # Return rates as percentage
21
- return 100 * rates
22
-
23
-
24
- def _convert_prices_in_older_contracts(df: pd.DataFrame) -> pd.DataFrame:
25
- # Prior to 01/01/2002, prices were not converted to rates
26
- convert_cols = [
27
- "FirstRate",
28
- "MinRate",
29
- "MaxRate",
30
- "AvgRate",
31
- "CloseRate",
32
- "CloseBidRate",
33
- "CloseAskRate",
34
- ]
35
- for col in convert_cols:
20
+ # Round to 5 (3 in %) dec. places (contract's current max. precision)
21
+ return rates.round(5)
22
+
23
+
24
+ def _adjust_older_contracts_rates(df: pd.DataFrame, rate_cols: list) -> pd.DataFrame:
25
+ for col in rate_cols:
36
26
  df[col] = _convert_prices_to_rates(df[col], df["BDaysToExp"])
37
27
 
38
28
  # Invert low and high prices
@@ -52,28 +42,7 @@ def _process_past_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataF
52
42
  Returns:
53
43
  pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
54
44
  """
55
- rename_dict = {
56
- "VENCTO": "ExpirationCode",
57
- "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
58
- "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
59
- "NÚM. NEGOC.": "TradeCount",
60
- "CONTR. NEGOC.": "TradeVolume",
61
- "VOL.": "FinancialVolume",
62
- "AJUSTE": "SettlementPrice",
63
- "AJUSTE ANTER. (3)": "PrevSettlementRate",
64
- "AJUSTE CORRIG. (4)": "AdjSettlementRate",
65
- "PREÇO MÍN.": "MinRate",
66
- "PREÇO MÉD.": "AvgRate",
67
- "PREÇO MÁX.": "MaxRate",
68
- "PREÇO ABERTU.": "FirstRate",
69
- "ÚLT. PREÇO": "CloseRate",
70
- "VAR. PTOS.": "PointsVariation",
71
- # Attention: bid/ask rates are inverted
72
- "ÚLT.OF. COMPRA": "CloseAskRate",
73
- "ÚLT.OF. VENDA": "CloseBidRate",
74
- }
75
-
76
- df = df.rename(columns=rename_dict)
45
+ df = cm.rename_columns(df)
77
46
 
78
47
  df["TradeDate"] = trade_date
79
48
  # Convert to datetime64[ns] since it is pandas default type for timestamps
@@ -82,56 +51,39 @@ def _process_past_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataF
82
51
  # Contract code format was changed in 22/05/2006
83
52
  if trade_date < pd.Timestamp("2006-05-22"):
84
53
  df["ExpirationDate"] = df["ExpirationCode"].apply(
85
- common.get_old_expiration_date, args=(trade_date,)
54
+ cm.get_old_expiration_date, args=(trade_date,)
86
55
  )
87
56
  else:
88
- df["ExpirationDate"] = df["ExpirationCode"].apply(common.get_expiration_date)
57
+ df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
58
+
59
+ df["BDaysToExp"] = bd.count_bdays(trade_date, df["ExpirationDate"])
89
60
 
90
- df["BDaysToExp"] = bday.count_bdays(trade_date, df["ExpirationDate"])
91
61
  # Remove expired contracts
92
62
  df.query("BDaysToExp > 0", inplace=True)
93
63
 
94
- # Prior to 17/01/2002 (incluive), prices were not converted to rates
95
- if trade_date <= pd.Timestamp("2002-01-17"):
96
- df = _convert_prices_in_older_contracts(df)
64
+ # Columns where 0 means NaN
65
+ rate_cols = [col for col in df.columns if "Rate" in col]
66
+ cols_with_nan = rate_cols + ["SettlementPrice"]
67
+ # Replace 0 with NaN in these columns
68
+ df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
69
+
70
+ # Prior to 17/01/2002 (inclusive), prices were not converted to rates
71
+ if trade_date > pd.Timestamp("2002-01-17"):
72
+ # Remove % and round to 5 (3 in %) dec. places in rate columns
73
+ df[rate_cols] = df[rate_cols].div(100).round(5)
74
+ else:
75
+ df = _adjust_older_contracts_rates(df, rate_cols)
97
76
 
77
+ # Calculate SettlementRate
98
78
  df["SettlementRate"] = _convert_prices_to_rates(
99
79
  df["SettlementPrice"], df["BDaysToExp"]
100
80
  )
101
81
 
102
- rate_cols = [col for col in df.columns if "Rate" in col]
103
- cols_with_nan = rate_cols + ["SettlementPrice"]
104
- # Columns where 0 means NaN
105
- df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
106
- # Remove % and round to 5 dec. places (3 in %) since it is the contract's precision
107
- df[rate_cols] = df[rate_cols].div(100).round(5)
108
-
109
82
  df["TickerSymbol"] = "DI1" + df["ExpirationCode"]
110
83
 
111
84
  # Filter and order columns
112
- ordered_cols = [
113
- "TradeDate",
114
- "TickerSymbol",
115
- # "ExpirationCode",
116
- "ExpirationDate",
117
- "BDaysToExp",
118
- "OpenContracts",
119
- # "OpenContractsEndSession" since there is no OpenContracts at the end of the
120
- # day in XML data, it will be removed to avoid confusion with XML data
121
- "TradeCount",
122
- "TradeVolume",
123
- "FinancialVolume",
124
- "SettlementPrice",
125
- "SettlementRate",
126
- "FirstRate",
127
- "MinRate",
128
- "AvgRate",
129
- "MaxRate",
130
- "CloseAskRate",
131
- "CloseBidRate",
132
- "CloseRate",
133
- ]
134
- return df[ordered_cols]
85
+ df = cm.reorder_columns(df)
86
+ return df
135
87
 
136
88
 
137
89
  def _process_last_raw_di_df(raw_df: pd.DataFrame) -> pd.DataFrame:
@@ -161,7 +113,7 @@ def _process_last_raw_di_df(raw_df: pd.DataFrame) -> pd.DataFrame:
161
113
  # Rename columns
162
114
  df = df.rename(columns=rename_columns)
163
115
 
164
- df["BDaysToExp"] = bday.count_bdays(df["TradeTimestamp"], df["ExpirationDate"])
116
+ df["BDaysToExp"] = bd.count_bdays(df["TradeTimestamp"], df["ExpirationDate"])
165
117
 
166
118
  # Remove percentage in all rate columns
167
119
  rate_cols = [col for col in df.columns if "Rate" in col]
@@ -178,7 +130,7 @@ def fetch_last_di() -> pd.DataFrame:
178
130
  Returns:
179
131
  pd.DataFrame: A Pandas pd.DataFrame containing the latest DI futures data.
180
132
  """
181
- raw_df = common.fetch_last_raw_df(future_code="DI1")
133
+ raw_df = cm.fetch_last_raw_df(future_code="DI1")
182
134
  return _process_last_raw_di_df(raw_df)
183
135
 
184
136
 
@@ -202,10 +154,7 @@ def fetch_past_di(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.Data
202
154
  - BDaysToExp: number of business days to ExpirationDate.
203
155
  - OpenContracts: number of open contracts at the start of the trading day.
204
156
  """
205
- df_raw = common.fetch_past_raw_df(asset_code="DI1", trade_date=trade_date)
206
- if return_raw:
157
+ df_raw = cm.fetch_past_raw_df(asset_code="DI1", trade_date=trade_date)
158
+ if return_raw or df_raw.empty:
207
159
  return df_raw
208
- if df_raw.empty:
209
- return pd.DataFrame()
210
- else:
211
- return _process_past_raw_df(df_raw, trade_date)
160
+ return _process_past_raw_df(df_raw, trade_date)
@@ -1,6 +1,6 @@
1
1
  import pandas as pd
2
2
 
3
- from . import common
3
+ from . import common as cm
4
4
 
5
5
 
6
6
  def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
@@ -14,28 +14,7 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
14
14
  Returns:
15
15
  pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
16
16
  """
17
- # Check if the pd.DataFrame is empty
18
- if df.empty:
19
- return df
20
-
21
- rename_dict = {
22
- "VENCTO": "ExpirationCode",
23
- "NÚM. NEGOC.": "TradeCount",
24
- "CONTR. NEGOC.": "TradeVolume",
25
- "VOL.": "FinancialVolume",
26
- "AJUSTE DE REF.": "SettlementRate",
27
- "PREÇO ABERTU.": "FirstRate",
28
- "PREÇO MÍN.": "MinRate",
29
- "PREÇO MÉD.": "AvgRate",
30
- "PREÇO MÁX.": "MaxRate",
31
- "ÚLT. PREÇO": "CloseRate",
32
- "VAR. PTOS.": "PointsVariation",
33
- # Attention: bid/ask rates are inverted
34
- "ÚLT.OF. COMPRA": "CloseAskRate",
35
- "ÚLT.OF. VENDA": "CloseBidRate",
36
- }
37
-
38
- df = df.rename(columns=rename_dict)
17
+ df = cm.rename_columns(df)
39
18
 
40
19
  df["TradeDate"] = trade_date
41
20
  # Convert to datetime64[ns] since it is pandas default type for timestamps
@@ -44,10 +23,10 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
44
23
  # Contract code format was changed in 22/05/2006
45
24
  if trade_date < pd.Timestamp("2006-05-22"):
46
25
  df["ExpirationDate"] = df["ExpirationCode"].apply(
47
- common.get_old_expiration_date, args=(trade_date,)
26
+ cm.get_old_expiration_date, args=(trade_date,)
48
27
  )
49
28
  else:
50
- df["ExpirationDate"] = df["ExpirationCode"].apply(common.get_expiration_date)
29
+ df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
51
30
 
52
31
  # Replace 0 values in rate columns with pd.NA and remove percentage
53
32
  rate_cols = [col for col in df.columns if "Rate" in col]
@@ -57,24 +36,8 @@ def _process_past_data(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFra
57
36
  df["TickerSymbol"] = "FRC" + df["ExpirationCode"]
58
37
 
59
38
  # Filter and order columns
60
- ordered_cols = [
61
- "TradeDate",
62
- "TickerSymbol",
63
- # "ExpirationCode",
64
- "ExpirationDate",
65
- "TradeCount",
66
- "TradeVolume",
67
- "FinancialVolume",
68
- "SettlementRate",
69
- "FirstRate",
70
- "MinRate",
71
- "AvgRate",
72
- "MaxRate",
73
- "CloseAskRate",
74
- "CloseBidRate",
75
- "CloseRate",
76
- ]
77
- return df[ordered_cols]
39
+ df = cm.reorder_columns(df)
40
+ return df
78
41
 
79
42
 
80
43
  def fetch_past_frc(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
@@ -92,7 +55,7 @@ def fetch_past_frc(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.Dat
92
55
  Returns:
93
56
  pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
94
57
  """
95
- df_raw = common.fetch_past_raw_df(asset_code="FRC", trade_date=trade_date)
96
- if return_raw:
58
+ df_raw = cm.fetch_past_raw_df(asset_code="FRC", trade_date=trade_date)
59
+ if return_raw or df_raw.empty:
97
60
  return df_raw
98
61
  return _process_past_data(df_raw, trade_date)
@@ -63,19 +63,22 @@ def fetch_current_month_ipca_projection() -> IndicatorProjection:
63
63
  data = workbook.get_sheet_by_name(first_sheet).to_python(skip_empty_area=True)
64
64
 
65
65
  # Extract projection update date and time from the first row
66
- last_update_str = data[0][0].split("Atualização:")[-1].strip()
66
+ update_str = str(data[0][0])
67
+ last_update_str = update_str.split("Atualização:")[-1].strip()
67
68
  last_updated = pd.to_datetime(last_update_str, format="%d/%m/%Y - %H:%M h")
68
69
 
69
70
  # Find the row containing the IPCA projection and extract its data
70
71
  ipca_data = next(line for line in data if "IPCA1" in line)
72
+ ipca_text = str(ipca_data[-1])
71
73
 
72
74
  # Convert the last element of the IPCA data row to float for the projection value
73
- ipca_value = round(float(ipca_data[-1]) / 100, 4)
75
+ ipca_value = round(float(ipca_text) / 100, 4)
74
76
 
75
77
  # Extract and format the reference month
76
- month_text = ipca_data[1].split("(")[-1].split(")")[0]
78
+ projection_text = str(ipca_data[1])
79
+ month_str = projection_text.split("(")[-1].split(")")[0]
77
80
  locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8")
78
- ipca_month_ts = pd.to_datetime(month_text, format="%b/%y")
81
+ ipca_month_ts = pd.to_datetime(month_str, format="%b/%y")
79
82
  ipca_month_br = ipca_month_ts.strftime("%b/%Y").upper()
80
83
  locale.setlocale(locale.LC_TIME, "") # Reset locale to default
81
84
 
@@ -32,7 +32,7 @@ dependencies = [
32
32
  "python-calamine>=0.2.0",
33
33
  ]
34
34
  dynamic = []
35
- version = "0.7.5"
35
+ version = "0.7.7"
36
36
 
37
37
  [project.license]
38
38
  file = "LICENSE"
@@ -1 +0,0 @@
1
- __version__ = "0.7.5"
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