Investiční studie v2: POTENCIÁLNÍ výroba místo telemetrie (škrcení 81 %!)

Klíčová oprava (postřeh uživatele): při sell<0 lokality škrtí výrobu
(reg 340 / GEN cutoff) — telemetrie ukázala 357 kWh, predikce 1879 kWh
(96 % minut v derating). Studie nyní používají max(skutečnost, kanonický
forecast per pole) v sell<0 slotech.

Nové výsledky (horní meze): BA81 32 kWh +35/+46 Kč/den (výkon 6.25/12 kW);
KV1 25 kWh +20/+22 Kč/den (stará smlouva); HU1 fixní: 75 Kč/den bez sdílení,
149 Kč/den s EDC sdílením @1.5 Kč distribuce (sdílitelných ~49 kWh/den!);
HU1 spot: 372 Kč/den, sdílení +0. + docs/onboarding-wallbox-tc-2026-06.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dusan Vojacek
2026-06-11 17:24:49 +02:00
parent d47f5f8b87
commit 53e9afb513
4 changed files with 110 additions and 4 deletions

View File

@@ -131,12 +131,34 @@ async def _load_slots(conn: asyncpg.Connection, site_id: int) -> list[Slot]:
select a.interval_start,
p.effective_buy_price_czk_kwh as buy,
p.effective_sell_price_czk_kwh as sell,
greatest(0, coalesce(a.actual_pv_production_wh,0) - coalesce(a.pv_b_production_wh,0)) as pv_a,
coalesce(a.pv_b_production_wh,0) as pv_b,
-- POTENCIÁL: při sell<0 lokalita škrtí výrobu (reg 340 / GEN cutoff),
-- telemetrie ji nevidí → použij max(skutečnost, predikce) per pole.
case when p.effective_sell_price_czk_kwh < 0
then greatest(coalesce(a.actual_pv_production_wh,0) - coalesce(a.pv_b_production_wh,0),
coalesce(fc.fc_a_wh, 0))
else greatest(0, coalesce(a.actual_pv_production_wh,0) - coalesce(a.pv_b_production_wh,0))
end as pv_a,
case when p.effective_sell_price_czk_kwh < 0
then greatest(coalesce(a.pv_b_production_wh,0), coalesce(fc.fc_b_wh, 0))
else coalesce(a.pv_b_production_wh,0)
end as pv_b,
coalesce(a.actual_load_consumption_wh,0) as load
from ems.audit_interval a
join ems.vw_site_effective_price p
on p.site_id = a.site_id and p.interval_start = a.interval_start
left join lateral (
select
sum(power_w) filter (where pa.controllable) * 0.25 as fc_a_wh,
sum(power_w) filter (where not pa.controllable) * 0.25 as fc_b_wh
from (
select distinct on (fpr.pv_array_id) fpi2.power_w, fpr.pv_array_id
from ems.forecast_pv_interval fpi2
join ems.forecast_pv_run fpr on fpr.id = fpi2.run_id
where fpi2.interval_start = a.interval_start
order by fpr.pv_array_id, fpr.created_at desc
) x
join ems.asset_pv_array pa on pa.id = x.pv_array_id and pa.site_id = a.site_id
) fc on true
where a.site_id = $1 and a.actual_load_consumption_wh is not null
order by a.interval_start
""",

View File

@@ -60,15 +60,31 @@ async def _load(conn: asyncpg.Connection, price_site: int = 3) -> list[Slot]:
else p.effective_buy_price_czk_kwh end as buy,
case when $1 = 5 then p2.effective_sell_price_czk_kwh
else p.effective_sell_price_czk_kwh end as sell,
-- POTENCIÁL: BA81 při sell<0 škrtí (81 % výroby v datech chybí)
case when p.effective_sell_price_czk_kwh < 0
then greatest(0, coalesce(a.actual_pv_production_wh,0)
- coalesce(a.actual_load_consumption_wh,0))
then greatest(0,
greatest(coalesce(a.actual_pv_production_wh,0),
coalesce(fc.fc_a_wh,0) + coalesce(fc.fc_b_wh,0))
- coalesce(a.actual_load_consumption_wh,0))
else 0 end as share_wh
from ems.audit_interval a
join ems.vw_site_effective_price p
on p.site_id = a.site_id and p.interval_start = a.interval_start
left join ems.vw_site_effective_price p2
on p2.site_id = 5 and p2.interval_start = a.interval_start
left join lateral (
select
sum(power_w) filter (where pa.controllable) * 0.25 as fc_a_wh,
sum(power_w) filter (where not pa.controllable) * 0.25 as fc_b_wh
from (
select distinct on (fpr.pv_array_id) fpi2.power_w, fpr.pv_array_id
from ems.forecast_pv_interval fpi2
join ems.forecast_pv_run fpr on fpr.id = fpi2.run_id
where fpi2.interval_start = a.interval_start
order by fpr.pv_array_id, fpr.created_at desc
) x
join ems.asset_pv_array pa on pa.id = x.pv_array_id and pa.site_id = a.site_id
) fc on true
where a.site_id = 3 and a.actual_load_consumption_wh is not null
and p2.effective_buy_price_czk_kwh is not null
order by a.interval_start

View File

@@ -0,0 +1,33 @@
# Studie navýšení baterie — perfect-hindsight nad reálnými daty (audit_interval)
# Okna 7 dní s navazujícím SoC; Δ = horní mez ročního přínosu
## BA81 (2026-04-26 … 2026-06-11; block_neg=False, pv_b_shed=True, export cap 16 kW)
current 12.5 kWh / 6.25 kW -4579 Kč / 45 dní
upgrade 32 kWh / 6.25 kW (výkon beze změny) -6144 Kč Δ +1565 Kč (+34.77 Kč/den; rok ~761512692 Kč)
upgrade 32 kWh / 12.00 kW (0.5C, cap AC stridace) -6657 Kč Δ +2078 Kč (+46.19 Kč/den; rok ~1011516858 Kč)
## KV1 (2026-04-30 … 2026-06-11; block_neg=True, pv_b_shed=False, export cap 8 kW)
current 12.5 kWh / 6.25 kW -2149 Kč / 41 dní
upgrade 25 kWh / 6.25 kW (výkon beze změny) -2952 Kč Δ +803 Kč (+19.58 Kč/den; rok ~42897148 Kč)
upgrade 25 kWh / 12.00 kW (0.5C, cap AC stridace) -3056 Kč Δ +907 Kč (+22.12 Kč/den; rok ~48448073 Kč)
Pozn.: rok = Kč/den × 365; dolní odhad ×0.6 (zima: méně PV, menší spready).
Horní mez (dokonalá předpověď) — reálný plánovač zachytí typicky 7090 %.
# HU1 BESS studie — 128 kWh / 36 kW / AC 40 kW; ceny site 3 (fixní nákup BA81)
# Období: 18 dní (BA81 audit); sdílitelný přebytek BA81 při sell<0: 882 kWh
bez EDC sdílení výnos 1351 Kč = 75.06 Kč/den (rok ~1643827396 Kč)
EDC sdílení, distribuce 2.0 Kč/kWh výnos 2251 Kč = 125.05 Kč/den (rok ~2738645643 Kč)
EDC sdílení, distribuce 1.5 Kč/kWh výnos 2689 Kč = 149.37 Kč/den (rok ~3271254520 Kč)
EDC sdílení, distribuce 1.0 Kč/kWh výnos 3130 Kč = 173.86 Kč/den (rok ~3807663460 Kč)
Pozn.: horní mez (perfect hindsight); jaro = nejsilnější sezóna pro spot spready.
# HU1 BESS studie — 128 kWh / 36 kW / AC 40 kW; ceny site 5 (SPOT nákup i prodej (site 5))
# Období: 18 dní (BA81 audit); sdílitelný přebytek BA81 při sell<0: 882 kWh
bez EDC sdílení výnos 6699 Kč = 372.17 Kč/den (rok ~81505135842 Kč)
EDC sdílení, distribuce 2.0 Kč/kWh výnos 6699 Kč = 372.17 Kč/den (rok ~81505135842 Kč)
EDC sdílení, distribuce 1.5 Kč/kWh výnos 6699 Kč = 372.17 Kč/den (rok ~81505135842 Kč)
EDC sdílení, distribuce 1.0 Kč/kWh výnos 6699 Kč = 372.17 Kč/den (rok ~81505135842 Kč)
Pozn.: horní mez (perfect hindsight); jaro = nejsilnější sezóna pro spot spready.