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.
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/.gitignore +1 -1
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/PKG-INFO +22 -3
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/README.md +21 -2
- eptr2-1.2.1.dev0/creds/eptr_credentials.json +9 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/__init__.py +1 -0
- eptr2-1.2.1.dev0/eptr2/composite/plant_costs.py +142 -0
- eptr2-1.2.1.dev0/eptr2/composite/production.py +376 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/help.py +12 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/parameters.py +1 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/path.py +7 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/processing.py +1 -0
- {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
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/pages/2_/360/237/224/256_Pozisyonlar.py +1 -1
- {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
- {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
- eptr2-1.2.1.dev0/eptr2/tutorials/composite/pages/5_/360/237/222/270_Santral_Dengesizlik.py +514 -0
- 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
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite//342/255/220/357/270/217_Ana_Sayfa.py +22 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/demo.py +4 -4
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/costs.py +92 -1
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/time.py +24 -4
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/pyproject.toml +4 -2
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/uv.lock +1 -1
- eptr2-1.2.0.dev0/eptr2/composite/production.py +0 -236
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/LICENSE +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/bpm.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/consumption.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/dabi_idm.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/idm_log.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/mms.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/composite/price_and_cost.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/main.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/mapping/checks.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/postprocess/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/postprocess/items.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/calls.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/processing/preprocess/params.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/calc.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/composite/common.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/tutorials/main.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/certificate.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/eptr2/util/evaluation.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/__init__.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_consumption.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_mms.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_price_and_cost.py +0 -0
- {eptr2-1.2.0.dev0 → eptr2-1.2.1.dev0}/tests/composite/test_production.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: eptr2
|
|
3
|
-
Version: 1.2.
|
|
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
|
+
}
|
|
@@ -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",
|