Skip to main content

Site-Calc Investment Client

Python client for Site-Calc investment planning API - long-term capacity planning and ROI analysis.

Installation

pip install site-calc-investment

Service compatibility

Client 1.5.5 requires server 1.5.3 with timezone capability support. It adds named planning timezones, DST-safe elapsed arithmetic and civil-day helpers, explicit fixed/calendar-year helpers, optional result timezone metadata, and service failure messages. See the timezone contract and historical limitations, and follow the migration guide. Submissions require /health to advertise features: ["planning_timezone"]; unsupported or unavailable health blocks the POST with an actionable error. Existing job/status reads remain available. The check reuses the existing cached health request; recreate the client after a service upgrade or health repair.

After the service is upgraded and advertises the capability:

pip install "site-calc-investment==1.5.5"

Legacy deployment (2026-09-11)

Historical calendar limitation: client 1.5.4 and the service deployed 2026-09-11 do not preserve the named Prague planning zone end to end. Local tariff months and monthly SOC boundaries can disagree; a ten-year explicit-decomposition job failed on this mismatch. Read Planning timezones, including the DST helper limitations, before relying on multi-month calendar behavior.

Use site-calc-investment 1.5.4 with the investment service release deployed on 2026-09-11. That service reports API 1.5 and server 1.5.2 at /health. Earlier server 1.5.2 builds predate the strategy controls, so the version number alone does not establish support; confirm the deployed release with your service operator when using another installation.

Client Compatibility with the 2026-09-11 investment service
1.5.4 Full Python/MCP strategy and SOC-policy controls, absolute/relative tolerances, and result certificates.
1.5.3 Existing planning, polling, results, and cancellation APIs remain available; upgrade for the new controls and typed certificate fields.

Jobs remain asynchronous. Unspecified options follow the service's defaults, including its monthly-fixed SOC policy; use the explicit controls in 1.5.4 when you need a particular policy. New response fields are optional when reading results from older services, but older services may not implement new request options. Match client and service API MAJOR.MINOR versions and confirm feature support before requesting decomposition on an older deployment.

pip install "site-calc-investment==1.5.4"

Quick Start

from datetime import datetime
from zoneinfo import ZoneInfo
from site_calc_investment import InvestmentClient
from site_calc_investment.models import (
    Resolution,
    Site,
    Battery,
    ElectricityImport,
    ElectricityExport,
    InvestmentPlanningRequest,
    InvestmentParameters,
    OptimizationConfig,
)
from site_calc_investment.models.requests import TimeSpanInvestment

# Initialize client
client = InvestmentClient(base_url="https://api.site-calc.example.com", api_key="inv_your_api_key_here")

# Create 1-week planning horizon (1-hour resolution)
timespan = TimeSpanInvestment(
    start=datetime(2025, 1, 1, tzinfo=ZoneInfo("Europe/Prague")),
    intervals=168,  # 1 week = 7 days × 24 hours
    resolution=Resolution.HOUR_1,
)

# Generate hourly prices (example: day/night pattern)
prices = [30.0 if h % 24 < 6 else 80.0 if 8 <= h % 24 < 20 else 50.0 for h in range(168)]

# Define devices (NO ancillary_services field)
battery = Battery(
    name="Battery1",
    properties={"capacity": 10.0, "max_power": 5.0, "efficiency": 0.90, "initial_soc": 0.5},
    investment={"capital_cost": 500000, "annual_opex": 5000},  # For client-side NPV
)

grid_import = ElectricityImport(name="GridImport", properties={"price": prices, "max_import": 10.0})

grid_export = ElectricityExport(name="GridExport", properties={"price": prices, "max_export": 10.0})

site = Site(site_id="investment_site", devices=[battery, grid_import, grid_export])

# Global investment parameters (per-device costs live on the devices)
inv_params = InvestmentParameters(
    discount_rate=0.05,
    project_lifetime_years=10,  # Required field
)

# Create and submit optimization request
request = InvestmentPlanningRequest(
    sites=[site],
    timespan=timespan,
    investment_parameters=inv_params,
    optimization_config=OptimizationConfig(
        objective="maximize_profit",  # Options: maximize_profit, minimize_cost, maximize_self_consumption
        time_limit_seconds=300,  # Max 3600 seconds (60 min)
    ),
)

job = client.create_planning_job(request)
result = client.wait_for_completion(job.job_id, poll_interval=5, timeout=600)

print(f"Status: {result.status}")
print(f"Solver: {result.summary.solver_status}")  # "Optimal", or "Feasible" when the time limit cut the solve short
print(f"Profit: €{result.summary.expected_profit:,.2f}")
if result.summary.is_optimal is False:  # "is False", not "not ...": None means an older service that does not report it
    # Best plan found so far; optimality_gap says how far it may be from the true optimum
    print(f"Stopped early ({result.summary.termination_reason}), relative gap {result.summary.optimality_gap}")

