build(agent): new-agents-4#58ba63 iteration
This commit is contained in:
parent
4028ae6868
commit
c4004abdea
|
|
@ -0,0 +1,2 @@
|
||||||
|
DeltaForge MVP scaffold for real-time cross-venue hedging across assets.
|
||||||
|
This repository provides core DSL primitives, a minimal ADMM-like coordinator, two starter adapters, a toy backtester, and a test harness.
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
"""
|
||||||
|
DeltaForge MVP: Core package initialization.
|
||||||
|
"""
|
||||||
|
from .dsl import StrategyDelta, Asset, MarketSignal, PlanDelta
|
||||||
|
from .coordinator import Coordinator
|
||||||
|
|
||||||
|
__all__ = ["StrategyDelta", "Asset", "MarketSignal", "PlanDelta", "Coordinator"]
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
import time
|
||||||
|
from typing import List
|
||||||
|
from ..dsl import Asset, MarketSignal
|
||||||
|
|
||||||
|
class EquityFeedAdapter:
|
||||||
|
"""
|
||||||
|
Starter equity feed adapter.
|
||||||
|
In a real system this would connect to a streaming data source.
|
||||||
|
Here we provide a deterministic, test-friendly generator.
|
||||||
|
"""
|
||||||
|
def __init__(self, asset_symbol: str = "AAPL"):
|
||||||
|
self.asset = Asset(id="eq-"+asset_symbol, type="equity", symbol=asset_symbol)
|
||||||
|
self.start = time.time()
|
||||||
|
|
||||||
|
def poll_signals(self) -> List[MarketSignal]:
|
||||||
|
t = time.time() - self.start
|
||||||
|
price = 150.0 + (t % 5) # deterministic-ish
|
||||||
|
return [MarketSignal(asset=self.asset, timestamp=t, price=price, liquidity=1.0)]
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
import time
|
||||||
|
from typing import List
|
||||||
|
from ..dsl import Asset, MarketSignal
|
||||||
|
|
||||||
|
class OptionsFeedAdapter:
|
||||||
|
"""
|
||||||
|
Starter options feed adapter (toy).
|
||||||
|
"""
|
||||||
|
def __init__(self, symbol: str = "AAPL-20260120-150C"):
|
||||||
|
self.asset = Asset(id="opt-"+symbol, type="option", symbol=symbol)
|
||||||
|
self.start = time.time()
|
||||||
|
|
||||||
|
def poll_signals(self) -> List[MarketSignal]:
|
||||||
|
t = time.time() - self.start
|
||||||
|
price = 5.0 + (t % 1.5)
|
||||||
|
return [MarketSignal(asset=self.asset, timestamp=t, price=price, liquidity=1.0)]
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import List
|
||||||
|
from .dsl import MarketSignal, PlanDelta
|
||||||
|
|
||||||
|
class Backtester:
|
||||||
|
"""
|
||||||
|
Tiny deterministic replay engine.
|
||||||
|
Applies PlanDelta actions to a simple PnL model.
|
||||||
|
"""
|
||||||
|
def __init__(self, initial_cash: float = 100000.0):
|
||||||
|
self.cash = initial_cash
|
||||||
|
self.positions: List[dict] = []
|
||||||
|
|
||||||
|
def apply(self, signals: List[MarketSignal], plan: PlanDelta) -> float:
|
||||||
|
# Very simple PnL: sum(action.size * current_price) and adjust cash
|
||||||
|
pnl = 0.0
|
||||||
|
for act in plan.delta:
|
||||||
|
symbol = act.get("symbol") or act.get("asset") or "UNKNOWN"
|
||||||
|
size = act.get("size", 0.0)
|
||||||
|
price = act.get("price") or act.get("premium") or 0.0
|
||||||
|
if price is None:
|
||||||
|
price = 0.0
|
||||||
|
pnl += size * price
|
||||||
|
self.positions.append({"symbol": symbol, "size": size, "price": price})
|
||||||
|
self.cash += pnl
|
||||||
|
return self.cash
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import List
|
||||||
|
from .dsl import MarketSignal, PlanDelta
|
||||||
|
|
||||||
|
class Coordinator:
|
||||||
|
"""
|
||||||
|
Lightweight ADMM-like coordinator.
|
||||||
|
It collects MarketSignals from multiple venues and emits a PlanDelta
|
||||||
|
representing a synchronized hedging action.
|
||||||
|
This is a minimal, deterministic stub suitable for MVP testing.
|
||||||
|
"""
|
||||||
|
def __init__(self, contract_id: str = "default-contract"):
|
||||||
|
self.contract_id = contract_id
|
||||||
|
self.last_plan: PlanDelta | None = None
|
||||||
|
|
||||||
|
def coordinate(self, signals: List[MarketSignal], author: str = "coordinator") -> PlanDelta:
|
||||||
|
# Very small heuristic: if two assets present, generate a delta-neutral hedge
|
||||||
|
actions: List[dict] = []
|
||||||
|
# Simple rule: create a hedge adjustment based on price relative to last plan
|
||||||
|
for s in signals:
|
||||||
|
if s.asset.type == "equity":
|
||||||
|
actions.append({"action": "hedge", "symbol": s.asset.symbol, "size": -0.5, "price": s.price, "ts": s.timestamp})
|
||||||
|
elif s.asset.type == "option":
|
||||||
|
actions.append({"action": "adjust", "symbol": s.asset.symbol, "size": -0.25, "premium": s.price, "ts": s.timestamp})
|
||||||
|
plan = PlanDelta(delta=actions, timestamp=signals[0].timestamp if signals else 0.0, author=author, contract_id=self.contract_id)
|
||||||
|
self.last_plan = plan
|
||||||
|
return plan
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import List, Optional, Any
|
||||||
|
|
||||||
|
def _validate_non_empty(name: str, value: Any) -> None:
|
||||||
|
if value is None or (isinstance(value, (str, list, dict)) and len(value) == 0):
|
||||||
|
raise ValueError(f"{name} must be non-empty")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Asset:
|
||||||
|
id: str
|
||||||
|
type: str # "equity" | "option" | "future"
|
||||||
|
symbol: str
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
_validate_non_empty("Asset.id", self.id)
|
||||||
|
_validate_non_empty("Asset.type", self.type)
|
||||||
|
_validate_non_empty("Asset.symbol", self.symbol)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MarketSignal:
|
||||||
|
asset: Asset
|
||||||
|
timestamp: float
|
||||||
|
price: float
|
||||||
|
liquidity: float = 1.0
|
||||||
|
extra: dict = field(default_factory=dict)
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
_validate_non_empty("MarketSignal.asset", self.asset)
|
||||||
|
if self.timestamp is None or self.price is None:
|
||||||
|
raise ValueError("MarketSignal timestamp/price required")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PlanDelta:
|
||||||
|
delta: List[dict] # A list of actions, simplified
|
||||||
|
timestamp: float
|
||||||
|
author: str
|
||||||
|
contract_id: Optional[str] = None
|
||||||
|
privacy_budget: Optional[dict] = None
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
_validate_non_empty("PlanDelta.delta", self.delta)
|
||||||
|
if self.timestamp is None:
|
||||||
|
raise ValueError("PlanDelta.timestamp required")
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class StrategyDelta:
|
||||||
|
id: str
|
||||||
|
assets: List[Asset]
|
||||||
|
objectives: dict
|
||||||
|
constraints: dict = field(default_factory=dict)
|
||||||
|
version: int = 1
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
_validate_non_empty("StrategyDelta.id", self.id)
|
||||||
|
_validate_non_empty("StrategyDelta.assets", self.assets)
|
||||||
|
if not isinstance(self.assets, list) or len(self.assets) == 0:
|
||||||
|
raise ValueError("StrategyDelta.assets must be a non-empty list")
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=42", "wheel"]
|
requires = ["setuptools", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "deltaforge-mvp"
|
name = "deltaforge"
|
||||||
version = "0.1.0"
|
version = "0.0.1"
|
||||||
description = "Minimal MVP scaffolding for DeltaForge cross-venue hedgingEngine"
|
description = "MVP: cross-venue hedging engine scaffold"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.9"
|
||||||
license = {text = "MIT"}
|
|
||||||
authors = [ { name = "DeltaForge MVP" } ]
|
|
||||||
dependencies = ["numpy"]
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="deltaforge",
|
||||||
|
version="0.0.1",
|
||||||
|
description="MVP: cross-venue hedging engine scaffold",
|
||||||
|
packages=find_packages(include=["deltaforge", "deltaforge.*"]),
|
||||||
|
include_package_data=True,
|
||||||
|
install_requires=[],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
import sys, os
|
||||||
|
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
if ROOT not in sys.path:
|
||||||
|
sys.path.insert(0, ROOT)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
from deltaforge.backtester import Backtester
|
||||||
|
from deltaforge.dsl import Asset, MarketSignal
|
||||||
|
from deltaforge.dsl import PlanDelta
|
||||||
|
|
||||||
|
def test_backtester_runs_deterministic():
|
||||||
|
a = Asset(id="eq-XYZ", type="equity", symbol="XYZ")
|
||||||
|
s = MarketSignal(asset=a, timestamp=0.0, price=10.0)
|
||||||
|
plan = PlanDelta(delta=[{"action": "hedge", "symbol": "XYZ", "size": -1.0, "price": 10.0}], timestamp=0.0, author="tester")
|
||||||
|
bt = Backtester(initial_cash=1000.0)
|
||||||
|
final_cash = bt.apply([s], plan)
|
||||||
|
assert final_cash == 1000.0 - 1.0 * 10.0 + 0 # initial cash minus hedge cost
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
from deltaforge.coordinator import Coordinator
|
||||||
|
from deltaforge.dsl import Asset, MarketSignal
|
||||||
|
|
||||||
|
def test_coordinator_creates_plan_delta():
|
||||||
|
a1 = Asset(id="eq-XYZ", type="equity", symbol="XYZ")
|
||||||
|
a2 = Asset(id="eq-ABC", type="equity", symbol="ABC")
|
||||||
|
s1 = MarketSignal(asset=a1, timestamp=1.0, price=10.0)
|
||||||
|
s2 = MarketSignal(asset=a2, timestamp=1.1, price=20.0)
|
||||||
|
c = Coordinator(contract_id="test-contract")
|
||||||
|
plan = c.coordinate([s1, s2], author="tester")
|
||||||
|
assert plan is not None
|
||||||
|
assert plan.contract_id == "test-contract"
|
||||||
|
assert isinstance(plan.delta, list)
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import math
|
||||||
|
from deltaforge.dsl import Asset, MarketSignal, PlanDelta, StrategyDelta
|
||||||
|
|
||||||
|
def test_asset_and_signals_creation():
|
||||||
|
a = Asset(id="eq-ABC", type="equity", symbol="ABC")
|
||||||
|
ms = MarketSignal(asset=a, timestamp=1.0, price=100.0)
|
||||||
|
assert a.symbol == "ABC"
|
||||||
|
assert ms.asset.symbol == "ABC"
|
||||||
|
assert ms.price == 100.0
|
||||||
|
|
||||||
|
def test_plan_delta_creation():
|
||||||
|
a = Asset(id="eq-ABC", type="equity", symbol="ABC")
|
||||||
|
ms = MarketSignal(asset=a, timestamp=1.0, price=100.0)
|
||||||
|
plan = PlanDelta(delta=[{"action": "hedge", "symbol": "ABC", "size": -0.5, "price": 100.0}], timestamp=1.0, author="tester")
|
||||||
|
assert isinstance(plan.delta, list)
|
||||||
|
assert plan.author == "tester"
|
||||||
|
assert plan.timestamp == 1.0
|
||||||
|
|
||||||
|
def test_strategy_delta_creation():
|
||||||
|
a = Asset(id="eq-ABC", type="equity", symbol="ABC")
|
||||||
|
sd = StrategyDelta(id="s1", assets=[a], objectives={"maximize": "return"})
|
||||||
|
assert sd.assets[0].symbol == "ABC"
|
||||||
Loading…
Reference in New Issue