PYield 0.30.0__tar.gz → 0.30.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 (50) hide show
  1. {pyield-0.30.0 → pyield-0.30.2}/PKG-INFO +2 -2
  2. pyield-0.30.2/pyield/__about__.py +1 -0
  3. {pyield-0.30.0 → pyield-0.30.2}/pyield/anbima/__init__.py +2 -0
  4. pyield-0.30.2/pyield/anbima/ettj.py +135 -0
  5. pyield-0.30.2/pyield/anbima/ipca.py +85 -0
  6. {pyield-0.30.0 → pyield-0.30.2}/pyield/anbima/tpf.py +19 -8
  7. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/di_over.py +12 -12
  8. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/futures/intraday.py +3 -3
  9. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/auction.py +1 -1
  10. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/bcdata.py +1 -1
  11. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/repo.py +1 -1
  12. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/sec.py +1 -1
  13. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/vna.py +1 -1
  14. {pyield-0.30.0 → pyield-0.30.2}/pyield/ibge/ipca.py +1 -1
  15. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/lft.py +2 -2
  16. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/ltn.py +3 -3
  17. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/ntnf.py +2 -2
  18. {pyield-0.30.0 → pyield-0.30.2}/pyproject.toml +1 -1
  19. pyield-0.30.0/pyield/__about__.py +0 -1
  20. pyield-0.30.0/pyield/anbima/ipca.py +0 -52
  21. {pyield-0.30.0 → pyield-0.30.2}/.gitignore +0 -0
  22. {pyield-0.30.0 → pyield-0.30.2}/LICENSE +0 -0
  23. {pyield-0.30.0 → pyield-0.30.2}/README.md +0 -0
  24. {pyield-0.30.0 → pyield-0.30.2}/pyield/__init__.py +0 -0
  25. {pyield-0.30.0 → pyield-0.30.2}/pyield/anbima/ima.py +0 -0
  26. {pyield-0.30.0 → pyield-0.30.2}/pyield/anbima/imaq.py +0 -0
  27. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/__init__.py +0 -0
  28. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/di.py +0 -0
  29. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/futures/__init__.py +0 -0
  30. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/futures/common.py +0 -0
  31. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/futures/historical.py +0 -0
  32. {pyield-0.30.0 → pyield-0.30.2}/pyield/b3/futures/xml.py +0 -0
  33. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/__init__.py +0 -0
  34. {pyield-0.30.0 → pyield-0.30.2}/pyield/bc/ptax.py +0 -0
  35. {pyield-0.30.0 → pyield-0.30.2}/pyield/bday.py +0 -0
  36. {pyield-0.30.0 → pyield-0.30.2}/pyield/conftest.py +0 -0
  37. {pyield-0.30.0 → pyield-0.30.2}/pyield/data_cache.py +0 -0
  38. {pyield-0.30.0 → pyield-0.30.2}/pyield/date_converter.py +0 -0
  39. {pyield-0.30.0 → pyield-0.30.2}/pyield/forwards.py +0 -0
  40. {pyield-0.30.0 → pyield-0.30.2}/pyield/holidays/__init__.py +0 -0
  41. {pyield-0.30.0 → pyield-0.30.2}/pyield/holidays/br_holidays_new.txt +0 -0
  42. {pyield-0.30.0 → pyield-0.30.2}/pyield/holidays/br_holidays_old.txt +0 -0
  43. {pyield-0.30.0 → pyield-0.30.2}/pyield/holidays/brholidays.py +0 -0
  44. {pyield-0.30.0 → pyield-0.30.2}/pyield/ibge/__init__.py +0 -0
  45. {pyield-0.30.0 → pyield-0.30.2}/pyield/interpolator.py +0 -0
  46. {pyield-0.30.0 → pyield-0.30.2}/pyield/py.typed +0 -0
  47. /pyield-0.30.0/pyield/config.py → /pyield-0.30.2/pyield/retry.py +0 -0
  48. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/__init__.py +0 -0
  49. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/ntnb.py +0 -0
  50. {pyield-0.30.0 → pyield-0.30.2}/pyield/tpf/tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PYield
3
- Version: 0.30.0
3
+ Version: 0.30.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>
@@ -34,7 +34,7 @@ Classifier: Programming Language :: Python :: 3
34
34
  Classifier: Topic :: Office/Business :: Financial :: Investment
