diff --git a/README.md b/README.md index fb70441..7436b9a 100644 --- a/README.md +++ b/README.md @@ -37,3 +37,12 @@ Testing and packaging If helpful, I can draft toy adapter blueprints, an EnergiBridge mapping for ArbSphere, and a minimal two-venue toy contract to bootstrap interoperability. + +Two-Venue MVP Orchestrator +- A small Python script (orchestrator.py) wired in idea159_arbsphere_federated_cross/ that demonstrates a complete two-venue flow: + - Build two LocalArbProblem instances for two venues + - Run admm_step against each to produce PlanDelta + - Deterministically merge deltas via EnergiBridge.merge_deltas + - Serialize to canonical IR with EnergiBridge.to_ir + - Route the merged delta through a toy broker adapter to simulate execution +- This serves as a practical, end-to-end demonstration of ArbSphere interoperability across two exchanges and a minimal governance/traceable flow. diff --git a/idea159_arbsphere_federated_cross/orchestrator.py b/idea159_arbsphere_federated_cross/orchestrator.py new file mode 100644 index 0000000..0a6fcc3 --- /dev/null +++ b/idea159_arbsphere_federated_cross/orchestrator.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +"""Two-venue MVP orchestrator for ArbSphere (toy demo). + +This script wires two LocalArbProblem instances (representing two venues) +with their corresponding SharedSignals, runs the minimal ADMM step for each, +merges the resulting PlanDelta deterministically via EnergiBridge, and routes +the combined delta through a mock broker adapter to demonstrate end-to-end +flow in a two-venue setting. +""" + +from datetime import datetime + +from idea159_arbsphere_federated_cross.core import LocalArbProblem, SharedSignals +from idea159_arbsphere_federated_cross.solver import admm_step +from idea159_arbsphere_federated_cross.energi_bridge import EnergiBridge +from idea159_arbsphere_federated_cross.adapters.broker_adapter import MockBrokerAdapter + + +def build_local_venue(venue: str, asset_pair: str, target_misprice: float, max_exposure: float, latency_budget_ms: int) -> LocalArbProblem: + return LocalArbProblem( + id=f"lp-{venue}-{datetime.utcnow().isoformat()}", + venue=venue, + asset_pair=asset_pair, + target_misprice=target_misprice, + max_exposure=max_exposure, + latency_budget_ms=latency_budget_ms, + ) + + +def build_signals(version: int, price_delta: float, cross_venue_corr: float, liquidity: float) -> SharedSignals: + return SharedSignals( + version=version, + price_delta=price_delta, + cross_venue_corr=cross_venue_corr, + liquidity=liquidity, + ) + + +def run_two_venue_demo() -> None: + # Venue 1 + local1 = build_local_venue("NYSE", "AAPL/GOOG", 0.5, 1_000_000.0, 50) + signals1 = build_signals(version=1, price_delta=0.10, cross_venue_corr=0.85, liquidity=1_000_000.0) + delta1 = admm_step(local1, signals1) + + # Venue 2 + local2 = build_local_venue("LON", "GOOG/AMZN", 0.6, 1_000_000.0, 60) + signals2 = build_signals(version=1, price_delta=0.08, cross_venue_corr=0.80, liquidity=1_200_000.0) + delta2 = admm_step(local2, signals2) + + # Deterministic merge of deltas (toy CRDT-like merge) + merged = EnergiBridge.merge_deltas(delta1, delta2) + + # Serialize to canonical IR (for adapters) + ir = EnergiBridge.to_ir(local1, signals1, delta=merged) + print("Canonical IR payload:") + print(ir) + + # Route to a mock broker to demonstrate end-to-end flow + broker = MockBrokerAdapter() + ack = broker.consume(merged) # type: ignore[arg-type] + print("Broker acknowledged delta. Actions:", merged.actions) + print("DeltaID:", merged.delta_id) + print("Completed two-venue demo at", datetime.utcnow().isoformat()) + + +if __name__ == "__main__": + run_two_venue_demo()