Johannesj00 commited on
Commit
2009f7f
·
0 Parent(s):

Deploy clean Space (no binary artifacts)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +3 -0
  2. .gitignore +15 -0
  3. Dockerfile +28 -0
  4. README.md +8 -0
  5. app/main.py +256 -0
  6. app/main2.py +105 -0
  7. entrypoint.sh +104 -0
  8. model/costs/capex/capex.py +84 -0
  9. model/costs/capex/capex_mod.py +169 -0
  10. model/costs/capex/other_costs.csv +7 -0
  11. model/costs/finance/finance.py +67 -0
  12. model/costs/finance/finance_mod.py +192 -0
  13. model/costs/opex/opex.csv +3 -0
  14. model/costs/opex/opex.py +35 -0
  15. model/costs/opex/opex_mod.py +86 -0
  16. model/costs/planning/merge.py +38 -0
  17. model/costs/planning/national_project_development_costs.csv +4 -0
  18. model/costs/planning/national_wind_project_development_costs.csv +5 -0
  19. model/costs/planning/permitting_phase_bundesland.csv +16 -0
  20. model/costs/planning/planning_phase_bundesland.csv +16 -0
  21. model/costs/planning/total_bundesland.csv +16 -0
  22. model/park_gross_mwh_monthly_mock_2015_2046.csv +385 -0
  23. model/profit.py +344 -0
  24. model/revenue/capture_factor_history_forecast/capture_factor_forecast_b2.csv +373 -0
  25. model/revenue/capture_factor_history_forecast/capture_factor_monthly_historical.csv +133 -0
  26. model/revenue/capture_factor_history_forecast/cf_his.py +96 -0
  27. model/revenue/capture_factor_history_forecast/reg_cf.py +182 -0
  28. model/revenue/curltailment_rate_per_tso/50Hertz1518.csv +0 -0
  29. model/revenue/curltailment_rate_per_tso/50Hertz1922.csv +0 -0
  30. model/revenue/curltailment_rate_per_tso/Amprion1518.csv +0 -0
  31. model/revenue/curltailment_rate_per_tso/Amprion1922.csv +0 -0
  32. model/revenue/curltailment_rate_per_tso/Tennet1518.csv +0 -0
  33. model/revenue/curltailment_rate_per_tso/Tennet1922.csv +0 -0
  34. model/revenue/curltailment_rate_per_tso/TransnetBW1518.csv +0 -0
  35. model/revenue/curltailment_rate_per_tso/TransnetBW1922.csv +0 -0
  36. model/revenue/curltailment_rate_per_tso/curltailment_rate_quarterly_by_tso.csv +31 -0
  37. model/revenue/curltailment_rate_per_tso/curltailmentcalc.py +103 -0
  38. model/revenue/curltailment_rate_per_tso/curtailment.csv +31 -0
  39. model/revenue/curltailment_rate_per_tso/curtailment_forecast_quarterly_by_tso_2021_2046.csv +417 -0
  40. model/revenue/curltailment_rate_per_tso/merge.py +106 -0
  41. model/revenue/curltailment_rate_per_tso/pred_cr.py +175 -0
  42. model/revenue/curltailment_rate_per_tso/wind_onshore_daily_by_tso.csv +0 -0
  43. model/revenue/day_ahead_market_prices/eh1516.csv +0 -0
  44. model/revenue/day_ahead_market_prices/eh1718.csv +0 -0
  45. model/revenue/day_ahead_market_prices/eh1920.csv +0 -0
  46. model/revenue/day_ahead_market_prices/eh2122.csv +0 -0
  47. model/revenue/day_ahead_market_prices/eh2324.csv +0 -0
  48. model/revenue/day_ahead_market_prices/eh25.csv +0 -0
  49. model/revenue/day_ahead_market_prices/market_price_forecast_20y_monthly.csv +241 -0
  50. model/revenue/day_ahead_market_prices/market_price_monthly_history.csv +133 -0