35
35
  Requires-Python: >=3.11
36
36
  Requires-Dist: numpy>=2.0.0
37
- Requires-Dist: pandas[excel,html,parquet]>=2.0.0
37
+ Requires-Dist: pandas[html,parquet]>=2.0.0
38
38
  Requires-Dist: requests>=2.31.0
39
39
  Requires-Dist: tenacity>=9.0.0
40
40
  Description-Content-Type: text/markdown
@@ -0,0 +1 @@
1
+ __version__ = "0.30.2"
@@ -1,3 +1,4 @@
1
+ from pyield.anbima.ettj import last_ettj
1
2
  from pyield.anbima.ima import last_ima
2
3
  from pyield.anbima.imaq import imaq
3
4
  from pyield.anbima.ipca import ipca_projection
@@ -10,4 +11,5 @@ __all__ = [
10
11
  "tpf_data",
11
12
  "tpf_rates",
12
13
  "tpf_pre_maturities",
14
+ "last_ettj",
13
15
  ]
@@ -0,0 +1,135 @@
1
+ import logging
2
+ from io import StringIO
3
+
4
+ import pandas as pd
5
+ import requests
6
+
7
+ from pyield.forwards import forward_rates
8
+ from pyield.retry import default_retry
9
+
10
+ logger = logging.getLogger(__name__)
11
+ LAST_ETTJ_URL = "https://www.anbima.com.br/informacoes/est-termo/CZ-down.asp"
12
+
13
+ # Anbima ETTJ data has 4 decimal places in percentage values
14
+ # We will round to 6 decimal places to avoid floating point errors
15
+ ROUND_DIGITS = 6
16
+
17
+
18
+ @default_retry
19
+ def _get_last_content() -> str:
20
+ """Fetches the raw yield curve data from ANBIMA."""
21
+ request_payload = {
22
+ "Idioma": "PT",
23
+ "Dt_Ref": "",
24
+ "saida": "csv",
25
+ }
26
+ r = requests.post(LAST_ETTJ_URL, data=request_payload)
27
+ r.raise_for_status()
28
+ return r.text
29
+
30
+
31
+ def _convert_text_to_df(text: str) -> pd.DataFrame:
32
+ """Converts the raw yield curve text to a DataFrame."""
33
+ raw_df = pd.read_csv(
34
+ StringIO(text),
35
+ sep=";",
36
+ encoding="latin1",
37
+ skiprows=5,
38
+ dtype_backend="numpy_nullable",
39
+ )
40
+
41
+ idx = raw_df.query("Vertices =='PREFIXADOS (CIRCULAR 3.361)'").first_valid_index() # noqa
42
+ raw_df.query("index < @idx", inplace=True)
43
+ csv_buffer = StringIO()
44
+
45
+ # Save the DataFrame as CSV in memory buffer to be read again
46
+ # It's easier than handling values with commas and dots directly in the DataFrame
47
+ raw_df.to_csv(csv_buffer, index=False)
48
+ csv_buffer.seek(0) # Move the buffer cursor to the beginning
49
+
50
+ df = pd.read_csv(
51
+ csv_buffer,
52
+ decimal=",",
53
+ thousands=".",
54
+ dtype_backend="numpy_nullable",
55
+ )
56
+ file_date_str = text[0:10] # 09/09/2024
57
+ file_date = pd.to_datetime(file_date_str, format="%d/%m/%Y")
58
+ df["date"] = file_date
59
+
60
+ return df
61
+
62
+
63
+ def _process_df(df: pd.DataFrame) -> pd.DataFrame:
64
+ """Processes the raw yield curve DataFrame to calculate rates and forward rates."""
65
+ # Rename columns
66
+ rename_dict = {
67
+ "Vertices": "vertex",
68
+ "ETTJ IPCA": "real_rate",
69
+ "ETTJ PREF": "nominal_rate",
70
+ "Inflação Implícita": "implied_inflation",
71
+ }
72
+ df.rename(columns=rename_dict, inplace=True)
73
+
74
+ # Divide float columns by 100 and round to 6 decimal places
75
+ df["real_rate"] = (df["real_rate"] / 100).round(ROUND_DIGITS)
76
+ df["nominal_rate"] = (df["nominal_rate"] / 100).round(ROUND_DIGITS)
77
+ df["implied_inflation"] = (df["implied_inflation"] / 100).round(ROUND_DIGITS)
78
+
79
+ df["real_rate_fwd"] = forward_rates(
80
+ business_days=df["vertex"],
81
+ zero_rates=df["real_rate"],
82
+ groupby_dates=df["date"],
83
+ )
84
+ df["nominal_rate_fwd"] = forward_rates(
85
+ business_days=df["vertex"],
86
+ zero_rates=df["nominal_rate"],
87
+ groupby_dates=df["date"],
88
+ )
89
+ df["implied_inflation_fwd"] = forward_rates(
90
+ business_days=df["vertex"],
91
+ zero_rates=df["implied_inflation"],
92
+ groupby_dates=df["date"],
93
+ )
94
+
95
+ column_order = [
96
+ "date",
97
+ "vertex",
98
+ "nominal_rate",
99
+ "real_rate",
100
+ "implied_inflation",
101
+ "nominal_rate_fwd",
102
+ "real_rate_fwd",
103
+ "implied_inflation_fwd",
104
+ ]
105
+ df = df[column_order].copy()
106
+
107
+ return df
108
+
109
+
110
+ def last_ettj() -> pd.DataFrame:
111
+ """
112
+ Retrieves and processes the latest Brazilian yield curve data from ANBIMA.
113
+
114
+ This function fetches the most recent yield curve data published by ANBIMA,
115
+ containing real rates (IPCA-indexed), nominal rates, and implied inflation
116
+ at various vertices (time points). Both spot rates and forward rates are
117
+ calculated and included in the returned DataFrame.
118
+
119
+ Returns:
120
+ pd.DataFrame: A DataFrame containing the following columns:
121
+ - date: Reference date of the yield curve
122
+ - vertex: Time point in business days
123
+ - nominal_rate: Zero-coupon nominal interest rate
124
+ - real_rate: Zero-coupon real interest rate (IPCA-indexed)
125
+ - implied_inflation: Implied inflation rate (break-even inflation)
126
+ - nominal_rate_fwd: Forward nominal interest rate
127
+ - real_rate_fwd: Forward real interest rate
128
+ - implied_inflation_fwd: Forward implied inflation rate
129
+
130
+ Note:
131
+ All rates are expressed in decimal format (e.g., 0.12 for 12%).
132
+ """
133
+ text = _get_last_content()
134
+ df = _convert_text_to_df(text)
135
+ return _process_df(df)
@@ -0,0 +1,85 @@
1
+ import io
2
+ import locale
3
+ import warnings
4
+ from dataclasses import dataclass
5
+
6
+ import pandas as pd
7
+ import requests
8
+ from bs4 import XMLParsedAsHTMLWarning
9
+
10
+ warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning)
11
+
12
+
13
+ @dataclass
14
+ class IndicatorProjection:
15
+ reference_period: pd.Period # Reference month as a pd.Period object
16
+ projected_value: float # Projected value
17
+ last_updated: pd.Timestamp # Date and time of the last update
18
+
19
+
20
+ def ipca_projection() -> IndicatorProjection:
21
+ """
22
+ Retrieves the current IPCA projection from the ANBIMA website.
23
+
24
+ This function makes an HTTP request to the ANBIMA website, extracts HTML tables
25
+ containing economic indicators, and specifically processes the IPCA projection data.
26
+
27
+ Process:
28
+ 1. Accesses the ANBIMA indicators webpage
29
+ 2. Extracts the third table that contains the IPCA projection
30
+ 3. Locates the row labeled as "IPCA1"
31
+ 4. Extracts the projection value and converts it to decimal format
32
+ 5. Extracts and formats the reference month of the projection
33
+ 6. Extracts the date and time of the last update
34
+
35
+ Returns:
36
+ IndicatorProjection: An object containing:
37
+ - reference_period (pd.Period): Reference period of the projection
38
+ - projected_value (float): Projected IPCA value as a decimal number
39
+ - last_updated (pd.Timestamp): Date and time of the last data update
40
+
41
+ Raises:
42
+ requests.RequestException: If there are connection issues with the ANBIMA site
43
+ ValueError: If the expected data is not found in the page structure
44
+ locale.Error: If the 'pt_BR.UTF-8' locale is not available on the system
45
+
46
+ Notes:
47
+ - The function requires internet connection to access the ANBIMA website
48
+ - The structure of the ANBIMA page may change, which could affect the function
49
+ - Temporarily changes the locale to pt_BR.UTF-8 to process dates in Portuguese
50
+ """
51
+ url = "https://www.anbima.com.br/informacoes/indicadores/"
52
+ r = requests.get(url)
53
+ r.encoding = "latin1"
54
+ dfs = pd.read_html(
55
+ io.StringIO(r.text),
56
+ flavor="html5lib",
57
+ decimal=",",
58
+ thousands=".",
59
+ dtype_backend="numpy_nullable",
60
+ )
61
+ # The IPCA projection is in the third table
62
+ df = dfs[2]
63
+
64
+ last_update_str = df.iat[0, 0].split("Atualização:")[-1].strip()
65
+ last_update = pd.to_datetime(last_update_str, format="%d/%m/%Y - %H:%M h")
66
+
67
+ ipca_row = df.loc[df[0] == "IPCA1"]
68
+ ipca_value = ipca_row.iloc[0, 2]
69
+ ipca_value = pd.to_numeric(ipca_value, errors="coerce")
70
+ ipca_value = round(float(ipca_value) / 100, 4)
71
+
72
+ # Extract and format the reference month
73
+ ipca_date = ipca_row.iloc[0, 1]
74
+ ipca_date = str(ipca_date)
75
+ ipca_date = ipca_date.split("(")[-1].split(")")[0]
76
+ locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8")
77
+ ipca_date = pd.to_datetime(ipca_date, format="%b/%y")
78
+ reference_period = ipca_date.to_period("M")
79
+ locale.setlocale(locale.LC_TIME, "") # Reset locale to default
80
+
81
+ return IndicatorProjection(
82
+ last_updated=last_update,
83
+ reference_period=reference_period,
84
+ projected_value=ipca_value,
85
+ )
@@ -1,19 +1,27 @@
1
1
  import logging
