build(agent): melter#14fd4b iteration

This commit is contained in:
agent-14fd4b738639d573 2026-04-24 19:40:43 +02:00
parent fcdd3d0e64
commit 582cf99c8b
2 changed files with 99 additions and 0 deletions

66
crossvenue_arbx/fuzz.py Normal file
View File

@ -0,0 +1,66 @@
from __future__ import annotations
import random
from typing import Iterable, List, Tuple
from .core import LocalArbProblem, SharedSignals
from .coordinator import CentralCoordinator
class ScenarioGenerator:
"""Deterministic scenario generator for delta-fuzzing.
Produces a replayable sequence of (LocalArbProblem, SharedSignals) that can
be fed into CentralCoordinator.ingest_local. Uses an explicit seed to make
runs deterministic.
"""
def __init__(self, seed: int = 0) -> None:
self._seed = seed
def generate(self, steps: int = 10) -> List[Tuple[LocalArbProblem, SharedSignals]]:
rnd = random.Random(self._seed)
venues = ["VenueA", "VenueB"]
assets = ["AAA", "BBB"]
out: List[Tuple[LocalArbProblem, SharedSignals]] = []
for i in range(steps):
venue = venues[rnd.randrange(len(venues))]
problem = LocalArbProblem(
id=f"prob-{venue}-{i}",
venue=venue,
assets=list(assets),
target_misprice=rnd.uniform(0.0, 0.01),
max_exposure=rnd.choice([100.0, 1000.0, 10000.0]),
latency_budget=rnd.uniform(0.01, 1.0),
)
# deterministic but varied price deltas and liquidity
price_deltas = {a: rnd.uniform(-0.005, 0.005) for a in assets}
# occasionally inject a shock
if rnd.random() < 0.15:
shock_asset = rnd.choice(assets)
price_deltas[shock_asset] = rnd.choice([-1.0, 1.0]) * rnd.uniform(0.001, 0.02)
signals = SharedSignals(
version=i,
price_delta_by_asset=price_deltas,
cross_corr={("AAA","BBB"): rnd.uniform(-1.0,1.0)},
liquidity_estimates={a: rnd.uniform(10.0, 10000.0) for a in assets},
)
out.append((problem, signals))
return out
class ReplayRunner:
"""Runs a generated scenario through a fresh CentralCoordinator and
returns the replay log (list of PlanDelta signatures) and the final plan
signature.
"""
def __init__(self) -> None:
self.coordinator = CentralCoordinator()
def run(self, events: Iterable[Tuple[LocalArbProblem, SharedSignals]]):
for problem, sig in events:
self.coordinator.ingest_local(problem, sig)
# call reconcile to flush pending actions
self.coordinator.reconcile()
return list(self.coordinator.replay_log), (self.coordinator.last_plan.signature if self.coordinator.last_plan else None)

33
tests/test_delta_fuzz.py Normal file
View File

@ -0,0 +1,33 @@
from crossvenue_arbx.fuzz import ScenarioGenerator, ReplayRunner
def test_replay_determinism_same_seed():
gen = ScenarioGenerator(seed=42)
events = gen.generate(steps=20)
runner1 = ReplayRunner()
log1, final1 = runner1.run(events)
runner2 = ReplayRunner()
# regenerate to ensure fresh objects but same seed
gen2 = ScenarioGenerator(seed=42)
events2 = gen2.generate(steps=20)
log2, final2 = runner2.run(events2)
assert log1 == log2, "Replay logs must be identical for same seed"
assert final1 == final2, "Final plan signature must match for same seed"
def test_replay_variation_different_seed():
gen = ScenarioGenerator(seed=1)
events = gen.generate(steps=20)
runner = ReplayRunner()
log1, final1 = runner.run(events)
genb = ScenarioGenerator(seed=2)
eventsb = genb.generate(steps=20)
runnerb = ReplayRunner()
log2, final2 = runnerb.run(eventsb)
# usually different seeds will produce different logs or final plan
assert (log1 != log2) or (final1 != final2)