build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
3cb90bff00
commit
73e3c70b42
|
|
@ -40,3 +40,9 @@ Enhancements plan (ELAC-Plan MVP refinement)
|
|||
- Security and privacy: TEEs/hardware attestation for edge solvers; secure aggregation; possible zk-proofs
|
||||
- Testing and metrics: latency, convergence, data-sharing volume, and governance auditability coverage
|
||||
- Artifacts: draft DSL sketch (LocalProblem/SharedVariables/PlanDelta/DualVariables/AuditLog), toy adapters, minimal transport spec, RFC for registry surface
|
||||
## ELAC-Plan Architectural Rules
|
||||
- The repository now includes a Python MVP for ELAC-Plan with a FastAPI app at `src/edge_latency_aware_cross_venue_execution/api/app.py`.
|
||||
- Core primitives are defined in `src/edge_latency_aware_cross_venue_execution/models.py` (LocalProblem, SharedVariables, PlanDelta, DualVariables, AuditLog).
|
||||
- A toy solver is provided in `src/edge_latency_aware_cross_venue_execution/solver.py`.
|
||||
- A minimal API exposes `/problems` (POST) and `/status` (GET) to exercise the MVP flows.
|
||||
- Tests can be run via `bash test.sh` which executes pytest and a package build.
|
||||
|
|
|
|||
45
README.md
45
README.md
|
|
@ -1,27 +1,28 @@
|
|||
# ELAC-Plan (Edge-Latency Aware Cross-Venue Execution Planner)
|
||||
# ELAC-Plan: Edge-Latency Aware Cross-Venue Execution Planner
|
||||
|
||||
This repository implements a production-oriented MVP of ELAC-Plan: an edge-native federation for cross-venue execution planning with privacy-preserving signals and deterministic delta-sync.
|
||||
ELAC-Plan is an open-source platform prototype for generating cross-venue execution plans locally near exchanges. It emphasizes latency reduction, data privacy, and deterministic replay/auditability via a canonical primitive set and a lightweight federation protocol.
|
||||
|
||||
- Primitives map to canonical primitives used across adapters:
|
||||
- Objects: LocalProblem
|
||||
- Morphisms: SharedVariables
|
||||
- DualVariables: DualVariables
|
||||
- PlanDelta: PlanDelta
|
||||
- Governance/AuditLog: GovernanceAuditLog (stubbed for now)
|
||||
- MVP adapters:
|
||||
- NBBOFeedAdapter: translates NBBO-like feeds into SharedVariables
|
||||
- BrokerGatewayAdapter: simulates broker API publishing of PlanDelta
|
||||
- Solver: LocalSolver (toy solver)
|
||||
- API: FastAPI app exposing /problems and /status to drive LocalProblem -> PlanDelta flow
|
||||
- Packaging: Python packaging metadata in pyproject.toml; tests with pytest; build via python -m build
|
||||
This repository implements a production-ready MVP skeleton in Python with a FastAPI API, in-memory storage, and a minimal LocalProblem/SharedVariables/PlanDelta model suite. It is designed to be extended with additional adapters, governance primitives, and a richer solver over time.
|
||||
|
||||
How to run (dev):
|
||||
- Run tests: ./test.sh
|
||||
- Run API locally (example): uvicorn elac_plan.api:app --reload
|
||||
Key primitives (canonical IR):
|
||||
- LocalProblem (Objects): per-asset, per-venue optimization task definitions
|
||||
- SharedVariables (Morphisms): privacy-bounded summarized signals
|
||||
- DualVariables: cross-venue coupling signals
|
||||
- PlanDelta: incremental plan updates with metadata and cryptographic tags
|
||||
- AuditLog: governance and provenance blocks
|
||||
|
||||
This is a minimal but production-conscious MVP intended to be extended by adding governance ledger, secure aggregation, and real adapters in subsequent iterations.
|
||||
Architecture overview
|
||||
- API: FastAPI app exposing /problems and /status (and delta reconciliation in future)
|
||||
- In-memory storage with deterministic replay hooks
|
||||
- Lightweight solver: generates PlanDelta from LocalProblem
|
||||
- Adapters: translate market feeds and broker APIs into the ELAC canonical representation
|
||||
|
||||
Interop and roadmap
|
||||
- See docs/elac_plan_interop.md for a minimal DSL sketch and EnergiBridge-style interoperability planning (LocalProblem/SharedVariables/PlanDelta/DualVariables/AuditLog).
|
||||
- The MVP already includes two adapters (NBBOFeedAdapter and BrokerGatewayAdapter) and a toy LocalSolver for end-to-end delta-sync.
|
||||
- The plan includes phases for governance, secure aggregation, cross-venue demos, and HIL testing; reference SDK and sample DSL are provided for integration with other domains.
|
||||
How to run
|
||||
- Install: python3 -m pip install -e .
|
||||
- Run API (example): uvicorn elac_plan.api.app:app --reload --port 8000
|
||||
- Tests: bash test.sh
|
||||
|
||||
Contributing
|
||||
- See AGENTS.md for contribution rules and how to run tests locally.
|
||||
|
||||
This is an early MVP; feedback and contributions are welcome.
|
||||
|
|
|
|||
|
|
@ -1,24 +1,19 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=61.0", "wheel"]
|
||||
requires = ["setuptools>=42", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "edge_latency_aware_cross_venue_execution"
|
||||
version = "0.1.0"
|
||||
description = "ELAC-Plan MVP: edge-native cross-venue execution planning with privacy-preserving federation."
|
||||
description = "Edge-Latency Aware Cross-Venue Execution Planner (ELAC-Plan) core MVP"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
license = {text = "MIT"}
|
||||
authors = [ { name = "OpenCode" } ]
|
||||
dependencies = [
|
||||
"fastapi>=0.95.0",
|
||||
"uvicorn[standard]",
|
||||
"pydantic>=1.10",
|
||||
"typing-extensions>=4.3",
|
||||
"cryptography>=3.3",
|
||||
"pytest>=7.0",
|
||||
"httpx>=0.23"
|
||||
]
|
||||
authors = [{name = "OpenCode", email = "devnull@example.com"}]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["elac_plan"]
|
||||
where = ["src"]
|
||||
include = ["edge_latency_aware_cross_venue_execution*"]
|
||||
|
||||
[project.urls]
|
||||
Home = "https://example.com/elac-plan"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="edge_latency_aware_cross_venue_execution",
|
||||
version="0.1.0",
|
||||
description="ELAC-Plan MVP: edge-native cross-venue execution planner",
|
||||
packages=find_packages(where="src"),
|
||||
package_dir={"": "src"},
|
||||
include_package_data=True,
|
||||
python_requires=">=3.8",
|
||||
install_requires=["fastapi>=0.95.0", "pydantic>=1.10.0", "uvicorn[standard]>=0.18.0"],
|
||||
)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
"""ELAC-Plan core package initializer"""
|
||||
|
||||
from .models import LocalProblem, SharedVariables, PlanDelta, DualVariables, AuditLog
|
||||
from .solver import LocalSolver
|
||||
from .api.app import app # re-export FastAPI app for convenience
|
||||
|
||||
__all__ = [
|
||||
"LocalProblem",
|
||||
"SharedVariables",
|
||||
"PlanDelta",
|
||||
"DualVariables",
|
||||
"AuditLog",
|
||||
"LocalSolver",
|
||||
"app",
|
||||
]
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import List
|
||||
from datetime import datetime
|
||||
|
||||
from ..models import LocalProblem, PlanDelta
|
||||
from ..solver import LocalSolver
|
||||
|
||||
app = FastAPI(title="ELAC-Plan API")
|
||||
|
||||
_solver = LocalSolver()
|
||||
_problems: dict[str, LocalProblem] = {}
|
||||
_deltas: List[PlanDelta] = []
|
||||
|
||||
|
||||
class ProblemCreate(BaseModel):
|
||||
id: str
|
||||
asset: str
|
||||
venue: str
|
||||
objective: str | None = None
|
||||
parameters: dict | None = None
|
||||
|
||||
|
||||
class DeltaOut(BaseModel):
|
||||
contract_id: str
|
||||
delta: dict
|
||||
timestamp: datetime
|
||||
|
||||
|
||||
@app.post("/problems", response_model=DeltaOut)
|
||||
def create_problem(p: ProblemCreate):
|
||||
if p.id in _problems:
|
||||
raise HTTPException(status_code=400, detail="Problem with this id already exists")
|
||||
problem = LocalProblem(
|
||||
id=p.id,
|
||||
asset=p.asset,
|
||||
venue=p.venue,
|
||||
objective=p.objective or "min_spread",
|
||||
parameters=p.parameters or {},
|
||||
)
|
||||
_problems[p.id] = problem
|
||||
delta = _solver.solve(problem)
|
||||
_deltas.append(delta)
|
||||
return DeltaOut(contract_id=delta.contract_id, delta=delta.delta, timestamp=delta.timestamp)
|
||||
|
||||
|
||||
@app.get("/status")
|
||||
def status():
|
||||
return {
|
||||
"problems_count": len(_problems),
|
||||
"deltas_count": len(_deltas),
|
||||
"last_delta_timestamp": _deltas[-1].timestamp if _deltas else None,
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
from __future__ import annotations
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LocalProblem(BaseModel):
|
||||
id: str = Field(..., description="Unique problem identifier")
|
||||
asset: str
|
||||
venue: str
|
||||
objective: str = Field("min_spread", description="High-level objective tag")
|
||||
parameters: Optional[dict] = Field(default_factory=dict)
|
||||
price_target: Optional[float] = None
|
||||
tolerance: Optional[float] = None
|
||||
constraints: Optional[dict] = None
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
|
||||
class SharedVariables(BaseModel):
|
||||
contract_id: str
|
||||
version: int
|
||||
signals: dict | None = None
|
||||
variables: dict | None = None
|
||||
privacy_budget: Optional[float] = 0.0
|
||||
|
||||
|
||||
class DualVariables(BaseModel):
|
||||
contract_id: str = ""
|
||||
version: int
|
||||
shadow_prices: dict
|
||||
|
||||
|
||||
class PlanDelta(BaseModel):
|
||||
contract_id: Optional[str] = None
|
||||
delta: dict
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
author_signature: Optional[str] = None
|
||||
author: Optional[str] = None
|
||||
|
||||
def to_json(self) -> str:
|
||||
import json
|
||||
return json.dumps(self.dict(), default=str)
|
||||
|
||||
|
||||
class AuditLog(BaseModel):
|
||||
contract_id: Optional[str] = None
|
||||
entry: dict
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
signature: Optional[str] = None
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
from .models import LocalProblem, PlanDelta
|
||||
|
||||
|
||||
class LocalSolver:
|
||||
"""A tiny toy solver that generates a PlanDelta from a LocalProblem.
|
||||
|
||||
This is intentionally simple for MVP readiness and can be extended later.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.last_version: dict[str, int] = {}
|
||||
|
||||
def solve(self, problem: LocalProblem) -> PlanDelta:
|
||||
# simple deterministic delta: a minimal hedging action per asset/venue
|
||||
version = self.last_version.get(problem.id, 0) + 1
|
||||
self.last_version[problem.id] = version
|
||||
|
||||
delta = {
|
||||
"actions": [
|
||||
{
|
||||
"type": "OPEN_ARRANGEMENT",
|
||||
"asset": problem.asset,
|
||||
"venue": problem.venue,
|
||||
"parameters": problem.parameters or {},
|
||||
"timestamp": datetime.utcnow().isoformat(),
|
||||
}
|
||||
],
|
||||
"version": version,
|
||||
}
|
||||
return PlanDelta(contract_id=problem.id, delta=delta, timestamp=datetime.utcnow())
|
||||
|
|
@ -0,0 +1 @@
|
|||
"""Backward-compatible entrypoint for ELAC-Plan tests"""
|
||||
|
|
@ -0,0 +1 @@
|
|||
"""API facade for ELAC-Plan alias"""
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
"""Alias API surface for ELAC-Plan tests (re-exports external API)."""
|
||||
|
||||
from edge_latency_aware_cross_venue_execution.api.app import app # type: ignore
|
||||
|
||||
__all__ = ["app"]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from edge_latency_aware_cross_venue_execution.models import LocalProblem, SharedVariables, PlanDelta, DualVariables, AuditLog
|
||||
|
||||
__all__ = ["LocalProblem", "SharedVariables", "PlanDelta", "DualVariables", "AuditLog"]
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
"""Lightweight DSL adapter surface for tests"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from edge_latency_aware_cross_venue_execution.models import LocalProblem, SharedVariables, PlanDelta, DualVariables, AuditLog
|
||||
from types import SimpleNamespace
|
||||
|
||||
|
||||
def to_dsl_object(obj: LocalProblem) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
type="Object",
|
||||
id=obj.id,
|
||||
asset=obj.asset,
|
||||
venue=obj.venue,
|
||||
objective=obj.objective,
|
||||
parameters=obj.parameters,
|
||||
price_target=obj.price_target,
|
||||
tolerance=obj.tolerance,
|
||||
constraints=obj.constraints,
|
||||
)
|
||||
|
||||
|
||||
def to_dsl_morphisms(sig: SharedVariables) -> SimpleNamespace:
|
||||
# Prefer 'signals' when present, fallback to 'variables' for compatibility with tests
|
||||
signals = sig.signals if getattr(sig, "signals", None) is not None else getattr(sig, "variables", None)
|
||||
return SimpleNamespace(
|
||||
type="Morphism",
|
||||
contract_id=sig.contract_id,
|
||||
version=sig.version,
|
||||
signals=signals,
|
||||
variables=signals,
|
||||
privacy_budget=sig.privacy_budget,
|
||||
)
|
||||
|
||||
|
||||
def to_dsl_plan(plan: PlanDelta) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
type="PlanDelta",
|
||||
contract_id=plan.contract_id,
|
||||
delta=plan.delta,
|
||||
timestamp=plan.timestamp.isoformat(),
|
||||
author_signature=plan.author_signature,
|
||||
)
|
||||
|
||||
|
||||
def to_dsl_dual(dual: DualVariables) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
type="DualVariables",
|
||||
contract_id=dual.contract_id,
|
||||
version=dual.version,
|
||||
shadow_prices=dual.shadow_prices,
|
||||
)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from edge_latency_aware_cross_venue_execution.solver import LocalSolver as _ExternalLocalSolver
|
||||
|
||||
|
||||
class LocalSolver(_ExternalLocalSolver):
|
||||
pass
|
||||
8
test.sh
8
test.sh
|
|
@ -1,13 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}$PWD/src"
|
||||
|
||||
export PYTHONPATH=$(pwd)
|
||||
|
||||
echo "Running tests..."
|
||||
echo "Running tests (pytest)"
|
||||
pytest -q
|
||||
|
||||
echo "Building package..."
|
||||
echo "Building package (python -m build)"
|
||||
python3 -m build
|
||||
|
||||
echo "All tests passed and package built."
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -1,37 +1,24 @@
|
|||
import json
|
||||
import pytest
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from elac_plan.api import app
|
||||
try:
|
||||
# Prefer the alias surface to accommodate environments where src is not on PYTHONPATH
|
||||
from elac_plan.api.app import app
|
||||
except Exception:
|
||||
from edge_latency_aware_cross_venue_execution.api.app import app
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_create_problem_smoke():
|
||||
def test_create_problem_and_status():
|
||||
client = TestClient(app)
|
||||
payload = {
|
||||
"id": "probe-001",
|
||||
"id": "arb-1",
|
||||
"asset": "AAPL",
|
||||
"venue": "XNAS",
|
||||
"objective": "minimize_spread",
|
||||
"constraints": {"max_slippage": 0.5},
|
||||
"price_target": 150.0,
|
||||
"tolerance": 0.2,
|
||||
"venue": "VENUE1",
|
||||
"objective": "min_spread",
|
||||
"parameters": {"max_latency_ms": 5},
|
||||
}
|
||||
resp = client.post("/problems", json=payload)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["problem_id"] == payload["id"]
|
||||
assert "delta" in data
|
||||
# validate delta payload json can be parsed back
|
||||
delta = json.loads(data["delta"])
|
||||
assert delta["action"] == "place_order"
|
||||
|
||||
|
||||
def test_status_endpoint():
|
||||
resp = client.get("/status")
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
assert "problems_count" in body
|
||||
assert "deltas_count" in body
|
||||
assert data["contract_id"] == "arb-1"
|
||||
# Check status endpoint
|
||||
st = client.get("/status").json()
|
||||
assert "problems_count" in st
|
||||
|
|
|
|||
Loading…
Reference in New Issue