PYield 0.7.6__tar.gz → 0.7.8__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.7.6 → pyield-0.7.8}/PKG-INFO +7 -7
- {pyield-0.7.6 → pyield-0.7.8}/README.md +5 -5
- pyield-0.7.8/pyield/__about__.py +1 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/data_access.py +23 -15
- pyield-0.7.8/pyield/futures/historical/__init__.py +6 -0
- {pyield-0.7.6/pyield/futures → pyield-0.7.8/pyield/futures/historical}/common.py +95 -44
- pyield-0.7.8/pyield/futures/historical/dap.py +62 -0
- pyield-0.7.8/pyield/futures/historical/ddi.py +80 -0
- pyield-0.7.8/pyield/futures/historical/di.py +91 -0
- {pyield-0.7.6/pyield/futures → pyield-0.7.8/pyield/futures/historical}/di_xml.py +2 -2
- pyield-0.7.8/pyield/futures/historical/frc.py +60 -0
- pyield-0.7.8/pyield/futures/intraday/__init__.py +3 -0
- pyield-0.7.8/pyield/futures/intraday/trading_data.py +107 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/projections.py +7 -4
- {pyield-0.7.6 → pyield-0.7.8}/pyield/treasuries.py +2 -2
- {pyield-0.7.6 → pyield-0.7.8}/pyproject.toml +2 -2
- pyield-0.7.8/tests/__init__.py +0 -0
- pyield-0.7.8/tests/test_futures.py +38 -0
- pyield-0.7.6/pyield/__about__.py +0 -1
- pyield-0.7.6/pyield/futures/__init__.py +0 -13
- pyield-0.7.6/pyield/futures/ddi.py +0 -145
- pyield-0.7.6/pyield/futures/di.py +0 -205
- pyield-0.7.6/pyield/futures/frc.py +0 -98
- pyield-0.7.6/tests/test_futures.py +0 -80
- {pyield-0.7.6 → pyield-0.7.8}/LICENSE +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/__init__.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/bday.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/data_analysis.py +0 -0
- {pyield-0.7.6/tests → pyield-0.7.8/pyield/futures}/__init__.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/holidays/__init__.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/holidays/br_holidays_new.txt +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/holidays/br_holidays_old.txt +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/holidays/core.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/indicators.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/py.typed +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/pyield/utils.py +0 -0
- {pyield-0.7.6 → pyield-0.7.8}/tests/test_bday.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: PYield
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.8
|
|
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>
|
|
@@ -32,13 +32,13 @@ Classifier: Intended Audience :: Financial and Insurance Industry
|
|
|
32
32
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
33
33
|
Project-URL: Source, https://github.com/crdcj/PYield
|
|
34
34
|
Requires-Python: >=3.11
|
|
35
|
-
Requires-Dist: requests
|
|
36
35
|
Requires-Dist: pandas>=2.0.0
|
|
37
36
|
Requires-Dist: numpy
|
|
38
37
|
Requires-Dist: beautifulsoup4
|
|
39
38
|
Requires-Dist: html5lib
|
|
40
39
|
Requires-Dist: lxml
|
|
41
40
|
Requires-Dist: python-calamine>=0.2.0
|
|
41
|
+
Requires-Dist: requests>=2.31.0
|
|
42
42
|
Description-Content-Type: text/markdown
|
|
43
43
|
|
|
44
44
|
[](https://pypi.python.org/pypi/pyield)
|
|
@@ -101,7 +101,7 @@ dtype: datetime64[ns]
|
|
|
101
101
|
```python
|
|
102
102
|
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
103
103
|
>>> yd.fetch_asset(asset_code="DI1")
|
|
104
|
-
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate
|
|
104
|
+
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate CurrentRate
|
|
105
105
|
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
106
106
|
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
107
107
|
2024-04-21 13:37:39 DI1N24 2024-07-01 48 ... 0.10480 0.10456 0.10462 0.10460
|
|
@@ -158,11 +158,11 @@ BondType ReferenceDate MaturityDate DISpread
|
|
|
158
158
|
```python
|
|
159
159
|
# Fetch the SELIC target rate from the Central Bank of Brazil
|
|
160
160
|
>>> yd.fetch_indicator(indicator_code="SELIC", reference_date='2024-04-12')
|
|
161
|
-
10.75
|
|
161
|
+
0.1075 # 10.75%
|
|
162
162
|
|
|
163
163
|
# Fetch the IPCA monthly inflation rate from IBGE
|
|
164
164
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-03-18')
|
|
165
|
-
0.16
|
|
165
|
+
0.16 # 0.16%
|
|
166
166
|
|
|
167
167
|
# If no data is yet available for the indicator, the function returns None
|
|
168
168
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-04-10')
|
|
@@ -178,9 +178,9 @@ IndicatorProjection(
|
|
|
178
178
|
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
179
179
|
reference_month_ts=Timestamp('2024-04-01 00:00:00'),
|
|
180
180
|
reference_month_br='ABR/2024',
|
|
181
|
-
projected_value=0.0035
|
|
181
|
+
projected_value=0.0035 # 0.35%
|
|
182
182
|
)
|
|
183
183
|
>>> ipca.projected_value
|
|
184
|
-
0.0035
|
|
184
|
+
0.0035 # 0.35%
|
|
185
185
|
```
|
|
186
186
|
|
|
@@ -58,7 +58,7 @@ dtype: datetime64[ns]
|
|
|
58
58
|
```python
|
|
59
59
|
# Fetch current DI Futures data from B3 (15 minutes delay)
|
|
60
60
|
>>> yd.fetch_asset(asset_code="DI1")
|
|
61
|
-
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate
|
|
61
|
+
TradeTimestamp TickerSymbol ExpirationDate BDaysToExp ... MaxRate LastAskRate LastBidRate CurrentRate
|
|
62
62
|
2024-04-21 13:37:39 DI1K24 2024-05-02 7 ... 0.10660 0.10652 0.10660 0.10660
|
|
63
63
|
2024-04-21 13:37:39 DI1M24 2024-06-03 28 ... 0.10518 0.10510 0.10516 0.10518
|
|
64
64
|
2024-04-21 13:37:39 DI1N24 2024-07-01 48 ... 0.10480 0.10456 0.10462 0.10460
|
|
@@ -115,11 +115,11 @@ BondType ReferenceDate MaturityDate DISpread
|
|
|
115
115
|
```python
|
|
116
116
|
# Fetch the SELIC target rate from the Central Bank of Brazil
|
|
117
117
|
>>> yd.fetch_indicator(indicator_code="SELIC", reference_date='2024-04-12')
|
|
118
|
-
10.75
|
|
118
|
+
0.1075 # 10.75%
|
|
119
119
|
|
|
120
120
|
# Fetch the IPCA monthly inflation rate from IBGE
|
|
121
121
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-03-18')
|
|
122
|
-
0.16
|
|
122
|
+
0.16 # 0.16%
|
|
123
123
|
|
|
124
124
|
# If no data is yet available for the indicator, the function returns None
|
|
125
125
|
>>> yd.fetch_indicator(indicator_code="IPCA", reference_date='2024-04-10')
|
|
@@ -135,9 +135,9 @@ IndicatorProjection(
|
|
|
135
135
|
last_updated=Timestamp('2024-04-19 18:55:00'),
|
|
136
136
|
reference_month_ts=Timestamp('2024-04-01 00:00:00'),
|
|
137
137
|
reference_month_br='ABR/2024',
|
|
138
|
-
projected_value=0.0035
|
|
138
|
+
projected_value=0.0035 # 0.35%
|
|
139
139
|
)
|
|
140
140
|
>>> ipca.projected_value
|
|
141
|
-
0.0035
|
|
141
|
+
0.0035 # 0.35%
|
|
142
142
|
```
|
|
143
143
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.8"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
|
|
3
|
-
from . import futures as ft
|
|
4
3
|
from . import indicators as it
|
|
5
4
|
from . import projections as pr
|
|
6
5
|
from . import treasuries as tr
|
|
6
|
+
from .futures import historical as fh
|
|
7
|
+
from .futures import intraday as fi
|
|
7
8
|
from .utils import _normalize_date
|
|
8
9
|
|
|
9
10
|
|
|
@@ -24,6 +25,7 @@ def fetch_asset(
|
|
|
24
25
|
- "DI1": One-day Interbank Deposit Futures (Futuro de DI) from B3.
|
|
25
26
|
- "DDI": DI x U.S. Dollar Spread Futures (Futuro de Cupom Cambial) from B3.
|
|
26
27
|
- "FRC": Forward Rate Agreement (FRA) from B3.
|
|
28
|
+
- "DAP": DI x IPCA Spread Futures
|
|
27
29
|
reference_date (str | pd.Timestamp | None): The reference date for which data is
|
|
28
30
|
fetched. Defaults to the last business day if None.
|
|
29
31
|
**kwargs: Additional keyword arguments, specifically:
|
|
@@ -43,24 +45,30 @@ def fetch_asset(
|
|
|
43
45
|
return_raw = kwargs.get("return_raw", False)
|
|
44
46
|
normalized_date = _normalize_date(reference_date)
|
|
45
47
|
|
|
48
|
+
today = pd.Timestamp.today().normalize()
|
|
49
|
+
if normalized_date == today:
|
|
50
|
+
return fi.fetch_intraday(future_code=asset_code.upper())
|
|
51
|
+
|
|
46
52
|
if asset_code.lower() == "trb":
|
|
47
53
|
return tr.fetch_bonds(reference_date=normalized_date, return_raw=return_raw)
|
|
48
|
-
|
|
54
|
+
|
|
55
|
+
if asset_code.lower() in ["ltn", "lft", "ntn-f", "ntn-b"]:
|
|
49
56
|
df = tr.fetch_bonds(reference_date=normalized_date)
|
|
50
57
|
return df.query(f"BondType == '{asset_code.upper()}'")
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
if asset_code.lower() == "di1":
|
|
60
|
+
return fh.fetch_di(trade_date=normalized_date, return_raw=return_raw)
|
|
61
|
+
|
|
62
|
+
if asset_code.lower() == "ddi":
|
|
63
|
+
return fh.fetch_ddi(trade_date=normalized_date, return_raw=return_raw)
|
|
64
|
+
|
|
65
|
+
if asset_code.lower() == "frc":
|
|
66
|
+
return fh.fetch_frc(trade_date=normalized_date, return_raw=return_raw)
|
|
67
|
+
|
|
68
|
+
if asset_code.lower() == "dap":
|
|
69
|
+
return fh.fetch_dap(trade_date=normalized_date, return_raw=return_raw)
|
|
70
|
+
|
|
71
|
+
raise ValueError("Asset type not supported.")
|
|
64
72
|
|
|
65
73
|
|
|
66
74
|
def fetch_indicator(
|
|
@@ -111,7 +119,7 @@ def fetch_indicator(
|
|
|
111
119
|
raise ValueError("Indicator type not supported.")
|
|
112
120
|
|
|
113
121
|
|
|
114
|
-
def fetch_projection(projection_code: str) ->
|
|
122
|
+
def fetch_projection(projection_code: str) -> pr.IndicatorProjection:
|
|
115
123
|
"""
|
|
116
124
|
Fetches a financial projection for a specified code and reference date.
|
|
117
125
|
|
|
@@ -3,7 +3,7 @@ import io
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
import requests
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from ... import bday
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def get_expiration_date(expiration_code: str) -> pd.Timestamp:
|
|
@@ -131,7 +131,28 @@ def get_old_expiration_date(
|
|
|
131
131
|
return pd.NaT # type: ignore
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
def
|
|
134
|
+
def convert_prices_to_rates(
|
|
135
|
+
prices: pd.Series, days_to_expiration: pd.Series, count_convention: int
|
|
136
|
+
) -> pd.Series:
|
|
137
|
+
"""
|
|
138
|
+
Internal function to convert DI futures prices to rates.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
prices (pd.Series): The futures prices to be converted.
|
|
142
|
+
days_to_expiration (pd.Series): The number of days to expiration for each price.
|
|
143
|
+
count_convention (int): The count convention for the DI futures contract.
|
|
144
|
+
Normally, it is 252 business days or 360 calendar days.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
pd.Series: A pd.Series containing the futures rates.
|
|
148
|
+
"""
|
|
149
|
+
rates = (100_000 / prices) ** (count_convention / days_to_expiration) - 1
|
|
150
|
+
|
|
151
|
+
# Round to 5 (3 in %) dec. places (contract's current max. precision)
|
|
152
|
+
return rates.round(5)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def fetch_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
135
156
|
"""
|
|
136
157
|
Fetch the historical futures data from B3 for a specific trade date. If the data is
|
|
137
158
|
not available, an empty DataFrame is returned.
|
|
@@ -177,54 +198,84 @@ def fetch_past_raw_df(asset_code: str, trade_date: pd.Timestamp) -> pd.DataFrame
|
|
|
177
198
|
return df
|
|
178
199
|
|
|
179
200
|
|
|
180
|
-
def
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
def rename_columns(df: pd.DataFrame) -> pd.DataFrame:
|
|
202
|
+
all_columns = {
|
|
203
|
+
"VENCTO": "ExpirationCode",
|
|
204
|
+
"CONTR. ABERT.(1)": "OpenContracts", # At the start of the day
|
|
205
|
+
"CONTR. FECH.(2)": "OpenContractsEndSession", # At the end of the day
|
|
206
|
+
"NÚM. NEGOC.": "TradeCount",
|
|
207
|
+
"CONTR. NEGOC.": "TradeVolume",
|
|
208
|
+
"VOL.": "FinancialVolume",
|
|
209
|
+
"AJUSTE": "SettlementPrice",
|
|
210
|
+
"AJUSTE ANTER. (3)": "PrevSettlementRate",
|
|
211
|
+
"AJUSTE CORRIG. (4)": "AdjSettlementRate",
|
|
212
|
+
"AJUSTE DE REF.": "SettlementRate", # FRC
|
|
213
|
+
"PREÇO MÍN.": "MinRate",
|
|
214
|
+
"PREÇO MÉD.": "AvgRate",
|
|
215
|
+
"PREÇO MÁX.": "MaxRate",
|
|
216
|
+
"PREÇO ABERTU.": "FirstRate",
|
|
217
|
+
"ÚLT. PREÇO": "CloseRate",
|
|
218
|
+
"VAR. PTOS.": "PointsVariation",
|
|
219
|
+
# Attention: bid/ask rates are inverted
|
|
220
|
+
"ÚLT.OF. COMPRA": "CloseAskRate",
|
|
221
|
+
"ÚLT.OF. VENDA": "CloseBidRate",
|
|
222
|
+
}
|
|
223
|
+
rename_dict = {c: all_columns[c] for c in all_columns if c in df.columns}
|
|
224
|
+
return df.rename(columns=rename_dict)
|
|
195
225
|
|
|
196
|
-
try:
|
|
197
|
-
r = requests.get(url)
|
|
198
|
-
r.raise_for_status() # Check for HTTP request errors
|
|
199
|
-
except requests.exceptions.RequestException:
|
|
200
|
-
raise Exception(f"Failed to fetch data for {future_code}.") from None
|
|
201
226
|
|
|
202
|
-
|
|
227
|
+
def process_raw_df(
|
|
228
|
+
df: pd.DataFrame, trade_date: pd.Timestamp, asset_code: str
|
|
229
|
+
) -> pd.DataFrame:
|
|
230
|
+
df = rename_columns(df)
|
|
203
231
|
|
|
204
|
-
|
|
205
|
-
|
|
232
|
+
df["TradeDate"] = trade_date
|
|
233
|
+
# Convert to datetime64[ns] since it is pandas default type for timestamps
|
|
234
|
+
df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
|
|
206
235
|
|
|
207
|
-
|
|
208
|
-
df.columns = (df.columns
|
|
209
|
-
.str.replace("SctyQtn.", "")
|
|
210
|
-
.str.replace("asset.AsstSummry.", "")
|
|
211
|
-
) # fmt: skip
|
|
212
|
-
df.drop(columns=["desc", "asset.code", "mkt.cd"], inplace=True)
|
|
236
|
+
df["TickerSymbol"] = asset_code + df["ExpirationCode"]
|
|
213
237
|
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
|
|
238
|
+
# Contract code format was changed in 22/05/2006
|
|
239
|
+
if trade_date < pd.Timestamp("2006-05-22"):
|
|
240
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(
|
|
241
|
+
get_old_expiration_date, args=(trade_date,)
|
|
242
|
+
)
|
|
243
|
+
else:
|
|
244
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(get_expiration_date)
|
|
217
245
|
|
|
218
|
-
#
|
|
219
|
-
df.
|
|
246
|
+
# Columns where 0 means NaN
|
|
247
|
+
cols_with_nan = [col for col in df.columns if "Rate" in col]
|
|
248
|
+
if "SettlementPrice" in df.columns:
|
|
249
|
+
cols_with_nan.append("SettlementPrice")
|
|
250
|
+
# Replace 0 with NaN in these columns
|
|
251
|
+
df[cols_with_nan] = df[cols_with_nan].replace(0, pd.NA)
|
|
220
252
|
|
|
221
|
-
|
|
222
|
-
now = pd.Timestamp.now().round("s")
|
|
223
|
-
# Subtract 15 minutes from the current time to account for API delay
|
|
224
|
-
trade_ts = now - pd.Timedelta(minutes=15)
|
|
225
|
-
df["TradeTimestamp"] = trade_ts
|
|
253
|
+
return df
|
|
226
254
|
|
|
227
|
-
# Convert DataFrame to use nullable data types for better type consistency
|
|
228
|
-
df = df.convert_dtypes(dtype_backend="numpy_nullable")
|
|
229
255
|
|
|
230
|
-
|
|
256
|
+
def reorder_columns(df: pd.DataFrame):
|
|
257
|
+
all_columns = [
|
|
258
|
+
"TradeDate",
|
|
259
|
+
"TickerSymbol",
|
|
260
|
+
# "ExpirationCode",
|
|
261
|
+
"ExpirationDate",
|
|
262
|
+
"BDaysToExp",
|
|
263
|
+
"DaysToExp",
|
|
264
|
+
"OpenContracts",
|
|
265
|
+
# "OpenContractsEndSession" since there is no OpenContracts at the end of the
|
|
266
|
+
# day in XML data, it will be removed to avoid confusion with XML data
|
|
267
|
+
"TradeCount",
|
|
268
|
+
"TradeVolume",
|
|
269
|
+
"FinancialVolume",
|
|
270
|
+
"SettlementPrice",
|
|
271
|
+
"SettlementRate",
|
|
272
|
+
"FirstRate",
|
|
273
|
+
"MinRate",
|
|
274
|
+
"AvgRate",
|
|
275
|
+
"MaxRate",
|
|
276
|
+
"CloseAskRate",
|
|
277
|
+
"CloseBidRate",
|
|
278
|
+
"CloseRate",
|
|
279
|
+
]
|
|
280
|
+
reordered_columns = [col for col in all_columns if col in df.columns]
|
|
281
|
+
return df[reordered_columns]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from ... import bday as bd
|
|
4
|
+
from . import common as cm
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _process_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
8
|
+
"""
|
|
9
|
+
Internal function to process and transform raw DI futures data.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
df (pd.DataFrame): the raw DI DataFrame.
|
|
13
|
+
trade_date: a datetime-like object representing the trade date.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
17
|
+
"""
|
|
18
|
+
df["BDaysToExp"] = bd.count_bdays(trade_date, df["ExpirationDate"])
|
|
19
|
+
|
|
20
|
+
# Remove expired contracts
|
|
21
|
+
df.query("BDaysToExp > 0", inplace=True)
|
|
22
|
+
|
|
23
|
+
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
24
|
+
# Remove % and round to 5 (3 in %) dec. places in rate columns
|
|
25
|
+
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
26
|
+
|
|
27
|
+
# Calculate SettlementRate
|
|
28
|
+
df["SettlementRate"] = cm.convert_prices_to_rates(
|
|
29
|
+
prices=df["SettlementPrice"],
|
|
30
|
+
days_to_expiration=df["BDaysToExp"],
|
|
31
|
+
count_convention=252,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
return df
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def fetch_dap(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
38
|
+
"""
|
|
39
|
+
Fetchs the DI futures data for a given date from B3.
|
|
40
|
+
|
|
41
|
+
This function fetches and processes the DI futures data from B3 for a specific
|
|
42
|
+
trade date. It's the primary external interface for accessing DI data. If the data
|
|
43
|
+
is not available, an empty DataFrame is returned.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
47
|
+
return_raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
48
|
+
Defaults to False.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
52
|
+
|
|
53
|
+
Notes:
|
|
54
|
+
- BDaysToExp: number of business days to ExpirationDate.
|
|
55
|
+
- OpenContracts: number of open contracts at the start of the trading day.
|
|
56
|
+
"""
|
|
57
|
+
df_raw = cm.fetch_raw_df(asset_code="DI1", trade_date=trade_date)
|
|
58
|
+
if return_raw or df_raw.empty:
|
|
59
|
+
return df_raw
|
|
60
|
+
df = cm.process_raw_df(df_raw, trade_date, asset_code="DI1")
|
|
61
|
+
df = _process_df(df, trade_date)
|
|
62
|
+
return cm.reorder_columns(df)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from . import common as cm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _convert_prices_to_rates(prices: pd.Series, n_days: pd.Series) -> pd.Series:
|
|
7
|
+
"""
|
|
8
|
+
Internal function to convert DDI futures prices to rates.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
prices (pd.Series): A pd.Series containing DDI futures prices.
|
|
12
|
+
bd (pd.Series): A serie containing the number of days to expiration.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
pd.Series: A pd.Series containing DDI futures rates.
|
|
16
|
+
"""
|
|
17
|
+
rates = (100_000 / prices - 1) * (360 / n_days)
|
|
18
|
+
# Round to 5 (3 in %) dec. places (contract's current max. precision)
|
|
19
|
+
return rates.round(5)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _process_ddi_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
23
|
+
"""
|
|
24
|
+
Internal function to process and transform raw DI futures data.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
df (pd.DataFrame): the raw DI DataFrame.
|
|
28
|
+
trade_date: a datetime-like object representing the trade date.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
32
|
+
"""
|
|
33
|
+
df["DaysToExp"] = (df["ExpirationDate"] - trade_date).dt.days
|
|
34
|
+
# Convert to nullable integer, since it is the default type in the library
|
|
35
|
+
df["DaysToExp"] = df["DaysToExp"].astype(pd.Int64Dtype())
|
|
36
|
+
|
|
37
|
+
# Remove expired contracts
|
|
38
|
+
df.query("DaysToExp > 0", inplace=True)
|
|
39
|
+
|
|
40
|
+
# Columns where 0 means NaN
|
|
41
|
+
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
42
|
+
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
43
|
+
|
|
44
|
+
# Calculate SettlementRate
|
|
45
|
+
df["SettlementRate"] = _convert_prices_to_rates(
|
|
46
|
+
df["SettlementPrice"], df["DaysToExp"]
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return df
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def fetch_ddi(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
53
|
+
"""
|
|
54
|
+
Fetchs the DDI futures data for a given date from B3.
|
|
55
|
+
|
|
56
|
+
This function fetches and processes the DI futures data from B3 for a specific
|
|
57
|
+
trade date. It's the primary external interface for accessing DI data.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
61
|
+
raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
62
|
+
Defaults to False.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
>>> from pyield.futures import di
|
|
69
|
+
>>> di.fetch_ddi(pd.Timestamp("2021-01-04"))
|
|
70
|
+
|
|
71
|
+
Notes:
|
|
72
|
+
- DaysToExp: number of business days to ExpirationDate.
|
|
73
|
+
- OpenContracts: number of open contracts at the start of the trading day.
|
|
74
|
+
"""
|
|
75
|
+
df_raw = cm.fetch_raw_df(asset_code="DDI", trade_date=trade_date)
|
|
76
|
+
if return_raw or df_raw.empty:
|
|
77
|
+
return df_raw
|
|
78
|
+
df = cm.process_raw_df(df_raw, trade_date, asset_code="DDI")
|
|
79
|
+
df = _process_ddi_df(df, trade_date)
|
|
80
|
+
return cm.reorder_columns(df)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from ... import bday as bd
|
|
4
|
+
from . import common as cm
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _convert_prices_to_rates(prices: pd.Series, bd: pd.Series) -> pd.Series:
|
|
8
|
+
"""
|
|
9
|
+
Internal function to convert DI futures prices to rates.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
prices (pd.Series): A pd.Series containing DI futures prices.
|
|
13
|
+
bd (pd.Series): A serie containing the number of business days to expiration.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
pd.Series: A pd.Series containing DI futures rates.
|
|
17
|
+
"""
|
|
18
|
+
rates = (100_000 / prices) ** (252 / bd) - 1
|
|
19
|
+
|
|
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:
|
|
26
|
+
df[col] = _convert_prices_to_rates(df[col], df["BDaysToExp"])
|
|
27
|
+
|
|
28
|
+
# Invert low and high prices
|
|
29
|
+
df["MinRate"], df["MaxRate"] = df["MaxRate"], df["MinRate"]
|
|
30
|
+
|
|
31
|
+
return df
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _process_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
35
|
+
"""
|
|
36
|
+
Internal function to process and transform raw DI futures data.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
df (pd.DataFrame): the raw DI DataFrame.
|
|
40
|
+
trade_date: a datetime-like object representing the trade date.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
44
|
+
"""
|
|
45
|
+
df["BDaysToExp"] = bd.count_bdays(trade_date, df["ExpirationDate"])
|
|
46
|
+
|
|
47
|
+
# Remove expired contracts
|
|
48
|
+
df.query("BDaysToExp > 0", inplace=True)
|
|
49
|
+
|
|
50
|
+
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
51
|
+
# Prior to 17/01/2002 (inclusive), prices were not converted to rates
|
|
52
|
+
if trade_date > pd.Timestamp("2002-01-17"):
|
|
53
|
+
# Remove % and round to 5 (3 in %) dec. places in rate columns
|
|
54
|
+
df[rate_cols] = df[rate_cols].div(100).round(5)
|
|
55
|
+
else:
|
|
56
|
+
df = _adjust_older_contracts_rates(df, rate_cols)
|
|
57
|
+
|
|
58
|
+
# Calculate SettlementRate
|
|
59
|
+
df["SettlementRate"] = _convert_prices_to_rates(
|
|
60
|
+
df["SettlementPrice"], df["BDaysToExp"]
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return df
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def fetch_di(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
67
|
+
"""
|
|
68
|
+
Fetchs the DI futures data for a given date from B3.
|
|
69
|
+
|
|
70
|
+
This function fetches and processes the DI futures data from B3 for a specific
|
|
71
|
+
trade date. It's the primary external interface for accessing DI data. If the data
|
|
72
|
+
is not available, an empty DataFrame is returned.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
76
|
+
return_raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
77
|
+
Defaults to False.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
81
|
+
|
|
82
|
+
Notes:
|
|
83
|
+
- BDaysToExp: number of business days to ExpirationDate.
|
|
84
|
+
- OpenContracts: number of open contracts at the start of the trading day.
|
|
85
|
+
"""
|
|
86
|
+
df_raw = cm.fetch_raw_df(asset_code="DI1", trade_date=trade_date)
|
|
87
|
+
if return_raw or df_raw.empty:
|
|
88
|
+
return df_raw
|
|
89
|
+
df = cm.process_raw_df(df_raw, trade_date, asset_code="DI1")
|
|
90
|
+
df = _process_df(df, trade_date)
|
|
91
|
+
return cm.reorder_columns(df)
|
|
@@ -7,7 +7,7 @@ import requests
|
|
|
7
7
|
from lxml import etree
|
|
8
8
|
from pandas import DataFrame, Timestamp
|
|
9
9
|
|
|
10
|
-
from
|
|
10
|
+
from ... import bday
|
|
11
11
|
from . import common as cm
|
|
12
12
|
|
|
13
13
|
|
|
@@ -206,7 +206,7 @@ def _standardize_column_names(df: DataFrame) -> DataFrame:
|
|
|
206
206
|
"TradAvrgPric": "AvgRate",
|
|
207
207
|
"MaxPric": "MaxRate",
|
|
208
208
|
"FrstPric": "FirstRate",
|
|
209
|
-
"LastPric": "
|
|
209
|
+
"LastPric": "CloseRate",
|
|
210
210
|
"AdjstdQtTax": "SettlementRate",
|
|
211
211
|
# "RglrTxsQty"
|
|
212
212
|
# "RglrTraddCtrcts"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from . import common as cm
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _process_frc_df(df: pd.DataFrame, trade_date: pd.Timestamp) -> pd.DataFrame:
|
|
7
|
+
"""
|
|
8
|
+
Internal function to process and transform raw DI futures data.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
df (pd.DataFrame): the raw DI DataFrame.
|
|
12
|
+
trade_date: a datetime-like object representing the trade date.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
pd.DataFrame: Processed and transformed data as a Pandas pd.DataFrame.
|
|
16
|
+
"""
|
|
17
|
+
df = cm.rename_columns(df)
|
|
18
|
+
|
|
19
|
+
df["TradeDate"] = trade_date
|
|
20
|
+
# Convert to datetime64[ns] since it is pandas default type for timestamps
|
|
21
|
+
df["TradeDate"] = df["TradeDate"].astype("datetime64[ns]")
|
|
22
|
+
|
|
23
|
+
# Contract code format was changed in 22/05/2006
|
|
24
|
+
if trade_date < pd.Timestamp("2006-05-22"):
|
|
25
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(
|
|
26
|
+
cm.get_old_expiration_date, args=(trade_date,)
|
|
27
|
+
)
|
|
28
|
+
else:
|
|
29
|
+
df["ExpirationDate"] = df["ExpirationCode"].apply(cm.get_expiration_date)
|
|
30
|
+
|
|
31
|
+
# Replace 0 values in rate columns with pd.NA and remove percentage
|
|
32
|
+
rate_cols = [col for col in df.columns if "Rate" in col]
|
|
33
|
+
# Round to 5 decimal places (3 in %) since it is the contract's precision
|
|
34
|
+
df[rate_cols] = df[rate_cols].replace(0, pd.NA).div(100).round(5)
|
|
35
|
+
|
|
36
|
+
return df
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def fetch_frc(trade_date: pd.Timestamp, return_raw: bool = False) -> pd.DataFrame:
|
|
40
|
+
"""
|
|
41
|
+
Fetchs the DI futures data for a given date from B3.
|
|
42
|
+
|
|
43
|
+
This function fetches and processes the DI futures data from B3 for a specific
|
|
44
|
+
trade date. It's the primary external interface for accessing DI data.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
trade_date (pd.Timestamp): The trade date to fetch the DI futures data.
|
|
48
|
+
raw (bool): If True, returns the raw data as a Pandas pd.DataFrame.
|
|
49
|
+
Defaults to False.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
pd.DataFrame: A Pandas pd.DataFrame containing processed DI futures data.
|
|
53
|
+
"""
|
|
54
|
+
df_raw = cm.fetch_raw_df(asset_code="FRC", trade_date=trade_date)
|
|
55
|
+
if return_raw or df_raw.empty:
|
|
56
|
+
return df_raw
|
|
57
|
+
# Filter and order columns
|
|
58
|
+
df = cm.process_raw_df(df_raw, trade_date, asset_code="FRC")
|
|
59
|
+
df = _process_frc_df(df, trade_date)
|
|
60
|
+
return cm.reorder_columns(df)
|