Skip to main content

EOIL Python SDK

Python client for the EOIL optimisation API.

Version: 0.5.2 — beta. API is stable.

Installation

pip install eoil

Requires Python ≥ 3.10. NumPy is optional but recommended — the SDK passes np.ndarray to your objective function when it's installed, otherwise list[float].

Authentication

Get an API key from app.eoil.ltdAPI Keys.

import eoil

client = eoil.Client(api_key="eoil_sk_...")

# Or set the environment variable EOIL_API_KEY and omit api_key=

1. Custom objective functions (stream_optimize)

Run your own Python function against the EOIL optimizer. Your code never leaves your machine — only candidate coordinate vectors and scalar values cross the network.

def rosenbrock(x):
    # x is np.ndarray (if numpy installed) or list[float]
    f = (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2
    grad = [
        -2*(1 - x[0]) - 400*x[0]*(x[1] - x[0]**2),
        200*(x[1] - x[0]**2),
    ]
    return f, grad   # return (f, grad) to supply gradient directly

result = client.stream_optimize(
    rosenbrock,
    dimension=2,
    budget_steps=500,
    bounds=(-5.0, 5.0),
)

print(result.x_best)       # [1.0, 1.0]        best solution found
print(result.f_best)       # ~0.0              best objective value
print(result.converged)    # True / False
print(result.steps)        # int               evaluations consumed
print(result.eoil_charged) # "5.0"             compute units charged

Gradient options

gradient= Behaviour
"auto" (default) Inspect return type on first call — tuple → use grad; scalar → finite differences
True Function must return (f, grad). Raises StreamError if it returns a scalar.
False Always use finite differences, even if function returns a tuple.

When finite differences are used, the SDK prints a one-time warning and costs 2 × dimension extra function calls per step. Supply an analytic gradient to avoid this.

Live progress

def on_step(step, x, f_best):
    if f_best is not None:
        print(f"step {step:4d} | f_best={f_best:.6f}")

result = client.stream_optimize(
    my_fn,
    dimension=10,
    budget_steps=1000,
    on_step=on_step,
)

All parameters

Parameter Default Description
fn required Objective function. Returns float or (float, list[float]).
dimension required Problem dimensionality (1–1000).
budget_steps 1000 Approximate number of function evaluations (100–100 000).
bounds (-5.0, 5.0) Box bounds (lower, upper) applied uniformly.
x0 None Initial point. Server picks randomly if omitted.
gradient "auto" Gradient supply mode — see table above.
fd_step 1e-5 Finite-difference step size.
on_step None Callback on_step(step, x, f_best) called after each evaluation.
timeout_s 3600.0 Total session wall-clock timeout in seconds.
eval_timeout_s 80.0 Per-evaluation timeout. Raises if function exceeds this.
verify_ssl True Set False for staging or self-signed certs.

2. Catalogue (client.catalogue)

Run built-in optimisation problems — no objective function needed.

Benchmark functions

result = client.catalogue.rastrigin(dimension=20, budget_steps=1000)
result = client.catalogue.sphere(dimension=10, budget_steps=500)
result = client.catalogue.rosenbrock(dimension=15, budget_steps=2000)
result = client.catalogue.ackley(dimension=10, budget_steps=1000)
result = client.catalogue.levy(dimension=10, budget_steps=1000)
result = client.catalogue.griewank(dimension=10, budget_steps=1000)
result = client.catalogue.quadratic(dimension=10, budget_steps=1000)

Portfolio optimisation

import numpy as np

# Maximise Sharpe ratio — pass a (T × N) returns matrix
returns = np.random.randn(252, 5) * 0.01  # 252 trading days, 5 assets
result = client.catalogue.portfolio_sharpe(
    returns=returns,
    dimension=5,
    budget_steps=2000,
)
weights = result.x_best  # portfolio weights, sum to 1

# Minimise portfolio variance — pass an (N × N) covariance matrix
cov = np.cov(returns.T)
result = client.catalogue.portfolio_minvol(
    cov=cov,
    dimension=5,
    budget_steps=2000,
)

Plain Python nested lists are accepted wherever NumPy arrays are shown.

Available catalogue methods

Method Description
catalogue.sphere() Convex, global min at origin
catalogue.rastrigin() Highly multimodal
catalogue.rosenbrock() Narrow curved valley
catalogue.quadratic() Coupled quadratic (ill-conditioned)
catalogue.ackley() Many local minima
catalogue.levy() Global min at x=(1,…,1)
catalogue.griewank() Regularly spaced local minima
catalogue.portfolio_sharpe() Maximise Sharpe ratio
catalogue.portfolio_minvol() Minimise portfolio variance

3. Optimizer presets

Presets are heuristics_override dicts tuned for common scenarios.

from eoil import PRESETS, get_preset

result = client.catalogue.rastrigin(
    dimension=50,
    budget_steps=5000,
    heuristics_override=PRESETS["thorough"],
)

# get_preset() returns a copy — safe to modify
opts = get_preset("portfolio")
opts["escape_strength"] = 0.8
result = client.catalogue.portfolio_sharpe(
    returns=returns,
    dimension=5,
    budget_steps=3000,
    heuristics_override=opts,
)
Preset Best for
fast CI checks and quick feasibility runs
balanced General-purpose (default)
thorough Production-quality results
portfolio Sharpe ratio and minimum-variance problems
ml_hyperparam Machine learning hyperparameter search
high_dimensional Problems with dimension ≥ 100

4. Async job submission

# Submit and get a job ID immediately
job_id = client.submit_job(objective_type="ackley", dimension=20)

# Retrieve the result later (polling)
result = client.get_job(job_id)

5. Result object

Both stream_optimize() and catalogue methods return a result object with these fields:

Field Alias Description
x_best .x Best solution vector found
f_best .f Best objective value
converged Whether the optimizer declared convergence
total_steps .steps Evaluations consumed
eoil_charged Compute units charged (stream_optimize only)

6. Error handling

from eoil import (
    AuthError,
    InsufficientBalanceError,
    RateLimitError,
    StreamError,
    SessionExpiredError,
    EoilError,
)

try:
    result = client.stream_optimize(my_fn, dimension=10, budget_steps=500)
except AuthError:
    print("Invalid or missing API key — check app.eoil.ltd → API Keys")
except InsufficientBalanceError:
    print("Insufficient compute balance")
except RateLimitError:
    print("Rate limit hit — retry shortly")
except SessionExpiredError:
    print("Session expired — try again")
except StreamError as e:
    print(f"Stream error [{e.code}]: {e}")
except EoilError as e:
    print(f"API error: {e}")

What's New in 0.5.0

  • eoil.adapters.scipy — drop-in replacement for scipy.optimize.minimize
  • eoil.adapters.sklearnEOILSearchCV replaces GridSearchCV / RandomizedSearchCV
  • eoil.adapters.pytorchEOILOptimizer for nn.Module training loops
  • eoil.adapters.pandasEOILPortfolioOptimizer for portfolio optimisation on pd.DataFrame
  • Promoted to Beta — all adapters tested against production API

Development

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

# Run tests (no API key needed — HTTP and WebSocket are mocked)
pytest tests/ -v

Links

Release files for eoil 0.5.2

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

Source distribution (sdist)

Source distribution for eoil 0.5.2
File Size Uploaded
eoil-0.5.2.tar.gz 47.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for eoil 0.5.2
File Interpreter ABI Platform
eoil-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 82.9 kB

Release files / eoil-0.5.2.tar.gz

Download URL eoil-0.5.2.tar.gz
Size 47.3 kB
Tags Source
SHA-256 checksum
How to use checksums
8fc50c3e1a4a7b90f221c02e5dd2565401d47d03a7528fd841366e63a9310f88
BLAKE2b-256 checksum
How to use checksums
b4044ae1f8128616e403a6450452dabe77d26dc2cfdc5813bb38cfdfdf31ce9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 13, 2026.

Transparency log

Release files / eoil-0.5.2-py3-none-any.whl

Download URL eoil-0.5.2-py3-none-any.whl
Size 35.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
274664413b244eec0489d978b624b32870f0fe28ff8f4155982c145627628e98
BLAKE2b-256 checksum
How to use checksums
b7afebb84a3a75fc259a8323da21a183fea42b3d4fcbb4dabf86b17e294cc202
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 Jun 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.2 This release

2 release files

0.5.1

2 release files

0.5.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