2
+ from typing import Literal
2
3
  from urllib.error import HTTPError
3
4
 
4
5
  import pandas as pd
5
6
 
6
7
  from pyield import bday
7
- from pyield.config import default_retry
8
8
  from pyield.data_cache import get_anbima_dataset
9
9
  from pyield.date_converter import DateScalar, convert_input_dates
10
+ from pyield.retry import default_retry
10
11
 
12
+ BOND_TYPES = Literal["LTN", "NTN-B", "NTN-C", "NTN-F", "LFT"]
11
13
  ANBIMA_URL = "https://www.anbima.com.br/informacoes/merc-sec/arqs"
12
14
  # URL example: https://www.anbima.com.br/informacoes/merc-sec/arqs/ms240614.txt
13
15
 
14
16
  logger = logging.getLogger(__name__)
15
17
 
16
18
 
19
+ def _bond_type_mapping(bond_type: str) -> str:
20
+ bond_type = bond_type.upper()
21
+ bond_type_mapping = {"NTNB": "NTN-B", "NTNC": "NTN-C", "NTNF": "NTN-F"}
22
+ return bond_type_mapping.get(bond_type, bond_type)
23
+
24
+
17
25
  def _build_file_url(date: pd.Timestamp) -> str:
18
26
  url_date = date.strftime("%y%m%d")
