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.
Files changed (21) hide show
  1. {detquantlib-3.5.0 → detquantlib-3.6.0}/PKG-INFO +1 -1
  2. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/databases/detdatabase.py +150 -24
  3. {detquantlib-3.5.0 → detquantlib-3.6.0}/pyproject.toml +1 -1
  4. {detquantlib-3.5.0 → detquantlib-3.6.0}/LICENSE.txt +0 -0
  5. {detquantlib-3.5.0 → detquantlib-3.6.0}/README.md +0 -0
  6. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/__init__.py +0 -0
  7. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/__init__.py +0 -0
  8. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/entsoe/entsoe.py +0 -0
  9. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/data/sftp/sftp.py +0 -0
  10. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/dates/__init__.py +0 -0
  11. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/dates/dates.py +0 -0
  12. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/figures/__init__.py +0 -0
  13. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/figures/plotly_figures.py +0 -0
  14. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/outputs/__init__.py +0 -0
  15. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/outputs/outputs_interface.py +0 -0
  16. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/stats/__init__.py +0 -0
  17. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/stats/data_analysis.py +0 -0
  18. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/tradable_products/__init__.py +0 -0
  19. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/tradable_products/tradable_products.py +0 -0
  20. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/utils/__init__.py +0 -0
  21. {detquantlib-3.5.0 → detquantlib-3.6.0}/detquantlib/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: detquantlib
3
- Version: 3.5.0
3
+ Version: 3.6.0
4
4
  Summary: An internal library containing functions and classes that can be used across Quant models.
5
5
  Author: DET
6
6
  Requires-Python: >=3.10,<4.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 + ["InsertionTimestamp", f"DateTime({timezone})"]
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 + ["InsertionTimestamp", f"DateTime({timezone})"]
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
- cols_datetime = ["TradingDate", "DeliveryStart", "DeliveryEnd", "InsertionTimestamp"]
593
- for c in cols_datetime:
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 ([InsertionTimestamp] AS DATE) BETWEEN '{start_trading_date_str}' AND "
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.sort_values(
725
- by=["InsertionTimestamp"],
726
- axis=0,
727
- ascending=True,
728
- inplace=True,
729
- ignore_index=True,
730
- )
731
-
732
- # Convert dates from datetime.date to pd.Timestamp
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 [Product] LIKE '{product_code}' "
835
- f"AND CAST ([TradingDate] AS DATE) BETWEEN '{start_trading_date_str}' AND "
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
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "detquantlib"
3
- version = "3.5.0"
3
+ version = "3.6.0"
4
4
  description = "An internal library containing functions and classes that can be used across Quant models."
5
5
  authors = ["DET"]
6
6
  readme = "README.md"
File without changes
File without changes