fix nabijeni z gridu u fixnich tarifu
This commit is contained in:
@@ -27,6 +27,8 @@ def _select_charge_slots(
|
||||
slots: list[PlanningSlot],
|
||||
battery: SimpleNamespace,
|
||||
current_soc_wh: float,
|
||||
*,
|
||||
purchase_pricing_mode: str = "spot",
|
||||
) -> set[int]:
|
||||
"""Kopie logiky z ems.fn_load_planning_slots_full (charge mask)."""
|
||||
charge_buf = float(getattr(battery, "charge_slot_buffer", 0) or 0)
|
||||
@@ -72,6 +74,10 @@ def _select_charge_slots(
|
||||
selected.add(t)
|
||||
cum += min(pv_surplus_w, max_p_w) * eta * INTERVAL_H
|
||||
|
||||
# B) Non-PV grid charge — jen spot nákup (u fixed je buy všude stejný → jen FVE)
|
||||
if purchase_pricing_mode == "fixed":
|
||||
return selected
|
||||
|
||||
# B) Non-PV: AM budget (OTE-first)
|
||||
am_candidates = [
|
||||
(t, getattr(slots[t], "is_predicted_price", False), float(slots[t].buy_price))
|
||||
@@ -112,6 +118,8 @@ def _select_discharge_export_slots(
|
||||
battery: SimpleNamespace,
|
||||
current_soc_wh: float,
|
||||
charge_slots: set[int] | None = None,
|
||||
*,
|
||||
purchase_pricing_mode: str = "spot",
|
||||
) -> set[int]:
|
||||
"""Kopie logiky z ems.fn_load_planning_slots_full (discharge-export mask)."""
|
||||
discharge_buf = float(getattr(battery, "discharge_slot_buffer", 0) or 0)
|
||||
@@ -138,10 +146,14 @@ def _select_discharge_export_slots(
|
||||
default=min(float(s.buy_price) for s in slots),
|
||||
)
|
||||
|
||||
if purchase_pricing_mode == "fixed":
|
||||
sell_min = degrad
|
||||
else:
|
||||
sell_min = ref_buy + degrad
|
||||
candidates = [
|
||||
(t, float(slots[t].sell_price))
|
||||
for t in range(len(slots))
|
||||
if float(slots[t].sell_price) > ref_buy + degrad
|
||||
if float(slots[t].sell_price) > sell_min
|
||||
]
|
||||
candidates.sort(key=lambda x: (-x[1], -x[0]))
|
||||
|
||||
@@ -330,5 +342,39 @@ class SelectDischargeExportSlotsTests(unittest.TestCase):
|
||||
self.assertNotIn(1, discharge, "sell 0.5 < ref 0.4 + 0.15")
|
||||
|
||||
|
||||
class FixedPurchasePricingTests(unittest.TestCase):
|
||||
"""purchase_pricing_mode=fixed: žádné grid CHARGE, export dle sell."""
|
||||
|
||||
def test_fixed_skips_non_pv_grid_charge_slots(self) -> None:
|
||||
slots = [
|
||||
_slot(buy=6.35, sell=2.0, hour_utc=14, load=500),
|
||||
_slot(buy=6.35, sell=3.5, hour_utc=18, load=500),
|
||||
]
|
||||
battery = _battery(charge_buf=1.3, uc_wh=12_500.0)
|
||||
out = _select_charge_slots(
|
||||
slots,
|
||||
battery,
|
||||
current_soc_wh=0.4 * battery.usable_capacity_wh,
|
||||
purchase_pricing_mode="fixed",
|
||||
)
|
||||
self.assertEqual(out, set(), "fixed buy must not enable non-PV grid charge")
|
||||
|
||||
def test_fixed_allows_discharge_on_high_sell(self) -> None:
|
||||
slots = [
|
||||
_slot(buy=6.35, sell=1.0, hour_utc=10),
|
||||
_slot(buy=6.35, sell=3.8, hour_utc=18),
|
||||
_slot(buy=6.35, sell=3.2, hour_utc=19),
|
||||
]
|
||||
battery = _battery(uc_wh=12_500.0, discharge_buf=2.0, degrad=0.3)
|
||||
discharge = _select_discharge_export_slots(
|
||||
slots,
|
||||
battery,
|
||||
current_soc_wh=0.5 * battery.usable_capacity_wh,
|
||||
purchase_pricing_mode="fixed",
|
||||
)
|
||||
self.assertIn(1, discharge)
|
||||
self.assertIn(2, discharge)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user