19
27
  filename = f"ms{url_date}.txt"
@@ -59,8 +67,9 @@ def _process_raw_df(df_raw: pd.DataFrame) -> pd.DataFrame:
59
67
 
60
68
  # Remove percentage from rates
61
69
  rate_cols = [col for col in df.columns if "Rate" in col]
62
- # Data has 6 decimal places, so we round to 7 decimal places
63
- df[rate_cols] = (df[rate_cols] / 100).round(7)
70
+ # Rate columns have percentage values with 4 decimal places in percentage values
71
+ # We will round to 6 decimal places to avoid floating point errors
72
+ df[rate_cols] = (df[rate_cols] / 100).round(6)
64
73
 
65
74
  df["ReferenceDate"] = pd.to_datetime(df["ReferenceDate"], format="%Y%m%d")
66
75
  df["MaturityDate"] = pd.to_datetime(df["MaturityDate"], format="%Y%m%d")
@@ -86,9 +95,10 @@ def tpf_data(date: DateScalar, bond_type: str | None = None) -> pd.DataFrame:
86
95
  Returns an empty DataFrame if data is not available for the
87
96
  specified date (weekends, holidays, or unavailable data).
88
97
  """
98
+ date = convert_input_dates(date)
99
+ date_log = date.strftime("%d/%m/%Y")
100
+
89
101
  try:
90
- date = convert_input_dates(date)
91
- date_log = date.strftime("%d/%m/%Y")
92
102
  file_url = _build_file_url(date)
93
103
  df = _read_raw_df(file_url)
94
104
  if df.empty:
@@ -99,8 +109,9 @@ def tpf_data(date: DateScalar, bond_type: str | None = None) -> pd.DataFrame:
99
109
  return df
100
110
  df = _process_raw_df(df)
101
111
  if bond_type:
112
+ bond_type = _bond_type_mapping(bond_type)
102
113
  df = df.query("BondType == @bond_type").reset_index(drop=True)
103
- return df
114
+ return df.sort_values(["BondType", "MaturityDate"]).reset_index(drop=True)
104
115
  except HTTPError as e:
105
116
  if e.code == 404: # noqa
106
117
  logger.info(
@@ -109,8 +120,8 @@ def tpf_data(date: DateScalar, bond_type: str | None = None) -> pd.DataFrame:
109
120
  )
110
121
  return pd.DataFrame()
111
122
  raise # Propagate other HTTP errors
112
- except Exception as e:
113
- logger.error(f"Error fetching TPF data for {date_log}: {e}")
123
+ except Exception:
124
+ logger.exception(f"Error fetching TPF data for {date_log}")
114
125
  raise
115
126
 
116
127
 
@@ -1,7 +1,10 @@
1
1
  import ftplib
2
+ import logging
2
3
 
3
4
  from pyield.date_converter import DateScalar, convert_input_dates
4
5
 
6
+ logger = logging.getLogger(__name__)
7
+
5
8
 
6
9
  def di_over(date: DateScalar) -> float:
7
10
  """