.gitattributes ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ backend/model/revenue/mc_inputs_30y_monthly_merged.csv filter=lfs diff=lfs merge=lfs -text
2
+ frontend/src/data/GER_NUTS3_TSOs.shp filter=lfs diff=lfs merge=lfs -text
3
+ frontend/src/data/tso.json filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # venv / local artifacts
2
+ .venv/
3
+ venv/
4
+ **/.venv/
5
+ **/venv/
6
+ __pycache__/
7
+ *.pyc
8
+
9
+ # model binaries
10
+ wind-power-climate-ml/LGBM_Model/model_artifacts/
11
+ *.pkl
12
+ *.joblib
13
+
14
+ # optional: trash / outputs
15
+ model/revenue/trash/
Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ WORKDIR /app
4
+
5
+ ENV PIP_NO_CACHE_DIR=1 \
6
+ PYTHONDONTWRITEBYTECODE=1 \
7
+ PYTHONUNBUFFERED=1
8
+
9
+ # Falls du lightgbm / netcdf etc. nutzt, brauchst du evtl. Systemlibs.
10
+ # Minimal (häufig nötig für lightgbm): gcc/g++ und libgomp
11
+ RUN apt-get update && apt-get install -y --no-install-recommends \
12
+ gcc g++ libgomp1 \
13
+ && rm -rf /var/lib/apt/lists/*
14
+
15
+ # Python deps zuerst (besserer Docker cache)
16
+ COPY wind-power-climate-ml/requirements.txt /app/requirements.txt
17
+ RUN pip install -r /app/requirements.txt
18
+ RUN pip install -U huggingface_hub
19
+
20
+ # App-Code
21
+ COPY wind-power-climate-ml /app/wind-power-climate-ml
22
+
23
+ # Entrypoint
24
+ COPY entrypoint.sh /app/entrypoint.sh
25
+ RUN chmod +x /app/entrypoint.sh
26
+
27
+ EXPOSE 7860
28
+ CMD ["/app/entrypoint.sh"]
README.md ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: windproject
3
+ sdk: docker
4
+ app_port: 7860
5
+ ---
6
+
7
+ Wind Energy Forecast API
8
+
app/main.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import Response
4
+ from pydantic import BaseModel, Field
5
+ from typing import Optional, Any
6
+ import pandas as pd
7
+ import numpy as np
8
+ from pathlib import Path
9
+ import sys
10
+ import json
11
+ import math
12
+
13
+
14
+ # --- Make sure Python can import from backend/model ---
15
+ # project/backend/app/main.py -> project/backend
16
+ BACKEND_ROOT = Path(__file__).resolve().parents[1]
17
+ MODEL_DIR = BACKEND_ROOT / "model"
18
+ sys.path.insert(0, str(MODEL_DIR))
19
+
20
+ # Now we can import your script
21
+ from profit import power_to_profit, FORECAST_MONTHS
22
+
23
+ app = FastAPI()
24
+
25
+ @app.get("/favicon.ico")
26
+ def favicon():
27
+ return Response(status_code=204)
28
+
29
+ @app.get("/")
30
+ def root():
31
+ return {"ok": True, "message": "Backend running. Go to /docs for API docs."}
32
+
33
+ # Allow the Vite dev server to call the API from the browser during development.
34
+ app.add_middleware(
35
+ CORSMiddleware,
36
+ allow_origins=["*"], # allow all origins for testing
37
+ allow_credentials=True,
38
+ allow_methods=["*"],
39
+ allow_headers=["*"],
40
+ )
41
+
42
+ # -------------------------
43
+ # Request schema
44
+ # -------------------------
45
+ class CalcRequest(BaseModel):
46
+ # Settings from the UI
47
+ n_turbines: int = Field(ge=1)
48
+ hub_height_m: int = Field(ge=1)
49
+ turbine_type_id: int = Field(ge=0, le=2)
50
+ equity_eur: int = Field(ge=0)
51
+
52
+ # Revenue module required keys
53
+ tso_id: int = Field(ge=0, le=3)
54
+ eeg_on: bool
55
+ cod_date: str # "YYYY-MM-DD"
56
+ manual_eeg_strike: Optional[float] = None
57
+
58
+ # For now: constant monthly MWh (easy to wire first)
59
+ mwh_constant: float = Field(gt=0)
60
+
61
+
62
+ def to_jsonable(obj: Any):
63
+ """Convert pandas/numpy objects into JSON-serializable Python types.
64
+ Also replaces NaN/Inf with None (JSON-compliant).
65
+ """
66
+ # pandas DataFrame
67
+ if isinstance(obj, pd.DataFrame):
68
+ df = obj.copy()
69
+
70
+ # Convert datetime columns to strings
71
+ for col in df.columns:
72
+ if pd.api.types.is_datetime64_any_dtype(df[col]):
73
+ df[col] = df[col].astype(str)
74
+
75
+ # Replace inf/-inf with NaN, then NaN -> None
76
+ df = df.replace([np.inf, -np.inf], np.nan)
77
+ df = df.where(pd.notnull(df), None)
78
+
79
+ return df.to_dict(orient="records")
80
+
81
+ # pandas Series
82
+ if isinstance(obj, pd.Series):
83
+ s = obj.copy()
84
+
85
+ # If index is datetime, return list of {date, value}
86
+ if pd.api.types.is_datetime64_any_dtype(s.index):
87
+ out = []
88
+ for idx, val in s.items():
89
+ if pd.isna(val) or val in (np.inf, -np.inf):
90
+ v = None
91
+ else:
92
+ v = float(val)
93
+ out.append({"date": str(idx), "value": v})
94
+ return out
95
+
96
+ # otherwise just list values
97
+ out = []
98
+ for x in s.to_list():
99
+ if pd.isna(x) or x in (np.inf, -np.inf):
100
+ out.append(None)
101
+ else:
102
+ out.append(float(x))
103
+ return out
104
+
105
+ # pandas Timestamp
106
+ if isinstance(obj, pd.Timestamp):
107
+ return str(obj)
108
+
109
+ # numpy scalars/arrays
110
+ if isinstance(obj, (np.integer,)):
111
+ return int(obj)
112
+
113
+ if isinstance(obj, (np.floating,)):
114
+ val = float(obj)
115
+ if val != val or val in (float("inf"), float("-inf")):
116
+ return None
117
+ return val
118
+
119
+ if isinstance(obj, np.ndarray):
120
+ # Convert elements too (in case the array has NaN)
121
+ return [to_jsonable(x) for x in obj.tolist()]
122
+
123
+ # plain Python float NaN/Inf
124
+ if isinstance(obj, float):
125
+ if obj != obj or obj in (float("inf"), float("-inf")):
126
+ return None
127
+ return obj
128
+
129
+ # dict / list / tuple
130
+ if isinstance(obj, dict):
131
+ return {k: to_jsonable(v) for k, v in obj.items()}
132
+
133
+ if isinstance(obj, (list, tuple)):
134
+ return [to_jsonable(x) for x in obj]
135
+
136
+ return obj
137
+
138
+ def scrub_nonfinite(obj: Any):
139
+ """Recursively replace NaN/Inf/-Inf with None in already JSON-like objects."""
140
+ # dict
141
+ if isinstance(obj, dict):
142
+ return {k: scrub_nonfinite(v) for k, v in obj.items()}
143
+
144
+ # list/tuple
145
+ if isinstance(obj, (list, tuple)):
146
+ return [scrub_nonfinite(v) for v in obj]
147
+
148
+ # numpy scalar that may still exist
149
+ if isinstance(obj, np.generic):
150
+ return scrub_nonfinite(obj.item())
151
+
152
+ # float NaN/Inf
153
+ if isinstance(obj, float):
154
+ return None if not math.isfinite(obj) else obj
155
+
156
+ return obj
157
+
158
+ def pick_first_col(df: pd.DataFrame, candidates: list[str]) -> str | None:
159
+ for c in candidates:
160
+ if c in df.columns:
161
+ return c
162
+ return None
163
+
164
+
165
+
166
+
167
+ @app.post("/api/calc")
168
+ def calc(req: CalcRequest):
169
+ try:
170
+ # Build monthly MWh series for 20 years
171
+ cod = pd.Timestamp(req.cod_date)
172
+ cod = pd.Timestamp(year=cod.year, month=cod.month, day=1)
173
+
174
+ dates = pd.date_range(cod, periods=FORECAST_MONTHS, freq="MS")
175
+ mwh_series = pd.Series(float(req.mwh_constant), index=dates)
176
+
177
+ result = power_to_profit(
178
+ mwh_monthly_20y=mwh_series,
179
+ turbine_type_id=req.turbine_type_id,
180
+ n_turbines=req.n_turbines,
181
+ hub_height_m=req.hub_height_m,
182
+ equity_eur=float(req.equity_eur),
183
+ revenue_kwargs={
184
+ "tso_id": int(req.tso_id),
185
+ "eeg_on": 1 if req.eeg_on else 0,
186
+ "manual_eeg_strike": req.manual_eeg_strike,
187
+ "cod_date": req.cod_date,
188
+ },
189
+ )
190
+
191
+ monthly = result["monthly_revenue_df"].copy()
192
+ yearly = result["yearly_df"].copy()
193
+
194
+ # Ensure project_year exists (it should, from your profit.py logic)
195
+ if "project_year" not in monthly.columns:
196
+ raise ValueError("monthly_revenue_df is missing 'project_year'")
197
+
198
+ # Choose a reasonable MWh column (depends on your revenue module output)
199
+ mwh_col = pick_first_col(monthly, ["mwh_gross", "mwh", "mwh_delivered"])
200
+ if not mwh_col:
201
+ raise ValueError("monthly_revenue_df has none of: mwh_gross, mwh, mwh_delivered")
202
+
203
+ # Weighted average helper (for market price)
204
+ def wavg(group: pd.DataFrame, value_col: str, weight_col: str):
205
+ w = pd.to_numeric(group[weight_col], errors="coerce").fillna(0.0)
206
+ v = pd.to_numeric(group[value_col], errors="coerce")
207
+ denom = float(w.sum())
208
+ if denom <= 0:
209
+ return np.nan
210
+ return float((v * w).sum() / denom)
211
+
212
+ # Aggregate monthly -> yearly drivers
213
+ agg = (
214
+ monthly.groupby("project_year", as_index=False)
215
+ .apply(lambda g: pd.Series({
216
+ "mwh_gross": float(pd.to_numeric(g[mwh_col], errors="coerce").fillna(0.0).sum()),
217
+ "market_price_eur_per_mwh": wavg(g, "p_market", mwh_col) if "p_market" in g.columns else np.nan,
218
+ "cf": float(pd.to_numeric(g["cf"], errors="coerce").mean()) if "cf" in g.columns else np.nan,
219
+ "cr": float(pd.to_numeric(g["cr"], errors="coerce").mean()) if "cr" in g.columns else np.nan,
220
+ }))
221
+ )
222
+
223
+ # Join with yearly opex/debt/profit
224
+ out = yearly.merge(agg, on="project_year", how="left")
225
+
226
+ # Build the exact columns you asked for
227
+ table_df = pd.DataFrame({
228
+ "year": out["project_year"],
229
+ "mwh_gross": out["mwh_gross"],
230
+ "market_price_electricity": out["market_price_eur_per_mwh"],
231
+ "cf": out["cf"],
232
+ "cr": out["cr"],
233
+ "opex": out["annual_opex_eur"],
234
+ "debt_service": out["debt_service_eur"],
235
+ "profit": out["profit_after_opex_and_debt_eur"],
236
+ })
237
+
238
+ # Convert NaN/Inf -> None for JSON
239
+ table_df = table_df.replace([np.inf, -np.inf], np.nan).where(pd.notnull(table_df), None)
240
+
241
+ payload = {
242
+ "ok": True,
243
+ "npv_eur": float(result["npv_eur"]),
244
+ "irr": None if (float(result["irr"]) != float(result["irr"])) else float(result["irr"]),
245
+ "discount_rate_used": float(result["discount_rate_used"]),
246
+ "table": table_df.to_dict(orient="records"),
247
+ }
248
+
249
+ # Ensure strict JSON (no NaN)
250
+ json.dumps(payload, allow_nan=False)
251
+
252
+ return payload
253
+
254
+
255
+ except Exception as e:
256
+ raise HTTPException(status_code=400, detail=str(e))
app/main2.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import Response
4
+ from pydantic import BaseModel, Field
5
+ from typing import Optional, List
6
+ import pandas as pd
7
+ from pathlib import Path
8
+ import sys
9
+
10
+ # --- Make sure Python can import from backend/model ---
11
+ # project/backend/app/main.py -> project/backend
12
+ BACKEND_ROOT = Path(__file__).resolve().parents[1]
13
+ MODEL_DIR = BACKEND_ROOT / "model"
14
+ sys.path.insert(0, str(MODEL_DIR))
15
+
16
+ # Now we can import your script
17
+ from profit import power_to_profit, FORECAST_MONTHS
18
+
19
+ app = FastAPI()
20
+
21
+ @app.get("/favicon.ico")
22
+ def favicon():
23
+ return Response(status_code=204)
24
+
25
+ @app.get("/")
26
+ def root():
27
+ return {"ok": True, "message": "Backend running. Go to /docs for API docs."}
28
+
29
+
30
+ # Allow the Vite dev server to call the API from the browser during development.
31
+ app.add_middleware(
32
+ CORSMiddleware,
33
+ allow_origins=["http://localhost:5173"],
34
+ allow_credentials=True,
35
+ allow_methods=["*"],
36
+ allow_headers=["*"],
37
+ )
38
+
39
+ # -------------------------
40
+ # Request/response schemas
41
+ # -------------------------
42
+ class CalcRequest(BaseModel):
43
+ # Settings from the UI
44
+ n_turbines: int = Field(ge=1)
45
+ hub_height_m: int = Field(ge=1)
46
+ turbine_type_id: int = Field(ge=0, le=2)
47
+ equity_eur: int = Field(ge=0)
48
+
49
+ # Revenue module required keys
50
+ tso_id: int = Field(ge=1)
51
+ eeg_on: bool
52
+ cod_date: str # "YYYY-MM-DD"
53
+ manual_eeg_strike: Optional[float] = None
54
+
55
+ # For now: constant monthly MWh (easy to wire first)
56
+ mwh_constant: float = Field(gt=0)
57
+
58
+ class CalcResponse(BaseModel):
59
+ ok: bool
60
+ npv_eur: float
61
+ irr: float
62
+ discount_rate_used: float
63
+ yearly: List[dict]
64
+
65
+ @app.post("/api/calc", response_model=CalcResponse)
66
+ def calc(req: CalcRequest):
67
+ try:
68
+ # Build monthly MWh series for 20 years
69
+ cod = pd.Timestamp(req.cod_date)
70
+ cod = pd.Timestamp(year=cod.year, month=cod.month, day=1)
71
+
72
+ dates = pd.date_range(cod, periods=FORECAST_MONTHS, freq="MS")
73
+ mwh_series = pd.Series(float(req.mwh_constant), index=dates)
74
+
75
+ result = power_to_profit(
76
+ mwh_monthly_20y=mwh_series,
77
+ turbine_type_id=req.turbine_type_id,
78
+ n_turbines=req.n_turbines,
79
+ hub_height_m=req.hub_height_m,
80
+ equity_eur=float(req.equity_eur),
81
+ revenue_kwargs={
82
+ "tso_id": int(req.tso_id),
83
+ "eeg_on": 1 if req.eeg_on else 0,
84
+ "manual_eeg_strike": req.manual_eeg_strike,
85
+ "cod_date": req.cod_date,
86
+ },
87
+ )
88
+
89
+ yearly_df = result["yearly_df"].copy()
90
+ if "year_start" in yearly_df.columns:
91
+ yearly_df["year_start"] = yearly_df["year_start"].astype(str)
92
+
93
+ irr_val = result["irr"]
94
+ irr_val = float(irr_val) if irr_val == irr_val else float("nan") # handle NaN
95
+
96
+ return {
97
+ "ok": True,
98
+ "npv_eur": float(result["npv_eur"]),
99
+ "irr": irr_val,
100
+ "discount_rate_used": float(result["discount_rate_used"]),
101
+ "yearly": yearly_df.to_dict(orient="records"),
102
+ }
103
+
104
+ except Exception as e:
105
+ raise HTTPException(status_code=400, detail=str(e))
entrypoint.sh ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ DATA_ROOT="/app/inference-data"
5
+ ERA5_SUBDIR="ERA5_Germany"
6
+ ERA5_PATH="$DATA_ROOT/$ERA5_SUBDIR"
7
+
8
+ MODEL_ROOT="/app/model-artifacts"
9
+
10
+ # ------------------------------------------------------------
11
+ # 1) Download ERA5 dataset (only if missing/empty)
12
+ # Dataset: dspunituebingen/era5
13
+ # Folder: ERA5_Germany/**
14
+ # ------------------------------------------------------------
15
+ if [ ! -d "$ERA5_PATH" ] || [ -z "$(ls -A "$ERA5_PATH" 2>/dev/null)" ]; then
16
+ echo "[BOOT] Downloading dataset dspunituebingen/era5 -> $DATA_ROOT (patterns: $ERA5_SUBDIR/**)"
17
+ python - <<'PY'
18
+ import os
19
+ from huggingface_hub import snapshot_download
20
+
21
+ token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACEHUB_API_TOKEN")
22
+
23
+ snapshot_download(
24
+ repo_id="dspunituebingen/era5",
25
+ repo_type="dataset",
26
+ local_dir="/app/inference-data",
27
+ allow_patterns=["ERA5_Germany/**"],
28
+ token=token,
29
+ )
30
+
31
+ print("[BOOT] ERA5 data ready at /app/inference-data/ERA5_Germany")
32
+ PY
33
+ fi
34
+
35
+ # ERA5 path used by your FastAPI code via env var
36
+ export ERA5_DIR="$ERA5_PATH"
37
+
38
+ # ------------------------------------------------------------
39
+ # 2) Download model repo (only if missing/empty)
40
+ # Model: dspunituebingen/windproject-model
41
+ # Files are in the repo ROOT (final_model.pkl, feature_imputer.pkl, *.json)
42
+ # ------------------------------------------------------------
43
+ if [ ! -d "$MODEL_ROOT" ] || [ -z "$(ls -A "$MODEL_ROOT" 2>/dev/null)" ]; then
44
+ echo "[BOOT] Downloading model dspunituebingen/windproject-model -> $MODEL_ROOT"
45
+ python - <<'PY'
46
+ import os
47
+ from huggingface_hub import snapshot_download
48
+
49
+ token = os.getenv("HF_TOKEN") or os.getenv("HUGGINGFACEHUB_API_TOKEN")
50
+
51
+ snapshot_download(
52
+ repo_id="dspunituebingen/windproject-model",
53
+ repo_type="model",
54
+ local_dir="/app/model-artifacts",
55
+ allow_patterns=["*.pkl", "*.json", ".gitattributes", "README.md"],
56
+ token=token,
57
+ )
58
+
59
+ print("[BOOT] Model artifacts ready at /app/model-artifacts")
60
+ PY
61
+ fi
62
+
63
+ # Model directory used by your FastAPI code via env var
64
+ # (Your model files are directly in the repo root, so MODEL_DIR == MODEL_ROOT)
65
+ export MODEL_DIR="$MODEL_ROOT"
66
+
67
+ # ------------------------------------------------------------
68
+ # 3) Turbine curves path (try dataset first, then repo fallbacks)
69
+ # ------------------------------------------------------------
70
+ if [ -z "${TURBINE_CURVES:-}" ] && [ -f "$DATA_ROOT/turbine_power_curves.json" ]; then
71
+ export TURBINE_CURVES="$DATA_ROOT/turbine_power_curves.json"
72
+ fi
73
+
74
+ if [ -z "${TURBINE_CURVES:-}" ]; then
75
+ if [ -f "/app/wind-power-climate-ml/data/turbine_power_curves.json" ]; then
76
+ export TURBINE_CURVES="/app/wind-power-climate-ml/data/turbine_power_curves.json"
77
+ elif [ -f "/app/wind-power-climate-ml/Data/turbine_power_curves.json" ]; then
78
+ export TURBINE_CURVES="/app/wind-power-climate-ml/Data/turbine_power_curves.json"
79
+ fi
80
+ fi
81
+
82
+ # ------------------------------------------------------------
83
+ # 4) Debug / sanity checks
84
+ # ------------------------------------------------------------
85
+ echo "[CONFIG] ERA5_DIR=$ERA5_DIR"
86
+ echo "[CONFIG] MODEL_DIR=$MODEL_DIR"
87
+ echo "[CONFIG] TURBINE_CURVES=${TURBINE_CURVES:-<default in code>}"
88
+
89
+ echo "[CHECK] ERA5_DIR listing:"
90
+ ls -lah "$ERA5_DIR" | head -n 50 || true
91
+
92
+ echo "[CHECK] MODEL_DIR listing:"
93
+ ls -lah "$MODEL_DIR" | head -n 50 || true
94
+
95
+ if [ -n "${TURBINE_CURVES:-}" ]; then
96
+ echo "[CHECK] TURBINE_CURVES exists:"
97
+ ls -lah "$TURBINE_CURVES" || true
98
+ fi
99
+
100
+ # ------------------------------------------------------------
101
+ # 5) Start FastAPI (Uvicorn)
102
+ # ------------------------------------------------------------
103
+ cd /app/wind-power-climate-ml
104
+ exec python -m uvicorn website.api:app --app-dir src --host 0.0.0.0 --port 7860 --log-level info
model/costs/capex/capex.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from dataclasses import dataclass
3
+
4
+ # -----------------------
5
+ # Turbine archetypes
6
+ # -----------------------
7
+ @dataclass(frozen=True)
8
+ class TurbineType:
9
+ name: str
10
+ p_mw: float
11
+ rotor_diameter_m: float
12
+
13
+ TURBINE_TYPES = {
14
+ "LOW_WIND": TurbineType("LOW_WIND", 6.0, 170.0),
15
+ "BALANCED": TurbineType("BALANCED", 5.6, 160.0),
16
+ "HIGH_WIND": TurbineType("HIGH_WIND", 4.2, 130.0),
17
+ }
18
+
19
+ # -----------------------
20
+ # BoP costs (2025–2028)
21
+ # -----------------------
22
+ BOP_EUR_PER_KW = 551 # foundations, grid, roads, planning, etc.
23
+
24
+ # -----------------------
25
+ # Engineering functions
26
+ # -----------------------
27
+ def sfl_w_per_m2(p_mw, rotor_diameter_m):
28
+ area = math.pi * (rotor_diameter_m / 2) ** 2
29
+ return (p_mw * 1_000_000) / area
30
+
31
+ def hik_eur_per_kw(p_mw, sfl, hub_height_m):
32
+ """
33
+ HIK regression from German industry data:
34
+ HIK = 1476.19 - 65.62*P - 1.29*SFL + 3.50*NH
35
+ """
36
+ return 1476.19 - 65.62 * p_mw - 1.29 * sfl + 3.50 * hub_height_m
37
+
38
+ # -----------------------
39
+ # Wind park CAPEX
40
+ # -----------------------
41
+ def windpark_capex(n_turbines, turbine_type_key, hub_height_m):
42
+ t = TURBINE_TYPES[turbine_type_key]
43
+
44
+ park_mw = n_turbines * t.p_mw
45
+ sfl = sfl_w_per_m2(t.p_mw, t.rotor_diameter_m)
46
+
47
+ turbine_capex_kw = hik_eur_per_kw(t.p_mw, sfl, hub_height_m)
48
+ total_capex_kw = turbine_capex_kw + BOP_EUR_PER_KW
49
+
50
+ total_capex = park_mw * 1000 * total_capex_kw
51
+
52
+ return {
53
+ "park_mw": park_mw,
54
+ "sfl": sfl,
55
+ "turbine_capex_eur_per_kw": turbine_capex_kw,
56
+ "bop_eur_per_kw": BOP_EUR_PER_KW,
57
+ "total_capex_eur_per_kw": total_capex_kw,
58
+ "total_capex_eur": total_capex
59
+ }
60
+
61
+ # -----------------------
62
+ # Pretty printer
63
+ # -----------------------
64
+ def print_windpark_result(n_turbines, turbine_type, hub_height_m):
65
+ res = windpark_capex(n_turbines, turbine_type, hub_height_m)
66
+ t = TURBINE_TYPES[turbine_type]
67
+
68
+ print(
69
+ f"{turbine_type} ({n_turbines} × {t.p_mw} MW) | "
70
+ f"NH={hub_height_m} m | "
71
+ f"SFL={res['sfl']:.0f} W/m² | "
72
+ f"Turbine={res['turbine_capex_eur_per_kw']:.0f} €/kW | "
73
+ f"BoP={res['bop_eur_per_kw']:.0f} €/kW | "
74
+ f"Total={res['total_capex_eur_per_kw']:.0f} €/kW | "
75
+ f"CAPEX={res['total_capex_eur']/1e6:.1f} M€"
76
+ )
77
+
78
+ # -----------------------
79
+ # Example
80
+ # -----------------------
81
+ if __name__ == "__main__":
82
+ print_windpark_result(12, "BALANCED", 160)
83
+ print_windpark_result(15, "HIGH_WIND", 120)
84
+ print_windpark_result(10, "LOW_WIND", 180)
model/costs/capex/capex_mod.py ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # capex.py
2
+ #
3
+ # Central callable CAPEX module for power_to_profit.py
4
+ # - Accepts turbine type as an INDEX (0,1,2) coming from profit.py
5
+ # - Accepts number of turbines and hub height
6
+ # - Returns a dict including keys used by power_to_profit.py:
7
+ # - park_mw
8
+ # - total_capex_eur
9
+ #
10
+ # Mapping (you can change ordering if you prefer):
11
+ # 0 -> LOW_WIND
12
+ # 1 -> BALANCED
13
+ # 2 -> HIGH_WIND
14
+
15
+ import math
16
+ from dataclasses import dataclass
17
+ from typing import Dict, Any
18
+
19
+
20
+ # -----------------------
21
+ # Turbine archetypes
22
+ # -----------------------
23
+ @dataclass(frozen=True)
24
+ class TurbineType:
25
+ name: str
26
+ p_mw: float
27
+ rotor_diameter_m: float
28
+
29
+
30
+ TURBINE_TYPES_BY_KEY: Dict[str, TurbineType] = {
31
+ "LOW_WIND": TurbineType("LOW_WIND", 6.0, 170.0),
32
+ "BALANCED": TurbineType("BALANCED", 5.6, 160.0),
33
+ "HIGH_WIND": TurbineType("HIGH_WIND", 4.2, 130.0),
34
+ }
35
+
36
+ # Index mapping expected by profit.py
37
+ TURBINE_TYPE_INDEX_MAP: Dict[int, str] = {
38
+ 0: "LOW_WIND",
39
+ 1: "BALANCED",
40
+ 2: "HIGH_WIND",
41
+ }
42
+
43
+ # -----------------------
44
+ # BoP costs (2025–2028)
45
+ # -----------------------
46
+ BOP_EUR_PER_KW = 551.0 # foundations, grid, roads, planning, etc.
47
+
48
+
49
+ # -----------------------
50
+ # Engineering functions
51
+ # -----------------------
52
+ def sfl_w_per_m2(p_mw: float, rotor_diameter_m: float) -> float:
53
+ """Specific rated power density (W/m²) based on rotor swept area."""
54
+ area = math.pi * (rotor_diameter_m / 2.0) ** 2
55
+ return (p_mw * 1_000_000.0) / area
56
+
57
+
58
+ def hik_eur_per_kw(p_mw: float, sfl: float, hub_height_m: float) -> float:
59
+ """
60
+ HIK regression from German industry data:
61
+ HIK = 1476.19 - 65.62*P - 1.29*SFL + 3.50*NH
62
+ """
63
+ return 1476.19 - 65.62 * p_mw - 1.29 * sfl + 3.50 * hub_height_m
64
+
65
+
66
+ # -----------------------
67
+ # Public API used by power_to_profit.py
68
+ # -----------------------
69
+ def windpark_capex(
70
+ *,
71
+ n_turbines: int,
72
+ turbine_type_id: int,
73
+ hub_height_m: float,
74
+ ) -> Dict[str, Any]:
75
+ """
76
+ Compute wind park CAPEX based on turbine archetype + hub height.
77
+
78
+ Parameters
79
+ ----------
80
+ n_turbines : int
81
+ Number of turbines in the park.
82
+ turbine_type_id : int
83
+ Turbine type index coming from profit.py:
84
+ 0 -> LOW_WIND
85
+ 1 -> BALANCED
86
+ 2 -> HIGH_WIND
87
+ hub_height_m : float
88
+ Hub height in meters.
89
+
90
+ Returns
91
+ -------
92
+ dict including:
93
+ - park_mw
94
+ - total_capex_eur
95
+ plus breakdown fields.
96
+ """
97
+ if not isinstance(n_turbines, int) or n_turbines <= 0:
98
+ raise ValueError("n_turbines must be a positive integer.")
99
+
100
+ try:
101
+ turbine_type_id = int(turbine_type_id)
102
+ except Exception as e:
103
+ raise ValueError("turbine_type_id must be an integer (0,1,2).") from e
104
+
105
+ if turbine_type_id not in TURBINE_TYPE_INDEX_MAP:
106
+ raise ValueError(
107
+ f"Unknown turbine_type_id={turbine_type_id}. "
108
+ f"Valid: {sorted(TURBINE_TYPE_INDEX_MAP.keys())} "
109
+ f"(0=LOW_WIND, 1=BALANCED, 2=HIGH_WIND)"
110
+ )
111
+
112
+ hub_height_m = float(hub_height_m)
113
+ if hub_height_m <= 0:
114
+ raise ValueError("hub_height_m must be > 0.")
115
+
116
+ turbine_key = TURBINE_TYPE_INDEX_MAP[turbine_type_id]
117
+ t = TURBINE_TYPES_BY_KEY[turbine_key]
118
+
119
+ park_mw = float(n_turbines) * float(t.p_mw)
120
+ sfl = sfl_w_per_m2(t.p_mw, t.rotor_diameter_m)
121
+
122
+ turbine_capex_eur_per_kw = hik_eur_per_kw(t.p_mw, sfl, hub_height_m)
123
+ total_capex_eur_per_kw = float(turbine_capex_eur_per_kw) + float(BOP_EUR_PER_KW)
124
+
125
+ total_capex_eur = park_mw * 1000.0 * total_capex_eur_per_kw
126
+
127
+ return {
128
+ "turbine_type_id": int(turbine_type_id),
129
+ "turbine_type": t.name,
130
+ "n_turbines": int(n_turbines),
131
+ "hub_height_m": float(hub_height_m),
132
+ "park_mw": float(park_mw),
133
+ "rotor_diameter_m": float(t.rotor_diameter_m),
134
+ "sfl": float(sfl),
135
+ "turbine_capex_eur_per_kw": float(turbine_capex_eur_per_kw),
136
+ "bop_eur_per_kw": float(BOP_EUR_PER_KW),
137
+ "total_capex_eur_per_kw": float(total_capex_eur_per_kw),
138
+ "total_capex_eur": float(total_capex_eur),
139
+ }
140
+
141
+
142
+ # -----------------------
143
+ # Convenience helper (optional)
144
+ # -----------------------
145
+ def print_windpark_result(n_turbines: int, turbine_type_id: int, hub_height_m: float) -> None:
146
+ res = windpark_capex(
147
+ n_turbines=n_turbines,
148
+ turbine_type_id=turbine_type_id,
149
+ hub_height_m=hub_height_m,
150
+ )
151
+ print(
152
+ f"Type={res['turbine_type']} (id={res['turbine_type_id']}) | "
153
+ f"{res['n_turbines']} × {TURBINE_TYPES_BY_KEY[res['turbine_type']].p_mw} MW | "
154
+ f"NH={res['hub_height_m']:.0f} m | "
155
+ f"SFL={res['sfl']:.0f} W/m² | "
156
+ f"Turbine={res['turbine_capex_eur_per_kw']:.0f} €/kW | "
157
+ f"BoP={res['bop_eur_per_kw']:.0f} €/kW | "
158
+ f"Total={res['total_capex_eur_per_kw']:.0f} €/kW | "
159
+ f"CAPEX={res['total_capex_eur']/1e6:.1f} M€"
160
+ )
161
+
162
+
163
+ # -----------------------
164
+ # Example
165
+ # -----------------------
166
+ if __name__ == "__main__":
167
+ print_windpark_result(12, 1, 160) # BALANCED
168
+ print_windpark_result(15, 2, 120) # HIGH_WIND
169
+ print_windpark_result(10, 0, 180) # LOW_WIND
model/costs/capex/other_costs.csv ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ category,eur_per_kw,share
2
+ Planning_and_development,163,0.30
3
+ Grid_connection,133,0.24
4
+ Infrastructure_and_foundations,119,0.22
5
+ Compensation,35,0.06
6
+ Other,101,0.18
7
+ Total,551,1.00
model/costs/finance/finance.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+ def financing_model(
4
+ capex_eur,
5
+ equity_share=0.15,
6
+ debt_rate=0.045,
7
+ equity_return=0.08,
8
+ debt_tenor_years=20
9
+ ):
10
+ """
11
+ Simple project finance model for a wind park.
12
+ """
13
+
14
+ debt_share = 1 - equity_share
15
+
16
+ equity = capex_eur * equity_share
17
+ debt = capex_eur * debt_share
18
+
19
+ # annuity loan formula
20
+ r = debt_rate
21
+ n = debt_tenor_years
22
+ annuity_factor = r * (1 + r)**n / ((1 + r)**n - 1)
23
+ annual_debt_service = debt * annuity_factor
24
+
25
+ # total debt repaid
26
+ total_debt_repayment = annual_debt_service * n
27
+ total_interest = total_debt_repayment - debt
28
+
29
+ # Weighted Average Cost of Capital
30
+ wacc = equity_share * equity_return + debt_share * debt_rate
31
+
32
+ return {
33
+ "capex_eur": capex_eur,
34
+ "equity_share": equity_share,
35
+ "debt_share": debt_share,
36
+ "equity_eur": equity,
37
+ "debt_eur": debt,
38
+ "annual_debt_service_eur": annual_debt_service,
39
+ "total_interest_paid_eur": total_interest,
40
+ "wacc": wacc
41
+ }
42
+
43
+ # -------------------------------
44
+ # Realistic German wind park example
45
+ # -------------------------------
46
+ if __name__ == "__main__":
47
+ capex = 80_000_000 # 80 million € project
48
+ equity_share = 0.15 # 15% equity (aggressive but bankable)
49
+ debt_rate = 0.045 # 4.5% KfW-270 loan
50
+ equity_return = 0.085 # 8.5% equity target
51
+ tenor = 18 # 18-year loan
52
+
53
+ result = financing_model(
54
+ capex_eur=capex,
55
+ equity_share=equity_share,
56
+ debt_rate=debt_rate,
57
+ equity_return=equity_return,
58
+ debt_tenor_years=tenor
59
+ )
60
+
61
+ print("---- German Onshore Wind Financing ----")
62
+ print(f"CAPEX: {result['capex_eur']/1e6:.1f} M€")
63
+ print(f"Equity (15%): {result['equity_eur']/1e6:.1f} M€")
64
+ print(f"Debt (85%): {result['debt_eur']/1e6:.1f} M€")
65
+ print(f"Annual debt svc: {result['annual_debt_service_eur']/1e6:.2f} M€ / year")
66
+ print(f"Total interest: {result['total_interest_paid_eur']/1e6:.1f} M€ over {tenor} years")
67
+ print(f"WACC: {result['wacc']*100:.2f} %")
model/costs/finance/finance_mod.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # finance.py
2
+ #
3
+ # Central callable finance module for power_to_profit.py
4
+ # - Inputs come from profit.py:
5
+ # - capex_eur (from capex_res["total_capex_eur"])
6
+ # - equity_eur (absolute € amount; we compute equity_share)
7
+ # - debt_rate, equity_return, debt_tenor_years
8
+ # - forecast_months (project horizon; default 240)
9
+ # - Outputs include:
10
+ # - equity_share_derived
11
+ # - annual_debt_service_eur
12
+ # - debt_service_yearly_df (project_year schedule aligned to horizon)
13
+ # - wacc
14
+ #
15
+ # Notes:
16
+ # - We keep the debt service as an ANNUITY yearly payment (like your current model).
17
+ # - Horizon alignment: we build project_year 1..ceil(forecast_months/12) and set payments
18
+ # to 0 after debt_tenor_years.
19
+
20
+ import math
21
+ import pandas as pd
22
+
23
+
24
+ def financing_model(
25
+ *,
26
+ capex_eur: float,
27
+ equity_eur: float | None = None,
28
+ # If equity_eur is None, you can still pass equity_share directly
29
+ equity_share: float | None = None,
30
+ debt_rate: float = 0.045,
31
+ equity_return: float = 0.08,
32
+ debt_tenor_years: int = 20,
33
+ forecast_months: int = 240,
34
+ ) -> dict:
35
+ """
36
+ Simple project finance model for a wind park.
37
+
38
+ Parameters
39
+ ----------
40
+ capex_eur : float
41
+ Total project CAPEX in €.
42
+ equity_eur : float | None
43
+ Absolute equity amount in €. If provided, equity_share is derived as equity_eur/capex_eur.
44
+ equity_share : float | None
45
+ Optional direct equity share (0..1). Used only if equity_eur is None.
46
+ debt_rate : float
47
+ Annual debt interest rate (e.g., 0.045).
48
+ equity_return : float
49
+ Annual equity target return (used for WACC).
50
+ debt_tenor_years : int
51
+ Loan tenor in years (annuity payments).
52
+ forecast_months : int
53
+ Project horizon in months (default 240 = 20y). Used to create aligned debt schedule.
54
+
55
+ Returns
56
+ -------
57
+ dict with keys used by power_to_profit.py plus schedule:
58
+ - annual_debt_service_eur
59
+ - wacc
60
+ - equity_share_derived
61
+ - debt_service_yearly_df (project_year, debt_service_eur)
62
+ - plus breakdown fields (equity_eur, debt_eur, total_interest_paid_eur, etc.)
63
+ """
64
+
65
+ capex_eur = float(capex_eur)
66
+ if capex_eur <= 0:
67
+ raise ValueError("capex_eur must be > 0")
68
+
69
+ forecast_months = int(forecast_months)
70
+ if forecast_months <= 0:
71
+ raise ValueError("forecast_months must be > 0")
72
+
73
+ debt_rate = float(debt_rate)
74
+ if debt_rate < 0:
75
+ raise ValueError("debt_rate must be >= 0")
76
+
77
+ equity_return = float(equity_return)
78
+
79
+ debt_tenor_years = int(debt_tenor_years)
80
+ if debt_tenor_years <= 0:
81
+ raise ValueError("debt_tenor_years must be > 0")
82
+
83
+ # -----------------------
84
+ # Derive equity share
85
+ # -----------------------
86
+ if equity_eur is not None:
87
+ equity_eur = float(equity_eur)
88
+ if equity_eur < 0:
89
+ raise ValueError("equity_eur must be >= 0")
90
+ equity_share_derived = equity_eur / capex_eur
91
+ else:
92
+ if equity_share is None:
93
+ # default: 15% equity if nothing provided
94
+ equity_share_derived = 0.15
95
+ else:
96
+ equity_share_derived = float(equity_share)
97
+
98
+ # clamp to [0, 1)
99
+ equity_share_derived = max(0.0, min(equity_share_derived, 0.999999))
100
+
101
+ debt_share = 1.0 - equity_share_derived
102
+
103
+ equity_eur_final = capex_eur * equity_share_derived
104
+ debt_eur = capex_eur * debt_share
105
+
106
+ # -----------------------
107
+ # Annuity debt service (annual)
108
+ # -----------------------
109
+ r = debt_rate
110
+ n = debt_tenor_years
111
+
112
+ if debt_eur <= 0:
113
+ annual_debt_service_eur = 0.0
114
+ total_interest_paid_eur = 0.0
115
+ else:
116
+ if r == 0.0:
117
+ annual_debt_service_eur = debt_eur / n
118
+ else:
119
+ annuity_factor = r * (1.0 + r) ** n / ((1.0 + r) ** n - 1.0)
120
+ annual_debt_service_eur = debt_eur * annuity_factor
121
+
122
+ total_debt_repayment = annual_debt_service_eur * n
123
+ total_interest_paid_eur = total_debt_repayment - debt_eur
124
+
125
+ # -----------------------
126
+ # WACC (simple weighted blend)
127
+ # -----------------------
128
+ wacc = equity_share_derived * equity_return + debt_share * debt_rate
129
+
130
+ # -----------------------
131
+ # Build aligned debt schedule by project year
132
+ # -----------------------
133
+ horizon_years = int(math.ceil(forecast_months / 12.0))
134
+ years = list(range(1, horizon_years + 1))
135
+
136
+ debt_service = [
137
+ float(annual_debt_service_eur) if y <= debt_tenor_years else 0.0
138
+ for y in years
139
+ ]
140
+
141
+ debt_service_yearly_df = pd.DataFrame({
142
+ "project_year": years,
143
+ "debt_service_eur": debt_service,
144
+ })
145
+
146
+ return {
147
+ "capex_eur": float(capex_eur),
148
+ "equity_share_derived": float(equity_share_derived),
149
+ "debt_share": float(debt_share),
150
+ "equity_eur": float(equity_eur_final),
151
+ "debt_eur": float(debt_eur),
152
+ "debt_rate": float(debt_rate),
153
+ "equity_return": float(equity_return),
154
+ "debt_tenor_years": int(debt_tenor_years),
155
+ "annual_debt_service_eur": float(annual_debt_service_eur),
156
+ "total_interest_paid_eur": float(total_interest_paid_eur),
157
+ "wacc": float(wacc),
158
+ "forecast_months": int(forecast_months),
159
+ "horizon_years": int(horizon_years),
160
+ "debt_service_yearly_df": debt_service_yearly_df,
161
+ }
162
+
163
+
164
+ # -------------------------------
165
+ # Standalone test / example
166
+ # -------------------------------
167
+ if __name__ == "__main__":
168
+ capex = 80_000_000
169
+ equity_eur = 12_000_000
170
+ debt_rate = 0.045
171
+ equity_return = 0.085
172
+ tenor = 18
173
+ forecast_months = 240
174
+
175
+ result = financing_model(
176
+ capex_eur=capex,
177
+ equity_eur=equity_eur,
178
+ debt_rate=debt_rate,
179
+ equity_return=equity_return,
180
+ debt_tenor_years=tenor,
181
+ forecast_months=forecast_months,
182
+ )
183
+
184
+ print("---- German Onshore Wind Financing ----")
185
+ print(f"CAPEX: {result['capex_eur']/1e6:.1f} M€")
186
+ print(f"Equity (input): {equity_eur/1e6:.1f} M€")
187
+ print(f"Equity share: {result['equity_share_derived']*100:.1f} %")
188
+ print(f"Debt: {result['debt_eur']/1e6:.1f} M€")
189
+ print(f"Annual debt service: {result['annual_debt_service_eur']/1e6:.2f} M€ / year")
190
+ print(f"Total interest: {result['total_interest_paid_eur']/1e6:.1f} M€ over {tenor} years")
191
+ print(f"WACC: {result['wacc']*100:.2f} %")
192
+ print(result["debt_service_yearly_df"].head())
model/costs/opex/opex.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ decade,maintenance,lease,operations,insurance,marketing,decommissioning,other,total_eur_per_kw_year
2
+ 1,15,19,5,4,1,3,6,53
3
+ 2,14,20,5,4,1,3,6,55
model/costs/opex/opex.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ OPEX_DECADE_1 = 53 # €/kW/year (years 1–10)
4
+ OPEX_DECADE_2 = 55 # €/kW/year (years 11–20)
5
+
6
+ def windpark_opex_timeseries(park_mw, years=20):
7
+ """
8
+ Returns a DataFrame with yearly O&M costs and total lifetime OPEX.
9
+ """
10
+ park_kw = park_mw * 1000
11
+ data = []
12
+
13
+ for year in range(1, years + 1):
14
+ if year <= 10:
15
+ opex_per_kw = OPEX_DECADE_1
16
+ else:
17
+ opex_per_kw = OPEX_DECADE_2
18
+
19
+ annual_cost = park_kw * opex_per_kw
20
+
21
+ data.append({
22
+ "year": year,
23
+ "opex_eur_per_kw": opex_per_kw,
24
+ "annual_opex_eur": annual_cost
25
+ })
26
+
27
+ df = pd.DataFrame(data)
28
+ total = df["annual_opex_eur"].sum()
29
+
30
+ return df, total
31
+
32
+ df, total = windpark_opex_timeseries(park_mw=50)
33
+
34
+ print(df)
35
+ print("Total OPEX over 20 years:", total/1e6, "million €")
model/costs/opex/opex_mod.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # opex.py
2
+ #
3
+ # Central callable OPEX module for power_to_profit.py
4
+ # - Inputs come from profit.py:
5
+ # - park_mw (already computed from capex_res["park_mw"])
6
+ # - forecast_months (typically 240 for 20 years)
7
+ # - Produces monthly + project-year OPEX aligned to the same 12-month blocks as revenue.
8
+
9
+ import pandas as pd
10
+
11
+ # €/kW/year (real terms)
12
+ OPEX_DECADE_1 = 53.0 # years 1–10
13
+ OPEX_DECADE_2 = 55.0 # years 11–20
14
+
15
+
16
+ def windpark_opex_timeseries(
17
+ *,
18
+ park_mw: float,
19
+ forecast_months: int = 240,
20
+ ) -> tuple[pd.DataFrame, float]:
21
+ """
22
+ Compute OPEX time series aligned to project months/years.
23
+
24
+ Parameters
25
+ ----------
26
+ park_mw : float
27
+ Park capacity in MW.
28
+ forecast_months : int
29
+ Number of months in horizon (default 240 = 20y).
30
+
31
+ Returns
32
+ -------
33
+ yearly_df : DataFrame with columns:
34
+ - project_year (1..ceil(forecast_months/12))
35
+ - annual_opex_eur
36
+ - opex_eur_per_kw_year (rate applied for that project year)
37
+ total_opex_eur : float
38
+ Total OPEX over the horizon (sum of monthly, equivalently yearly).
39
+ """
40
+ park_mw = float(park_mw)
41
+ if park_mw <= 0:
42
+ raise ValueError("park_mw must be > 0")
43
+
44
+ forecast_months = int(forecast_months)
45
+ if forecast_months <= 0:
46
+ raise ValueError("forecast_months must be > 0")
47
+
48
+ park_kw = park_mw * 1000.0
49
+
50
+ # Build monthly series (project month 1..N)
51
+ m = pd.DataFrame({"project_month": range(1, forecast_months + 1)})
52
+ m["project_year"] = ((m["project_month"] - 1) // 12) + 1 # 1..20 (for 240)
53
+
54
+ # Choose rate per project year (decade 1 vs decade 2)
55
+ m["opex_eur_per_kw_year"] = m["project_year"].apply(
56
+ lambda y: OPEX_DECADE_1 if y <= 10 else OPEX_DECADE_2
57
+ ).astype(float)
58
+
59
+ # Convert annual €/kW/year into monthly €:
60
+ # monthly_cost = park_kw * (€/kW/year) / 12
61
+ m["monthly_opex_eur"] = park_kw * m["opex_eur_per_kw_year"] / 12.0
62
+
63
+ total_opex_eur = float(m["monthly_opex_eur"].sum())
64
+
65
+ # Aggregate to project-year (sum of months in that year; last year might be partial if forecast_months not multiple of 12)
66
+ yearly_df = (
67
+ m.groupby("project_year", as_index=False)
68
+ .agg(
69
+ annual_opex_eur=("monthly_opex_eur", "sum"),
70
+ opex_eur_per_kw_year=("opex_eur_per_kw_year", "first"),
71
+ months_in_year=("monthly_opex_eur", "size"),
72
+ )
73
+ .sort_values("project_year")
74
+ .reset_index(drop=True)
75
+ )
76
+
77
+ return yearly_df, total_opex_eur
78
+
79
+
80
+ # -----------------------
81
+ # Optional standalone test
82
+ # -----------------------
83
+ if __name__ == "__main__":
84
+ yearly, total = windpark_opex_timeseries(park_mw=50, forecast_months=240)
85
+ print(yearly.head(12))
86
+ print("Total OPEX:", total / 1e6, "million €")
model/costs/planning/merge.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ # Load the three Bundesland tables
4
+ planning = pd.read_csv("planning_phase_bundesland.csv")
5
+ permitting = pd.read_csv("permitting_phase_bundesland.csv")
6
+ total = pd.read_csv("total_bundesland.csv")
7
+
8
+ # Remove rows without projects or without mean
9
+ planning = planning.dropna(subset=["mean_eur_per_kw", "projects"])
10
+ permitting = permitting.dropna(subset=["mean_eur_per_kw", "projects"])
11
+ total = total.dropna(subset=["mean_eur_per_kw", "projects"])
12
+
13
+ def weighted_mean(df):
14
+ df = df.dropna(subset=["mean_eur_per_kw", "projects"])
15
+ return (df["mean_eur_per_kw"] * df["projects"]).sum() / df["projects"].sum()
16
+
17
+ # Compute national values
18
+ national_planning = weighted_mean(planning)
19
+ national_permitting = weighted_mean(permitting)
20
+ national_total = weighted_mean(total)
21
+
22
+ # Derive precheck
23
+ national_precheck = national_total - national_planning - national_permitting
24
+
25
+ # Create output table
26
+ national_costs = pd.DataFrame({
27
+ "phase": ["Vorpruefung", "Planung", "Genehmigung", "Total_bis_Genehmigung"],
28
+ "mean_eur_per_kw": [
29
+ national_precheck,
30
+ national_planning,
31
+ national_permitting,
32
+ national_total
33
+ ]
34
+ })
35
+
36
+ national_costs.to_csv("national_wind_project_development_costs.csv", index=False)
37
+
38
+ print(national_costs)
model/costs/planning/national_project_development_costs.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ phase,weighted_mean_eur_per_kw,projects_used
2
+ Planning,29.03921568627451,204
3
+ Permitting,29.986486486486488,148
4
+ Total_to_Permit,70.06849315068493,146
model/costs/planning/national_wind_project_development_costs.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ phase,mean_eur_per_kw
2
+ Vorpruefung,11.042790977923932
3
+ Planung,29.03921568627451
4
+ Genehmigung,29.986486486486488
5
+ Total_bis_Genehmigung,70.06849315068493
model/costs/planning/permitting_phase_bundesland.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ bundesland,projects,min_eur_per_kw,max_eur_per_kw,mean_eur_per_kw
2
+ Baden-Wuerttemberg,0,,,
3
+ Bayern,13,15,117,47
4
+ Brandenburg,11,21,55,38
5
+ Bremen,0,,,
6
+ Hessen,4,16,34,25
7
+ Mecklenburg-Vorpommern,2,7,52,30
8
+ Niedersachsen,17,12,60,24
9
+ Nordrhein-Westfalen,6,6,10,8
10
+ Rheinland-Pfalz,16,9,60,23
11
+ Saarland,1,62,62,62
12
+ Sachsen,3,14,53,30
13
+ Sachsen-Anhalt,1,53,53,53
14
+ Schleswig-Holstein,0,,,
15
+ Thueringen,0,,,
16
+ Gesamt,74,6,117,30
model/costs/planning/planning_phase_bundesland.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ bundesland,projects,min_eur_per_kw,max_eur_per_kw,mean_eur_per_kw
2
+ Baden-Wuerttemberg,1,100,100,100
3
+ Bayern,14,13,124,55
4
+ Brandenburg,12,15,72,37
5
+ Bremen,0,,,
6
+ Hessen,12,5,69,21
7
+ Mecklenburg-Vorpommern,2,18,48,33
8
+ Niedersachsen,18,9,69,29
9
+ Nordrhein-Westfalen,6,7,24,17
10
+ Rheinland-Pfalz,17,5,40,15
11
+ Saarland,1,40,40,40
12
+ Sachsen,8,4,41,20
13
+ Sachsen-Anhalt,5,6,69,23
14
+ Schleswig-Holstein,1,5,5,5
15
+ Thueringen,5,5,64,27
16
+ Gesamt,102,4,124,29
model/costs/planning/total_bundesland.csv ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ bundesland,projects,min_eur_per_kw,max_eur_per_kw,mean_eur_per_kw
2
+ Baden-Wuerttemberg,0,,,
3
+ Bayern,13,50,234,123
4
+ Brandenburg,11,44,134,85
5
+ Bremen,0,,,
6
+ Hessen,4,38,82,56
7
+ Mecklenburg-Vorpommern,2,36,104,70
8
+ Niedersachsen,17,23,140,59
9
+ Nordrhein-Westfalen,5,17,35,28
10
+ Rheinland-Pfalz,16,17,120,46
11
+ Saarland,1,134,134,134
12
+ Sachsen,2,28,44,36
13
+ Sachsen-Anhalt,1,67,67,67
14
+ Schleswig-Holstein,0,,,
15
+ Thueringen,0,,,
16
+ Gesamt,74,17,234,70
model/park_gross_mwh_monthly_mock_2015_2046.csv ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ date,park_capacity_mw,mwh_gross
2
+ 2015-01-01,50.0,14387.24
3
+ 2015-02-01,50.0,12107.57
4
+ 2015-03-01,50.0,12850.37
5
+ 2015-04-01,50.0,11438.82
6
+ 2015-05-01,50.0,10472.28
7
+ 2015-06-01,50.0,9019.09
8
+ 2015-07-01,50.0,8876.66
9
+ 2015-08-01,50.0,9514.59
10
+ 2015-09-01,50.0,10141.8
11
+ 2015-10-01,50.0,11848.71
12
+ 2015-11-01,50.0,12366.89
13
+ 2015-12-01,50.0,14314.35
14
+ 2016-01-01,50.0,13643.95
15
+ 2016-02-01,50.0,12054.36
16
+ 2016-03-01,50.0,12047.31
17
+ 2016-04-01,50.0,10364.25
18
+ 2016-05-01,50.0,9977.09
19
+ 2016-06-01,50.0,8626.77
20
+ 2016-07-01,50.0,8542.72
21
+ 2016-08-01,50.0,8848.35
22
+ 2016-09-01,50.0,8827.63
23
+ 2016-10-01,50.0,10744.48
24
+ 2016-11-01,50.0,11576.21
25
+ 2016-12-01,50.0,12973.94
26
+ 2017-01-01,50.0,14705.81
27
+ 2017-02-01,50.0,13159.2
28
+ 2017-03-01,50.0,12471.5
29
+ 2017-04-01,50.0,11554.11
30
+ 2017-05-01,50.0,10125.46
31
+ 2017-06-01,50.0,9295.0
32
+ 2017-07-01,50.0,9281.69
33
+ 2017-08-01,50.0,9637.22
34
+ 2017-09-01,50.0,10282.34
35
+ 2017-10-01,50.0,12113.0
36
+ 2017-11-01,50.0,12671.76
37
+ 2017-12-01,50.0,14225.79
38
+ 2018-01-01,50.0,15295.5
39
+ 2018-02-01,50.0,12592.58
40
+ 2018-03-01,50.0,12383.39
41
+ 2018-04-01,50.0,10907.28
42
+ 2018-05-01,50.0,10428.07
43
+ 2018-06-01,50.0,9583.02
44
+ 2018-07-01,50.0,9328.28
45
+ 2018-08-01,50.0,9721.26
46
+ 2018-09-01,50.0,9994.44
47
+ 2018-10-01,50.0,11954.61
48
+ 2018-11-01,50.0,13119.51
49
+ 2018-12-01,50.0,14372.47
50
+ 2019-01-01,50.0,12983.11
51
+ 2019-02-01,50.0,10662.15
52
+ 2019-03-01,50.0,10938.85
53
+ 2019-04-01,50.0,9586.89
54
+ 2019-05-01,50.0,8880.27
55
+ 2019-06-01,50.0,8228.35
56
+ 2019-07-01,50.0,7865.6
57
+ 2019-08-01,50.0,8183.19
58
+ 2019-09-01,50.0,8821.07
59
+ 2019-10-01,50.0,10356.07
60
+ 2019-11-01,50.0,11281.52
61
+ 2019-12-01,50.0,12423.3
62
+ 2020-01-01,50.0,13053.7
63
+ 2020-02-01,50.0,11617.85
64
+ 2020-03-01,50.0,10838.87
65
+ 2020-04-01,50.0,9576.8
66
+ 2020-05-01,50.0,9131.13
67
+ 2020-06-01,50.0,8121.55
68
+ 2020-07-01,50.0,8334.6
69
+ 2020-08-01,50.0,8215.14
70
+ 2020-09-01,50.0,8874.89
71
+ 2020-10-01,50.0,10960.69
72
+ 2020-11-01,50.0,11296.22
73
+ 2020-12-01,50.0,13147.47
74
+ 2021-01-01,50.0,13785.73
75
+ 2021-02-01,50.0,11972.09
76
+ 2021-03-01,50.0,11897.89
77
+ 2021-04-01,50.0,10630.16
78
+ 2021-05-01,50.0,10456.95
79
+ 2021-06-01,50.0,8515.39
80
+ 2021-07-01,50.0,8949.82
81
+ 2021-08-01,50.0,9123.17
82
+ 2021-09-01,50.0,9457.81
83
+ 2021-10-01,50.0,10825.65
84
+ 2021-11-01,50.0,12275.01
85
+ 2021-12-01,50.0,13578.99
86
+ 2022-01-01,50.0,13917.99
87
+ 2022-02-01,50.0,11747.02
88
+ 2022-03-01,50.0,12508.32
89
+ 2022-04-01,50.0,10390.54
90
+ 2022-05-01,50.0,9634.66
91
+ 2022-06-01,50.0,8798.96
92
+ 2022-07-01,50.0,8666.34
93
+ 2022-08-01,50.0,9187.65
94
+ 2022-09-01,50.0,9619.14
95
+ 2022-10-01,50.0,11146.24
96
+ 2022-11-01,50.0,12460.34
97
+ 2022-12-01,50.0,12966.97
98
+ 2023-01-01,50.0,13714.3
99
+ 2023-02-01,50.0,11546.07
100
+ 2023-03-01,50.0,11932.77
101
+ 2023-04-01,50.0,10150.43
102
+ 2023-05-01,50.0,10247.37
103
+ 2023-06-01,50.0,8794.9
104
+ 2023-07-01,50.0,8325.58
105
+ 2023-08-01,50.0,8658.53
106
+ 2023-09-01,50.0,9582.74
107
+ 2023-10-01,50.0,11437.28
108
+ 2023-11-01,50.0,12798.86
109
+ 2023-12-01,50.0,14792.43
110
+ 2024-01-01,50.0,13516.61
111
+ 2024-02-01,50.0,11410.27
112
+ 2024-03-01,50.0,10790.85
113
+ 2024-04-01,50.0,10190.33
114
+ 2024-05-01,50.0,9367.07
115
+ 2024-06-01,50.0,8348.38
116
+ 2024-07-01,50.0,8163.49
117
+ 2024-08-01,50.0,8490.93
118
+ 2024-09-01,50.0,9354.21
119
+ 2024-10-01,50.0,10702.65
120
+ 2024-11-01,50.0,11474.82
121
+ 2024-12-01,50.0,12584.86
122
+ 2025-01-01,50.0,13778.79
123
+ 2025-02-01,50.0,12142.34
124
+ 2025-03-01,50.0,12507.09
125
+ 2025-04-01,50.0,11567.87
126
+ 2025-05-01,50.0,10474.09
127
+ 2025-06-01,50.0,9457.2
128
+ 2025-07-01,50.0,8901.56
129
+ 2025-08-01,50.0,8936.54
130
+ 2025-09-01,50.0,9564.71
131
+ 2025-10-01,50.0,11323.8
132
+ 2025-11-01,50.0,13328.93
133
+ 2025-12-01,50.0,13766.25
134
+ 2026-01-01,50.0,14748.42
135
+ 2026-02-01,50.0,11888.24
136
+ 2026-03-01,50.0,12769.88
137
+ 2026-04-01,50.0,11019.33
138
+ 2026-05-01,50.0,10297.59
139
+ 2026-06-01,50.0,9098.52
140
+ 2026-07-01,50.0,8785.44
141
+ 2026-08-01,50.0,9311.53
142
+ 2026-09-01,50.0,9634.33
143
+ 2026-10-01,50.0,11056.94
144
+ 2026-11-01,50.0,11947.98
145
+ 2026-12-01,50.0,14068.67
146
+ 2027-01-01,50.0,14500.96
147
+ 2027-02-01,50.0,11815.79
148
+ 2027-03-01,50.0,11912.61
149
+ 2027-04-01,50.0,10573.43
150
+ 2027-05-01,50.0,10346.92
151
+ 2027-06-01,50.0,8824.51
152
+ 2027-07-01,50.0,8517.88
153
+ 2027-08-01,50.0,9136.23
154
+ 2027-09-01,50.0,9520.95
155
+ 2027-10-01,50.0,11555.94
156
+ 2027-11-01,50.0,12022.43
157
+ 2027-12-01,50.0,12974.65
158
+ 2028-01-01,50.0,13930.04
159
+ 2028-02-01,50.0,13428.58
160
+ 2028-03-01,50.0,13191.98
161
+ 2028-04-01,50.0,10940.09
162
+ 2028-05-01,50.0,10326.61
163
+ 2028-06-01,50.0,9601.42
164
+ 2028-07-01,50.0,8748.0
165
+ 2028-08-01,50.0,9028.79
166
+ 2028-09-01,50.0,10052.88
167
+ 2028-10-01,50.0,11453.29
168
+ 2028-11-01,50.0,12543.05
169
+ 2028-12-01,50.0,14062.85
170
+ 2029-01-01,50.0,14165.43
171
+ 2029-02-01,50.0,12413.74
172
+ 2029-03-01,50.0,12142.06
173
+ 2029-04-01,50.0,10823.7
174
+ 2029-05-01,50.0,9464.78
175
+ 2029-06-01,50.0,8866.75
176
+ 2029-07-01,50.0,8514.31
177
+ 2029-08-01,50.0,8629.15
178
+ 2029-09-01,50.0,9270.29
179
+ 2029-10-01,50.0,11077.11
180
+ 2029-11-01,50.0,12443.47
181
+ 2029-12-01,50.0,13100.05
182
+ 2030-01-01,50.0,13080.46
183
+ 2030-02-01,50.0,10938.48
184
+ 2030-03-01,50.0,11173.61
185
+ 2030-04-01,50.0,10193.15
186
+ 2030-05-01,50.0,9550.01
187
+ 2030-06-01,50.0,8607.05
188
+ 2030-07-01,50.0,8102.7
189
+ 2030-08-01,50.0,8172.45
190
+ 2030-09-01,50.0,8813.16
191
+ 2030-10-01,50.0,10503.16
192
+ 2030-11-01,50.0,11345.78
193
+ 2030-12-01,50.0,12300.27
194
+ 2031-01-01,50.0,13895.85
195
+ 2031-02-01,50.0,11851.1
196
+ 2031-03-01,50.0,12870.28
197
+ 2031-04-01,50.0,11084.33
198
+ 2031-05-01,50.0,9711.16
199
+ 2031-06-01,50.0,8699.48
200
+ 2031-07-01,50.0,8253.4
201
+ 2031-08-01,50.0,8694.29
202
+ 2031-09-01,50.0,9498.05
203
+ 2031-10-01,50.0,11457.48
204
+ 2031-11-01,50.0,11706.28
205
+ 2031-12-01,50.0,13217.65
206
+ 2032-01-01,50.0,12077.99
207
+ 2032-02-01,50.0,11315.41
208
+ 2032-03-01,50.0,10792.09
209
+ 2032-04-01,50.0,9619.93
210
+ 2032-05-01,50.0,9039.84
211
+ 2032-06-01,50.0,8151.34
212
+ 2032-07-01,50.0,7617.44
213
+ 2032-08-01,50.0,7882.38
214
+ 2032-09-01,50.0,9324.79
215
+ 2032-10-01,50.0,9902.73
216
+ 2032-11-01,50.0,10781.98
217
+ 2032-12-01,50.0,13251.46
218
+ 2033-01-01,50.0,15335.09
219
+ 2033-02-01,50.0,11559.66
220
+ 2033-03-01,50.0,12045.69
221
+ 2033-04-01,50.0,10790.35
222
+ 2033-05-01,50.0,10670.37
223
+ 2033-06-01,50.0,8667.43
224
+ 2033-07-01,50.0,8721.92
225
+ 2033-08-01,50.0,9219.33
226
+ 2033-09-01,50.0,9701.93
227
+ 2033-10-01,50.0,11127.96
228
+ 2033-11-01,50.0,12132.91
229
+ 2033-12-01,50.0,13157.0
230
+ 2034-01-01,50.0,13335.38
231
+ 2034-02-01,50.0,11316.77
232
+ 2034-03-01,50.0,11678.69
233
+ 2034-04-01,50.0,10000.82
234
+ 2034-05-01,50.0,9795.92
235
+ 2034-06-01,50.0,8763.22
236
+ 2034-07-01,50.0,8405.5
237
+ 2034-08-01,50.0,8669.03
238
+ 2034-09-01,50.0,9133.68
239
+ 2034-10-01,50.0,10716.89
240
+ 2034-11-01,50.0,11348.31
241
+ 2034-12-01,50.0,13191.0
242
+ 2035-01-01,50.0,13255.01
243
+ 2035-02-01,50.0,12000.15
244
+ 2035-03-01,50.0,12020.97
245
+ 2035-04-01,50.0,10182.63
246
+ 2035-05-01,50.0,9341.51
247
+ 2035-06-01,50.0,8136.82
248
+ 2035-07-01,50.0,8576.72
249
+ 2035-08-01,50.0,8557.58
250
+ 2035-09-01,50.0,9155.77
251
+ 2035-10-01,50.0,10051.97
252
+ 2035-11-01,50.0,11800.05
253
+ 2035-12-01,50.0,13109.44
254
+ 2036-01-01,50.0,12485.38
255
+ 2036-02-01,50.0,11215.29
256
+ 2036-03-01,50.0,11240.83
257
+ 2036-04-01,50.0,9795.15
258
+ 2036-05-01,50.0,9206.99
259
+ 2036-06-01,50.0,8152.89
260
+ 2036-07-01,50.0,7984.43
261
+ 2036-08-01,50.0,8286.88
262
+ 2036-09-01,50.0,9156.11
263
+ 2036-10-01,50.0,9511.87
264
+ 2036-11-01,50.0,11074.78
265
+ 2036-12-01,50.0,12631.76
266
+ 2037-01-01,50.0,14264.09
267
+ 2037-02-01,50.0,11874.61
268
+ 2037-03-01,50.0,11565.15
269
+ 2037-04-01,50.0,10811.08
270
+ 2037-05-01,50.0,10694.76
271
+ 2037-06-01,50.0,8540.67
272
+ 2037-07-01,50.0,9035.23
273
+ 2037-08-01,50.0,8941.18
274
+ 2037-09-01,50.0,9581.62
275
+ 2037-10-01,50.0,10924.79
276
+ 2037-11-01,50.0,12087.62
277
+ 2037-12-01,50.0,14291.39
278
+ 2038-01-01,50.0,13405.15
279
+ 2038-02-01,50.0,11771.63
280
+ 2038-03-01,50.0,11778.27
281
+ 2038-04-01,50.0,10107.44
282
+ 2038-05-01,50.0,9970.52
283
+ 2038-06-01,50.0,8452.29
284
+ 2038-07-01,50.0,8410.56
285
+ 2038-08-01,50.0,8339.81
286
+ 2038-09-01,50.0,8962.85
287
+ 2038-10-01,50.0,10292.26
288
+ 2038-11-01,50.0,11715.67
289
+ 2038-12-01,50.0,12364.31
290
+ 2039-01-01,50.0,13251.5
291
+ 2039-02-01,50.0,10934.18
292
+ 2039-03-01,50.0,11573.04
293
+ 2039-04-01,50.0,10024.81
294
+ 2039-05-01,50.0,9819.97
295
+ 2039-06-01,50.0,8378.26
296
+ 2039-07-01,50.0,7684.8
297
+ 2039-08-01,50.0,8252.93
298
+ 2039-09-01,50.0,8481.63
299
+ 2039-10-01,50.0,10170.26
300
+ 2039-11-01,50.0,11688.58
301
+ 2039-12-01,50.0,12837.24
302
+ 2040-01-01,50.0,12680.94
303
+ 2040-02-01,50.0,11061.75
304
+ 2040-03-01,50.0,11195.44
305
+ 2040-04-01,50.0,9449.74
306
+ 2040-05-01,50.0,9127.38
307
+ 2040-06-01,50.0,8278.41
308
+ 2040-07-01,50.0,8347.86
309
+ 2040-08-01,50.0,8423.76
310
+ 2040-09-01,50.0,8189.55
311
+ 2040-10-01,50.0,10429.17
312
+ 2040-11-01,50.0,11210.06
313
+ 2040-12-01,50.0,12757.56
314
+ 2041-01-01,50.0,14142.2
315
+ 2041-02-01,50.0,10747.12
316
+ 2041-03-01,50.0,11440.46
317
+ 2041-04-01,50.0,10394.36
318
+ 2041-05-01,50.0,9239.91
319
+ 2041-06-01,50.0,8919.01
320
+ 2041-07-01,50.0,8494.74
321
+ 2041-08-01,50.0,8833.61
322
+ 2041-09-01,50.0,9000.88
323
+ 2041-10-01,50.0,11024.96
324
+ 2041-11-01,50.0,12021.88
325
+ 2041-12-01,50.0,13213.92
326
+ 2042-01-01,50.0,13425.51
327
+ 2042-02-01,50.0,11415.19
328
+ 2042-03-01,50.0,11213.75
329
+ 2042-04-01,50.0,10050.17
330
+ 2042-05-01,50.0,9543.79
331
+ 2042-06-01,50.0,8538.87
332
+ 2042-07-01,50.0,8553.54
333
+ 2042-08-01,50.0,8244.49
334
+ 2042-09-01,50.0,9017.58
335
+ 2042-10-01,50.0,11110.16
336
+ 2042-11-01,50.0,11256.56
337
+ 2042-12-01,50.0,12650.11
338
+ 2043-01-01,50.0,13396.76
339
+ 2043-02-01,50.0,11596.42
340
+ 2043-03-01,50.0,11502.2
341
+ 2043-04-01,50.0,10484.86
342
+ 2043-05-01,50.0,9822.43
343
+ 2043-06-01,50.0,8644.7
344
+ 2043-07-01,50.0,8432.48
345
+ 2043-08-01,50.0,9098.68
346
+ 2043-09-01,50.0,8985.14
347
+ 2043-10-01,50.0,9986.17
348
+ 2043-11-01,50.0,12053.19
349
+ 2043-12-01,50.0,12776.78
350
+ 2044-01-01,50.0,13324.08
351
+ 2044-02-01,50.0,12157.69
352
+ 2044-03-01,50.0,10916.92
353
+ 2044-04-01,50.0,9678.87
354
+ 2044-05-01,50.0,9092.4
355
+ 2044-06-01,50.0,8209.34
356
+ 2044-07-01,50.0,8382.0
357
+ 2044-08-01,50.0,8615.93
358
+ 2044-09-01,50.0,9091.87
359
+ 2044-10-01,50.0,10147.85
360
+ 2044-11-01,50.0,10674.76
361
+ 2044-12-01,50.0,12941.83
362
+ 2045-01-01,50.0,14139.85
363
+ 2045-02-01,50.0,12350.01
364
+ 2045-03-01,50.0,12645.79
365
+ 2045-04-01,50.0,10905.49
366
+ 2045-05-01,50.0,10550.01
367
+ 2045-06-01,50.0,9144.45
368
+ 2045-07-01,50.0,9076.33
369
+ 2045-08-01,50.0,8967.01
370
+ 2045-09-01,50.0,9685.53
371
+ 2045-10-01,50.0,11511.7
372
+ 2045-11-01,50.0,12691.48
373
+ 2045-12-01,50.0,13788.88
374
+ 2046-01-01,50.0,12845.6
375
+ 2046-02-01,50.0,10656.8
376
+ 2046-03-01,50.0,10882.85
377
+ 2046-04-01,50.0,9815.31
378
+ 2046-05-01,50.0,8551.96
379
+ 2046-06-01,50.0,7697.22
380
+ 2046-07-01,50.0,7528.12
381
+ 2046-08-01,50.0,7512.55
382
+ 2046-09-01,50.0,8412.46
383
+ 2046-10-01,50.0,10318.6
384
+ 2046-11-01,50.0,10829.41
385
+ 2046-12-01,50.0,12377.7
model/profit.py ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # power_to_profit.py
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import numpy_financial as npf
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ ROOT = Path(__file__).resolve().parent
10
+
11
+ # Add module folders to Python import path
12
+ sys.path.insert(0, str(ROOT / "revenue"))
13
+ sys.path.insert(0, str(ROOT / "costs" / "capex"))
14
+ sys.path.insert(0, str(ROOT / "costs" / "opex"))
15
+ sys.path.insert(0, str(ROOT / "costs" / "finance"))
16
+
17
+ import revenue_mod as revenue_mod
18
+ import capex_mod as capex_mod
19
+ import opex_mod as opex_mod
20
+ import finance_mod as finance_mod
21
+
22
+
23
+ FORECAST_MONTHS = 240 # 20 years
24
+
25
+
26
+ def _compute_npv(cashflows, discount_rate):
27
+ return sum(cf / ((1 + discount_rate) ** t) for t, cf in enumerate(cashflows))
28
+
29
+
30
+
31
+ def _compute_irr(cashflows, guess=0.08):
32
+ if all(cf >= 0 for cf in cashflows) or all(cf <= 0 for cf in cashflows):
33
+ return np.nan
34
+
35
+ r = guess
36
+ for _ in range(200):
37
+ npv = 0.0
38
+ d_npv = 0.0
39
+ for t, cf in enumerate(cashflows):
40
+ denom = (1 + r) ** t
41
+ npv += cf / denom
42
+ if t > 0:
43
+ d_npv += -t * cf / ((1 + r) ** (t + 1))
44
+
45
+ if abs(npv) < 1e-6:
46
+ return r
47
+
48
+ if abs(d_npv) < 1e-12:
49
+ break
50
+
51
+ r_new = r - (npv / d_npv)
52
+ # If Newton wants to run outside sane bounds, treat as failure
53
+ if r_new <= -0.99 or r_new >= 5.0:
54
+ return np.nan
55
+
56
+
57
+ if abs(r_new - r) < 1e-9:
58
+ return r_new
59
+
60
+ r = r_new
61
+
62
+ return np.nan
63
+
64
+
65
+ def _month_index(dt: pd.Series) -> pd.Series:
66
+ """Integer month index for easy month-diff calculations: year*12 + (month-1)."""
67
+ return dt.dt.year * 12 + (dt.dt.month - 1)
68
+
69
+
70
+ def power_to_profit(
71
+ mwh_monthly_20y,
72
+ turbine_type_id=1, # 0=LOW_WIND, 1=BALANCED, 2=HIGH_WIND
73
+ n_turbines=12,
74
+ hub_height_m=160,
75
+ equity_eur=None, # <-- absolute € amount (not share)
76
+ debt_rate=0.045,
77
+ equity_return=0.085,
78
+ debt_tenor_years=20,
79
+ discount_rate=None,
80
+ revenue_kwargs=None,
81
+ ):
82
+ """
83
+ Orchestrates: revenue + capex + opex + finance => yearly profit, NPV, IRR
84
+
85
+ IMPORTANT:
86
+ - Yearly aggregation is PROJECT YEARS (12-month blocks from COD),
87
+ not calendar years.
88
+ """
89
+
90
+ revenue_kwargs = revenue_kwargs or {}
91
+
92
+ # -----------------------
93
+ # 1) Prepare monthly MWh input -> DataFrame(date, mwh)
94
+ # -----------------------
95
+ if isinstance(mwh_monthly_20y, pd.Series):
96
+ mwh_df = mwh_monthly_20y.rename("mwh").to_frame()
97
+ mwh_df = mwh_df.reset_index().rename(columns={"index": "date"})
98
+ elif isinstance(mwh_monthly_20y, pd.DataFrame):
99
+ mwh_df = mwh_monthly_20y.copy()
100
+ if "date" not in mwh_df.columns:
101
+ raise ValueError("mwh_monthly_20y DataFrame must contain a 'date' column.")
102
+ if "mwh" not in mwh_df.columns:
103
+ for alt in ["mwh_gross", "MWh", "MWh_gross", "mwh_gross_park", "mwh_park"]:
104
+ if alt in mwh_df.columns:
105
+ mwh_df = mwh_df.rename(columns={alt: "mwh"})
106
+ break
107
+ if "mwh" not in mwh_df.columns:
108
+ raise ValueError("mwh_monthly_20y must contain an 'mwh' column (or mwh_gross).")
109
+ else:
110
+ raise TypeError("mwh_monthly_20y must be a pandas Series or DataFrame.")
111
+
112
+ mwh_df["date"] = pd.to_datetime(mwh_df["date"], errors="coerce")
113
+ mwh_df["mwh"] = pd.to_numeric(mwh_df["mwh"], errors="coerce")
114
+ mwh_df = mwh_df.dropna(subset=["date", "mwh"]).sort_values("date").reset_index(drop=True)
115
+
116
+ # -----------------------
117
+ # 2) Revenue module (NEW API)
118
+ # -----------------------
119
+ required = ["tso_id", "eeg_on", "cod_date"]
120
+ missing = [k for k in required if k not in revenue_kwargs]
121
+ if missing:
122
+ raise ValueError(
123
+ f"revenue_kwargs missing required keys: {missing}. "
124
+ f"Expected at least: {required} (manual_eeg_strike optional)."
125
+ )
126
+
127
+ tso_id = int(revenue_kwargs["tso_id"])
128
+ eeg_on = int(revenue_kwargs.get("eeg_on", 1))
129
+ manual_eeg_strike = revenue_kwargs.get("manual_eeg_strike", None)
130
+ cod_date = revenue_kwargs["cod_date"]
131
+
132
+ # COD normalized to month-start
133
+ cod = pd.Timestamp(cod_date)
134
+ cod = pd.Timestamp(year=cod.year, month=cod.month, day=1)
135
+
136
+ optional_keys = ["base_dir", "market_file", "cf_file", "curtail_file", "eeg_file"]
137
+ optional_args = {k: revenue_kwargs[k] for k in optional_keys if k in revenue_kwargs}
138
+
139
+ monthly_rev = revenue_mod.generate_monthly_revenue(
140
+ tso_id=tso_id,
141
+ mwh_monthly_20y=mwh_df,
142
+ eeg_on=eeg_on,
143
+ manual_eeg_strike=manual_eeg_strike,
144
+ cod_date=cod,
145
+ forecast_months=FORECAST_MONTHS,
146
+ **optional_args,
147
+ )
148
+
149
+ if "date" not in monthly_rev.columns or "revenue_eur" not in monthly_rev.columns:
150
+ raise ValueError("Revenue output must contain columns: 'date' and 'revenue_eur'.")
151
+
152
+ monthly_rev["date"] = pd.to_datetime(monthly_rev["date"], errors="coerce")
153
+ monthly_rev = monthly_rev.dropna(subset=["date"]).sort_values("date").reset_index(drop=True)
154
+
155
+ print("\n===== REVENUE DRIVERS =====")
156
+ print("Avg delivered MWh / month:", monthly_rev["mwh_delivered"].mean())
157
+ print("Avg realised price €/MWh:", monthly_rev["p_wind_realised"].mean())
158
+ print("Avg revenue per month (k€):", monthly_rev["revenue_eur"].mean() / 1e3)
159
+ print("Avg market price €/MWh:", monthly_rev["p_market"].mean())
160
+ print("Avg capture factor:", monthly_rev["cf"].mean())
161
+ print("Avg curtailment:", monthly_rev["cr"].mean())
162
+ print("==========================\n")
163
+
164
+
165
+ # safety net
166
+ monthly_rev = monthly_rev[monthly_rev["date"] >= cod].copy()
167
+ if len(monthly_rev) < FORECAST_MONTHS:
168
+ raise ValueError(f"Revenue series has only {len(monthly_rev)} months from COD, need {FORECAST_MONTHS}.")
169
+ monthly_rev = monthly_rev.head(FORECAST_MONTHS).copy()
170
+
171
+ # -----------------------
172
+ # 2c) Aggregate by PROJECT YEAR (Year 1..20 from COD)
173
+ # -----------------------
174
+ moff = _month_index(monthly_rev["date"]) - (cod.year * 12 + (cod.month - 1))
175
+ monthly_rev["project_month"] = moff + 1
176
+ monthly_rev["project_year"] = (moff // 12) + 1
177
+
178
+ yearly_revenue = (
179
+ monthly_rev.groupby("project_year", as_index=False)["revenue_eur"]
180
+ .sum()
181
+ .sort_values("project_year")
182
+ .reset_index(drop=True)
183
+ )
184
+
185
+ horizon_years = int(np.ceil(FORECAST_MONTHS / 12.0))
186
+ year_starts = [cod + pd.DateOffset(months=12 * (y - 1)) for y in range(1, horizon_years + 1)]
187
+ yearly_revenue["year_start"] = year_starts
188
+
189
+ # -----------------------
190
+ # 3) CAPEX module (CAPEX -> finance dependency handled correctly)
191
+ # -----------------------
192
+ capex_res = capex_mod.windpark_capex(
193
+ n_turbines=n_turbines,
194
+ turbine_type_id=turbine_type_id,
195
+ hub_height_m=hub_height_m,
196
+ )
197
+ capex_total = float(capex_res["total_capex_eur"])
198
+ park_mw = float(capex_res["park_mw"])
199
+
200
+ # -----------------------
201
+ # 4) OPEX module (NEW: aligned to forecast_months, returns project_year already)
202
+ # -----------------------
203
+ opex_df, opex_total = opex_mod.windpark_opex_timeseries(
204
+ park_mw=park_mw,
205
+ forecast_months=FORECAST_MONTHS,
206
+ )
207
+
208
+ # NEW opex.py returns: project_year, annual_opex_eur
209
+ if "project_year" not in opex_df.columns or "annual_opex_eur" not in opex_df.columns:
210
+ raise ValueError("OPEX output must contain columns: 'project_year' and 'annual_opex_eur'.")
211
+
212
+ opex_df = opex_df.sort_values("project_year").reset_index(drop=True)
213
+
214
+ # -----------------------
215
+ # 5) Financing module (NEW: equity_eur input, debt schedule returned)
216
+ # -----------------------
217
+ if equity_eur is None:
218
+ equity_eur = 0.15 * capex_total # default: 15% of capex
219
+
220
+ fin = finance_mod.financing_model(
221
+ capex_eur=capex_total,
222
+ equity_eur=float(equity_eur), # <-- absolute €
223
+ debt_rate=debt_rate,
224
+ equity_return=equity_return,
225
+ debt_tenor_years=debt_tenor_years,
226
+ forecast_months=FORECAST_MONTHS,
227
+ )
228
+
229
+ # aligned yearly debt schedule
230
+ debt_service_df = fin["debt_service_yearly_df"]
231
+ if "project_year" not in debt_service_df.columns or "debt_service_eur" not in debt_service_df.columns:
232
+ raise ValueError("finance.py must return debt_service_yearly_df with columns: project_year, debt_service_eur")
233
+
234
+ debt_service_df = debt_service_df.sort_values("project_year").reset_index(drop=True)
235
+
236
+ print("\n===== DEBT SERVICE SCHEDULE =====")
237
+ print(debt_service_df.head(5))
238
+ print("...")
239
+ print(debt_service_df.tail(5))
240
+ print("================================\n")
241
+
242
+
243
+ print("\n===== FINANCIAL SANITY CHECK =====")
244
+ print("Park MW:", park_mw)
245
+ print("CAPEX total (M€):", capex_total / 1e6)
246
+ print("CAPEX €/kW:", capex_res["total_capex_eur_per_kw"])
247
+ print("Equity (M€):", equity_eur / 1e6)
248
+ print("Equity share:", fin.get("equity_share_derived"))
249
+ print("Debt (M€):", fin["debt_eur"] / 1e6)
250
+
251
+ print("Average yearly debt service (M€):",
252
+ debt_service_df["debt_service_eur"].mean() / 1e6)
253
+
254
+ print("=================================\n")
255
+
256
+
257
+ # -----------------------
258
+ # 6) Unite yearly cashflows (by project_year)
259
+ # -----------------------
260
+ yearly = pd.DataFrame({
261
+ "project_year": list(range(1, horizon_years + 1)),
262
+ "year_start": year_starts,
263
+ })
264
+
265
+ yearly = yearly.merge(yearly_revenue[["project_year", "revenue_eur"]], on="project_year", how="left")
266
+ yearly = yearly.merge(opex_df[["project_year", "annual_opex_eur"]], on="project_year", how="left")
267
+ yearly = yearly.merge(debt_service_df[["project_year", "debt_service_eur"]], on="project_year", how="left")
268
+
269
+ # Fill any missing (shouldn't happen, but keeps things robust)
270
+ yearly["revenue_eur"] = yearly["revenue_eur"].fillna(0.0)
271
+ yearly["annual_opex_eur"] = yearly["annual_opex_eur"].fillna(0.0)
272
+ yearly["debt_service_eur"] = yearly["debt_service_eur"].fillna(0.0)
273
+
274
+ yearly["profit_after_opex_and_debt_eur"] = (
275
+ yearly["revenue_eur"] - yearly["annual_opex_eur"] - yearly["debt_service_eur"]
276
+ )
277
+
278
+ # -----------------------
279
+ # 7) Equity cashflows + NPV + IRR
280
+ # -----------------------
281
+ equity_cashflows = [-float(equity_eur)] + yearly["profit_after_opex_and_debt_eur"].tolist()
282
+
283
+ # -----------------------
284
+ # Terminal value (residual value at end of year 20)
285
+ # -----------------------
286
+ TERMINAL_VALUE_SHARE = 0.30 # 10% of CAPEX as salvage / repowering option
287
+ terminal_value = TERMINAL_VALUE_SHARE * capex_total
288
+
289
+ equity_cashflows[-1] += terminal_value
290
+
291
+ print(f"Terminal value added in year 20: {terminal_value/1e6:.1f} M€")
292
+
293
+
294
+ used_discount_rate = discount_rate if discount_rate is not None else float(fin["wacc"])
295
+ npv_eur = _compute_npv(equity_cashflows, used_discount_rate)
296
+ irr = npf.irr(equity_cashflows)
297
+
298
+ return {
299
+ "monthly_revenue_df": monthly_rev,
300
+ "yearly_df": yearly,
301
+ "capex_summary": {**capex_res},
302
+ "opex_summary": {"total_opex_eur": float(opex_total)},
303
+ "finance_summary": fin | {
304
+ "equity_eur_input": float(equity_eur),
305
+ },
306
+ "equity_cashflows": equity_cashflows,
307
+ "npv_eur": npv_eur,
308
+ "irr": irr,
309
+ "discount_rate_used": used_discount_rate,
310
+ }
311
+
312
+
313
+ # -------------------------
314
+ # Example call
315
+ # -------------------------
316
+ if __name__ == "__main__":
317
+ cod = pd.Timestamp.today()
318
+ cod = pd.Timestamp(year=cod.year, month=cod.month, day=1)
319
+
320
+ dates = pd.date_range(cod, periods=FORECAST_MONTHS, freq="MS")
321
+ example_mwh = pd.Series(24000.0, index=dates)
322
+
323
+ result = power_to_profit(
324
+ mwh_monthly_20y=example_mwh,
325
+ turbine_type_id=1,
326
+ n_turbines=12,
327
+ hub_height_m=160,
328
+ equity_eur=60_000_000,
329
+ revenue_kwargs={
330
+ "tso_id": 0,
331
+ "eeg_on": 1,
332
+ "manual_eeg_strike": None,
333
+ "cod_date": str(cod.date()),
334
+ # If you run from a different working dir, set:
335
+ # "base_dir": str(ROOT),
336
+ }
337
+ )
338
+
339
+ print("NPV (equity):", f"{result['npv_eur']/1e6:.1f} M€")
340
+ print("IRR (equity):", f"{result['irr']*100:.2f}%")
341
+ print(result["yearly_df"].head())
342
+ print(result["yearly_df"].tail(5))
343
+
344
+
model/revenue/capture_factor_history_forecast/capture_factor_forecast_b2.csv ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ month,cf_hist,wind_mwh_hist,wind_mwh_low,cf_low,wind_mwh_base,cf_base,wind_mwh_high,cf_high
2
+ 2015-01-01,0.7971657646881044,7830853.25,,,,,,
3
+ 2015-02-01,0.8690542944179981,5325677.75,,,,,,
4
+ 2015-03-01,0.8255342879088481,7010958.25,,,,,,
5
+ 2015-04-01,0.8730305964403778,5157796.5,,,,,,
6
+ 2015-05-01,0.9108853171899532,5105062.25,,,,,,
7
+ 2015-06-01,0.9352319647730498,3871212.5,,,,,,
8
+ 2015-07-01,0.8438483980050792,5401805.25,,,,,,
9
+ 2015-08-01,0.9394317407515804,3553163.75,,,,,,
10
+ 2015-09-01,0.8796387097310245,5328808.5,,,,,,
11
+ 2015-10-01,0.9307452220979952,3438960.5,,,,,,
12
+ 2015-11-01,0.8363187233591128,9763092.0,,,,,,
13
+ 2015-12-01,0.8596254975904842,10359892.25,,,,,,
14
+ 2016-01-01,0.843399934260027,8406655.5,,,,,,
15
+ 2016-02-01,0.8476904277698321,9366679.75,,,,,,
16
+ 2016-03-01,0.885148550782457,5710792.5,,,,,,
17
+ 2016-04-01,0.9594746283445816,5587231.75,,,,,,
18
+ 2016-05-01,0.840229734804759,5706867.75,,,,,,
19
+ 2016-06-01,0.9633910888369888,2902409.5,,,,,,
20
+ 2016-07-01,0.8833173371246897,4302145.75,,,,,,
21
+ 2016-08-01,0.9387251967374728,4262079.75,,,,,,
22
+ 2016-09-01,0.9116825453835888,3729333.5,,,,,,
23
+ 2016-10-01,0.912104248421158,4488192.0,,,,,,
24
+ 2016-11-01,0.8668111264786234,7267011.75,,,,,,
25
+ 2016-12-01,0.6650078674754464,8416867.75,,,,,,
26
+ 2017-01-01,0.796002572213315,7186927.25,,,,,,
27
+ 2017-02-01,0.8310610612983536,8439755.75,,,,,,
28
+ 2017-03-01,0.916222166975428,8511720.0,,,,,,
29
+ 2017-04-01,0.8584551912833392,7421613.0,,,,,,
30
+ 2017-05-01,0.8703020447211074,4963043.75,,,,,,
31
+ 2017-06-01,0.85696744583063,6153125.0,,,,,,
32
+ 2017-07-01,0.8963757838970061,5011439.25,,,,,,
33
+ 2017-08-01,0.8851074120163239,4804535.25,,,,,,
34
+ 2017-09-01,0.8240239875515648,5904335.5,,,,,,
35
+ 2017-10-01,0.7110785406630726,11014475.5,,,,,,
36
+ 2017-11-01,0.7781521585823284,9256318.75,,,,,,
37
+ 2017-12-01,0.7368746365402401,13454183.0,,,,,,
38
+ 2018-01-01,0.7662484585750495,13144978.0,,,,,,
39
+ 2018-02-01,0.9003090338258714,6859993.0,,,,,,
40
+ 2018-03-01,0.8148924669900246,9588788.75,,,,,,
41
+ 2018-04-01,0.9190437359638376,8002044.25,,,,,,
42
+ 2018-05-01,0.8446908004296617,6270346.75,,,,,,
43
+ 2018-06-01,0.891257853677082,5135329.25,,,,,,
44
+ 2018-07-01,0.9505727463099204,4064678.75,,,,,,
45
+ 2018-08-01,0.9364000264231565,5343261.5,,,,,,
46
+ 2018-09-01,0.8825727774185559,6545188.25,,,,,,
47
+ 2018-10-01,0.8249529792385146,8733167.0,,,,,,
48
+ 2018-11-01,0.9212191950381042,8035869.5,,,,,,
49
+ 2018-12-01,0.8294148831145396,12092006.75,,,,,,
50
+ 2019-01-01,0.7913858813006717,12551354.25,,,,,,
51
+ 2019-02-01,0.8977788571766797,8914979.0,,,,,,
52
+ 2019-03-01,0.8067350106096033,13736642.0,,,,,,
53
+ 2019-04-01,0.9219362017284696,7303645.75,,,,,,
54
+ 2019-05-01,0.9491406744264954,6428337.75,,,,,,
55
+ 2019-06-01,0.7478043560132084,5114514.5,,,,,,
56
+ 2019-07-01,0.9210644724288692,4862707.5,,,,,,
57
+ 2019-08-01,0.8332421822301923,4493530.5,,,,,,
58
+ 2019-09-01,0.8641271028355628,7145538.75,,,,,,
59
+ 2019-10-01,0.8761714169867824,9341217.0,,,,,,
60
+ 2019-11-01,0.9046159763857736,7880445.25,,,,,,
61
+ 2019-12-01,0.8298915951927173,12208935.0,,,,,,
62
+ 2020-01-01,0.8892173696652799,12670559.0,,,,,,
63
+ 2020-02-01,0.801370670148446,17239833.25,,,,,,
64
+ 2020-03-01,0.8173275716339073,11552708.75,,,,,,
65
+ 2020-04-01,0.6561987925727963,6991474.0,,,,,,
66
+ 2020-05-01,0.7418702532802646,6132951.75,,,,,,
67
+ 2020-06-01,0.8489769334655407,4983084.0,,,,,,
68
+ 2020-07-01,0.7245227771392173,5480898.5,,,,,,
69
+ 2020-08-01,0.8639570295298692,5156488.25,,,,,,
70
+ 2020-09-01,0.8713188572706236,4632294.25,,,,,,
71
+ 2020-10-01,0.8859669990959038,10816688.5,,,,,,
72
+ 2020-11-01,0.8295916172231614,8665897.5,,,,,,
73
+ 2020-12-01,0.7772918524357464,9073761.0,,,,,,
74
+ 2021-01-01,0.8838423830800066,9223364.5,,,,,,
75
+ 2021-02-01,0.9033426083189586,8487553.25,,,,,,
76
+ 2021-03-01,0.743485203895938,9086611.25,,,,,,
77
+ 2021-04-01,0.8399588953639053,7735461.0,,,,,,
78
+ 2021-05-01,0.809950076338887,8828518.25,,,,,,
79
+ 2021-06-01,0.8650260832050826,3361513.75,,,,,,
80
+ 2021-07-01,0.85478206431339,4704354.75,,,,,,
81
+ 2021-08-01,0.8902143299225604,6191015.5,,,,,,
82
+ 2021-09-01,0.9231758067302543,4465397.5,,,,,,
83
+ 2021-10-01,0.8028855536070918,10167443.25,,,,,,
84
+ 2021-11-01,0.8091082944249354,7822972.75,,,,,,
85
+ 2021-12-01,0.7496126000956357,9782408.0,,,,,,
86
+ 2022-01-01,0.7889801281913014,12982727.75,,,,,,
87
+ 2022-02-01,0.8596946300768242,17728127.25,,,,,,
88
+ 2022-03-01,0.8179331024127248,6793504.0,,,,,,
89
+ 2022-04-01,0.7914207750015567,9550806.0,,,,,,
90
+ 2022-05-01,0.7913465861919791,6454706.0,,,,,,
91
+ 2022-06-01,0.9105198867698971,4412514.75,,,,,,
92
+ 2022-07-01,0.8987415020852123,5502496.0,,,,,,
93
+ 2022-08-01,0.9925071049033212,3527019.25,,,,,,
94
+ 2022-09-01,0.8340116597492033,6189613.5,,,,,,
95
+ 2022-10-01,0.8467040971896496,8613400.25,,,,,,
96
+ 2022-11-01,0.7997193134836902,10118516.25,,,,,,
97
+ 2022-12-01,0.6093778772271731,9410138.25,,,,,,
98
+ 2023-01-01,0.7627862272091563,14692525.75,,,,,,
99
+ 2023-02-01,0.837630935069364,10445029.0,,,,,,
100
+ 2023-03-01,0.8509837017682864,12133716.25,,,,,,
101
+ 2023-04-01,0.9055675186026236,8382426.5,,,,,,
102
+ 2023-05-01,1.0098968064125304,6771381.25,,,,,,
103
+ 2023-06-01,0.9829993685400272,4872287.25,,,,,,
104
+ 2023-07-01,0.8004890662131304,8392192.75,,,,,,
105
+ 2023-08-01,0.7339691885049526,5778036.5,,,,,,
106
+ 2023-09-01,0.878258506831602,5339625.25,,,,,,
107
+ 2023-10-01,0.8082344425554973,11857250.75,,,,,,
108
+ 2023-11-01,0.8488888543617532,14477253.5,,,,,,
109
+ 2023-12-01,0.6786395758987744,16331164.75,,,,,,
110
+ 2024-01-01,0.8575479503325244,15593084.75,,,,,,
111
+ 2024-02-01,0.8818434631285619,14148354.0,,,,,,
112
+ 2024-03-01,0.8673996697790639,9393471.75,,,,,,
113
+ 2024-04-01,0.81147041545214,9724048.5,,,,,,
114
+ 2024-05-01,0.8936559177774147,6274470.0,,,,,,
115
+ 2024-06-01,0.8213854820827964,5693810.5,,,,,,
116
+ 2024-07-01,0.7962444278290781,5548569.25,,,,,,
117
+ 2024-08-01,0.8161256180272725,5204624.75,,,,,,
118
+ 2024-09-01,0.8333547783596332,8986503.75,,,,,,
119
+ 2024-10-01,0.8103438589199886,8389045.5,,,,,,
120
+ 2024-11-01,0.7996357070589065,10300191.5,,,,,,
121
+ 2024-12-01,0.678921664750227,13757540.0,,,,,,
122
+ 2025-01-01,0.7624826815595828,13253343.0,,,,,,
123
+ 2025-02-01,0.9039940754471032,7260679.75,,,,,,
124
+ 2025-03-01,0.8461786901389727,6526920.5,,,,,,
125
+ 2025-04-01,0.995593530428029,5876514.75,,,,,,
126
+ 2025-05-01,0.9731317396080782,7894329.5,,,,,,
127
+ 2025-06-01,0.8898558714550471,8705267.75,,,,,,
128
+ 2025-07-01,0.9453370489262092,6193497.28,,,,,,
129
+ 2025-08-01,0.9180756708029312,5483354.49,,,,,,
130
+ 2025-09-01,0.7932076348765756,9763607.04,,,,,,
131
+ 2025-10-01,0.6984761049626177,13717685.62,,,,,,
132
+ 2025-11-01,0.8786533220749594,9908591.42,,,,,,
133
+ 2025-12-01,0.8957505447033655,12331010.68,,,,,,
134
+ 2026-01-01,,,13103059.484574642,0.8492030747426846,13244361.45920035,0.8483026536483922,13456531.710088486,0.846970275358313
135
+ 2026-02-01,,,13689202.763027957,0.8479966013963295,13848246.970530061,0.8467726649271549,14087302.693321768,0.8449624334085396
136
+ 2026-03-01,,,9853240.617301166,0.8200502205273487,9975945.412549093,0.8187104482705418,10160569.296187991,0.8167293616956085
137
+ 2026-04-01,,,8533402.529355861,0.8441655622383798,8646802.502112843,0.8426718790898418,8817601.133243259,0.8404635807784577
138
+ 2026-05-01,,,6941277.461347821,0.8598682058847109,7039325.437522491,0.8582435082662649,7187152.922073533,0.855841873297681
139
+ 2026-06-01,,,4699670.560019861,0.8792027800737486,4769989.096843592,0.8774399093354863,4876117.474608206,0.8748344007231785
140
+ 2026-07-01,,,5972682.425109518,0.8519568326478111,6067052.119957717,0.8501511869876742,6209625.822393165,0.8474828366845745
141
+ 2026-08-01,,,5214603.942758426,0.8734667751366975,5301368.1288230885,0.8715160015609547,5432585.876867274,0.8686335922980556
142
+ 2026-09-01,,,5974607.4885946335,0.8592582369012907,6079030.8134803735,0.8572413748189331,6237117.332225739,0.8542617368285655
143
+ 2026-10-01,,,10060336.32471937,0.8108437221831425,10244618.665359516,0.8088482236576238,10523889.963258559,0.8059005645923316
144
+ 2026-11-01,,,10375679.56313895,0.828251579887865,10574459.544784559,0.826119001294311,10876010.372046163,0.8229692995780001
145
+ 2026-12-01,,,11788004.199059997,0.7441170188677465,12023758.447539996,0.7421164148082282,12381766.44616,0.7391620503393418
146
+ 2027-01-01,,,13168574.781997515,0.8051499597737084,13443026.881088354,0.8028936777033087,13860227.661391139,0.7995622157076347
147
+ 2027-02-01,,,13757648.776843095,0.8348270672077652,14055970.67508801,0.8323926685443391,14509921.774121422,0.8287987211342658
148
+ 2027-03-01,,,9902506.82038767,0.8160031900945485,10125584.593737328,0.813530882402419,10465386.375073629,0.8098814856312622
149
+ 2027-04-01,,,8576069.54200264,0.8425622184517824,8776504.539644536,0.8399136329057572,9082129.167240558,0.836004583899231
150
+ 2027-05-01,,,6975983.848654561,0.858979312182233,7144915.319085329,0.8561814540670567,7402767.509735739,0.8520526778462385
151
+ 2027-06-01,,,4723168.91281996,0.8785105766984712,4841538.9332962455,0.8755492266506828,5022400.998846453,0.8711798050374514
152
+ 2027-07-01,,,6002545.837235065,0.8513458378202918,6158057.901757083,0.8483792811315463,6395914.59706496,0.8440027965105219
153
+ 2027-08-01,,,5240676.962472217,0.8728577891566051,5380888.650755433,0.869717063381894,5595563.453173293,0.8650842871608452
154
+ 2027-09-01,,,6004480.5260376055,0.8586640379614583,6170216.275682578,0.8554767990627234,6424230.852192512,0.8507760781091576
155
+ 2027-10-01,,,10110638.006342966,0.8102843137570893,10398287.945339905,0.8071845770456438,10839606.662156317,0.8026135561005525
156
+ 2027-11-01,,,10427557.960954644,0.8276805425945527,10733076.437956328,0.8244202141735054,11202290.68320755,0.8196130571846552
157
+ 2027-12-01,,,11846944.220055297,0.7436040854692202,12204114.824253095,0.7405904638316432,12753219.4395448,0.7361476897218651
158
+ 2028-01-01,,,13234417.655907499,0.8045949852482717,13644672.284304678,0.8012427856797019,14276034.491232876,0.7963015687026807
159
+ 2028-02-01,,,13826437.020727308,0.8342516456662152,14266810.235214328,0.8306811302292898,14945219.427345064,0.8254188553899853
160
+ 2028-03-01,,,9952019.354489608,0.8154407457545062,10277468.362643387,0.8118581295370708,10779347.966325838,0.8065787674116687
161
+ 2028-04-01,,,8618949.889712652,0.841981468564351,8908152.107739203,0.8381866335052264,9354593.042257775,0.8325953357185459
162
+ 2028-05-01,,,7010863.767897832,0.8583872467523311,7252089.048871608,0.854421005583623,7624850.535027811,0.848577985337047
163
+ 2028-06-01,,,4746784.75738406,0.8779050490886193,4914162.017295688,0.8737489549343262,5173073.028811846,0.8676271116781111
164
+ 2028-07-01,,,6032558.566421239,0.8507590339624741,6250428.770283437,0.8466348752622951,6587792.034976908,0.8405609316987592
165
+ 2028-08-01,,,5266880.347284579,0.8722561578440794,5461601.980516765,0.8679287835646984,5763430.356768491,0.8615564515004304
166
+ 2028-09-01,,,6034502.928667793,0.8580721899222994,6262769.519817815,0.8537177995477595,6616957.777758287,0.8473065916894749
167
+ 2028-10-01,,,10161191.196374679,0.8097258122236144,10554262.264520004,0.8055248741983562,11164794.862021007,0.7993404776672501
168
+ 2028-11-01,,,10479695.750759415,0.8271100504298508,10894072.58452567,0.8227250720515551,11538359.403703775,0.8162706543549908
169
+ 2028-12-01,,,11906178.941155571,0.7430915443587958,12387176.546616893,0.7390676893184154,13135816.022731146,0.7331456607771257
170
+ 2029-01-01,,,13300589.744187037,0.8040404051763852,13849342.368569247,0.7995953001225402,14704315.525969861,0.7930542307141804
171
+ 2029-02-01,,,13895569.205830945,0.8336766242627695,14480812.38874254,0.8289731146451039,15393576.010165416,0.8220527763680673
172
+ 2029-03-01,,,10001779.451262055,0.8148786900672492,10431630.388083037,0.8101888171054592,11102728.405315615,0.8032895187462434
173
+ 2029-04-01,,,8662044.639161216,0.8414011192557894,9041774.389355289,0.836463185384902,9635230.833525507,0.8291999908278794
174
+ 2029-05-01,,,7045918.08673732,0.8577955894965248,7360870.384604681,0.8526641769524143,7853596.0510786455,0.845117462795974
175
+ 2029-06-01,,,4770518.681170979,0.8772999388727262,4987874.447555123,0.8719523848939292,5328265.219676202,0.8640889063168025
176
+ 2029-07-01,,,6062721.359253344,0.8501726345753781,6344185.201837688,0.8448940561820982,6785425.796026216,0.8371331029057067
177
+ 2029-08-01,,,5293214.749021,0.8716549412175943,5543526.010224516,0.8661441807437796,5936333.267471545,0.8580430024452566
178
+ 2029-09-01,,,6064675.443311132,0.8574807498244952,6356711.062615082,0.8519624168225963,6815466.511091036,0.8438512539239348
179
+ 2029-10-01,,,10211997.152356552,0.8091676956464771,10712576.198487803,0.8038685839703603,11499738.707881637,0.7960807469309402
180
+ 2029-11-01,,,10532094.229513213,0.826539951486118,11057483.673293553,0.8210334154177087,11884510.18581489,0.8129418819288599
181
+ 2029-12-01,,,11965709.835861348,0.74257935652561,12572984.194816144,0.7375480458774061,13529890.50341308,0.7301558741825546
182
+ 2030-01-01,,,13367092.69290797,0.8034862073577619,14057082.504097786,0.7979512020637907,15145444.991748959,0.7898201354523412
183
+ 2030-02-01,,,13965047.051860096,0.833101999202102,14698024.574573679,0.8272686110189132,15855383.29047038,0.8187004243017532
184
+ 2030-03-01,,,10051788.348518364,0.814317021785941,10588104.843904283,0.8085229370518624,11435810.257475084,0.8000136837202797
185
+ 2030-04-01,,,8705354.86235702,0.8408211699623502,9177401.005195618,0.8347432809543778,9924287.758531272,0.8258184922397707
186
+ 2030-05-01,,,7081147.677171006,0.8572043400500257,7471283.440373751,0.8509109606467676,8089203.932611005,0.8416710523535702
187
+ 2030-06-01,,,4794371.2745768335,0.8766952457388096,5062692.56426845,0.8701595088938993,5488113.176266489,0.8605651298466735
188
+ 2030-07-01,,,6093034.966049612,0.8495866393735183,6439347.979865254,0.8431568165092219,6988988.569907002,0.83371925288539
189
+ 2030-08-01,,,5319680.822766105,0.871054138989367,5626678.900377883,0.8643632473566772,6114423.265495692,0.8545438813244176
190
+ 2030-09-01,,,6094998.820527687,0.8568897173863181,6452061.7285543075,0.8502106434499773,7019930.506423767,0.8404100071134173
191
+ 2030-10-01,,,10263057.138118334,0.8086099637601931,10873264.84146512,0.8022156993446087,11844730.869118087,0.7928343094592274
192
+ 2030-11-01,,,10584754.700660778,0.825970245492278,11223345.928392954,0.819345237105192,12241045.491389336,0.8096266843210882
193
+ 2030-12-01,,,12025538.385040654,0.7420675217261502,12761578.957738385,0.7360315270706096,13935787.218515472,0.7271782800135259
194
+ 2031-01-01,,,13433928.15637251,0.8029323915289246,14267938.74165925,0.7963104845382003,15599808.341501426,0.7865992289129847
195
+ 2031-02-01,,,14034872.287119396,0.8325277702110265,14918494.943192283,0.8255676121295594,16331044.789184494,0.8153617432121694
196
+ 2031-03-01,,,10102047.290260956,0.8137557406435558,10746926.416562846,0.8068604823187515,11778884.565199336,0.7967512076326151
197
+ 2031-04-01,,,8748881.636668803,0.8402416204083165,9315062.020273551,0.8330269129272503,10222016.391287211,0.8224507834886473
198
+ 2031-05-01,,,7116553.41555686,0.8566134981317443,7583352.691979356,0.8491613492391543,8331880.050589337,0.8382386964603389
199
+ 2031-06-01,,,4818343.130949717,0.8760909693993897,5138632.9527324755,0.8683703193386879,5652756.571554483,0.85705572342634
200
+ 2031-07-01,,,6123500.140879858,0.8490010480783035,6535938.199563231,0.8414231488838217,7198658.227004213,0.8303193246320187
201
+ 2031-08-01,,,5346279.226879935,0.8704537508737664,5711079.083883551,0.8625859758584377,6297855.963460564,0.851059029708235
202
+ 2031-09-01,,,6125473.814630324,0.8562990923267831,6548842.654482621,0.8484624720084862,7230528.421616481,0.836982793794651
203
+ 2031-10-01,,,10314372.423808923,0.8080526162996082,11036363.814087093,0.8005662133186292,12200072.795191629,0.7896011110418423
204
+ 2031-11-01,,,10637678.47416408,0.8254009321774841,11391696.117318848,0.8176605299620106,12608276.856131017,0.8063250061732227
205
+ 2031-12-01,,,12085666.076965857,0.7415560397170822,12953002.64210446,0.7345181264732698,14353860.835070938,0.7242128285490202
206
+ 2032-01-01,,,13501097.797154369,0.8023789574265805,14481957.822784137,0.7946731405948446,16067802.59174647,0.7833914573121663
207
+ 2032-02-01,,,14105046.648554994,0.8319539370165457,15142272.367340164,0.8238701107707332,16820976.132860027,0.8120366773487253
208
+ 2032-03-01,,,10152557.52671226,0.813194846373251,10908130.312811287,0.8052014458631108,12132251.102155317,0.7935020360051604
209
+ 2032-04-01,,,8792626.044852147,0.8396624703181607,9454787.950577654,0.831314074032099,10528676.883025827,0.8190968083392035
210
+ 2032-05-01,,,7152136.182634645,0.8560230634607856,7697102.982359046,0.8474153353173173,8581836.452107018,0.8348203378014722
211
+ 2032-06-01,,,4842434.8466044655,0.8754871095671838,5215712.4470234625,0.8665848086483648,5822339.2687011175,0.8535606284543742
212
+ 2032-07-01,,,6154117.641584257,0.8484158604113348,6633977.272556679,0.8396930459611868,7414617.973814339,0.8269332613722746
213
+ 2032-08-01,,,5373010.623014334,0.8698537765853588,5796745.270141803,0.860812358719622,6486791.64236438,0.8475883894053061
214
+ 2032-09-01,,,6156101.183703475,0.8557088743650968,6647075.294299861,0.8467178950919665,7447444.274264975,0.8335695567387003
215
+ 2032-10-01,,,10365944.285927966,0.8074956529997506,11201909.271298401,0.7989201189043467,12566074.979047377,0.7863810976895858
216
+ 2032-11-01,,,10690866.866534898,0.8248320112710753,11562571.55907863,0.8159792868508753,12986525.161814947,0.8030367923525628
217
+ 2032-12-01,,,12146094.407350685,0.7410449102552389,13147297.681736026,0.7330078376738405,14784476.660123067,0.7212594702707794
218
+ 2033-01-01,,,13568603.28614014,0.8018259047876185,14699187.190125898,0.7930391632970883,16549836.669498866,0.7801967670852735
219
+ 2033-02-01,,,14175571.881797764,0.8313804993458498,15369406.452850264,0.8221760997509426,17325605.41684583,0.8087251711881847
220
+ 2033-03-01,,,10203320.31434582,0.8126343387083697,11071752.267503455,0.8035458206564055,12496218.635219976,0.7902661145819905
221
+ 2033-04-01,,,8836589.175076408,0.8390837194165464,9596609.76983632,0.8296047570124536,10844537.189516604,0.8157565107854641
222
+ 2033-05-01,,,7187896.863547817,0.8554330357564479,7812559.52709443,0.8456729114842396,8839291.545670226,0.8314159192958938
223
+ 2033-06-01,,,4866647.020837488,0.8748836659551077,5293948.133728814,0.8648029692585852,5997009.446762151,0.8500797865683272
224
+ 2033-07-01,,,6184888.229792177,0.8478310760944049,6733486.931645028,0.8379665004117082,7637056.51302877,0.8235610065643622
225
+ 2033-08-01,,,5399875.676129405,0.8692542158389073,5883696.449193929,0.8590423884262725,6681395.391635312,0.8441319024615356
226
+ 2033-09-01,,,6186881.6896219915,0.8551190632206611,6746781.423714358,0.84497690530949,7670867.602492924,0.830170238950011
227
+ 2033-10-01,,,10417774.007357607,0.8069390735958308,11369937.910367874,0.7972774091280567,12943057.228418801,0.7831742156334273
228
+ 2033-11-01,,,10744321.200867571,0.8242634825025775,11736010.132464807,0.8143015006491727,13376120.916669395,0.7997619879512408
229
+ 2033-12-01,,,12206824.879387435,0.7405341330976217,13344507.146962065,0.7315006542739587,15228010.959926758,0.7183181558624839
230
+ 2034-01-01,,,13636446.302570838,0.8012732333491085,14919674.997977784,0.7914085457225608,17046331.769583832,0.7770151048861319
231
+ 2034-02-01,,,14246449.741206754,0.8308074569263182,15599947.549643017,0.8204855718934827,17845373.5793512,0.8054271694337342
232
+ 2034-03-01,,,10254336.915917547,0.8120742173824373,11237828.551516006,0.8018935996845519,12871105.194276575,0.7870433893284347
233
+ 2034-04-01,,,8880772.120951787,0.8385053674283266,9740558.916383862,0.8278989546267658,11169873.3052021,0.8124298350498464
234
+ 2034-05-01,,,7223836.3478655545,0.8548434147382226,7929747.920000847,0.8439340703581155,9104470.292040335,0.8280253840953047
235
+ 2034-06-01,,,4890980.255941674,0.8742806382762747,5373357.355734745,0.8630247936205575,6176919.730165016,0.8466131396437531
236
+ 2034-07-01,,,6215812.670941138,0.8472466948494978,6834489.235619703,0.8362435049208474,7866168.208419633,0.8202025038970644
237
+ 2034-08-01,,,5426875.054510051,0.8686550683493713,5971951.895931838,0.8572760574798807,6881837.253384371,0.8406895111591659
238
+ 2034-09-01,,,6217816.098070102,0.8545296586130706,6847983.145070072,0.8432394952853253,7900993.630567713,0.8267847836654584
239
+ 2034-10-01,,,10469862.877394393,0.8063828778232435,11540486.979023391,0.7956380770303919,13331348.945271365,0.779980411323609
240
+ 2034-11-01,,,10798042.80687191,0.8236953456017044,11912050.28445178,0.8126271642489349,13777404.544169478,0.7965005382853044
241
+ 2034-12-01,,,12267859.003784373,0.7400237080013994,13544674.754166495,0.7299965698884179,15684851.288724562,0.7153888362089266
242
+ 2035-01-01,,,13704628.53408369,0.8007209428483025,15143470.12294745,0.7897812809631244,17557721.722671345,0.7738464175861138
243
+ 2035-02-01,,,14317681.989912786,0.830234809485518,15833946.762887662,0.8187985200364047,18380734.786731742,0.8021426170140633
244
+ 2035-03-01,,,10305608.600497134,0.8115144821291641,11406395.979788747,0.8002447759478898,13257238.350104874,0.7838338064301797
245
+ 2035-04-01,,,8925175.981556546,0.8379274140785434,9886667.30012962,0.8261966596483755,11504969.504358165,0.809116725582231
246
+ 2035-05-01,,,7259955.529604882,0.8542542001257947,8048694.138800859,0.842198804572316,9377604.400801545,0.8246486755832353
247
+ 2035-06-01,,,4915435.157221382,0.8736780262439964,5453957.716070767,0.8612502742010122,6362227.322069967,0.8431606297932387
248
+ 2035-07-01,,,6246891.734295842,0.8466627163987902,6937006.574153998,0.8345240521891067,8102153.254672223,0.8168576972888034
249
+ 2035-08-01,,,5454009.429782601,0.868056333831907,6061531.174370815,0.8555133583973582,7088292.370985903,0.8372611580158135
250
+ 2035-09-01,,,6248905.178560451,0.853940660262113,6950702.892246123,0.8415056576589068,8138023.439484744,0.8234131343533991
251
+ 2035-10-01,,,10522212.191781363,0.8058270654175639,11713594.283708742,0.7940021156662961,13731289.413629506,0.7767996314287491
252
+ 2035-11-01,,,10852033.020906268,0.8231276002983546,12090731.038718555,0.8109562705568076,14190726.680494564,0.7932523888938039
253
+ 2035-12-01,,,12329198.298803294,0.7395136347239082,13747844.87547899,0.7284955781451399,16155396.8273863,0.7124714623951931
254
+ 2036-01-01,,,13773151.67675411,0.8001690330226326,15370622.17479166,0.7881573621248449,18084453.374351487,0.7706906522732516
255
+ 2036-02-01,,,14389270.399862347,0.829662556751203,16071455.964330977,0.8171149370324866,18932156.830333695,0.798871459082445
256
+ 2036-03-01,,,10357136.643499617,0.8109551326824428,11577491.919485576,0.7985993424611507,13654955.500608021,0.7806373122923674
257
+ 2036-04-01,,,8969801.861464329,0.8373498590924294,10034967.309631564,0.8244978648654827,11850118.589488909,0.8058171270590334
258
+ 2036-05-01,,,7296255.307252906,0.8536653916390426,8169424.55088287,0.8404671067753593,9658932.532825591,0.8212857373740995
259
+ 2036-06-01,,,4940012.333007488,0.8730758295717818,5535767.081811828,0.8594794034821687,6553094.141732066,0.8397221993654383
260
+ 2036-07-01,,,6278126.192967321,0.8460791404646494,7041061.672766307,0.8328081349319968,8345217.85231239,0.8135265308867031
261
+ 2036-08-01,,,5481279.476931513,0.8674580120018663,6152454.141986377,0.8537542837110009,7300941.14211548,0.8338467857835105
262
+ 2036-09-01,,,6280149.704453253,0.8533520678877694,7054963.435629814,0.8397753850848033,8382164.142669286,0.8200552347127273
263
+ 2036-10-01,,,10574823.25274027,0.8052716361145503,11889298.197964372,0.7923695181049916,14143228.096038392,0.7736318228349538
264
+ 2036-11-01,,,10906293.186010798,0.8225602463226129,12272092.004299333,0.8092888124940235,14616448.480909402,0.790017485537884
265
+ 2036-12-01,,,12390844.290297309,0.739003913022651,13954062.548611175,0.7269976726851494,16640058.732207887,0.7095659857058465
266
+ 2037-01-01,,,13842017.43513788,0.7996175036097126,15601181.507413534,0.7865367823279646,18626986.975582033,0.7675477562513539
267
+ 2037-02-01,,,14461216.751861656,0.8290906984513159,16312527.80379594,0.8154348157492012,19500121.535243705,0.795613641015816
268
+ 2037-03-01,,,10408922.326717114,0.81039616877635,11751154.298277859,0.7969572922534294,14064604.165626261,0.7774538535387004
269
+ 2037-04-01,,,9014650.870771648,0.8367727021954056,10185491.819276035,0.8228025630811164,12205622.147173576,0.8025309843822789
270
+ 2037-05-01,,,7332736.583789169,0.8530769889980377,8291965.919146113,0.8387389696308805,9948700.508810358,0.817936513312252
271
+ 2037-06-01,,,4964712.394672525,0.8724740479733367,5618803.588039004,0.857712173961705,6749686.965984029,0.8362977909441083
272
+ 2037-07-01,,,6309516.823932158,0.8454959667696345,7146677.597857802,0.8310957458800063,8595574.387881761,0.8102089490656571
273
+ 2037-08-01,,,5508685.874316171,0.8668601025747984,6244740.954116172,0.8519988259684608,7519969.376378945,0.8304463374477471
274
+ 2037-09-01,,,6311550.452975518,0.8527638812102141,7160787.88716426,0.8380486702326869,8633629.066949366,0.8167110286719341
275
+ 2037-10-01,,,10627697.36900397,0.804716589650143,12067637.670933835,0.7907402774299536,14567524.938919544,0.7704769326449283
276
+ 2037-11-01,,,10960824.65194085,0.8219932834047505,12456173.38436382,0.8076247829963697,15054941.935336683,0.7867957741998745
277
+ 2037-12-01,,,12452798.511748794,0.7384945426552981,14163373.486840341,0.7255028471625455,17139260.494174127,0.7066723576241111
278
+ 2038-01-01,,,13911227.522313565,0.7990663543473367,15835199.230024736,0.7849195347068708,19185796.584849495,0.7644176770391262
279
+ 2038-02-01,,,14533522.835620964,0.828519234313986,16557215.720852874,0.813758149068688,20085125.181301016,0.7923691084138693
280
+ 2038-03-01,,,10460966.938350698,0.8098375901451457,11927421.612752026,0.7953186183681527,14486542.290595049,0.774283377010552
281
+ 2038-04-01,,,9059724.125125507,0.8361959431130827,10338274.196565175,0.8211107471131022,12571790.811588787,0.7992582426786853
282
+ 2038-05-01,,,7369400.266708115,0.8524889919230445,8416345.407933304,0.837014385817598,10247161.52407467,0.8146009474710533
283
+ 2038-06-01,,,4989535.956645887,0.8718726811625657,5703085.641859589,0.8559485781527244,6952177.574963549,0.8328873473471513
284
+ 2038-07-01,,,6341064.408051818,0.8449131950364955,7253877.761825668,0.8293868777785716,8853441.619518213,0.806904896427399
285
+ 2038-08-01,,,5536229.30368775,0.8662626052664474,6338412.068427914,0.850246977732713,7745568.457670312,0.8270597562265198
286
+ 2038-09-01,,,6343108.205240396,0.8521760999498139,7268199.705471723,0.8363255057873025,8892637.938957848,0.8133804603881725
287
+ 2038-10-01,,,10680835.855848989,0.8041619257604643,12248652.235997843,0.7891143867388766,15004550.68708713,0.7673349081770942
288
+ 2038-11-01,,,11015628.775200553,0.8214267112752245,12643015.985129276,0.8059641750141573,15506590.193396783,0.7835872010823927
289
+ 2038-12-01,,,12515062.504307535,0.7379855233796875,14375824.089142943,0.7240110952444753,17653438.308999352,0.7037905298310654
290
+ 2039-01-01,,,13980783.659925131,0.79851558497348,16072727.218475105,0.7833056124100682,19761370.48239498,0.7613003623692933
291
+ 2039-02-01,,,14606190.449799066,0.8279481640675307,16805573.956665665,0.8120849298877216,20687678.936740045,0.7891378070981433
292
+ 2039-03-01,,,10513271.773042452,0.8092793965232729,12106332.936943304,0.7936833138630534,14921138.5593129,0.7711258297660772
293
+ 2039-04-01,,,9105022.745751131,0.8356195815712605,10493348.30951365,0.8194224097940356,12948944.53593645,0.7959988472987435
294
+ 2039-05-01,,,7406247.2680416545,0.8519014001345192,8542590.589052303,0.8352933480292848,10554576.36979691,0.811278984151933
295
+ 2039-06-01,,,5014483.636429116,0.8712717288535691,5788631.926487482,0.8541886085837248,7160742.902212455,0.8294908116256592
296
+ 2039-07-01,,,6372769.730092076,0.8443308249881737,7362685.928253052,0.8276815233880449,9119044.868103761,0.8036143177995786
297
+ 2039-08-01,,,5563910.4502061885,0.865665519792754,6433488.249454332,0.8484987315820238,7977935.511400423,0.8236869855693842
298
+ 2039-09-01,,,6374823.746266597,0.8515887238271282,7377222.701053799,0.8346058844484361,9159417.077126583,0.8100634742463234
299
+ 2039-10-01,,,10734240.035128232,0.8036076441818185,12432382.019537808,0.787491839143649,15454687.207699744,0.7642056969647104
300
+ 2039-11-01,,,11070706.919076556,0.8208605296646776,12832661.224906215,0.804306981512195,15971787.899198689,0.7803917126074416
301
+ 2039-12-01,,,12577637.816829072,0.737476854953823,14591461.450480087,0.7225224106111083,18183041.45826933,0.7009204542048321
302
+ 2040-01-01,,,14050687.578224756,0.7979651952262982,16313818.12675223,0.7816950086001482,20354211.59686683,0.7581957601877278
303
+ 2040-02-01,,,14679221.402048063,0.8273774874404543,17057657.56601565,0.8104151511176811,21308309.30484225,0.7859196831111165
304
+ 2040-03-01,,,10565838.131907662,0.8087215876453576,12287927.930997454,0.7920513718101366,15368772.716092288,0.7679811590793295
305
+ 2040-04-01,,,9150547.859479887,0.8350436172959277,10650748.534156354,0.8177375439712473,13337412.872014543,0.7927527438158076
306
+ 2040-05-01,,,7443278.504381861,0.8513142133531123,8670729.447888087,0.8335758489747365,10871213.660890818,0.8079705678834608
307
+ 2040-06-01,,,5039556.054611262,0.8706711907606444,5875461.405384794,0.8524322577985669,7375565.189278829,0.8261081270629631
308
+ 2040-07-01,,,6404633.578742536,0.8437488563478016,7473126.217176848,0.8259796754836649,9392616.214146875,0.8003371582348395
309
+ 2040-08-01,,,5591730.002457219,0.8650688458698541,6529990.573196146,0.8467540801099199,8217273.576742435,0.8203279691565095
310
+ 2040-09-01,,,6406697.864997929,0.8510017525629099,7487881.0415696055,0.8328897989308841,9434199.58944038,0.8067600148580671
311
+ 2040-10-01,,,10787911.235303873,0.8030537446506913,12618867.749830876,0.7858726277703219,15918327.823930738,0.7610892467549959
312
+ 2040-11-01,,,11126060.453671938,0.8202947383039385,13025151.143279808,0.8026531954697549,16450941.536174648,0.7772092554155171
313
+ 2040-12-01,,,12640526.005913217,0.7369685371358758,14810333.372237286,0.7210367869556077,18728532.70201741,0.6980620828197772
314
+ 2041-01-01,,,14120941.01611588,0.7974151848441277,16558525.398653511,0.7800877164537623,20964837.944772836,0.7551038186525802
315
+ 2041-02-01,,,14752617.5090583,0.8268072041614478,17313522.429505885,0.8087488056845228,21947558.58398752,0.7827146827153092
316
+ 2041-03-01,,,10618667.3225672,0.808164163246209,12472246.849962413,0.7904227852956538,15829835.897575058,0.7648493124393797
317
+ 2041-04-01,,,9196300.598777285,0.8344680500132623,10810509.762168698,0.8160561425067763,13737535.258174978,0.7895198780251848
318
+ 2041-05-01,,,7480494.89690377,0.8507274312996662,8800790.389606407,0.8318618813777406,11197350.070717543,0.8046756434204211
319
+ 2041-06-01,,,5064753.834884317,0.8700710665982877,5963593.326465566,0.850679518356442,7596832.144957194,0.8227392371736865
320
+ 2041-07-01,,,6436656.746636247,0.8431672888387022,7585223.1104345,0.8242813268555257,9674394.70057128,0.7970733630099026
321
+ 2041-08-01,,,5619688.652469505,0.8644725832140804,6627940.431794087,0.8450130159251582,8463791.784044709,0.8169826508977394
322
+ 2041-09-01,,,6438731.354322918,0.8504151858781033,7600199.257193149,0.8311772419644222,9717225.577123592,0.80347002706096
323
+ 2041-10-01,,,10841850.79148039,0.8025002269037503,12808150.766078334,0.7842567457590793,16395877.658648659,0.7579855055082586
324
+ 2041-11-01,,,11181690.755940296,0.8197293369240207,13220528.410429003,0.8010028098805462,16944469.78225989,0.7740397763647175
325
+ 2041-12-01,,,12703728.63594278,0.7364605696841843,15032488.372820843,0.7195542179841052,19290388.683077935,0.6952153679457088
326
+ 2042-01-01,,,14191545.721196456,0.7968655535654848,16806903.279633313,0.7784837291615911,21593783.08311602,0.7520244861334134
327
+ 2042-02-01,,,14826380.596603591,0.8262373139593906,17573225.26594847,0.8070858865287466,22605985.341507144,0.7795227523923827
328
+ 2042-03-01,,,10671760.659180034,0.8076071230608192,12659330.552711848,0.7887975474200722,16304730.97450231,0.7617302375494397
329
+ 2042-04-01,,,9242282.101771172,0.8338928794496303,10972667.408601228,0.8143781982773383,14149661.315920228,0.7863001959432295
330
+ 2042-05-01,,,7517897.371388288,0.8501410536952151,8932802.245450502,0.8301514379770458,11533270.57283907,0.8013941557428887
331
+ 2042-06-01,,,5090077.604058738,0.86947135608119,6053047.226362549,0.8489303828318412,7824737.109305911,0.8193840857028009
332
+ 2042-07-01,,,6468840.030369428,0.8425861221843893,7699001.457091016,0.8225864703085458,9964626.541588418,0.7938228776246508
333
+ 2042-08-01,,,5647787.095731852,0.8638767315419599,6727359.538270999,0.8432755316516913,8717705.53756605,0.8136509749316536
334
+ 2042-09-01,,,6470925.011094531,0.8498290234938459,7714202.246051045,0.8294682062937757,10008742.3444373,0.800193455917512
335
+ 2042-10-01,,,10896060.04543779,0.8019470906778452,13000273.027569508,0.7826441862642118,16887753.98840812,0.7548944213970253
336
+ 2042-11-01,,,11237599.209719995,0.8191643252561245,13418836.336585438,0.7993558177526833,17452803.875727687,0.7708832225298529
337
+ 2042-12-01,,,12767247.279122492,0.7359529523572523,15257975.698413154,0.7180746974156729,19869100.343570273,0.692380262047079
338
+ 2043-01-01,,,14262503.449802438,0.7963163011290667,17059006.82882781,0.7768830399283165,22241596.5756095,0.7489577112103407
339
+ 2043-02-01,,,14900512.499586606,0.8256678165633475,17836823.644937694,0.8054263866053692,23284164.90175236,0.7763438388422491
340
+ 2043-03-01,,,10725119.462475933,0.8070504668243622,12849220.511002524,0.7871756512980447,16793872.90373738,0.7586238823259897
341
+ 2043-04-01,,,9288493.512280026,0.8333181053315871,11137257.419730244,0.8127037041742952,14574151.155397836,0.7830936438064444
342
+ 2043-05-01,,,7555486.858245228,0.8495550802609865,9066794.27913226,0.8284445115263305,11879268.690024242,0.7981260500553122
343
+ 2043-06-01,,,5115527.992079031,0.8688720589242394,6143842.934757985,0.8471848438145233,8059479.222585089,0.8160426166246882
344
+ 2043-07-01,,,6501184.230521274,0.842005356108567,7814486.478947381,0.8208950986624381,10263565.337836072,0.7905856478012204
345
+ 2043-08-01,,,5676026.031210511,0.8632812905702157,6828269.931345062,0.841541619928639,8979236.703693032,0.8103328856246365
346
+ 2043-09-01,,,6503279.636150003,0.8492432651314666,7829915.279741811,0.8277626846785867,10309004.61477042,0.7969302467142685
347
+ 2043-10-01,,,10950540.345664978,0.8013943357100058,13195277.122983051,0.7810349424540846,17394386.608060364,0.7518159428051762
348
+ 2043-11-01,,,11293787.205768595,0.8185997030316341,13620118.881634219,0.7977122121086578,17976387.991999518,0.7677395412015663
349
+ 2043-12-01,,,12831083.515518103,0.735445684913751,15486845.33388935,0.7165982189822983,20465173.35387738,0.6895567177821922
350
+ 2044-01-01,,,14333815.967051448,0.7957674272737497,17314891.931260224,0.7752856419725932,22908844.472877786,0.7459034426731663
351
+ 2044-02-01,,,14975015.062084539,0.8250987117025711,18104375.99961176,0.803770298883892,23982689.848804932,0.773177888982179
352
+ 2044-03-01,,,10778745.059788313,0.8064941942721954,13041958.81866756,0.7855570900583826,17297689.0908495,0.7555301948979066
353
+ 2044-04-01,,,9334935.979841424,0.8327437273858761,11304316.281026198,0.8110326531036259,15011375.69005977,0.7799001680705794
354
+ 2044-05-01,,,7593264.292536453,0.8489695107183991,9202796.193319242,0.8267410947941739,12235646.750724971,0.7948712717855969
355
+ 2044-06-01,,,5141105.632039425,0.8682731748425211,6236000.578779355,0.8454428939094846,8301263.599262641,0.8127147741422037
356
+ 2044-07-01,,,6533690.15167388,0.8414249903351305,7931703.77613159,0.8192072047516792,10571472.297971154,0.7873616194830948
357
+ 2044-08-01,,,5704406.161366562,0.8626862600157656,6930693.980315238,0.8398112734102566,9248613.804803824,0.8070283275699485
358
+ 2044-09-01,,,6535796.034330754,0.8486579105124868,7947364.008937935,0.8260606698933857,10618274.753213532,0.7936803449608995
359
+ 2044-10-01,,,11005293.047393303,0.8008419617374442,13393206.279827796,0.7794290075111103,17916218.206302173,0.748750018327084
360
+ 2044-11-01,,,11350256.141797436,0.8180354699821196,13824420.664858729,0.7960719859853077,18515679.631759502,0.7646086798854486
361
+ 2044-12-01,,,12895238.933095692,0.7349387671125175,15719148.01389769,0.7151247764288567,21079128.554493703,0.6867446880024122
362
+ 2045-01-01,,,14405485.046886703,0.795218931738591,17574615.310229126,0.7736915285270181,23596109.80706412,0.742861629520532
363
+ 2045-02-01,,,15049890.13739496,0.8245299991064995,18375941.639605936,0.8021176163482724,24702170.544269077,0.770024849945915
364
+ 2045-03-01,,,10832638.785087254,0.8059383051398578,13237588.200947573,0.7839418568440251,17816619.763574988,0.7524491236056
365
+ 2045-04-01,,,9381610.65974063,0.8321697453394289,11473881.025241591,0.8093650379858954,15461716.960761564,0.7767197154097402
366
+ 2045-05-01,,,7631230.613999136,0.8483843447890643,9340838.13621903,0.8250411805640231,12602716.15324672,0.7916297665841949
367
+ 2045-06-01,,,5166811.160199623,0.8676747035513164,6329540.587461045,0.8437045257369259,8550301.50724052,0.809400502685745
368
+ 2045-07-01,,,6566358.602432248,0.8408450245881649,8050679.3327735625,0.8175227814254794,10888616.46691029,0.7841507388342001
369
+ 2045-08-01,,,5732928.192173394,0.8620916395957234,7034654.390019966,0.838084484765903,9526072.21894794,0.8037372455867987
370
+ 2045-09-01,,,6568475.014502406,0.8480729593586203,8066574.469072005,0.8243621547275596,10936822.995809937,0.7904436963892859
371
+ 2045-10-01,,,11060319.512630269,0.800289968497553,13594104.37402521,0.7778263746317201,18453704.75249124,0.7456965967667538
372
+ 2045-11-01,,,11407007.422506422,0.8174716258393356,14031786.97483161,0.7944351324337883,19071150.02071229,0.7614905863011651
373
+ 2045-12-01,,,12959715.12776117,0.7344321987125549,15954935.234106155,0.7136543635130848,21711502.411128514,0.683944125751377
model/revenue/capture_factor_history_forecast/capture_factor_monthly_historical.csv ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ month,p_market_eur_mwh,wind_mwh,price_x_wind,p_wind_capture_eur_mwh,capture_factor
2
+ 2015-01-01,31.05307098765432,7830853.25,193848426.705,24.754445079787445,0.7971657646881044
3
+ 2015-02-01,36.71691964285714,5325677.75,169937033.715,31.908996693425546,0.8690542944179981
4
+ 2015-03-01,31.34314939434724,7010958.25,181407454.6275,25.87484451608309,0.8255342879088481
5
+ 2015-04-01,29.724375,5157796.5,133846308.9275,25.950288835067454,0.8730305964403778
6
+ 2015-05-01,25.357916666666668,5105062.25,117917513.8575,23.098153966193067,0.9108853171899531
7
+ 2015-06-01,30.06438888888889,3871212.5,108847568.965,28.117177490256605,0.9352319647730498
8
+ 2015-07-01,34.99568548387097,5401805.25,159520997.85,29.531053132654122,0.8438483980050792
9
+ 2015-08-01,31.605094086021502,3553163.75,105496375.725,29.690828553848664,0.9394317407515805
10
+ 2015-09-01,31.881319444444443,5328808.5,149441333.1175,28.044042700633735,0.8796387097310245
11
+ 2015-10-01,39.38145161290323,3438960.5,126051994.9375,36.654097927993064,0.9307452220979952
12
+ 2015-11-01,32.389375,9763092.0,264461081.3275,27.087840750399565,0.8363187233591128
13
+ 2015-12-01,27.780604838709678,10359892.25,247403719.2625,23.880916257840422,0.8596254975904842
14
+ 2016-01-01,29.035524193548387,8406655.5,205866880.8525,24.488559196044132,0.843399934260027
15
+ 2016-02-01,21.989554597701147,9366679.75,174598047.8475,18.640334943393363,0.8476904277698321
16
+ 2016-03-01,24.30504710632571,5710792.5,122859575.4525,21.513577222863553,0.885148550782457
17
+ 2016-04-01,24.21348611111111,5587231.75,129803828.425,23.232225587385024,0.9594746283445817
18
+ 2016-05-01,22.53751009421265,5706867.75,108069163.365,18.936686129619876,0.840229734804759
19
+ 2016-06-01,27.596571018651364,2902409.5,77164302.4125,26.586290601825826,0.9633910888369888
20
+ 2016-07-01,27.188306451612902,4302145.75,103319912.6825,24.01590245576873,0.8833173371246897
21
+ 2016-08-01,27.182567204301076,4262079.75,108755321.68,25.516960746687108,0.9387251967374729
22
+ 2016-09-01,30.493861111111112,3729333.5,103678159.8375,27.80072091635141,0.9116825453835887
23
+ 2016-10-01,37.17476388888889,4488192.0,152182293.42,33.907260077109,0.9121042484211579
24
+ 2016-11-01,38.222541666666665,7267011.75,240768630.505,33.13172439895945,0.8668111264786234
25
+ 2016-12-01,37.477889784946235,8416867.75,209774365.61,24.92309156336691,0.6650078674754464
26
+ 2017-01-01,52.372956989247314,7186927.25,299615871.055,41.68900847785818,0.796002572213315
27
+ 2017-02-01,39.70160714285714,8439755.75,278465181.54,32.99445976739315,0.8310610612983536
28
+ 2017-03-01,31.701386271870795,8511720.0,247227272.4325,29.04551282613855,0.9162221669754281
29
+ 2017-04-01,28.86991666666667,7421613.0,183933767.205,24.783529834417397,0.8584551912833392
30
+ 2017-05-01,30.460510752688172,4963043.75,131569519.505,26.509844791313796,0.8703020447211074
31
+ 2017-06-01,30.00161111111111,6153125.0,158199329.8875,25.710404044692737,0.85696744583063
32
+ 2017-07-01,33.009112903225805,5011439.25,148281318.315,29.58856945437381,0.8963757838970061
33
+ 2017-08-01,30.848387096774193,4804535.25,131183684.21,27.304136068103567,0.8851074120163239
34
+ 2017-09-01,34.34861111111111,5904335.5,167116781.355,28.30407949463576,0.8240239875515648
35
+ 2017-10-01,28.401478494623657,11014475.5,222444843.28,20.19568188063063,0.7110785406630726
36
+ 2017-11-01,40.366625,9256318.75,290753712.135,31.41137637843338,0.7781521585823284
37
+ 2017-12-01,30.765725806451613,13454183.0,305012827.27,22.67048302152572,0.7368746365402401
38
+ 2018-01-01,29.46159946236559,13144978.0,296746631.88,22.57490517519314,0.7662484585750495
39
+ 2018-02-01,40.11510416666666,6859993.0,247755443.2125,36.11599067411585,0.9003090338258714
40
+ 2018-03-01,37.36347240915209,9588788.75,291951885.8775,30.447212206807663,0.8148924669900246
41
+ 2018-04-01,32.056263888888886,8002044.25,235749094.075,29.461108525487095,0.9190437359638375
42
+ 2018-05-01,33.54216397849462,6270346.75,177656212.9,28.332757339137586,0.8446908004296617
43
+ 2018-06-01,42.42323611111111,5135329.25,194167016.4875,37.810042362424966,0.891257853677082
44
+ 2018-07-01,49.54345430107527,4064678.75,191424653.24,47.09465741665316,0.9505727463099205
45
+ 2018-08-01,56.189408602150536,5343261.5,281139784.47,52.6157636997553,0.9364000264231565
46
+ 2018-09-01,54.832138888888885,6545188.25,316743606.16,48.39335311096667,0.8825727774185559
47
+ 2018-10-01,53.12668010752688,8733167.0,382748623.9175,43.82701303175583,0.8249529792385146
48
+ 2018-11-01,56.676013888888896,8035869.5,419561038.75,52.21103189269064,0.9212191950381042
49
+ 2018-12-01,48.13212365591398,12092006.75,482731044.0375,39.92149971612446,0.8294148831145396
50
+ 2019-01-01,49.393373655913976,12551354.25,490622629.265,39.08921854109886,0.7913858813006717
51
+ 2019-02-01,42.82078869047619,8914979.0,342723875.3975,38.44359873393981,0.8977788571766797
52
+ 2019-03-01,30.626958277254378,13736642.0,339402745.9525,24.707839510740687,0.8067350106096033
53
+ 2019-04-01,36.95590277777778,7303645.75,248842402.1525,34.07098463839104,0.9219362017284695
54
+ 2019-05-01,37.84356182795699,6428337.75,230898588.0775,35.91886379608788,0.9491406744264954
55
+ 2019-06-01,32.517583333333334,5114514.5,124368577.42,24.316790463689173,0.7478043560132084
56
+ 2019-07-01,39.68502688172043,4862707.5,177743961.98,36.552468348137324,0.9210644724288692
57
+ 2019-08-01,36.84849462365591,4493530.5,137968102.6075,30.70372007211256,0.8332421822301923
58
+ 2019-09-01,35.75070833333333,7145538.75,220748243.425,30.893156016402543,0.8641271028355628
59
+ 2019-10-01,36.999556451612904,9341217.0,302823141.18,32.41795380409212,0.8761714169867824
60
+ 2019-11-01,41.00120833333333,7880445.25,292288457.58,37.09034810945485,0.9046159763857736
61
+ 2019-12-01,31.966142473118282,12208935.0,323883913.7725,26.528432969173803,0.8298915951927173
62
+ 2020-01-01,35.0349059139785,12670559.0,394734120.9,31.153646883298517,0.8892173696652799
63
+ 2020-02-01,21.919008620689652,17239833.25,302821991.81,17.56525062735163,0.801370670148446
64
+ 2020-03-01,22.485827725437417,11552708.75,212318996.7,18.37828697101015,0.8173275716339073
65
+ 2020-04-01,17.093125,6991474.0,78419784.1275,11.21648798629588,0.6561987925727963
66
+ 2020-05-01,17.596505376344084,6132951.75,80061538.61,13.054323900395923,0.7418702532802646
67
+ 2020-06-01,26.18488888888889,4983084.0,110775784.4775,22.230366672024797,0.8489769334655407
68
+ 2020-07-01,30.062862903225806,5480898.5,119380704.9125,21.781228919400714,0.7245227771392173
69
+ 2020-08-01,34.86395161290322,5156488.25,155318356.07,30.120956073156957,0.8639570295298692
70
+ 2020-09-01,43.690194444444444,4632294.25,176342595.7925,38.06809029726468,0.8713188572706236
71
+ 2020-10-01,34.01510752688172,10816688.5,325974566.6075,30.13626273951589,0.8859669990959038
72
+ 2020-11-01,38.78570833333333,8665897.5,278836504.7425,32.17629850139585,0.8295916172231614
73
+ 2020-12-01,43.51974462365591,9073761.0,306943039.6375,33.82754291605212,0.7772918524357464
74
+ 2021-01-01,52.806223118279576,9223364.5,430476355.135,46.67237808231476,0.8838423830800066
75
+ 2021-02-01,48.70494047619048,8487553.25,373428984.98,43.99724796778153,0.9033426083189586
76
+ 2021-03-01,47.16483176312248,9086611.25,318634331.8425,35.066354560122726,0.743485203895938
77
+ 2021-04-01,53.61313888888889,7735461.0,348349722.7575,45.03283291810275,0.8399588953639053
78
+ 2021-05-01,53.34893817204301,8828518.25,381480066.51,43.2099765450448,0.809950076338887
79
+ 2021-06-01,74.07995833333334,3361513.75,215409485.995,64.08109620107905,0.8650260832050826
80
+ 2021-07-01,81.36924731182796,4704354.75,327201859.7975,69.55297318883106,0.85478206431339
81
+ 2021-08-01,82.69688172043011,6191015.5,455769864.25,73.61794914743793,0.8902143299225604
82
+ 2021-09-01,128.37230555555556,4465397.5,529195180.915,118.51020674307271,0.9231758067302543
83
+ 2021-10-01,139.59403225806452,10167443.25,1139547028.6075,112.07803186976236,0.8028855536070918
84
+ 2021-11-01,176.1513611111111,7822972.75,1114973316.6325,142.525527349242,0.8091082944249354
85
+ 2021-12-01,221.06038978494624,9782408.0,1621039440.71,165.70965356484825,0.7496126000956357
86
+ 2022-01-01,167.72657258064518,12982727.75,1718042438.0675,132.33293273576504,0.7889801281913014
87
+ 2022-02-01,128.80267857142857,17728127.25,1963052746.3075,110.73097110736838,0.8596946300768242
88
+ 2022-03-01,252.00685060565274,6793504.0,1400309280.6425,206.1247451451416,0.8179331024127248
89
+ 2022-04-01,165.73190277777778,9550806.0,1252718775.385,131.16367093887155,0.7914207750015567
90
+ 2022-05-01,177.4769489247312,6454706.0,906536203.7325,140.44577765935426,0.7913465861919791
91
+ 2022-06-01,218.0332361111111,4412514.75,875988301.9975,198.52359745596317,0.9105198867698973
92
+ 2022-07-01,315.0009946236559,5502496.0,1557781197.615,283.1044670664004,0.8987415020852123
93
+ 2022-08-01,465.18350806451616,3527019.25,1628417510.9125,461.6979368378837,0.9925071049033212
94
+ 2022-09-01,346.11512500000003,6189613.5,1786718900.0125,288.664049865553,0.8340116597492033
95
+ 2022-10-01,152.67469086021507,8613400.25,1113456716.235,129.27028628850724,0.8467040971896496
96
+ 2022-11-01,173.634375,10118516.25,1405044651.6125,138.85876317216963,0.7997193134836902
97
+ 2022-12-01,251.61639784946237,9410138.25,1442851476.595,153.3294663970532,0.6093778772271731
98
+ 2023-01-01,117.82931451612903,14692525.75,1320543325.67,89.87857827439915,0.7627862272091563
99
+ 2023-02-01,128.31184523809523,10445029.0,1122610522.9875,107.47797090726124,0.837630935069364
100
+ 2023-03-01,102.5214535666218,12133716.25,1058594984.825,87.24408606678931,0.8509837017682864
101
+ 2023-04-01,100.74399999999999,8382426.5,764732911.3025,91.23049409410271,0.9055675186026237
102
+ 2023-05-01,81.71538978494624,6771381.25,558802219.1075,82.52411117857231,1.0098968064125304
103
+ 2023-06-01,94.7561111111111,4872287.25,453830157.63,93.14519738753087,0.9829993685400273
104
+ 2023-07-01,77.6061559139785,8392192.75,521347177.1025,62.12287927997126,0.8004890662131304
105
+ 2023-08-01,94.3218817204301,5778036.5,400009739.9725,69.2293549846042,0.7339691885049526
106
+ 2023-09-01,100.72348611111111,5339625.25,472349969.6125,88.46125851481806,0.878258506831602
107
+ 2023-10-01,87.49303763440861,11857250.75,838484140.9875,70.71488649993339,0.8082344425554973
108
+ 2023-11-01,91.12227777777777,14477253.5,1119854443.9775,77.35268598961122,0.8488888543617532
109
+ 2023-12-01,68.51932795698924,16331164.75,759397979.57,46.49992766560022,0.6786395758987744
110
+ 2024-01-01,76.57114247311829,15593084.75,1023895370.9975,65.66342628244229,0.8575479503325244
111
+ 2024-02-01,61.335847701149426,14148354.0,765264891.5,54.08861635070765,0.8818434631285619
112
+ 2024-03-01,64.70199192462988,9393471.75,527184990.815,56.122486429471614,0.8673996697790639
113
+ 2024-04-01,62.360819444444445,9724048.5,492075361.94,50.60396006251923,0.81147041545214
114
+ 2024-05-01,67.21001344086021,6274470.0,376861146.4975,60.06262624532431,0.8936559177774147
115
+ 2024-06-01,72.88772222222222,5693810.5,340882267.415,59.86891685541695,0.8213854820827964
116
+ 2024-07-01,67.69702956989246,5548569.25,299086651.03,53.90338257560721,0.7962444278290781
117
+ 2024-08-01,82.04717741935484,5204624.75,348505854.545,66.96080337876424,0.8161256180272725
118
+ 2024-09-01,78.30997222222223,8986503.75,586459140.7675,65.25998954459904,0.8333547783596332
119
+ 2024-10-01,86.10174731182795,8389045.5,585320668.665,69.77202217642042,0.8103438589199886
120
+ 2024-11-01,113.90644444444445,10300191.5,938179143.0125,91.0836602418994,0.7996357070589065
121
+ 2024-12-01,108.31559139784946,13757540.0,1011699247.44,73.53780163023332,0.678921664750227
122
+ 2025-01-01,114.14016129032258,13253343.0,1153437066.3125,87.02989625428845,0.7624826815595828
123
+ 2025-02-01,128.52236607142856,7260679.75,843570877.09,116.18345749101522,0.9039940754471033
124
+ 2025-03-01,94.72749663526245,6526920.5,523174378.72,80.15638902297033,0.8461786901389727
125
+ 2025-04-01,77.93565277777778,5876514.75,455971894.0425,77.5922316952408,0.995593530428029
126
+ 2025-05-01,67.33862903225807,7894329.5,517310337.7625,65.52935721298434,0.9731317396080782
127
+ 2025-06-01,63.9875,8705267.75,495674921.255,56.93965257472982,0.8898558714550471
128
+ 2025-07-01,87.79522849462366,6193497.28,514036009.4487,82.99608221490976,0.9453370489262092
129
+ 2025-08-01,76.99025537634408,5483354.49,387579289.3329,70.68288034992608,0.9180756708029313
130
+ 2025-09-01,83.51108333333333,9763607.04,646757234.238,66.24162889681395,0.7932076348765756
131
+ 2025-10-01,84.51182795698925,13717685.62,809748019.2526,59.02949241466871,0.6984761049626177
132
+ 2025-11-01,101.88231944444445,9908591.42,887009557.9371,89.51923844056334,0.8786533220749594
133
+ 2025-12-01,93.47024193548387,12331010.68,1032426448.3832,83.72602012726503,0.8957505447033655
model/revenue/capture_factor_history_forecast/cf_his.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+
4
+ # -----------------------------
5
+ # CONFIG
6
+ # -----------------------------
7
+ PRICES_FILE = "../day_ahead_market_prices/prices_hourly_merged.csv"
8
+ WIND_FILE = "../produced_mwh_wind/wind_onshore_hourly_merged.csv"
9
+
10
+ # Column names – ADJUST if needed
11
+ PRICE_DATE_COL = "datetime"
12
+ PRICE_COL = "price_eur_mwh" # day-ahead price €/MWh
13
+
14
+ WIND_DATE_COL = "datetime"
15
+ WIND_COL = "wind_onshore_mwh" # hourly wind generation in MWh
16
+
17
+ OUTPUT_FILE = "capture_factor_monthly_historical.csv"
18
+
19
+ # -----------------------------
20
+ # 1. Load data
21
+ # -----------------------------
22
+ prices = pd.read_csv(PRICES_FILE, parse_dates=[PRICE_DATE_COL])
23
+ wind = pd.read_csv(WIND_FILE, parse_dates=[WIND_DATE_COL])
24
+
25
+ # ensure numeric
26
+ prices[PRICE_COL] = pd.to_numeric(prices[PRICE_COL], errors="coerce")
27
+ wind[WIND_COL] = pd.to_numeric(wind[WIND_COL], errors="coerce")
28
+
29
+ prices = prices.dropna(subset=[PRICE_DATE_COL, PRICE_COL])
30
+ wind = wind.dropna(subset=[WIND_DATE_COL, WIND_COL])
31
+
32
+ # -----------------------------
33
+ # 2. Merge hourly price & wind
34
+ # -----------------------------
35
+ hourly = prices.merge(
36
+ wind,
37
+ left_on=PRICE_DATE_COL,
38
+ right_on=WIND_DATE_COL,
39
+ how="inner",
40
+ suffixes=("_price", "_wind")
41
+ )
42
+
43
+ # keep one timestamp column only
44
+ hourly["timestamp"] = hourly[PRICE_DATE_COL]
45
+ hourly = hourly[["timestamp", PRICE_COL, WIND_COL]]
46
+
47
+ # -----------------------------
48
+ # 3. Add month identifier
49
+ # -----------------------------
50
+ hourly["month"] = hourly["timestamp"].dt.to_period("M").dt.to_timestamp()
51
+
52
+ # -----------------------------
53
+ # 4. Monthly aggregation
54
+ # -----------------------------
55
+ # Market price: simple average
56
+ monthly_market = (
57
+ hourly.groupby("month")[PRICE_COL]
58
+ .mean()
59
+ .rename("p_market_eur_mwh")
60
+ )
61
+
62
+ # Wind capture price: wind-weighted average
63
+ hourly["price_x_wind"] = hourly[PRICE_COL] * hourly[WIND_COL]
64
+
65
+ monthly_wind = (
66
+ hourly.groupby("month")
67
+ .agg(
68
+ wind_mwh=(WIND_COL, "sum"),
69
+ price_x_wind=("price_x_wind", "sum")
70
+ )
71
+ )
72
+
73
+ monthly_wind["p_wind_capture_eur_mwh"] = (
74
+ monthly_wind["price_x_wind"] / monthly_wind["wind_mwh"]
75
+ )
76
+
77
+ # -----------------------------
78
+ # 5. Combine & compute CF
79
+ # -----------------------------
80
+ monthly = pd.concat([monthly_market, monthly_wind], axis=1).reset_index()
81
+
82
+ monthly["capture_factor"] = (
83
+ monthly["p_wind_capture_eur_mwh"] / monthly["p_market_eur_mwh"]
84
+ )
85
+
86
+ # -----------------------------
87
+ # 6. Clean up & save
88
+ # -----------------------------
89
+ monthly = monthly.sort_values("month").reset_index(drop=True)
90
+
91
+ monthly.to_csv(OUTPUT_FILE, index=False)
92
+ print(f"Saved historical capture factors to: {OUTPUT_FILE}")
93
+
94
+ # Optional: quick sanity stats
95
+ print("\nCapture factor summary:")
96
+ print(monthly["capture_factor"].describe())
model/revenue/capture_factor_history_forecast/reg_cf.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Scenario B2: Capture factor (CF) regression + forecast using scaled historical wind.
3
+
4
+ We model:
5
+ z_t = log(CF_t)
6
+ z_t = const + phi*z_{t-1} + season(month) + beta*log(wind_mwh_t) + error
7
+
8
+ Then we forecast CF for 20 years by:
9
+ - building future wind_mwh_t by scaling a repeating monthly wind pattern
10
+ from a recent reference window, with an annual growth rate per scenario
11
+ - recursively forecasting z_t with AR(1) dynamics
12
+
13
+ Inputs (monthly, historical):
14
+ capture_factor_monthly_historical.csv
15
+ columns: month, p_market_eur_mwh, wind_mwh, p_wind_capture_eur_mwh, capture_factor
16
+
17
+ Outputs:
18
+ capture_factor_forecast_b2.csv
19
+ month, wind_mwh_scen_*, cf_scen_*, p_wind_merchant_scen_* (optional)
20
+ """
21
+
22
+ import numpy as np
23
+ import pandas as pd
24
+ import statsmodels.api as sm
25
+
26
+ # -----------------------------
27
+ # CONFIG
28
+ # -----------------------------
29
+ INPUT_FILE = "capture_factor_monthly_historical.csv" # created by your CF history script
30
+ DATE_COL = "month"
31
+ CF_COL = "capture_factor"
32
+ WIND_COL = "wind_mwh"
33
+
34
+ FORECAST_YEARS = 20
35
+
36
+ # Reference window used to build the repeating seasonal wind pattern (monthly averages)
37
+ REF_START = "2020-01-01"
38
+ REF_END = "2024-12-01"
39
+
40
+ # Wind growth scenarios (annual growth of national wind generation proxy)
41
+ WIND_GROWTH_SCEN = {
42
+ "low": 0.005, # +0.5% p.a.
43
+ "base": 0.015, # +1.5% p.a.
44
+ "high": 0.030, # +3.0% p.a.
45
+ }
46
+
47
+ # CF forecast guardrails (applied after exp() back-transform)
48
+ CF_FLOOR = 0.55
49
+ CF_CAP = 1.15
50
+
51
+ OUTPUT_FILE = "capture_factor_forecast_b2.csv"
52
+
53
+ # -----------------------------
54
+ def to_month_start(s: pd.Series) -> pd.Series:
55
+ dt = pd.to_datetime(s)
56
+ return pd.to_datetime(dt.dt.to_period("M").dt.to_timestamp())
57
+
58
+ # -----------------------------
59
+ # 1) Load historical monthly CF
60
+ # -----------------------------
61
+ df = pd.read_csv(INPUT_FILE, parse_dates=[DATE_COL])
62
+ df[DATE_COL] = to_month_start(df[DATE_COL])
63
+ df = df.sort_values(DATE_COL).reset_index(drop=True)
64
+
65
+ # Basic checks
66
+ df[CF_COL] = pd.to_numeric(df[CF_COL], errors="coerce")
67
+ df[WIND_COL] = pd.to_numeric(df[WIND_COL], errors="coerce")
68
+ df = df.dropna(subset=[CF_COL, WIND_COL])
69
+
70
+ # CF must be positive for log
71
+ df = df[df[CF_COL] > 0].copy()
72
+
73
+ # -----------------------------
74
+ # 2) Build regression dataset: z_t = log(CF_t)
75
+ # -----------------------------
76
+ df["z"] = np.log(df[CF_COL].values.astype(float))
77
+ df["z_lag"] = df["z"].shift(1)
78
+ df["month_num"] = df[DATE_COL].dt.month.astype(int)
79
+
80
+ # Seasonality via month dummies
81
+ month_dummies = pd.get_dummies(df["month_num"], prefix="m", drop_first=True).astype(float)
82
+
83
+ # Wind driver in logs (avoid log(0))
84
+ df["log_wind"] = np.log(np.maximum(df[WIND_COL].values.astype(float), 1.0))
85
+
86
+ X = pd.concat([df["z_lag"], df["log_wind"], month_dummies], axis=1)
87
+ X = sm.add_constant(X)
88
+ reg = pd.concat([df["z"], X], axis=1).dropna()
89
+
90
+ model = sm.OLS(reg["z"].astype(float), reg[X.columns].astype(float)).fit()
91
+ print(model.summary())
92
+
93
+ params = model.params
94
+ const = float(params["const"])
95
+ phi = float(params["z_lag"])
96
+ beta_wind = float(params["log_wind"])
97
+ season_params = {k: float(v) for k, v in params.items() if k.startswith("m_")}
98
+
99
+ # stability clamp (optional but sensible)
100
+ phi = max(min(phi, 0.98), 0.0)
101
+
102
+ print("\n--- Fitted ---")
103
+ print(f"phi={phi:.4f}, beta_wind={beta_wind:.4f}, CF bounds [{CF_FLOOR}, {CF_CAP}]")
104
+
105
+ # -----------------------------
106
+ # 3) Build a repeating monthly wind pattern from the reference window
107
+ # -----------------------------
108
+ mask_ref = (df[DATE_COL] >= pd.Timestamp(REF_START)) & (df[DATE_COL] <= pd.Timestamp(REF_END))
109
+ if mask_ref.sum() < 24:
110
+ raise ValueError("Reference window too short/missing. Adjust REF_START/REF_END.")
111
+
112
+ ref = df.loc[mask_ref, [DATE_COL, WIND_COL]].copy()
113
+ ref["m"] = ref[DATE_COL].dt.month
114
+
115
+ # monthly seasonal wind pattern (average MWh for each month-of-year)
116
+ wind_seasonal = ref.groupby("m")[WIND_COL].mean().to_dict()
117
+
118
+ # anchor wind level: mean in ref window
119
+ wind_anchor = float(ref[WIND_COL].mean())
120
+ anchor_date = df.loc[mask_ref, DATE_COL].iloc[-1]
121
+
122
+ print(f"Wind anchor (mean {REF_START}..{REF_END}): {wind_anchor:,.0f} MWh/month (anchor date {anchor_date.date()})")
123
+
124
+ # -----------------------------
125
+ # 4) Forecast horizon dates
126
+ # -----------------------------
127
+ last_date = df[DATE_COL].max()
128
+ future_dates = pd.date_range(last_date + pd.offsets.MonthBegin(1), periods=FORECAST_YEARS * 12, freq="MS")
129
+
130
+ # Starting state: last observed z
131
+ z_prev = float(df["z"].iloc[-1])
132
+
133
+ # -----------------------------
134
+ # 5) Forecast CF under each wind-growth scenario
135
+ # -----------------------------
136
+ out = pd.DataFrame({DATE_COL: pd.concat([df[DATE_COL], pd.Series(future_dates)], ignore_index=True)})
137
+ out["cf_hist"] = pd.concat([df[CF_COL], pd.Series([np.nan] * len(future_dates))], ignore_index=True)
138
+ out["wind_mwh_hist"] = pd.concat([df[WIND_COL], pd.Series([np.nan] * len(future_dates))], ignore_index=True)
139
+
140
+ for scen, g in WIND_GROWTH_SCEN.items():
141
+ # Build future wind series: seasonal shape * growth factor
142
+ wind_future = []
143
+ for d in future_dates:
144
+ months_from_anchor = (d.year - anchor_date.year) * 12 + (d.month - anchor_date.month)
145
+ growth_factor = (1.0 + g) ** (months_from_anchor / 12.0)
146
+
147
+ # seasonal baseline for month-of-year
148
+ base_m = float(wind_seasonal[int(d.month)])
149
+ # rescale so the mean matches wind_anchor
150
+ # (seasonal dict already in MWh, but this keeps growth around the anchor)
151
+ w = base_m * growth_factor
152
+ wind_future.append(w)
153
+
154
+ wind_future = np.array(wind_future, dtype=float)
155
+ log_wind_future = np.log(np.maximum(wind_future, 1.0))
156
+
157
+ # Forecast z_t recursively (deterministic P50 path)
158
+ z_path = np.zeros(len(future_dates), dtype=float)
159
+ z_prev_s = z_prev
160
+
161
+ for i, d in enumerate(future_dates):
162
+ season_effect = season_params.get(f"m_{d.month}", 0.0) # month 1 baseline 0.0
163
+ z_now = const + phi * z_prev_s + beta_wind * log_wind_future[i] + season_effect
164
+ z_path[i] = z_now
165
+ z_prev_s = z_now
166
+
167
+ cf_future = np.exp(z_path)
168
+
169
+ # Apply guardrails
170
+ cf_future = np.clip(cf_future, CF_FLOOR, CF_CAP)
171
+
172
+ # Store
173
+ out[f"wind_mwh_{scen}"] = np.nan
174
+ out[f"cf_{scen}"] = np.nan
175
+
176
+ future_mask = out[DATE_COL].isin(future_dates)
177
+ out.loc[future_mask, f"wind_mwh_{scen}"] = wind_future
178
+ out.loc[future_mask, f"cf_{scen}"] = cf_future
179
+
180
+ # Save
181
+ out.to_csv(OUTPUT_FILE, index=False)
182
+ print(f"\nSaved CF forecast (Scenario B2) to: {OUTPUT_FILE}")
model/revenue/curltailment_rate_per_tso/50Hertz1518.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/50Hertz1922.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/Amprion1518.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/Amprion1922.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/Tennet1518.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/Tennet1922.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/TransnetBW1518.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/TransnetBW1922.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/curltailment_rate_per_tso/curltailment_rate_quarterly_by_tso.csv ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ quarter,TenneT_curtailment_rate,TenneT_production_mwh,TenneT_curtailed_mwh,50Hertz_curtailment_rate,50Hertz_production_mwh,50Hertz_curtailed_mwh,Amprion_curtailment_rate,Amprion_production_mwh,Amprion_curtailed_mwh,TransnetBW_curtailment_rate,TransnetBW_production_mwh,TransnetBW_curtailed_mwh
2
+ 2015Q1,0.09530035207443505,8194858.75,863240.0,0.029447978426624857,8396098.5,254750.0,0.0045541750385832145,3597806.0,16460.0,0.0007189108500621559,250198.75,180.0
3
+ 2015Q2,0.09232223551591376,5428926.0,552190.0,0.03301157413500447,5115625.75,174640.0,0.0043909375926906415,2244743.75,9900.0,0.0010237457834470544,146370.75,150.0
4
+ 2015Q3,0.08906269152732005,5464026.75,534220.0,0.049698280341429805,5116318.5,267570.0,0.004713182524425895,2436911.75,11540.0,0.00911726229951419,204322.25,1880.0
5
+ 2015Q4,0.1376137133917989,9454346.25,1508660.0,0.056710695709236376,8709226.25,523600.0,0.0006524281568595988,3967195.75,2590.0,0.0022775368439033185,315411.0,720.0
6
+ 2016Q1,0.11403908314741337,9088086.75,1169800.0,0.03968417234191625,7965088.75,329150.0,0.002492969903268064,4453424.5,11130.0,0.002325947310452397,437511.0,1020.0
7
+ 2016Q2,0.06500282591989906,5783928.75,402110.0,0.02620616497341991,4798336.5,129130.0,0.0009612773559822682,2255243.0,2170.0,0.0017322469861923801,247802.5,430.0
8
+ 2016Q3,0.08397410061565538,5023442.75,460510.0,0.018784136594201518,4313682.75,82580.0,0.004142343442756978,1781432.5,7410.0,0.002580140321565849,235811.25,610.0
9
+ 2016Q4,0.2693268665746293,7883700.25,2905940.0,0.09684204258521692,7401934.0,793680.0,0.012692774868053544,3131623.25,40260.0,0.007125029600306795,473791.0,3400.0
10
+ 2017Q1,0.10103203552398203,9546415.0,1072890.0,0.041128314496888876,7744028.0,332160.0,0.001289273869082042,4415393.25,5700.0,0.0017965299333364555,650085.5,1170.0
11
+ 2017Q2,0.13542094040218902,7453511.0,1167460.0,0.028476218172948722,6627914.0,194270.0,0.00029222431572862825,2531561.25,740.0,0.0007084531402526044,366736.75,260.0
12
+ 2017Q3,0.04962306812140752,6028640.75,314780.0,0.020139071371826293,5215786.25,107200.0,0.004346506438805504,2636593.75,11510.0,0.0014176682356437237,366279.5,520.0
13
+ 2017Q4,0.12889244238320588,13156996.0,1946760.0,0.028161149640748697,11688162.75,338690.0,0.0033190713664527044,5939718.25,19780.0,0.002631969944601278,822307.5,2170.0
14
+ 2018Q1,0.1268028912140319,11630541.25,1688950.0,0.027486834090733287,9202966.0,260110.0,0.0031937154148919313,6164270.0,19750.0,0.002292579942596469,896491.0,2060.0
15
+ 2018Q2,0.09039803222877749,7801113.5,775290.0,0.02474019609469666,6392749.75,162170.0,0.002022288394415014,3163266.5,6410.0,0.0024771385095120036,479203.0,1190.0
16
+ 2018Q3,0.08619250707598622,6527082.25,615650.0,0.018843631395328308,5251611.5,100860.0,0.002359892078568851,2629493.75,6220.0,0.001063332210128814,347592.75,370.0
17
+ 2018Q4,0.12072562638072601,11807743.25,1621220.0,0.011933023176121825,10264847.5,123970.0,0.002576862337850747,5898929.25,15240.0,0.00394989642255305,811991.25,3220.0
18
+ 2019Q1,0.16309594006510778,13995837.0,2727510.0,0.03772119552742623,12866117.0,504350.0,0.004159575569904906,7141574.75,29830.0,0.002630054861863574,1107323.0,2920.0
19
+ 2019Q2,0.0757248899629744,8192464.25,671200.0,0.028003505063692098,6566750.0,189190.0,0.004115823000902675,3460096.25,14300.0,0.0013681578577072531,576628.75,790.0
20
+ 2019Q3,0.09242527777578635,7215897.0,734850.0,0.01889591780924663,5820917.5,112110.0,0.005497930961294054,3008144.25,16630.0,0.0013535094869534376,413179.25,560.0
21
+ 2019Q4,0.09914484544370618,11869281.5,1306290.0,0.020015040696809004,9827738.25,200720.0,0.004669104478904939,6663814.0,31260.0,0.0007175833586439269,1002647.75,720.0
22
+ 2020Q1,0.1263987966246904,16649725.75,2409000.0,0.03622689605066002,14179825.5,533000.0,0.001965673444636316,9139167.0,18000.0,0.0007300217236214406,1368822.25,1000.0
23
+ 2020Q2,0.08958656425205197,7652278.25,753000.0,0.026092787961127305,6307885.5,169000.0,0.005638221673873841,3527217.75,20000.0,0.008817720090293454,562040.0,5000.0
24
+ 2020Q3,0.10387380167918364,6547943.5,759000.0,0.023614342558073015,5044351.75,122000.0,0.004351101236528583,3203576.25,14000.0,0.016443234431193287,418707.0,7000.0
25
+ 2020Q4,0.0909823250777832,11889463.5,1190000.0,0.01652246982319331,9523782.25,160000.0,0.0012697024591160767,6292688.75,8000.0,0.0,776930.25,0.0
26
+ 2021Q1,0.1232079070182118,11194037.75,1573000.0,0.029212089188968154,8706889.5,262000.0,0.004553583535321305,5902396.0,27000.0,0.001115655236871736,895334.25,1000.0
27
+ 2021Q2,0.12498272369689316,8037269.5,1148000.0,0.04886486485043129,7124044.25,366000.0,0.006656793655483931,4029006.75,27000.0,0.003013372215879492,661708.25,2000.0
28
+ 2021Q3,0.09737752558343477,6562671.5,708000.0,0.03304682037784841,5413118.0,185000.0,0.011511429537566408,2919586.25,34000.0,0.0024022408102277806,415278.0,1000.0
29
+ 2021Q4,0.08872773855692674,11472073.25,1117000.0,0.034816724980992794,9813527.25,354000.0,0.0021196948398987865,5649192.25,12000.0,0.00129169552798862,773176.25,1000.0
30
+ 2022Q1,0.12810022516371697,15416467.75,2265000.0,0.06746653111498681,13366032.75,967000.0,0.006943418185353013,7437106.75,52000.0,0.0008432725298702942,1184856.25,1000.0
31
+ 2022Q2,0.1514992349312791,8781887.25,1568000.0,0.07451236551741768,6806484.0,548000.0,0.004101540635169408,4127784.0,17000.0,0.0,595612.0,0.0
model/revenue/curltailment_rate_per_tso/curltailmentcalc.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pandas as pd
3
+
4
+ # -------------------------------------------------
5
+ # CONFIG
6
+ # -------------------------------------------------
7
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
8
+
9
+ PRODUCTION_FILE = "wind_onshore_daily_by_tso.csv"
10
+ CURTAILMENT_FILE = "curtailment.csv"
11
+
12
+ OUTPUT_FILE = "curtailment_rate_quarterly_by_tso.csv"
13
+
14
+ # TSO column names (must match both files)
15
+ TSOS = ["TenneT", "50Hertz", "Amprion", "TransnetBW"]
16
+
17
+ # -------------------------------------------------
18
+ def parse_german_number(x):
19
+ """
20
+ Convert strings like '863,24' to float 863.24
21
+ """
22
+ if pd.isna(x):
23
+ return float("nan")
24
+ return float(str(x).replace(".", "").replace(",", "."))
25
+
26
+ def parse_quarter_label(q):
27
+ """
28
+ 'Q1 2015' -> pandas Period('2015Q1')
29
+ """
30
+ q = q.strip()
31
+ year = int(q[-4:])
32
+ quarter = int(q[1])
33
+ return pd.Period(year=year, quarter=quarter, freq="Q")
34
+
35
+ def main():
36
+ # -----------------------------
37
+ # Load production data (daily)
38
+ # -----------------------------
39
+ prod = pd.read_csv(
40
+ os.path.join(BASE_DIR, PRODUCTION_FILE),
41
+ parse_dates=["date"]
42
+ )
43
+
44
+ # Ensure numeric
45
+ for tso in TSOS:
46
+ prod[tso] = pd.to_numeric(prod[tso], errors="coerce")
47
+
48
+ # Create quarter index
49
+ prod["quarter"] = prod["date"].dt.to_period("Q")
50
+
51
+ # Aggregate daily → quarterly (MWh)
52
+ prod_q = (
53
+ prod.groupby("quarter")[TSOS]
54
+ .sum()
55
+ .reset_index()
56
+ )
57
+
58
+ # -----------------------------
59
+ # Load curtailment data (quarterly)
60
+ # -----------------------------
61
+ curt = pd.read_csv(os.path.join(BASE_DIR, CURTAILMENT_FILE))
62
+
63
+ # Parse quarter
64
+ curt["quarter"] = curt["Quarter"].apply(parse_quarter_label)
65
+
66
+ # Parse German numbers & convert GWh → MWh
67
+ for tso in TSOS:
68
+ curt[tso] = curt[tso].apply(parse_german_number) * 1_000
69
+
70
+ # Keep only relevant columns
71
+ curt_q = curt[["quarter"] + TSOS]
72
+
73
+ # -----------------------------
74
+ # Merge production + curtailment
75
+ # -----------------------------
76
+ df = prod_q.merge(curt_q, on="quarter", how="inner", suffixes=("_prod", "_curt"))
77
+
78
+ # -----------------------------
79
+ # Compute curtailment rates
80
+ # -----------------------------
81
+ out = pd.DataFrame({"quarter": df["quarter"]})
82
+
83
+ for tso in TSOS:
84
+ prod_col = f"{tso}_prod"
85
+ curt_col = f"{tso}_curt"
86
+
87
+ out[f"{tso}_curtailment_rate"] = (
88
+ df[curt_col] / (df[curt_col] + df[prod_col])
89
+ )
90
+
91
+ out[f"{tso}_production_mwh"] = df[prod_col]
92
+ out[f"{tso}_curtailed_mwh"] = df[curt_col]
93
+
94
+ # Sort and save
95
+ out = out.sort_values("quarter").reset_index(drop=True)
96
+ out.to_csv(os.path.join(BASE_DIR, OUTPUT_FILE), index=False)
97
+
98
+ print(f"Saved: {OUTPUT_FILE}")
99
+ print("\nPreview:")
100
+ print(out.head(5).to_string(index=False))
101
+
102
+ if __name__ == "__main__":
103
+ main()
model/revenue/curltailment_rate_per_tso/curtailment.csv ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Quarter,TenneT,50Hertz,Amprion,TransnetBW,GesamtWindOnshore
2
+ Q1 2015,"863,24","254,75","16,46","0,18","969,69"
3
+ Q2 2015,"552,19","174,64","9,90","0,15","588,37"
4
+ Q3 2015,"534,22","267,57","11,54","1,88","733,45"
5
+ Q4 2015,"1508,66","523,60","2,59","0,72","1819,05"
6
+ Q1 2016,"1169,80","329,15","11,13","1,02","1451,41"
7
+ Q2 2016,"402,11","129,13","2,17","0,43","481,78"
8
+ Q3 2016,"460,51","82,58","7,41","0,61","497,90"
9
+ Q4 2016,"2905,94","793,68","40,26","3,4","3498,02"
10
+ Q1 2017,"1072,89","332,16","5,70","1,17","1300,17"
11
+ Q2 2017,"1167,46","194,27","0,74","0,26","1162,75"
12
+ Q3 2017,"314,78","107,20","11,51","0,52","336,05"
13
+ Q4 2017,"1946,76","338,69","19,78","2,17","1654,56"
14
+ Q1 2018,"1688,95","260,11","19,75","2,06","1431,34"
15
+ Q2 2018,"775,29","162,17","6,41","1,19","765,82"
16
+ Q3 2018,"615,65","100,86","6,22","0,37","575,48"
17
+ Q4 2018,"1621,22","123,97","15,24","3,22","1111,99"
18
+ Q1 2019,"2727,51","504,35","29,83","2,92","2520,17"
19
+ Q2 2019,"671,20","189,19","14,30","0,79","730,51"
20
+ Q3 2019,"734,85","112,11","16,63","0,56","700,43"
21
+ Q4 2019,"1306,29","200,72","31,26","0,72","1199,15"
22
+ Q1 2020,"2409,00","533,00","18,00","1,00","2169,00"
23
+ Q2 2020,"753,00","169,00","20,00","5,00","636,00"
24
+ Q3 2020,"759,00","122,00","14,00","7,00","520,00"
25
+ Q4 2020,"1190,00","160,00","8,00","0,00","804,00"
26
+ Q1 2021,"1573,00","262,00","27,00","1,00","1145,00"
27
+ Q2 2021,"1148,00","366,00","27,00","2,00","995,00"
28
+ Q3 2021,"708,00","185,00","34,00","1,00","527,00"
29
+ Q4 2021,"1117,00","354,00","12,00","1,00","741,00"
30
+ Q1 2022,"2265,00","967,00","52,00","1,00","1638,00"
31
+ Q2 2022,"1568,00","548,00","17,00","0,00","1069,00"
model/revenue/curltailment_rate_per_tso/curtailment_forecast_quarterly_by_tso_2021_2046.csv ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ quarter,TSO,wind_mwh,load_mwh,S,cr_hat
2
+ 2021Q1,50Hertz,10332139.598789917,26458894.51705215,0.3904977810819379,0.037591391757116115
3
+ 2021Q2,50Hertz,6250356.920074381,23348612.198897533,0.2676971490566582,0.033994561506153556
4
+ 2021Q3,50Hertz,5208241.8405525815,23550796.659246545,0.22114928492271257,0.03263117466462488
5
+ 2021Q4,50Hertz,9703123.698236724,25964529.24843711,0.3737068985689693,0.03709958684400646
6
+ 2022Q1,50Hertz,10435460.994777817,26591188.98963741,0.39244055611219636,0.037648295633622306
7
+ 2022Q2,50Hertz,6312860.489275125,23465355.25989202,0.2690289756688804,0.03403357070479426
8
+ 2022Q3,50Hertz,5260324.258958107,23668550.64254278,0.222249530121333,0.0326634008441535
9
+ 2022Q4,50Hertz,9800154.935219092,26094351.894679293,0.37556613687030754,0.03715404392990016
10
+ 2023Q1,50Hertz,10539815.604725594,26724144.934585594,0.39439299668986894,0.0377054826139917
11
+ 2023Q2,50Hertz,6375989.094167876,23582682.03619148,0.27036742828414845,0.034072773979050085
12
+ 2023Q3,50Hertz,5312927.501547689,23786893.39575549,0.22335524917666308,0.032695787352933506
13
+ 2023Q4,50Hertz,9898156.484571284,26224823.654152684,0.3774346251134435,0.037208771946569456
14
+ 2024Q1,50Hertz,10645213.76077285,26857765.65925852,0.3963551509022564,0.03776295410670125
15
+ 2024Q2,50Hertz,6439748.985109555,23700595.446372434,0.2717125398676517,0.03411217229447137
16
+ 2024Q3,50Hertz,5366056.776563165,23905827.862734266,0.22446646932182057,0.03272833498862286
17
+ 2024Q4,50Hertz,9997138.049416997,26355947.77242345,0.37931240931798793,0.037263772241928644
18
+ 2025Q1,50Hertz,10751665.89838058,26992054.48755481,0.3983270670758995,0.03782071152723523
19
+ 2025Q2,50Hertz,6504146.47496065,23819098.42360429,0.2730643435485854,0.03415176662141216
20
+ 2025Q3,50Hertz,5419717.3443287965,24025357.002047934,0.22558321792541178,0.03276104455284799
21
+ 2025Q4,50Hertz,10097109.429911166,26487727.511285562,0.38119953573250537,0.03731904617059808
22
+ 2026Q1,50Hertz,10859182.557364386,27127014.759992577,0.4003087937777698,0.03787875629812012
23
+ 2026Q2,50Hertz,6569187.939710257,23938193.91572231,0.27442287262096643,0.03419155793505415
24
+ 2026Q3,50Hertz,5473914.517772085,24145483.78705817,0.2267055224922049,0.03279391685122349
25
+ 2026Q4,50Hertz,10198080.524210278,26620166.14884199,0.3830960508356522,0.03737459509393751
26
+ 2027Q1,50Hertz,10967774.38293803,27262649.83379254,0.4023003798164651,0.03793708984895966
27
+ 2027Q2,50Hertz,6634879.819107359,24057884.88530092,0.2757881605444538,0.034231547215430674
28
+ 2027Q3,50Hertz,5528653.662949806,24266211.20599346,0.22783341066380794,0.032826952693372005
29
+ 2027Q4,50Hertz,10300061.32945238,26753266.97958619,0.3850020013373222,0.037430420380079626
30
+ 2028Q1,50Hertz,11077452.12676741,27398963.0829615,0.4043018742434128,0.03799571361647004
31
+ 2028Q2,50Hertz,6701228.617298433,24178174.309727423,0.2771602409451725,0.03427173544745086
32
+ 2028Q3,50Hertz,5583940.199579304,24387542.26202342,0.22896691021934934,0.03286015289294414
33
+ 2028Q4,50Hertz,10403061.942746906,26887033.31448412,0.3869174341797965,0.03748652340396374
34
+ 2029Q1,50Hertz,11188226.648035085,27535957.898376305,0.40631332635407663,0.03805462904451531
35
+ 2029Q2,50Hertz,6768240.903471417,24299065.181276057,0.2785391476165416,0.03431212362092389
36
+ 2029Q3,50Hertz,5639779.601575096,24509479.973333538,0.23010604907616197,0.032893518267638526
37
+ 2029Q4,50Hertz,10507092.562174374,27021468.48105654,0.38884239653889996,0.037542905547369665
38
+ 2030Q1,50Hertz,11300108.914515434,27673637.687868185,0.4083347856891715,0.03811383758414288
39
+ 2030Q2,50Hertz,6835923.312506132,24420560.507182434,0.27992491452010654,0.03435271273058335
40
+ 2030Q3,50Hertz,5696177.397590848,24632027.373200204,0.23125085529047126,0.03292704963922194
41
+ 2030Q4,50Hertz,10612163.487796118,27156575.82346182,0.3907769358251632,0.03759956819895174
42
+ 2031Q1,50Hertz,11413110.003660588,27812005.87630752,0.4103663020358838,0.03817334069361935
43
+ 2031Q2,50Hertz,6904282.545631194,24542663.309718344,0.28131757578637573,0.03439350377611176
44
+ 2031Q3,50Hertz,5753139.171566756,24755187.510066204,0.2324013570580856,0.03296074783354955
45
+ 2031Q4,50Hertz,10718285.12267408,27292358.70257913,0.3927210996849899,0.03765651275427303
46
+ 2032Q1,50Hertz,11527241.103697194,27951065.905689057,0.4124079254290972,0.038233139838466344
47
+ 2032Q2,50Hertz,6973325.371087505,24665376.626266934,0.2827171657156612,0.03443449776216519
48
+ 2032Q3,50Hertz,5810670.563282425,24878963.44761653,0.23355758271509106,0.032994613680585254
49
+ 2032Q4,50Hertz,10825467.97390082,27428820.49609202,0.3946749360018306,0.037713740615839694
50
+ 2033Q1,50Hertz,11642513.514734168,28090821.2352175,0.4144597061526251,0.038293236491496664
51
+ 2033Q2,50Hertz,7043058.624798381,24788703.509398267,0.28412371877892323,0.034475695698397986
52
+ 2033Q3,50Hertz,5868777.268915248,25003358.264854606,0.23471956073854924,0.03302864801442213
53
+ 2033Q4,50Hertz,10933722.653639829,27565964.598572478,0.39663849289736225,0.037771253193135554
54
+ 2034Q1,50Hertz,11758938.649881508,28231275.341393583,0.4165216947404492,0.03835363213285052
55
+ 2034Q2,50Hertz,7113489.211046365,24912647.026945256,0.2855372696186194,0.034517098599487664
56
+ 2034Q3,50Hertz,5927465.041604401,25128375.05617888,0.23588731974719876,0.03306285167330297
57
+ 2034Q4,50Hertz,11043059.880176226,27703794.421565335,0.39861181873267254,0.037829051902656764
58
+ 2035Q1,50Hertz,11876528.036380323,28372431.718100548,0.4185939419779639,0.038414328250032
59
+ 2035Q2,50Hertz,7184624.103156828,25037210.262079976,0.2869578530495579,0.034558707485159885
60
+ 2035Q3,50Hertz,5986739.692020444,25254016.93145977,0.23706088850215995,0.033097225499640934
61
+ 2035Q4,50Hertz,11153490.478977988,27842313.39367316,0.400594962109452,0.037887138167946734
62
+ 2036Q1,50Hertz,11995293.316744126,28514293.876691047,0.42067649890322745,0.03847532633794573
63
+ 2036Q2,50Hertz,7256470.344188396,25162396.313390374,0.28838550405975466,0.03460052338021355
64
+ 2036Q3,50Hertz,6046607.088940649,25380287.016117066,0.2382402959076434,0.033131770340040285
65
+ 2036Q4,50Hertz,11265025.383767769,27981524.960641526,0.4025879718711906,0.037945513419631184
66
+ 2037Q1,50Hertz,12115246.249911569,28656865.346074495,0.4227694168082188,0.03853662789893366
67
+ 2037Q2,50Hertz,7329035.047630281,25288208.294957325,0.28982025781129583,0.03464254731454609
68
+ 2037Q3,50Hertz,6107073.159830056,25507188.45119765,0.23942557101166154,0.03316648704531724
69
+ 2037Q4,50Hertz,11377675.637605445,28121432.58544473,0.4045908971043806,0.038004179095453366
70
+ 2038Q1,50Hertz,12236398.712410685,28800149.67280487,0.42487274724010043,0.038598234442812074
71
+ 2038Q2,50Hertz,7402325.398106583,25414649.336432107,0.2912621496412028,0.034684780323178795
72
+ 2038Q3,50Hertz,6168143.891428357,25634724.393453635,0.2406167430067445,0.03320137647052094
73
+ 2038Q4,50Hertz,11491452.393981501,28262039.74837195,0.4066037871397259,0.03806313664030949
74
+ 2039Q1,50Hertz,12358762.699534792,28944150.42116889,0.4269865420024891,0.03866014748690879
75
+ 2039Q2,50Hertz,7476348.652087649,25541722.583114266,0.2927112150623033,0.03472722344628231
76
+ 2039Q3,50Hertz,6229825.33034264,25762898.015420903,0.24181384123065863,0.03323643947495451
77
+ 2039Q4,50Hertz,11606366.917921318,28403349.947113805,0.4086266915533565,0.03812238750628431
78
+ 2040Q1,50Hertz,12482350.32653014,29088871.17327473,0.42911085315673037,0.03872236855610051
79
+ 2040Q2,50Hertz,7551112.1386085255,25669431.196029834,0.29416748976410584,0.03476987772920226
80
+ 2040Q3,50Hertz,6292123.5836460665,25891712.505498003,0.2430168951671296,0.033271676922196215
81
+ 2040Q4,50Hertz,11722430.58710053,28545366.696849372,0.41065966016804983,0.03818193315268685
82
+ 2041Q1,50Hertz,12607173.82979544,29234315.529141102,0.43124573302318175,0.0387848991828504
83
+ 2041Q2,50Hertz,7626623.25999461,25797778.352009982,0.2956310096136785,0.034812744222484995
84
+ 2041Q3,50Hertz,6355044.819482528,26021171.06802549,0.24422593444656812,0.033307089680120715
85
+ 2041Q4,50Hertz,11839654.892971536,28688093.530333616,0.4127027430544581,0.038241775046086425
86
+ 2042Q1,50Hertz,12733245.568093395,29380487.106786806,0.4333912341825011,0.03884774090724581
87
+ 2042Q2,50Hertz,7702889.492594557,25926767.243770026,0.29710181065653274,0.03485582398190346
88
+ 2042Q3,50Hertz,6418595.267677354,26151276.923365615,0.24544098884679982,0.033342678620920455
89
+ 2042Q4,50Hertz,11958051.44190125,28831533.997985277,0.414755990532341,0.038301914660348685
90
+ 2043Q1,50Hertz,12860578.023774331,29527389.542320736,0.43554740947694154,0.03891089527703623
91
+ 2043Q2,50Hertz,7779918.387520503,26056401.079988874,0.2985799291175105,0.03489911806848322
92
+ 2043Q3,50Hertz,6482781.220354126,26282033.307982437,0.24666208829379885,0.033378444621127164
93
+ 2043Q4,50Hertz,12077631.956320263,28975691.6679752,0.4168194531718055,0.03836235347667195
94
+ 2044Q1,50Hertz,12989183.804012073,29675026.490032334,0.43771431201165273,0.03897436384767137
95
+ 2044Q2,50Hertz,7857717.571395707,26186683.085388817,0.30006540140167726,0.034942627548528546
96
+ 2044Q3,50Hertz,6547609.032557667,26413443.47452235,0.24788926286242471,0.0334143885616334
97
+ 2044Q4,50Hertz,12198408.275883466,29120570.126315072,0.4188931817945509,0.03842309298362369
98
+ 2045Q1,50Hertz,13119075.642052194,29823401.622482494,0.43989199515598937,0.03903814818233953
99
+ 2045Q2,50Hertz,7936294.747109665,26317616.500815757,0.30155826409521796,0.034986353493648724
100
+ 2045Q3,50Hertz,6613085.122883244,26545510.69189496,0.24912254277716317,0.0334505113277143
101
+ 2045Q4,50Hertz,12320392.3586423,29266172.976946644,0.4209772274751208,0.03848413467717718
102
+ 2046Q1,50Hertz,13250266.398472717,29972518.630594905,0.44208051254482517,0.03910224985200603
103
+ 2046Q2,50Hertz,8015657.694580762,26449204.58331983,0.3030585539663385,0.03503029698078443
104
+ 2046Q3,50Hertz,6679215.974112077,26678238.24535443,0.2503619584128705,0.03348681380904934
105
+ 2046Q4,50Hertz,12443596.282228725,29412503.84183138,0.4230716415421612,0.038545480060748344
106
+ 2021Q1,Amprion,6607879.562974096,43397052.420583755,0.15226563082980027,0.0034787359242224973
107
+ 2021Q2,Amprion,3478748.138202513,39140322.7988437,0.0888788821717455,0.0040932599068450905
108
+ 2021Q3,Amprion,2928110.483509553,39256092.77548496,0.07458996238510342,0.004231788606937147
109
+ 2021Q4,Amprion,5919954.583392162,42203211.27664723,0.14027260969754488,0.0035950062688276246
110
+ 2022Q1,Amprion,6673958.358603838,43614037.68268667,0.15302317128168985,0.0034713916955730027
111
+ 2022Q2,Amprion,3513535.6195845385,39336024.412837915,0.08932106566513728,0.004088973011442471
112
+ 2022Q3,Amprion,2957391.588344649,39452373.239362374,0.07496105672532784,0.004228190909047424
113
+ 2022Q4,Amprion,5979154.129226084,42414227.33303046,0.14097048337763218,0.0035882404996040243
114
+ 2023Q1,Amprion,6740697.942189876,43832107.871100105,0.153784480591549,0.003464010928472514
115
+ 2023Q2,Amprion,3548670.975780384,39532704.5349021,0.08976544907640663,0.004084664788202033
116
+ 2023Q3,Amprion,2986965.5042280955,39649635.105559185,0.07533399730605086,0.004224575312163224
117
+ 2023Q4,Amprion,6038945.670518344,42626298.469695605,0.14167182906607814,0.0035814410698370228
118
+ 2024Q1,Amprion,6808104.921611775,44051268.4104556,0.15454957750991494,0.0034565934411376967
119
+ 2024Q2,Amprion,3584157.6855381876,39730368.05757661,0.0902120433504186,0.004080335131015123
120
+ 2024Q3,Amprion,3016835.1592703764,39847883.28108698,0.07570879331254864,0.00422094172723483
121
+ 2024Q4,Amprion,6099335.127223528,42839429.96204408,0.14237666403655616,0.0035746078120612312
122
+ 2025Q1,Amprion,6876185.970827892,44271524.75250787,0.15531848088061104,0.0034491390508808104
123
+ 2025Q2,Amprion,3619999.2623935696,39929019.89786448,0.09066085948649036,0.004075983933245191
124
+ 2025Q3,Amprion,3047003.51086308,40047122.697492406,0.07608545397579516,0.004217290064769473
125
+ 2025Q4,Amprion,6160328.478495764,43053627.1118543,0.14308500564867835,0.0035677405579780976
126
+ 2026Q1,Amprion,6944947.830536172,44492882.3762704,0.15609120964121115,0.0034416475741052346
127
+ 2026Q2,Amprion,3656199.255017505,40128664.99735381,0.09111190853866194,0.00407161108772516
128
+ 2026Q3,Amprion,3077473.545971711,40247358.310979865,0.07646398857268967,0.004213620234829164
129
+ 2026Q4,Amprion,6221931.763280721,43268895.24741357,0.14379687134842303,0.0035608391384517636
130
+ 2027Q1,Amprion,7014397.308841534,44715346.788151756,0.15686778282350572,0.0034341188263009303
131
+ 2027Q2,Amprion,3692761.24756768,40329308.32234057,0.09156520161596873,0.004067216486754781
132
+ 2027Q3,Amprion,3108248.2814314286,40448595.10253476,0.07684440642628515,0.004209932147028458
133
+ 2027Q4,Amprion,6284151.080913529,43485239.72365063,0.14451227866856448,0.0035539033835048986
134
+ 2028Q1,Amprion,7084541.281929949,44938923.52209251,0.15764821955397096,0.0034265526220398843
135
+ 2028Q2,Amprion,3729688.860043357,40530954.86395227,0.09202074988271486,0.004062800022097985
136
+ 2028Q3,Amprion,3139330.7642457425,40650838.078047425,0.07722671690601793,0.004206225710532224
137
+ 2028Q4,Amprion,6346992.591722664,43702665.922268875,0.1452312452291046,0.0035469331223145183
138
+ 2029Q1,Amprion,7155386.694749249,45163618.13970296,0.1584325390542395,0.0034189487749715676
139
+ 2029Q2,Amprion,3766985.748643791,40733609.63827203,0.09247856455874827,0.0040583615849802065
140
+ 2029Q3,Amprion,3170724.0718881995,40854092.26843766,0.07761092942793842,0.004202500834053425
141
+ 2029Q4,Amprion,6410462.51763989,43921179.25188022,0.1459537887377071,0.0035399281832077696
142
+ 2030Q1,Amprion,7226940.561696741,45389436.23040148,0.159220760641574,0.0034113070978183356
143
+ 2030Q2,Amprion,3804655.606130229,40937277.68646338,0.0929386569197371,0.004053901066085722
144
+ 2030Q3,Amprion,3202431.312607082,41058362.72977985,0.0779970534549431,0.0041987574258508485
145
+ 2030Q4,Amprion,6474567.14281629,44140785.14813961,0.14667992699013357,0.003532888393657705
146
+ 2031Q1,Amprion,7299209.967313708,45616383.41155348,0.16001290372934304,0.0034036274023708096
147
+ 2031Q2,Amprion,3842702.162191531,41141964.074895695,0.09340103829744724,0.004049418355554953
148
+ 2031Q3,Amprion,3234455.625733153,41263654.54342874,0.0783850984970075,0.004194995393726867
149
+ 2031Q4,Amprion,6539312.814244453,44361489.073880315,0.14740967787068146,0.003525813580279029
150
+ 2032Q1,Amprion,7372202.066986845,45844465.32861124,0.160808987827499,0.0033959094994832455
151
+ 2032Q2,Amprion,3881129.183813446,41347673.89527017,0.0938657200800216,0.004044913342981734
152
+ 2032Q3,Amprion,3266800.1819904847,41469972.816145875,0.0787750741114205,0.0041912146450251535
153
+ 2032Q4,Amprion,6604705.942386897,44583296.51924971,0.14814305935262517,0.0035187035688238437
154
+ 2033Q1,Amprion,7445924.087656715,46073687.6552543,0.16160903254305872,0.003388153199068874
155
+ 2033Q2,Amprion,3919940.4756515813,41554412.26474652,0.09433271371226054,0.0040403859174106445
156
+ 2033Q3,Amprion,3299468.1838103896,41677322.6802266,0.07916698990301961,0.004187415086628409
157
+ 2033Q4,Amprion,6670753.001810767,44806213.001845956,0.14888008949865816,0.003511558184177338
158
+ 2034Q1,Amprion,7520383.328533281,46304056.09353056,0.16241305758058638,0.0033803583100952307
159
+ 2034Q2,Amprion,3959139.8804080975,41762184.32607024,0.09480203069590365,0.004035835967334225
160
+ 2034Q3,Amprion,3332462.865648493,41885709.29362773,0.07956085552442767,0.004183596624956057
161
+ 2034Q4,Amprion,6737460.531828873,45030244.06685517,0.14962078646133806,0.0035043772503534874
162
+ 2035Q1,Amprion,7595587.161818613,46535576.3739982,0.16322108274267888,0.0033725246405794315
163
+ 2035Q2,Amprion,3998731.279212178,41970995.24770059,0.09527368258991313,0.004031263380690257
164
+ 2035Q3,Amprion,3365787.494304978,42095137.84009587,0.07995668067629048,0.004179759165961951
165
+ 2035Q4,Amprion,6804835.137147162,45255395.28718945,0.1503651684835338,0.0034971605904907145
166
+ 2036Q1,Amprion,7671543.033436799,46768254.2558682,0.1640331279304534,0.003364651997583453
167
+ 2036Q2,Amprion,4038718.5920042996,42180850.22393908,0.09574768101075848,0.004026668044859006
168
+ 2036Q3,Amprion,3399445.369248028,42305613.52929634,0.08035447510751584,0.004175902615132052
169
+ 2036Q4,Amprion,6872883.488518634,45481672.26362539,0.15111325389887476,0.0034899080268475276
170
+ 2037Q1,Amprion,7748258.463771168,47002095.527147524,0.1648492131440378,0.003356740187209384
171
+ 2037Q2,Amprion,4079105.777924343,42391754.47505878,0.09622403763270256,0.004022049846660443
172
+ 2037Q3,Amprion,3433439.8229405084,42517141.59694282,0.08075424861551343,0.004172026877482107
173
+ 2037Q4,Amprion,6941612.32340382,45709080.62494351,0.15186506113220252,0.0034826193807981597
174
+ 2038Q1,Amprion,7825741.04840888,47237106.00478326,0.16566935848306288,0.0033487890145946463
175
+ 2038Q2,Amprion,4119896.8357035867,42603713.24743407,0.09670276418808915,0.0040174086723514316
176
+ 2038Q3,Amprion,3467774.2211699137,42729727.30492753,0.0811560110464364,0.004168131857555296
177
+ 2038Q4,Amprion,7011028.446637859,45937626.02806822,0.15262060870002445,0.0034752944728281415
178
+ 2039Q1,Amprion,7903998.458892969,47473291.53480717,0.16649358414715776,0.0033407982839072023
179
+ 2039Q2,Amprion,4161095.804060622,42816731.81367124,0.09718387246763188,0.004012744407622976
180
+ 2039Q3,Amprion,3502451.9633816127,42943375.94145217,0.08155977229542365,0.004164217459419892
181
+ 2039Q4,Amprion,7081138.731104238,46167314.15820856,0.15337991521096989,0.0034679331225299197
182
+ 2040Q1,Amprion,7983038.443481899,47710657.992481194,0.16732191043644712,0.0033327677983407133
183
+ 2040Q2,Amprion,4202706.762101228,43030815.472739585,0.0976673743207047,0.004008056937597364
184
+ 2040Q3,Amprion,3537476.4830154288,43158092.82115942,0.08196554230684368,0.0041602835866669
185
+ 2040Q4,Amprion,7151950.11841528,46398150.7289996,0.15414299936624834,0.003460535148598367
186
+ 2041Q1,Amprion,8062868.827916718,47949211.282443605,0.16815435775205134,0.003324697360109718
187
+ 2041Q2,Amprion,4244733.829722241,43245969.550103284,0.09815328165563357,0.004003346146825352
188
+ 2041Q3,Amprion,3572851.247845583,43373883.28526521,0.08237333107453944,0.004156330142407676
189
+ 2041Q4,Amprion,7223469.619599434,46630141.482644595,0.1549098799601103,0.003453100368826366
190
+ 2042Q1,Amprion,8143497.516195885,48188957.33885582,0.16899094659658892,0.0033165867704447356
191
+ 2042Q2,Amprion,4287181.168019463,43462199.39785379,0.09864160643998998,0.003998611919283336
192
+ 2042Q3,Amprion,3608579.7603240395,43590752.70169153,0.08278314864207448,0.004152357029271539
193
+ 2042Q4,Amprion,7295704.315795427,46863292.19005781,0.15568057588030987,0.0034456286001002707
194
+ 2043Q1,Amprion,8224932.491357844,48429902.12555009,0.16983169757468142,0.003308435829587387
195
+ 2043Q2,Amprion,4330052.979699658,43679510.39484306,0.09913236070088546,0.003993854138370459
196
+ 2043Q3,Amprion,3644665.5579272793,43808706.465199985,0.08319500510298031,0.004148364149403384
197
+ 2043Q4,Amprion,7368661.358953382,47097608.651008084,0.15645510610857016,0.0034381196583954388
198
+ 2044Q1,Amprion,8307181.816271422,48672051.63617783,0.17067663139346098,0.0033002443367854788
199
+ 2044Q2,Amprion,4373353.509496654,43897907.946817264,0.099625556525268,0.0039890726869057785
200
+ 2044Q3,Amprion,3681112.213506552,44027749.99752598,0.08360891060100509,0.004144351404461254
201
+ 2044Q4,Amprion,7442347.972542915,47333096.69426312,0.15723348972105058,0.0034305733587716783
202
+ 2045Q1,Amprion,8390253.634434137,48915411.89435872,0.1715257688630802,0.003292012090288038
203
+ 2045Q2,Amprion,4417087.044591621,44117397.486551344,0.10012120606021958,0.003984267447125354
204
+ 2045Q3,Amprion,3717923.335641618,44247888.74751361,0.08402487533036335,0.0041403186956139384
205
+ 2045Q4,Amprion,7516771.452268345,47569762.177734435,0.15801574588881706,0.003422989515368697
206
+ 2046Q1,Amprion,8474156.170778478,49159988.95383051,0.17237913089722487,0.0032837388873403622
207
+ 2046Q2,Amprion,4461257.915037537,44337984.4739841,0.1006193215132555,0.003979438300679355
208
+ 2046Q3,Amprion,3755102.5689980336,44469128.191251166,0.08444290953598704,0.0041362659235385305
209
+ 2046Q4,Amprion,7591939.166791029,47807610.988623105,0.15880189387831367,0.0034153679414015183
210
+ 2021Q1,TenneT,12447538.18763111,36111271.20442925,0.34469952932879167,0.12715710853226286
211
+ 2021Q2,TenneT,7708988.706875039,32033876.410622682,0.2406511346943537,0.11115882842036676
212
+ 2021Q3,TenneT,6477958.469000448,32595113.862966057,0.19874016996027677,0.10471467946514934
213
+ 2021Q4,TenneT,11609727.10634837,35641542.32964574,0.3257358225121389,0.12424128561468112
214
+ 2022Q1,TenneT,12572013.569507422,36291827.56045139,0.3464144523602783,0.12742079178393106
215
+ 2022Q2,TenneT,7786078.59394379,32194045.792675793,0.24184840402119132,0.11134291823864242
216
+ 2022Q3,TenneT,6542738.053690452,32758089.432280883,0.19972892702475578,0.10486670884086176
217
+ 2022Q4,TenneT,11725824.377411852,35819750.041293964,0.32735639874354255,0.12449046228466978
218
+ 2023Q1,TenneT,12697733.705202496,36473286.69825365,0.34813790734714534,0.1276857868925727
219
+ 2023Q2,TenneT,7863939.379883228,32355016.02163917,0.24305162991184404,0.11152792392666078
220
+ 2023Q3,TenneT,6608165.434227357,32921879.879442286,0.2007226032786103,0.10501949458162746
221
+ 2023Q4,TenneT,11843082.621185971,35998848.79150043,0.32898503754326175,0.1247408786395838
222
+ 2024Q1,TenneT,12824711.04225452,36655653.13174491,0.3498699367369322,0.12795210038483948
223
+ 2024Q2,TenneT,7942578.77368206,32516791.10174736,0.2442608420009577,0.11171385004098766
224
+ 2024Q3,TenneT,6674247.08856963,33086489.278839495,0.20172122319541932,0.10517304045045665
225
+ 2024Q4,TenneT,11961513.447397832,36178843.03545793,0.3306217790235765,0.12499254084700978
226
+ 2025Q1,TenneT,12952958.152677067,36838931.39740363,0.35161058318835975,0.12821973881985382
227
+ 2025Q2,TenneT,8022004.561418881,32679375.05725609,0.24547607007061428,0.11190070116085847
228
+ 2025Q3,TenneT,6740989.559455327,33251921.725233685,0.20272481137052095,0.10532735022908105
229
+ 2025Q4,TenneT,12081128.58187181,36359737.250635214,0.33226666349633066,0.12524545510521903
230
+ 2026Q1,TenneT,13082487.734203838,37023126.05439064,0.3533598895723815,0.12848870878937074
231
+ 2026Q2,TenneT,8102224.607033068,32842771.932542372,0.24669734405106505,0.11208848188829082
232
+ 2026Q3,TenneT,6808399.45504988,33418181.333859853,0.20373339252161807,0.10548242771804683
233
+ 2026Q4,TenneT,12201939.867690528,36541535.93688839,0.33391973147392434,0.12549962764331982
234
+ 2027Q1,TenneT,13213312.611545878,37208241.684662595,0.35511789897323914,0.12875901691793995
235
+ 2027Q2,TenneT,8183246.853103399,33006985.79220508,0.2479246940214684,0.11227719684819795
236
+ 2027Q3,TenneT,6876483.44960038,33585272.24052915,0.20474699148938738,0.10563827673680848
237
+ 2027Q4,TenneT,12323959.266367434,36724243.61657282,0.3355810236703122,0.1257550647214112
238
+ 2028Q1,TenneT,13345445.737661336,37394282.893085904,0.35688465468952396,0.12903066986306924
239
+ 2028Q2,TenneT,8265079.321634434,33172020.7211661,0.24915815021063,0.11246685068850265
240
+ 2028Q3,TenneT,6945248.284096383,33753198.601731785,0.20576563323809083,0.10579490112382267
241
+ 2028Q4,TenneT,12447198.85903111,36907864.83465568,0.33725058100200533,0.12601177263073687
242
+ 2029Q1,TenneT,13478900.19503795,37581254.307551324,0.3586602002352431,0.12930367431538822
243
+ 2029Q2,TenneT,8347730.114850778,33337880.82477193,0.2503977429977476,0.11265744808025163
244
+ 2029Q3,TenneT,7014700.766937346,33921964.59474044,0.20678934285619077,0.10595230473664291
245
+ 2029Q4,TenneT,12571670.847621419,37092404.15882896,0.33892844458907995,0.12626975769384025
246
+ 2030Q1,TenneT,13613689.196988327,37769160.57908908,0.36044457934089097,0.12957803699881323
247
+ 2030Q2,TenneT,8431207.415999286,33504570.228895783,0.2516435029131593,0.11284899371773072
248
+ 2030Q3,TenneT,7084847.774606721,34091574.41771414,0.2078181455569679,0.10611049145201448
249
+ 2030Q4,TenneT,12697387.556097634,37277866.1796231,0.3406146557561899,0.12652902626472026
250
+ 2031Q1,TenneT,13749826.088958211,37958006.38198452,0.3622378359545274,0.12985376467071305
251
+ 2031Q2,TenneT,8515519.490159279,33672093.08004026,0.2528954606390954,0.11304149231858034
252
+ 2031Q3,TenneT,7155696.252352787,34262032.289802715,0.20885206667914183,0.10626946516597
253
+ 2031Q4,TenneT,12824361.43165861,37464255.51052121,0.34230925603358386,0.12678958472898774
254
+ 2032Q1,TenneT,13887324.349847792,38147796.41389444,0.36404001424285837,0.130130864122075
255
+ 2032Q2,TenneT,8600674.685060872,33840453.54544046,0.25415364701043425,0.11323494862391179
256
+ 2032Q3,TenneT,7227253.2148763165,34433342.451251715,0.2098911316874959,0.1064292297939253
257
+ 2032Q4,TenneT,12952605.045975195,37651576.788073815,0.34401228715812904,0.1270514395040227
258
+ 2033Q1,TenneT,14026197.593346274,38338535.39596391,0.3658511585923254,0.1304093421776726
259
+ 2033Q2,TenneT,8686681.431911482,34009655.813167654,0.25541809301546137,0.11342936739842402
260
+ 2033Q3,TenneT,7299525.747025079,34605509.163507976,0.2109353661735033,0.10658978927077588
261
+ 2033Q4,TenneT,13082131.096434949,37839834.672014184,0.3457237910743387,0.1273145970391325
262
+ 2034Q1,TenneT,14166459.569279734,38530228.072943725,0.36767131361019767,0.13068920569623338
263
+ 2034Q2,TenneT,8773548.246230597,34179704.092233494,0.25668882979663277,0.11362475343052086
264
+ 2034Q3,TenneT,7372521.004495329,34778536.70932551,0.21198479585595859,0.10675114755099388
265
+ 2034Q4,TenneT,13212952.407399297,38029033.84537424,0.34744380993540513,0.1275790638157105
266
+ 2035Q1,TenneT,14308124.16497253,38722879.21330844,0.3695005241256713,0.1309704615706079
267
+ 2035Q2,TenneT,8861283.728692902,34350602.61269465,0.25796588865134246,0.11382111153242916
268
+ 2035Q3,TenneT,7446246.214540282,34952429.39287213,0.21303944658161011,0.10691330860872542
269
+ 2035Q4,TenneT,13345081.931473289,38219179.01460112,0.3491723861042379,0.12784484634739585
270
+ 2036Q1,TenneT,14451205.406622257,38916493.60937498,0.3713388351909732,0.1312531167279395
271
+ 2036Q2,TenneT,8949896.56597983,34522355.62575812,0.25924930103269245,0.11401844654031709
272
+ 2036Q3,TenneT,7520708.676685685,35127191.53983649,0.21409934432579728,0.10707627643788845
273
+ 2036Q4,TenneT,13478532.750788022,38410274.909674115,0.35090956215450786,0.12811195118023386
274
+ 2037Q1,TenneT,14595717.46068848,39111076.077421844,0.37318629208247067,0.13153717812983495
275
+ 2037Q2,TenneT,9039395.53163963,34694967.403886914,0.260539098550268,0.11421676331441338
276
+ 2037Q3,TenneT,7595915.763452543,35302827.497535676,0.2151645151930898,0.10724005505227119
277
+ 2037Q4,TenneT,13613318.078295903,38602326.28422248,0.3526553808716945,0.12838038489283723
278
+ 2038Q1,TenneT,14741674.635295365,39306631.45780895,0.3750429403017865,0.13182265277253585
279
+ 2038Q2,TenneT,9129789.486956026,34868442.24090634,0.26183531297091617,0.1144160667391271
280
+ 2038Q3,TenneT,7671874.9210870685,35479341.63502334,0.21623498541793112,0.10740464848563097
281
+ 2038Q4,TenneT,13749451.259078862,38795337.915643595,0.35440988525414074,0.12865015409654806
282
+ 2039Q1,TenneT,14889091.381648319,39503164.61509799,0.3769088255769198,0.13210954768709096
283
+ 2039Q2,TenneT,9221087.381825587,35042784.45211087,0.2631379762195277,0.11461636172316778
284
+ 2039Q3,TenneT,7748593.670297938,35656738.34319846,0.21731078136528395,0.10757006079179351
285
+ 2039Q4,TenneT,13886945.771669652,38989314.6052218,0.35617311851411176,0.12892126543560078
286
+ 2040Q1,TenneT,15037982.295464803,39700680.43817347,0.37878399386337225,0.13239786993952946
287
+ 2040Q2,TenneT,9313298.255643843,35217998.374371424,0.26444712037982393,0.11481765319966633
288
+ 2040Q3,TenneT,7826079.607000918,35835022.03491445,0.21839192953128045,0.1077362960447529
289
+ 2040Q4,TenneT,14025815.229386348,39184261.17824791,0.35794512407885853,0.12919372558728556
290
+ 2041Q1,TenneT,15188362.11841945,39899183.84036434,0.3806684913452796,0.1326876266310348
291
+ 2041Q2,TenneT,9406431.23820028,35394088.36624327,0.26576277769514645,0.11501994612629673
292
+ 2041Q3,TenneT,7904340.403070928,36014197.145089015,0.2194784565438739,0.1079033583387718
293
+ 2041Q4,TenneT,14166073.381680213,39380182.484139144,0.35972594559168874,0.1294675412621131
294
+ 2042Q1,TenneT,15340245.739603644,40098679.75956616,0.3825623644365496,0.13297882489811977
295
+ 2042Q2,TenneT,9500495.550582284,35571058.80807449,0.2670849805692517,0.11522324548539793
296
+ 2042Q3,TenneT,7983383.807101638,36194268.130814455,0.22057038916349525,0.10807125178848233
297
+ 2042Q4,TenneT,14307734.115497014,39577083.396559834,0.36151562691304046,0.12974271920397956
298
+ 2043Q1,TenneT,15493648.196999682,40299173.15836398,0.3844656597820052,0.13327147191280217
299
+ 2043Q2,TenneT,9595500.506088106,35748914.102114856,0.26841376156710867,0.11542755628409664
300
+ 2043Q3,TenneT,8063217.645172653,36375239.47146852,0.22166775428371163,0.10823998052898744
301
+ 2043Q4,TenneT,14450811.456651984,39774968.81354263,0.3633142121215631,0.1300192661903329
302
+ 2044Q1,TenneT,15648584.678969678,40500669.024155796,0.3863784242585326,0.1335655748827815
303
+ 2044Q2,TenneT,9691455.511148987,35927658.67262542,0.2697491534157013,0.11563288355443069
304
+ 2044Q3,TenneT,8143849.82162438,36557115.668825865,0.2227705789318893,0.10840954871596271
305
+ 2044Q4,TenneT,14595319.571218504,39973843.657610334,0.36512174551520277,0.13029718903233975
306
+ 2045Q1,TenneT,15805070.525759377,40703172.36927657,0.38830070497623687,0.13386114105161648
307
+ 2045Q2,TenneT,9788370.066260478,36107296.96598855,0.2710911890048342,0.11583923235347285
308
+ 2045Q3,TenneT,8225288.319840624,36739901.247169994,0.2238788902698589,0.10857996052575876
309
+ 2045Q4,TenneT,14741272.76693069,40173712.87589838,0.3669382716122934,0.1305764945750531
310
+ 2046Q1,TenneT,15963121.23101697,40906688.231122956,0.39023254927960116,0.13415817769890334
311
+ 2046Q2,TenneT,9886253.766923083,36287833.45081849,0.2724399013879429,0.11604660776345552
312
+ 2046Q3,TenneT,8307541.20303903,36923600.75340583,0.22499271559458464,0.10875122015550406
313
+ 2046Q4,TenneT,14888685.494599998,40374581.440277874,0.3687638351526531,0.13085718969758095
314
+ 2021Q1,TransnetBW,982592.6868155334,14907943.888683865,0.06591067783407661,0.001822947089878152
315
+ 2021Q2,TransnetBW,527448.8774056936,13084479.565202389,0.04031103222541776,0.002714510254756039
316
+ 2021Q3,TransnetBW,399061.20892765094,13197586.721116466,0.030237437901365943,0.0030653450192111263
317
+ 2021Q4,TransnetBW,829085.9884025174,14552773.808496533,0.056970993936459144,0.0021342909651258547
318
+ 2022Q1,TransnetBW,992418.6136836888,14982483.608127283,0.06623859165414665,0.0018115267800934733
319
+ 2022Q2,TransnetBW,532723.3661797505,13149901.963028401,0.040511584624549186,0.0027075255826075686
320
+ 2022Q3,TransnetBW,403051.8210169275,13263574.654722048,0.030387872915800605,0.003060105793651985
321
+ 2022Q4,TransnetBW,837376.8482865426,14625537.677539015,0.05725443171723755,0.0021244196298448974
322
+ 2023Q1,TransnetBW,1002342.7998205257,15057396.026167918,0.06656813688625683,0.0018000496528471806
323
+ 2023Q2,TransnetBW,538050.5998415481,13215651.47284354,0.040713134796810636,0.0027005061608464213
324
+ 2023Q3,TransnetBW,407082.33922709676,13329892.527995655,0.030539056363142903,0.0030548405022940463
325
+ 2023Q4,TransnetBW,845750.616769408,14698665.365926707,0.05753927963622879,0.002114499183443138
326
+ 2024Q1,TransnetBW,1012366.227818731,15132683.006298756,0.06689932164688499,0.001788515425465334
327
+ 2024Q2,TransnetBW,543431.1058399635,13281729.730207758,0.040915687706247504,0.002693451816588952
328
+ 2024Q3,TransnetBW,411153.1626193677,13396541.990635633,0.030690991966939633,0.003049549015456711
329
+ 2024Q4,TransnetBW,854208.1229371021,14772158.69275634,0.057825544709045856,0.0021045293815866485
330
+ 2025Q1,TransnetBW,1022489.8900969182,15208346.421330249,0.06723215409288939,0.001776923813867657
331
+ 2025Q2,TransnetBW,548865.4168983632,13348138.378858794,0.04111924834160198,0.002686362376091392
332
+ 2025Q3,TransnetBW,415264.6942455614,13463524.70058881,0.03084368346926272,0.0030442312028142147
333
+ 2025Q4,TransnetBW,862750.2041664731,14846019.48622012,0.0581132339862053,0.00209450997872589
334
+ 2026Q1,TransnetBW,1032714.7889978875,15284388.153436897,0.06756664242170976,0.001765274532560538
335
+ 2026Q2,TransnetBW,554354.0710673467,13414879.070753088,0.04132382171643581,0.002679237664745586
336
+ 2026Q3,TransnetBW,419417.34118801705,13530842.324091753,0.030997134630801344,0.0030388869333924026
337
+ 2026Q4,TransnetBW,871377.7062081379,14920249.583651219,0.05840235455330085,0.00208444072808971
338
+ 2027Q1,TransnetBW,1043041.9368878665,15360810.094204081,0.06790279487156901,0.001753567294630002
339
+ 2027Q2,TransnetBW,559897.6117780203,13481953.466106853,0.04152941286925391,0.002672077507074676
340
+ 2027Q3,TransnetBW,423611.51459989726,13598496.53571221,0.031151349230954594,0.0030335160755655087
341
+ 2027Q4,TransnetBW,880091.4832702193,14994850.831569472,0.05869291353117798,0.0020743213816792165
342
+ 2028Q1,TransnetBW,1053472.356256745,15437614.1446751,0.06824061972167633,0.001741801811734639
343
+ 2028Q2,TransnetBW,565496.5878958005,13549363.233437384,0.04173602686362832,0.0026648817267287857
344
+ 2028Q3,TransnetBW,427847.6297458962,13666489.01839077,0.03130633106792452,0.0030281184970529056
345
+ 2028Q4,TransnetBW,888892.3981029216,15069825.085727317,0.05898491807610923,0.002064151690261709
346
+ 2029Q1,TransnetBW,1064007.0798193126,15514802.215398472,0.06858012529243096,0.0017299777940985028
347
+ 2029Q2,TransnetBW,571151.5537747585,13617110.04960457,0.04194366878832299,0.0026576501464806827
348
+ 2029Q3,TransnetBW,432126.10604335513,13734821.463482723,0.031462083958809714,0.003022694064915867
349
+ 2029Q4,TransnetBW,897781.3220839506,15145174.211155953,0.059278375379970466,0.002053931403364514
350
+ 2030Q1,TransnetBW,1074647.1506175057,15592376.226475464,0.06892131994562713,0.001718094950503974
351
+ 2030Q2,TransnetBW,576863.0693125061,13685195.59985259,0.042152343757419136,0.002650382588221388
352
+ 2030Q3,TransnetBW,436447.3671037887,13803495.570800135,0.03161861173969932,0.0030172426455542627
353
+ 2030Q4,TransnetBW,906759.1353047902,15220900.082211731,0.05957329267041809,0.002043660269268825
354
+ 2031Q1,TransnetBW,1085393.6221236805,15670338.10760784,0.06926421208466009,0.001706152988284599
355
+ 2031Q2,TransnetBW,582631.7000056312,13753621.577851852,0.04236205691044112,0.0026430788729558292
356
+ 2031Q3,TransnetBW,440811.8407748266,13872513.048654133,0.03177591826576748,0.0030117641047032982
357
+ 2031Q4,TransnetBW,915826.7266578382,15297004.58262279,0.05986967721106694,0.0020333380350035027
358
+ 2032Q1,TransnetBW,1096247.5583449174,15748689.798145877,0.06960881015473304,0.0016941516133178666
359
+ 2032Q2,TransnetBW,588458.0170056875,13822389.685741112,0.04257281341248312,0.0026357388207984035
360
+ 2032Q3,TransnetBW,445219.9591825749,13941875.613897402,0.03193400741136832,0.0030062583074301867
361
+ 2032Q4,TransnetBW,924984.9939244165,15373489.605535902,0.06016753630166927,0.00202296444633885
362
+ 2033Q1,TransnetBW,1107210.0339283668,15827433.247136606,0.06995512264306507,0.0016820905300179607
363
+ 2033Q2,TransnetBW,594342.5971757444,13891501.634169815,0.04278461845433627,0.002628362250968557
364
+ 2033Q3,TransnetBW,449672.1587744006,14011584.991966886,0.03209288307013135,0.003000725118130841
365
+ 2033Q4,TransnetBW,934234.8438636607,15450357.05356358,0.060466877278294494,0.0020125392477803455
366
+ 2034Q1,TransnetBW,1118282.1342676503,15906570.413372288,0.07030315807910022,0.0016699694413285088
367
+ 2034Q2,TransnetBW,600286.0231475019,13960959.142340662,0.042997477252616566,0.002620948981786317
368
+ 2034Q3,TransnetBW,454168.8803621446,14081642.91692672,0.03225254915505738,0.0029951644005265267
369
+ 2034Q4,TransnetBW,943577.1923022972,15527608.838831395,0.0607677075135099,0.002002062182562346
370
+ 2035Q1,TransnetBW,1129464.9556103267,15986103.265439145,0.07065292503471764,0.0016577880487152231
371
+ 2035Q2,TransnetBW,606288.8833789768,14030763.938052364,0.04321139504989326,0.0026134988306678528
372
+ 2035Q3,TransnetBW,458710.56916576606,14152051.131511353,0.03241300959861488,0.002989576017660499
373
+ 2035Q4,TransnetBW,953012.9642253201,15605246.883025551,0.06107003441656218,0.001991532992641768
374
+ 2036Q1,TransnetBW,1140759.6051664301,16066033.78176634,0.07100443212444262,0.0016455460521585946
375
+ 2036Q2,TransnetBW,612351.7722127666,14100917.757742623,0.043426377114818115,0.002606011614120933
376
+ 2036Q3,TransnetBW,463297.67485742376,14222811.387168907,0.03257426835283685,0.002983959831894638
377
+ 2036Q4,TransnetBW,962543.0938675734,15683273.117440678,0.061373865433560014,0.001980951418691739
378
+ 2037Q1,TransnetBW,1152167.2012180944,16146363.950675167,0.07135768800565877,0.0016332431501464538
379
+ 2037Q2,TransnetBW,618475.2899348943,14171422.346531335,0.043642428742255025,0.0025984871477404484
380
+ 2037Q3,TransnetBW,467930.651605998,14293925.444104752,0.03273632938941813,0.002978315704906063
381
+ 2037Q4,TransnetBW,972168.5248062492,15761689.48302788,0.061679208047657336,0.001970317200095186
382
+ 2038Q1,TransnetBW,1163688.8732302755,16227095.770428544,0.07171270137882124,0.001620879039666595
383
+ 2038Q2,TransnetBW,624660.0428342433,14242279.458263991,0.04385955525341052,0.002590925246203843
384
+ 2038Q3,TransnetBW,472609.95812205796,14365395.071325272,0.032899196699813255,0.002972643497683714
385
+ 2038Q4,TransnetBW,981890.2100543117,15840497.930443017,0.06198606977923773,0.001959630074938455
386
+ 2039Q1,TransnetBW,1175325.7619625782,16308231.249280684,0.07206948098767112,0.0016084534161992722
387
+ 2039Q2,TransnetBW,630906.6432625856,14313490.855555309,0.04407776199596481,0.002583325723266555
388
+ 2039Q3,TransnetBW,477336.05770327855,14437222.0466819,0.03306287429533471,0.0029669430705249362
389
+ 2039Q4,TransnetBW,991709.1121548549,15919700.42009523,0.062294458186099626,0.0019488897800048234
390
+ 2040Q1,TransnetBW,1187079.019582204,16389772.405527085,0.07242803561945059,0.0015959659737097218
391
+ 2040Q2,TransnetBW,637215.7096952115,14385058.309833085,0.044297054344203446,0.002575688391757442
392
+ 2040Q3,TransnetBW,482109.41828031134,14509408.156915307,0.0332273662072518,0.002961214283032032
393
+ 2040Q4,TransnetBW,1001626.2032764034,15999298.922195705,0.06260438086364241,0.0019380960507680428
394
+ 2041Q1,TransnetBW,1198949.809778026,16471721.26755472,0.0727883741051195,0.0015834164046406272
395
+ 2041Q2,TransnetBW,643587.8667921636,14456983.60138225,0.04451743769914973,0.002568013063574154
396
+ 2041Q3,TransnetBW,486930.51246311446,14581955.197699882,0.03339267648688988,0.0029554569941088182
397
+ 2041Q4,TransnetBW,1011642.4653091675,16079295.416806683,0.06291584544505358,0.0019272486213858
398
+ 2042Q1,TransnetBW,1210939.3078758062,16554079.873892492,0.07315050531957283,0.0015708043999045178
399
+ 2042Q2,TransnetBW,650023.7454600853,14529268.519389158,0.04473891748869775,0.002560299549678513
400
+ 2042Q3,TransnetBW,491799.81758774567,14654864.973688379,0.033558809205730136,0.0029496710619571244
401
+ 2042Q4,TransnetBW,1021758.8899622591,16159691.893890712,0.06322885960149663,0.0019163472246932003
402
+ 2043Q1,TransnetBW,1223048.7009545644,16636850.273261953,0.07351443818185927,0.0015581296488761942
403
+ 2043Q2,TransnetBW,656523.9829146862,14601914.861986103,0.04496149916774601,0.002552547660091848
404
+ 2043Q3,TransnetBW,496717.81576362305,14728139.298556818,0.03372576845550989,0.002943856344073341
405
+ 2043Q4,TransnetBW,1031976.4788618817,16240490.353360163,0.0635434310423001,0.0019053915921961595
406
+ 2044Q1,TransnetBW,1235279.18796411,16720034.52462826,0.07388018165540088,0.0015453918393850373
407
+ 2044Q2,TransnetBW,663089.222743833,14674924.43629603,0.045185188218331805,0.002544757203890323
408
+ 2044Q3,TransnetBW,501684.9939212593,14801779.995049601,0.033893558348323374,0.0029380126972448593
409
+ 2044Q4,TransnetBW,1042296.2436505004,16321692.805126963,0.06385956751514738,0.0018943814540648071
410
+ 2045Q1,TransnetBW,1247631.9798437513,16803634.697251398,0.07424774474821384,0.0015325906577073577
411
+ 2045Q2,TransnetBW,669720.1149712714,14748299.058477508,0.04540999014976631,0.0025369279892002335
412
+ 2045Q3,TransnetBW,506701.8438604719,14875788.89502485,0.034062183016722994,0.002932139977546582
413
+ 2045Q4,TransnetBW,1052719.2060870056,16403301.269152595,0.06417727680626753,0.0018833165391268294
414
+ 2046Q1,TransnetBW,1260108.2996421887,16887652.870737657,0.0746171365131303,0.001519725788558645
415
+ 2046Q2,TransnetBW,676417.316120984,14822040.553769896,0.04563591049877012,0.0025290598231932776
416
+ 2046Q3,TransnetBW,511768.86229907663,14950167.83949997,0.03423164661382112,0.00292623804033737
417
+ 2046Q4,TransnetBW,1063246.3981478757,16485317.775498357,0.06449656674062708,0.0018721965748607974
model/revenue/curltailment_rate_per_tso/merge.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import re
4
+ import pandas as pd
5
+
6
+ # -------------------------------------------------
7
+ # CONFIG
8
+ # -------------------------------------------------
9
+ # Put the script in the same folder as your CSVs (recommended).
10
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
11
+
12
+ # Which column to extract from each file:
13
+ VALUE_COL = "Wind onshore [MWh] Calculated resolutions"
14
+
15
+ # Output file
16
+ OUT_FILE = os.path.join(BASE_DIR, "wind_onshore_daily_by_tso.csv")
17
+
18
+ # Expected TSOs and filename patterns.
19
+ # Adjust these if your filenames differ.
20
+ TSO_PATTERNS = {
21
+ "TenneT": "Tennet*.csv", # note: your file uses 'Tennet' not 'TenneT'
22
+ "50Hertz": "50Hertz*.csv",
23
+ "Amprion": "Amprion*.csv",
24
+ "TransnetBW": "TransnetBW*.csv",
25
+ }
26
+
27
+ # If your filenames are slightly different, add more patterns or rename keys.
28
+
29
+ # -------------------------------------------------
30
+ def parse_numeric_series(s: pd.Series) -> pd.Series:
31
+ """
32
+ Convert strings like '29,339.75' (US format with thousands comma)
33
+ or '29339.75' into float.
34
+ """
35
+ s = s.astype(str).str.strip()
36
+ # remove thousands separators (commas) but keep decimal dot
37
+ s = s.str.replace(",", "", regex=False)
38
+ return pd.to_numeric(s, errors="coerce")
39
+
40
+ def read_one_tso(files, tso_name: str) -> pd.DataFrame:
41
+ """
42
+ Read all files for one TSO, extract Start date + VALUE_COL,
43
+ return a daily series with columns: date, <tso_name>.
44
+ """
45
+ parts = []
46
+ for f in sorted(files):
47
+ df = pd.read_csv(f, sep=";", dtype=str, encoding="utf-8", engine="python")
48
+
49
+ # Basic column checks
50
+ if "Start date" not in df.columns:
51
+ raise ValueError(f"'Start date' column not found in {f}")
52
+ if VALUE_COL not in df.columns:
53
+ raise ValueError(f"'{VALUE_COL}' not found in {f}. Available columns: {list(df.columns)}")
54
+
55
+ tmp = df[["Start date", VALUE_COL]].copy()
56
+ tmp = tmp.rename(columns={"Start date": "date", VALUE_COL: tso_name})
57
+
58
+ # Parse date (examples: 'Jan 1, 2015')
59
+ tmp["date"] = pd.to_datetime(tmp["date"], errors="coerce")
60
+
61
+ # Parse numeric
62
+ tmp[tso_name] = parse_numeric_series(tmp[tso_name])
63
+
64
+ parts.append(tmp)
65
+
66
+ out = pd.concat(parts, ignore_index=True)
67
+
68
+ # Drop bad dates, sort, dedupe (keep last in case of overlaps)
69
+ out = out.dropna(subset=["date"]).sort_values("date")
70
+ out = out.drop_duplicates(subset=["date"], keep="last").reset_index(drop=True)
71
+
72
+ # Keep only date part (daily frequency)
73
+ out["date"] = out["date"].dt.normalize()
74
+
75
+ return out
76
+
77
+ def main():
78
+ series_list = []
79
+
80
+ # Find and read each TSO
81
+ for tso, pattern in TSO_PATTERNS.items():
82
+ paths = glob.glob(os.path.join(BASE_DIR, pattern))
83
+ if not paths:
84
+ raise FileNotFoundError(f"No files found for {tso} using pattern: {pattern}")
85
+
86
+ df_tso = read_one_tso(paths, tso)
87
+ series_list.append(df_tso)
88
+
89
+ # Merge all TSOs on date (outer join to keep full coverage)
90
+ merged = series_list[0]
91
+ for df in series_list[1:]:
92
+ merged = merged.merge(df, on="date", how="outer")
93
+
94
+ merged = merged.sort_values("date").reset_index(drop=True)
95
+
96
+ # Optional: check missingness
97
+ print("Rows:", len(merged))
98
+ print("Date range:", merged["date"].min().date(), "→", merged["date"].max().date())
99
+ print("\nMissing values per column:")
100
+ print(merged.isna().sum())
101
+
102
+ merged.to_csv(OUT_FILE, index=False)
103
+ print(f"\nSaved: {OUT_FILE}")
104
+
105
+ if __name__ == "__main__":
106
+ main()
model/revenue/curltailment_rate_per_tso/pred_cr.py ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import statsmodels.formula.api as smf
4
+
5
+ # =============================
6
+ # CONFIG
7
+ # =============================
8
+ WIND_DAILY_FILE = "wind_onshore_daily_by_tso.csv"
9
+ LOAD_MONTHLY_FILE = "../monthly_gridload_per_tso/tso_grid_load_monthly_wide.csv"
10
+ CURTAIL_FILE = "curltailment_rate_quarterly_by_tso.csv"
11
+
12
+ FUTURE_START = "2021Q1"
13
+ FUTURE_END = "2046Q4"
14
+
15
+ CR_FLOOR = 0.0
16
+ CR_CAP = 0.30
17
+
18
+ TSOS = ["TenneT", "50Hertz", "Amprion", "TransnetBW"]
19
+ LOAD_COL_MAP = {
20
+ "TenneT": "load_mwh_tennet",
21
+ "50Hertz": "load_mwh_50hertz",
22
+ "Amprion": "load_mwh_amprion",
23
+ "TransnetBW": "load_mwh_transnetbw",
24
+ }
25
+
26
+ # Option B growth assumptions (scenario knobs)
27
+ G_WIND = {tso: 0.01 for tso in TSOS} # +1%/yr wind proxy
28
+ G_LOAD = {tso: 0.005 for tso in TSOS} # +0.5%/yr load proxy
29
+
30
+ LEVEL_QTRS = 8 # last 8 quarters average = baseline level
31
+
32
+ OUTPUT_FILE = "curtailment_forecast_quarterly_by_tso_2021_2046.csv"
33
+
34
+ # =============================
35
+ # HELPERS
36
+ # =============================
37
+ def to_quarter_period_from_dates(s):
38
+ return pd.to_datetime(s).dt.to_period("Q")
39
+
40
+ def wide_to_quarter_long(df, date_col, value_cols, value_name):
41
+ df = df.copy()
42
+ df[date_col] = pd.to_datetime(df[date_col])
43
+ df["quarter"] = to_quarter_period_from_dates(df[date_col])
44
+ long = df.melt(id_vars="quarter", value_vars=value_cols,
45
+ var_name="TSO", value_name=value_name)
46
+ return long.groupby(["quarter", "TSO"], as_index=False)[value_name].sum()
47
+
48
+ def make_season_factors(df_q, value_col):
49
+ """
50
+ Returns season_factor per (TSO, q_num) normalized to mean=1 within each TSO.
51
+ """
52
+ tmp = df_q.copy()
53
+ tmp["q_num"] = tmp["quarter"].dt.quarter.astype(int)
54
+ seas = tmp.groupby(["TSO", "q_num"])[value_col].mean().reset_index()
55
+ seas["mean_tso"] = seas.groupby("TSO")[value_col].transform("mean")
56
+ seas["season_factor"] = seas[value_col] / seas["mean_tso"]
57
+ return seas[["TSO", "q_num", "season_factor"]]
58
+
59
+ def make_future_series(df_q, value_col, g_map, future_q, last_q):
60
+ """
61
+ level = mean of last LEVEL_QTRS for each TSO
62
+ season = avg by q_num per TSO (normalized)
63
+ growth = (1+g)^(years_ahead) where years_ahead = quarters_ahead/4
64
+ """
65
+ df_q = df_q.copy().sort_values(["TSO", "quarter"])
66
+
67
+ # level per TSO (last LEVEL_QTRS) — warning-free
68
+ levels = (
69
+ df_q.groupby("TSO", as_index=True)[value_col]
70
+ .apply(lambda s: float(s.tail(LEVEL_QTRS).mean()))
71
+ .to_dict()
72
+ )
73
+
74
+ seas = make_season_factors(df_q, value_col)
75
+
76
+ future = pd.MultiIndex.from_product([future_q, TSOS], names=["quarter", "TSO"]).to_frame(index=False)
77
+ future["q_num"] = future["quarter"].dt.quarter.astype(int)
78
+
79
+ # FIX: last_q is a scalar Period
80
+ quarters_ahead = future["quarter"].apply(lambda p: p.ordinal) - last_q.ordinal
81
+ years_ahead = quarters_ahead / 4.0
82
+
83
+ future = future.merge(seas, on=["TSO", "q_num"], how="left")
84
+ future["season_factor"] = future["season_factor"].fillna(1.0)
85
+
86
+ out = []
87
+ for tso in TSOS:
88
+ g = float(g_map[tso])
89
+ lvl = float(levels[tso])
90
+
91
+ idx = future["TSO"] == tso
92
+ growth = (1.0 + g) ** years_ahead[idx].values
93
+ vals = lvl * future.loc[idx, "season_factor"].values * growth
94
+
95
+ out.append(pd.DataFrame({
96
+ "quarter": future.loc[idx, "quarter"].values,
97
+ "TSO": tso,
98
+ value_col: vals
99
+ }))
100
+
101
+ out = pd.concat(out, ignore_index=True).sort_values(["quarter", "TSO"]).reset_index(drop=True)
102
+ return out
103
+
104
+ # =============================
105
+ # LOAD & PREPROCESS
106
+ # =============================
107
+ # Wind (daily -> quarterly)
108
+ wind = pd.read_csv(WIND_DAILY_FILE)
109
+ wind_q = wide_to_quarter_long(wind, "date", TSOS, "wind_mwh")
110
+
111
+ # Load (monthly -> quarterly)
112
+ load = pd.read_csv(LOAD_MONTHLY_FILE)
113
+ load = load.rename(columns={v: k for k, v in LOAD_COL_MAP.items()})
114
+ load_q = wide_to_quarter_long(load, "date", TSOS, "load_mwh")
115
+
116
+ # Curtailment (quarterly by TSO in wide columns)
117
+ curt = pd.read_csv(CURTAIL_FILE)
118
+
119
+ # Parse quarter like "2015Q1" safely
120
+ curt["quarter"] = pd.PeriodIndex(curt["quarter"].astype(str), freq="Q")
121
+
122
+ records = []
123
+ for tso in TSOS:
124
+ records.append(pd.DataFrame({
125
+ "quarter": curt["quarter"],
126
+ "TSO": tso,
127
+ "cr": pd.to_numeric(curt[f"{tso}_curtailment_rate"], errors="coerce"),
128
+ "prod_mwh": pd.to_numeric(curt[f"{tso}_production_mwh"], errors="coerce"),
129
+ "curt_mwh": pd.to_numeric(curt[f"{tso}_curtailed_mwh"], errors="coerce"),
130
+ }))
131
+ curt_q = pd.concat(records, ignore_index=True).dropna(subset=["quarter", "TSO", "cr"])
132
+
133
+ # Merge historical modeling frame
134
+ df = curt_q.merge(wind_q, on=["quarter", "TSO"], how="inner").merge(load_q, on=["quarter", "TSO"], how="inner")
135
+ df["S"] = df["wind_mwh"] / df["load_mwh"]
136
+
137
+ # =============================
138
+ # FIT MODEL 0 ON ALL HISTORY
139
+ # =============================
140
+ model0 = smf.ols("cr ~ S * C(TSO)", data=df).fit()
141
+ print(model0.summary())
142
+
143
+ # =============================
144
+ # FUTURE QUARTERS 2021Q1–2046Q4
145
+ # =============================
146
+ future_q = pd.period_range(pd.Period(FUTURE_START, freq="Q"),
147
+ pd.Period(FUTURE_END, freq="Q"),
148
+ freq="Q")
149
+
150
+ # last observed quarter for growth baseline
151
+ last_q_wind = wind_q["quarter"].max()
152
+ last_q_load = load_q["quarter"].max()
153
+ last_q = max(last_q_wind, last_q_load)
154
+
155
+ # =============================
156
+ # OPTION B: forecast wind & load -> future S
157
+ # =============================
158
+ wind_f = make_future_series(wind_q, "wind_mwh", G_WIND, future_q=future_q, last_q=last_q)
159
+ load_f = make_future_series(load_q, "load_mwh", G_LOAD, future_q=future_q, last_q=last_q)
160
+
161
+ future = wind_f.merge(load_f, on=["quarter", "TSO"], how="inner")
162
+ future["S"] = future["wind_mwh"] / future["load_mwh"]
163
+
164
+ # =============================
165
+ # PREDICT CURTAILMENT
166
+ # =============================
167
+ future["cr_hat"] = model0.predict(future).clip(CR_FLOOR, CR_CAP)
168
+
169
+ out = future[["quarter", "TSO", "wind_mwh", "load_mwh", "S", "cr_hat"]].copy()
170
+ out = out.sort_values(["TSO", "quarter"]).reset_index(drop=True)
171
+
172
+ out.to_csv(OUTPUT_FILE, index=False)
173
+ print(f"\nSaved: {OUTPUT_FILE}")
174
+ print(f"Quarter parsing OK (example): {curt['quarter'].iloc[0]}")
175
+ print(f"Baseline last_q used for growth: {last_q}")
model/revenue/curltailment_rate_per_tso/wind_onshore_daily_by_tso.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh1516.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh1718.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh1920.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh2122.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh2324.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/eh25.csv ADDED
The diff for this file is too large to render. See raw diff
 
model/revenue/day_ahead_market_prices/market_price_forecast_20y_monthly.csv ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ date,price_eur_mwh_forecast,log_price_shifted_forecast,mu_log_shifted
2
+ 2026-01-01,44.594443155319794,5.499601504905559,10.090382171916277
3
+ 2026-02-01,39.8876563183496,5.480170715076063,10.091211366154042
4
+ 2026-03-01,40.31309723395208,5.481942644935687,10.092040560391805
5
+ 2026-04-01,33.71001488980778,5.4540810942415465,10.092869754629568
6
+ 2026-05-01,32.24481358096807,5.447792046253938,10.093698948867333
7
+ 2026-06-01,39.17433840003221,5.477192735385145,10.094528143105096
8
+ 2026-07-01,46.79436025343941,5.50855544028488,10.095357337342861
9
+ 2026-08-01,54.5263014655435,5.539404176291427,10.096186531580624
10
+ 2026-09-01,55.389489699997256,5.542789790441547,10.09701572581839
11
+ 2026-10-01,45.62275007189419,5.503796822568928,10.097844920056152
12
+ 2026-11-01,54.667081420068826,5.53995712910992,10.098674114293917
13
+ 2026-12-01,55.9591260499198,5.5450177678644295,10.09950330853168
14
+ 2027-01-01,47.77805957013297,5.512533424395862,10.100332502769445
15
+ 2027-02-01,42.94185981096632,5.492822154676124,10.101161697007209
16
+ 2027-03-01,43.3108854302921,5.4943399895625475,10.101990891244974
17
+ 2027-04-01,36.57096983074101,5.466248246766748,10.102820085482737
18
+ 2027-05-01,35.03881271384006,5.4597506609910935,10.103649279720502
19
+ 2027-06-01,42.00597831031092,5.488962429613169,10.104478473958265
20
+ 2027-07-01,49.673480418633176,5.520153985873101,10.105307668196028
21
+ 2027-08-01,57.455701758413284,5.550847673298426,10.106136862433793
22
+ 2027-09-01,58.29254150962663,5.554092824383411,10.106966056671556
23
+ 2027-10-01,48.383173167497375,5.5149726068932186,10.107795250909321
24
+ 2027-11-01,57.499462897584124,5.551017634266991,10.108624445147084
25
+ 2027-12-01,58.77885059214668,5.555973838236961,10.10945363938485
26
+ 2028-01-01,50.483959421399845,5.523394884228731,10.110282833622612
27
+ 2028-02-01,45.57389601527561,5.503597904041414,10.111112027860377
28
+ 2028-03-01,45.92782321017441,5.50503809129704,10.11194122209814
29
+ 2028-04-01,39.0985966704842,5.47687600523118,10.112770416335906
30
+ 2028-05-01,37.53493168075448,5.470314693420453,10.113599610573669
31
+ 2028-06-01,44.5619694917919,5.4994687307550585,10.114428804811434
32
+ 2028-07-01,52.29725774059088,5.530607986545498,10.115257999049197
33
+ 2028-08-01,60.14893487070765,5.561254293438896,10.116087193286962
34
+ 2028-09-01,60.983326230568366,5.564456521107945,10.116916387524725
35
+ 2028-10-01,50.960967239780445,5.525297418034146,10.11774558176249
36
+ 2028-11-01,60.16270345518876,5.561307217815251,10.118574776000253
37
+ 2028-12-01,61.44697960060353,5.56623150807402,10.119403970238016
38
+ 2029-01-01,53.0592478400047,5.533623642497176,10.120233164475781
39
+ 2029-02-01,48.09220476406074,5.513800470470412,10.121062358713544
40
+ 2029-03-01,48.44386627275534,5.5152169297691565,10.12189155295131
41
+ 2029-04-01,41.539578996819955,5.487033347850016,10.122720747189073
42
+ 2029-05-01,39.955277520734455,5.480452562314247,10.123549941426838
43
+ 2029-06-01,47.049558407765915,5.509588957829186,10.1243791356646
44
+ 2029-07-01,54.85945373180962,5.540712231376867,10.125208329902366
45
+ 2029-08-01,62.7870634303689,5.571344059486982,10.126037524140129
46
+ 2029-09-01,63.62645827259104,5.574533170400865,10.126866718377894
47
+ 2029-10-01,53.499584625872416,5.535362184473179,10.127695912615657
48
+ 2029-11-01,62.79157282696548,5.57136121922783,10.128525106853422
49
+ 2029-12-01,64.08625073875174,5.57627575713285,10.129354301091185
50
+ 2030-01-01,55.611587660874505,5.543659056612215,10.13018349532895
51
+ 2030-02-01,50.59244158904281,5.523827880750296,10.131012689566713
52
+ 2030-03-01,50.94582749874303,5.525237089139615,10.131841883804476
53
+ 2030-04-01,43.970407794765265,5.4970469384085945,10.132671078042241
54
+ 2030-05-01,42.36871976466685,5.490460201993145,10.133500272280004
55
+ 2030-06-01,49.5330088476656,5.519591206431345,10.13432946651777
56
+ 2030-07-01,57.42015543615912,5.550709596044214,10.135158660755533
57
+ 2030-08-01,65.42624345391704,5.581336999654292,10.135987854993298
58
+ 2030-09-01,66.27300106892642,5.584522102283594,10.13681704923106
59
+ 2030-10-01,56.043534108496544,5.545347485133146,10.137646243468826
60
+ 2030-11-01,65.4278972243822,5.5813432302564046,10.138475437706589
61
+ 2030-12-01,66.73476842458899,5.5862547879876985,10.139304631944354
62
+ 2031-01-01,58.174416030150326,5.553635387640124,10.140133826182117
63
+ 2031-02-01,53.104327635604335,5.53380176592566,10.140963020419882
64
+ 2031-03-01,53.46069420035994,5.5352087585452985,10.141792214657645
65
+ 2031-04-01,46.41487532724648,5.507016600483423,10.14262140889541
66
+ 2031-05-01,44.79669398114041,5.500428045567976,10.143450603133173
67
+ 2031-06-01,52.03233747031638,5.5295574025736,10.144279797370938
68
+ 2031-07-01,59.99809387246307,5.5606742997288965,10.145108991608701
69
+ 2031-08-01,68.08399652588372,5.591300351277809,10.145938185846465
70
+ 2031-09-01,68.93890343689054,5.594484229035179,10.14676738008423
71
+ 2031-10-01,58.60673297125959,5.555308502237256,10.147596574321993
72
+ 2031-11-01,68.08477150970634,5.59130324209827,10.148425768559758
73
+ 2031-12-01,69.40447885444422,5.596213889132958,10.14925496279752
74
+ 2032-01-01,60.75823197554888,5.563593663758574,10.150084157035286
75
+ 2032-02-01,55.63721094344635,5.5437592946280825,10.150913351273049
76
+ 2032-03-01,55.99697042740411,5.545165610141584,10.151742545510814
77
+ 2032-04-01,48.88049429607648,5.516972838669362,10.152571739748577
78
+ 2032-05-01,47.24598408552714,5.510383728047464,10.153400933986342
79
+ 2032-06-01,54.553894969079835,5.539512581622283,10.154230128224105
80
+ 2032-07-01,62.599228176701786,5.570629022704825,10.15505932246187
81
+ 2032-08-01,70.76591385385802,5.6012546610840275,10.155888516699633
82
+ 2032-09-01,71.62927159807685,5.604438164538819,10.156717710937398
83
+ 2032-10-01,61.193653242804544,5.565262098649194,10.157546905175161
84
+ 2032-11-01,70.76642024969038,5.60125653131707,10.158376099412925
85
+ 2032-12-01,72.09925288715021,5.606166900056472,10.15920529365069
86
+ 2033-01-01,63.36645373628602,5.57354642256621,10.160034487888453
87
+ 2033-02-01,58.19415096456606,5.553711825036538,10.160863682126218
88
+ 2033-03-01,58.55745534354651,5.555117933636508,10.16169287636398
89
+ 2033-04-01,51.369753009473925,5.526924974715243,10.162522070601746
90
+ 2033-05-01,49.71885231054458,5.520335694277747,10.163351264839509
91
+ 2033-06-01,57.09981482116547,5.549464394011629,10.164180459077274
92
+ 2033-07-01,65.22557643528586,5.580580695725143,10.165009653315037
93
+ 2033-08-01,73.4739055114834,5.611206207845852,10.165838847552802
94
+ 2033-09-01,74.34586651337332,5.614389596919362,10.166668041790565
95
+ 2033-10-01,63.8058530285486,5.575213427408377,10.16749723602833
96
+ 2033-11-01,73.47433168172603,5.611207766202616,10.168326430266093
97
+ 2033-12-01,74.82047049100709,5.616118049899132,10.169155624503858
98
+ 2034-01-01,66.00031563161656,5.58349749536602,10.169984818741622
99
+ 2034-02-01,60.776267755249705,5.5636628280409655,10.170814012979385
100
+ 2034-03-01,61.143188912655944,5.565068873411253,10.17164320721715
101
+ 2034-04-01,53.88359059186001,5.536875857208356,10.172472401454913
102
+ 2034-05-01,52.216166877849616,5.5302865248777495,10.173301595692678
103
+ 2034-06-01,59.67093053155702,5.559415177600135,10.174130789930441
104
+ 2034-07-01,67.87794206874867,5.590531436724557,10.174959984168206
105
+ 2034-08-01,76.20874719567752,5.621156910262554,10.175789178405969
106
+ 2034-09-01,77.0894184496504,5.624340264382854,10.176618372643734
107
+ 2034-10-01,66.4439928096333,5.585164063206726,10.177447566881497
108
+ 2034-11-01,76.20915130374135,5.621158373314584,10.178276761119262
109
+ 2034-12-01,77.56874466330521,5.626068631023262,10.179105955357025
110
+ 2035-01-01,68.66037970070784,5.593448052947007,10.17993514959479
111
+ 2035-02-01,63.38408453172809,5.573613364293528,10.180764343832553
112
+ 2035-03-01,63.754669880547,5.575019390341767,10.181593538070318
113
+ 2035-04-01,56.42246972366303,5.546826356634458,10.182422732308082
114
+ 2035-05-01,54.73836744903937,5.540237008446092,10.183251926545847
115
+ 2035-06-01,62.26767612138377,5.569365646802467,10.18408112078361
116
+ 2035-07-01,70.55675539954859,5.6004818929122955,10.184910315021373
117
+ 2035-08-01,78.97086634317583,5.631107354659992,10.185739509259138
118
+ 2035-09-01,79.86034142144422,5.63429069809911,10.186568703496901
119
+ 2035-10-01,69.10845781505611,5.5951144872465886,10.187397897734666
120
+ 2035-11-01,78.97126636768934,5.631108788588316,10.18822709197243
121
+ 2035-12-01,80.34445355042078,5.636019038355501,10.189056286210194
122
+ 2036-01-01,71.34700229789246,5.603398453084811,10.189885480447957
123
+ 2036-02-01,66.01794207418999,5.5835637579136845,10.190714674685722
124
+ 2036-03-01,66.3922317270688,5.584969778057392,10.191543868923485
125
+ 2036-04-01,58.98670776217796,5.556776739000998,10.19237306316125
126
+ 2036-05-01,57.28576313040668,5.550187385966736,10.193202257399014
127
+ 2036-06-01,64.8903640814836,5.579316019933074,10.194031451636778
128
+ 2036-07-01,73.2623334195938,5.610432262065839,10.194860645874542
129
+ 2036-08-01,81.76058478297745,5.641057720210597,10.195689840112307
130
+ 2036-09-01,82.65895372059816,5.644241060385705,10.19651903435007
131
+ 2036-10-01,71.79955013309637,5.605064846576219,10.197348228587833
132
+ 2036-11-01,81.76098630014172,5.641059145239149,10.198177422825598
133
+ 2036-12-01,83.14790470333486,5.645969392579529,10.199006617063361
134
+ 2037-01-01,74.06047812337567,5.613348805110329,10.199835811301126
135
+ 2037-02-01,68.67812664835361,5.593514107947505,10.20066500553889
136
+ 2037-03-01,69.05615871954478,5.594920126286878,10.201494199776654
137
+ 2037-04-01,61.576578957463994,5.566727085595883,10.202323394014417
138
+ 2037-05-01,59.85862446752458,5.560137731080789,10.203152588252182
139
+ 2037-06-01,67.5392711787328,5.589266363705596,10.203981782489945
140
+ 2037-07-01,75.99495998404115,5.62038260462303,10.20481097672771
141
+ 2037-08-01,84.57819364819437,5.651008061666781,10.205640170965474
142
+ 2037-09-01,85.4855460000602,5.65419140084446,10.206469365203239
143
+ 2037-10-01,74.51754802327457,5.615015186131371,10.207298559441002
144
+ 2037-11-01,84.57859840658534,5.651009483975701,10.208127753678767
145
+ 2037-12-01,85.97938579277292,5.655919730574487,10.20895694791653
146
+ 2038-01-01,76.80108469550021,5.623299142433453,10.209786142154293
147
+ 2038-02-01,71.36490950539496,5.603464444661998,10.210615336392058
148
+ 2038-03-01,71.74672174970044,5.604870462449991,10.211444530629821
149
+ 2038-04-01,64.1923460179193,5.576677421259488,10.212273724867586
150
+ 2038-05-01,62.45721185596574,5.570088066291871,10.21310291910535
151
+ 2038-06-01,70.214664957318,5.599216698506728,10.213932113343114
152
+ 2038-07-01,78.75491058086925,5.6303329390527725,10.214761307580877
153
+ 2038-08-01,87.42397651596599,5.660958395760074,10.215590501818642
154
+ 2038-09-01,88.34040230643274,5.66414173463295,10.216419696056406
155
+ 2038-10-01,77.26272424080327,5.624965519643736,10.21724889029417
156
+ 2038-11-01,87.42438508306878,5.660959817237911,10.218078084531934
157
+ 2038-12-01,88.83918028107018,5.665870063610079,10.218907278769699
158
+ 2039-01-01,79.56909609519778,5.633249475263744,10.219736473007462
159
+ 2039-02-01,74.07855909136009,5.613414777306299,10.220565667245227
160
+ 2039-03-01,74.46418941255416,5.6148207949258,10.22139486148299
161
+ 2039-04-01,66.83426987034437,5.586627753582654,10.222224055720755
162
+ 2039-05-01,65.08178432753851,5.580038398476753,10.223053249958518
163
+ 2039-06-01,72.91681193614801,5.609167030566333,10.223882444196281
164
+ 2039-07-01,81.54245999438939,5.640283270998889,10.224711638434046
165
+ 2039-08-01,90.29821656855955,5.670908727603376,10.22554083267181
166
+ 2039-09-01,91.22380659072292,5.674092066383111,10.226370026909574
167
+ 2039-10-01,80.03535171077118,5.634915851309515,10.227199221147337
168
+ 2039-11-01,90.29862914760832,5.670910148827248,10.228028415385102
169
+ 2039-12-01,91.72757227843869,5.675820395130163,10.228857609622866
170
+ 2040-01-01,82.36478722674906,5.643199806721093,10.22968680386063
171
+ 2040-02-01,76.81934483378916,5.623365108706811,10.230515998098394
172
+ 2040-03-01,77.20883144413546,5.624771126274824,10.231345192336159
173
+ 2040-04-01,69.50261269011042,5.59657808488503,10.232174386573922
174
+ 2040-05-01,67.73260227976863,5.589988729736874,10.233003580811687
175
+ 2040-06-01,75.64598015713221,5.619117361788172,10.23383277504945
176
+ 2040-07-01,84.35788468930582,5.650233602186047,10.234661969287215
177
+ 2040-08-01,93.20119882295933,5.680859058759115,10.235491163524978
178
+ 2040-09-01,94.13604473725479,5.684042397510386,10.236320357762743
179
+ 2040-10-01,82.83570529811294,5.644866182411004,10.237149552000506
180
+ 2040-11-01,93.20161550504315,5.680860479905377,10.23797874623827
181
+ 2040-12-01,94.64484806127126,5.68577072618713,10.238807940476034
182
+ 2041-01-01,85.1884351516693,5.653150137758885,10.239637134713798
183
+ 2041-02-01,79.58753832889005,5.6333154397272365,10.240466328951563
184
+ 2041-03-01,79.98091980100014,5.634721457279515,10.241295523189326
185
+ 2041-04-01,72.19763885437624,5.606528415875468,10.24212471742709
186
+ 2041-05-01,70.40992833619299,5.599939060714397,10.242953911664854
187
+ 2041-06-01,78.40243999006759,5.629067692753997,10.243783105902619
188
+ 2041-07-01,87.20146356550998,5.660183933141273,10.244612300140382
189
+ 2041-08-01,96.13321083856891,5.690809389704741,10.245441494378147
190
+ 2041-09-01,97.0774052095104,5.693992728447314,10.24627068861591
191
+ 2041-10-01,85.66406237277067,5.654816513340053,10.247099882853675
192
+ 2041-11-01,96.13363168045043,5.690810810827287,10.247929077091438
193
+ 2041-12-01,97.59129656041682,5.695721057102574,10.248758271329203
194
+ 2042-01-01,88.0403195194366,5.663100468668471,10.249587465566966
195
+ 2042-02-01,82.3834137266116,5.643265770631515,10.25041665980473
196
+ 2042-03-01,82.78072901210379,5.644671788178986,10.251245854042494
197
+ 2042-04-01,74.91961525445168,5.616478746770582,10.252075048280258
198
+ 2042-05-01,73.1140276299339,5.609889391605567,10.252904242518023
199
+ 2042-06-01,81.18646439964851,5.639018023641592,10.253733436755786
200
+ 2042-07-01,90.0734782102125,5.670134264025631,10.25456263099355
201
+ 2042-08-01,99.09454295540507,5.700759720586163,10.255391825231314
202
+ 2042-09-01,100.0481792692861,5.70394305932608,10.256221019469079
203
+ 2042-10-01,88.52070300318843,5.664766844216409,10.257050213706842
204
+ 2042-11-01,99.09496800353827,5.700761141701463,10.257879407944607
205
+ 2042-12-01,100.5672095317405,5.705671387974771,10.25870860218237
206
+ 2043-01-01,90.9207227196465,5.6730507995388795,10.259537796420135
207
+ 2043-02-01,85.20724786833222,5.653216101500301,10.260366990657898
208
+ 2043-03-01,85.60853630626599,5.654622119046303,10.261196184895663
209
+ 2043-04-01,77.66881141055563,5.626429077636569,10.262025379133426
210
+ 2043-05-01,75.84516790943604,5.6198397224703465,10.26285457337119
211
+ 2043-06-01,83.9983290466327,5.64896835450528,10.263683767608955
212
+ 2043-07-01,92.97421299510637,5.680084594888328,10.264512961846718
213
+ 2043-08-01,102.0854883875678,5.7107100514479665,10.265342156084483
214
+ 2043-09-01,103.0486610643494,5.71389339018707,10.266171350322246
215
+ 2043-10-01,91.4059100352859,5.674717175076665,10.26700054456001
216
+ 2043-11-01,102.08591768551321,5.7107114725610515,10.267829738797774
217
+ 2043-12-01,103.57288162882418,5.7156217188337575,10.268658933035539
218
+ 2044-01-01,93.82992994839128,5.683001130397317,10.269488127273302
219
+ 2044-02-01,88.05932034839117,5.663166432358245,10.270317321511067
220
+ 2044-03-01,88.4646216705761,5.664572449903796,10.27114651574883
221
+ 2044-04-01,80.44549952576034,5.6363794084936565,10.271975709986595
222
+ 2044-05-01,78.6036195895199,5.629790053327066,10.272804904224358
223
+ 2044-06-01,86.83831233802204,5.658918685361666,10.273634098462123
224
+ 2044-07-01,95.90395512592022,5.690034925744412,10.274463292699886
225
+ 2044-08-01,105.10634327224909,5.720660382303775,10.275292486937651
226
+ 2044-09-01,106.07914767572493,5.72384372104263,10.276121681175415
227
+ 2044-10-01,94.31996913627626,5.6846675059319995,10.276950875413178
228
+ 2044-11-01,105.10677686296742,5.720661803416183,10.277780069650943
229
+ 2044-12-01,106.60861044565729,5.725572049688703,10.278609263888706
230
+ 2045-01-01,96.76822924835352,5.692951461252097,10.27943845812647
231
+ 2045-02-01,90.93991355229906,5.67311676321287,10.280267652364234
232
+ 2045-03-01,91.34926788766711,5.674522780758286,10.281096846601999
233
+ 2045-04-01,83.24995452135676,5.646329739348021,10.281926040839762
234
+ 2045-05-01,81.38965578572021,5.6397403841813185,10.282755235077527
235
+ 2045-06-01,89.70669546168648,5.668869016215815,10.28358442931529
236
+ 2045-07-01,98.86299467744556,5.69998525659847,10.284413623553055
237
+ 2045-08-01,108.15740670521978,5.730610713157748,10.285242817790818
238
+ 2045-09-01,109.13993915270811,5.7337940518965285,10.286072012028583
239
+ 2045-10-01,97.26316882783567,5.694617836785829,10.286901206266347
240
+ 2045-11-01,108.15784463178181,5.7306121342699505,10.287730400504111
241
+ 2045-12-01,109.67469655028236,5.735522380542415,10.288559594741875
model/revenue/day_ahead_market_prices/market_price_monthly_history.csv ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ date,price_eur_mwh
2
+ 2015-01-01,31.05307098765432
3
+ 2015-02-01,36.71691964285714
4
+ 2015-03-01,31.34314939434724
5
+ 2015-04-01,29.724375
6
+ 2015-05-01,25.357916666666668
7
+ 2015-06-01,30.06438888888889
8
+ 2015-07-01,34.99568548387097
9
+ 2015-08-01,31.605094086021502
10
+ 2015-09-01,31.881319444444443
11
+ 2015-10-01,39.38145161290323
12
+ 2015-11-01,32.389375
13
+ 2015-12-01,27.780604838709678
14
+ 2016-01-01,29.035524193548387
15
+ 2016-02-01,21.989554597701147
16
+ 2016-03-01,24.30504710632571
17
+ 2016-04-01,24.21348611111111
18
+ 2016-05-01,22.54236559139785
19
+ 2016-06-01,27.69377777777778
20
+ 2016-07-01,27.188306451612902
21
+ 2016-08-01,27.182567204301076
22
+ 2016-09-01,30.493861111111112
23
+ 2016-10-01,37.135551075268815
24
+ 2016-11-01,38.222541666666665
25
+ 2016-12-01,37.477889784946235
26
+ 2017-01-01,52.372956989247314
27
+ 2017-02-01,39.70160714285714
28
+ 2017-03-01,31.701386271870795
29
+ 2017-04-01,28.86991666666667
30
+ 2017-05-01,30.460510752688172
31
+ 2017-06-01,30.00161111111111
32
+ 2017-07-01,33.009112903225805
33
+ 2017-08-01,30.848387096774193
34
+ 2017-09-01,34.34861111111111
35
+ 2017-10-01,28.401478494623657
36
+ 2017-11-01,40.366625
37
+ 2017-12-01,30.765725806451613
38
+ 2018-01-01,29.46159946236559
39
+ 2018-02-01,40.11510416666666
40
+ 2018-03-01,37.36347240915209
41
+ 2018-04-01,32.056263888888886
42
+ 2018-05-01,33.54216397849462
43
+ 2018-06-01,42.42323611111111
44
+ 2018-07-01,49.54345430107527
45
+ 2018-08-01,56.189408602150536
46
+ 2018-09-01,54.832138888888885
47
+ 2018-10-01,53.12668010752688
48
+ 2018-11-01,56.676013888888896
49
+ 2018-12-01,48.13212365591398
50
+ 2019-01-01,49.393373655913976
51
+ 2019-02-01,42.82078869047619
52
+ 2019-03-01,30.626958277254378
53
+ 2019-04-01,36.95590277777778
54
+ 2019-05-01,37.84356182795699
55
+ 2019-06-01,32.517583333333334
56
+ 2019-07-01,39.68502688172043
57
+ 2019-08-01,36.84849462365591
58
+ 2019-09-01,35.75070833333333
59
+ 2019-10-01,36.999556451612904
60
+ 2019-11-01,41.00120833333333
61
+ 2019-12-01,31.966142473118282
62
+ 2020-01-01,35.0349059139785
63
+ 2020-02-01,21.919008620689652
64
+ 2020-03-01,22.485827725437417
65
+ 2020-04-01,17.093125
66
+ 2020-05-01,17.596505376344084
67
+ 2020-06-01,26.18488888888889
68
+ 2020-07-01,30.062862903225806
69
+ 2020-08-01,34.86395161290322
70
+ 2020-09-01,43.690194444444444
71
+ 2020-10-01,34.01510752688172
72
+ 2020-11-01,38.78570833333333
73
+ 2020-12-01,43.51974462365591
74
+ 2021-01-01,52.806223118279576
75
+ 2021-02-01,48.70494047619048
76
+ 2021-03-01,47.16483176312248
77
+ 2021-04-01,53.61313888888889
78
+ 2021-05-01,53.34893817204301
79
+ 2021-06-01,74.07995833333334
80
+ 2021-07-01,81.36924731182796
81
+ 2021-08-01,82.69688172043011
82
+ 2021-09-01,128.37230555555556
83
+ 2021-10-01,139.59403225806452
84
+ 2021-11-01,176.1513611111111
85
+ 2021-12-01,221.06038978494624
86
+ 2022-01-01,167.72657258064518
87
+ 2022-02-01,128.80267857142857
88
+ 2022-03-01,252.00685060565274
89
+ 2022-04-01,165.73190277777778
90
+ 2022-05-01,177.4769489247312
91
+ 2022-06-01,218.0332361111111
92
+ 2022-07-01,315.0009946236559
93
+ 2022-08-01,465.18350806451616
94
+ 2022-09-01,346.11512500000003
95
+ 2022-10-01,152.67469086021507
96
+ 2022-11-01,173.634375
97
+ 2022-12-01,251.61639784946237
98
+ 2023-01-01,117.82931451612903
99
+ 2023-02-01,128.31184523809523
100
+ 2023-03-01,102.5214535666218
101
+ 2023-04-01,100.74399999999999
102
+ 2023-05-01,81.71538978494624
103
+ 2023-06-01,94.7561111111111
104
+ 2023-07-01,77.6061559139785
105
+ 2023-08-01,94.3218817204301
106
+ 2023-09-01,100.72348611111111
107
+ 2023-10-01,87.49303763440861
108
+ 2023-11-01,91.12227777777777
109
+ 2023-12-01,68.51932795698924
110
+ 2024-01-01,76.57114247311829
111
+ 2024-02-01,61.335847701149426
112
+ 2024-03-01,64.70199192462988
113
+ 2024-04-01,62.360819444444445
114
+ 2024-05-01,67.21001344086021
115
+ 2024-06-01,72.88772222222222
116
+ 2024-07-01,67.69702956989246
117
+ 2024-08-01,82.04717741935484
118
+ 2024-09-01,78.30997222222223
119
+ 2024-10-01,86.10174731182795
120
+ 2024-11-01,113.90644444444445
121
+ 2024-12-01,108.31559139784946
122
+ 2025-01-01,114.14016129032258
123
+ 2025-02-01,128.52236607142856
124
+ 2025-03-01,94.72749663526245
125
+ 2025-04-01,77.93565277777778
126
+ 2025-05-01,67.33862903225807
127
+ 2025-06-01,63.9875
128
+ 2025-07-01,87.79522849462366
129
+ 2025-08-01,76.99025537634408
130
+ 2025-09-01,83.51108333333333
131
+ 2025-10-01,84.51182795698925
132
+ 2025-11-01,101.88231944444445
133
+ 2025-12-01,93.47024193548387