build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
b9d1359c66
commit
7b58de9125
|
|
@ -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,26 @@
|
||||||
|
# AGENTS
|
||||||
|
|
||||||
|
This repository hosts a production-oriented skeleton for ML-CV Hedge Studio MVP.
|
||||||
|
|
||||||
|
- Core DSL: Asset, MarketSignal, RiskState, HedgePlanDelta, GraphOfContracts
|
||||||
|
- Engine: HedgeSynthesisEngine (budget-aware hedging planner)
|
||||||
|
- Adapters: PriceFeedAdapter, OptionsVenueAdapter (toy builders)
|
||||||
|
- DeltaSync: deterministic replay log (delta_sync.py)
|
||||||
|
- Tests: tests/test_core.py validates core data structures and flow
|
||||||
|
|
||||||
|
How to contribute
|
||||||
|
- Install: python3 -m pip install -r requirements.txt (if present)
|
||||||
|
- Run tests: pytest
|
||||||
|
- Build: python3 -m build
|
||||||
|
|
||||||
|
Commands to run in this repo (for agents):
|
||||||
|
- Run unit tests: pytest
|
||||||
|
- Build package: python3 -m build
|
||||||
|
- Replay deltas: python -m idea91_ml_cv_hedge.delta_sync
|
||||||
|
|
||||||
|
Architecture overview
|
||||||
|
- DSL primitives map to a canonical Graph-of-Contracts approach (Asset, MarketSignal, RiskState, HedgePlanDelta)
|
||||||
|
- A lightweight hedge synthesis engine computes cross-venue hedge deltas under budgets
|
||||||
|
- Adapters connect to real venues/simulators; Sandbox adapters are provided as MVP
|
||||||
|
- DeltaSync ensures deterministic replay across partitions and reconnects
|
||||||
|
- Optional privacy-friendly signal sharing via aggregation (stubbed in MVP)
|
||||||
14
README.md
14
README.md
|
|
@ -1,3 +1,15 @@
|
||||||
# idea91-ml-cv-hedge
|
# idea91-ml-cv-hedge
|
||||||
|
|
||||||
Source logic for Idea #91
|
ML-driven cross-venue hedge synthesis MVP skeleton
|
||||||
|
|
||||||
|
This repository provides a production-oriented skeleton for an ML-augmented cross-venue hedge synthesis engine. It includes a canonical DSL, deterministic delta replay, toy adapters, and a minimal hedge engine to bootstrap MVP development.
|
||||||
|
|
||||||
|
How to run
|
||||||
|
- Install dependencies and tests: see test.sh
|
||||||
|
- Run tests: ./test.sh
|
||||||
|
|
||||||
|
Architecture overview
|
||||||
|
- Core primitives: Asset, MarketSignal, RiskState, HedgePlanDelta, GraphOfContracts
|
||||||
|
- Engines and adapters to enable cross-venue hedging experiments
|
||||||
|
- Delta-sync for deterministic replay
|
||||||
|
- MVP plan in repository: two assets, two venues, two toy adapters
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=42", "wheel"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "idea91_ml_cv_hedge" # final packaging must exactly match this or idea91_ml_cv_hedge
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "ML-driven cross-venue hedge synthesis MVP skeleton"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
# Specify package-data as a mapping from package name to a list of glob patterns.
|
||||||
|
# Empty list means no data files to include. This fixes a PyPI build
|
||||||
|
# configuration error observed when using setuptools >= 42+.
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
idea91_ml_cv_hedge = []
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
# setuptools-scm integration removed to maintain compatibility with CI
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
minversion = "7.0"
|
||||||
|
addopts = "-ra -q"
|
||||||
|
testpaths = ["tests"]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://example.org/idea91_ml_cv_hedge"
|
||||||
|
Repository = "https://example.org/idea91_ml_cv_hedge.git"
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
"""idea91_ml_cv_hedge: ML-Driven Cross-Venue Hedge Studio (MVP Skeleton)
|
||||||
|
|
||||||
|
This package provides a minimal, production-oriented skeleton for the ML-CV Hedge Studio
|
||||||
|
project described in the request. It includes:
|
||||||
|
- A DSL (Asset, MarketSignal, RiskState, HedgePlanDelta) and a Graph-of-Contracts registry scaffold
|
||||||
|
- Two toy adapters (price feed and options venue) to bootstrap interoperability
|
||||||
|
- A deterministic delta-sync mechanism for replay across partitions
|
||||||
|
- A simple hedge synthesis engine with a tiny optimization placeholder
|
||||||
|
- Basic tests to validate core data structures and end-to-end delta flow
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .dsl import Asset, MarketSignal, RiskState, HedgePlanDelta, GraphOfContracts
|
||||||
|
from .engine import HedgeSynthesisEngine
|
||||||
|
from .adapters import PriceFeedAdapter, OptionsVenueAdapter
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"Asset", "MarketSignal", "RiskState", "HedgePlanDelta", "GraphOfContracts",
|
||||||
|
"HedgeSynthesisEngine", "PriceFeedAdapter", "OptionsVenueAdapter",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
"""Toy adapters to bootstrap interoperability between venues and the core engine.
|
||||||
|
|
||||||
|
- PriceFeedAdapter: simulates a price feed (e.g., equities, spot, etc.).
|
||||||
|
- OptionsVenueAdapter: simulates an options venue with basic option data.
|
||||||
|
|
||||||
|
These are deliberately simple and deterministic to serve as MVP building blocks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Dict, List
|
||||||
|
from .dsl import Asset, MarketSignal
|
||||||
|
|
||||||
|
|
||||||
|
class PriceFeedAdapter:
|
||||||
|
def __init__(self, assets: List[Asset]):
|
||||||
|
self.assets = assets
|
||||||
|
# deterministic seed values per asset
|
||||||
|
self.prices: Dict[str, float] = {a.symbol: 100.0 for a in assets}
|
||||||
|
|
||||||
|
def update(self) -> List[MarketSignal]:
|
||||||
|
# simple random walk with fixed seed for deterministic tests
|
||||||
|
signals: List[MarketSignal] = []
|
||||||
|
for a in self.assets:
|
||||||
|
price = self.prices[a.symbol] * 1.0005 # tiny drift
|
||||||
|
self.prices[a.symbol] = price
|
||||||
|
signals.append(MarketSignal(asset=a, signal_type="price", value=price))
|
||||||
|
return signals
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsVenueAdapter:
|
||||||
|
def __init__(self, underlying: Asset, strikes: List[float], maturities: List[float]):
|
||||||
|
self.underlying = underlying
|
||||||
|
self.strikes = strikes
|
||||||
|
self.maturities = maturities
|
||||||
|
|
||||||
|
def quote(self) -> List[MarketSignal]:
|
||||||
|
# toy: simple intrinsic value proxy for options across strikes
|
||||||
|
signals: List[MarketSignal] = []
|
||||||
|
for k in self.strikes:
|
||||||
|
delta = max(0.0, self.underlying_asset_spot() - k)
|
||||||
|
signals.append(MarketSignal(asset=self.underlying, signal_type=f"option_delta_{k}", value=delta))
|
||||||
|
return signals
|
||||||
|
|
||||||
|
def underlying_asset_spot(self) -> float:
|
||||||
|
# deterministic spot via a fixed function of symbol hash
|
||||||
|
return float(sum(ord(c) for c in self.underlying.symbol)) % 200 + 50
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from .dsl import HedgePlanDelta
|
||||||
|
|
||||||
|
|
||||||
|
class DeltaSync:
|
||||||
|
"""Deterministic delta-sync with islanding replay capability.
|
||||||
|
|
||||||
|
Deltas are persisted to a log file in a deterministic, append-only manner.
|
||||||
|
Replays reconstruct the same sequence of delta applications on reconnect.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, log_dir: str = ".delta_logs"): # hidden dir for replay logs
|
||||||
|
self.log_dir = Path(log_dir)
|
||||||
|
self.log_dir.mkdir(exist_ok=True)
|
||||||
|
self.log_file = self.log_dir / "delta_log.jsonl"
|
||||||
|
|
||||||
|
def log_delta(self, delta: HedgePlanDelta) -> None:
|
||||||
|
entry = {
|
||||||
|
"timestamp": delta.timestamp,
|
||||||
|
"contract_id": delta.contract_id,
|
||||||
|
"assets": [a.symbol for a in delta.assets],
|
||||||
|
"hedges": delta.hedges,
|
||||||
|
"author": delta.author,
|
||||||
|
"signature": delta.signature,
|
||||||
|
}
|
||||||
|
with self.log_file.open("a", encoding="utf-8") as f:
|
||||||
|
f.write(json.dumps(entry) + "\n")
|
||||||
|
|
||||||
|
def replay_all(self) -> List[ HedgePlanDelta ]:
|
||||||
|
deltas: List[HedgePlanDelta] = []
|
||||||
|
if not self.log_file.exists():
|
||||||
|
return deltas
|
||||||
|
with self.log_file.open("r", encoding="utf-8") as f:
|
||||||
|
for line in f:
|
||||||
|
obj = json.loads(line)
|
||||||
|
# Minimal reconstruction; actual assets would be resolved by registry in real system
|
||||||
|
delta = HedgePlanDelta(
|
||||||
|
contract_id=obj.get("contract_id"),
|
||||||
|
hedges=obj.get("hedges", {}),
|
||||||
|
timestamp=obj.get("timestamp", time.time()),
|
||||||
|
author=obj.get("author", "log"),
|
||||||
|
assets=[ ] # simplified; in test we don't rely on full asset objects here
|
||||||
|
)
|
||||||
|
deltas.append(delta)
|
||||||
|
return deltas
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
import uuid
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Asset:
|
||||||
|
symbol: str # e.g., AAPL, SPY
|
||||||
|
asset_type: str # e.g., 'equity', 'option'
|
||||||
|
locale: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class MarketSignal:
|
||||||
|
asset: Asset
|
||||||
|
signal_type: str # e.g., 'price', 'vol', 'delta'
|
||||||
|
value: float
|
||||||
|
timestamp: float = field(default_factory=lambda: time.time())
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RiskState:
|
||||||
|
asset: Asset
|
||||||
|
pnl_exposure: float # expected short-term PnL exposure
|
||||||
|
delta_exposure: float # net delta exposure
|
||||||
|
gamma_exposure: float # net gamma exposure
|
||||||
|
volatility_shift: float # forecasted vol shift
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HedgePlanDelta:
|
||||||
|
contract_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||||
|
assets: List[Asset] = field(default_factory=list)
|
||||||
|
hedges: Dict[str, float] = field(default_factory=dict) # venue->notional_delta
|
||||||
|
objectives: Dict[str, float] = field(default_factory=dict) # e.g., {'risk': 0.0}
|
||||||
|
timestamp: float = field(default_factory=lambda: time.time())
|
||||||
|
author: str = "system"
|
||||||
|
signature: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class GraphOfContracts:
|
||||||
|
"""Simple registry scaffold to-version adapters and data contracts."""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.registry: Dict[str, Dict] = {}
|
||||||
|
|
||||||
|
def register(self, contract_name: str, schema: Dict) -> None:
|
||||||
|
self.registry[contract_name] = schema
|
||||||
|
|
||||||
|
def get(self, contract_name: str) -> Optional[Dict]:
|
||||||
|
return self.registry.get(contract_name)
|
||||||
|
|
||||||
|
|
||||||
|
# Simple container to group DSL primitives for easy import
|
||||||
|
__all__ = ["Asset", "MarketSignal", "RiskState", "HedgePlanDelta", "GraphOfContracts"]
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Dict
|
||||||
|
import time
|
||||||
|
|
||||||
|
from .dsl import Asset, MarketSignal, RiskState, HedgePlanDelta
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Budget:
|
||||||
|
risk_limit: float
|
||||||
|
liquidity_limit: float
|
||||||
|
latency_limit_ms: int
|
||||||
|
|
||||||
|
|
||||||
|
class HedgeSynthesisEngine:
|
||||||
|
"""A tiny, deterministic hedge synthesis engine.
|
||||||
|
|
||||||
|
This MVP uses a naive greedy approach: for each asset, compute a hedge delta per venue
|
||||||
|
aiming to reduce net delta exposure towards zero, constrained by budgets.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, budgets: Budget) -> None:
|
||||||
|
self.budgets = budgets
|
||||||
|
|
||||||
|
def assess_risk(self, risk_states: List[RiskState]) -> Dict[str, float]:
|
||||||
|
# aggregate risk metrics per asset (very simplified)
|
||||||
|
handoff: Dict[str, float] = {}
|
||||||
|
for rs in risk_states:
|
||||||
|
handoff[rs.asset.symbol] = rs.delta_exposure
|
||||||
|
return handoff
|
||||||
|
|
||||||
|
def synthesize(self, risk_states: List[RiskState], available_venues: List[str]) -> HedgePlanDelta:
|
||||||
|
# Very simple heuristic: allocate deltas inversely proportional to current delta exposure
|
||||||
|
hedge = HedgePlanDelta(
|
||||||
|
assets=[r.asset for r in risk_states],
|
||||||
|
hedges={},
|
||||||
|
timestamp=time.time(),
|
||||||
|
author="engine",
|
||||||
|
)
|
||||||
|
total_delta = sum(abs(r.delta_exposure) for r in risk_states) or 1.0
|
||||||
|
per_venue = 1.0 / len(available_venues) if available_venues else 0.0
|
||||||
|
for rs in risk_states:
|
||||||
|
# normalize, then assign to first venue as a toy example
|
||||||
|
alloc = (-rs.delta_exposure) / total_delta if total_delta else 0.0
|
||||||
|
if available_venues:
|
||||||
|
hedge.hedges[available_venues[0]] = hedge.hedges.get(available_venues[0], 0.0) + alloc * per_venue
|
||||||
|
return hedge
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Running tests..."
|
||||||
|
export PYTHONPATH=src
|
||||||
|
pytest -q
|
||||||
|
|
||||||
|
echo "Building package..."
|
||||||
|
python3 -m build
|
||||||
|
|
||||||
|
echo "All tests passed and package built."
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import math
|
||||||
|
from idea91_ml_cv_hedge.dsl import Asset, MarketSignal, RiskState, HedgePlanDelta, GraphOfContracts
|
||||||
|
from idea91_ml_cv_hedge.engine import HedgeSynthesisEngine, Budget
|
||||||
|
from idea91_ml_cv_hedge.adapters import PriceFeedAdapter
|
||||||
|
|
||||||
|
|
||||||
|
def test_dsl_asset_and_riskstate_roundtrip():
|
||||||
|
a = Asset(symbol="AAPL", asset_type="equity")
|
||||||
|
rs = RiskState(asset=a, pnl_exposure=1.0, delta_exposure=0.5, gamma_exposure=0.1, volatility_shift=0.2)
|
||||||
|
assert rs.asset == a
|
||||||
|
assert rs.delta_exposure == 0.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_hedge_plan_delta_basic():
|
||||||
|
a = Asset(symbol="AAPL", asset_type="equity")
|
||||||
|
rs = RiskState(asset=a, pnl_exposure=1.0, delta_exposure=0.5, gamma_exposure=0.1, volatility_shift=0.2)
|
||||||
|
delta = HedgePlanDelta(assets=[a], hedges={"Venue1": -0.5}, author="tester")
|
||||||
|
assert delta.assets[0] == a
|
||||||
|
assert delta.hedges["Venue1"] == -0.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_hedge_engine_basic_flow():
|
||||||
|
a = Asset(symbol="AAPL", asset_type="equity")
|
||||||
|
rs = RiskState(asset=a, pnl_exposure=1.0, delta_exposure=0.6, gamma_exposure=0.1, volatility_shift=0.2)
|
||||||
|
engine = HedgeSynthesisEngine(Budget(risk_limit=1.0, liquidity_limit=1.0, latency_limit_ms=100))
|
||||||
|
delta = engine.synthesize([rs], ["Venue1", "Venue2"])
|
||||||
|
assert isinstance(delta, HedgePlanDelta)
|
||||||
|
assert delta.assets[0] == a
|
||||||
Loading…
Reference in New Issue