detquantlib 4.0.0__tar.gz → 5.0.1__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 (33) hide show
  1. {detquantlib-4.0.0 → detquantlib-5.0.1}/PKG-INFO +4 -1
  2. {detquantlib-4.0.0 → detquantlib-5.0.1}/README.md +3 -0
  3. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/dates/dates.py +4 -65
  4. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/tradable_products/tradable_products.py +83 -24
  5. {detquantlib-4.0.0 → detquantlib-5.0.1}/pyproject.toml +1 -1
  6. {detquantlib-4.0.0 → detquantlib-5.0.1}/LICENSE.txt +0 -0
  7. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/__init__.py +0 -0
  8. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/assets/__init__.py +0 -0
  9. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/assets/battery.py +0 -0
  10. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/assets/wind_turbine.py +0 -0
  11. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/converters/__init__.py +0 -0
  12. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/converters/definitions.py +0 -0
  13. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/converters/energy.py +0 -0
  14. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/converters/helpers.py +0 -0
  15. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/converters/price.py +0 -0
  16. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/data/__init__.py +0 -0
  17. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/data/databases/detdatabase.py +0 -0
  18. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/data/databases/helpers.py +0 -0
  19. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/data/entsoe/entsoe.py +0 -0
  20. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/data/sftp/sftp.py +0 -0
  21. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/dates/__init__.py +0 -0
  22. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/figures/__init__.py +0 -0
  23. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/figures/plotly_figures.py +0 -0
  24. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/forecasting/__init__.py +0 -0
  25. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/forecasting/forecasting.py +0 -0
  26. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/outputs/__init__.py +0 -0
  27. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/outputs/outputs_interface.py +0 -0
  28. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/stats/__init__.py +0 -0
  29. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/stats/data_analysis.py +0 -0
  30. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/tradable_products/__init__.py +0 -0
  31. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/utils/__init__.py +0 -0
  32. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/utils/logging.py +0 -0
  33. {detquantlib-4.0.0 → detquantlib-5.0.1}/detquantlib/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detquantlib
3
- Version: 4.0.0
3
+ Version: 5.0.1
4
4
  Summary: An internal library containing functions and classes that can be used across Quant models.
5
5
  License-File: LICENSE.txt
6
6
  Author: Dynamic Energy Trading
@@ -104,6 +104,9 @@ Classes:
104
104
  - `WindTurbine`:
105
105
  - `from detquantlib.assets import WindTurbine`
106
106
  - `from detquantlib.assets.wind_turbine import WindTurbine`
107
+ - `WindTurbineModels`:
108
+ - `from detquantlib.assets import WindTurbineModels`
109
+ - `from detquantlib.assets.wind_turbine import WindTurbineModels`
107
110
 
108
111
  Functions:
109
112
 
@@ -78,6 +78,9 @@ Classes:
78
78
  - `WindTurbine`:
79
79
  - `from detquantlib.assets import WindTurbine`
80
80
  - `from detquantlib.assets.wind_turbine import WindTurbine`
81
+ - `WindTurbineModels`:
82
+ - `from detquantlib.assets import WindTurbineModels`
83
+ - `from detquantlib.assets.wind_turbine import WindTurbineModels`
81
84
 
82
85
  Functions:
83
86
 
@@ -3,16 +3,10 @@ from datetime import datetime, timezone
3
3
  from typing import Literal
4
4
 
5
5
  # Third-party packages
6
- import pandas as pd
7
6
  from dateutil.relativedelta import *
8
7
 
9
8
  # Specify functions to expose
10
- __all__ = [
11
- "count_nr_hours",
12
- "count_delivery_periods",
13
- "calc_months_diff",
14
- "datetime_to_month_code",
15
- ]
9
+ __all__ = ["count_nr_hours", "calc_months_diff", "datetime_to_month_code"]
16
10
 
17
11
 
18
12
  def count_nr_hours(start_date: datetime, end_date: datetime) -> float:
@@ -46,61 +40,6 @@ def count_nr_hours(start_date: datetime, end_date: datetime) -> float:
46
40
  return td.days * 24 + td.seconds / 3600
47
41
 
48
42
 