Optional OptimizationConfig fields select strategy, absolute or relative tolerance (abs_gap / mip_gap), and soc_boundary_policy. For decomposed, auto, or an omitted strategy, abs_gap defaults to 100 EUR and must be at least 1 EUR. Explicit monolithic keeps optional nonnegative tolerances. Pass mip_gap=0.01 to also request a 1% relative tolerance; satisfying either criterion can establish optimality. The monthly_fixed policy fixes month-end and terminal SOC to half the installed energy capacity, including on monolithic fallback. See strategy, bounds, and model-policy behavior before choosing a policy or interpreting nullable result bounds.

Features

  • ✅ Long-term capacity planning (1-10 years)
  • ✅ Investment ROI analysis (NPV, IRR, payback)
  • ✅ Per-device investment costs (capital_cost / annual_opex) for client-side NPV
  • ✅ Capacity reservations: per-period capacity limits and charges with automatic cheapest-tariff assignment
  • ✅ BESS investment sizing: optimizer-sized battery power (MW) and energy capacity (MWh)
  • ✅ Czech distribution-tariff import device (monthly T1/T2 capacity tariff, 2027 structure)
  • ✅ Scenario comparison utilities
  • ✅ Financial analysis helpers
  • ✅ 1-hour resolution optimization
  • ✅ Multi-site optimization
  • ✅ Type-safe Pydantic models
  • ✅ Automatic retry and error handling
  • ✅ Job management (cancel single or all jobs)

Capabilities

Feature Value
Max Horizon 100,000 intervals (~11 years at 1-hour)
Resolution 1-hour only
ANS Support No
Binary Variables Relaxed to continuous
Timeout 3600 seconds (60 minutes) max

Supported Devices

  • Battery (NO ANS; optional power_sizing / capacity_sizing reservations let the optimizer size installed MW / MWh)
  • CHP - Combined Heat and Power (continuous operation)
  • Heat Accumulator
  • Photovoltaic: photovoltaic_nonsteerable (exact profile) / photovoltaic_steerable (curtailable up to a max-power profile)
  • Fixed Production / Fixed Consumption (follow a power profile exactly)
  • Max-Power Production / Consumption (steerable in [0, max] at a linear EUR/MWh cost or value)
  • Heat Demand
  • Electricity Demand
  • Electricity Import/Export (market interface; optional capacity_reservation for per-period grid capacity tariffs)
  • Czech Distribution Import (cz_distribution_import: electricity import billed under the Czech monthly T1/T2 capacity tariff)
  • Import with Overflow (electricity_import_with_overflow: net-metered grid connection, consumption billed at the import price and the surplus paid at the overflow price; either importing or exporting in any hour, never both)
  • Gas Import (market interface)
  • Heat Export (market interface)

Every device also accepts an optional investment block ({"capital_cost": EUR, "annual_opex": EUR/year}) used only for client-side NPV/IRR analysis -- it is stripped from the API payload.

Job Management

The client provides methods for managing optimization jobs:

# Create a job
job = client.create_planning_job(request)
print(f"Job ID: {job.job_id}")

# Check job status
status = client.get_job_status(job.job_id)
print(f"Status: {status.status}, Progress: {status.progress}%")

# Wait for completion
result = client.wait_for_completion(job.job_id, poll_interval=30, timeout=7200)

# Cancel a single job
cancelled = client.cancel_job(job.job_id)

# Cancel all pending/running jobs (bulk cancel)
result = client.cancel_all_jobs()
print(f"Cancelled {result['cancelled_count']} jobs")

Financial Analysis

from site_calc_investment.analysis import (
    calculate_investment_metrics,
    calculate_npv,
    calculate_irr,
    calculate_payback_period,
    compare_scenarios,
)

# All-in-one: NPV/IRR/payback from annual aggregates + device investment blocks
metrics = calculate_investment_metrics(
    annual_revenues=result.investment_metrics.annual_revenue_by_year,
    annual_costs=result.investment_metrics.annual_costs_by_year,  # already includes capacity-reservation charges
    discount_rate=0.05,
    devices=site.devices,
)
print(metrics["npv"], metrics["irr"], metrics["payback_period_years"])

# NPV calculation
npv = calculate_npv(cash_flows=annual_revenues, discount_rate=0.05, initial_investment=-1500000)

# IRR calculation
irr = calculate_irr([-1500000] + annual_revenues)

# Scenario comparison
comparison = compare_scenarios([result_5mw, result_10mw, result_15mw], names=["5 MW", "10 MW", "15 MW"])
print(comparison)  # DataFrame with NPV, IRR, costs, revenues

MCP Server (LLM Integration)

The package includes an MCP server for use with Claude Desktop, ChatGPT, and other MCP-compatible LLM tools.

Installation

pip install site-calc-investment[mcp]

Claude Desktop Configuration

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "site-calc-investment": {
      "command": "uvx",
      "args": ["--from", "site-calc-investment[mcp]", "site-calc-investment-mcp"],
      "env": {
        "INVESTMENT_API_URL": "http://your-api-url",
        "INVESTMENT_API_KEY": "inv_your_key_here",
        "INVESTMENT_DATA_DIR": "/path/to/data/directory"
      }
    }
  }
}

