detquantlib 3.14.0__tar.gz → 3.15.0__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.
- {detquantlib-3.14.0 → detquantlib-3.15.0}/PKG-INFO +3 -3
- detquantlib-3.15.0/detquantlib/assets/__init__.py +4 -0
- detquantlib-3.15.0/detquantlib/assets/battery.py +174 -0
- detquantlib-3.15.0/detquantlib/assets/wind_turbine.py +92 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/data/databases/detdatabase.py +14 -14
- {detquantlib-3.14.0 → detquantlib-3.15.0}/pyproject.toml +8 -3
- {detquantlib-3.14.0 → detquantlib-3.15.0}/LICENSE.txt +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/README.md +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/converters/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/converters/definitions.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/converters/energy.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/converters/helpers.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/converters/price.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/data/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/data/databases/helpers.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/data/entsoe/entsoe.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/data/sftp/sftp.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/dates/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/dates/dates.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/figures/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/figures/plotly_figures.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/forecasting/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/forecasting/forecasting.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/outputs/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/outputs/outputs_interface.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/stats/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/stats/data_analysis.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/tradable_products/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/tradable_products/tradable_products.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/utils/__init__.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/utils/logging.py +0 -0
- {detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/utils/utils.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: detquantlib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.15.0
|
|
4
4
|
Summary: An internal library containing functions and classes that can be used across Quant models.
|
|
5
5
|
License-File: LICENSE.txt
|
|
6
|
-
Author:
|
|
6
|
+
Author: Dynamic Energy Trading
|
|
7
7
|
Requires-Python: >=3.10,<4.0
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -19,9 +19,9 @@ Requires-Dist: plotly (>=6.3.1,<7.0.0)
|
|
|
19
19
|
Requires-Dist: pyarrow (>=21.0.0,<22.0.0)
|
|
20
20
|
Requires-Dist: pyodbc (>=5.2.0,<6.0.0)
|
|
21
21
|
Requires-Dist: python-dotenv (>=1.1.0,<2.0.0)
|
|
22
|
+
Requires-Dist: redis (>=7.4.0,<8.0.0)
|
|
22
23
|
Requires-Dist: scipy (>=1.15.2,<2.0.0)
|
|
23
24
|
Requires-Dist: sqlalchemy (>=2.0.43,<3.0.0)
|
|
24
|
-
Project-URL: Repository, https://github.com/Dynamic-Energy-Trading/detquantlib
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
26
26
|
|
|
27
27
|
# DET Quant Library
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Python built-in packages
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Third-party packages
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import redis
|
|
8
|
+
|
|
9
|
+
# Internal modules
|
|
10
|
+
from detquantlib.utils import list_to_str
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Battery:
|
|
14
|
+
"""A class containing the characteristics of a battery."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
capacity_mwh: float = None,
|
|
19
|
+
power_mw: float = None,
|
|
20
|
+
state_of_charge_mwh: float = None,
|
|
21
|
+
roundtrip_eff: float = None,
|
|
22
|
+
group_id: int = None,
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Constructor method.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
capacity_mwh: Battery capacity in MWh
|
|
29
|
+
power_mw: Battery power in MW
|
|
30
|
+
state_of_charge_mwh: Current state of charge in MWh
|
|
31
|
+
roundtrip_eff: Roundtrip efficiency
|
|
32
|
+
group_id: Group ID (used to differentiate batteries with different characteristics
|
|
33
|
+
"""
|
|
34
|
+
# Assign inputs
|
|
35
|
+
self.capacity_mwh = capacity_mwh
|
|
36
|
+
self.power_mw = power_mw
|
|
37
|
+
self.state_of_charge_mwh = state_of_charge_mwh
|
|
38
|
+
self.roundtrip_eff = roundtrip_eff
|
|
39
|
+
self.group_id = group_id
|
|
40
|
+
|
|
41
|
+
# Calculate power-to-capacity ratio
|
|
42
|
+
if self.capacity_mwh and self.power_mw:
|
|
43
|
+
self.capacity_power_ratio = round(self.capacity_mwh / self.power_mw, 0)
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def build_from_redis() -> (list["Battery"], str):
|
|
47
|
+
"""
|
|
48
|
+
Builds Battery objects from the individual battery units found in the redis cache.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Tuple:
|
|
52
|
+
- List of Battery objects
|
|
53
|
+
- Message listing all the batteries whose information could not be retrieved
|
|
54
|
+
from the redis cache
|
|
55
|
+
"""
|
|
56
|
+
# Load individual battery units
|
|
57
|
+
battery_units, missing_units = Battery.load_battery_units_from_redis()
|
|
58
|
+
|
|
59
|
+
# Print missing battery units
|
|
60
|
+
msg_missing_units = ""
|
|
61
|
+
nr_found, nr_miss = len(battery_units), len(missing_units)
|
|
62
|
+
if nr_miss > 0:
|
|
63
|
+
msg_missing_units = (
|
|
64
|
+
f"Failed to retrieve the battery storage data of {nr_miss}/{nr_found + nr_miss} "
|
|
65
|
+
f"batteries. Details:"
|
|
66
|
+
)
|
|
67
|
+
for mb in missing_units:
|
|
68
|
+
msg_missing_units += (
|
|
69
|
+
f"\n- Site node ID: {mb['site_node_id']}. Error message: '{mb['error_msg']}'."
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if nr_found == 0:
|
|
73
|
+
return list(), msg_missing_units
|
|
74
|
+
|
|
75
|
+
# Set battery groups based on capacity:power ratio
|
|
76
|
+
battery_units = pd.DataFrame(battery_units)
|
|
77
|
+
battery_units.sort_values("cp_ratio", ignore_index=True, inplace=True)
|
|
78
|
+
battery_units["cp_group"] = battery_units["cp_ratio"].round(0)
|
|
79
|
+
|
|
80
|
+
# Calculate aggregated virtual batteries
|
|
81
|
+
agg_units = (
|
|
82
|
+
battery_units[["capacity_mwh", "power_mw", "state_of_charge_mwh", "cp_group"]]
|
|
83
|
+
.groupby("cp_group", as_index=False)
|
|
84
|
+
.agg({"capacity_mwh": "sum", "power_mw": "sum", "state_of_charge_mwh": "sum"})
|
|
85
|
+
.reset_index(drop=True)
|
|
86
|
+
)
|
|
87
|
+
agg_units["group_id"] = agg_units["cp_group"].rank(method="dense")
|
|
88
|
+
agg_units.drop(columns="cp_group", inplace=True)
|
|
89
|
+
|
|
90
|
+
# Round to avoid machine precision issues caused by 'group by'
|
|
91
|
+
agg_units = agg_units.round(9)
|
|
92
|
+
|
|
93
|
+
# Create battery objects
|
|
94
|
+
batteries = [Battery(**agg_units.loc[i, :].to_dict()) for i in agg_units.index]
|
|
95
|
+
|
|
96
|
+
return batteries, msg_missing_units
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def load_battery_units_from_redis() -> (list[dict], list[dict]):
|
|
100
|
+
"""
|
|
101
|
+
Loads individual battery units from the redis cache.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Tuple:
|
|
105
|
+
- Individual battery units whose information could be found
|
|
106
|
+
- Individual battery units whose information could not be found
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
ConnectionError: Raises an error if environment variables are not defined.
|
|
110
|
+
"""
|
|
111
|
+
# Check mandatory environment variables to connect to Redis cache
|
|
112
|
+
mandatory_vars = ["DET_REDIS_HOST", "DET_REDIS_PORT", "DET_REDIS_PASSWORD", "DET_REDIS_DB"]
|
|
113
|
+
for mv in mandatory_vars:
|
|
114
|
+
if mv not in os.environ:
|
|
115
|
+
raise ConnectionError(
|
|
116
|
+
f"Environment variable '{mv}' not found. Connection to Redis cache requires "
|
|
117
|
+
f"the following environment variables: {list_to_str(mandatory_vars)}."
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Connect to redis cache
|
|
121
|
+
r = redis.Redis(
|
|
122
|
+
host=os.environ["DET_REDIS_HOST"],
|
|
123
|
+
port=int(os.environ["DET_REDIS_PORT"]),
|
|
124
|
+
password=os.environ["DET_REDIS_PASSWORD"],
|
|
125
|
+
ssl=True,
|
|
126
|
+
db=int(os.environ["DET_REDIS_DB"]),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Loop over cache data
|
|
130
|
+
battery_units = []
|
|
131
|
+
missing_units = []
|
|
132
|
+
for key in r.scan_iter("*"):
|
|
133
|
+
# Parse data
|
|
134
|
+
raw = r.get(key)
|
|
135
|
+
data = json.loads(raw)
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
storage = data["data"]["state"]["storage"]
|
|
139
|
+
except KeyError:
|
|
140
|
+
# Skip battery if info cannot be found
|
|
141
|
+
missing_units.append(
|
|
142
|
+
dict(site_node_id=data["siteNodeId"], error_msg=data["data"].get("errors", ""))
|
|
143
|
+
)
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# Convert settings
|
|
147
|
+
capacity_mwh = storage["energy_capacity_Wh"] / 1e6
|
|
148
|
+
state_of_charge_mwh = storage["energy_stored_Wh"] / 1e6
|
|
149
|
+
charge_rate_mw = storage["max_charge_power_W"] / 1e6
|
|
150
|
+
discharge_rate_mw = storage["max_discharge_power_W"] / 1e6
|
|
151
|
+
|
|
152
|
+
# Set (dis)charge rate
|
|
153
|
+
power_mw = max(charge_rate_mw, -discharge_rate_mw)
|
|
154
|
+
|
|
155
|
+
# Calculate capacity:power ratio
|
|
156
|
+
cp_ratio = capacity_mwh / power_mw
|
|
157
|
+
|
|
158
|
+
# Get BESS group data
|
|
159
|
+
timestamp = data["time"]
|
|
160
|
+
site_node_id = data["siteNodeId"]
|
|
161
|
+
|
|
162
|
+
# Store characteristics
|
|
163
|
+
battery_units.append(
|
|
164
|
+
dict(
|
|
165
|
+
capacity_mwh=capacity_mwh,
|
|
166
|
+
power_mw=power_mw,
|
|
167
|
+
state_of_charge_mwh=state_of_charge_mwh,
|
|
168
|
+
cp_ratio=cp_ratio,
|
|
169
|
+
timestamp=timestamp,
|
|
170
|
+
site_node_id=site_node_id,
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return battery_units, missing_units
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Third-party packages
|
|
2
|
+
import numpy as np
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from scipy.interpolate import CubicSpline
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WindTurbine:
|
|
8
|
+
"""A class to store wind turbine information and perform wind turbine-related calculations."""
|
|
9
|
+
|
|
10
|
+
def __init__(
|
|
11
|
+
self, rated_power: float, cut_in: float, cut_out: float, power_curve: CubicSpline = None
|
|
12
|
+
):
|
|
13
|
+
"""
|
|
14
|
+
Constructor method.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
rated_power: Rated power
|
|
18
|
+
cut_in: Cut-in wind speed
|
|
19
|
+
cut_out: Cut-out wind speed
|
|
20
|
+
power_curve: Power curve, stored as a cubic spline object. If not provided, can be
|
|
21
|
+
set via the 'fit_power_curve()' method below.
|
|
22
|
+
"""
|
|
23
|
+
self.rated_power = rated_power
|
|
24
|
+
self.cut_in = cut_in
|
|
25
|
+
self.cut_out = cut_out
|
|
26
|
+
self.power_curve = power_curve
|
|
27
|
+
|
|
28
|
+
def fit_power_curve(
|
|
29
|
+
self, wind_speed: list | np.ndarray | pd.Series, power: list | np.ndarray | pd.Series
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
Fits the wind turbine's power curve with a cubic spline, and stores the resulting spline
|
|
33
|
+
object in attribute self.power_curve.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
wind_speed: Wind speeds
|
|
37
|
+
power: Corresponding power
|
|
38
|
+
"""
|
|
39
|
+
# Make sure input data is stored as numpy array
|
|
40
|
+
wind_speed, power = np.array(wind_speed), np.array(power)
|
|
41
|
+
|
|
42
|
+
# Trim data to cut-in - cut-out interval
|
|
43
|
+
idx = (wind_speed >= self.cut_in) & (wind_speed <= self.cut_out)
|
|
44
|
+
wind_speed_trim, power_trim = wind_speed[idx], power[idx]
|
|
45
|
+
|
|
46
|
+
# Add data point with power=0.0 before cut-in to ensure smooth behaviour of spline
|
|
47
|
+
# interpolation
|
|
48
|
+
w0 = wind_speed_trim[0] - np.diff(wind_speed_trim[:2])
|
|
49
|
+
p0 = [0]
|
|
50
|
+
wind_speed_trim, power_trim = np.concat([w0, wind_speed_trim]), np.concat([p0, power_trim])
|
|
51
|
+
|
|
52
|
+
# Fit cubic spline
|
|
53
|
+
cs = CubicSpline(wind_speed_trim, power_trim)
|
|
54
|
+
|
|
55
|
+
# Store spline object
|
|
56
|
+
self.power_curve = cs
|
|
57
|
+
|
|
58
|
+
def wind_to_power(self, wind_speed: list | np.ndarray | pd.Series) -> np.ndarray:
|
|
59
|
+
"""
|
|
60
|
+
Converts wind speeds to wind turbine power.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
wind_speed: Wind speeds
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Corresponding power
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
ValueError: Raises an error if self.power_curve is None.
|
|
70
|
+
"""
|
|
71
|
+
# Check that power curve attribute is defined
|
|
72
|
+
if self.power_curve is None:
|
|
73
|
+
raise ValueError(
|
|
74
|
+
"Cannot execute method self.wind_to_power() if attribute self.power_curve is "
|
|
75
|
+
"None. Use method self.fit_power_curve() to set self.power_curve based on power "
|
|
76
|
+
"curve data."
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Make sure input data is stored as numpy array
|
|
80
|
+
wind_speed = np.array(wind_speed)
|
|
81
|
+
|
|
82
|
+
# Cubic spline interpolation
|
|
83
|
+
power = self.power_curve(wind_speed)
|
|
84
|
+
|
|
85
|
+
# Cap to rated power
|
|
86
|
+
power = np.minimum(power, self.rated_power)
|
|
87
|
+
|
|
88
|
+
# Adjust values outside of cut-in - cut-out bounds
|
|
89
|
+
idx = (wind_speed < self.cut_in) | (wind_speed > self.cut_out)
|
|
90
|
+
power[idx] = 0.0
|
|
91
|
+
|
|
92
|
+
return power
|
|
@@ -51,7 +51,7 @@ class DetDatabase:
|
|
|
51
51
|
Checks if environment variables needed by the class are defined.
|
|
52
52
|
|
|
53
53
|
Raises:
|
|
54
|
-
|
|
54
|
+
ConnectionError: Raises an error if environment variables are not defined.
|
|
55
55
|
"""
|
|
56
56
|
required_env_vars = [
|
|
57
57
|
dict(name="DET_DB_NAME", value=None, description="Database name"),
|
|
@@ -64,7 +64,7 @@ class DetDatabase:
|
|
|
64
64
|
if d["name"] not in available_env_vars:
|
|
65
65
|
required_env_vars_names = [x["name"] for x in required_env_vars]
|
|
66
66
|
required_env_vars_str = list_to_str(required_env_vars_names)
|
|
67
|
-
raise
|
|
67
|
+
raise ConnectionError(
|
|
68
68
|
f"The DetDatabase class requires the following environment variables: "
|
|
69
69
|
f"{required_env_vars_str}. Environment variable '{d['name']}' "
|
|
70
70
|
f"(description: '{d['description']}') not found."
|
|
@@ -104,11 +104,11 @@ class DetDatabase:
|
|
|
104
104
|
Dataframe containing the queried data
|
|
105
105
|
|
|
106
106
|
Raises:
|
|
107
|
-
Exception: Raises an error if the SQL query fails
|
|
107
|
+
Exception: Raises an error if the SQL query fails.
|
|
108
108
|
"""
|
|
109
109
|
try:
|
|
110
110
|
df = pd.read_sql_query(query, con=self.engine)
|
|
111
|
-
except Exception
|
|
111
|
+
except Exception:
|
|
112
112
|
# If query fails, close connection before raising the error
|
|
113
113
|
self.terminate_engine()
|
|
114
114
|
raise
|
|
@@ -171,10 +171,10 @@ class DetDatabase:
|
|
|
171
171
|
|
|
172
172
|
Raises:
|
|
173
173
|
ValueError: Raises an error if input arguments 'columns' and 'process_data' are not
|
|
174
|
-
compatible
|
|
174
|
+
compatible.
|
|
175
175
|
ValueError: Raises an error if the combination of trading dates and delivery dates
|
|
176
176
|
is not valid.
|
|
177
|
-
ValueError: Raises an error if no price data is found for user inputs
|
|
177
|
+
ValueError: Raises an error if no price data is found for user inputs.
|
|
178
178
|
"""
|
|
179
179
|
# Input validation
|
|
180
180
|
if process_data and columns is not None:
|
|
@@ -385,10 +385,10 @@ class DetDatabase:
|
|
|
385
385
|
|
|
386
386
|
Raises:
|
|
387
387
|
ValueError: Raises an error if input arguments 'columns' and 'process_data' are not
|
|
388
|
-
compatible
|
|
388
|
+
compatible.
|
|
389
389
|
ValueError: Raises an error if the combination of trading dates and delivery dates
|
|
390
390
|
is not valid.
|
|
391
|
-
ValueError: Raises an error if no price data is found for user inputs
|
|
391
|
+
ValueError: Raises an error if no price data is found for user inputs.
|
|
392
392
|
"""
|
|
393
393
|
# Input validation
|
|
394
394
|
if process_data and columns is not None:
|
|
@@ -569,7 +569,7 @@ class DetDatabase:
|
|
|
569
569
|
Dataframe containing futures end-of-day settlement prices
|
|
570
570
|
|
|
571
571
|
Raises:
|
|
572
|
-
ValueError: Raises an error if no price data is found for user inputs
|
|
572
|
+
ValueError: Raises an error if no price data is found for user inputs.
|
|
573
573
|
"""
|
|
574
574
|
# Set default column values
|
|
575
575
|
if columns is None:
|
|
@@ -669,8 +669,8 @@ class DetDatabase:
|
|
|
669
669
|
A dictionary containing the requested information
|
|
670
670
|
|
|
671
671
|
Raises:
|
|
672
|
-
ValueError: Raises an error if match with input filter value is not unique
|
|
673
|
-
ValueError: Raises an error if the input filter value is not found
|
|
672
|
+
ValueError: Raises an error if match with input filter value is not unique.
|
|
673
|
+
ValueError: Raises an error if the input filter value is not found.
|
|
674
674
|
"""
|
|
675
675
|
# Get commodity information for user-defined filtering criteria
|
|
676
676
|
condition = f"WHERE {filter_column}='{filter_value}'"
|
|
@@ -1000,7 +1000,7 @@ class DetDatabase:
|
|
|
1000
1000
|
Dataframe containing customer day-ahead auction bids
|
|
1001
1001
|
|
|
1002
1002
|
Raises:
|
|
1003
|
-
ValueError: Raises an error if no data is found for user inputs
|
|
1003
|
+
ValueError: Raises an error if no data is found for user inputs.
|
|
1004
1004
|
"""
|
|
1005
1005
|
# Convert start delivery date from local timezone to UTC and string
|
|
1006
1006
|
start_delivery_date = start_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
|
|
@@ -1104,8 +1104,8 @@ class DetDatabase:
|
|
|
1104
1104
|
A dictionary containing the requested information
|
|
1105
1105
|
|
|
1106
1106
|
Raises:
|
|
1107
|
-
ValueError: Raises an error if match with input filter value is not unique
|
|
1108
|
-
ValueError: Raises an error if the input filter value is not found
|
|
1107
|
+
ValueError: Raises an error if match with input filter value is not unique.
|
|
1108
|
+
ValueError: Raises an error if the input filter value is not found.
|
|
1109
1109
|
"""
|
|
1110
1110
|
# Get client information for user-defined filtering criteria
|
|
1111
1111
|
condition = f"WHERE {filter_column}='{filter_value}'"
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "detquantlib"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.15.0"
|
|
4
4
|
description = "An internal library containing functions and classes that can be used across Quant models."
|
|
5
|
-
authors = ["
|
|
5
|
+
authors = ["Dynamic Energy Trading"]
|
|
6
6
|
readme = "README.md"
|
|
7
|
-
repository = "https://github.com/Dynamic-Energy-Trading/detquantlib"
|
|
8
7
|
packages = [
|
|
9
8
|
{ include = "detquantlib" }, # Specifies the location of the package
|
|
10
9
|
]
|
|
@@ -21,6 +20,7 @@ pandas = "^2.3.3"
|
|
|
21
20
|
pyarrow = "^21.0.0"
|
|
22
21
|
scipy = "^1.15.2"
|
|
23
22
|
colorlog = "^6.10.1"
|
|
23
|
+
redis = "^7.4.0"
|
|
24
24
|
|
|
25
25
|
[tool.poetry.group.dev.dependencies]
|
|
26
26
|
toml = "^0.10.2"
|
|
@@ -30,6 +30,7 @@ pytest-cov = "^7.0.0"
|
|
|
30
30
|
black = "^25.9.0"
|
|
31
31
|
darglint = "^1.8.1"
|
|
32
32
|
isort = "^6.1.0"
|
|
33
|
+
ruff = "^0.15.4"
|
|
33
34
|
colorama = "^0.4.6"
|
|
34
35
|
pymarkdownlnt = "^0.9.32"
|
|
35
36
|
md-toc = "^9.0.0"
|
|
@@ -53,6 +54,10 @@ known_third_party = ["invoke"]
|
|
|
53
54
|
[tool.black]
|
|
54
55
|
line-length = 99
|
|
55
56
|
|
|
57
|
+
[tool.ruff.lint]
|
|
58
|
+
select = ["B", "F"] # "B"=flake8-bugbear, "F"=Pyflakes
|
|
59
|
+
ignore = ["F403", "F405"]
|
|
60
|
+
|
|
56
61
|
[tool.pymarkdown]
|
|
57
62
|
plugins.md013.enabled = false # Disable line length requirements
|
|
58
63
|
plugins.md040.enabled = false # Disable fenced code blocks language requirements
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{detquantlib-3.14.0 → detquantlib-3.15.0}/detquantlib/tradable_products/tradable_products.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|