M6-T03: add pricing profile framework + strategy registry

- app/integrations/pricing: profiles.py (pydantic ManualProfile/TibberProfile,
  load_profile/list_profiles/validate_values), manual.yaml + tibber.yaml
  (structure-only, no price values), strategies.py (register/get_strategy,
  manual dual-tariff + tibber strategies, all Decimal).
- tibber strategy matches nearest tibber_price with starts_at <= t0.
- tests for profiles + strategies (hand-checked dual-tariff & tibber math).
This commit is contained in:
2026-06-23 20:58:34 +02:00
parent df54f5518b
commit bedea196c3
8 changed files with 1695 additions and 1 deletions
@@ -0,0 +1,20 @@
kind: manual
label: 固定 / 可变费率(NL,双费率)
energy:
dual_tariff: true # use delivered_1/2, returned_1/2 for low/high tariffs
buy:
normal: { unit: EUR/kWh } # high-tariff buy price (delivered_2 register)
dal: { unit: EUR/kWh } # low-tariff buy price (delivered_1 register)
sell:
normal: { unit: EUR/kWh } # high-tariff sell / return price
dal: { unit: EUR/kWh } # low-tariff sell / return price (currently equal to normal)
energy_tax: { unit: EUR/kWh } # energy tax added to buy price (incl. VAT)
ode: { unit: EUR/kWh, default: 0 } # currently merged into energy_tax
standing: # fixed charges; UI fills per month, engine prorates to days
network_fee: { unit: EUR/month }
management_fee: { unit: EUR/month }
credits:
heffingskorting: { unit: EUR/year } # energy-tax credit; deducted at summary layer
@@ -0,0 +1,14 @@
kind: tibber
label: Tibber 动态电价(15 分钟)
energy:
source: tibber_api # buy = total (from API); sell = total energy_tax sell_adjust
energy_tax: { unit: EUR/kWh } # subtracted from total to derive sell price (incl. VAT)
sell_adjust: { unit: EUR/kWh, default: 0 } # additional sell-price adjustment (residual spread)
standing: # fixed charges; UI fills per month, engine prorates to days
management_fee: { unit: EUR/month, default: 5.99 }
network_fee: { unit: EUR/month }
credits:
heffingskorting: { unit: EUR/year } # energy-tax credit; deducted at summary layer