@@ -46,14 +49,18 @@ def di_over(date: DateScalar) -> float:
46
49
  rate = int(raw_rate) / 10000
47
50
  return round(rate, 5)
48
51
  else:
49
- return "Empty file or no data"
52
+ logger.error(f"No data found for date {date}")
53
+ return float("nan")
50
54
 
51
55
  except ValueError as e:
52
- return f"Date format error: {e}"
56
+ logger.error(f"Date format error: {e}")
57
+ raise
53
58
  except ftplib.error_perm as e:
54
- return f"File access error: {e}"
55
- except Exception as e:
56
- return f"Unexpected error: {e}"
59
+ logger.error(f"File access error: {e}")
60
+ raise
61
+ except Exception:
62
+ logger.exception("Unexpected error")
63
+ raise
57
64
  finally:
58
65
  # Ensure FTP connection is closed
59
66
  if ftp:
@@ -61,10 +68,3 @@ def di_over(date: DateScalar) -> float:
61
68
  ftp.quit()
62
69
  except: # noqa
63
70
  pass
64
-
65
-
66
- # Example usage
67
- if __name__ == "__main__":
68
- date = "28/02/2025"
69
- rate = di_over(date)
70
- print(f"DI Rate for {date}: {rate}")
@@ -9,7 +9,7 @@ from pyield import bday
9
9
  TIMEZONE_BZ = ZoneInfo("America/Sao_Paulo")
10
10
 
11
11
 
12
- def _fetch_b3_df(future_code: str) -> pd.DataFrame:
12
+ def _fetch_b3_df(contract_code: str) -> pd.DataFrame:
13
13
  """
14
14
  Fetch the latest data for a given future code from B3 derivatives quotation API.
15
15
 
@@ -24,13 +24,13 @@ def _fetch_b3_df(future_code: str) -> pd.DataFrame:
24
24
  Exception: An exception is raised if the data fetch operation fails.
25
25
  """
26
26
 
27
- url = f"https://cotacao.b3.com.br/mds/api/v1/DerivativeQuotation/{future_code}"
27
+ url = f"https://cotacao.b3.com.br/mds/api/v1/DerivativeQuotation/{contract_code}"
28
28
 
