54 lines
1.7 KiB
Python
54 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
import uuid
|
|
from .core import LocalArbProblem, SharedSignals
|
|
|
|
|
|
class PlanDelta:
|
|
def __init__(
|
|
self,
|
|
actions,
|
|
timestamp: datetime | None = None,
|
|
dual_variables=None,
|
|
audit_log=None,
|
|
privacy_budget=None,
|
|
delta_id: str | None = None,
|
|
parent_id: str | None = None,
|
|
):
|
|
self.actions = actions
|
|
self.timestamp = timestamp or datetime.utcnow()
|
|
# Optional extensions for advanced governance/provenance.
|
|
self.dual_variables = dual_variables
|
|
self.audit_log = audit_log
|
|
self.privacy_budget = privacy_budget
|
|
# Lightweight, deterministic delta identifiers to enable CRDT-like merging.
|
|
self.delta_id = delta_id or uuid.uuid4().hex
|
|
self.parent_id = parent_id
|
|
|
|
|
|
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",
|
|
}
|
|
|
|
# In this minimal MVP, we don't yet populate dual/audit/privacy here.
|
|
return PlanDelta(actions=[action])
|
|
|
|
|
|
__all__ = ["PlanDelta", "admm_step"]
|