nerezta PV A pri prodeji z baterie
This commit is contained in:
@@ -33,6 +33,10 @@ Příklad (čistá arbitráž, nákup = spot + fixní adder + distribuce/poplatk
|
||||
--buy-distribution-kwh 1.80 --buy-other-fees-kwh 0.20 --buy-vat-multiplier 1.21 \\
|
||||
... (ostatní jako výše)
|
||||
|
||||
Příklad (nákup jako home-01, prodej spot −0,30 dle živé DB):
|
||||
python3 scripts/analysis/battery_sizing_screen.py --db \\
|
||||
--buy-home-01 --sell-margin-fixed -0.30 ... (ostatní jako výše)
|
||||
|
||||
Vyžaduje: pip install pulp (volitelně psycopg2 pro --db).
|
||||
|
||||
Omezení modelu: FVE buď syntetický denní tvar (--pv-daily-kwh-*), nebo součet měsíčních
|
||||
@@ -81,6 +85,24 @@ class SiteLimits:
|
||||
soc_max_frac: float = 0.95
|
||||
|
||||
|
||||
# home-01 (živá DB site_market_config + V016 tarif/HDO): ověř MCP před změnou
|
||||
HOME01_BUY_MARGIN_FIXED_KWH = 0.0
|
||||
HOME01_BUY_MARGIN_PCT = 9.0
|
||||
HOME01_SYSTEM_SERVICES_KWH = 0.192
|
||||
HOME01_OTE_FEE_KWH = 0.001
|
||||
HOME01_DIST_NT_KWH = 0.2243
|
||||
HOME01_DIST_VT_KWH = 0.74987
|
||||
HOME01_VAT_MULTIPLIER = 1.21
|
||||
HOME01_SELL_MARGIN_FIXED_KWH = -0.30
|
||||
# VT okna Europe/Prague (každý den): 09–10, 12–13, 16–17, 20–21
|
||||
HOME01_VT_SLOT_MINUTES: tuple[tuple[int, int], ...] = (
|
||||
(9 * 60, 10 * 60),
|
||||
(12 * 60, 13 * 60),
|
||||
(16 * 60, 17 * 60),
|
||||
(20 * 60, 21 * 60),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BuyPricingConfig:
|
||||
mode: str = "flat"
|
||||
@@ -210,6 +232,35 @@ def effective_buy_spot_asym_pct_kc_kwh(raw_ote: float, asym_pct: float) -> float
|
||||
return raw_ote * (1.0 - asym_pct / 100.0)
|
||||
|
||||
|
||||
def slot_is_vt_home01(slot_index: int) -> bool:
|
||||
"""15min slot 0..95 od půlnoci (Europe/Prague) — VT okna jako u home-01 HDO."""
|
||||
mins = (slot_index // 4) * 60 + (slot_index % 4) * 15
|
||||
for start_m, end_m in HOME01_VT_SLOT_MINUTES:
|
||||
if start_m <= mins < end_m:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def effective_buy_home01_kc_kwh(raw_ote: float, is_vt: bool) -> float:
|
||||
"""Stejná struktura jako ems.fn_effective_buy_price pro home-01 (spot, buy_margin_percent=0)."""
|
||||
dist = HOME01_DIST_VT_KWH if is_vt else HOME01_DIST_NT_KWH
|
||||
if HOME01_BUY_MARGIN_PCT != 0.0:
|
||||
if raw_ote >= 0:
|
||||
energy = raw_ote * (1.0 + HOME01_BUY_MARGIN_PCT / 100.0)
|
||||
else:
|
||||
energy = raw_ote * (1.0 - HOME01_BUY_MARGIN_PCT / 100.0)
|
||||
else:
|
||||
energy = raw_ote
|
||||
subtotal = (
|
||||
energy
|
||||
+ dist
|
||||
+ HOME01_SYSTEM_SERVICES_KWH
|
||||
+ HOME01_OTE_FEE_KWH
|
||||
+ HOME01_BUY_MARGIN_FIXED_KWH
|
||||
)
|
||||
return subtotal * HOME01_VAT_MULTIPLIER
|
||||
|
||||
|
||||
def build_buy_prices_96(raw_ote_96: Sequence[float], cfg: BuyPricingConfig) -> list[float]:
|
||||
fixed_fees_kwh = cfg.distribution_kwh + cfg.other_fees_kwh
|
||||
if cfg.mode == "spot_add_fixed":
|
||||
@@ -240,6 +291,11 @@ def build_buy_prices_96(raw_ote_96: Sequence[float], cfg: BuyPricingConfig) -> l
|
||||
cfg.nt_to_hour,
|
||||
)
|
||||
]
|
||||
if cfg.mode == "home01":
|
||||
return [
|
||||
effective_buy_home01_kc_kwh(px, slot_is_vt_home01(t))
|
||||
for t, px in enumerate(raw_ote_96)
|
||||
]
|
||||
if cfg.mode != "flat":
|
||||
raise ValueError(f"Neznámý buy mode: {cfg.mode}")
|
||||
return [(cfg.flat_kwh + fixed_fees_kwh) * cfg.vat_multiplier] * SLOTS_PER_DAY
|
||||
@@ -597,6 +653,11 @@ def main() -> None:
|
||||
default=None,
|
||||
help="Základ nákupu = raw OTE × (1 + p/100) pro raw >= 0, raw OTE × (1 - p/100) pro raw < 0",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--buy-home-01",
|
||||
action="store_true",
|
||||
help="Nákup jako home-01 z živé DB (spot ×1.09/×0.91, dist NT/VT HDO, SS+OTE, DPH 21 %)",
|
||||
)
|
||||
ap.add_argument(
|
||||
"--buy-distribution-kwh",
|
||||
type=float,
|
||||
@@ -647,9 +708,13 @@ def main() -> None:
|
||||
args.buy_nt_kwh is not None,
|
||||
args.buy_spot_add_fixed_kwh is not None,
|
||||
args.buy_spot_asym_pct is not None,
|
||||
args.buy_home_01,
|
||||
]
|
||||
if sum(base_buy_modes) > 1:
|
||||
ap.error("Zvol jen jeden režim základu nákupu: flat, NT/VT, --buy-spot-add-fixed-kwh nebo --buy-spot-asym-pct")
|
||||
ap.error(
|
||||
"Zvol jen jeden režim nákupu: flat, NT/VT, --buy-spot-add-fixed-kwh, "
|
||||
"--buy-spot-asym-pct nebo --buy-home-01"
|
||||
)
|
||||
if args.buy_vat_multiplier <= 0:
|
||||
ap.error("--buy-vat-multiplier musí být > 0")
|
||||
if args.solver_time_limit_sec < 0:
|
||||
@@ -686,7 +751,9 @@ def main() -> None:
|
||||
if args.pvgis_csv:
|
||||
monthly_ed = merge_pvgis_monthly_ed_kwh([Path(p) for p in args.pvgis_csv])
|
||||
|
||||
if args.buy_spot_add_fixed_kwh is not None:
|
||||
if args.buy_home_01:
|
||||
buy_cfg = BuyPricingConfig(mode="home01")
|
||||
elif args.buy_spot_add_fixed_kwh is not None:
|
||||
buy_cfg = BuyPricingConfig(
|
||||
mode="spot_add_fixed",
|
||||
spot_add_fixed_kwh=args.buy_spot_add_fixed_kwh,
|
||||
@@ -762,6 +829,15 @@ def main() -> None:
|
||||
f" Nákup = raw OTE × (1 + {args.buy_spot_asym_pct}/100) pro raw >= 0, "
|
||||
f"raw OTE × (1 - {args.buy_spot_asym_pct}/100) pro raw < 0"
|
||||
)
|
||||
elif buy_cfg.mode == "home01":
|
||||
print(
|
||||
" Nákup = home-01 (MCP): raw OTE ×(1+9%) / ×(1-9%) + dist NT/VT dle HDO + "
|
||||
f"{HOME01_SYSTEM_SERVICES_KWH} SS + {HOME01_OTE_FEE_KWH} OTE, ×{HOME01_VAT_MULTIPLIER} DPH"
|
||||
)
|
||||
print(
|
||||
f" distribuce NT {HOME01_DIST_NT_KWH} / VT {HOME01_DIST_VT_KWH} Kč/kWh; "
|
||||
"VT 09–10, 12–13, 16–17, 20–21; prodej typicky sell_margin_fixed -0.30"
|
||||
)
|
||||
else:
|
||||
print(f" Nákup = flat {args.buy_vat_kwh} Kč/kWh")
|
||||
if args.buy_distribution_kwh or args.buy_other_fees_kwh:
|
||||
|
||||
Reference in New Issue
Block a user