29
29
  try:
30
30
  r = requests.get(url, timeout=10)
31
31
  r.raise_for_status() # Check for HTTP request errors
32
32
  except requests.exceptions.RequestException:
33
- raise Exception(f"Failed to fetch data for {future_code}.") from None
33
+ raise Exception(f"Failed to fetch data for {contract_code}.") from None
34
34
 
35
35
  r.encoding = "utf-8" # Explicitly set response encoding to utf-8 for consistency
36
36
 
@@ -14,8 +14,8 @@ import requests
14
14
 
15
15
  from pyield import bday
16
16
  from pyield import date_converter as dc
17
- from pyield.config import default_retry
18
17
  from pyield.date_converter import DateScalar
18
+ from pyield.retry import default_retry
19
19
  from pyield.tpf.ntnb import duration as duration_b
20
20
  from pyield.tpf.ntnf import duration as duration_f
21
21
 
@@ -20,8 +20,8 @@ from urllib.error import HTTPError
20
20
 
21
21
  import pandas as pd
22
22
 
23
- from pyield.config import default_retry
24
23
  from pyield.date_converter import DateScalar, convert_input_dates
24
+ from pyield.retry import default_retry
25
25
 
26
26
  logger = logging.getLogger(__name__)
27
27
 
@@ -13,8 +13,8 @@ import requests
13
13
 
14
14
  from pyield import bday
15
15
  from pyield import date_converter as dc
16
- from pyield.config import default_retry
17
16
  from pyield.date_converter import DateScalar
17
+ from pyield.retry import default_retry
18
18
 
19
19
  """Dicionário com o mapeamento das colunas da API do BC para o DataFrame final
20
20
  Chaves com comentário serão descartadas ao final do processamento
@@ -2,8 +2,8 @@ import logging
2
2
 
3
3
  import pandas as pd
4
4
 
5
- from pyield.config import default_retry
6
5
  from pyield.date_converter import DateScalar, convert_input_dates
6
+ from pyield.retry import default_retry
7
7
 
8
8
  logger = logging.getLogger(__name__)
9
9
 
@@ -1,7 +1,7 @@
1
1
  import requests
2
2
 
3
- from pyield.config import default_retry
4
3
  from pyield.date_converter import DateScalar, convert_input_dates
4
+ from pyield.retry import default_retry
5
5
 
6
6
 
7
7
  @default_retry
@@ -3,8 +3,8 @@ import logging
3
3
  import pandas as pd
4
4
  import requests
5
5
 
6
- from pyield.config import default_retry
7
6
  from pyield.date_converter import DateScalar, convert_input_dates
7
+ from pyield.retry import default_retry
8
8
 
9
9
  logger = logging.getLogger(__name__)
10
10
  IPCA_URL = "https://servicodados.ibge.gov.br/api/v3/agregados/6691/periodos/"
@@ -94,9 +94,9 @@ def premium(lft_rate: float, selic_over: float) -> float:
94
94
  >>> lft_rate = 0.1695 / 100 # 0.1695%
95
95
  >>> selic_over = 10.40 / 100 # 10.40%
96
96
  >>> yd.lft.premium(lft_rate, selic_over)
97
- 1.017121
97
+ 1.017120519283759
98
98
  """
99
99
  adjusted_lft_rate = (lft_rate + 1) * (selic_over + 1) - 1
100
100
  f1 = (adjusted_lft_rate + 1) ** (1 / 252) - 1
101
101
  f2 = (selic_over + 1) ** (1 / 252) - 1
102
- return round(f1 / f2, 6)
102
+ return f1 / f2
@@ -175,14 +175,14 @@ def premium(ltn_rate: float, di_rate: float) -> float:
175
175
  LTN rate for 01-01-2030: 0.118746
176
176
  DI (JAN30) Settlement rate: 0.11725
177
177
  >>> yd.ltn.premium(0.118746, 0.11725)
