detquantlib 3.5.0__tar.gz → 3.6.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.5.0 → detquantlib-3.6.0}/PKG-INFO +1 -1
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/databases/detdatabase.py +150 -24
- {detquantlib-3.5.0 → detquantlib-3.6.0}/pyproject.toml +1 -1
- {detquantlib-3.5.0 → detquantlib-3.6.0}/LICENSE.txt +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/README.md +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/entsoe/entsoe.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/sftp/sftp.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/dates/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/dates/dates.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/figures/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/figures/plotly_figures.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/outputs/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/outputs/outputs_interface.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/stats/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/stats/data_analysis.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/tradable_products/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/tradable_products/tradable_products.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/utils/__init__.py +0 -0
- {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/utils/utils.py +0 -0
|
@@ -233,18 +233,16 @@ class DetDatabase:
|
|
|
233
233
|
)
|
|
234
234
|
|
|
235
235
|
# Convert date columns to timezone-aware dates
|
|
236
|
-
cols_date_utc = ["DateTime(UTC)", "UpdateTime(UTC)"]
|
|
236
|
+
cols_date_utc = ["DateTime(UTC)", "UpdateTime(UTC)", "InsertionTimestamp"]
|
|
237
237
|
for c in cols_date_utc:
|
|
238
238
|
if c in df.columns:
|
|
239
239
|
df[c] = df[c].dt.tz_localize("UTC")
|
|
240
|
-
if "InsertionTimestamp" in df.columns:
|
|
241
|
-
df["InsertionTimestamp"] = df["InsertionTimestamp"].dt.tz_localize(timezone)
|
|
242
240
|
|
|
243
241
|
# Add column with delivery date expressed in local timezone
|
|
244
242
|
df[f"DateTime({timezone})"] = df["DateTime(UTC)"].dt.tz_convert(timezone)
|
|
245
243
|
|
|
246
244
|
if not timezone_aware_dates:
|
|
247
|
-
cols_date_all = cols_date_utc + [
|
|
245
|
+
cols_date_all = cols_date_utc + [f"DateTime({timezone})"]
|
|
248
246
|
for c in cols_date_all:
|
|
249
247
|
if c in df.columns:
|
|
250
248
|
df[c] = df[c].dt.tz_localize(None)
|
|
@@ -435,18 +433,16 @@ class DetDatabase:
|
|
|
435
433
|
)
|
|
436
434
|
|
|
437
435
|
# Convert date columns to timezone-aware dates
|
|
438
|
-
cols_date_utc = ["DateTime(UTC)", "UpdateTime(UTC)"]
|
|
436
|
+
cols_date_utc = ["DateTime(UTC)", "UpdateTime(UTC)", "InsertionTimestamp"]
|
|
439
437
|
for c in cols_date_utc:
|
|
440
438
|
if c in df.columns:
|
|
441
439
|
df[c] = df[c].dt.tz_localize("UTC")
|
|
442
|
-
if "InsertionTimestamp" in df.columns:
|
|
443
|
-
df["InsertionTimestamp"] = df["InsertionTimestamp"].dt.tz_localize(timezone)
|
|
444
440
|
|
|
445
441
|
# Add column with delivery date expressed in local timezone
|
|
446
442
|
df[f"DateTime({timezone})"] = df["DateTime(UTC)"].dt.tz_convert(timezone)
|
|
447
443
|
|
|
448
444
|
if not timezone_aware_dates:
|
|
449
|
-
cols_date_all = cols_date_utc + [
|
|
445
|
+
cols_date_all = cols_date_utc + [f"DateTime({timezone})"]
|
|
450
446
|
for c in cols_date_all:
|
|
451
447
|
if c in df.columns:
|
|
452
448
|
df[c] = df[c].dt.tz_localize(None)
|
|
@@ -589,8 +585,9 @@ class DetDatabase:
|
|
|
589
585
|
timezone = commodity_info["Timezone"]
|
|
590
586
|
|
|
591
587
|
# Convert timezone-naive to timezone-aware dates
|
|
592
|
-
|
|
593
|
-
|
|
588
|
+
df["InsertionTimestamp"] = df["InsertionTimestamp"].dt.tz_localize("UTC")
|
|
589
|
+
cols_local_tz = ["TradingDate", "DeliveryStart", "DeliveryEnd"]
|
|
590
|
+
for c in cols_local_tz:
|
|
594
591
|
if c in df.columns:
|
|
595
592
|
df[c] = df[c].dt.tz_localize(timezone)
|
|
596
593
|
|
|
@@ -707,7 +704,7 @@ class DetDatabase:
|
|
|
707
704
|
table = DetDatabaseDefinitions.DEFINITIONS["table_name_account_position"]
|
|
708
705
|
query = (
|
|
709
706
|
f"SELECT {columns_str} FROM {table} "
|
|
710
|
-
f"WHERE CAST
|
|
707
|
+
f"WHERE CAST(InsertionTimestamp AS DATE) BETWEEN '{start_trading_date_str}' AND "
|
|
711
708
|
f"'{end_trading_date_str}'"
|
|
712
709
|
)
|
|
713
710
|
|
|
@@ -720,17 +717,16 @@ class DetDatabase:
|
|
|
720
717
|
if df.empty:
|
|
721
718
|
raise ValueError("No account position data found for user-defined inputs.")
|
|
722
719
|
|
|
723
|
-
# Sort data
|
|
724
|
-
df.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
df["InsertionTimestamp"] = pd.DatetimeIndex(df["InsertionTimestamp"])
|
|
720
|
+
# Sort data and convert dates from datetime.date to pd.Timestamp
|
|
721
|
+
if "InsertionTimestamp" in df.columns:
|
|
722
|
+
df.sort_values(
|
|
723
|
+
by=["InsertionTimestamp"],
|
|
724
|
+
axis=0,
|
|
725
|
+
ascending=True,
|
|
726
|
+
inplace=True,
|
|
727
|
+
ignore_index=True,
|
|
728
|
+
)
|
|
729
|
+
df["InsertionTimestamp"] = pd.DatetimeIndex(df["InsertionTimestamp"])
|
|
734
730
|
|
|
735
731
|
return df
|
|
736
732
|
|
|
@@ -831,8 +827,8 @@ class DetDatabase:
|
|
|
831
827
|
table = DetDatabaseDefinitions.DEFINITIONS["table_name_eex_eod_price"]
|
|
832
828
|
query = (
|
|
833
829
|
f"SELECT {columns_str} FROM {table} "
|
|
834
|
-
f"WHERE
|
|
835
|
-
f"AND CAST
|
|
830
|
+
f"WHERE Product LIKE '{product_code}' "
|
|
831
|
+
f"AND CAST(TradingDate AS DATE) BETWEEN '{start_trading_date_str}' AND "
|
|
836
832
|
f"'{end_trading_date_str}'"
|
|
837
833
|
)
|
|
838
834
|
|
|
@@ -865,6 +861,135 @@ class DetDatabase:
|
|
|
865
861
|
|
|
866
862
|
return df
|
|
867
863
|
|
|
864
|
+
def load_forecast_customer_volume(
|
|
865
|
+
self,
|
|
866
|
+
profile: str,
|
|
867
|
+
forecast_date: datetime,
|
|
868
|
+
start_delivery_date: datetime,
|
|
869
|
+
end_delivery_date: datetime,
|
|
870
|
+
local_timezone: str,
|
|
871
|
+
timezone_aware_dates: bool = False,
|
|
872
|
+
columns: list = None,
|
|
873
|
+
) -> pd.DataFrame:
|
|
874
|
+
"""
|
|
875
|
+
Loads customer volume forecasts from DET database.
|
|
876
|
+
|
|
877
|
+
Args:
|
|
878
|
+
profile: Customer/profile name.
|
|
879
|
+
Note on the 'Portfolio' and 'Portfolioweekend' profiles:
|
|
880
|
+
- Profile names 'Portfolio' and 'Portfolioweekend' refer to the same set of
|
|
881
|
+
connection points.
|
|
882
|
+
- In the database, the profile name is set to 'Portfolio' when the forecast date
|
|
883
|
+
is between Monday and Friday.
|
|
884
|
+
- In the database, the profile name is set to 'Portfolioweekend' when the forecast
|
|
885
|
+
date is Saturday or Sunday.
|
|
886
|
+
- When calling this method, the input argument 'profile' can be set to
|
|
887
|
+
'PortfolioAll' to automatically let the method switch between 'Portfolio' and
|
|
888
|
+
'Portfolioweekend', based on the used-input forecast date.
|
|
889
|
+
forecast_date: Date on which customer volume forecast is generated.
|
|
890
|
+
start_delivery_date: First delivery date included.
|
|
891
|
+
end_delivery_date: Last delivery date included.
|
|
892
|
+
local_timezone: Local timezone (needed to account for DST switches).
|
|
893
|
+
timezone_aware_dates: If true, returns all dates as timezone-aware. Otherwise, returns
|
|
894
|
+
them as timezone-naive.
|
|
895
|
+
columns: Requested database table columns. Set columns=["*"] (i.e. as list) to get all
|
|
896
|
+
columns.
|
|
897
|
+
|
|
898
|
+
Returns:
|
|
899
|
+
Dataframe containing customer volume forecasts.
|
|
900
|
+
|
|
901
|
+
Raises:
|
|
902
|
+
ValueError: Raises an error if no volume forecast data is found for user inputs.
|
|
903
|
+
"""
|
|
904
|
+
# Convert profile if set to "PortfolioAll"
|
|
905
|
+
if profile == "PortfolioAll":
|
|
906
|
+
if forecast_date.weekday() > 4:
|
|
907
|
+
profile = "Portfolioweekend"
|
|
908
|
+
else:
|
|
909
|
+
profile = "Portfolio"
|
|
910
|
+
|
|
911
|
+
# Convert start delivery date from local timezone to UTC and string
|
|
912
|
+
start_delivery_date = start_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
|
|
913
|
+
start_delivery_date = start_delivery_date.astimezone(ZoneInfo("UTC"))
|
|
914
|
+
start_date_str = start_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
|
|
915
|
+
|
|
916
|
+
# Set delivery end time
|
|
917
|
+
end_delivery_date = end_delivery_date.replace(hour=23, minute=59, second=59)
|
|
918
|
+
|
|
919
|
+
# Convert end delivery date form local timezone to UTC and string
|
|
920
|
+
end_delivery_date = end_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
|
|
921
|
+
end_delivery_date = end_delivery_date.astimezone(ZoneInfo("UTC"))
|
|
922
|
+
end_date_str = end_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
|
|
923
|
+
|
|
924
|
+
# Set default column values
|
|
925
|
+
if columns is None:
|
|
926
|
+
columns = ["*"]
|
|
927
|
+
|
|
928
|
+
# Convert columns from list to string
|
|
929
|
+
if len(columns) == 1:
|
|
930
|
+
columns_str = str(columns[0])
|
|
931
|
+
else:
|
|
932
|
+
columns_str = f"[{'], ['.join(columns)}]"
|
|
933
|
+
|
|
934
|
+
# Convert dates from datetime to string
|
|
935
|
+
forecast_date = forecast_date.strftime("%Y-%m-%d")
|
|
936
|
+
|
|
937
|
+
# Create query
|
|
938
|
+
table = DetDatabaseDefinitions.DEFINITIONS["table_name_forecast_customer_volume"]
|
|
939
|
+
query = (
|
|
940
|
+
f"SELECT {columns_str} FROM {table} "
|
|
941
|
+
f"WHERE Profile = '{profile}'"
|
|
942
|
+
f"AND ForecastDate = '{forecast_date}'"
|
|
943
|
+
f"AND CAST(Datetime AS DATETIME) BETWEEN '{start_date_str}' AND "
|
|
944
|
+
f"'{end_date_str}'"
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
# Query db
|
|
948
|
+
self.open_connection()
|
|
949
|
+
df = self.query_db(query)
|
|
950
|
+
self.close_connection()
|
|
951
|
+
|
|
952
|
+
# Assert data
|
|
953
|
+
if df.empty:
|
|
954
|
+
raise ValueError("No volume forecast data found for user-defined inputs.")
|
|
955
|
+
|
|
956
|
+
# Sort data
|
|
957
|
+
sort_cols = ["Profile", "ForecastDate", "Datetime"]
|
|
958
|
+
sort_cols = [c for c in sort_cols if c in df.columns]
|
|
959
|
+
if len(sort_cols) > 0:
|
|
960
|
+
df.sort_values(
|
|
961
|
+
by=sort_cols,
|
|
962
|
+
axis=0,
|
|
963
|
+
ascending=True,
|
|
964
|
+
inplace=True,
|
|
965
|
+
ignore_index=True,
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
# Localize, convert and set timezone-(un)aware datetimes
|
|
969
|
+
cols_date = ["ForecastDate", "Datetime", "InsertionTimestamp"]
|
|
970
|
+
for c in cols_date:
|
|
971
|
+
if c in df.columns:
|
|
972
|
+
# Convert from datetime to pandas timestamp
|
|
973
|
+
df[c] = pd.DatetimeIndex(df[c])
|
|
974
|
+
|
|
975
|
+
# Convert to timezone-aware dates
|
|
976
|
+
if c == "ForecastDate":
|
|
977
|
+
df[c] = df[c].dt.tz_localize(local_timezone)
|
|
978
|
+
else:
|
|
979
|
+
df[c] = df[c].dt.tz_localize("UTC")
|
|
980
|
+
df[c] = df[c].dt.tz_convert(local_timezone)
|
|
981
|
+
|
|
982
|
+
if not timezone_aware_dates:
|
|
983
|
+
df[c] = df[c].dt.tz_localize(None)
|
|
984
|
+
|
|
985
|
+
# Rescale column values
|
|
986
|
+
df["kWh"] = df["kWh"] / 1000
|
|
987
|
+
|
|
988
|
+
# Rename columns
|
|
989
|
+
df = df.rename(columns={"kWh": "Volume(MWh)", "Datetime": "DeliveryStart"})
|
|
990
|
+
|
|
991
|
+
return df
|
|
992
|
+
|
|
868
993
|
|
|
869
994
|
class DetDatabaseDefinitions:
|
|
870
995
|
"""A class containing some hard-coded definitions related to the DET database."""
|
|
@@ -877,4 +1002,5 @@ class DetDatabaseDefinitions:
|
|
|
877
1002
|
table_name_account_position="[TT].[AccountPosition]",
|
|
878
1003
|
table_name_instruments="[TT].[Instrument]",
|
|
879
1004
|
table_name_eex_eod_price="[EEX].[EODPrice]",
|
|
1005
|
+
table_name_forecast_customer_volume="[DISP].[ForecastGold]",
|
|
880
1006
|
)
|
|
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
|