detquantlib 5.1.0__tar.gz → 5.1.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.
- {detquantlib-5.1.0 → detquantlib-5.1.2}/PKG-INFO +1 -1
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/data/databases/detdatabase.py +47 -26
- {detquantlib-5.1.0 → detquantlib-5.1.2}/pyproject.toml +1 -1
- {detquantlib-5.1.0 → detquantlib-5.1.2}/LICENSE.txt +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/README.md +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/assets/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/assets/battery.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/assets/wind_turbine.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/converters/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/converters/definitions.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/converters/energy.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/converters/helpers.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/converters/price.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/data/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/data/databases/helpers.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/data/entsoe/entsoe.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/data/sftp/sftp.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/dates/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/dates/dates.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/figures/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/figures/plotly_figures.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/forecasting/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/forecasting/forecasting.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/outputs/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/outputs/outputs_interface.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/stats/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/stats/data_analysis.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/tradable_products/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/tradable_products/tradable_products.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/utils/__init__.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/utils/logging.py +0 -0
- {detquantlib-5.1.0 → detquantlib-5.1.2}/detquantlib/utils/utils.py +0 -0
|
@@ -35,26 +35,32 @@ class DetDatabase:
|
|
|
35
35
|
initialized.
|
|
36
36
|
driver: ODBC driver
|
|
37
37
|
"""
|
|
38
|
-
# Store database name if it is provided
|
|
39
|
-
if db_name:
|
|
40
|
-
os.environ["DET_DB_NAME"] = db_name
|
|
41
|
-
|
|
42
38
|
# Only allow object creation if mandatory environment variables exist
|
|
43
|
-
|
|
39
|
+
skip_db_name = db_name is not None
|
|
40
|
+
DetDatabase.check_environment_variables(skip_db_name)
|
|
44
41
|
|
|
42
|
+
self.db_name = db_name if db_name else os.environ["DET_DB_NAME"]
|
|
45
43
|
self.driver = driver
|
|
46
44
|
self.engine = engine if engine is not None else self.initialize_engine()
|
|
47
45
|
|
|
48
46
|
@staticmethod
|
|
49
|
-
def check_environment_variables():
|
|
47
|
+
def check_environment_variables(skip_db_name: bool):
|
|
50
48
|
"""
|
|
51
49
|
Checks if environment variables needed by the class are defined.
|
|
52
50
|
|
|
51
|
+
Args:
|
|
52
|
+
skip_db_name: If true, does not check if the environment variable containing the
|
|
53
|
+
database name is defined
|
|
54
|
+
|
|
53
55
|
Raises:
|
|
54
56
|
ConnectionError: Raises an error if environment variables are not defined.
|
|
55
57
|
"""
|
|
56
|
-
required_env_vars =
|
|
57
|
-
|
|
58
|
+
required_env_vars = (
|
|
59
|
+
[]
|
|
60
|
+
if skip_db_name
|
|
61
|
+
else [dict(name="DET_DB_NAME", value=None, description="Database name")]
|
|
62
|
+
)
|
|
63
|
+
required_env_vars += [
|
|
58
64
|
dict(name="DET_DB_SERVER", value=None, description="Server name"),
|
|
59
65
|
dict(name="DET_DB_USERNAME", value=None, description="Username"),
|
|
60
66
|
dict(name="DET_DB_PASSWORD", value=None, description="Password"),
|
|
@@ -81,7 +87,7 @@ class DetDatabase:
|
|
|
81
87
|
connection_str = (
|
|
82
88
|
f"DRIVER={self.driver};"
|
|
83
89
|
f"SERVER={os.getenv('DET_DB_SERVER')};"
|
|
84
|
-
f"DATABASE={
|
|
90
|
+
f"DATABASE={self.db_name};"
|
|
85
91
|
f"UID={os.getenv('DET_DB_USERNAME')};"
|
|
86
92
|
f"PWD={quote_plus(os.getenv('DET_DB_PASSWORD'))}"
|
|
87
93
|
)
|
|
@@ -872,15 +878,20 @@ class DetDatabase:
|
|
|
872
878
|
Args:
|
|
873
879
|
profile: Customer/profile name.
|
|
874
880
|
Note on the 'Portfolio' and 'Portfolioweekend' profiles:
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
881
|
+
- [Legacy data until March 2026]:
|
|
882
|
+
- Profile names 'Portfolio' and 'Portfolioweekend' refer to the same set
|
|
883
|
+
of connection points.
|
|
884
|
+
- In the database, the profile name is set to 'Portfolio' when the
|
|
885
|
+
forecast date is between Monday and Friday.
|
|
886
|
+
- In the database, the profile name is set to 'Portfolioweekend' when
|
|
887
|
+
the forecast date is Saturday or Sunday.
|
|
888
|
+
- [Data since March 2026]:
|
|
889
|
+
- The 'Portfolioweekend' name is deprecated. Day-ahead forecasts are
|
|
890
|
+
now stored under the 'Portfolio' profile only.
|
|
891
|
+
- When calling this method, set the input argument 'profile' to
|
|
892
|
+
'PortfolioAll' to automatically switch between 'Portfolio' and
|
|
893
|
+
'Portfolioweekend', based on the used-input forecast date.
|
|
894
|
+
'PortfolioAll' supports both the legacy and new data structure.
|
|
884
895
|
forecast_date: Date on which customer volume forecast is generated.
|
|
885
896
|
start_delivery_date: First delivery date included.
|
|
886
897
|
end_delivery_date: Last delivery date included.
|
|
@@ -896,13 +907,6 @@ class DetDatabase:
|
|
|
896
907
|
Raises:
|
|
897
908
|
ValueError: Raises an error if no volume forecast data is found for user inputs.
|
|
898
909
|
"""
|
|
899
|
-
# Convert profile if set to "PortfolioAll"
|
|
900
|
-
if profile == "PortfolioAll":
|
|
901
|
-
if forecast_date.weekday() > 4:
|
|
902
|
-
profile = "Portfolioweekend"
|
|
903
|
-
else:
|
|
904
|
-
profile = "Portfolio"
|
|
905
|
-
|
|
906
910
|
# Convert start delivery date from local timezone to UTC and string
|
|
907
911
|
start_delivery_date = start_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
|
|
908
912
|
start_delivery_date = start_delivery_date.astimezone(ZoneInfo("UTC"))
|
|
@@ -924,17 +928,34 @@ class DetDatabase:
|
|
|
924
928
|
# Convert dates from datetime to string
|
|
925
929
|
forecast_date_str = forecast_date.strftime("%Y-%m-%d")
|
|
926
930
|
|
|
931
|
+
# Define query profile name. If 'PortfolioAll', first try with 'Portfolio' (compatibility
|
|
932
|
+
# with new data).
|
|
933
|
+
query_profile = "Portfolio" if profile == "PortfolioAll" else profile
|
|
934
|
+
|
|
927
935
|
# Query db
|
|
928
936
|
table = DetDatabase.get_table_name("client_volume_forecast")
|
|
929
937
|
query = (
|
|
930
938
|
f"SELECT {columns_str} FROM {table} "
|
|
931
|
-
f"WHERE Profile='{
|
|
939
|
+
f"WHERE Profile='{query_profile}' "
|
|
932
940
|
f"AND ForecastDate='{forecast_date_str}' "
|
|
933
941
|
f"AND Datetime>='{start_date_str}' "
|
|
934
942
|
f"AND Datetime<'{end_date_str}'"
|
|
935
943
|
)
|
|
936
944
|
df = self.query_db(query)
|
|
937
945
|
|
|
946
|
+
if profile == "PortfolioAll" and df.empty and forecast_date.weekday() > 4:
|
|
947
|
+
# If 'Portfolio' not found, try with 'Portfolioweekend' (backward compatibility with
|
|
948
|
+
# legacy data)
|
|
949
|
+
query_profile = "Portfolioweekend"
|
|
950
|
+
query = (
|
|
951
|
+
f"SELECT {columns_str} FROM {table} "
|
|
952
|
+
f"WHERE Profile='{query_profile}' "
|
|
953
|
+
f"AND ForecastDate='{forecast_date_str}' "
|
|
954
|
+
f"AND Datetime>='{start_date_str}' "
|
|
955
|
+
f"AND Datetime<'{end_date_str}'"
|
|
956
|
+
)
|
|
957
|
+
df = self.query_db(query)
|
|
958
|
+
|
|
938
959
|
# Assert data
|
|
939
960
|
if df.empty:
|
|
940
961
|
raise ValueError("No volume forecast data found for user-defined inputs.")
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|