178
- 1.012072
178
+ 1.0120718007994287
179
179
  """
180
180
  # Cálculo das taxas diárias
181
181
  ltn_factor = (1 + ltn_rate) ** (1 / 252)
182
182
  di_factor = (1 + di_rate) ** (1 / 252)
183
183
 
184
184
  # Retorno do cálculo do prêmio
185
- return round((ltn_factor - 1) / (di_factor - 1), 6)
185
+ return (ltn_factor - 1) / (di_factor - 1)
186
186
 
187
187
 
188
188
  def historical_premium(
@@ -202,7 +202,7 @@ def historical_premium(
202
202
 
203
203
  Examples:
204
204
  >>> yd.ltn.historical_premium("22-08-2024", "01-01-2030")
205
- 1.012072
205
+ 1.0120718007994287
206
206
 
207
207
  """
208
208
  # Convert input dates to a consistent format
@@ -532,7 +532,7 @@ def premium(
532
532
  ... di_expirations=exp_dates,
533
533
  ... di_rates=di_rates,
534
534
  ... )
535
- 1.00996
535
+ 1.0099602136954626
536
536
 
537
537
  Notes:
538
538
  - The function adjusts coupon payment dates to business days and calculates
@@ -572,7 +572,7 @@ def premium(
572
572
  factor_ntnf = (1 + ntnf_rate) ** (1 / 252)
573
573
  factor_di = (1 + di_ytm) ** (1 / 252)
574
574
  premium_np = (factor_ntnf - 1) / (factor_di - 1)
575
- return round(float(premium_np), 6)
575
+ return float(premium_np)
576
576
 
577
577
 
578
578
  def historical_premium(
@@ -14,7 +14,7 @@ classifiers = [
14
14
  "Topic :: Office/Business :: Financial :: Investment",
15
15
  ]
16
16
  dependencies = [
17
- "pandas[html,parquet,excel]>=2.0.0",
17
+ "pandas[html,parquet]>=2.0.0",
18
18
  "numpy>=2.0.0",
19
19
  "requests>=2.31.0",
20
20
  "tenacity>=9.0.0",
@@ -1 +0,0 @@
1
- __version__ = "0.30.0"
@@ -1,52 +0,0 @@
1
- import locale
2
- from dataclasses import dataclass
3
-
4
- import pandas as pd
5
-
6
-
7
- @dataclass
8
- class IndicatorProjection:
9
- reference_period: pd.Period # Reference month as a pd.Period object
10
- projected_value: float # Projected value
11
- last_updated: pd.Timestamp # Date and time of the last update
12
-
13
-
14
- def ipca_projection() -> IndicatorProjection:
15
- """
16
- This function retrieves and parses the Excel file that contains economic indicators,
17
- specifically looking for the IPCA projection. It extracts the date of the last
18
- update and the IPCA projection for the reference month.
19
-
20
- Data file format example after parsing:
21
- - ['Data e Hora da Última Atualização: 19/04/2024 - 18:55 h', '', '']
22
- - ...
23
- - ['IPCA1', 'Projeção (abr/24)', 0.35]
24
- - ...
25
- """
26
- # Define the URL and get the data
27
- url = "https://www.anbima.com.br/informacoes/indicadores/arqs/indicadores.xls"
28
- df = pd.read_excel(url, dtype_backend="numpy_nullable")
29
-
30
- last_update_str = df.columns[0].split("Atualização:")[-1].strip()
31
- last_update = pd.to_datetime(last_update_str, format="%d/%m/%Y - %H:%M h")
32
-
33
- ipca_row = df[df.iloc[:, 0] == "IPCA1"]
34
-
35
- ipca_value = ipca_row.iloc[0, 2]
36
- ipca_value = pd.to_numeric(ipca_value, errors="coerce")
37
- ipca_value = round(float(ipca_value) / 100, 4)
38
-
39
- # Extract and format the reference month
40
- ipca_date = ipca_row.iloc[0, 1]
41
- ipca_date = str(ipca_date)
42
- ipca_date = ipca_date.split("(")[-1].split(")")[0]
43
- locale.setlocale(locale.LC_TIME, "pt_BR.UTF-8")
44
- ipca_date = pd.to_datetime(ipca_date, format="%b/%y")
45
- reference_period = ipca_date.to_period("M")
46
- locale.setlocale(locale.LC_TIME, "") # Reset locale to default
47
-
48
- return IndicatorProjection(
49
- last_updated=last_update,
50
- reference_period=reference_period,
51
- projected_value=ipca_value,
52
- )
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