49
- def count_delivery_periods(
50
- start_date: datetime,
51
- end_date: datetime,
52
- delivery_frequency: str,
53
- full_periods_only: bool = False,
54
- timezone: str = None,
55
- ) -> int:
56
- """
57
- Counts the number of delivery periods within a time interval.
58
-
59
- Note: When the end date is exactly equal to the start of the next delivery period, that next
60
- period is not included (because it has not yet started). For example, if the end date is
61
- 15-Jan-2025 00:00:00 and the delivery frequency is daily, then the period
62
- 15-Jan-2025 00:00:00 to 16-Jan-2025 00:00:00 is not included.
63
-
64
- Args:
65
- start_date: Delivery start date
66
- end_date: Delivery end date
67
- delivery_frequency: Delivery frequency, expressed as Pandas offset aliases
68
- full_periods_only: Indicates whether to count only fully elapsed periods.
69
- For example, suppose that start date is 15-Jan-2025 00:15:00, end date is
70
- 3-Feb-2025 03:45:00, and delivery frequency is hourly. Then:
71
- - If full_periods_only=True, the number of periods is 2 (01:00:00-02:00:00 and
72
- 02:00:00-03:00:00), because the hours 00:00:00-01:00:00 and 00:03:00-04:00:00
73
- are not full.
74
- - If full_periods_only=False, the number of periods is 4, because incomplete hours
75
- 00:00:00-01:00:00 and 00:03:00-04:00:00 are also included. Note:
76
- - If end date is 3-Feb-2025 04:00:00, hour 04:00:00-05:00:00 is not included.
77
- - If end date is 3-Feb-2025 04:00:01, hour 04:00:00-05:00:00 is included.
78
- timezone: Timezone (needed to account for DST switches)
79
-
80
- Returns:
81
- Number of delivery periods in the interval
82
- """
83
- # Convert to pandas timestamp
84
- start_date = pd.Timestamp(start_date)
85
- end_date = pd.Timestamp(end_date)
86
-
87
- if full_periods_only:
88
- start_date = start_date.ceil(delivery_frequency)
89
- end_date = end_date.floor(delivery_frequency)
90
- else:
91
- start_date = start_date.floor(delivery_frequency)
92
-
93
- periods = pd.date_range(
94
- start=start_date,
95
- end=end_date,
96
- freq=delivery_frequency,
97
- inclusive="left",
98
- tz=timezone,
99
- )
100
- nr_periods = len(periods)
101
- return nr_periods
102
-
103
-
104
43
  def calc_months_diff(
105
44
  start_date: datetime,
106
45
  end_date: datetime,
@@ -138,8 +77,8 @@ def calc_months_diff(
138
77
  Month difference between 2 dates
139
78
 
140
79
  Raises:
141
- ValueError: Raises an error when end_date < start_date
142
- ValueError: Raises an error when the input argument 'diff_method' is invalid
80
+ ValueError: Raises an error when end_date < start_date.
81
+ ValueError: Raises an error when the input argument 'diff_method' is invalid.
143
82
  """
144
83
  # Input validation
145
84
  if end_date < start_date and diff_method != "month":
@@ -185,7 +124,7 @@ def datetime_to_month_code(d: datetime) -> int:
185
124
  Corresponding month code
186
125
 
187
126
  Raises:
188
- ValueError: Raises an error if the input datetime is before 1 January 1900
127
+ ValueError: Raises an error if the input datetime is before 1 January 1900.
189
128
  """
190
129
  if d < datetime(1900, 1, 1):
191
130
  raise ValueError("Input date cannot be before 1 January 1900.")
@@ -15,6 +15,7 @@ from detquantlib.utils import list_to_str
15
15
  __all__ = [
16
16
  "convert_delivery_start_date_to_maturity",
17
17
  "convert_maturity_to_delivery_start_date",
18
+ "count_delivery_periods",
18
19
  "tenor_to_pd_offset_alias",
19
20
  "tenor_to_nr_hours",
20
21
  ]
@@ -70,56 +71,114 @@ def tenor_to_nr_hours(
70
71
  return nr_hours
71
72
 
72
73
 
74
+ def count_delivery_periods(
75
+ start_date: datetime,
76
+ end_date: datetime,
77
+ tenor: str,
78
+ full_periods_only: bool = False,
79
+ tz: str = None,
80
+ ) -> int:
81
+ """
82
+ Counts the number of delivery periods within a time interval.
83
+
84
+ Note: When the end date is exactly equal to the start of the next delivery period, that next
85
+ period is not included (because it has not yet started). For example, if the end date is
86
+ 15-Jan-2025 00:00:00 and the delivery frequency is daily, then the period
87
+ 15-Jan-2025 00:00:00 to 16-Jan-2025 00:00:00 is not included.
88
+
89
+ Args:
90
+ start_date: Delivery start date
91
+ end_date: Delivery end date
92
+ tenor: Product tenor
93
+ full_periods_only: Indicates whether to count only fully elapsed periods.
94
+ For example, suppose that start date is 15-Jan-2025 00:15:00, end date is
95
+ 3-Feb-2025 03:45:00, and delivery frequency is hourly. Then:
96
+ - If full_periods_only=True, the number of periods is 2 (01:00:00-02:00:00 and
97
+ 02:00:00-03:00:00), because the hours 00:00:00-01:00:00 and 00:03:00-04:00:00
98
+ are not full.
99
+ - If full_periods_only=False, the number of periods is 4, because incomplete hours
100
+ 00:00:00-01:00:00 and 00:03:00-04:00:00 are also included. Note:
101
+ - If end date is 3-Feb-2025 04:00:00, hour 04:00:00-05:00:00 is not included.
102
+ - If end date is 3-Feb-2025 04:00:01, hour 04:00:00-05:00:00 is included.
103
+ tz: Timezone (needed to account for DST switches)
104
+
105
+ Returns:
106
+ Number of delivery periods in the interval
107
+ """
108
+ # Convert tenor to offset alias
109
+ freq = tenor_to_pd_offset_alias(tenor)
110
+
111
+ # Convert to pandas timestamp
112
+ start_date = pd.Timestamp(start_date)
113
+ end_date = pd.Timestamp(end_date)
114
+
115
+ if full_periods_only:
116
+ start_date = start_date.ceil(freq)
117
+ end_date = end_date.floor(freq)
118
+ else:
119
+ start_date = start_date.floor(freq)
120
+
121
+ periods = pd.date_range(
122
+ start=start_date,
123
+ end=end_date,
124
+ freq=freq,
125
+ inclusive="left",
126
+ tz=tz,
127
+ )
128
+ nr_periods = len(periods)
129
+ return nr_periods
130
+
131
+
73
132
  def convert_delivery_start_date_to_maturity(
74
133
  trading_date: datetime,
75
134
  delivery_start_date: datetime,
76
- product: Literal["day", "weekend", "week", "month", "quarter", "year"],
135
+ tenor: Literal["day", "weekend", "week", "month", "quarter", "year"],
77
136
  ) -> int:
78
137
  """
79
138
  Calculates the number of maturities between the input trading date and the input delivery
80
- date, based on the input product type.
139
+ date, based on the input product tenor.
81
140
 
82
141
  Args:
83
142
  trading_date: Trading date
84
143
  delivery_start_date: Delivery start date
85
- product: Product type (e.g. "month", "quarter", "year")
144
+ tenor: Product tenor (e.g. "month", "quarter", "year")
86
145
 
87
146
  Returns:
88
147
  Product maturity
89
148
 
90
149
  Raises:
91
- ValueError: Raises an error when the input product type is not recognized
150
+ ValueError: Raises an error when the input product tenor is not recognized.
92
151
  """
93
152
  # Make input product string lower case only
94
- product = product.lower()
153
+ tenor = tenor.lower()
95
154
 
96
155
  # Set trading date and delivery date to midnight
97
156
  trading_date = datetime.combine(trading_date, time())
98
157
  delivery_start_date = datetime.combine(delivery_start_date, time())
99
158
 
100
- if product == "day":
159
+ if tenor == "day":
101
160
  maturity = (delivery_start_date - trading_date).days
102
161
 
103
- elif product == "week":
162
+ elif tenor == "week":
104
163
  maturity = math.ceil((delivery_start_date - trading_date).days / 7)
105
164
 
106
- elif product == "weekend":
165
+ elif tenor == "weekend":
107
166
  maturity = math.ceil((delivery_start_date - trading_date).days / 7)
108
167
 
109
- elif product == "month":
168
+ elif tenor == "month":
110
169
  maturity = calc_months_diff(
111
170
  start_date=trading_date,
112
171
  end_date=delivery_start_date,
113
172
  diff_method="month",
114
173
  )
115
174
 
116
- elif product == "quarter":
175
+ elif tenor == "quarter":
117
176
  trading_quarter_start_date = convert_maturity_to_delivery_start_date(
118
- trading_date=trading_date, maturity=0, product="quarter"
177
+ trading_date=trading_date, maturity=0, tenor="quarter"
119
178
  )
120
179
 
121
180
  delivery_quarter_start_date = convert_maturity_to_delivery_start_date(
122
- trading_date=delivery_start_date, maturity=0, product="quarter"
181
+ trading_date=delivery_start_date, maturity=0, tenor="quarter"
123
182
  )
124
183
 
125
184
  months_diff = calc_months_diff(
@@ -129,11 +188,11 @@ def convert_delivery_start_date_to_maturity(
129
188
  )
130
189
  maturity = months_diff / 3
131
190
 
132
- elif product == "year":
191
+ elif tenor == "year":
133
192
  maturity = delivery_start_date.year - trading_date.year
134
193
 
135
194
  else:
136
- raise ValueError("Invalid input product name.")
195
+ raise ValueError("Invalid input product tenor.")
137
196
 
138
197
  return maturity
139
198
 
@@ -141,42 +200,42 @@ def convert_delivery_start_date_to_maturity(
141
200
  def convert_maturity_to_delivery_start_date(
142
201
  trading_date: datetime,
143
202
  maturity: int,
144
- product: Literal["month", "quarter", "year"],
203
+ tenor: Literal["month", "quarter", "year"],
145
204
  ) -> datetime:
146
205
  """
147
- Calculates the delivery start date of the input product, based on the input trading date
148
- and input maturity.
206
+ Calculates the delivery start date of the input product tenor, based on the input trading
207
+ date and input maturity.
149
208
 
150
209
  Args:
151
210
  trading_date: Trading date
152
211
  maturity: Product maturity
153
- product: Product type (e.g. "month", "quarter", "year")
212
+ tenor: Product tenor (e.g. "month", "quarter", "year")
154
213
 
155
214
  Returns:
156
215
  Delivery start date
157
216
 
158
217
  Raises:
159
- ValueError: Raises an error when the input product type is not recognized
218
+ ValueError: Raises an error when the input product tenor is not recognized.
160
219
  """
161
220
 
162
221
  # Make input product string lower case only
163
- product = product.lower()
222
+ tenor = tenor.lower()
164
223
 
165
- if product == "month":
224
+ if tenor == "month":
166
225
  month_start_date = datetime(trading_date.year, trading_date.month, 1)
167
226
  delivery_start_date = month_start_date + relativedelta(months=maturity)
168
227
 
169
- elif product == "quarter":
228
+ elif tenor == "quarter":
170
229
  quarter = pd.Timestamp(trading_date).quarter
171
230
  year_start_date = datetime(trading_date.year, 1, 1)
172
231
  quarter_start_date = year_start_date + relativedelta(months=((quarter - 1) * 3))
173
232
  delivery_start_date = quarter_start_date + relativedelta(months=(maturity * 3))
174
233
 
175
- elif product == "year":
234
+ elif tenor == "year":
176
235
  year_start_date = datetime(trading_date.year, 1, 1)
177
236
  delivery_start_date = year_start_date + relativedelta(years=maturity)
178
237
 
179
238
  else:
180
- raise ValueError("Invalid input product name.")
239
+ raise ValueError("Invalid input product tenor.")
181
240
 
182
241
  return delivery_start_date
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "detquantlib"
3
- version = "4.0.0"
3
+ version = "5.0.1"
4
4
  description = "An internal library containing functions and classes that can be used across Quant models."
5
5
  authors = ["Dynamic Energy Trading"]
6
6
  readme = "README.md"
File without changes