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.ltd → API 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 forscipy.optimize.minimizeeoil.adapters.sklearn—EOILSearchCVreplacesGridSearchCV/RandomizedSearchCVeoil.adapters.pytorch—EOILOptimizerfornn.Moduletraining loopseoil.adapters.pandas—EOILPortfolioOptimizerfor portfolio optimisation onpd.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)
| File | Size | Uploaded | |
|---|---|---|---|
| eoil-0.5.2.tar.gz | 47.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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