eptr2 1.2.0.dev0__tar.gz → 1.2.1.dev0__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 (55) hide show
  1. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/.gitignore +1 -1
  2. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/PKG-INFO +22 -3
  3. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/README.md +21 -2
  4. eptr2-1.2.1.dev0/creds/eptr_credentials.json +9 -0
  5. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/__init__.py +1 -0
  6. eptr2-1.2.1.dev0/eptr2/composite/plant_costs.py +142 -0
  7. eptr2-1.2.1.dev0/eptr2/composite/production.py +376 -0
  8. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/help.py +12 -0
  9. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/parameters.py +1 -0
  10. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/path.py +7 -0
  11. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/processing.py +1 -0
  12. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/pages/1_/360/237/221/251/342/200/215/360/237/222/273_Demo.py +4 -4
  13. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/pages/2_/360/237/224/256_Pozisyonlar.py +1 -1
  14. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/pages/3_/342/232/241/357/270/217_/303/234retim_Planlama.py +1 -3
  15. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/pages/4_/360/237/222/260_Fiyat_ve_Maliyetler.py +1 -3
  16. eptr2-1.2.1.dev0/eptr2/tutorials/composite/pages/5_/360/237/222/270_Santral_Dengesizlik.py +514 -0
  17. eptr2-1.2.1.dev0/eptr2/tutorials/composite/pages/6_/360/237/221/250/342/200/215/360/237/222/273_Yeni_Dengesizlik_Hesab/304/261.py +69 -0
  18. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite//342/255/220/357/270/217_Ana_Sayfa.py +22 -0
  19. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/demo.py +4 -4
  20. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/costs.py +92 -1
  21. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/time.py +24 -4
  22. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/pyproject.toml +4 -2
  23. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/uv.lock +1 -1
  24. eptr2-1.2.0.dev0/eptr2/composite/production.py +0 -236
  25. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/LICENSE +0 -0
  26. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/__init__.py +0 -0
  27. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/bpm.py +0 -0
  28. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/consumption.py +0 -0
  29. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/dabi_idm.py +0 -0
  30. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/idm_log.py +0 -0
  31. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/mms.py +0 -0
  32. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/price_and_cost.py +0 -0
  33. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/main.py +0 -0
  34. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/__init__.py +0 -0
  35. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/checks.py +0 -0
  36. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/__init__.py +0 -0
  37. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/postprocess/__init__.py +0 -0
  38. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/postprocess/items.py +0 -0
  39. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/__init__.py +0 -0
  40. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/calls.py +0 -0
  41. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/params.py +0 -0
  42. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/__init__.py +0 -0
  43. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/calc.py +0 -0
  44. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/__init__.py +0 -0
  45. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/common.py +0 -0
  46. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/main.py +0 -0
  47. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/__init__.py +0 -0
  48. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/certificate.py +0 -0
  49. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/evaluation.py +0 -0
  50. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/__init__.py +0 -0
  51. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/__init__.py +0 -0
  52. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_consumption.py +0 -0
  53. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_mms.py +0 -0
  54. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_price_and_cost.py +0 -0
  55. {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_production.py +0 -0
@@ -164,4 +164,4 @@ data/
164
164
  runs/
165
165
  .vscode/
166
166
  helpdocs/
167
- creds/
167
+ creds/.env
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eptr2
3
- Version: 1.2.0.dev0
3
+ Version: 1.2.1.dev0
4
4
  Summary: EPIAS Transparency Platform v2.0 Python client by Robokami Data
5
5
  Author-email: Tideseed <info@tideseed.com>
6
6
  License: Apache License 2.0
@@ -253,10 +253,8 @@ df = get_day_ahead_and_bilateral_matches(eptr=eptr,start_date="2023-01-01", end_
253
253
  df2 = get_day_ahead_detail_info(
254
254
  eptr=eptr, start_date="2023-01-01", end_date="2023-01-31", verbose=True
255
255
  )
256
-
257
256
  ```
258
257
 
259
-
260
258
  #### Balancing Power Market Data
261
259
 
262
260
  ```python
@@ -276,3 +274,24 @@ df2 = get_bpm_period(
276
274
  )
277
275
  ```
278
276
 
277
+ #### Plant Costs
278
+
279
+ ```python
280
+ from eptr2 import EPTR2
281
+ from eptr2.composite import gather_and_calculate_plant_costs
282
+
283
+ eptr = EPTR2(credentials_file_path="creds/eptr_credentials.json")
284
+
285
+ df = gather_and_calculate_plant_costs(
286
+ eptr=eptr,
287
+ start_date="2023-01-01",
288
+ end_date="2023-01-31",
289
+ pp_id=120, ## BOZCAADA RES
290
+ org_id=195, ## EÜAŞ
291
+ uevcb_id=3204384, ## BOZCAADA RES
292
+ plant_type="wind",
293
+ verbose=True,
294
+ forecast_source = "kgup",
295
+ actual_source = "uevm"
296
+ )
297
+ ```
@@ -231,10 +231,8 @@ df = get_day_ahead_and_bilateral_matches(eptr=eptr,start_date="2023-01-01", end_
231
231
  df2 = get_day_ahead_detail_info(
232
232
  eptr=eptr, start_date="2023-01-01", end_date="2023-01-31", verbose=True
233
233
  )
234
-
235
234
  ```
236
235
 
237
-
238
236
  #### Balancing Power Market Data
239
237
 
240
238
  ```python
@@ -254,3 +252,24 @@ df2 = get_bpm_period(
254
252
  )
255
253
  ```
256
254
 
255
+ #### Plant Costs
256
+
257
+ ```python
258
+ from eptr2 import EPTR2
259
+ from eptr2.composite import gather_and_calculate_plant_costs
260
+
261
+ eptr = EPTR2(credentials_file_path="creds/eptr_credentials.json")
262
+
263
+ df = gather_and_calculate_plant_costs(
264
+ eptr=eptr,
265
+ start_date="2023-01-01",
266
+ end_date="2023-01-31",
267
+ pp_id=120, ## BOZCAADA RES
268
+ org_id=195, ## EÜAŞ
269
+ uevcb_id=3204384, ## BOZCAADA RES
270
+ plant_type="wind",
271
+ verbose=True,
272
+ forecast_source = "kgup",
273
+ actual_source = "uevm"
274
+ )
275
+ ```
@@ -0,0 +1,9 @@
1
+ {
2
+ "EPTR_USERNAME": "berk.orbay@tideseed.com",
3
+ "EPTR_PASSWORD": "TDSD!S3ffaf2",
4
+ "tgt_d": {
5
+ "tgt": "TGT-2550194--Z6WQIsu7keXmLbbKdIspChHBqJprLfR-dcCthsnUJGBaVO-p-XM3E0W1eNiPfjYdyM-cas-7dc76c888-gmdxk",
6
+ "tgt_exp": 1753043389.532092,
7
+ "tgt_exp_0": 1753043389.532092
8
+ }
9
+ }
@@ -5,3 +5,4 @@ from eptr2.composite.dabi_idm import *
5
5
  from eptr2.composite.bpm import *
6
6
  from eptr2.composite.idm_log import *
7
7
  from eptr2.composite.mms import *
8
+ from eptr2.composite.plant_costs import *
@@ -0,0 +1,142 @@
1
+ from eptr2 import EPTR2
2
+ import pandas as pd
3
+ from eptr2.composite.production import wrapper_hourly_production_plan_and_realized
4
+ from eptr2.composite.price_and_cost import get_hourly_price_and_cost_data
5
+ from eptr2.util.costs import calculate_kupsm, get_kupst_tolerance
6
+ from typing import Literal
7
+
8
+
9
+ def postprocess_plant_cost_df(df: pd.DataFrame):
10
+ df["cumulative_kupst_cost"] = df["total_kupst_cost"].cumsum()
11
+ df["cumulative_imb_cost"] = df["total_imb_cost"].cumsum()
12
+ df["cumulative_total_cost"] = df["total_cost"].cumsum()
13
+
14
+ d = {
15
+ "total_forecast": df["forecast"].sum(),
16
+ "total_actual": df["actual"].sum(),
17
+ "total_kupsm": df["kupsm"].sum(),
18
+ "total_bias": df["diff"].sum(),
19
+ "total_mae": df["diff"].abs().sum(),
20
+ "total_kupst_cost": df["total_kupst_cost"].sum(),
21
+ "total_imb_cost": df["total_imb_cost"].sum(),
22
+ "total_cost": df["total_cost"].sum(),
23
+ }
24
+
25
+ return {"summary": d, "data": df}
26
+
27
+
28
+ def gather_and_calculate_plant_costs(
29
+ eptr: EPTR2,
30
+ start_date: str,
31
+ end_date: str,
32
+ pp_id: int | str,
33
+ org_id: int | str,
34
+ uevcb_id: int | str,
35
+ plant_type: str,
36
+ forecast_source: Literal["kgup_v1", "kgup", "kudup"] = "kudup",
37
+ actual_source: Literal["rt", "uevm"] = "uevm",
38
+ verbose=False,
39
+ timeout=5,
40
+ postprocess: bool = False,
41
+ **kwargs,
42
+ ):
43
+ """
44
+ For a given power plant and selected forecast and actual production sources, this function gathers data and calculates imbalance and kupst costs.
45
+
46
+ Example usage:
47
+ pp_id=120, ## BOZCAADA RES
48
+ org_id=195, ## EÜAŞ
49
+ uevcb_id=3204384, ## BOZCAADA RES
50
+ plant_type="wind",
51
+ """
52
+
53
+ ### Regulate skips
54
+ params = dict(
55
+ skip_kgup=True,
56
+ skip_kgup_v1=True,
57
+ skip_kudup=True,
58
+ skip_uevm=True,
59
+ skip_rt=True,
60
+ )
61
+
62
+ params[f"skip_{forecast_source}"] = False
63
+ params[f"skip_{actual_source}"] = False
64
+
65
+ ### Regulate ids
66
+ if actual_source == "rt":
67
+ params["rt_pp_id"] = pp_id
68
+ params["uevm_pp_id"] = None
69
+ else:
70
+ params["rt_pp_id"] = None
71
+ params["uevm_pp_id"] = pp_id
72
+
73
+ df = wrapper_hourly_production_plan_and_realized(
74
+ eptr=eptr,
75
+ start_date=start_date,
76
+ end_date=end_date,
77
+ verbose=verbose,
78
+ include_contract_symbol=True,
79
+ org_id=org_id,
80
+ uevcb_id=uevcb_id,
81
+ timeout=timeout,
82
+ **params,
83
+ **kwargs,
84
+ )
85
+
86
+ cost_df = get_hourly_price_and_cost_data(
87
+ eptr=eptr,
88
+ start_date=start_date,
89
+ end_date=end_date,
90
+ verbose=verbose,
91
+ include_contract_symbol=True,
92
+ include_wap=False,
93
+ timeout=timeout,
94
+ )
95
+
96
+ #### Merge and calculate costs
97
+ prod_df = (
98
+ df[["dt", "contract", f"toplam_{forecast_source}", f"total_{actual_source}"]]
99
+ .rename(
100
+ columns={
101
+ f"toplam_{forecast_source}": "forecast",
102
+ f"total_{actual_source}": "actual",
103
+ }
104
+ )
105
+ .copy()
106
+ )
107
+
108
+ prod_df["diff"] = prod_df["forecast"] - prod_df["actual"]
109
+
110
+ merged_df = prod_df.merge(
111
+ cost_df.rename(columns={"date": "dt"})[
112
+ ["dt", "pos_imb_cost", "neg_imb_cost", "kupst_cost"]
113
+ ],
114
+ on="dt",
115
+ how="inner",
116
+ )
117
+
118
+ ## Calculate kupsm and costs
119
+ kupst_tolerance = get_kupst_tolerance(plant_type)
120
+ merged_df["kupsm"] = merged_df.apply(
121
+ lambda row: calculate_kupsm(
122
+ actual=row["actual"], forecast=row["forecast"], tol=kupst_tolerance
123
+ ),
124
+ axis=1,
125
+ )
126
+
127
+ ### Calculate total costs
128
+ merged_df["total_kupst_cost"] = merged_df["kupsm"] * merged_df["kupst_cost"]
129
+ merged_df["total_imb_cost"] = merged_df.apply(
130
+ lambda row: (row["pos_imb_cost"] if row["diff"] < 0 else row["neg_imb_cost"])
131
+ * abs(row["diff"]),
132
+ axis=1,
133
+ )
134
+ merged_df["total_cost"] = (
135
+ merged_df["total_kupst_cost"] + merged_df["total_imb_cost"]
136
+ )
137
+
138
+ if postprocess:
139
+ d = postprocess_plant_cost_df(merged_df)
140
+ return d
141
+
142
+ return merged_df
@@ -0,0 +1,376 @@
1
+ from eptr2 import EPTR2
2
+ import pandas as pd
3
+ from eptr2.util.time import (
4
+ iso_to_contract,
5
+ check_date_for_settlement,
6
+ )
7
+ import time
8
+
9
+
10
+ def get_hourly_production_data(
11
+ eptr: EPTR2,
12
+ start_date: str,
13
+ end_date: str,
14
+ rt_pp_id: str | int | None = None,
15
+ uevm_pp_id: str | int | None = None,
16
+ verbose: bool = False,
17
+ include_contract_symbol: bool = True,
18
+ skip_uevm: bool = False,
19
+ skip_rt: bool = False,
20
+ **kwargs,
21
+ ):
22
+ """
23
+ This composite function gets production data (Gerçek Zamanlı Üretim, UEVM) and merges them.
24
+
25
+ It is also possible to enter pp_id to get the production data for a specific production plan. Example ID values are given below.
26
+
27
+ rt_pp_id=641, ## ATATÜRK HES
28
+ uevm_pp_id=142, ## ATATÜRK HES
29
+ """
30
+
31
+ max_trials = kwargs.get("max_trials", 2)
32
+ timeout = kwargs.get("timeout", 5)
33
+ sleep_interval = kwargs.get("sleep_interval", 3)
34
+
35
+ #### SANITY CHECKS ####
36
+ if skip_rt and skip_uevm:
37
+ raise ValueError("Both skip_rt and skip_uevm cannot be True.")
38
+
39
+ #### REAL TIME GENERATION PHASE ####
40
+ if skip_rt:
41
+ rt_included = False
42
+ rt_gen_df = pd.DataFrame()
43
+
44
+ else:
45
+ rt_included = True
46
+ if verbose:
47
+ print("Loading real time production data...")
48
+
49
+ trials = max_trials
50
+ while trials > 0:
51
+ try:
52
+ rt_gen_df: pd.DataFrame = eptr.call(
53
+ "rt-gen",
54
+ start_date=start_date,
55
+ end_date=end_date,
56
+ pp_id=rt_pp_id,
57
+ request_kwargs={"timeout": timeout},
58
+ )
59
+ break
60
+ except Exception as e:
61
+ trials -= 1
62
+
63
+ if trials == 0:
64
+ raise e
65
+
66
+ time.sleep(sleep_interval)
67
+ if verbose:
68
+ print(
69
+ f"An error occurred while fetching RT data. Retrying after {sleep_interval} seconds... ({trials} attempts left)"
70
+ )
71
+
72
+ if rt_gen_df.empty:
73
+ raise ValueError("No data (production) is available for this date range.")
74
+
75
+ try:
76
+ rt_gen_df.drop("hour", axis=1, inplace=True)
77
+ except Exception as e:
78
+ if verbose:
79
+ print(e)
80
+
81
+ rt_gen_df.columns = [
82
+ x + "_rt" if x not in ["date"] else x for x in rt_gen_df.columns
83
+ ]
84
+
85
+ #### UEVM PHASE ####
86
+ if skip_uevm:
87
+ uevm_included = False
88
+ uevm_df = pd.DataFrame()
89
+
90
+ else:
91
+ uevm_included = True
92
+ if verbose:
93
+ print("Loading UEVM data...")
94
+
95
+ trials = max_trials
96
+ while trials > 0:
97
+ try:
98
+ uevm_df: pd.DataFrame = eptr.call(
99
+ "uevm",
100
+ start_date=start_date,
101
+ end_date=end_date,
102
+ pp_id=uevm_pp_id,
103
+ request_kwargs={"timeout": timeout},
104
+ )
105
+ break
106
+ except Exception as e:
107
+ trials -= 1
108
+ if trials == 0:
109
+ raise e
110
+
111
+ time.sleep(sleep_interval)
112
+ if verbose:
113
+ print(
114
+ f"An error occurred while fetching UEVM data. Retrying after {sleep_interval} seconds... ({trials} attempts left)"
115
+ )
116
+
117
+ try:
118
+ uevm_df.drop("hour", axis=1, inplace=True)
119
+ except Exception as e:
120
+ within_settlement = check_date_for_settlement(x=end_date)
121
+ if not within_settlement:
122
+ print("Warning: The end date may not be within the settlement period.")
123
+ if verbose:
124
+ print(e)
125
+
126
+ uevm_df.columns = [
127
+ x + "_uevm" if x not in ["date"] else x for x in uevm_df.columns
128
+ ]
129
+
130
+ if uevm_included and rt_included:
131
+ if verbose:
132
+ print("Merging data...")
133
+
134
+ if uevm_df.empty:
135
+ merged_df = rt_gen_df.copy()
136
+ else:
137
+ merged_df = rt_gen_df.merge(uevm_df, how="left", on=["date"])
138
+ elif uevm_included:
139
+ merged_df = uevm_df.copy()
140
+ elif rt_included:
141
+ merged_df = rt_gen_df.copy()
142
+
143
+ if include_contract_symbol:
144
+ try:
145
+ merged_df["contract"] = merged_df["date"].apply(
146
+ lambda x: iso_to_contract(x)
147
+ )
148
+ except Exception as e:
149
+ print("Contract information could not be added. Error:", e)
150
+
151
+ merged_df = merged_df.rename(columns={"date": "dt"})
152
+
153
+ return merged_df
154
+
155
+
156
+ def get_hourly_production_plan_data(
157
+ eptr: EPTR2,
158
+ start_date: str,
159
+ end_date: str,
160
+ org_id: str | None = None,
161
+ uevcb_id: str | None = None,
162
+ verbose: bool = False,
163
+ include_contract_symbol: bool = True,
164
+ skip_kgup: bool = False,
165
+ skip_kgup_v1: bool = False,
166
+ skip_kudup: bool = False,
167
+ **kwargs,
168
+ ):
169
+ """
170
+ This composite function gets KGUP v1, KGUP and KUDUP data and merges them.
171
+
172
+ It is also possible to enter org_id to get the total production plan for a specific organization. If uevcb_id is also added with org_id, it will get the production plan for a specific uevcb. Example ID values are given below.
173
+
174
+ org_id=195, ## ELEKTRİK ÜRETİM AŞ
175
+ uevcb_id=733, ## ATATÜRK HES DB
176
+ """
177
+
178
+ max_trials = kwargs.get("max_trials", 2)
179
+ timeout = kwargs.get("timeout", 5)
180
+
181
+ if all([skip_kgup_v1, skip_kgup, skip_kudup]):
182
+ raise ValueError(
183
+ "At least one of skip_kgup, skip_kgupv1, or skip_kudup must be False."
184
+ )
185
+
186
+ if uevcb_id is not None:
187
+ if org_id is None:
188
+ raise ValueError("org_id is required if uevcb_id is specified.")
189
+
190
+ if not skip_kgup_v1:
191
+
192
+ if verbose:
193
+ print("Loading KGUP v1...")
194
+
195
+ trials = max_trials
196
+ while trials > 0:
197
+ try:
198
+ kgup_v1_df: pd.DataFrame = eptr.call(
199
+ "kgup-v1",
200
+ start_date=start_date,
201
+ end_date=end_date,
202
+ org_id=org_id,
203
+ uevcb_id=uevcb_id,
204
+ request_kwargs={"timeout": timeout},
205
+ )
206
+ break
207
+ except Exception as e:
208
+ trials -= 1
209
+ if trials == 0:
210
+ raise e
211
+ if verbose:
212
+ print(
213
+ f"An error occurred while fetching KGUP v1 data. Retrying... ({trials} attempts left)"
214
+ )
215
+
216
+ if kgup_v1_df.empty:
217
+ skip_kgup_v1 = True
218
+ print("No data (KGUP v1) is available for this date range.")
219
+ else:
220
+ kgup_v1_df.columns = [
221
+ x + "_kgup_v1" if x not in ["date", "time"] else x
222
+ for x in kgup_v1_df.columns
223
+ ]
224
+
225
+ if not skip_kgup:
226
+ if verbose:
227
+ print("Loading KGUP...")
228
+
229
+ trials = max_trials
230
+ while trials > 0:
231
+ try:
232
+ kgup_df: pd.DataFrame = eptr.call(
233
+ "kgup",
234
+ start_date=start_date,
235
+ end_date=end_date,
236
+ org_id=org_id,
237
+ uevcb_id=uevcb_id,
238
+ request_kwargs={"timeout": timeout},
239
+ )
240
+ break
241
+ except Exception as e:
242
+ trials -= 1
243
+ if trials == 0:
244
+ raise e
245
+ if verbose:
246
+ print(
247
+ f"An error occurred while fetching KGUP data. Retrying... ({trials} attempts left)"
248
+ )
249
+ if kgup_df.empty:
250
+ skip_kgup = True
251
+ print("No data (KGUP) is available for this date range.")
252
+ else:
253
+ kgup_df.columns = [
254
+ x + "_kgup" if x not in ["date", "time"] else x for x in kgup_df.columns
255
+ ]
256
+
257
+ if not skip_kudup:
258
+ if verbose:
259
+ print("Loading KUDUP...")
260
+
261
+ trials = max_trials
262
+ while trials > 0:
263
+ try:
264
+ kudup_df: pd.DataFrame = eptr.call(
265
+ "kudup",
266
+ start_date=start_date,
267
+ end_date=end_date,
268
+ org_id=org_id,
269
+ uevcb_id=uevcb_id,
270
+ request_kwargs={"timeout": timeout},
271
+ )
272
+ break
273
+ except Exception as e:
274
+ trials -= 1
275
+ if trials == 0:
276
+ raise e
277
+ if verbose:
278
+ print(
279
+ f"An error occurred while fetching KUDUP data. Retrying... ({trials} attempts left)"
280
+ )
281
+
282
+ if kudup_df.empty:
283
+ skip_kudup = True
284
+ print("No data (KUDUP) is available for this date range.")
285
+ else:
286
+ kudup_df.columns = [
287
+ x + "_kudup" if x not in ["date", "time"] else x
288
+ for x in kudup_df.columns
289
+ ]
290
+
291
+ #### MERGE PHASE ####
292
+ if verbose:
293
+ print("Merging dataframes...")
294
+
295
+ merged_df = None
296
+ for _ in ["kgup_v1", "kgup", "kudup"]:
297
+ if not eval(f"skip_{_}"):
298
+ if merged_df is None:
299
+ merged_df: pd.DataFrame = eval(f"{_}_df").copy()
300
+ else:
301
+ merged_df = merged_df.merge(
302
+ eval(f"{_}_df"), on=["date", "time"], how="outer"
303
+ )
304
+
305
+ ### Column reordering and contract addition
306
+ if include_contract_symbol:
307
+ try:
308
+ merged_df["contract"] = merged_df["date"].apply(
309
+ lambda x: iso_to_contract(x)
310
+ )
311
+ except Exception as e:
312
+ print("Contract information could not be added. Error:", e)
313
+
314
+ merged_df = merged_df.rename(columns={"date": "dt"})
315
+
316
+ col_order = (
317
+ ["dt", "time"] + ["contract"]
318
+ if include_contract_symbol
319
+ else [] + [x for x in merged_df.columns if x.startswith("toplam")]
320
+ )
321
+
322
+ merged_df = merged_df[
323
+ col_order + [x for x in merged_df.columns if x not in col_order]
324
+ ]
325
+
326
+ return merged_df
327
+
328
+
329
+ def wrapper_hourly_production_plan_and_realized(
330
+ eptr: EPTR2,
331
+ start_date: str,
332
+ end_date: str,
333
+ org_id: str | None = None,
334
+ uevcb_id: str | None = None,
335
+ rt_pp_id: str | None = None,
336
+ uevm_pp_id: str | None = None,
337
+ verbose: bool = False,
338
+ include_contract_symbol: bool = True,
339
+ **kwargs,
340
+ ):
341
+
342
+ if verbose:
343
+ print("Loading production plan data...")
344
+
345
+ plan_df = get_hourly_production_plan_data(
346
+ eptr=eptr,
347
+ start_date=start_date,
348
+ end_date=end_date,
349
+ org_id=org_id,
350
+ uevcb_id=uevcb_id,
351
+ verbose=verbose,
352
+ include_contract_symbol=include_contract_symbol,
353
+ **kwargs,
354
+ )
355
+
356
+ if verbose:
357
+ print("Loading production realizations data...")
358
+
359
+ realized_df = get_hourly_production_data(
360
+ eptr=eptr,
361
+ start_date=start_date,
362
+ end_date=end_date,
363
+ rt_pp_id=rt_pp_id,
364
+ uevm_pp_id=uevm_pp_id,
365
+ verbose=verbose,
366
+ include_contract_symbol=include_contract_symbol,
367
+ **kwargs,
368
+ )
369
+
370
+ merged_df = plan_df.merge(
371
+ realized_df,
372
+ how="outer",
373
+ on=["dt"] + (["contract"] if include_contract_symbol else []),
374
+ )
375
+
376
+ return merged_df
@@ -743,6 +743,18 @@ def get_help_d(key=None):
743
743
  },
744
744
  "url": "https://seffaflik.epias.com.tr/electricity/electricity-generation/ex-post-generation/real-time-generation",
745
745
  },
