build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
29d0a3aaaf
commit
ccce28a92e
|
|
@ -0,0 +1,21 @@
|
|||
node_modules/
|
||||
.npmrc
|
||||
.env
|
||||
.env.*
|
||||
__tests__/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
dist/
|
||||
build/
|
||||
.cache/
|
||||
*.log
|
||||
.DS_Store
|
||||
tmp/
|
||||
.tmp/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
*.egg-info/
|
||||
.pytest_cache/
|
||||
READY_TO_PUBLISH
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# AGENTS
|
||||
|
||||
- This repository contains a lightweight, test-driven Python prototype for ArbSphere's federated cross-arbitrage primitives.
|
||||
- Core concepts provided: LocalArbProblem, SharedSignals, and a deterministic admm_step that outputs a PlanDelta.
|
||||
- Tests verify deterministic plan generation and basic structure.
|
||||
- How to run:
|
||||
- bash test.sh
|
||||
- Important: This document is a stub for onboarding agents and does not describe a full production architecture.
|
||||
10
README.md
10
README.md
|
|
@ -1,3 +1,9 @@
|
|||
# idea159-arbsphere-federated-cross
|
||||
# ArbSphere Federated Cross (Toy)
|
||||
|
||||
Source logic for Idea #159
|
||||
This repository provides a minimal, test-focused Python package that defines
|
||||
the canonical LocalArbProblem and SharedSignals primitives and a simple ADMM-like
|
||||
step function used by unit tests. It serves as a starting point for a more
|
||||
comprehensive federated arbitrage prototype.
|
||||
|
||||
Note: This is a lightweight, educational scaffold designed to satisfy tests and
|
||||
CI checks in this kata. It is not a production-grade implementation.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
"""Idea159 ArbSphere Federated Cross (toy) package.
|
||||
|
||||
This lightweight package provides the core primitives used by the tests and
|
||||
minimal bridging utilities to enable interoperability with a canonical IR
|
||||
via EnergiBridge.
|
||||
"""
|
||||
|
||||
__all__ = ["core", "solver", "energi_bridge"]
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import List
|
||||
|
||||
from ..core import PlanDelta
|
||||
|
||||
|
||||
class MockBrokerAdapter:
|
||||
def __init__(self):
|
||||
self.decisions: List[PlanDelta] = []
|
||||
|
||||
def consume(self, plan: PlanDelta) -> None:
|
||||
# In a real adapter, this would route orders. Here we record for testability.
|
||||
self.decisions.append(plan)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
from ..core import LocalArbProblem, SharedSignals
|
||||
|
||||
|
||||
@dataclass
|
||||
class MockPriceFeedAdapter:
|
||||
version: int = 1
|
||||
|
||||
def emit(self) -> tuple[LocalArbProblem, SharedSignals]:
|
||||
# Minimal synthetic data for MVP
|
||||
local = LocalArbProblem(
|
||||
id="lp-01",
|
||||
venue="NYSE",
|
||||
asset_pair="AAPL/GOOG",
|
||||
target_misprice=0.5,
|
||||
max_exposure=1000000.0,
|
||||
latency_budget_ms=50,
|
||||
)
|
||||
signals = SharedSignals(
|
||||
version=self.version,
|
||||
price_delta=0.1,
|
||||
cross_venue_corr=0.8,
|
||||
liquidity=1000000.0,
|
||||
)
|
||||
return local, signals
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class LocalArbProblem:
|
||||
id: str
|
||||
venue: str
|
||||
asset_pair: str
|
||||
target_misprice: float
|
||||
max_exposure: float
|
||||
latency_budget_ms: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class SharedSignals:
|
||||
version: int
|
||||
price_delta: float
|
||||
cross_venue_corr: float
|
||||
liquidity: float
|
||||
|
||||
|
||||
__all__ = ["LocalArbProblem", "SharedSignals"]
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
"""EnergiBridge: Canonical IR translator for ArbSphere primitives.
|
||||
|
||||
This module provides a lightweight, vendor-agnostic translation layer that
|
||||
maps ArbSphere primitives (LocalArbProblem, SharedSignals, PlanDelta) into a
|
||||
canonical IR suitable for adapters/bridges to cross-exchange data feeds and
|
||||
execution venues. The goal is minimal, deterministic, and easy to extend.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from .core import LocalArbProblem, SharedSignals
|
||||
from .solver import PlanDelta
|
||||
|
||||
|
||||
class EnergiBridge:
|
||||
"""Static translator utilities for ArbSphere primitives to a canonical IR."""
|
||||
|
||||
@staticmethod
|
||||
def to_ir(local: LocalArbProblem, signals: SharedSignals, delta: PlanDelta | None = None) -> Dict[str, Any]:
|
||||
"""Serialize a LocalArbProblem and SharedSignals (and optional PlanDelta) to IR.
|
||||
|
||||
The IR schema is intentionally simple and versioned via the top-level keys.
|
||||
It is designed to be extended by adapters without coupling to internal
|
||||
Python types.
|
||||
"""
|
||||
payload: Dict[str, Any] = {
|
||||
"IRVersion": 1,
|
||||
"Object": {
|
||||
"id": local.id,
|
||||
"venue": local.venue,
|
||||
"asset_pair": local.asset_pair,
|
||||
"target_misprice": local.target_misprice,
|
||||
"max_exposure": local.max_exposure,
|
||||
"latency_budget_ms": local.latency_budget_ms,
|
||||
},
|
||||
"SharedSignals": asdict(signals),
|
||||
}
|
||||
|
||||
if delta is not None:
|
||||
# Include a lightweight delta snapshot with actions for replay
|
||||
payload["PlanDelta"] = {
|
||||
"actions": delta.actions,
|
||||
"timestamp": delta.timestamp.isoformat(),
|
||||
}
|
||||
|
||||
return payload
|
||||
|
||||
@staticmethod
|
||||
def from_ir(ir: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Deserialize a canonical IR payload back into a structured dict.
|
||||
|
||||
This helper is intentionally permissive to avoid tight coupling with
|
||||
Python types in adapters. It is suitable for simple round-trips and
|
||||
can be extended for full bidirectional mapping.
|
||||
"""
|
||||
return ir
|
||||
|
||||
@staticmethod
|
||||
def merge_deltas(base: PlanDelta, new: PlanDelta) -> PlanDelta:
|
||||
"""Deterministic merge of two PlanDelta objects.
|
||||
|
||||
For this toy MVP, we concatenate actions and keep the latest timestamp.
|
||||
A real CRDT-like merge would deduplicate and order actions, but this
|
||||
keeps the implementation small and deterministic for replay.
|
||||
"""
|
||||
merged_actions: List[Dict[str, Any]] = []
|
||||
if isinstance(base.actions, list):
|
||||
merged_actions.extend(base.actions)
|
||||
if isinstance(new.actions, list):
|
||||
merged_actions.extend(new.actions)
|
||||
|
||||
latest_ts = max(base.timestamp, new.timestamp)
|
||||
return PlanDelta(actions=merged_actions, timestamp=latest_ts)
|
||||
|
||||
|
||||
__all__ = ["EnergiBridge"]
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
"""Graph-of-Contracts (GoC) placeholders for adapters and data schemas."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict
|
||||
|
||||
|
||||
@dataclass
|
||||
class ContractMetadata:
|
||||
name: str
|
||||
version: str
|
||||
endpoint: str | None = None
|
||||
|
||||
|
||||
class GraphOfContracts:
|
||||
def __init__(self):
|
||||
self._registry: Dict[str, ContractMetadata] = {}
|
||||
|
||||
def register(self, key: str, meta: ContractMetadata):
|
||||
self._registry[key] = meta
|
||||
|
||||
def get(self, key: str) -> ContractMetadata | None:
|
||||
return self._registry.get(key)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from .core import LocalArbProblem, SharedSignals
|
||||
|
||||
|
||||
class PlanDelta:
|
||||
def __init__(self, actions, timestamp: datetime | None = None):
|
||||
self.actions = actions
|
||||
self.timestamp = timestamp or datetime.utcnow()
|
||||
|
||||
|
||||
def admm_step(local: LocalArbProblem, signals: SharedSignals) -> PlanDelta:
|
||||
"""Deterministic, minimal ADMM-like step producing a single PlanDelta.
|
||||
|
||||
The plan contains a single action that routes a hedge-like size from the
|
||||
local venue to a cross-venue placeholder, using available liquidity and
|
||||
respecting the local exposure cap.
|
||||
"""
|
||||
# Deterministic sizing based on available liquidity and max exposure
|
||||
available = max(0.0, float(signals.liquidity))
|
||||
size = min(float(local.max_exposure), available * 0.5)
|
||||
|
||||
action = {
|
||||
"venue_from": local.venue,
|
||||
"venue_to": "CROSS-VENUE",
|
||||
"instrument": local.asset_pair,
|
||||
"size": size,
|
||||
"time": datetime.utcnow().isoformat() + "Z",
|
||||
}
|
||||
|
||||
return PlanDelta(actions=[action])
|
||||
|
||||
|
||||
__all__ = ["PlanDelta", "admm_step"]
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=61", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "idea159-arbsphere-federated-cross"
|
||||
version = "0.1.0"
|
||||
description = "Toy primitives for ArbSphere federated cross-arb (tests only)."
|
||||
readme = "README.md"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="idea159-arbsphere-federated-cross",
|
||||
version="0.1.0",
|
||||
packages=find_packages(),
|
||||
description="Toy primitives for ArbSphere federated cross-arb (tests only).",
|
||||
)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Run Python tests
|
||||
pytest -q
|
||||
|
||||
# Build the package (verifies packaging metadata and structure)
|
||||
python3 -m build
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from idea159_arbsphere_federated_cross.core import LocalArbProblem, SharedSignals
|
||||
from idea159_arbsphere_federated_cross.solver import admm_step
|
||||
|
||||
|
||||
def test_admm_step_produces_plan_delta_deterministically():
|
||||
local = LocalArbProblem(
|
||||
id="test-1",
|
||||
venue="NYSE",
|
||||
asset_pair="AAPL/GOOG",
|
||||
target_misprice=0.5,
|
||||
max_exposure=10000.0,
|
||||
latency_budget_ms=100,
|
||||
)
|
||||
signals = SharedSignals(version=1, price_delta=0.05, cross_venue_corr=0.9, liquidity=50000.0)
|
||||
|
||||
plan = admm_step(local, signals)
|
||||
|
||||
# Basic sanity checks on shape and content
|
||||
assert plan is not None
|
||||
assert isinstance(plan.actions, list)
|
||||
assert len(plan.actions) == 1
|
||||
act = plan.actions[0]
|
||||
assert "venue_from" in act and "venue_to" in act
|
||||
assert act["instrument"] == local.asset_pair
|
||||
assert plan.timestamp <= datetime.datetime.utcnow()
|
||||
Loading…
Reference in New Issue