PYield 0.7.6__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.6 → pyield-0.7.7}/PKG-INFO +1 -1
  2. pyield-0.7.7/pyield/__about__.py +1 -0
  3. {pyield-0.7.6 → pyield-0.7.7}/pyield/data_access.py +1 -1
  4. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/common.py +82 -0
  5. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/ddi.py +9 -53
  6. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/di.py +5 -50
  7. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/frc.py +8 -45
  8. {pyield-0.7.6 → pyield-0.7.7}/pyield/projections.py +7 -4
  9. {pyield-0.7.6 → pyield-0.7.7}/pyproject.toml +1 -1
  10. pyield-0.7.6/pyield/__about__.py +0 -1
  11. {pyield-0.7.6 → pyield-0.7.7}/LICENSE +0 -0
  12. {pyield-0.7.6 → pyield-0.7.7}/README.md +0 -0
  13. {pyield-0.7.6 → pyield-0.7.7}/pyield/__init__.py +0 -0
  14. {pyield-0.7.6 → pyield-0.7.7}/pyield/bday.py +0 -0
  15. {pyield-0.7.6 → pyield-0.7.7}/pyield/data_analysis.py +0 -0
  16. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/__init__.py +0 -0
  17. {pyield-0.7.6 → pyield-0.7.7}/pyield/futures/di_xml.py +0 -0
  18. {pyield-0.7.6 → pyield-0.7.7}/pyield/holidays/__init__.py +0 -0
  19. {pyield-0.7.6 → pyield-0.7.7}/pyield/holidays/br_holidays_new.txt +0 -0
  20. {pyield-0.7.6 → pyield-0.7.7}/pyield/holidays/br_holidays_old.txt +0 -0
  21. {pyield-0.7.6 → pyield-0.7.7}/pyield/holidays/core.py +0 -0
  22. {pyield-0.7.6 → pyield-0.7.7}/pyield/indicators.py +0 -0
  23. {pyield-0.7.6 → pyield-0.7.7}/pyield/py.typed +0 -0
  24. {pyield-0.7.6 → pyield-0.7.7}/pyield/treasuries.py +0 -0
  25. {pyield-0.7.6 → pyield-0.7.7}/pyield/utils.py +0 -0
  26. {pyield-0.7.6 → pyield-0.7.7}/tests/__init__.py +0 -0
  27. {pyield-0.7.6 → pyield-0.7.7}/tests/test_bday.py +0 -0
  28. {pyield-0.7.6 → 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.6
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:
@@ -30,32 +30,7 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
30
30
  Returns:
31
31
  pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
32
32
  """
33
- # Check if the pd.DataFrame is empty
34
- if df.empty:
35
- return df
36
-
37
- rename_dict = {
38
- "VENCTO": "ExpirationCode",
39
- "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
40
- "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
41
- "NÚM. NEGOC.": "TradeCount",
42
- "CONTR. NEGOC.": "TradeVolume",
43
- "VOL.": "FinancialVolume",
44
- "AJUSTE": "SettlementPrice",
45
- "AJUSTE ANTER. (3)": "PrevSettlementRate",
46
- "AJUSTE CORRIG. (4)": "AdjSettlementRate",
47
- "PREÇO MÍN.": "MinRate",
48
- "PREÇO MÉD.": "AvgRate",
49
- "PREÇO MÁX.": "MaxRate",
50
- "PREÇO ABERTU.": "FirstRate",
51
- "ÚLT. PREÇO": "LastRate",
52
- "VAR. PTOS.": "PointsVariation",
53
- # Attention: bid/ask rates are inverted
54
- "ÚLT.OF. COMPRA": "LastAskRate",
55
- "ÚLT.OF. VENDA": "LastBidRate",
56
- }
57
-
58
- df = df.rename(columns=rename_dict)
33
+ df = cm.rename_columns(df)
59
34
 
60
35
  df["TradeDate"] = trade_date
61
36
  # Convert to datetime64[ns] since it is pandas default type for timestamps
@@ -64,10 +39,10 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
64
39
  # Contract code format was changed in 22/05/2006
65
40
  if trade_date < pd.Timestamp("2006-05-22"):
66
41
  df["ExpirationDate"] = df["ExpirationCode"].apply(
67
- common.get_old_expiration_date, args=(trade_date,)
42
+ cm.get_old_expiration_date, args=(trade_date,)
68
43
  )
69
44
  else:
70
- df["ExpirationDate"] = df["ExpirationCode"].apply(common.get_expiration_date)
45
+ df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
71
46
 
72
47
  df["DaysToExp"] = (df["ExpirationDate"] - trade_date).dt.days
73
48
  # Convert to nullable integer, since other columns use this data type
@@ -92,28 +67,9 @@ def _process_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
92
67
  df["TickerSymbol"] = "DI1" + df["ExpirationCode"]
93
68
 
94
69
  # Filter and order columns
95
- ordered_cols = [
96
- "TradeDate",
97
- "ExpirationCode",
98
- "ExpirationDate",
99
- "DaysToExp",
100
- "OpenContracts",
101
- # "OpenContractsEndSession" since there is no OpenContracts at the end of the
102
- # day in XML data, it will be removed to avoid confusion with XML data
103
- "TradeCount",
104
- "TradeVolume",
105
- "FinancialVolume",
106
- "SettlementPrice",
107
- "MinRate",
108
- "AvgRate",
109
- "MaxRate",
110
- "FirstRate",
111
- "LastRate",
112
- "LastAskRate",
113
- "LastBidRate",
114
- "SettlementRate",
115
- ]
116
- return df[ordered_cols]
70
+ df = cm.reorder_columns(df)
71
+
72
+ return df
117
73
 
118
74
 
119
75
  def fetch_past_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
@@ -139,7 +95,7 @@ def fetch_past_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.Dat
139
95
  - DaysToExp: number of business days to ExpirationDate.
140
96
  - OpenContracts: number of open contracts at the start of the trading day.
141
97
  """
142
- df_raw = common.fetch_past_raw_df(asset_code="DDI", trade_date=trade_date)
143
- 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:
144
100
  return df_raw
145
101
  return _process_raw_df(df_raw, trade_date)
@@ -42,28 +42,7 @@ def _process_past_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataF
42
42
  Returns:
43
43
  pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
44
44
  """
45
- rename_dict = {
46
- "VENCTO": "ExpirationCode",
47
- "CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
48
- "CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
49
- "NÚM. NEGOC.": "TradeCount",
50
- "CONTR. NEGOC.": "TradeVolume",
51
- "VOL.": "FinancialVolume",
52
- "AJUSTE": "SettlementPrice",
53
- "AJUSTE ANTER. (3)": "PrevSettlementRate",
54
- "AJUSTE CORRIG. (4)": "AdjSettlementRate",
55
- "PREÇO MÍN.": "MinRate",
56
- "PREÇO MÉD.": "AvgRate",
57
- "PREÇO MÁX.": "MaxRate",
58
- "PREÇO ABERTU.": "FirstRate",
59
- "ÚLT. PREÇO": "CloseRate",
60
- "VAR. PTOS.": "PointsVariation",
61
- # Attention: bid/ask rates are inverted
62
- "ÚLT.OF. COMPRA": "CloseAskRate",
63
- "ÚLT.OF. VENDA": "CloseBidRate",
64
- }
65
-
66
- df = df.rename(columns=rename_dict)
45
+ df = cm.rename_columns(df)
67
46
 
68
47
  df["TradeDate"] = trade_date
69
48
  # Convert to datetime64[ns] since it is pandas default type for timestamps
@@ -103,29 +82,8 @@ def _process_past_raw_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataF
103
82
  df["TickerSymbol"] = "DI1" + df["ExpirationCode"]
104
83
 
105
84
  # Filter and order columns
106
- ordered_cols = [
107
- "TradeDate",
108
- "TickerSymbol",
109
- # "ExpirationCode",
110
- "ExpirationDate",
111
- "BDaysToExp",
112
- "OpenContracts",
113
- # "OpenContractsEndSession" since there is no OpenContracts at the end of the
114
- # day in XML data, it will be removed to avoid confusion with XML data
115
- "TradeCount",
116
- "TradeVolume",
117
- "FinancialVolume",
118
- "SettlementPrice",
119
- "SettlementRate",
120
- "FirstRate",
121
- "MinRate",
122
- "AvgRate",
123
- "MaxRate",
124
- "CloseAskRate",
125
- "CloseBidRate",
126
- "CloseRate",
127
- ]
128
- return df[ordered_cols]
85
+ df = cm.reorder_columns(df)
86
+ return df
129
87
 
130
88
 
131
89
  def _process_last_raw_di_df(raw_df: pd.DataFrame) -> pd.DataFrame:
@@ -197,9 +155,6 @@ def fetch_past_di(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.Data
197
155
  - OpenContracts: number of open contracts at the start of the trading day.
198
156
  """
199
157
  df_raw = cm.fetch_past_raw_df(asset_code="DI1", trade_date=trade_date)
200
- if return_raw:
158
+ if return_raw or df_raw.empty:
201
159
  return df_raw
202
- if df_raw.empty:
203
- return pd.DataFrame()
204
- else:
205
- 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.6"
35
+ version = "0.7.7"
36
36
 
37
37
  [project.license]
38
38
  file = "LICENSE"
@@ -1 +0,0 @@
1
- __version__ = "0.7.6"
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