detquantlib 3.6.0__tar.gz → 3.7.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.6.0 → detquantlib-3.7.0}/PKG-INFO +1 -1
  2. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/data/databases/detdatabase.py +185 -24
  3. {detquantlib-3.6.0 → detquantlib-3.7.0}/pyproject.toml +1 -1
  4. {detquantlib-3.6.0 → detquantlib-3.7.0}/LICENSE.txt +0 -0
  5. {detquantlib-3.6.0 → detquantlib-3.7.0}/README.md +0 -0
  6. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/__init__.py +0 -0
  7. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/data/__init__.py +0 -0
  8. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/data/entsoe/entsoe.py +0 -0
  9. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/data/sftp/sftp.py +0 -0
  10. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/dates/__init__.py +0 -0
  11. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/dates/dates.py +0 -0
  12. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/figures/__init__.py +0 -0
  13. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/figures/plotly_figures.py +0 -0
  14. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/outputs/__init__.py +0 -0
  15. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/outputs/outputs_interface.py +0 -0
  16. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/stats/__init__.py +0 -0
  17. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/stats/data_analysis.py +0 -0
  18. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/tradable_products/__init__.py +0 -0
  19. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/tradable_products/tradable_products.py +0 -0
  20. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/utils/__init__.py +0 -0
  21. {detquantlib-3.6.0 → detquantlib-3.7.0}/detquantlib/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: detquantlib
3
- Version: 3.6.0
3
+ Version: 3.7.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
@@ -402,8 +402,7 @@ class DetDatabase:
402
402
 
403
403
  # Convert end trading date to end delivery date
404
404
  if end_trading_date is not None:
405
- end_trading_date = pd.Timestamp(end_trading_date).floor("D")
406
- end_delivery_date = end_trading_date + relativedelta(days=1)
405
+ end_trading_date = pd.Timestamp(end_trading_date).floor("D") + relativedelta(days=1)
407
406
 
408
407
  # Convert end date to UTC and string
409
408
  end_delivery_date = end_delivery_date.replace(tzinfo=ZoneInfo(timezone))
@@ -666,10 +665,7 @@ class DetDatabase:
666
665
  return commodity_info
667
666
 
668
667
  def load_account_positions(
669
- self,
670
- start_trading_date: datetime,
671
- end_trading_date: datetime,
672
- columns: list = None,
668
+ self, start_trading_date: datetime, end_trading_date: datetime, columns: list = None
673
669
  ) -> pd.DataFrame:
674
670
  """
675
671
  Loads account positions from the database, over a user-defined range of trading dates.
@@ -697,6 +693,7 @@ class DetDatabase:
697
693
  columns_str = f"[{'], ['.join(columns)}]"
698
694
 
699
695
  # Convert dates from datetime to string
696
+ end_trading_date = pd.Timestamp(end_trading_date).floor("D") + relativedelta(days=1)
700
697
  start_trading_date_str = start_trading_date.strftime("%Y-%m-%d")
701
698
  end_trading_date_str = end_trading_date.strftime("%Y-%m-%d")
702
699
 
@@ -704,8 +701,8 @@ class DetDatabase:
704
701
  table = DetDatabaseDefinitions.DEFINITIONS["table_name_account_position"]
705
702
  query = (
706
703
  f"SELECT {columns_str} FROM {table} "
707
- f"WHERE CAST(InsertionTimestamp AS DATE) BETWEEN '{start_trading_date_str}' AND "
708
- f"'{end_trading_date_str}'"
704
+ f"WHERE InsertionTimestamp>='{start_trading_date_str}' "
705
+ f"AND InsertionTimestamp<'{end_trading_date_str}'"
709
706
  )
710
707
 
711
708
  # Query db
@@ -730,11 +727,7 @@ class DetDatabase:
730
727
 
731
728
  return df
732
729
 
733
- def load_instruments(
734
- self,
735
- identifiers: list,
736
- columns: list = None,
737
- ) -> pd.DataFrame:
730
+ def load_instruments(self, identifiers: list, columns: list = None) -> pd.DataFrame:
738
731
  """
739
732
  Loads instrument data based on identifier (of account positions) from the database.
740
733
 
@@ -828,8 +821,8 @@ class DetDatabase:
828
821
  query = (
829
822
  f"SELECT {columns_str} FROM {table} "
830
823
  f"WHERE Product LIKE '{product_code}' "
831
- f"AND CAST(TradingDate AS DATE) BETWEEN '{start_trading_date_str}' AND "
832
- f"'{end_trading_date_str}'"
824
+ f"AND TradingDate>='{start_trading_date_str}' "
825
+ f"AND TradingDate<='{end_trading_date_str}'"
833
826
  )
834
827
 
835
828
  # Query db
@@ -872,7 +865,7 @@ class DetDatabase:
872
865
  columns: list = None,
873
866
  ) -> pd.DataFrame:
874
867
  """
875
- Loads customer volume forecasts from DET database.
868
+ Loads customer volume forecasts from the database.
876
869
 
877
870
  Args:
878
871
  profile: Customer/profile name.
@@ -913,10 +906,8 @@ class DetDatabase:
913
906
  start_delivery_date = start_delivery_date.astimezone(ZoneInfo("UTC"))
914
907
  start_date_str = start_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
915
908
 
916
- # Set delivery end time
917
- end_delivery_date = end_delivery_date.replace(hour=23, minute=59, second=59)
918
-
919
909
  # Convert end delivery date form local timezone to UTC and string
910
+ end_delivery_date = pd.Timestamp(end_delivery_date).floor("D") + relativedelta(days=1)
920
911
  end_delivery_date = end_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
921
912
  end_delivery_date = end_delivery_date.astimezone(ZoneInfo("UTC"))
922
913
  end_date_str = end_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
@@ -932,16 +923,16 @@ class DetDatabase:
932
923
  columns_str = f"[{'], ['.join(columns)}]"
933
924
 
934
925
  # Convert dates from datetime to string
935
- forecast_date = forecast_date.strftime("%Y-%m-%d")
926
+ forecast_date_str = forecast_date.strftime("%Y-%m-%d")
936
927
 
937
928
  # Create query
938
929
  table = DetDatabaseDefinitions.DEFINITIONS["table_name_forecast_customer_volume"]
939
930
  query = (
940
931
  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}'"
932
+ f"WHERE Profile='{profile}' "
933
+ f"AND ForecastDate='{forecast_date_str}' "
934
+ f"AND Datetime>='{start_date_str}' "
935
+ f"AND Datetime<'{end_date_str}'"
945
936
  )
946
937
 
947
938
  # Query db
@@ -990,6 +981,174 @@ class DetDatabase:
990
981
 
991
982
  return df
992
983
 
984
+ def load_customer_day_ahead_auction_bids(
985
+ self,
986
+ client_id: str,
987
+ start_delivery_date: datetime,
988
+ end_delivery_date: datetime,
989
+ local_timezone: str,
990
+ timezone_aware_dates: bool = False,
991
+ columns: list = None,
992
+ ) -> pd.DataFrame:
993
+ """
994
+ Loads customer day-ahead auction bids (volumes and limit prices) from the database.
995
+
996
+ Args:
997
+ client_id: Client ID
998
+ start_delivery_date: First delivery date included
999
+ end_delivery_date: Last delivery date included
1000
+ local_timezone: Local timezone (needed to account for DST switches)
1001
+ timezone_aware_dates: If true, returns all dates as timezone-aware. Otherwise, returns
1002
+ them as timezone-naive
1003
+ columns: Requested database table columns. Set columns=["*"] (i.e. as list) to get all
1004
+ columns
1005
+
1006
+ Returns:
1007
+ Dataframe containing customer day-ahead auction bids
1008
+
1009
+ Raises:
1010
+ ValueError: Raises an error if no data is found for user inputs
1011
+ """
1012
+ # Convert start delivery date from local timezone to UTC and string
1013
+ start_delivery_date = start_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
1014
+ start_delivery_date = start_delivery_date.astimezone(ZoneInfo("UTC"))
1015
+ start_date_str = start_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
1016
+
1017
+ # Convert end delivery date form local timezone to UTC and string
1018
+ end_delivery_date = pd.Timestamp(end_delivery_date).floor("D") + relativedelta(days=1)
1019
+ end_delivery_date = end_delivery_date.replace(tzinfo=ZoneInfo(local_timezone))
1020
+ end_delivery_date = end_delivery_date.astimezone(ZoneInfo("UTC"))
1021
+ end_date_str = end_delivery_date.strftime("%Y-%m-%d %H:%M:%S")
1022
+
1023
+ # Set default column values
1024
+ if columns is None:
1025
+ columns = ["*"]
1026
+
1027
+ # Convert columns from list to string
1028
+ if len(columns) == 1:
1029
+ columns_str = str(columns[0])
1030
+ else:
1031
+ columns_str = f"[{'], ['.join(columns)}]"
1032
+
1033
+ # Create query
1034
+ table = DetDatabaseDefinitions.DEFINITIONS["table_name_customer_day_ahead_auction_bids"]
1035
+ query = (
1036
+ f"SELECT {columns_str} FROM {table} "
1037
+ f"WHERE ClientId='{client_id}' "
1038
+ f"AND DeliveryStart>='{start_date_str}' "
1039
+ f"AND DeliveryStart<'{end_date_str}'"
1040
+ )
1041
+
1042
+ # Query db
1043
+ self.open_connection()
1044
+ df = self.query_db(query)
1045
+ self.close_connection()
1046
+
1047
+ # Assert data
1048
+ if df.empty:
1049
+ raise ValueError("No data found for user-defined inputs.")
1050
+
1051
+ # Sort data
1052
+ sort_cols = ["ClientId", "InsertionTimestamp", "DeliveryStart"]
1053
+ sort_cols = [c for c in sort_cols if c in df.columns]
1054
+ if len(sort_cols) > 0:
1055
+ df.sort_values(
1056
+ by=sort_cols,
1057
+ axis=0,
1058
+ ascending=True,
1059
+ inplace=True,
1060
+ ignore_index=True,
1061
+ )
1062
+
1063
+ # Localize, convert and set timezone-(un)aware datetimes
1064
+ cols_date = ["DeliveryStart", "DeliveryEnd", "InsertionTimestamp"]
1065
+ for c in cols_date:
1066
+ if c in df.columns:
1067
+ # Convert from datetime to pandas timestamp
1068
+ df[c] = pd.DatetimeIndex(df[c])
1069
+
1070
+ # Convert to timezone-aware dates
1071
+ if c == "InsertionTimestamp":
1072
+ df[c] = df[c].dt.tz_localize(local_timezone)
1073
+ else:
1074
+ df[c] = df[c].dt.tz_localize("UTC")
1075
+ df[c] = df[c].dt.tz_convert(local_timezone)
1076
+
1077
+ if not timezone_aware_dates:
1078
+ df[c] = df[c].dt.tz_localize(None)
1079
+
1080
+ return df
1081
+
1082
+ def load_clients(self, columns: list = None, conditions: str = None) -> pd.DataFrame:
1083
+ """
1084
+ General method to load data from the database's client table.
1085
+
1086
+ Args:
1087
+ columns: Requested database table columns. Set columns=["*"] (i.e. as list) to get
1088
+ all columns.
1089
+ conditions: Optional conditions to add to SQL query. E.g. "WHERE Type='Supplier'".
1090
+
1091
+ Returns:
1092
+ Table data
1093
+ """
1094
+ # Set default column values
1095
+ if columns is None:
1096
+ columns = ["*"]
1097
+
1098
+ # Convert columns from list to string
1099
+ if len(columns) == 1:
1100
+ columns_str = str(columns[0])
1101
+ else:
1102
+ columns_str = f"[{'], ['.join(columns)}]"
1103
+
1104
+ # Create query
1105
+ table = DetDatabaseDefinitions.DEFINITIONS["table_name_client"]
1106
+ query = f"SELECT {columns_str} FROM {table} {conditions}"
1107
+
1108
+ # Query db
1109
+ self.open_connection()
1110
+ df = self.query_db(query)
1111
+ self.close_connection()
1112
+
1113
+ return df
1114
+
1115
+ def get_client_info(self, filter_column: str, filter_value: str, info_columns: list) -> dict:
1116
+ """
1117
+ Finds information related to a specific, user-defined client.
1118
+
1119
+ Args:
1120
+ filter_column: Column used to filter data for one specific client
1121
+ filter_value: Value used to filter data for one specific client
1122
+ info_columns: Columns containing the requested information
1123
+
1124
+ Returns:
1125
+ A dictionary containing the requested information
1126
+
1127
+ Raises:
1128
+ ValueError: Raises an error if match with input filter value is not unique
1129
+ ValueError: Raises an error if the input filter value is not found
1130
+ """
1131
+ # Get client information for user-defined filtering criteria
1132
+ condition = f"WHERE {filter_column}='{filter_value}'"
1133
+ client_info = self.load_clients(columns=info_columns, conditions=condition)
1134
+
1135
+ # Validate response
1136
+ if client_info.shape[0] > 1:
1137
+ raise ValueError(f"More than one match found for {filter_column}={filter_value}.")
1138
+
1139
+ elif client_info.shape[0] == 0:
1140
+ available_values = self.load_clients(columns=[filter_column])
1141
+ available_values_str = ", ".join(f"'{x}'" for x in available_values[filter_column])
1142
+ raise ValueError(
1143
+ f"Value {filter_value} not found in column '{filter_column}'. Available values: "
1144
+ f"{available_values_str}."
1145
+ )
1146
+
1147
+ # Convert dataframe row to dict
1148
+ client_info = client_info.loc[0, :].to_dict()
1149
+
1150
+ return client_info
1151
+
993
1152
 
994
1153
  class DetDatabaseDefinitions:
995
1154
  """A class containing some hard-coded definitions related to the DET database."""
@@ -1003,4 +1162,6 @@ class DetDatabaseDefinitions:
1003
1162
  table_name_instruments="[TT].[Instrument]",
1004
1163
  table_name_eex_eod_price="[EEX].[EODPrice]",
1005
1164
  table_name_forecast_customer_volume="[DISP].[ForecastGold]",
1165
+ table_name_customer_day_ahead_auction_bids="[TRADE].[ClientBid]",
1166
+ table_name_client="[META].[Client]",
1006
1167
  )
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "detquantlib"
3
- version = "3.6.0"
3
+ version = "3.7.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