746
+ "pp-list-for-date-range": {
747
+ "category": "Listeleme",
748
+ "title": {
749
+ "tr": "Santral Listeleme (Tarih Aralığı ile)",
750
+ "en": "Powerplant listing (with Date Range)",
751
+ },
752
+ "desc": {
753
+ "tr": "Santral Listeleme (Tarih Aralığı ile)",
754
+ "en": "Powerplant listing (with Date Range)",
755
+ },
756
+ "url": "https://seffaflik.epias.com.tr/electricity/electricity-generation/ex-post-generation/real-time-generation",
757
+ },
746
758
  "gen-org": {
747
759
  "category": "Listeleme",
748
760
  "title": {
@@ -121,6 +121,7 @@ def get_required_parameters(key, return_mapping=False, mapping_only_keys=False):
121
121
  "load-plan": ["start_date", "end_date"],
122
122
  "rt-cons": ["start_date", "end_date"],
123
123
  "pp-list": [],
124
+ "pp-list-for-date-range": ["start_date", "end_date"],
124
125
  "uevm-pp-list": [],
125
126
  "ren-pp-list": ["period"],
126
127
  "ren-rt-gen": ["start_date", "end_date"],
@@ -323,6 +323,12 @@ def get_path_map(just_call_keys: bool = False):
323
323
  "prev": "generation",
324
324
  "label": "powerplant-list",
325
325
  },
326
+ ##Tarih Araligina Gore Santral Listeleme Servisi
327
+ "pp-list-for-date-range": {
328
+ "prefix": "data",
329
+ "prev": "generation",
330
+ "label": "powerplant-list-for-date-range",
331
+ },
326
332
  ## Santral Listeleme
327
333
  "uevm-pp-list": {
328
334
  "prefix": "data",
@@ -1132,6 +1138,7 @@ def get_call_method(key):
1132
1138
  "interim-mcp-status",
1133
1139
  "market-participants-organization-list",
1134
1140
  "pp-list",
1141
+ # "pp-list-for-date-range", ## POST method
1135
1142
  "uevm-pp-list",
1136
1143
  "region-list",
1137
1144
  "mms-message-type-list",
@@ -58,6 +58,7 @@ def get_postprocess_function(key):
58
58
  "gen-uevcb",
59
59
  "rt-gen",
60
60
  "pp-list",
61
+ "pp-list-for-date-range",
61
62
  "uevm-pp-list",
62
63
  "lic-pp-list",
63
64
  "load-plan",