For local development against a source checkout, use uv run --directory instead:

{
  "mcpServers": {
    "site-calc-investment": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/client-investment", "site-calc-investment-mcp"],
      "env": {
        "INVESTMENT_API_URL": "http://your-api-url",
        "INVESTMENT_API_KEY": "inv_your_key_here",
        "INVESTMENT_DATA_DIR": "/path/to/data/directory"
      }
    }
  }
}

ChatGPT Configuration

ChatGPT supports MCP via streaming HTTP or SSE (stdio is not supported). This requires:

  • An eligible ChatGPT plan with Developer Mode access (Pro, Plus, Business, Enterprise, or Education). Business plan restricts Developer Mode to admins/owners; other plans may have similar admin gating.
  • Developer Mode enabled (navigate to Settings -- the exact path may vary by account type)

Step 1 -- Start the MCP server in HTTP mode:

cd /path/to/client-investment
INVESTMENT_API_URL="http://your-api-url" \
INVESTMENT_API_KEY="inv_your_key_here" \
INVESTMENT_DATA_DIR="/path/to/data" \
uv run fastmcp run site_calc_investment.mcp.server:mcp --transport http --port 8000

Step 2 -- Expose to the internet (for local development):

ngrok http 8000

For production, deploy the server to a publicly accessible host instead.

Step 3 -- Add to ChatGPT:

  1. Open ChatGPT Settings > Apps & Connectors (or Connectors) > Advanced settings > Enable Developer Mode
  2. Click Create app
  3. Enter the ngrok HTTPS URL (e.g. https://abc123.ngrok.io/mcp) as the server endpoint
  4. Name: "Site-Calc Investment", Description: "Investment planning optimization tools"
  5. Click Refresh to load the tool list

Note: ChatGPT shows tool call details and may require manual confirmation for actions. The save_data_file tool requires the server to have local filesystem access.

Tools (17)

Tool Description
get_version Get server and package version info
create_scenario Create a new draft scenario
add_device Add a device (battery, CHP, PV, etc.), optionally with an investment cost block
set_timespan Set optimization time horizon
set_investment_params Set global financial parameters (discount rate, project lifetime)
review_scenario Review scenario before submission
remove_device Remove a device
delete_scenario Delete a scenario
list_scenarios List all draft scenarios
submit_scenario Submit for optimization
get_job_status Check job progress
get_job_result Get optimization results (incl. capacity reservation summaries)
cancel_job Cancel a job
list_jobs List all jobs
get_device_schema Get device property schema
save_data_file Save generated data as CSV
fetch_url Download a file (e.g. CSV price data) from a URL

save_data_file lets the LLM write generated data (price arrays, demand profiles) to local CSV files, which can then be referenced in add_device properties.

See docs/MCP_SERVER_SPEC.md for full specification.

Documentation

Full documentation available at: https://github.com/stranma/site-calc-investment#readme

Examples

See examples/ directory for complete examples:

  • 01_basic_capacity_planning.py - one-week battery capacity planning workflow
  • 02_scenario_comparison.py - compare device configurations
  • 03_financial_analysis.py - investment ROI calculation
  • 04_import_with_overflow.py - net-metered import with overflow: the device, a hand-built pairing, and why it matters

Requirements

  • Python ≥ 3.10
  • API key with inv_ prefix (investment client)

Key Differences from Operational Client

  • ❌ No /optimal-bidding endpoint
  • ❌ No ancillary_services on devices
  • ❌ No 15-minute resolution (1-hour only)
  • ✅ Up to 100,000 intervals (vs. 296)
  • ✅ Investment metrics (NPV, IRR, payback)
  • ✅ Financial analysis helpers

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Format code
ruff format .

# Type check
mypy site_calc_investment

License

MIT License

Support


Part of the Site-Calc platform.

Metadata

Release files for site-calc-investment 1.5.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for site-calc-investment 1.5.5
File Size Uploaded
site_calc_investment-1.5.5.tar.gz 296.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for site-calc-investment 1.5.5
File Interpreter ABI Platform
site_calc_investment-1.5.5-py3-none-any.whl Python 3 none any Details

Total release size: 361.5 kB

Release files / site_calc_investment-1.5.5.tar.gz

Download URL site_calc_investment-1.5.5.tar.gz
Size 296.3 kB
Tags Source
SHA-256 checksum
How to use checksums
9ac8d360b7221874113037a720121a2be5a0ca6f183b3bfc50d3c45d0a921aa6
BLAKE2b-256 checksum
How to use checksums
55ad58ec540707796dac85d226e0cdb8a5a225599b4f09a38c592758cc507089
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release files / site_calc_investment-1.5.5-py3-none-any.whl

Download URL site_calc_investment-1.5.5-py3-none-any.whl
Size 65.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dbea03c64e961f292590a0b83e38986ab8336245532216a8b7ef253bd77da023
BLAKE2b-256 checksum
How to use checksums
2a724d1bb460078026cf95bae1ca942b24eeb57962adc157f1ff71c7258ec7cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.5.5 This release

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.9

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page